fix(api): enforce image generation API key auth - #8306
diegosouzapw merged 2 commits into
Conversation
…8306 The complexity/cognitive-complexity baseline bumps (2130->2168, 951->956) reconcile pre-existing release-branch drift unrelated to this PR's image-generation API-key auth fix. Ratchet rebaselines are reserved for the release captain (owner-approved, see prior _rebaseline_* entries in these files) and are out of scope for a contributor branch. Reverting to the recorded baseline; the underlying drift is real (measured 2167/956 on origin/release/v3.8.49) and already tracked by the owner's open base-red slice PRs (diegosouzapw#8254, diegosouzapw#8256). Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
The route-level guard added for image generation was stricter than the authz middleware that already fronts /api/v1/* (src/proxy.ts → clientApiPolicy), so requests the pipeline admits were 401'd by the handler: - A cookie-authenticated dashboard session was rejected under REQUIRE_API_KEY=true. The dashboard Media page (dashboard/cache/media) and the Playground call these routes with a session and no Bearer — the same mismatch already fixed for /api/playground/presets. - A presented invalid key was rejected even with REQUIRE_API_KEY=false, where clientApiPolicy (diegosouzapw#2257) and the sibling /v1/embeddings and /v1/web/fetch routes degrade a stale CLI key to anonymous instead. Extract the shared guard into shared/utils/clientApiRouteAuth so both image routes (and future /v1 handlers) mirror the middleware contract instead of re-deriving it, and drop the now-dead auth imports. Also switch the call-log attribution fallback back to `||`: with `??`, an empty-string apiKeyId/apiKeyName would be persisted verbatim and would block the request-scoped context, which the previous `entry.apiKeyId || null` never did. Tests: cover the dashboard-session and keyless-mode-invalid-key branches, and split the auth/attribution cases into image-generation-route-auth.test.ts to stay under the 800-line new-test-file cap. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
d110762 to
cf5535b
Compare
Rebased onto current
|
CI on the rebased head: 4 red checks, all reproduced on an untouched baseEvery failure on Unit Tests fast-path (1/4) + (2/4) — 4 failures, identical on base:
These are the same three resilience regressions the dropped No new ESLint warnings — base fails identically:
Fast Quality Gates — What this PR's own scope reports
AskThe branch is now Happy to do either, your call: (a) merge/queue this on the understanding that the four reds are inherited, or (b) land the base repair first (as its own PR against |
|
Opened #8561 — a dedicated repair PR against It fixes three of the four reds at the source: the 3 stale backoff assertions (#8396 capped the cooldown and the tests were never updated), The complexity ratchet is deliberately untouched — per No production code is modified there: 2 test files, 1 allowlist entry, 2 quality baselines. Once #8561 lands I'll rebase this PR on top; nothing here changes in the meantime. |
* fix(api): enforce image generation API key auth * fix(api): align image route auth guard with clientApiPolicy The route-level guard added for image generation was stricter than the authz middleware that already fronts /api/v1/* (src/proxy.ts → clientApiPolicy), so requests the pipeline admits were 401'd by the handler: - A cookie-authenticated dashboard session was rejected under REQUIRE_API_KEY=true. The dashboard Media page (dashboard/cache/media) and the Playground call these routes with a session and no Bearer — the same mismatch already fixed for /api/playground/presets. - A presented invalid key was rejected even with REQUIRE_API_KEY=false, where clientApiPolicy (diegosouzapw#2257) and the sibling /v1/embeddings and /v1/web/fetch routes degrade a stale CLI key to anonymous instead. Extract the shared guard into shared/utils/clientApiRouteAuth so both image routes (and future /v1 handlers) mirror the middleware contract instead of re-deriving it, and drop the now-dead auth imports. Also switch the call-log attribution fallback back to `||`: with `??`, an empty-string apiKeyId/apiKeyName would be persisted verbatim and would block the request-scoped context, which the previous `entry.apiKeyId || null` never did. Tests: cover the dashboard-session and keyless-mode-invalid-key branches, and split the auth/attribution cases into image-generation-route-auth.test.ts to stay under the 800-line new-test-file cap. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: alexey.nazarov@softmg.ru <alexey.nazarov@softmg.ru> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* fix(api): enforce image generation API key auth * fix(api): align image route auth guard with clientApiPolicy The route-level guard added for image generation was stricter than the authz middleware that already fronts /api/v1/* (src/proxy.ts → clientApiPolicy), so requests the pipeline admits were 401'd by the handler: - A cookie-authenticated dashboard session was rejected under REQUIRE_API_KEY=true. The dashboard Media page (dashboard/cache/media) and the Playground call these routes with a session and no Bearer — the same mismatch already fixed for /api/playground/presets. - A presented invalid key was rejected even with REQUIRE_API_KEY=false, where clientApiPolicy (diegosouzapw#2257) and the sibling /v1/embeddings and /v1/web/fetch routes degrade a stale CLI key to anonymous instead. Extract the shared guard into shared/utils/clientApiRouteAuth so both image routes (and future /v1 handlers) mirror the middleware contract instead of re-deriving it, and drop the now-dead auth imports. Also switch the call-log attribution fallback back to `||`: with `??`, an empty-string apiKeyId/apiKeyName would be persisted verbatim and would block the request-scoped context, which the previous `entry.apiKeyId || null` never did. Tests: cover the dashboard-session and keyless-mode-invalid-key branches, and split the auth/attribution cases into image-generation-route-auth.test.ts to stay under the 800-line new-test-file cap. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: alexey.nazarov@softmg.ru <alexey.nazarov@softmg.ru> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Summary
REQUIRE_API_KEYand reject invalid presented keys on the canonical and provider-scoped image generation routes.api_key_idandapi_key_name.shared/utils/clientApiRouteAuth) that mirrors theclientApiPolicycontract, so the handler check can never be stricter than the authz middleware already fronting/api/v1/*.Related Issues
release/v3.8.49, as requested in fix(api): enforce image generation API key auth #8293.Validation
tests/unit/image-generation-route*.test.ts: 24/24 passingcall-log*+tests/unit/usage/**: 68/68 passingnpm run typecheck:coreeslinton all changed filesnpm run check:file-size—[test-file-size] OKcheck-docs-sync,check:any-budget:t11,check-tracked-artifactsTests Added Or Updated
tests/unit/image-generation-route-auth.test.ts(new — split out of the main image-route suite to stay under the 800-line new-test-file cap)REQUIRE_API_KEY=trueREQUIRE_API_KEY=trueREQUIRE_API_KEY=false(matchesclientApiPolicy, [BUG] invalid api key in Codex Desktop auto config #2257)REQUIRE_API_KEY=truetests/unit/image-generation-route.test.ts— keeps the CORS preflight coverage for the three image-routeOPTIONShandlers.Coverage Notes
The tests cover every branch of the shared guard (valid key / invalid key × enforcement on-off / dashboard session / anonymous), successful call-log attribution on both routes, and the
OPTIONShandlers that keep the function-coverage ratchet from regressing. The coverage baseline was not changed.Reviewer Notes
Scope is the image routes, the shared client-API route guard, call-log attribution, and their tests — 7 files. The earlier release-repair commits are dropped; that set lives in #8307 and the base has since resolved most of it. This branch is rebased on the current
release/v3.8.49head and merges cleanly.Image provider handlers emit call logs in multiple provider-specific branches.
AsyncLocalStoragekeeps validated key identity request-scoped and concurrency-safe without threading attribution arguments through every handler. Explicit call-log API-key fields still take precedence. No schema or migration changes are required.check:complexity-ratchetsand twocheck:file-sizefreezes (dashboard/providers/page.tsx,lib/tokenHealthCheck.ts) fail identically on a cleanorigin/release/v3.8.49checkout — inherited base-red, deliberately not touched here.