mirror of
https://github.com/Kong/insomnia.git
synced 2026-08-02 19:02:29 -04:00
feat(templating): (T1) Preferences UI — plugin-sandbox toggle + per-plugin elevated + mode indicator
- Scripting settings: new "Sandbox all plugin code (experimental)" toggle for pluginSandboxEnabled (data-testid toggle-plugin-sandbox), beside the existing template-tag toggle. - Plugins settings: each user plugin card now shows its resolved execution mode (Sandboxed / Elevated / In-process, data-testid plugin-mode-<name>) and a "Full host access" checkbox (data-testid plugin-elevated-<name>) that writes pluginConfig.<name>.elevated. Mode + toggle read from live settings so they update immediately, before the plugin list reloads. - Widened SerializablePlugin.config to carry the optional `elevated` flag through the bridge.
This commit is contained in:
@@ -76,7 +76,7 @@ export interface SerializablePlugin {
|
||||
description: string;
|
||||
version: string;
|
||||
directory: string;
|
||||
config: { disabled: boolean };
|
||||
config: { disabled: boolean; elevated?: boolean };
|
||||
/** Parsed `insomnia.permissions` manifest (sandbox plan C3), surfaced in Preferences → Plugins. */
|
||||
permissions: { modules: string[]; capabilities: string[] };
|
||||
/** Validation warnings from parsing `permissions`; shown on the plugin card. Empty when clean. */
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from 'react-aria-components';
|
||||
|
||||
import type { SerializablePlugin } from '~/common/plugins/bridge-types';
|
||||
import { resolvePluginExecutionMode } from '~/common/plugins/sandbox-mode';
|
||||
import { validatePluginName } from '~/common/utils/plugin-name';
|
||||
import { useRootLoaderData } from '~/root';
|
||||
import { plugins as pluginsBridge } from '~/ui/plugins/renderer-bridge';
|
||||
@@ -498,6 +499,28 @@ export const Plugins: FC = () => {
|
||||
? 'Declared empty permissions (baseline access)'
|
||||
: 'No permissions declared (baseline access)';
|
||||
|
||||
// T1: this plugin's resolved execution mode + the per-plugin "elevated" escape hatch.
|
||||
// Only user plugins reach this list (bundle plugins are filtered out above). Read
|
||||
// `elevated` from live settings (not the load-time plugin.config snapshot) so the toggle
|
||||
// and badge update immediately, before the plugin list reloads.
|
||||
const isElevated = settings.pluginConfig?.[plugin.name]?.elevated === true;
|
||||
const executionMode = resolvePluginExecutionMode(settings, {
|
||||
directory: plugin.directory,
|
||||
config: { elevated: isElevated },
|
||||
});
|
||||
const modeLabel =
|
||||
executionMode === 'sandboxed'
|
||||
? 'Sandboxed'
|
||||
: executionMode === 'elevated'
|
||||
? 'Elevated'
|
||||
: 'In-process';
|
||||
const modeTitle =
|
||||
executionMode === 'sandboxed'
|
||||
? 'Runs in the QuickJS sandbox (default-deny host access).'
|
||||
: executionMode === 'elevated'
|
||||
? 'Runs in the main process with full host access (you granted this).'
|
||||
: 'Sandbox is off — runs in the main process with full host access.';
|
||||
|
||||
return (
|
||||
<GridListItem
|
||||
textValue={plugin.name}
|
||||
@@ -540,6 +563,13 @@ export const Plugins: FC = () => {
|
||||
>
|
||||
{permissionLabel}
|
||||
</span>
|
||||
<span
|
||||
data-testid={`plugin-mode-${plugin.name}`}
|
||||
className="rounded-sm bg-(--hl-xs) px-1.5 text-xs whitespace-nowrap text-(--hl)"
|
||||
title={modeTitle}
|
||||
>
|
||||
{modeLabel}
|
||||
</span>
|
||||
{plugin.permissionWarnings && plugin.permissionWarnings.length > 0 && (
|
||||
<span
|
||||
data-testid={`plugin-permission-warning-${plugin.name}`}
|
||||
@@ -554,6 +584,37 @@ export const Plugins: FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-6">
|
||||
<Checkbox
|
||||
data-testid={`plugin-elevated-${plugin.name}`}
|
||||
isSelected={isElevated}
|
||||
isDisabled={isRefreshingPlugins}
|
||||
className="group flex items-center gap-1.5 p-0 text-xs disabled:animate-pulse"
|
||||
onChange={isSelected => {
|
||||
patchSettings({
|
||||
pluginConfig: {
|
||||
...settings.pluginConfig,
|
||||
[plugin.name]: {
|
||||
...plugin.config,
|
||||
...settings.pluginConfig?.[plugin.name],
|
||||
elevated: isSelected,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="flex h-4 w-4 items-center justify-center rounded-sm ring-1 ring-(--hl-sm) transition-colors group-focus:ring-2 group-data-selected:bg-(--hl-xs)">
|
||||
<Icon
|
||||
icon="check"
|
||||
className="h-3 w-3 opacity-0 group-data-selected:text-(--color-warning) group-data-selected:opacity-100"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
className="whitespace-nowrap text-(--hl)"
|
||||
title="Run this plugin in the main process with full host access instead of the sandbox."
|
||||
>
|
||||
Full host access
|
||||
</span>
|
||||
</Checkbox>
|
||||
<div className="flex w-[8ch] items-center justify-center gap-2">
|
||||
{plugin.version}
|
||||
<a className="space-left" href={link} title={link}>
|
||||
|
||||
@@ -144,6 +144,7 @@ export const ScriptingSettings = () => {
|
||||
const sandboxEnabled = settings.scriptSandboxEnabled !== false;
|
||||
const strictModeEnabled = settings.scriptStrictModeEnabled !== false;
|
||||
const templateTagSandboxEnabled = settings.templateTagSandboxEnabled === true;
|
||||
const pluginSandboxEnabled = settings.pluginSandboxEnabled === true;
|
||||
const disabledRules = settings.disabledSecurityRules ?? [];
|
||||
const disabledProperties = settings.disabledBlockedProperties ?? [];
|
||||
const disabledRoots = settings.disabledBlockedRoots ?? [];
|
||||
@@ -340,6 +341,29 @@ export const ScriptingSettings = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border border-solid border-(--hl-sm) bg-(--hl-xs) p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-sm font-medium text-(--color-font)">Sandbox all plugin code (experimental)</span>
|
||||
<p className="text-xs text-(--hl)">
|
||||
Run every untrusted plugin surface — template tags, request/response hooks, actions, and load-time code —
|
||||
inside the QuickJS-WASM sandbox. Installed plugins are default-deny; grant an individual plugin full host
|
||||
access with "Run with full host access" in Preferences → Plugins.
|
||||
</p>
|
||||
</div>
|
||||
<Switch
|
||||
data-testid="toggle-plugin-sandbox"
|
||||
isSelected={pluginSandboxEnabled}
|
||||
onChange={enabled => patchSettings({ pluginSandboxEnabled: enabled })}
|
||||
className="group flex items-center gap-2"
|
||||
>
|
||||
<div className="flex h-6 w-11 cursor-pointer items-center rounded-full border-2 border-solid border-transparent bg-(--hl-md) transition-colors group-data-selected:bg-(--color-surprise)">
|
||||
<span className="h-5 w-5 translate-x-0 rounded-full bg-white transition-transform group-data-selected:translate-x-5" />
|
||||
</div>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RuleCard
|
||||
title="Mask Rules"
|
||||
description="Overwrites specific global variables with undefined so scripts cannot access them."
|
||||
|
||||
Reference in New Issue
Block a user