diff --git a/app/_indices/insomnia.yaml b/app/_indices/insomnia.yaml index 1ead84a94ff..00e23acf244 100644 --- a/app/_indices/insomnia.yaml +++ b/app/_indices/insomnia.yaml @@ -52,6 +52,9 @@ sections: - path: /insomnia/plugins/plugin-reference/ - path: /insomnia/plugins/context-object-reference/ - path: /insomnia/plugins/hooks-and-actions/ + - path: /insomnia/plugins/sandbox-and-trust/ + - path: /insomnia/plugins/permissions/ + - path: /insomnia/plugins/troubleshooting/ - title: Authentication and authorization items: diff --git a/app/insomnia/plugins/permissions.md b/app/insomnia/plugins/permissions.md new file mode 100644 index 00000000000..da9b8d3d8b3 --- /dev/null +++ b/app/insomnia/plugins/permissions.md @@ -0,0 +1,102 @@ +--- +title: Plugin permissions + +description: "Declare the modules and host capabilities a sandboxed Insomnia plugin needs with the insomnia.permissions manifest, and learn the default-deny baseline and capability reference." + +content_type: reference +layout: reference + +products: +- insomnia + +breadcrumbs: +- /insomnia/ +- /insomnia/plugins/ + +tags: +- insomnia-plugins + +search_aliases: + - insomnia.permissions + - plugin capabilities + - plugin modules + - sandbox permissions + +related_resources: + - text: Plugins + url: /insomnia/plugins/ + - text: Plugin sandbox and trust model + url: /insomnia/plugins/sandbox-and-trust/ + - text: Context object reference + url: /insomnia/plugins/context-object-reference/ + - text: Plugin troubleshooting + url: /insomnia/plugins/troubleshooting/ +--- + +When a plugin runs sandboxed, it is **default-deny** on two axes: which modules it can `require()`, and which host capabilities it can call. Declare what your plugin needs in its `package.json` under the `insomnia.permissions` key. + +```json +{ + "name": "insomnia-plugin-example", + "insomnia": { + "permissions": { + "modules": ["crypto", "ajv"], + "capabilities": ["network", "storage"] + } + } +} +``` + +A plugin with no `permissions` block gets the baseline only (see below). Requesting anything beyond the baseline requires declaring it, or the call fails with an actionable error such as: + +``` +capability 'network' not granted — add it to insomnia.permissions.capabilities +``` + +## Baseline (no manifest) + +A plugin that declares no permissions still gets a minimal, read-only baseline: + +| Axis | Baseline grant | +|------|----------------| +| Modules | `path`, `crypto` | +| Capabilities | `render`, `models.read`, `util`, `crypto` | + +Anything network, filesystem, credential, storage, or app/UI related must be declared explicitly. + +## Capabilities reference + +Values you can declare in `insomnia.permissions.capabilities`: + +| Capability | Grants | +|------------|--------| +| `render` | Nested template rendering (`context.util.render`) | +| `models.read` | Read requests, workspaces, cookie jars, responses, settings, and OAuth 2.0 tokens | +| `util` | Encode/decode and host OS info helpers | +| `crypto` | The host-backed `crypto` module (hash, HMAC, random) | +| `network` | Outbound HTTP via `context.network.sendRequest` | +| `storage` | Plugin-scoped key/value store (`context.store`) | +| `fs-read` | Allow-listed file reads | +| `credentials` | Read and update stored cloud credentials | +| `app` | Dialogs, prompts, clipboard, and open-in-browser | + +{:.warning} +> `models.read` includes reading **OAuth 2.0 tokens**, which are live bearer credentials, and it's part of the baseline. Treat it as a credential-disclosure surface when reasoning about what a manifest-less plugin can access. + +## Modules reference + +Inside the sandbox, `require(name)` resolves **only** from Insomnia's curated registry — never your plugin's `node_modules`, and never raw Node.js built-ins. Declaring a module in `insomnia.permissions.modules` unlocks it; the registry is what provides a safe implementation. + +Categories: + +* **Baseline:** `path`, `crypto` +* **Polyfilled built-ins:** for example `events` +* **Vetted libraries:** for example `ajv`, `uuid` + + + +Two distinct error messages tell you which problem you have: + +* `Module 'X' not permitted by manifest` — the module exists in the registry, but you didn't declare it. +* `Module 'X' not available in sandbox` — you declared it, but it isn't in the registry. diff --git a/app/insomnia/plugins/sandbox-and-trust.md b/app/insomnia/plugins/sandbox-and-trust.md new file mode 100644 index 00000000000..b8fe73ad92d --- /dev/null +++ b/app/insomnia/plugins/sandbox-and-trust.md @@ -0,0 +1,94 @@ +--- +title: Plugin sandbox and trust model + +description: "Understand how Insomnia runs plugin code — in-process versus the QuickJS sandbox — the pluginSandboxEnabled setting, per-plugin elevated access, and how to migrate an existing plugin." + +content_type: reference +layout: reference + +products: +- insomnia + +breadcrumbs: +- /insomnia/ +- /insomnia/plugins/ + +tags: +- insomnia-plugins + +search_aliases: + - Insomnia plugin sandbox + - pluginSandboxEnabled + - elevated plugin + - full host access + +related_resources: + - text: Plugins + url: /insomnia/plugins/ + - text: Plugin permissions + url: /insomnia/plugins/permissions/ + - text: Plugin troubleshooting + url: /insomnia/plugins/troubleshooting/ + - text: Plugin reference + url: /insomnia/plugins/plugin-reference/ +--- + +## How plugin code runs + +Insomnia can run an installed (user) plugin's code in one of two places: + +* **In-process** — directly in the app process, with full Node.js access (`fs`, `child_process`, arbitrary `require`, and so on). This is the original behavior. +* **In the QuickJS sandbox** — an isolated JavaScript runtime with no direct Node.js access. The plugin reaches the app only through a capability-gated bridge, and `require()` resolves only from a curated module registry. See [Plugin permissions](/insomnia/plugins/permissions/). + +Which one is used depends on a global setting and a per-plugin opt-in. + +## The `pluginSandboxEnabled` setting + +In **Preferences > Scripting**, enable **Sandbox all plugin code**. When it's on, every untrusted (user) plugin surface — template tags, request and response hooks, actions, and load-time code — runs in the sandbox. + +This setting supersedes the earlier experiment, **Run template tags in sandbox** (`templateTagSandboxEnabled`). During migration, *either* setting activates the sandbox, so if you already enabled the template-tag experiment, nothing changes for you. New guidance should refer only to `pluginSandboxEnabled`. + +## Execution modes + +For a given plugin, the resolved mode is one of: + +| Mode | When | Runs | Host access | +|------|------|------|-------------| +| **Trusted** | First-party bundled plugin (ships with Insomnia) | In-process | Full (by design) | +| **Sandboxed** | User plugin, sandbox on, not elevated | QuickJS sandbox | Only declared capabilities | +| **Elevated** | User plugin, sandbox on, "Full host access" turned on | In-process | Full | +| **In-process** | User plugin, sandbox off | In-process | Full (legacy) | + +**Preferences > Plugins** shows each plugin's mode as a badge next to its name. + +## Full host access (elevated) + +Some community plugins genuinely need native modules or host access the sandbox doesn't grant. For those, **Preferences > Plugins** provides a per-plugin **Full host access** toggle. It is: + +* **Off by default** — a plugin is sandboxed unless you deliberately elevate it. +* **Per-plugin** — never global. +* **A trust decision** — an elevated plugin runs in-process with full Node.js access, exactly like the pre-sandbox behavior. Only elevate plugins you trust. + +## Migrate an existing plugin + +If your plugin worked before the sandbox and breaks when it's on: + +1. **Does it `require()` `fs`, `child_process`, or an arbitrary npm package?** Those aren't reachable in the sandbox. Move to a registry module and declare it (see [Plugin permissions](/insomnia/plugins/permissions/)), or ask the user to enable **Full host access** for your plugin. +2. **Does it call `context.network`, read files, use storage, or read credentials?** Declare the matching capability in `insomnia.permissions.capabilities`. An undeclared call fails with an error naming the missing capability. +3. **Is it a multi-file plugin?** Your own `node_modules` is *not* consulted at runtime — third-party dependencies must be registry modules declared in `insomnia.permissions.modules`. + +## Caveats + +* **The Inso CLI has no sandbox.** Under the pure-Node CLI, user-plugin hooks run in-process regardless of the setting — CLI users are trusting their own plugins. +* **Bundled template tags** run in the sandbox only under the legacy `templateTagSandboxEnabled` experiment (a hardening opt-in); enabling `pluginSandboxEnabled` leaves trusted first-party plugins in-process. + +## What changed + +The sandbox is a deliberate hardening, not a set of regressions: + +| Change | Kind | Effect for plugin authors | +|--------|------|---------------------------| +| User plugins run in the QuickJS sandbox when the sandbox is on | Hardening | Plugin code no longer has raw Node.js; it reaches the app only through declared capabilities | +| `require()` resolves only from a curated registry | Hardening | Arbitrary npm or `node_modules` requires fail unless the module is in the registry *and* declared | +| Default-deny permissions (baseline only unless declared) | Hardening | A plugin that used network, filesystem, or credentials without declaring them must add an `insomnia.permissions` block | +| Load failures now show as a disabled row with a reason | Fix | A plugin that fails to load (or whose name collides with another) no longer silently disappears — see [Troubleshooting](/insomnia/plugins/troubleshooting/) | diff --git a/app/insomnia/plugins/troubleshooting.md b/app/insomnia/plugins/troubleshooting.md new file mode 100644 index 00000000000..fa0b792b996 --- /dev/null +++ b/app/insomnia/plugins/troubleshooting.md @@ -0,0 +1,61 @@ +--- +title: Plugin troubleshooting + +description: "Diagnose Insomnia plugin problems — plugins that fail to load now show a disabled row with a reason instead of disappearing — plus current sandbox known limitations." + +content_type: reference +layout: reference + +products: +- insomnia + +breadcrumbs: +- /insomnia/ +- /insomnia/plugins/ + +tags: +- insomnia-plugins + +search_aliases: + - plugin disappeared + - plugin failed to load + - plugin not showing + +related_resources: + - text: Plugins + url: /insomnia/plugins/ + - text: Plugin sandbox and trust model + url: /insomnia/plugins/sandbox-and-trust/ + - text: Plugin permissions + url: /insomnia/plugins/permissions/ +--- + +## A plugin disappeared from the list + +A plugin that fails to load **no longer silently disappears**. Instead it appears in **Preferences > Plugins** as a disabled row with a reason: + +* Open **Preferences > Plugins** and look for a row marked **Failed to load plugin** (a warning icon, and no enable checkbox). Expand it to see the exact error. + +Common reasons and fixes: + +| Reason shown | Cause | Fix | +|--------------|-------|-----| +| `Cannot find module '…'` | A `require()` failed (a missing dependency, or a module that isn't in the sandbox registry) | Add the dependency as a registry module in `insomnia.permissions.modules`, or fix the missing dependency. See [Plugin permissions](/insomnia/plugins/permissions/). | +| `Multiple plugin folders declare the name "…"` | Two folders under your plugin paths declare the same plugin `name` | Remove or rename the duplicate folder. While a name is claimed by more than one folder, *none* of them load — this is deliberate, to avoid an ambiguous trust grant. | +| Other load-time error | The plugin's top-level code threw | Read the message. If the plugin needs host access the sandbox doesn't grant, consider **Full host access** — see [Plugin sandbox and trust model](/insomnia/plugins/sandbox-and-trust/). | + +### A plugin stayed broken even after I fixed the error + +Older versions cached the plugin and render engine for the whole session, so a plugin that failed once stayed broken until you restarted the app. This is fixed. Use **Preferences > Plugins > Reload plugins** (or the plugin-reload keyboard shortcut): reloading now rebuilds the render engine and re-scans the registry, so a plugin recovers once its underlying error is fixed. You no longer need to reinstall it into a fresh folder. + +## Known limitations + +### `context.app.dialog()` with a DOM element + +`context.app.dialog(title, body, options)` currently expects `body` to be a live DOM element. When an action runs in the isolated plugin window, that element can't be passed across Electron IPC to the main window (DOM nodes aren't structured-cloneable), so the call fails with `An object could not be cloned` (tracked in [Kong/insomnia#10292](https://github.com/Kong/insomnia/issues/10292)). + +Until this is addressed, avoid passing DOM nodes across the boundary — prefer serializable content, or a template tag / other UI affordance for now. + +## Still stuck? + +[Open an issue](https://github.com/Kong/insomnia/issues) with the exact text from the plugin's disabled-row reason and your `package.json` `insomnia` block.