Commit Graph

556 Commits

Author SHA1 Message Date
Peter Steinberger
0d7f1e2c84 feat(security): fail closed on dangerous skill installs 2026-03-31 23:27:20 +09:00
Peter Steinberger
da6e9bb76f refactor: move tasks behind plugin-sdk seam 2026-03-31 15:22:09 +01:00
Josh Avant
81b777c768 fix(config): harden SecretRef round-trip handling in Control UI and RPC writes (#58044)
* Config: harden SecretRef round-trip handling

* Gateway: test SecretRef preflight on config writes

* Agents: align skill loader with upstream Skill type

* Docs: align SecretRef write semantics with Control UI and RPC behavior

* Config: add UI and gateway regression evidence for SecretRef hardening

* Config: add token SecretRef restore regression and skill sourceInfo compat

* UI: scope structured-value lockout to SecretRef fields

* Agents: remove out-of-scope skill loader compat edits

* UI: reduce app-render churn to rawAvailable-only changes

* Gateway: scope SecretRef preflight to submitted config

* Docs: clarify config write SecretRef preflight scope

* changelog

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>

---------

Signed-off-by: joshavant <830519+joshavant@users.noreply.github.com>
2026-03-30 23:55:03 -05:00
Vincent Koc
91f7a6b0fd fix(gateway): revoke active sessions on token rotation (#57646) 2026-03-31 09:05:34 +09:00
mappel-nv
5cc0bc936c Gateway: open config files without shell interpolation (#57921)
* Gateway: open config files without shell interpolation

Co-authored-by: peteryuqin <peter.yuqin@gmail.com>

* Gateway: align config opener review fixes

* Gateway: tidy config opener logging

* Gateway: simplify config opener error path

* Gateway: cover Windows config opener test path

* Gateway: use literal Windows config open path

---------

Co-authored-by: peteryuqin <peter.yuqin@gmail.com>
2026-03-30 15:21:25 -06:00
Sean
c6f2db1506 fix: prevent gateway attachment offload regressions (#55513) (thanks @Syysean)
* feat(gateway): implement claim check pattern to prevent OOM on large attachments

* fix: sanitize mediaId, refine trimEnd, remove warn log, add threshold and absolute path

* fix: enforce maxBytes before decoding and use dynamic path from saveMediaBuffer

* fix: enforce absolute maxBytes limit before Buffer allocation and preserve file extensions

* fix: align saveMediaBuffer arguments and satisfy oxfmt linter

* chore: strictly enforce linting rules (curly braces, unused vars, and error typing)

* fix: restrict offload to mainstream mimes to avoid extension-loss bug in store.ts for BMP/TIFF

* fix: restrict offload to mainstream mimes to bypass store.ts extension-loss bug

* chore: document bmp/tiff exclusion from offload whitelist in MIME_TO_EXT

* feat: implement agent-side resolver for opaque media URIs and finalize contract

* fix: support unicode media URIs and allow consecutive dots in safe IDs based on Codex review

* fix(gateway): enforce strict fail-fast for oversized media to prevent OOM bypass

* refactor(gateway): harden media offload with performance and security optimizations

This update refines the Claim Check pattern with industrial-grade guards:

- Performance: Implemented sampled Base64 validation for large payloads (>4KB) to prevent event loop blocking.
- Security: Added null-byte (\u0000) detection and reinforced path traversal guards.
- I18n: Updated media-uri regex to a blacklist-based character class for Unicode/Chinese filename support, with oxlint bypass for intentional control regex.
- Robustness: Enhanced error diagnostics with JSON-serialized IDs.

* fix: add HEIC/HEIF to offload allowlist and pass maxBytes to saveMediaBuffer

* fix(gateway): clean up offloaded media files on attachment parse failure

Address Codex review feedback: track saved media IDs and implement best-effort cleanup via deleteMediaBuffer if subsequent attachments fail validation, preventing orphaned files on disk.

* fix(gateway): enforce full base64 validation to prevent whitespace padding bypass

Address Codex review feedback: remove early return in isValidBase64 so padded payloads cannot bypass offload thresholds and reintroduce memory pressure. Updated related comments.

* fix(gateway): preserve offloaded media metadata and fix validation error mapping

Address Codex review feedback:
- Add \offloadedRefs\ to \ParsedMessageWithImages\ to expose structured metadata for offloaded attachments, preventing transcript media loss.
- Move \erifyDecodedSize\ outside the storage try-catch block to correctly surface client base64 validation failures as 4xx errors instead of 5xx \MediaOffloadError\.
- Add JSDoc TODOs indicating that upstream callers (chat.ts, agent.ts, server-node-events.ts) must explicitly pass the \supportsImages\ flag.

* fix(agents): explicitly allow media store dir when loading offloaded images

Address Codex review feedback: Pass getMediaDir() to loadWebMedia's localRoots for media-uri refs to prevent legacy path resolution mismatches from silently dropping large attachments.

* fix(gateway): resolve attachment offload regressions and error mapping

Address Codex review feedback:
- Pass \supportsImages\ dynamically in \chat.ts\ and \gent.ts\ based on model catalog, and explicitly in \server-node-events.ts\.
- Persist \offloadedRefs\ into the transcript pipeline in \chat.ts\ to preserve media metadata for >2MB attachments.
- Correctly map \MediaOffloadError\ to 5xx (UNAVAILABLE) to differentiate server storage faults from 4xx client validation errors.

* fix(gateway): dynamically compute supportsImages for overrides and node events

Address follow-up Codex review feedback:

- Use effective model (including overrides) to compute \supportsImages\ in \gent.ts\.

- Move session load earlier in \server-node-events.ts\ to dynamically compute \supportsImages\ rather than hardcoding true.

* fix(gateway): resolve capability edge cases reported by codex

Address final Codex edge cases:
- Refactor \gent.ts\ to compute \supportsImages\ even when no session key is present, ensuring text-only override requests without sessions safely drop attachments.
- Update catalog lookups in \chat.ts\, \gent.ts\, and \server-node-events.ts\ to strictly match both \id\ and \provider\ to prevent cross-provider model collisions.

* fix(agents): restore before_install hook for skill installs

Restore the plugin scanner security hook that was accidentally dropped during merge conflict resolution.

* fix: resolve attachment pathing, defer parsing after auth gates, and clean up node-event mocks

* fix: resolve syntax errors in test-env, fix missing helper imports, and optimize parsing sequence in node events

* fix(gateway): re-enforce message length limit after attachment parsing

Adds a secondary check to ensure the 20,000-char cap remains effective even after media markers are appended during the offload flow.

* fix(gateway): prevent dropping valid small images and clean up orphaned media on size rejection

* fix(gateway): share attachment image capability checks

* fix(gateway): preserve mixed attachment order

* fix: fail closed on unknown image capability (#55513) (thanks @Syysean)

* fix: classify offloaded attachment refs explicitly (#55513) (thanks @Syysean)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
2026-03-30 20:54:40 +05:30
Vincent Koc
8fb247c528 refactor(tasks): guard executor-only producer writes (#57486)
* refactor(tasks): add executor facade

* refactor(tasks): extract delivery policy

* refactor(tasks): route acp through executor

* refactor(tasks): route subagents through executor

* refactor(cron): split main and detached dispatch

* refactor(tasks): guard executor-only producer writes
2026-03-30 14:00:25 +09:00
Josh Avant
5e4a64848f fix(exec): harden async approval followup delivery in webchat-only sessions (#57359)
* fix(exec): harden approval followup delivery fallback

* refactor(delivery): share best-effort followup routing helpers

* test(subagents): cover webchat-only completion announce delivery

* docs(exec): clarify async followup delivery behavior

* fix(exec): harden delivery downgrade logging

* test(gateway): cover multi-channel best-effort fallback

* fix(exec): preserve webchat origin on session-only followups

* fix(subagents): keep internal announces channel-less
2026-03-29 20:54:13 -05:00
Vincent Koc
53bcd5769e refactor(tasks): unify the shared task run registry (#57324)
* refactor(tasks): simplify shared task run registry

* refactor(tasks): remove legacy task registry aliases

* fix(cron): normalize timeout task status and harden ledger writes

* fix(cron): keep manual runs resilient to ledger failures
2026-03-30 08:28:17 +09:00
Vincent Koc
0e47ce58bc fix(approvals): restore queue targeting and plugin id prefixes 2026-03-30 07:37:50 +09:00
Peter Steinberger
27519cf061 refactor: centralize node identity resolution 2026-03-29 23:14:22 +01:00
Peter Steinberger
6ca81f8ec7 test(gateway): decouple send coverage from telegram specifics 2026-03-29 22:59:32 +01:00
Peter Steinberger
168ab94eee refactor(config): pin runtime snapshot and drop ttl cache 2026-03-29 22:57:31 +01:00
Peter Steinberger
3ec000b995 refactor: align same-chat approval routing 2026-03-30 06:52:28 +09:00
Peter Steinberger
f16c176a4c fix: disambiguate legacy mac node identities 2026-03-29 22:47:15 +01:00
Peter Steinberger
574d3c5213 fix: make same-chat approvals work across channels 2026-03-30 06:35:04 +09:00
Peter Steinberger
63e5c3349e refactor(config): drop obsolete legacy config aliases 2026-03-29 22:00:56 +01:00
Mariano
17c36b5093 Gateway: track background task lifecycle (#52518)
Merged via squash.

Prepared head SHA: 7c4554204e
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Co-authored-by: mbelinky <132747814+mbelinky@users.noreply.github.com>
Reviewed-by: @mbelinky
2026-03-29 12:48:02 +02:00
Peter Steinberger
b12f3ce6e5 fix(gateway): support synthetic chat origins 2026-03-28 05:23:55 +00:00
Gustavo Madeira Santana
21c00165ef test: fix gateway handler and typing lease helper types 2026-03-28 01:11:24 -04:00
Ayaan Zaidi
3a341355bf test(gateway): fill channels status handler options 2026-03-28 10:33:05 +05:30
Tak Hoffman
0bcf076901 fix(regression): auto-enable channel status state 2026-03-27 23:56:29 -05:00
Tak Hoffman
ff348d2063 fix(regression): auto-enable gateway send selection 2026-03-27 23:51:28 -05:00
Peter Steinberger
ec5877346c fix: harden mcp channel bridge smoke 2026-03-28 04:10:19 +00:00
Tak Hoffman
2638b566f1 fix(regression): canonicalize chat final session routing 2026-03-27 21:06:45 -05:00
Tak Hoffman
a0f48f099e fix(regression): canonicalize chat inject session routing 2026-03-27 21:04:16 -05:00
Tak Hoffman
d11dc8feba fix: summarize plugin tool descriptions in catalog 2026-03-27 20:32:50 -05:00
Tak Hoffman
ae9b9575c5 fix(regression): preserve gateway subagent session change metadata 2026-03-27 20:28:58 -05:00
Tak Hoffman
f4a45071e3 fix: preserve session thread ids in agent send events 2026-03-27 20:24:35 -05:00
Tak Hoffman
7fadb4f7ff fix(regression): preserve subagent session ownership metadata 2026-03-27 20:24:15 -05:00
Tak Hoffman
1fee91e431 fix: preserve session thread ids in sessions changed events 2026-03-27 20:21:07 -05:00
Tak Hoffman
53861607f6 fix: use origin thread metadata in tools effective context 2026-03-27 20:21:06 -05:00
Tak Hoffman
59cd79d37f fix: use session origin thread metadata in chat routing 2026-03-27 20:21:06 -05:00
Jacob Tomlinson
4d7cc6bb4f gateway: restrict node pairing approvals (#55951)
* gateway: restrict node pairing approvals

* gateway: tighten node pairing scope checks

* gateway: harden node pairing reconnects

* agents: request elevated node pairing scopes

* agents: fix node pairing approval preflight scopes
2026-03-27 19:14:16 +00:00
Jacob Tomlinson
7a801cc451 Gateway: disconnect revoked device sessions (#55952)
* Gateway: disconnect revoked device sessions

* Gateway: normalize device disconnect targets

* Gateway: scope token revoke disconnects by role

* Gateway: respond before disconnecting sessions
2026-03-27 19:01:26 +00:00
Josh Avant
6ade9c474c feat(hooks): add async requireApproval to before_tool_call (#55339)
* Plugins: add native ask dialog for before_tool_call hooks

Extend the before_tool_call plugin hook with a requireApproval return field
that pauses agent execution and waits for real user approval via channels
(Telegram, Discord, /approve command) instead of relying on the agent to
cooperate with a soft block.

- Add requireApproval field to PluginHookBeforeToolCallResult with id, title,
  description, severity, timeout, and timeoutBehavior options
- Extend runModifyingHook merge callback to receive hook registration so
  mergers can stamp pluginId; always invoke merger even for the first result
- Make ExecApprovalManager generic so it can be reused for plugin approvals
- Add plugin.approval.request/waitDecision/resolve gateway methods with
  schemas, scope guards, and broadcast events
- Handle requireApproval in pi-tools via two-phase gateway RPC with fallback
  to soft block when the gateway is unavailable
- Extend the exec approval forwarder with plugin approval message builders
  and forwarding methods
- Update /approve command to fall back to plugin.approval.resolve when exec
  approval lookup fails
- Document before_tool_call requireApproval in hooks docs and unified
  /approve behavior in exec-approvals docs

* Plugins: simplify plugin approval code

- Extract mergeParamsWithApprovalOverrides helper to deduplicate param
  merge logic in before_tool_call hook handling
- Use idiomatic conditional spread syntax in toolContext construction
- Extract callApprovalMethod helper in /approve command to eliminate
  duplicated callGateway calls
- Simplify plugin approval schema by removing unnecessary Type.Union
  with Type.Null on optional fields
- Extract normalizeTrimmedString helper for turn source field trimming

* Tests: add plugin approval wiring and /approve fallback coverage

Fix 3 broken assertions expecting old "Exec approval" message text.
Add tests for the /approve command's exec→plugin fallback path,
plugin approval method registration and scope authorization, and
handler factory key verification.

* UI: wire plugin approval events into the exec approval overlay

Handle plugin.approval.requested and plugin.approval.resolved gateway
events by extending the existing exec approval queue with a kind
discriminator. Plugin approvals reuse the same overlay, queue management,
and expiry timer, with branched rendering for plugin-specific content
(title, description, severity). The decision handler routes resolve calls
to the correct gateway method based on kind.

* fix: read plugin approval fields from nested request payload

The gateway broadcasts plugin approval payloads with title, description,
severity, pluginId, agentId, and sessionKey nested inside the request
object (PluginApprovalRequestPayload), not at the top level. Fix the
parser to read from the correct location so the overlay actually appears.

* feat: invoke plugin onResolution callback after approval decision

Adds onResolution to the requireApproval type and invokes it after
the user resolves the approval dialog, enabling plugins to react to
allow-always vs allow-once decisions.

* docs: add onResolution callback to requireApproval hook documentation

* test: fix /approve assertion for unified approval response text

* docs: regenerate plugin SDK API baseline

* docs: add changelog entry for plugin approval hooks

* fix: harden plugin approval hook reliability

- Add APPROVAL_NOT_FOUND error code so /approve fallback uses structured
  matching instead of fragile string comparison
- Check block before requireApproval so higher-priority plugin blocks
  cannot be overridden by a lower-priority approval
- Race waitDecision against abort signal so users are not stuck waiting
  for the full approval timeout after cancelling a run
- Use null consistently for missing pluginDescription instead of
  converting to undefined
- Add comments explaining the +10s timeout buffer on gateway RPCs

* docs: document block > requireApproval precedence in hooks

* fix: address Phase 1 critical correctness issues for plugin approval hooks

- Fix timeout-allow param bug: return merged hook params instead of
  original params when timeoutBehavior is "allow", preventing security
  plugins from having their parameter rewrites silently discarded.

- Host-generate approval IDs: remove plugin-provided id field from the
  requireApproval type, gateway request, and protocol schema. Server
  always generates IDs via randomUUID() to prevent forged/predictable
  ID attacks.

- Define onResolution semantics: add PluginApprovalResolutions constants
  and PluginApprovalResolution type. onResolution callback now fires on
  every exit path (allow, deny, timeout, abort, gateway error, no-ID).
  Decision branching uses constants instead of hard-coded strings.

- Fix pre-existing test infrastructure issues: bypass CJS mock cache for
  getGlobalHookRunner global singleton, reset gateway mock between tests,
  fix hook merger priority ordering in block+requireApproval test.

* fix: tighten plugin approval schema and add kind-prefixed IDs

Harden the plugin approval request schema: restrict severity to
enum (info|warning|critical), cap timeoutMs at 600s, limit title
to 80 chars and description to 256 chars. Prefix plugin approval
IDs with `plugin:` so /approve routing can distinguish them from
exec approvals deterministically instead of relying on fallback.

* fix: address remaining PR feedback (Phases 1-3 source changes)

* chore: regenerate baselines and protocol artifacts

* fix: exclude requesting connection from approval-client availability check

hasExecApprovalClients() counted the backend connection that issued
the plugin.approval.request RPC as an approval client, preventing
the no-approval-route fast path from firing in headless setups and
causing 120s stalls. Pass the caller's connId so it is skipped.
Applied to both plugin and exec approval handlers.

* Approvals: complete Discord parity and compatibility fallback

* Hooks: make plugin approval onResolution non-blocking

* Hooks: freeze params after approval owner is selected

* Gateway: harden plugin approval request/decision flow

* Discord/Telegram: fix plugin approval delivery parity

* Approvals: fix Telegram plugin approval edge cases

* Auto-reply: enforce Telegram plugin approval approvers

* Approvals: harden Telegram and plugin resolve policies

* Agents: static-import gateway approval call and fix e2e mock loading

* Auto-reply: restore /approve Telegram import boundary

* Approvals: fail closed on no-route and neutralize Discord mentions

* docs: refresh generated config and plugin API baselines

---------

Co-authored-by: Václav Belák <vaclav.belak@gendigital.com>
2026-03-27 09:06:40 -07:00
Jacob Tomlinson
4b9542716c Gateway: require verified scope for chat provenance (#55700)
* Gateway: require verified scope for chat provenance

* Gateway: clarify chat provenance auth gate
2026-03-27 10:13:34 +00:00
Tak Hoffman
6e5bc5647a fix: use session origin provider in chat delivery routing 2026-03-26 22:42:45 -05:00
Tak Hoffman
e1ff753790 fix: persist create transcript paths in session entries 2026-03-26 20:54:15 -05:00
Tak Hoffman
c326083ad8 fix: keep session settings in gateway live events 2026-03-26 20:11:13 -05:00
Tak Hoffman
48ff617169 fix: keep fast mode in gateway session rows 2026-03-26 20:11:13 -05:00
Peter Steinberger
0ef2a9c8b5 refactor: remove core browser test duplicates 2026-03-26 23:28:34 +00:00
Peter Steinberger
d1d0887932 refactor: remove legacy browser bridge entrypoints 2026-03-26 23:11:17 +00:00
Peter Steinberger
4b40d4dfa8 perf: optimize cold import paths 2026-03-26 23:11:00 +00:00
Peter Steinberger
09c186d5f9 refactor: remove browser compat shadow tree 2026-03-26 22:53:37 +00:00
Peter Steinberger
d72115c9df refactor: genericize speech provider config surface 2026-03-26 22:48:57 +00:00
Peter Steinberger
83ca6fbfc6 refactor: finish browser compat untangle 2026-03-26 22:42:41 +00:00
Peter Steinberger
0f5a77d058 refactor: route memory runtime through memory plugin 2026-03-26 22:30:47 +00:00
Peter Steinberger
2c6d099b01 refactor: plugin-own speech provider config 2026-03-26 22:28:24 +00:00
Peter Steinberger
8eeb7f0829 refactor: switch browser ownership to bundled plugin 2026-03-26 22:20:40 +00:00