* diagnostic panel
* ci: temporarily enable code signing for PR #10470 recurring builds
* Revert "ci: temporarily enable code signing for PR #10470 recurring builds"
This reverts commit d10322c979.
* feat: gate the Git change analysis behind a Debug Mode setting [INS-3829]
Add a per-user `debugMode` setting, toggled from Help > Enable/Disable Debug
Mode (right under Show App Logs Folder). The Git commit dialog's change
analysis is now only computed and rendered while it is on.
- diffFileLoader skips buildInsomniaChangeReport and returns no diagnostics
when debugMode is off, so the dialog pays nothing for it.
- The menu label follows the setting across every open window via db.onChange.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* fix: key change-report containers by parent id instead of display path
The container identity embedded the parent's display path, so renaming a
folder or collection made every descendant look moved and skipped reorder
detection inside the renamed parent, and same-named parents were merged into
one reorder group. Key containers by the parent id and keep the path only as
a display label.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
[INS-3767](https://konghq.atlassian.net/browse/INS-3767)
## Summary
- Remove scripting-environment imports from Insomnia application modules.
- Move shared faker, URL helpers, and response reason data into appropriate insomnia-data modules.
- Move certificate matching behavior and its test into the ClientCertificate model.
- Update all callers and remove obsolete module paths.
## Verification
- insomnia-data type-check and lint
- insomnia-scripting-environment lint and tests
- insomnia type-check
- URL/certificate tests: 50 passed
- circular-reference check: no new circular dependencies; insomnia-scripting-environment has 0 cycles
The existing scripting-environment tsconfig is intentionally unchanged here; its source-wide type-check scope is enabled in the stacked sendRequest PR after the remaining Insomnia runtime dependency is removed.
## Background
Hovering a `{{ _.vault.key }}` chip showed no source: vault secrets are stored under the reserved `__insomnia_vault` key in each environment and only surface under the runtime `vault` namespace after decryption, while the key source map was built by a parallel walk over the raw environment data in `getRenderContext`, duplicating the merge semantics that `buildRenderContext` implements for values.
## Changes
- Move key source registration into `buildRenderContext`, where the values are merged. Registration runs in the same order the runtime resolves values: the `__insomnia_vault` entries of every environment are recorded under the `vault` namespace first, then every environment's plain data walk — so a legacy plaintext `vault` key, which import and sync can carry without reserved-key validation, wins over sealed values just like it does in the final vault spread.
- Unify source labels to `<environment type> : <name>` — Project Environment, Collection Environment and Folder Environment; runner upload data and script variables keep their own type names.
- Prefix the source line in the hover tooltip with `Source`, matching the live preview modal.
- Rename the setting to "Template tags show variable source and value" so its scope is obvious from the name.
* migrate request related p2
- grpc-request
- cookie-jar
- fix ts errors
* add unit test to check field mismatch
* migrate request group model
* migrate the socket io request and import parser
* migrate websocket schema and fix ts error
* fix order issue and add unit tests
add initial settings for legacy test
add initial check for legacy unit test suites
show dropdown
remove spec route and merged with default debug page
showing document as collection
remove document term in UI
fix lint issue
fix ut failures
## Summary
- Splits the single "Manage Environments" popover into two independent dropdowns — project-level and collection-level — each with a scope tooltip and an inheritance-order hint (folder overrides collection, which overrides project).
- Replaces the hidden "+" menu in the collection environment editor and the project-level full-page environment editor with explicit, always-visible "Add Sub Environment" / "Add Private Sub Environment" buttons.
- Adds an "Add Project Environment" action to the project dropdown (does not auto-select the new environment).
- Adds a keyboard shortcut for the project dropdown (Cmd/Ctrl+Alt+E), alongside the existing collection-environment shortcut (Cmd/Ctrl+Shift+E).
- Fixes smoke tests broken by removing the old single-picker trigger, and adds new coverage for the split dropdowns and create flows.
* poc: opt-in QuickJS sandbox for pre-request/after-response scripts
Adds settings.useQuickJsScriptSandbox (default off) and wires it into the
existing hidden-BrowserWindow dispatch point in concurrency.renderer.ts, so
scripts can optionally run in the QuickJS-WASM sandbox already used for
plugin template tags instead of the hidden window.
This PoC supports console, insomnia.environment/variables get/set, and
read-only insomnia.request; insomnia.sendRequest() and insomnia.test()/
pm.test() are not yet bridged and throw a clear error.
Full rollout plan (worker-boundary move, async host bridge, test-lifecycle
and request-mutation parity, security verification, telemetry/soak, and
eventually flipping the default to opt-out) is written up here:
https://gist.github.com/jackkav/3ebf8768bf84be024a3a138874919354
* fix: address Copilot review feedback on QuickJS script sandbox PoC
- Timeout error now reports the configured duration instead of an epoch
deadline timestamp.
- insomnia.request is deep-frozen so mutation attempts are silently
no-ops consistently, rather than appearing to succeed inside the
script while never reaching the host.
- Fix operator-precedence bug in a test script (?? binds looser than +).
- Add an aria-label to the new sandbox toggle Switch for screen readers.
* poc: move QuickJS script execution to a dedicated Web Worker (PR 1)
Splits run-script-quickjs.ts into:
- quickjs-script-engine.ts: the pure QuickJS execution logic (unchanged
behavior), runnable from anywhere.
- quickjs-script.worker.ts: a Web Worker entry point that runs the engine
off the renderer's main thread.
- run-script-quickjs.ts: now a thin client that lazily creates the worker
(only when useQuickJsScriptSandbox is actually used) and correlates
postMessage/response pairs by id, matching the existing
templating-handler.ts/templating.worker.ts pattern used for template
tags.
A runaway script (e.g. an infinite loop) now blocks only the disposable
worker instead of the renderer's UI thread. A worker-level crash rejects
every in-flight call and the next call gets a fresh worker.
concurrency.renderer.ts is unchanged apart from continuing to import
runScriptInQuickJs by the same name/path.
Ref: PR 1 of the rollout plan — https://gist.github.com/jackkav/3ebf8768bf84be024a3a138874919354
* style: formatting pass on quickjs worker-client test
* poc: async host bridge + insomnia.sendRequest() parity for QuickJS sandbox (PR 2)
Bridges insomnia.sendRequest() to a real HTTP request instead of throwing,
reusing the existing insomnia-templating-worker-database:// fetch protocol
and its network.sendRequestWithoutSideEffects handler (the same one the
template-tag sandbox already uses) rather than adding a second protocol
scheme. This is the same fetch-to-custom-protocol pattern
templating.worker.ts uses to reach the main process from a dedicated Web
Worker, generalized to a second async host bridge inside
quickjs-script-engine.ts (a VM promise resolved off a real fetch(),
settled via executePendingJobs() — no asyncify).
- quickjs-script-engine.ts: installSendRequestBridge() + BOOTSTRAP's
insomnia.sendRequest() now normalizes a URL string or a plain
{url, method, headers, body} object, calls the bridge, and rebuilds a
response object ({code, status, headers, body, responseTime, json(),
text()}) — supports both the Postman-style (error, response) callback
and awaiting the returned promise. insomnia.test()/pm.test() still
throws (unchanged).
- run-script-quickjs.ts (client): fetches the templating-db auth token
once via window.main.templatingDb.getAuthToken() (same pattern as
ui/worker/templating-handler.ts) and forwards it on every postMessage.
- quickjs-script.worker.ts: passes the auth token through to the engine.
Known gaps (documented in quickjs-script-engine.ts, deferred to a later
parity PR): no auth/client-certs/cookies/multipart-or-urlencoded bodies,
and the response object doesn't yet match the hidden-window Response
class's full surface (chai assertions, originalRequest, cookies).
Ref: PR 2 of the rollout plan — https://gist.github.com/jackkav/3ebf8768bf84be024a3a138874919354
* Revert "poc: async host bridge + insomnia.sendRequest() parity for QuickJS sandbox (PR 2)"
This reverts commit 37d19c1da8.
* test: add e2e smoke test for QuickJS sandbox (PR 0 + PR 1 only)
Proves the opt-in QuickJS engine and Web Worker boundary work end to
end in the real Electron app, not just in vitest's mocked unit tests:
- console.log, insomnia.environment.get/set, and read-only
insomnia.request all work through the real Worker/QuickJS pipeline
(canary: `typeof require` confirms the script actually ran in
QuickJS, not the legacy hidden-window engine).
- A runaway (`while(true){}`) script blocks only its dedicated Worker —
the app UI stays responsive and interactive while it churns.
insomnia.sendRequest() (PR 2) is intentionally not exercised — it's
been split into its own WIP branch/PR (#10392) pending a real fix for
a QuickJSUseAfterFree crash that only reproduces under real Electron
timing.
Uses "testQueryParams", a request at the workspace root with no body
and no folder-inherited scripts. Every other candidate in this fixture
either references environment variables undefined until a script runs
(triggering Insomnia's "N environment variables are missing"
confirmation dialog) or inherits a folder-level after-response script
calling an API this minimal engine doesn't bridge, which turns an
otherwise-successful send into a displayed "Error" status. Asserting
via the Console tab (console.log output) instead of an echoed response
body sidesteps template rendering entirely.
Ref: PR 0/1 of the rollout plan — https://gist.github.com/jackkav/3ebf8768bf84be024a3a138874919354
* fix(scripting): guard __proto__/constructor/prototype keys in QuickJS env/var bridge (#10395)
A script-supplied "__proto__"/"constructor"/"prototype" key reaching the bridge's store object could rewire its prototype or shadow those names; the bridge now rejects these keys before assignment.
---------
Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
* refactor(templating): retire templateTagSandboxEnabled, unify on pluginSandboxEnabled
The experimental `templateTagSandboxEnabled` toggle only ever gated
template-tag execution and had been superseded by `pluginSandboxEnabled`,
which sandboxes every untrusted plugin surface. Retire the legacy flag:
- drop it from the Settings type + defaults
- simplify `isSandboxEnabled` to read only `pluginSandboxEnabled`
- bundle plugins are trusted, so their tags always run in-process (the
legacy all-modules/all-caps bundle sandbox branch is removed)
- remove the "Run template tags in sandbox" Preferences toggle
- carry a user's prior opt-in forward via a settings migration
(templateTagSandboxEnabled === true -> pluginSandboxEnabled = true),
then delete the stale field
Smoke helpers repointed to the surviving `toggle-plugin-sandbox`; the now
-duplicate `enablePluginSandbox` helper is folded into `enableSandbox`.
* refactor(plugins): rename 'trusted' execution mode to 'internal'
'trusted' is an internal-only PluginExecutionMode label for built-in
bundled plugins the user can't install or change; it's never surfaced in
the UI (the Plugins badge shows 'In-process'). Rename it to the more
neutral, descriptive 'internal' to match the docs. Distinct from the
plugin *registry* trust concept (resolveTrustedPlugin, the 'trusted-plugin'
guard), which is unchanged.
* sandbox: reject bundle-plugin name impersonation, remove stale doc (#10376)
* docs(settings): simplify 'Sandbox all plugin code' toggle description
Address review nit: drop implementation jargon (QuickJS-WASM, default-deny)
from the Preferences copy in favour of plain language, keeping the coverage
list and the full-host-access escape-hatch pointer.
---------
Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
* feat(settings): add proxyIntegrations option for first-party integrations
* fix(proxy): improve handling of integration host URLs in insomniaIntegrationHosts function
* feat(proxy): enhance proxy integration handling for various services and update settings help text
* feat(proxy): introduce ProxyScope to manage proxy usage for requests and all traffic
* refactor(proxy): rename ProxyScope to ProxyScopes and update references throughout the codebase
* feat: add sidebar focus setting for collections in General settings
* feat: add depthOffset prop to EmptyNode and RequestNode for sidebar focus adjustment
* feat: add sidebar collection-focus-mode swipe transitions animations
* feat: clear focus state when exiting collection focus mode
* feat: implement backToAllProjects method and update tests for sidebar navigation
* feat: enhance workspace active state check with polling mechanism
* feat: update cloud sync test to include navigation back to all projects before branch actions
* feat: add sidebar focus mode onboarding with dismissal persistence
* feat: update onboarding text for sidebar focus mode to clarify navigation
* fix: correct typo in onboarding text for sidebar focus mode
* feat: implement seedSettings function to pre-seed settings for tests and update sidebar focus mode onboarding tests
* feat(templating): (T1) pluginSandboxEnabled + per-plugin elevated opt-in, centralized gate
Introduces the trust-model flip's core logic and wires every untrusted-execution surface to it.
- New setting `pluginSandboxEnabled` (default off) that supersedes/absorbs `templateTagSandboxEnabled`:
either flag on activates the sandbox, so existing template-tag opt-ins keep working (migration bridge).
- New per-plugin `pluginConfig.elevated` escape hatch: a user plugin marked elevated runs in-process
with full host access even while the sandbox is on. Widened PluginConfig/PluginConfigMap/Plugin.config.
- New pure resolver `common/plugins/sandbox-mode.ts` (isSandboxEnabled / resolvePluginExecutionMode /
shouldSandboxPlugin) — the single source of truth replacing the 7 duplicated
`templateTagSandboxEnabled && directory !== ''` conditions. Dependency-free so main, the plugin
window, and the inso CLI node runtime all share it. Unit-tested (12 cases).
- Wired all surfaces to shouldSandboxPlugin: load-time discovery (now per-plugin, so an elevated
plugin is nodeRequire-d for live functions), request/response hooks (plugin-window + node runtime),
actions, and user template tags. Bundle-tag path reads isSandboxEnabled (bundle stays trusted).
No UI yet (next commit); default-off means no behavior change until a flag is toggled.
* 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.
* test(templating): (T1) e2e — pluginSandboxEnabled sandboxes a user plugin; elevating runs it in-process
Composes the trust-flip's two user-visible behaviors on one action-probe plugin:
- Enabling the new pluginSandboxEnabled toggle (not the legacy template-tag flag) routes the user
plugin's action into the sandbox (canary reports ranin-sandboxed).
- Toggling "Full host access" in Preferences → Plugins flips the mode indicator to "Elevated" and the
same action then runs in-process (marker absent, ranin-mainprocess) — the per-plugin escape hatch.
Reuses the sandbox-action-collection.yaml fixture and the established writePlugin/clearPluginToast
helpers; adds enablePluginSandbox + setPluginElevated helpers.
* fix(templating): (T1) close two plugin-registry trust-cache gaps (#10326)
* fix(templating): close two plugin-registry trust-cache gaps
- pluginConfig.elevated is keyed by declared plugin name, not by folder;
a same-named folder placed alongside an already-elevated plugin
inherited its trust grant and ran in-process before any collision was
even noticed. traversePluginPath now pre-scans for duplicate names
(order-independent) and refuses to load any colliding folder.
- applyRequestHooks/applyResponseHooks tagged a caught error with
`error.plugin = plugin`, a plain assignment that a plugin-thrown Error
could intercept via its own `plugin` property setter, handing the hook
a live, mutable reference to its own cached registry entry and letting
it flip `directory`/`config.elevated` to defeat later sandboxing.
Switched to Object.defineProperty, which bypasses any such setter.
* fix(plugins): use relative-path containment check instead of startsWith
A bare .startsWith(base) on a resolved path accepts a sibling directory
whose name happens to prefix-match the base (e.g. /plugins-evil vs
/plugins). Added a shared isContainedIn helper (path.relative, rejects
.. or an absolute result) and applied it to both the existing
plugin-path containment check and the new duplicate-name pre-pass.
* fix(templating): (T1) address Copilot review — skip CLI settings read, scope bundle-tag sandbox to legacy flag
- network-adapter.node.ts: only read services.settings.get() when canSandbox (Electron). The pure-Node
inso CLI can never reach the sandbox host, so the read was wasted work; pass undefined otherwise
(shouldSandboxPlugin treats it as off). Both applyRequestHooks and applyResponseHooks.
- templating-worker-database.ts: bundle (first-party/trusted) template tags now sandbox only under the
legacy templateTagSandboxEnabled experiment, not the new pluginSandboxEnabled. The T1 flag isolates
*untrusted* plugins; sandboxing trusted bundle tags under it was an unintended behavior change.
Dropped the now-unused isSandboxEnabled import.
---------
Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
* perf: rewrite command palette search to eliminate UI freezes and stale results
Problems fixed:
- clientLoader blocked navigation on every palette open, freezing the UI during
full sequential DB scan
- no AbortController: stale searches could overwrite newer results mid-type
- no debounce: every keystroke triggered a full DB traversal immediately
- React Aria's default contains filter re-filtered server-side fuzzy results,
silently dropping valid matches and making fuzzy work redundant
- no warm baseline: palette started blank until the entire load completed
Changes:
- move fuzzyMatch/fuzzyMatchAll → insomnia-data/common-src/search.ts (shared,
testable in node)
- move search logic → insomnia-data/node-src/services/helpers/command-search.ts
- per-request AbortController cancellation via abort(requestId)
- recursion depth guard (max 20) on request group traversal
- safeParent() replaces non-null assertions, safe against orphaned documents
- add CommandSearchResult type in insomnia-data/src/command-search-types.ts
- add useCommandSearch hook: 250ms debounce + abort on filter change + warm
baseline on mount
- add defaultFilter={() => true} to ComboBox, delegating all filtering to the
service
- delete routes/commands.tsx
* fix
* fix
* feat(templating): PoC run plugin template tags in a QuickJS-WASM sandbox
Behind a new `templateTagSandboxEnabled` setting (default off), route plugin
template-tag execution through a QuickJS-WASM sandbox instead of invoking the
plugin's `run()` directly in the main process.
Approach (per PR #10072): bulk-copy render state into the sandbox as JSON,
rebuild the plugin `context` API in pure JS inside the sandbox, and bridge only
async work back to the host via the existing `pluginToMainAPI` handlers.
`node:crypto` is exposed as synchronous host functions so `require('crypto')`
works without a sync/async mismatch.
- templating/sandbox/: quickjs-runtime, marshal, host-bridge, in-sandbox-bootstrap,
plugin-tag-sandbox (+ parity tests vs in-process tags and node:crypto)
- main/templating-worker-database.ts: route execute handlers through the sandbox
when the flag is on; legacy path unchanged otherwise
- esbuild: keep quickjs-emscripten external so its .wasm resolves at runtime
- settings + scripting-settings UI toggle
- examples/insomnia-plugin-sandbox-demo: manual E2E fixture
Scope: template tags only; sandbox runs in main. require shim covers path + crypto
(other modules throw a clear error — follow-up work).
* test(smoke): e2e canary for the template-tag sandbox flag
Installs an inline probe plugin, renders its tags via the tag editor Live
Preview, and asserts the execution path flips main-process -> sandbox when
templateTagSandboxEnabled is toggled in Preferences > Scripting, with a
require('crypto') sha256 workload staying byte-identical across both paths.
* test(sandbox): suppress hardcoded-hmac-key semgrep finding on parity fixture
The HMAC key is a test vector for sandbox-vs-node:crypto parity, not a
credential; rename it to make that self-evident and add the repo-standard
nosemgrep suppression.
* fix(templating): contain sandbox plugin entry resolution to the plugin directory
Reject a package.json "main" that resolves outside the plugin's own folder
and bundled-plugin names that look like paths, so the sandbox source loader
cannot be steered into reading arbitrary files.
* fix(review): inline nosemgrep placement, plugin-load error context, cross-arch-safe canary
- Move the hardcoded-hmac-key suppression onto the flagged line (line-above
placement was not honored by the scanner).
- Wrap getPluginEntrySource failures with the plugin name for diagnosability.
- Derive the canary's expected arch from the Electron main process instead of
the Playwright runner so cross-arch setups can't flake the assertion.
* sec(templating): QuickJS template-tag sandbox additions (#10209)
* fix(sandbox): enforce timeout on synchronous plugin loops
QuickJS's executePendingJobs() blocks the host thread until a synchronous
call returns, so the wall-clock deadline in drivePromiseToString was never
checked during a tight sync loop in plugin code, hanging the Electron main
process indefinitely. Add a QuickJS interrupt handler, which is polled
during synchronous execution, to enforce the deadline.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sandbox): clamp crypto.randomBytes size to prevent OOM
hostCrypto.randomBytes(size) passed the sandboxed number straight to
Node's crypto.randomBytes with no upper bound, letting a plugin request
a multi-GB allocation (e.g. crypto.randomBytes(2 ** 31)) and crash the
host process. Clamp to 64KB before the call.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sandbox): cap QuickJS heap to prevent unbounded allocation
QuickJS.newContext() had no memory limit, so a plugin allocating without
bound could exhaust the WASM heap and crash the host process. Set a 32MB
ceiling via ctx.runtime.setMemoryLimit().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sandbox): resolve symlinks before validating plugin entry path
getPluginEntrySource's containment check compared raw path strings, so a
plugin directory with a symlinked entry (e.g. index.js -> ../../../etc/secret)
passed the check while fs.readFileSync followed the symlink and read the
out-of-directory target. Re-run the check against fs.realpathSync'd paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sandbox): close util.render sandbox escape
context.util.render() bridged to the shared render() pipeline, whose Liquid
engine dispatches any registered tag's real run() directly, in-process,
regardless of templateTagSandboxEnabled. A sandboxed plugin could hand it a
string containing "{% anyTag %}" (including its own tag) and have that tag
execute completely unsandboxed. Verified with a PoC that reached
child_process execution from inside a plugin tag with no require() or Node
access.
util.render is now restricted to plain {{ variable }} interpolation (the
only real existing use, confirmed against all built-in tag call sites) via
a second Liquid engine with no tags registered; {% tag %} syntax now fails
to parse instead of dispatching. Default render() behavior is unchanged for
every other caller.
Also drops the dead renderDepth field's misleading doc comment: within one
sandboxed execution the envelope's renderDepth is always 0, so depth could
never exceed 1 regardless of enforcement — it couldn't have caught this
recursion anyway.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(sandbox): fixed linting issue
* fix(sandbox): fixed linting issue
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Move insomnia-data models, services, database code, and common utilities into a dedicated workspace package. Update consumers to import from the new package entrypoints and declare workspace dependencies for the extracted package.