Repository navigation
fix(runtime): an API-key caller of an api action whose target is an identity route is refused by name, before the forward - #28263
Conversation
…identity route is refused by name before the forward Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d1MkJvadehWmrLUUT1
…d changeset Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WV4d1MkJvadehWmrLUUT1
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 9 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 28 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ea2b409ec3ca9381e9025b7c1755216f348bcc40 && git checkout ea2b409ec3ca9381e9025b7c1755216f348bcc40
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 99a6a781b391083ed143ac8953041732dc745512 cf29292bf3ffa037981a8b10886843e113f72734 && git checkout -B drift-repro 99a6a781b391083ed143ac8953041732dc745512 && git merge --no-ff cf29292bf3ffa037981a8b10886843e113f72734
node scripts/docs-audit/affected-docs.mjs --json 99a6a781b391083ed143ac8953041732dc745512
|
|
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia Seat ACCEPT · PR #28263 · head
|
Requested by Elon · project thread
domain:server#3 · os-elon-musk · session_016WV4d1MkJvadehWmrLUUT1
Fixes #28217
Clause-②: no (a call that was already refused now says why and is refused before its target is called; no credential is newly accepted anywhere, and no error code, status name, answer member or package export is added)
Metadata-protocol: none
维护者速读
type: 'api'动作,如果目标是身份路由(/api/v1/auth/…,比如 Ban User),两个动作门(REST/actions和 MCPrun_action)在转发前就按名拒绝:401UNAUTHENTICATED,说明这个端点只接受已登录会话,不接受 API key。目标不会被调用。packages/runtime/src/action-execution.ts的forwardApiAction开头和apiActionIdentityRouteKeyRefusal。What changes
forwardApiAction(packages/runtime/src/action-execution.ts), the one forward both action doors call, now refuses one combination before it calls the target: a caller the door admitted by API key, running an action whosetargetis an identity route (under/api/v1/auth/). The answer is401with the standardUNAUTHENTICATEDcode and a sentence that names the action and its identity endpoint, says the endpoint accepts a signed-in session only and not an API key, and says the action was not run. Both doors relay it the way they relay a target's own refusal: the REST door answers it, and MCPrun_actionthrows it with the same status and code.isIdentityRouteTarget, which the existingorganizationIdstamp inbuildApiActionRequestnow reads too, so the two rules cannot disagree about which targets are identity routes.apiActionIdentityRouteKeyRefusal, a module export like the file's other refusal sentences (@objectstack/runtimeexports only its root entry, which does not re-export this module).content/docs/ai/actions-as-tools.mdx, theapirow of the dispatch table, says an API-key caller of an identity-route target is refused401before the forward.Unchanged: which credentials an identity route accepts. A signed-in session (session token or cookie) is forwarded to it exactly as before. An API-key caller is still forwarded to every target that is not an identity route, and served. This does not touch #28178 (the OAuth-agent lane), which is waiting on its own decision.
Why
An api action's forward carries the caller's own credentials so the target authorizes the same principal the door admitted. An identity route reads its caller from its own signed-in session only, so a key-admitted caller arrived there as nobody, and the target answered its anonymous
401("Sign in first") to a caller that had authenticated. It failed closed (triage 6530162284: a broken function, not a hole). Triage ruled that refusing by name before the forward, and pinning it, needs no decision, and that any change to which credentials an identity route accepts does.Verification
Premise re-checked on
main86cf7cefbefore the change; it held as the card states.packages/runtime/src/domains/api-action-forward.test.ts(+5): REST door, key-admitted caller of an identity-route action: the named401, the target never called; the same action for a session-admitted caller: forwarded as before; a key-admitted caller of a data-door target: forwarded with the key carried across. MCPrun_action: the key-admitted identity-route call throws the same refusal and forwards nothing; a key-admitted non-identity target is forwarded. 42/42.packages/qa/dogfood/test/api-action-door-forward.dogfood.test.ts(+2, booted showcase): an admin's API key runningban_usergets the named refusal, not "Sign in first", and nobody is banned; the same admin's API key running an api action whose target is the data door is served and the row changes. 10/10.pnpm --filter @objectstack/runtime typecheckgreen; the runtime suite green (487 files, 7912 passed); the dogfood package compiles with no error in the touched file.dispatch-gates --commandsderives (91) ran and exited 0, reconciled with--ran(0 NOT-MEASURED, after a whole-tree build);pnpm lintexits 0.Skills-docs:
grep -rniE "forward|api.?key" skills content/docsread for api-action forwarding and API-key callers:content/docs/ai/actions-as-tools.mdxdescribes the forward and gains the sentence above; no skill describes the forward or API-key callers of actions.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses.main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (Not touched.)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_016WV4d1MkJvadehWmrLUUT1