Skip to content

fix(proxy): harden request, routing, and cache boundaries - #3251

Merged
kwakayama merged 21 commits into
mainfrom
codex/server-handlers-reconcile-20260802
Aug 2, 2026
Merged

fix(proxy): harden request, routing, and cache boundaries#3251
kwakayama merged 21 commits into
mainfrom
codex/server-handlers-reconcile-20260802

Conversation

@kojiwakayama

@kojiwakayama kojiwakayama commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • harden proxy asset delivery, metadata lookup, authorization, token resolution, renderer/server routing, retries, request draining, host/path parsing, and response forwarding with bounded work and fail-closed validation
  • retain admission ownership until discarded upstream bodies settle, including late responses, and route standalone forwarding through the same hop-by-hop and internal-header policy as combined mode
  • make the core token-cache contract extension-neutral, validate cache boundaries, bound resilient-cache recovery state, and require explicit extension activation instead of implicit Redis selection or memory fallback
  • update the Redis cache extension and standalone proxy composition with explicit activation metadata and fail-closed startup behavior while keeping core free of third-party dependencies
  • retire the invalid module batch endpoint with non-cacheable 410 Gone, restrict module-serving namespaces to GET and HEAD, and enforce dependency snapshot consistency for self-hosted library modules
  • bind every control-plane JWS to the exact uppercase HTTP method and canonical URL.pathname, including a two-phase authenticity then project-binding flow for custom domains
  • preserve caller-provided OAuth cancellation context for Error and primitive AbortSignal reasons, classify cancellation from owned controller state, and consolidate abort normalization behind the dependency-neutral shared utility

Breaking changes

  • CACHE_TYPE=redis is no longer accepted. Core supports memory or extension; selecting extension requires an already activated TokenCacheStore provider. REDIS_URL alone never activates a provider.
  • /_vf_modules/_batch now returns 410 Gone; its broken generator is no longer reachable.
  • module-serving endpoints reject methods other than GET and HEAD.
  • control-plane JWS payloads must include request_method and request_path. The method must be an uppercase HTTP token. The path must equal the exact canonical URL.pathname received at verification. Current control-plane routes are root-scoped. Host, scheme, and query are deliberately excluded. Legacy signatures missing either claim fail closed.

Security regression coverage

  • rejects replay of a valid resume signature against DELETE cancellation while leaving the run active
  • rejects replay across method, operation path, and run id at both proxy and authoritative handler boundaries
  • verifies canonical URL dot-segment behavior without treating scheme, host, or query as signed operation identity
  • authenticates custom-domain candidates before metadata lookup, then requires the resolved project audience and id before auth bypass or token forwarding
  • rejects missing, lowercase, oversized, non-canonical, and accessor-backed request bindings without invoking caller-controlled getters
  • strips hop-by-hop and Connection-owned headers in both proxy deployment modes and retains concurrency permits through hostile body cancellation

Validation

  • all 99 changed TypeScript files: deno check and deno lint; all 103 changed files: deno fmt --check
  • deno task typecheck and consumer typecheck against the built npm declarations
  • deno task lint:core-deps, dependency/module boundaries, extension contracts/capabilities, and architecture validation
  • expanded proxy/cache/serve regression suite: 119 passed / 492 steps
  • channels and internal-agents suites: 16 files / 164 steps
  • full server-handler suite
  • cache, Redis extension, and proxy CLI suites: 126 files / 591 steps
  • runs, security, and server-runtime suites: 103 files / 1,409 steps
  • full documentation validation, including all 1,195 links
  • full source/CLI/integration sweep: 3,471 passed / 28,505 steps before one independently reproducible failure in untouched src/discovery/auto-discovery.integration.test.ts
  • exact-head follow-up: focused OAuth/abort suite (6 tests / 30 steps), full proxy suite (46 files / 455 steps), full agent runtime suite (317 tests / 594 steps), Redis extension and CLI composition (3 files / 31 steps), server module/snapshot and control-plane auth suites (7 files / 133 steps), and deno task verify:quick

Existing mainline gate debt

  • root deno task test scans scripts/build/build-npm-extension-packages.ts, whose #dnt alias currently exists only in scripts/test.deno.json; this branch does not modify the script or either config
  • the duplicate-webhook discovery assertion above reproduces alone and this branch has no discovery/webhook diff

@kojiwakayama
kojiwakayama requested a review from kwakayama as a code owner August 2, 2026 13:01

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6edb42bbce

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread src/server/handlers/request/lib-modules.handler.ts Outdated
Base automatically changed from codex/modules-resolution-hardening-20260802 to main August 2, 2026 13:49
Copilot AI review requested due to automatic review settings August 2, 2026 14:46
@kojiwakayama
kojiwakayama force-pushed the codex/server-handlers-reconcile-20260802 branch from 55d5780 to 7063645 Compare August 2, 2026 14:46
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact head 706364513b65a277163e67c8ac6f7af931143911, with particular attention to the required request_method + canonical request_path JWS binding, prefix/proxy canonicalization, and resume-to-cancel replay rejection.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens Veryfront’s proxy and control-plane boundaries by tightening request validation, method/path binding for JWS verification, and making the token-cache contract explicitly extension-activated (fail-closed) rather than implicitly Redis-activated or memory-fallback driven.

Changes:

  • Bind control-plane JWS trust to the exact uppercase HTTP method and canonical URL.pathname, and add regression tests for replay across methods/paths.
  • Replace implicit Redis cache selection with an explicit CACHE_TYPE=extension contract-driven token-cache model, including explicit standalone CLI activation/teardown.
  • Retire the /_vf_modules/_batch endpoint with a non-cacheable 410 Gone, restrict module-serving namespaces to GET/HEAD, and harden proxy header/body handling (cache-control parsing, hop-by-hop stripping, request draining, retries).

Verification (not run in this review environment):

  • deno task test -- tests/docs/
  • deno test --no-check --allow-all (or the repo’s full test command used in CI)

Reviewed changes

Copilot reviewed 95 out of 95 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/utils/project-identity.test.ts Adds tests for project slug/opaque id normalization and bounds.
src/utils/permit-semaphore.ts Introduces a bounded FIFO permit semaphore with abort/timeout handling.
src/utils/permit-semaphore.test.ts Tests semaphore capacity validation, timeout validation, FIFO ordering.
src/utils/lru-wrapper.ts Adds generic option typing and supports estimateSizeOf for byte eviction.
src/utils/lru-wrapper.test.ts Tests byte-bound eviction using a custom size estimator.
src/utils/abort.ts Adds abort-reason normalization and abortable awaiting helpers.
src/utils/abort.test.ts Tests abort error normalization and cancellation winning behavior.
src/server/handlers/utils/dependency-snapshot-protocol.ts Ensures HEAD conflict responses have no body.
src/server/handlers/utils/dependency-snapshot-protocol.test.ts Adds a HEAD response-body regression test.
src/server/handlers/request/project-run-execute.handler.test.ts Updates control-plane signature construction to include method/path binding.
src/server/handlers/request/module/module.handler.ts Restricts module namespaces to GET/HEAD; wires removed batch endpoint handler.
src/server/handlers/request/module/module.handler.test.ts Tests method restriction and removed batch endpoint tombstone behavior.
src/server/handlers/request/module/batch-module-handler.ts Implements 410 Gone tombstone and method restriction for batch endpoint.
src/server/handlers/request/lib-modules.handler.ts Adds method restriction and snapshot-protocol based dependency pin enforcement.
src/server/handlers/request/internal-agents-list.handler.test.ts Forces control-plane signatures in tests to include request bindings.
src/server/handlers/request/internal-agent-run.test-helpers.ts Extends signature helper to include request method/path claims.
src/server/handlers/request/agent-stream.handler.test.ts Updates resume signature tests with method/path binding.
src/server/handlers/request/agent-run-resume.handler.test.ts Updates helper wrapper to supply method/path defaults for resume.
src/server/handlers/request/agent-run-cancel.handler.test.ts Adds replay regression test (resume signature vs DELETE cancel) and updates bindings.
src/proxy/upstream-error-response.test.ts Tightens error response headers (content-type charset, no-store).
src/proxy/token-priority.test.ts Updates metadata expectations (protected: false).
src/proxy/timing.ts Adds portable max timer delay constant for proxy timers.
src/proxy/server-resolver.test.ts Adds extensive resolver hardening tests: expiry, inflight bounds, body limits, unsafe inputs.
src/proxy/retry.ts Hardens retry classification against hostile errors and bounds retry count.
src/proxy/retry.test.ts Adds hostile accessor/proxy tests and retry-count validation tests.
src/proxy/response-headers.ts Replaces naive cache-control parsing with a bounded, strict parser.
src/proxy/response-headers.test.ts Tests malformed/ambiguous cache-control handling and quoted values.
src/proxy/response-body.ts Splits “fire-and-forget” cancel from “settled” drain, and tightens cancellation semantics.
src/proxy/request-path.ts Adds origin-form path normalization (single leading slash).
src/proxy/request-lifecycle.ts Uses ensureError for safe span errors on hostile throws.
src/proxy/request-lifecycle.test.ts Tests hostile non-Error throws are contained while preserving original rejection.
src/proxy/request-init.ts Adds duplex tagging for streamed request bodies for Node fetch portability.
src/proxy/request-init.test.ts Tests duplex tagging and ownership preservation for ReadableStream bodies.
src/proxy/request-host.ts Adds Host header canonicalization and validation for routing/token identity.
src/proxy/request-host.test.ts Tests host normalization, fallback behavior, and invalid authority rejection.
src/proxy/request-drain.ts Hardens drain timing validation and adds non-cacheable draining response headers.
src/proxy/request-drain.test.ts Tests new timing validation and server-close bounding behavior.
src/proxy/proxy-token-resolution.ts Hardens auth cookie parsing, passes abort signals to token waiters, typed missing-project classification.
src/proxy/proxy-token-resolution.test.ts Adds tests for bounded cookie parsing and cancellation propagation.
src/proxy/oauth-client.ts Hardens OAuth token fetch: URL/timeout validation, bounded body reads, caller abort propagation, sanitized errors.
src/proxy/oauth-client.test.ts Adds tests for malformed responses, oversized body, sanitized errors, and invalid policies.
src/proxy/mode-parity.test.ts Adds parity tests for cancellation propagation and streaming body forwarding.
src/proxy/main.ts Switches to explicit extension cache activation acquisition and renderer router creation helper.
src/proxy/local-project-resolver.ts Hardens local project discovery inputs, bounds config, isolates discovery caches, adds disable switch.
src/proxy/local-project-resolver.test.ts Adds tests for traversal slugs, inherited entries, operational fs failures, per-resolver cache isolation.
src/proxy/hop-by-hop-headers.ts Introduces strict hop-by-hop and Connection-owned header stripping.
src/proxy/hop-by-hop-headers.test.ts Tests hop-by-hop stripping behavior.
src/proxy/error-response.ts Makes proxy error responses non-cacheable, adds nosniff, and tightens redirect headers.
src/proxy/error-response.test.ts Tests new cache/no-sniff/redirect header behavior.
src/proxy/control-plane-signature.ts Adds method/path-aware route classification and uses shared signature verifiers with audience/project binding.
src/proxy/control-plane-signature.test.ts Adds extensive tests for binding, route classification, and replay rejection.
src/proxy/cache/validation.ts Adds strict cache boundary validation/snapshotting utilities for hostile contracts.
src/proxy/cache/types.ts Changes cache type contract to memory or extension; removes redis inline options.
src/proxy/cache/tracing-cache.ts Snapshots cache ops, validates inputs/outputs, adds close ownership controls.
src/proxy/cache/tracing-cache.test.ts Adds tests for snapshotting, accessor rejection, stat/entry validation, close semantics.
src/proxy/cache/memory-cache.ts Hardens memory cache: validates options, enforces bounds, LRU recency refresh, idempotent close.
src/proxy/cache/memory-cache.test.ts Adds tests for immutable snapshots, accessor rejection, LRU behavior, close behavior, policy validation.
src/proxy/cache/index.ts Implements explicit extension-vs-memory cache selection and fail-closed extension mode.
src/proxy/cache/index.test.ts Adds tests for fail-closed extension mode and ownership semantics.
src/proxy/cache/extension-store.ts Adds explicit extension store acquisition gated by CACHE_TYPE=extension.
src/proxy/cache/extension-store.test.ts Tests acquisition gating, fail-closed behavior, and hostile inputs.
src/internal-agents/control-plane-auth.ts Adds request method/path binding to downstream JWS verification options.
src/internal-agents/control-plane-auth.test.ts Updates tests for canonical path binding and method inclusion.
src/extensions/cache/token-cache-store.ts Updates TokenCacheStats type to memory or extension.
src/channels/control-plane.test.ts Adds method/path binding tests and introduces signature-only verifier tests.
src/cache/verified-api-credential-context.test.ts Updates control-plane request tests to include explicit method.
src/cache/backend.test.ts Updates control-plane request tests to include explicit method.
extensions/ext-cache-redis/src/redis-cache.ts Updates reported cache type to extension.
extensions/ext-cache-redis/src/index.ts Makes missing Redis config a setup error; updates env reading behavior.
extensions/ext-cache-redis/src/index.test.ts Adds manifest parity test and updates behavior to fail-closed on missing config.
extensions/ext-cache-redis/README.md Updates docs for explicit activation and contract details.
extensions/ext-cache-redis/deno.json Marks extension activation as explicit in manifest metadata.
docs/guides/extensions.md Updates extension usage examples and contract family naming.
cli/commands/serve/split-mode.ts Removes implicit Redis env requirements/static env for split mode.
cli/commands/serve/split-mode.test.ts Asserts split mode does not force CACHE_TYPE.
cli/commands/serve/proxy-extension-composition.ts Adds explicit activation composition for standalone proxy cache extension.
cli/commands/serve/proxy-extension-composition.test.ts Tests explicit activation and borrowed store semantics.
cli/commands/serve/command.ts Activates selected proxy cache extension before importing proxy runtime; ensures teardown on startup failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread extensions/ext-cache-redis/README.md
Comment thread extensions/ext-cache-redis/README.md Outdated
Comment thread docs/guides/extensions.md Outdated
Comment thread src/proxy/cache/resilient-cache.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed
Comment thread src/proxy/cache/resilient-cache.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed
Comment thread src/proxy/renderer-router.ts Fixed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 706364513b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

Comment thread src/proxy/handler.ts Outdated
Copilot AI review requested due to automatic review settings August 2, 2026 15:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 98 out of 98 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/utils/permit-semaphore.ts:107

  • The abort-path promise rejection uses signal?.reason directly, which can be any value (including non-Error). To keep error handling consistent for callers, reject with a normalized AbortError/Error instance instead of an arbitrary value.
    src/utils/permit-semaphore.ts:71
  • When an AbortSignal is already aborted, this throws signal.reason directly. Abort reasons are allowed to be non-Error values, so callers may end up catching a non-Error rejection/throw. Normalize the abort reason to an Error instance (consistent with other abort helpers in the codebase).

This issue also appears on line 105 of the same file.
src/utils/abort.ts:17

  • createAbortError() / throwIfAborted() appear to duplicate the existing implementations in src/agent/runtime/error-utils.ts. Keeping two copies risks behavioral drift; consider consolidating behind a single shared utility or re-exporting one from the other.

Copilot AI review requested due to automatic review settings August 2, 2026 15:07
@kojiwakayama
kojiwakayama force-pushed the codex/server-handlers-reconcile-20260802 branch from a77f9f8 to 8b6e630 Compare August 2, 2026 15:07
@kojiwakayama

kojiwakayama commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact rebased head 8b6e6300183881b8eb125e24041fdeb9ea0cf55a, including the two-phase custom-domain JWS binding, admission ownership through body cancellation, split-mode header parity, Redis prefix validation, and the static-analysis remediations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 98 out of 98 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/utils/permit-semaphore.ts:107

  • The queued-abort path can also reject with a non-Error when AbortSignal.reason is a string/primitive. Reject with a normalized Error so downstream error handling is consistent.
    src/utils/permit-semaphore.ts:71
  • tryAcquire() can throw a non-Error when AbortSignal.reason is a string/primitive (because it throws signal.reason directly). That makes abort handling inconsistent and can break callers that assume an Error instance. Normalize the abort reason to an Error before throwing.

This issue also appears on line 105 of the same file.

Comment thread src/proxy/renderer-router.ts Fixed
Copilot AI review requested due to automatic review settings August 2, 2026 15:14
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact corrected head 026c52a5239ffcebeda9c65c4267a9b74a40fc85. The prior head was superseded by a re-entrancy-safe cache recovery owner: its shared promise is installed before extension callbacks and is covered by a synchronous callback regression.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 98 out of 98 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/proxy/request-host.ts:56

  • normalizeProxyRequestHost() returns parsed.hostname, which drops IPv6 brackets (for [::1]:8080 it returns ::1). The accompanying test expects [::1], and preserving brackets is also important if this value is later used as an HTTP Host authority (IPv6 literals require brackets to avoid colon ambiguity).

Copilot AI review requested due to automatic review settings August 2, 2026 15:18
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact head 430c487269175cafa1c79a8f9d42906fa83a5d8e. Since the prior reviewed head, recovery now also joins work started by a reentrant injected clock callback, and both uint64 hash wraps use explicit modulo 2^64 arithmetic. Independent review is clear; all 95 changed TypeScript files, root typecheck, and the 44-file / 471-step proxy-cache-serve suite pass.

@kojiwakayama
kojiwakayama force-pushed the codex/server-handlers-reconcile-20260802 branch from 430c487 to 63fe3f1 Compare August 2, 2026 15:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 98 out of 98 changed files in this pull request and generated 1 comment.

Comment thread src/proxy/cache/index.ts
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact rebased head 63fe3f160d33fe93a03d33e828c78ce0df1841ee. This is the same independently reviewed 15-commit delta replayed conflict-free over current main (e44480d28); the two new base commits have no changed-file overlap. Post-rebase root typecheck, all 95 changed-file checks/lint, 98-file format check, dependency/extension/architecture gates, and the 44-file / 471-step proxy-cache-serve suite all pass.

Copilot AI review requested due to automatic review settings August 2, 2026 16:34
@kojiwakayama
kojiwakayama force-pushed the codex/server-handlers-reconcile-20260802 branch from 8ddfab8 to 26eacdd Compare August 2, 2026 16:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 103 out of 103 changed files in this pull request and generated no new comments.

Suppressed comments (2)

src/proxy/oauth-client.ts:194

  • On caller-driven aborts, a primitive abort reason (like a string) is currently converted into a generic "OAuth token request was aborted" DOMException, dropping the original cancellation message. Preserve a non-empty string reason in the thrown AbortError message (or normalize via createAbortError(config.signal?.reason)).
    src/proxy/oauth-client.ts:119
  • When the abort signal carries a primitive reason (e.g. a string), this branch replaces it with a generic DOMException message. That loses caller-provided cancellation context and is inconsistent with createAbortError() behavior used elsewhere in the proxy. Preserve a non-empty string reason in the thrown AbortError message (or use createAbortError(signal.reason)).

This issue also appears on line 189 of the same file.

CodeQL's abstract interpreter does not model hexadecimal BigInt literals
and reports them as undefined arithmetic operands
(js/implicit-operand-conversion). Match the decimal spelling already used
by the FNV-1a constants in src/cache/keys/utils.ts, which the same query
accepts. Values and hash outputs are unchanged.
Copilot AI review requested due to automatic review settings August 2, 2026 17:30
@kojiwakayama

kojiwakayama commented Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Collapsed/suppressed review audit is complete on exact head 731622a76652ebc1b5f4546630168878e94a1eb3.

  • Primitive semaphore abort reasons are normalized through the shared utility, with preflight and queued regressions.
  • The duplicate agent abort implementation is now a re-export of the dependency-neutral shared utility.
  • OAuth cancellation now keys classification off the owned controller state, preserves Error identity or a non-empty primitive reason both before fetch and during response-body reads, and preserves the first abort cause when timeout and caller cancellation race.
  • The IPv6 host concern does not reproduce: the supported URL implementation preserves brackets in hostname, and the focused [::1]:8080 -> [::1] regression passes.
  • Standalone cache-extension teardown is registered with the proxy shutdown owner and covered for normal teardown, registration failure, disposal failure, re-entry, and hostile intrinsic mutation.
  • The drain timeout diagnostic now says “non-negative decimal integer.”
  • Redis prefix constraints, extension-store ownership, resilient-cache re-entry fencing, workflow module path, custom-domain signature rebinding, and uint64 routing vectors all have focused passing regressions.

Local exact-head validation: focused OAuth/abort 6 tests / 30 steps; proxy 46 files / 455 steps; agent runtime 317 tests / 594 steps; Redis plus CLI composition 3 files / 31 steps; server module/snapshot plus control-plane auth 7 files / 133 steps; deno task verify:quick passed. GraphQL reports 0 unresolved review threads.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 104 out of 104 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/proxy/oauth-client.ts:176

  • The OAuth success-path content-type check is case-sensitive (contentType !== "application/json"). HTTP media types are case-insensitive, and other proxy codepaths (for example src/proxy/project-metadata-client.ts) normalize to lowercase before comparing. As written, a valid response like Content-Type: Application/JSON; charset=utf-8 would be rejected and the body would be canceled.

Copilot AI review requested due to automatic review settings August 2, 2026 17:36
@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@codex review

Please review exact head 731622a76652ebc1b5f4546630168878e94a1eb3. Since the prior reviewed head, OAuth cancellation now preserves primitive caller reasons, classifies aborts from owned controller state, keeps the first abort cause stable across timeout/caller races, and the agent runtime reuses the shared dependency-neutral abort utility. Focused and broad exact-head validation is recorded in the PR body.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 104 out of 104 changed files in this pull request and generated no new comments.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 731622a766

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

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".

@kojiwakayama

Copy link
Copy Markdown
Contributor Author

@kwakayama #3251 is ready for independent code-owner approval at exact head 731622a76652ebc1b5f4546630168878e94a1eb3. All required CI passes, Copilot and Codex exact-head reviews are clean, and GraphQL reports 0 unresolved review threads. All 21 commits are authored by Koji, so your approval is the remaining merge-queue gate.

@kwakayama
kwakayama enabled auto-merge August 2, 2026 17:53
@kwakayama
kwakayama added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 99104f6 Aug 2, 2026
31 checks passed
@kwakayama
kwakayama deleted the codex/server-handlers-reconcile-20260802 branch August 2, 2026 18:03
kwakayama added a commit that referenced this pull request Aug 4, 2026
Every failure path in verifyInternalControlPlaneSignature returned a bare
`false`. An unconfigured verification key, a stripped x-token, a missing
signature header and a genuinely bad signature were indistinguishable,
with no log line at any of them.

That cost real time on veryfront-issue-inbox#356. veryfront-api was not
minting the request_method / request_path claims this repo began
requiring in 0.1.1189 (#3251), so the bypass never fired and protected
environments 302'd every control-plane run to the sign-in page. Nothing
in the logs distinguished that from a missing key or a config drift.

Failures now carry a reason: missing_x_token,
verification_key_not_configured, missing_signature_header or
signature_rejected. Ordinary non-internal routes stay silent.

Also adds a cross-repo contract test. control-plane-signature.test.ts
mints its own compliant JWS, so it proves the verifier works on a good
token but never that veryfront-api produces one — which is exactly the
gap that let #3251 ship. The new test mints the payload as veryfront-api
does and pins both sides together.

Refs veryfront-issue-inbox#356
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants