fix(security): add IPC policy entries for daemon OAuth connect routes#29612
Merged
credence-the-bot[bot] merged 1 commit intoMay 5, 2026
Conversation
Codex P1 on PR #29596: #29596 (comment)... (see latest review) The new daemon-owned OAuth connect HTTP routes added in this branch (internal_oauth_connect_start, internal_oauth_connect_status) are gateway-only on the daemon HTTP path (internal.write + svc_gateway, enforced via daemon-side route-policy), but the gateway IPC proxy default-allows operationIds without an entry in this policy table. Without these entries, an authenticated edge JWT could reach the new routes by setting X-Vellum-Proxy-Server: ipc, bypassing the daemon's HTTP router entirely (same class of bug as #29571 fixed for the MCP OAuth routes). Mirrors Noa's fix in #29571.
Contributor
Author
|
@chatgpt-codex-connector review This is the targeted fix for the P1 you flagged on #29596 (IPC policy entries for the new daemon OAuth connect routes). 4-line additive change, mirrors the pattern from #29571. All 6 tests pass locally. Once this lands, #29596 auto-updates and is ready for your re-review pass. |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
7403265
into
credence-the-bot/oauth-connect-daemon-flow
14 checks passed
Merged
5 tasks
noanflaherty
pushed a commit
that referenced
this pull request
May 5, 2026
…ay` through daemon IPC (#29596) * fix(oauth): route `assistant oauth connect --callback-transport=gateway` through daemon IPC (#29570) * fix(oauth): route assistant oauth connect --callback-transport=gateway through daemon IPC * fix(oauth-connect): pass lint, type-check, and openapi-check - Sort imports per simple-import-sort/imports rule (autofix) - Add eslint-disable for the intentionally-let resolvedState binding - Narrow OAuthConnectResult union before reading .error (split into two if branches) - Narrow OAuthConnectStatusResponse before reading .error in CLI poll loop - Regenerate openapi.yaml to include the 2 new internal routes * fix: use operationId and structured params for cliIpcCall (Devin/Codex P1 review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: thread grantedScopes through IPC path to avoid empty-scopes inconsistency (Devin review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(oauth): align IPC poll timeout with 5-min loopback OAuth window (Codex review) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: credence-the-bot <credence@vellum.ai> Co-authored-by: credence-the-bot[bot] <183148327+credence-the-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: surface daemon errors instead of silent fallback; add gateway transport test and policy tests (#29590) Co-authored-by: credence-the-bot <credence@vellum.ai> * fix: add defensive guards for poll daemon errors and ok:true missing auth_url (#29593) Co-authored-by: credence-the-bot <credence@vellum.ai> * test: add missing test coverage for oauth-connect daemon flow (round-3) (#29595) Co-authored-by: credence-the-bot <credence@vellum.ai> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: suppress browser-wait log in JSON mode; sweep expired OAuth state on insertion (#29597) * fix: suppress browser-wait log in JSON mode; sweep expired state on insert * test: make JSON-mode log suppression test exercise the actual if (!jsonMode) guard Configure the logger mock to write to process.stdout in the specific test so the test would fail if the guard were removed from connect.ts. Also reset mockLogInfo to no-op in beforeEach for test isolation. --------- Co-authored-by: credence-the-bot <credence@vellum.ai> * fix(oauth): replace 'Daemon' with 'assistant' in user-facing error strings (#29603) * fix(oauth): replace 'Daemon' with 'assistant' in user-facing error strings * test: update assertion to match new 'assistant' string from devin nit fix The previous commit replaced 'Daemon' with 'assistant' in user-facing error strings (per Devin review), but missed updating the test that asserts on the old 'Daemon returned unexpected response' wording. --------- Co-authored-by: credence-the-bot <credence@vellum.ai> Co-authored-by: credence-the-bot[bot] <credence-the-bot[bot]@users.noreply.github.com> * fix(security): add IPC policy entries for daemon OAuth connect routes (#29612) Closes Codex P1 on #29596 by adding IPC policy entries for the new daemon OAuth connect routes (`internal_oauth_connect_start`, `internal_oauth_connect_status`). Mirrors the pattern from #29571 for the MCP OAuth routes. 4-line additive change, 6/6 tests pass. Both Codex and Devin re-reviewed clean. --------- Co-authored-by: credence-the-bot[bot] <277301654+credence-the-bot[bot]@users.noreply.github.com> Co-authored-by: credence-the-bot <credence@vellum.ai> Co-authored-by: credence-the-bot[bot] <183148327+credence-the-bot[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: credence-the-bot[bot] <credence-the-bot[bot]@users.noreply.github.com> Co-authored-by: credence-the-bot[bot] <credence-the-bot@vellum.ai>
credence-the-bot Bot
pushed a commit
that referenced
this pull request
May 6, 2026
…outes The gateway IPC proxy default-allows operationIds that have no entry in `gateway/src/auth/ipc-route-policy.ts`. Daemon routes restricted to `svc_gateway` on the HTTP path are bypassable via IPC unless their operationId is also locked down here — an authenticated edge JWT can reach them by setting `X-Vellum-Proxy-Server: ipc`, sidestepping the daemon HTTP router entirely. This bug class has shipped twice already and been caught by Codex both times: - PR #29571 — `internal_mcp_auth_start/status/reload` - PR #29612 — `internal_oauth_connect_start/status` While auditing the daemon route policy I found six more gateway-only operationIds with no IPC policy entry: - `channel_inbound` (ingress.write, the only non-internal.write here) - `emit_event` - `internal_oauth_callback` - `internal_twilio_connect_action` - `internal_twilio_status` - `internal_twilio_voice_webhook` - `upgrade_broadcast` - `workspace_commit` This PR: 1. Adds the eight missing entries to `POLICY_TABLE`. 2. Adds a comment block in `ipc-route-policy.ts` documenting the invariant, so the next contributor sees it. 3. Extends the explicit test list in `ipc-route-policy.test.ts`. 4. Adds a new `ipc-route-policy-coverage.test.ts` lint test that walks the daemon route source files and asserts every gateway-only operationId has a matching IPC policy entry. Catches this class of regression without relying on Codex. The lint is text-based (regex over source files) because the gateway and assistant packages don't share source-level imports — they communicate via `@vellumai/service-contracts`. False positives only add coverage; false negatives would defeat the lint, so regexes are intentionally loose. Verification: simulated removing the existing `internal_mcp_reload` entry — lint correctly flagged it. Simulated removing one of the new entries — lint correctly flagged it. Both 32 tests pass on the final state.
noanflaherty
pushed a commit
that referenced
this pull request
May 6, 2026
…outes (#29754) * fix(gateway): close IPC policy coverage gap for gateway-only daemon routes The gateway IPC proxy default-allows operationIds that have no entry in `gateway/src/auth/ipc-route-policy.ts`. Daemon routes restricted to `svc_gateway` on the HTTP path are bypassable via IPC unless their operationId is also locked down here — an authenticated edge JWT can reach them by setting `X-Vellum-Proxy-Server: ipc`, sidestepping the daemon HTTP router entirely. This bug class has shipped twice already and been caught by Codex both times: - PR #29571 — `internal_mcp_auth_start/status/reload` - PR #29612 — `internal_oauth_connect_start/status` While auditing the daemon route policy I found six more gateway-only operationIds with no IPC policy entry: - `channel_inbound` (ingress.write, the only non-internal.write here) - `emit_event` - `internal_oauth_callback` - `internal_twilio_connect_action` - `internal_twilio_status` - `internal_twilio_voice_webhook` - `upgrade_broadcast` - `workspace_commit` This PR: 1. Adds the eight missing entries to `POLICY_TABLE`. 2. Adds a comment block in `ipc-route-policy.ts` documenting the invariant, so the next contributor sees it. 3. Extends the explicit test list in `ipc-route-policy.test.ts`. 4. Adds a new `ipc-route-policy-coverage.test.ts` lint test that walks the daemon route source files and asserts every gateway-only operationId has a matching IPC policy entry. Catches this class of regression without relying on Codex. The lint is text-based (regex over source files) because the gateway and assistant packages don't share source-level imports — they communicate via `@vellumai/service-contracts`. False positives only add coverage; false negatives would defeat the lint, so regexes are intentionally loose. Verification: simulated removing the existing `internal_mcp_reload` entry — lint correctly flagged it. Simulated removing one of the new entries — lint correctly flagged it. Both 32 tests pass on the final state. * test(ipc-route-policy-coverage): normalize :params + assert scope parity Address Codex P2 findings on PR #29754: 1. **Normalize parameterized endpoints before matching.** Daemon routes declare endpoints like `internal/oauth/connect/status/:state` while the daemon's route-policy keys drop the param segment. The previous match silently excluded `:state`, `:serverId`, `:runId` routes from the lint — exactly the parameterized gateway-only routes it was meant to guard. Strip `/:param` segments before lookup. 2. **Assert IPC requiredScopes match daemon requiredScopes.** Previously only principals were checked. If a future gateway-only route's IPC entry uses a broader scope than the daemon HTTP path requires, the IPC path is more permissive than HTTP — recreating the scope-bypass class this guard was designed to prevent. Now each test asserts the IPC scope set equals the daemon scope set. Coverage now includes the previously-missed parameterized routes (internal_mcp_auth_status, internal_oauth_connect_status, and the four profiler_runs_by_runId_* routes). Total: 19 gateway-only routes linted with 56 assertions, up from 17 routes / 35 assertions. * fix(test): widen Scope[] to string[] for toEqual comparison bun's typed expect inferred Scope[] from policy!.requiredScopes, then rejected daemonScopes (string[] from text-parsed daemon source) at the toEqual call. Both compare structurally as strings — annotate both locals as string[] to satisfy tsc. --------- Co-authored-by: credence-the-bot[bot] <207016121+credence-the-bot[bot]@users.noreply.github.com> Co-authored-by: credence-the-bot[bot] <credence-the-bot[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses Codex P1 on PR #29596: the new daemon-owned OAuth connect routes (
internal_oauth_connect_start,internal_oauth_connect_status) registered inassistant/src/runtime/routes/oauth-connect-routes.tsare gateway-only on the daemon HTTP path (internal.write+svc_gateway), but the gateway IPC proxy default-allows operationIds without an entry inPOLICY_TABLE.Without these entries, an authenticated edge JWT can reach the new routes by setting
X-Vellum-Proxy-Server: ipc, bypassing the daemon's HTTP router entirely.Same class of bug as #29571 fixed for the MCP OAuth routes a few hours earlier. Same fix pattern.
Changes
gateway/src/auth/ipc-route-policy.ts: Add 2 entries toPOLICY_TABLErequiringinternal.writescope andsvc_gatewayprincipal.gateway/src/__tests__/ipc-route-policy.test.ts: Extend the existingtest.each(added in fix(security): add IPC policy entries for daemon MCP OAuth routes #29571) to cover the 2 new operationIds.Test results
All existing tests in this file still pass (admin_rollback + 3 MCP entries + 2 new OAuth connect entries = 6 cases).
Why this targets the feature branch and not main
This branch (
credence-the-bot/oauth-connect-daemon-flow) is the feature branch for #29596 — the OAuth connect daemon-flow work that introduces the new routes. Routing this fix into the feature branch keeps the security guarantee atomic with the route introduction.