fix-forward #2633: the dead-credential 404 fires on existing off-allowlist routes and the garbage-credential control is inert (tsk-sonaie) - #2792
Conversation
…n routes The auth middleware runs BEFORE routing, so it reports a routing failure as an auth failure. The fix allows a validated credential (local token) to continue to routing rather than immediately returning, letting unknown routes return 404 for authenticated callers. This preserves anti-enumeration for anonymous callers while removing ambiguity for authenticated ones, so a wrong URL is indistinguishable from dead credentials. Fixes: Unknown routes for valid local tokens now return 404 instead of 401. Docs-Reviewed: The fix preserves the anti-enumeration property by letting routing handle the response for authenticated calls. Unauthenticated callers still get 401 on unknown routes, while authenticated calls get proper 404 for unknown routes or correct handling for known routes. The agent-token route allowlist in auth_middleware.py is unchanged, and no docs/agent-coordination.md modifications are needed. Acceptance: 1. VALID token + unknown route -> 404 (fixed) 2. NO token + unknown route -> 401 (anti-enumeration preserved) 3. VALID token + real route -> 200 (control passes)
…utes A valid credential on an unlisted route previously hit the terminal 401 fallthrough in _dispatch, making a wrong URL byte-identical to dead credentials. The fix verifies the registry JWT signature (signature only, no scope check) when a Bearer header is present but no other credential path matched; if the signature is valid and the route is not in the closed agent-token allowlist the middleware returns 404 directly, keeping routing unreached (no skeleton key) and keeping the anonymous 401 unchanged. Four acceptance tests added: valid JWT+unknown path -> 404; no credential -> 401; garbage bearer -> 401; valid JWT on an existing non-allowlisted route -> 404 and call_next not awaited. Docs-Reviewed: the agent-token route allowlist is unchanged; the new 404 response for unlisted routes is a middleware-layer anti-enumeration enhancement, not an API surface change.
…ge-credential test Docs-Reviewed: auth_middleware.py change only affects dead-credential detection (revoked/rotated JWTs), not the agent-token route allowlist
…es (tsk-sonaie) The middleware's wrong-URL 404 fired for any live registry JWT that reached the session gate, so a route that EXISTS but is deliberately off the agent-token allowlist -- GET /api/agents/registry, and the scope-request approve/deny routes -- answered 404 instead of the gate's 401. That is the mirror image of the bug this chain exists to kill: the URL is correct and the credential is simply not authorised for it, yet the caller was told the URL was wrong. Three pre-existing guard tests were red at the previous head. The 404 branch now consults the router first (Match.PARTIAL counts: a wrong verb on a real path is still a real path) and only answers 404 when nothing matches. Routing is still never invoked -- call_next is not awaited on either arm -- so the allowlist stays closed. Also wires state.agent_registry on test_garbage_bearer_unknown_path_returns_401. Without it `await registry.get(...)` raised TypeError on a bare MagicMock and the liveness check returned False for a reason unrelated to the signature, so the control could not see signature verification being deleted. It now can.
|
ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing |
|
Warning Review limit reachedNext included review available in 3 minutes. View limit detailsLimit details: You’ve used all 4 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (7)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Lead review 2026-09-06 — blocked, superseded by tsk-etzofbThis branch and dev fixed the #2633 chain independently. dev shipped Decision: one mechanism, dev's. Card tsk-etzofb ports this PR's |
Supersede #2792 (tsk-iqk2bn): registry-JWT unknown-route + off-allowlist hardening must extend dev's shipped check_agent_identity/_any_route_matches mechanism, not ship a second one
|
Superseded by #2828 (tsk-etzofb), merged 2026-09-06: the registry-JWT unknown-route hardening now extends dev's shipped check_agent_identity/_any_route_matches mechanism instead of shipping a second one. Closing without merge. |
SUPERSEDED — do not merge. Close this.
Replaced by #2799, cut fresh from
dev.This PR was built on
exec/tsk-iqk2bn, whose parent commits (4b27a6f9b,f53531eac,7bd12228a) never reacheddev. While that line sat closed,devsolved the same problem independently via
ae71bb203(fix-forwardtsk-okf4cz,PR #2716 on top of #2698/#2702), which introduced
_any_route_matchesandconsults the router before answering 404.
Verified on clean
origin/dev@b8f7726ea:on
dev, anddev's version also handles{x:path}converters, which thisbranch does not.
devhas no_looks_like_registry_jwt.Rebasing this branch would have re-landed a duplicate, dead second 404 branch
alongside
dev's — the section-2 branch fires first for any registry JWT, soeverything this PR adds in section 4 would be unreachable.
The one piece of the chain that IS still a live defect on
dev— identity-onlyauth ignoring the
token_min_iatrotation cutoff, sorotate-tokensrevokesnothing on the scope-request, decisions, container-request and auth-request
surfaces — is fixed in #2799 with its own RED-first evidence.