Commit Graph

6370 Commits

Author SHA1 Message Date
Jay Wu
6ac780fda5 Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-22 17:44:15 +08:00
Jay Wu
2ed05987db fix button alignment 2026-07-22 16:41:28 +08:00
Pavlos Koutoglou
a4286f5b95 fix: prevent blur-flush from persisting empty rows or re-enabling disabled rows in EnvironmentKVEditor (#10278) 2026-07-22 09:54:51 +02:00
Ryan Willis
6c2c3b9c24 fix: guard against infinite loops (#10281) 2026-07-21 16:08:37 -04:00
Curry Yang
0d39a28964 fix: support prompt tag in main process (#10251)
* fix: support prompt tag in main process

* fix: show cancel message

* fix: lint

* fix lint
2026-07-21 18:12:55 +08:00
Ryan Willis
36436d7ee7 fix(sidebar): deduplicate repeated workspace IDs (#10179) 2026-07-21 04:58:47 +00:00
Ryan Willis
5143b41030 fix: collection runner ux (#10271) 2026-07-17 15:00:05 -07:00
Jack Kavanagh
6c021150f2 feat(templating): multi-file plugins via in-sandbox module map (M4) (#10256)
* feat(templating): multi-file plugins via in-sandbox module map (M4)

esbuild is dev-only, so instead of bundling plugins at load time this reads the
plugin's own source files into a module map (readPluginModuleMap, host-side)
and teaches the in-sandbox require to resolve RELATIVE specifiers from that map
(./util, ../x, ./dir -> ./dir/index.js) with a CommonJS cache. Bare specifiers
still route through the grant-gated registry.

Security (the poison guarantee): the host walker reads ONLY within the plugin
directory — node_modules and dot-dirs are skipped, symlink-escapes dropped,
file count/size bounded — so a plugin's own node_modules is never consulted and
a bare require('uuid') always binds the vetted registry copy, never a plugin's
substitute. Plugin source now travels as envelope DATA (moduleFiles) compiled by
the loader via new Function; no host-side eval of plugin code. Single-file
callers keep working via a synthesized one-entry map.

Tests: multi-file-plugins.test.ts (7: relative/nested/dir-index resolution,
hybrid bare-uuid, CJS cache, not-found, syntax-error propagation, bare-vs-map
shadow) + readPluginModuleMap tests (map shape, node_modules-excluded poison
guarantee, custom main, entry-escape). E2E: multi-file resolution + poison
(fake node_modules/uuid ignored). Demo converted to multi-file
(require('./lib/greeting')). PERMISSIONS.md documents multi-file + the
require-vetted-libs-inside-run note.

No esbuild runtime dependency added.

* fix(templating): tighten M4 module-map byte guard and relative-path escape

Address review feedback on the multi-file plugin loader:

- readPluginModuleMap counted source.length (UTF-16 code units), which
  undercounts multi-byte UTF-8 payloads against MAX_PLUGIN_MODULE_BYTES, and
  the custom-"main" entry fallback was added to the map without counting its
  bytes at all. Count Buffer.byteLength(...'utf8') via a shared addModule
  helper used by both the walk and the entry fallback.

- __normalizeKey clamped above-root '..' traversal back into the plugin root,
  so require('../../util') from a shallow dir could masquerade as an in-plugin
  module. Return null for above-root traversal (unresolvable), matching Node
  semantics; __resolveRelative propagates it as MODULE_NOT_FOUND.
2026-07-17 09:44:17 -04:00
Bingbing
8a1dc1ef62 perf: rewrite command palette search to eliminate UI freezes and stale results (#10257)
* 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
2026-07-17 01:07:38 +00:00
Ryan Willis
6a79057a55 fix: deep-link mcp workspace matching (#10269) 2026-07-16 17:35:41 -07:00
Fares Osman
8f6302d69f feat: show number of matches when filtering a JSON response (#10261)
* feat: show number of matches when filtering a JSON response

* chore: copilot feedback
2026-07-16 19:14:43 +00:00
Pavlos Koutoglou
ed476d9d84 fix(first-request): polish input UI and fix cURL method detection [INS-3055] (#10267)
* feat: add cURL command detection utility and integrate into request creation flow

* feat: add placement prop to MethodSelector and set default placement in RequestUrlBar

* fix: improve cURL command method extraction logic for better accuracy
2026-07-16 19:00:46 +00:00
Alison Sabuwala
37e6a00220 fix: route v3 spaces SDK through proxy-aware fetch (#10265) 2026-07-16 17:22:11 +00:00
Pavlos Koutoglou
19c6e21718 fix: restore visible keyboard focus indicators across the app (#10268)
* feat: enhance focus-visible styles for input elements

* feat: simplify focus-visible styles for form elements
2026-07-16 19:30:26 +03:00
Pavlos Koutoglou
4ad32eeb7c fix: stop reusing blank-row ids in key-value editors [INS-2598] (#10260)
* fix: ensure unique blank IDs for environment key-value pairs to prevent stale state

* test: add validation for blank row behavior after deleting committed rows in environment table editor
2026-07-16 18:58:04 +03:00
Jack Kavanagh
3842690f60 feat(templating): vetted npm libraries in the sandbox — uuid + ajv (M3) (#10244) 2026-07-16 12:53:23 +03:00
Shelby
e97c1b14f7 feat: add a tooltip for show/hide secret on auth tab (#10263) 2026-07-15 15:46:28 -07:00
Jack Kavanagh
04786987bb feat(undo): broaden undo-history persistence via a stable historyKey (#10233) 2026-07-15 21:37:15 +00:00
Ryan Willis
e36661b096 fix(import): always show collection picker (#10262) 2026-07-15 20:19:37 +00:00
Fares Osman
f70cda4366 chore: emit and upload junit test results per shard (#10253)
* chore: emit junit reports per e2e tests shard

* chore: include retries in junit reporter

* chore: test some stuff

* chore: test again

* chore: revert test
2026-07-15 13:49:26 -04:00
Curry Yang
02ddedb538 Feat/basic components m0 (#10230)
* refactor: components infra

* fix

* fix: data-* class

* rename cn to cls
2026-07-15 09:30:21 +00:00
Curry Yang
7df04dae4c fix: cloud sync test flaky (#10238)
* fix: cloud sync test flaky

* fix
2026-07-15 03:56:33 +00:00
Jack Kavanagh
afe4c91705 feat(templating): surface profiles + ceiling + migration warning (P1) (#10242)
* feat(templating): surface profiles + ceiling + manifest-less migration warning (P1)

Add per-surface sandbox profiles (surface-profiles.ts): a profile is the
ceiling of what a plugin on a surface may be granted, effective grant =
floor ∪ (declared ∩ ceiling).

- TEMPLATE_TAG_PROFILE excludes 'credentials' from its capability ceiling —
  cloud-credential access is reserved for first-party bundle plugins; a user
  template-tag plugin can't obtain it even by declaring it.
- SCRIPTING_PROFILE (broad, enumerated) defined for the later scripting-engine
  reuse; unit-tested, not wired to a live surface yet.
- resolveTemplateTag{Modules,Capabilities} move here from module-registry/
  host-bridge and delegate to the profile (capabilities enforce the ceiling;
  modules pass declared names through so the require gate gives the precise
  'not available' vs 'not permitted' message).
- Migration warning: a manifest-less plugin denied a non-baseline module gets a
  one-time (per-plugin-per-session) toast via the existing show-toast channel,
  naming the module + the insomnia.permissions field to add.
- Docs: PERMISSIONS.md; demo README + capability ceiling note.

Tests: surface-profiles.test.ts (effectiveGrant matrix, floor⊆ceiling, credentials
ceiling exclusion); migration-warning dedup unit test; C2 shape tests decoupled
from the profile (grant caps directly); e2e P1 test (ceiling + one-time warning).
107 unit + 4 smoke green.

* feat(templating): typed module denial (#10254)

* fix(templating): typed module-denial error instead of message regex (P1)

maybeWarnMissingManifest matched the sandbox's thrown error message
("Module 'X' not permitted by manifest") with a regex to decide whether
to show the migration toast. That couples a UI feature to English error
prose crossing the QuickJS VM boundary — any future wrapping or wording
change breaks the toast silently, with no compiler signal.

__require now throws with `code`/`moduleName` own properties
(SANDBOX_MODULE_NOT_PERMITTED vs SANDBOX_MODULE_NOT_AVAILABLE), which
toError() in plugin-tag-sandbox.ts carries through onto the rebuilt
Error. maybeWarnMissingManifest branches on that discriminant instead of
regexing the message text; the message strings remain unchanged and
still asserted verbatim by the existing tests.

* fix(templating): key migration-warning dedup by (plugin, module), add ceiling tripwire

maybeWarnMissingManifest deduped its one-time toast by plugin name alone,
so a manifest-less plugin that trips on two different ungranted modules in
one session only ever saw a hint for the first one it hit — the second,
equally actionable denial was silently suppressed. Key by (plugin, module)
instead so each distinct missing grant still gets its own toast, while a
repeat denial for the same module still doesn't re-toast.

Also added a regression test pinning that a manifest with a malformed axis
(declared:true, per-card warning) is correctly routed away from this toast
path, and a tripwire test on TEMPLATE_TAG_PROFILE.moduleCeiling: resolveTemplateTagModules
deliberately doesn't enforce the ceiling (an unregistered module must still
reach require() for the precise "not available" message), which is only
safe while the ceiling equals the full module registry — this test fails
first if a future change narrows it, as a signal to revisit that function.

---------

Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
2026-07-14 16:45:04 +00:00
Bingbing
5bd2ad6629 fix: handle lint process error by terminating it and resetting the reference (#9871) 2026-07-13 21:01:21 +00:00
Fares Osman
cb181a1e3b fix: don't count auto-derived file name as a changed field in new workspace modal (#10246)
* fix: don't count auto-derived file name as a changed field in new workspace modal

* test: adds test case for future regression
2026-07-13 11:57:48 -07:00
Fares Osman
9ec35e5070 chore: enable retries for playwright smoke tests (#10234)
* chore: adds junit xml reporter and enable retries for playwright

* chore: revert in favour of later pr
2026-07-13 12:32:07 -04:00
Pavlos Koutoglou
52e2b29e10 feat: add request_url_length property to request creation metrics (#10243) 2026-07-13 09:03:03 -07:00
Jack Kavanagh
911e188654 feat(templating): capability-aware sandbox context construction (C2) (#10226)
__buildContext now builds the full context, then removes branches whose
capability is not granted, so context.network/store/app/util.readFile/
util.openInBrowser/util.models.cloudCredential are undefined (not
present-but-rejecting stubs) unless declared. Driven by __hasCap reading the
captured grantedCapabilities via the pristine __arrIndexOf (unspoofable),
kept in lockstep with C1's BRIDGE_PATH_CAPABILITIES. Baseline caps (render,
models.read, util, crypto) and context/meta/renderPurpose data are never gated.

Plugins can feature-detect (if (context.network)) and degrade gracefully;
touching an ungranted branch fails at the property access in the plugin's own
code, not as a later async rejection. C1's bridge gate remains the backstop.

- unit: context-shape matrix, feature-detect, attach-on-grant, and a C1<->C2
  consistency test (branch present iff its bridge-path capability is granted)
- reframed the C1 e2e denial test to prove the bridge backstop (branch granted
  to C2 but withheld from the bridge filter); no-manifest denial now covered by
  C2's absent-branch test
- smoke: capdenied tag feature-detects (returns 'no-storage-capability'); test
  retitled (C1 + C2)
2026-07-13 16:14:02 +02:00
Jay Wu
3e79f53606 fix: button size (#10241)
* fix: button size

* polish the help message
2026-07-13 10:10:41 +00:00
Pavlos Koutoglou
5ba0655bb5 fix(INS-2933): let empty-input request creation and re-focus the first-request input on project switch (#10240)
* fix: improve request creation handling and input focus behavior

* fix: simplify user ownership check in project component

* fix: refactor onboarding state loading to use async/await for better readability

* fix: enhance request creation button disable logic to include workspace fetcher state
2026-07-13 17:17:11 +08:00
Kent Wang
9cbecb7b38 fix: Previous response will show after a request is sent successfully (#10239)
* add a request id to track in response pane

* add comments
2026-07-13 15:41:55 +08:00
Pavlos Koutoglou
4f5a72dc16 feat(INS-2933): first-request experience A/B experiment (13.1) (#10215)
* Create new methods colors

* Implement first request logic

* feat: enhance first request treatment logic with backend support and caching

* feat: add experiment assignment analytics and related utility functions

* feat: add reportRequestsCreated function to track request creation for first-request experiments

* feat: enhance request creation reporting with session tracking

* feat: add tests for reportRequestsCreated function to validate API interactions

* feat: refactor localStorage methods for better error handling and state management

* feat: enhance accessibility of error message in FirstRequestCreation component

* feat: simplify user ownership check in project component

* feat: update user tests to include onboarding state and related functions

* feat: replace reportRequestCreated function with maybeLatchRequestThreshold for request tracking

* feat: integrate onboarding state into first request treatment logic and refactor related functions

* feat: integrate onboarding state into FirstRequestCreation component and enhance treatment logic

* feat: implement maybeLatchRequestThreshold function for tracking first-request graduation

* feat: refactor onboarding request handling and replace reportRequestsCreated with latchRequestThresholdReached

* feat: simplify first request treatment logic and remove unused functions

* feat: update latchRequestThresholdReached to use PATCH method for idempotent threshold latch

* feat: update onboarding state interface and test to use reached_request_threshold instead of has_reached_request_threshold

* feat: update latchRequestThresholdReached to use PUT method and correct endpoint for idempotent threshold latch

* feat: remove reached_request_threshold from onboarding state and related tests

* feat: integrate request tracking with maybeLatchRequestThreshold in clientAction

* feat: update onboarding state handling and treatment logic in user module

* feat: update @getinsomnia/insomnia-v3-fetch to version 1.0.20 in package-lock and package.json

* feat: add padding to request URL bar and adjust MethodSelector alignment

* feat: enhance request threshold handling by adding per-account request count baseline

* feat: update analytics event emission for treatment assignments in first request flow
2026-07-10 18:10:53 +00:00
Jack Kavanagh
e4f4cd5945 feat(templating): capability-gate the sandbox host bridge (C1) (#10222) 2026-07-10 16:16:30 +00:00
Kent Wang
bb89fc798e fix curl modal not showing issue (#10235) 2026-07-10 08:17:23 +00:00
Curry Yang
50ee4c7a0f feat: add skill for maintain component documents (#10229) 2026-07-10 03:46:53 +00:00
yaoweiprc
aff48ee919 fix: propagate system proxy settings to user requests (INS-2943) (#10228)
* fix: propagate system proxy settings to user requests (INS-2943)

When proxyEnabled is false in Insomnia Preferences, the request engine
(node-libcurl) now falls back to the OS system proxy via Electron's
session.defaultSession.resolveProxy(), matching the behavior of
Insomnia's internal API calls.

Previously, disabling the proxy toggle explicitly set CURLOPT_PROXY to
an empty string, which prevented libcurl from using any proxy including
the system proxy. This caused user requests to bypass the OS proxy while
Insomnia's own network calls (via Chromium's network stack) correctly
respected it.

Changes:
- Add parseResolvedProxy() helper to parse PAC-format proxy strings
- Call resolveProxy() inside createConfiguredCurlInstance() when proxy
  is not explicitly configured
- Refactor api.protocol.ts to use the shared helper (removes ~50 lines
  of duplicated proxy parsing logic)

* fix: catch resolveProxy errors and fall back to direct connection

* fix: catch resolveProxy errors in api.protocol.ts

* fix: remove redundant comment about proxy mode in updateProxy function
2026-07-09 10:11:01 +00:00
Bingbing
1a3bed2d77 refactor: update environment service methods and replace database calls with service calls (#10227) 2026-07-09 16:52:42 +08:00
Jack Kavanagh
a91f1056f3 feat(templating): seed ambient sandbox stdlib globals — Buffer/process/crypto/URL (M2) (#10220)
* feat(templating): seed ambient sandbox stdlib globals (M2)

Add always-present, ungated safe-equivalent globals to the QuickJS sandbox:
Buffer (from/alloc/concat/isBuffer + utf8/base64/hex/latin1), a frozen
process stub (platform/arch from the envelope, empty frozen env, microtask
nextTick), Web-Crypto crypto.getRandomValues + crypto.subtle.digest
(host-backed), and URL/URLSearchParams. Lives in sandbox-globals.ts, eval'd
after the bootstrap + host-crypto installs.

Because the sandbox now provides a process stub, the old
'typeof process === undefined' sandbox-detection heuristic no longer holds;
add a non-writable INSOMNIA_TEMPLATE_SANDBOX marker and switch the canary +
demo probe to it.

- +19 unit parity tests vs node: Buffer/subtle/URL/URLSearchParams/getRandomValues + escape + marker
- e2e: stdlibprobe renders each API; flag-off captured and asserted byte-identical
  under the flag (parity), subtle pinned to a known hash, process.env '{}' + frozen sandbox-only
- smoke helpers wait for modal close + poll the post-toggle canary (re-open until
  the flag propagates), de-flaking the mid-test toggle
- demo plugin gains a stdlibprobe tag

require() module wrappers (url/buffer/util/querystring/string_decoder/assert)
are the M2b follow-up; they mostly re-export these globals.

* test(sandbox): pass M2 global-probe values as tag args, not interpolated code

CodeQL flagged the runGlobal test helper for constructing eval'd plugin
source from interpolated values. Make body a constant literal at every call
site and thread dynamic values through the tag's args (envelope data, read as
arguments[1..]) so no test value is concatenated into sandbox-eval'd code.

* fix(sandbox): enforce WebCrypto 65536-byte quota in getRandomValues + review nits

- getRandomValues now throws past 65536 bytes (matching WebCrypto's
  QuotaExceededError) instead of silently zero-filling the tail beyond the
  host __cryptoRandomBytes clamp — no predictable output.
- Correct the enableSandbox comment: assertions are expect.soft (mandated by
  the smoke ESLint config); the authoritative flag-applied signal is the
  downstream polling canary.
- Fix a doc-comment typo: typeof process === "undefined" (quoted).

* fix(sandbox): M2 stdlib parity fixes + bridge hardening (#10224)

* fix(sandbox): plumb host arch into process stub

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sandbox): add crypto.randomUUID to ambient web crypto

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sandbox): URLSearchParams.set keeps first occurrence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sandbox): support URLSearchParams copy-construct

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sandbox): guard bridge dispatch against inherited keys

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(sandbox): hide raw host bridge from plugin code

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(lint): fixed linting issue

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: kwburns-kong <kyle.burns@konghq.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 04:16:43 +00:00
Jack Kavanagh
1b4f44f0c3 feat(undo): reconcile native + CodeMirror undo via one app-level handler (#10167)
The Edit menu's Undo/Redo used role: 'undo'/'redo', driving only the native
webContents stack. On macOS the menu accelerator swallows Cmd+Z before
CodeMirror's keymap, so CodeMirror surfaces had no working undo — two competing
stacks with the native one always winning and doing nothing useful for CM.

Menu Undo/Redo now send edit:undo/edit:redo to the focused window; a single
renderer handler (editor-undo.ts, wired in renderer-listeners.ts) routes by
focus: CodeMirror surfaces drive cm.undo()/redo(); everything else replays the
native execCommand, preserving prior plain-input behaviour. No double-fire: the
accelerator still keeps CM's own keymap from firing independently.
2026-07-08 08:49:00 -04:00
Kent Wang
cf35ed02fa Chore: Plugin window debug support in dev (#10181)
* add show/hide and start/stop plugin window support in dev app menu

* change order
2026-07-08 10:59:37 +08:00
Kent Wang
a9108f5f1a add analytic events for create shortcut (#10212)
add analytic events for create shortcut
2026-07-08 02:36:19 +00:00
James Gatz
490aa9b917 feat(Git Sync): Git projects can live anywhere on disk (#10155)
* tech_design

* tech-doc

* add directory to git repo model

* tech doc

* tech doc

* use directory picker to select an existing repo to clone from/to

* tech doc

* Open git repo

* tech doc

* Implement Git project local storage features and add e2e tests

* tech doc

* Implement folder opening as Git projects with user trust confirmation

* Add Git credential selection to project creation form and enhance repo file watcher for directory availability

* tech doc

* refactor: clean up code and remove references to GIT_LOCAL_REPOS_DESIGN.md

* fix: handle optional author name in Git credential display

* feat: enhance Git credential handling for local repositories

* feat: enhance Git project folder handling and improve test descriptions

* fix: update Git project mode button copy

Rename 'Clone from URL' to 'Clone from Remote' and 'Open existing
folder' to 'Open local folder'. Update the smoke test selector and a
stale comment accordingly.

* fix: align control heights and styling in Git clone form

Standardize the credential select, author email select, and clone
location box to match the repository/branch comboboxes: shared
--line-height-xs height, consistent label spacing, and input-sized
value text and padding.

* feat: show clone target path and remember last clone folder

Default the clone parent directory to the folder the user last cloned
into, and render the resulting target path middle-truncated with a full
path tooltip via a new MiddleTruncate component.

* fix: reorder and align Open local folder input layout

Move the helper text directly below the Folder label, and align the
folder box and Choose folder button to the shared control height with
middle-truncated path display.

* feat: warn when opening a folder already used by a project

Add a git.checkGitRepoDirectory IPC that resolves the project adopting
a folder. The Open local folder flow checks at folder-pick time and
shows a red, no-background warning below the input offering to open the
existing project, and blocks continuing while the warning is present.

* fix: top-align empty organization view and scroll the full page

Replace the vertically centered grid with a top-aligned, page-scrolling
layout so the new project form no longer jumps when switching project
types and the scrollbar spans the whole pane.

* fix: align project modal to top and match folder description color

Top-align the project modal overlay so it no longer jumps as the form
height changes, and drop the dimmer color override on the Open local
folder helper text so it matches the repository URL field description.

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: always use getRepoBaseDir

* fix comment

* delete duplicate code

* fix: test

* test: add Git repository relocation tests

* fix: ensure selection change handler converts key to string

---------

Co-authored-by: Pavlos Koutoglou <pkoutoglou@gmail.com>
Co-authored-by: Curry Yang <163384738+CurryYangxx@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Curry Yang <1019yanglu@gmail.com>
2026-07-08 05:16:54 +03:00
Fares Osman
d1ef1e5a2c fix: surface invalid spectral ruleset issues to renderer in git sync projects (#10203)
* feat: adds some progress to fixing issue with invalid spectral rulesets being imported when creating git sync projects

* feat: surfaces ruleset import problem to the renderer in git sync projects

* test: adds additional test

* chore: formatting

* fix: ui
2026-07-07 20:39:43 -04:00
Fares Osman
7a3f77322c fix: restore project modal top-anchored positioning (#10217) 2026-07-07 22:11:30 +00:00
Ryan Willis
99a55ac1e8 fix: support nested query param schemas (#10219) 2026-07-07 17:54:37 -04:00
Ryan Willis
1dd4593f58 chore: harden electron web permissions [INS-2367] (#10159) 2026-07-07 20:47:39 +00:00
Jack Kavanagh
30650f9dad feat(templating): plugin manifest permissions loader + Plugins-UI display (C3) (#10211) 2026-07-07 21:54:19 +02:00
Jack Kavanagh
9b1f17f70f feat(templating): manifest-gated module registry for the sandbox require (M1) (#10208)
* feat(templating): manifest-gated module registry for the sandbox require (M1)

Replace the hardcoded path/crypto require shim with a curated module
registry (single source of truth in module-registry.ts) resolved by a
default-deny __require against the envelope's grantedModules:

- ungranted name  -> "Module 'X' not permitted by manifest"
- granted, no impl -> "Module 'X' not available in sandbox"

Grants are the hardcoded path/crypto baseline until the manifest loader
(C3) lands. node:-prefixed aliases resolve to canonical names; exports
are cached per context. E2E: requireprobe tag asserts the baseline works
through the registry and that npm/builtin names fail with the exact
denial message in the tag Live Preview.

* sec(templating): capture envelope before plugin eval; lock registry; null-proto maps

- Inject __envelopeJSON/__tagName before the bootstrap, capture them into
  closure state, and delete the globals — plugin top-level code can no
  longer rewrite grantedModules (or any envelope field) before __invoke().
- delete __registerModule once the registry is populated so plugin code
  cannot register or replace factories.
- Null-prototype registry/alias/cache maps so __proto__/constructor behave
  as absent keys.
- Test helper defaults grants to TEMPLATE_TAG_BASELINE_MODULES; new tests
  cover envelope tampering and prototype-chain module names.

* sec(templating): harden module gate against intrinsic tampering

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* sec(templating): lock sandbox-internal globals from plugin reassignment

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* sec(templating): enforce trusted-literal invariant for module factorySource

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Kyle <kyle.burns@konghq.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 15:19:07 +00:00
Fares Osman
71e71cd9e1 fix: fix invite/cookies modal backdrop rendering wrong theme color (#10210) 2026-07-07 10:20:42 -04:00
Jack Kavanagh
cc9288c218 feat(templating): QuickJS template-tag sandbox behind a flag, with e2e canary (#10207)
* 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>
2026-07-06 19:01:48 +00:00