ADORSYS-GIS / ADORSYS-GIS/converse-frontends
[Story]: Console usage integration catches up with the authenticated query contract (and the proxy stops being a catch-all)
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 1h 49m
- Merged PRs (30d)
- 253
Description
### Story Statement
As a console user, I want the usage panels to keep working against the usage query API's new authenticated contract, and I want the console's proxy to expose only the routes it actually needs, so that a change in the backend contract doesn't silently break charts and the proxy can't be used as a pass-through to unrelated backend routes.
### Real Intent
On 2026-08-31 the usage query API changed materially (lightbridge-authz#603, #605, both merged):
1. `POST /usage/v1/usage/query` now **requires** `Authorization: Bearer ` and verifies the caller owns the `scope_id` — refusing with 403 otherwise. The console proxy already forwards the user's access token (`apps/console/src/server/proxy.ts`), so the happy path should keep working — but that is currently true by luck of an existing implementation detail, not by an asserted contract.
2. `UsageQueryResponse` gained a **required** `truncated: boolean` field (#578's fix: truncation now drops the oldest *whole* bucket instead of silently dropping the newest data). The generated client and any hand-maintained schema need to catch up, and the UI now has something honest to say when a chart is truncated.
3. `scope: "all"` was added (estate-wide, gated on the `usage:read-all` permission), and `scope: "api_key"` is now refused unconditionally.
Separately — and this is the security half — the console's usage proxy is a **catch-all** (`/api/usage/[...path]`). Its scope-ownership guard runs for exactly one path, by its own design note. That is how `/usage/v1/spend/query` was reachable through it for any signed-in user until lightbridge-authz#603 closed that server-side. The backend fix is authoritative and already merged; a path allowlist here is the defence-in-depth that stops the next backend route from being incidentally exposed the same way.
### Background and Context
The backend deliberately made the server the authoritative gate rather than relying on the console (see lightbridge-authz#570). This story is not "re-implement the check" — it is: don't break on the new contract, tell the user the truth about truncation, and stop proxying routes nobody asked for.
Note the backend's ownership predicate is deliberately **wider** than this console's existing guard (backend: owner **or** project roster member; console guard: owner only). That divergence is documented on both sides and is intentional — the console stays the tighter gate. Do not "fix" it by widening the console.
### Source of truth (links)
- lightbridge-authz#603 (bearer + ownership gate; spend-endpoint Authorization refusal; `truncated`)
- lightbridge-authz#605 (`scope: all`, `usage:read-all`)
- lightbridge-authz#570 (why the server is the authoritative gate)
- `docs/lightbridge-query-api.md` and `docs/usage-api.md` in lightbridge-authz (rewritten 2026-08-31, current)
- Related existing tickets here: #275 (give the proxy a client certificate), #274 (Overview shows real usage), #276 (honest unavailable states)
### Acceptance Criteria
- [ ] The generated/maintained usage client carries `truncated` and the `all` scope; a typecheck against the current backend OpenAPI passes with no hand-patching.
- [ ] A truncated result is **visible to the user** — a chart that came back truncated says so rather than silently rendering a short series. (Pairs with #276's honesty rule: never render a number that implies completeness when the response says otherwise.)
- [ ] The usage proxy serves a **path allowlist** — `/usage/v1/usage/query` and whatever else the console genuinely needs — and any other path returns 404 from the proxy without being forwarded. A test asserts an unlisted path (use `/usage/v1/spend/query`) is not proxied.
- [ ] A 401 or 403 from the backend renders as an explicit unavailable/not-permitted state, never as a zero and never as an empty chart (#276's contract, now reachable by two more status codes).
- [ ] The existing bearer-forwarding behaviour is **pinned by a test**, so a future proxy refactor cannot silently drop the header and turn every usage panel into a 401.
### Out of Scope
- Re-implementing scope-ownership in the console (the backend owns it; the console guard stays as defence-in-depth, unchanged in scope).
- The client-certificate work — that is #275.
- Anything requiring the local backend stack to be reachable; this can be developed against fixtures.
### Dependencies and Blockers
Backend is merged and deployed-safe (`ai-helm-values`#332 landed the config prerequisite). No blocker.
### Assumptions
1. The console's session always carries an access token by the time a usage panel renders — otherwise the panel needs an explicit signed-out state rather than a 401 surface. Verify against the current session handling rather than assuming.
### Implementation Notes
`apps/console/src/server/proxy.ts` is the catch-all; `usage-scope-guard.ts` holds the existing ownership guard whose own comment documents that it covers a single path. The allowlist belongs next to that guard so the two are read together.
### Test Expectations
- Unlisted-path proxy refusal, written to fail first (it passes through today).
- Bearer-forwarding pin.
- A truncated response renders the truncation state; a 403 renders not-permitted, not zero.
### Verification evidence
To be supplied by the implementing PR, including the fail-first output for the proxy-refusal test.
### Human accountable owner
Stephane Segning Lambou
### AI Usage Declaration
AI-assisted (Claude): drafted from findings raised by two adversarial reviews of lightbridge-authz#603 during the 2026-08-31 session (the catch-all proxy exposure and the client-regeneration coordination item). Backend behaviour was verified against merged code; the console-side details above were read from this repo but **not** executed — treat the implementation notes as leads to confirm, not as verified fact.
Contributor guide
Assessment
This issue has not been assessed yet.