Skip to content

fix(api): let source-auth callers read runs under portal enforcement - #332

Open
xianjixiance wants to merge 2 commits into
yc-software:mainfrom
xianjixiance:fix/source-signed-run-queries
Open

fix(api): let source-auth callers read runs under portal enforcement#332
xianjixiance wants to merge 2 commits into
yc-software:mainfrom
xianjixiance:fix/source-signed-run-queries

Conversation

@xianjixiance

@xianjixiance xianjixiance commented Aug 11, 2026

Copy link
Copy Markdown

Problem

The run read routes declare source authentication, but they were also classified as user-scoped. When signed portal identity enforcement is enabled, a correctly source-signed caller without a portal identity is rejected before the run handler executes.

These read routes do not carry a caller-provided actor field, so the user-scoped classification adds a second authentication requirement without binding the request to a user.

Change

  • Remove GET /v1/runs/:id and GET /v1/runs from the user-scoped route table.
  • Add an integration regression covering source-signed reads, unsigned and incorrectly signed requests, a system turn submission, and a route that must remain user-scoped.

The write route POST /v1/runs/:id/signal keeps its existing classification.

Security

The read routes remain fail-closed. A request without a capability token still has to pass source-auth verification before it reaches the portal identity gate. The regression also provisions distinct source, capability, and portal identity secrets to exercise the production isolation contract.

Verification

  • node --test test/run-query-source-auth.test.ts — 7 passed, 0 failed
  • npm run typecheck
  • npm run lint
  • npm run lint:ox
  • git diff --check

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

GET /v1/runs/:id and GET /v1/runs are declared auth: "source" in the
turns route table, but they were also listed in USER_SCOPED. In
production requireSignedPortalIdentity is on, so the gate in server.ts
demanded a portal identity from callers that only hold the source-auth
signing secret, and a correctly signed surface request got 401. The two
routes carry no user-scoped field, so the entry only ever added the
portal requirement — it never bound a caller-named actor to the request.

Drop them from USER_SCOPED so the route table is the single source of
truth for how they authenticate. They stay fail closed: without a
capability token the request must still pass source-auth verification,
which runs before the portal gate. POST /v1/runs/:id/signal is a write
and keeps its existing classification.
…ource-auth fixture

createServer refuses to boot with portal identity enforcement on unless
CAPABILITY_SECRET, PORTAL_IDENTITY_SECRET and CORE_SIGNING_SECRET are three
distinct values, so the fixture cancelled during before(). Pass the same
core-only capability secret the other enforcement fixtures use. The suite's
security assertions are unchanged: the wrong-secret and unsigned cases still
expect 401, and the user-scoped route still demands a portal identity.
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.

1 participant