Skip to content

open-edition-honest-degradation c3: anonymous-deny ordering inverted on /ai/** (unauth /ai/models → 501, /ai/agents → 200 instead of 401) #7653

Description

@huangyiirene

The degradation itself is honest and PASSES — please do not "fix" that half: /ai/models, /conversations, /usage, /chat all 501 with the Cloud/EE remedy sentence (mounted-but-unimplemented, never 404/503); /ai/agents returns the declared envelope with the relocated payload; and /discovery's services.ai message is string-identical to the 501 body. The defect below is only the ordering of the anonymous-deny gate.

Symptom

Unauthenticated callers reach the /ai/** family instead of being denied.

  • Observed: unauth GET /api/v1/ai/models501 (leaking the Cloud/EE remedy sentence); unauth GET /api/v1/ai/agents200. Reproduced twice.
  • Expected: both → 401.
  • Control (proves anonymous-deny is otherwise live on the same boot): anonymous GET /api/v1/data/showcase_task401, correctly.

Disclosure impact is limited to two static strings, but the ordering contract this item exists to pin is inverted.

Root cause

runtime/src/domains/ai.tshandleAIRequest returns the /ai/agents empty-list courtesy ({ agents: [] }) and capabilityUnavailable(deps, 'ai') at the top of the handler (around ai.ts:68-79), while the shouldDenyAnonymous gate lives inside the per-route loop further down (ai.ts:128) — reachable only when the AI service is serveable. So on every open-edition deployment the whole /ai/** family answers unauthenticated callers before the anonymous gate is ever consulted. Still present on origin/main (the courtesy + capabilityUnavailable return precedes the shouldDenyAnonymous check).

Reproduction

On a stock boot, with no Authorization header:

curl http://<host>/api/v1/ai/models # expected 401, actual 501
curl http://<host>/api/v1/ai/agents # expected 401, actual 200
curl http://<host>/api/v1/data/showcase_task # control: 401 (correct)

Source

Extracted from the QA run #7627 (framework 92f26f7, console 6314e87f).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions