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)

Open
#435 2 comments 0 reactions 0 assignees View on GitHub
user-story
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.