# Console Workspaces API ## 1. Goals and scope Console workspaces provide tenant-scoped, read-only aggregates for operators and automation: - `/console/vuln/*` surfaces findings annotated with policy verdicts, VEX context, reachability signals, and evidence pointers. - `/console/vex/*` streams underlying VEX statements and summaries (optionally via SSE). All endpoints MUST: 1. Remain deterministic (stable sort keys, ISO-8601 UTC timestamps, stable identifiers). 2. Enforce tenant isolation for every request. 3. Be offline-friendly by supporting export flows and fixture-based operation in air-gapped environments. ## 2. Shared request/response conventions | Requirement | Description | | --- | --- | | Auth headers | `Authorization: Bearer ` and optional proof headers (e.g., `DPoP: `) depending on deployment profile. | | Tenant header | Required. See `docs/api/gateway/tenant-auth.md`; prefer `X-Stella-Tenant` (legacy alias: `X-StellaOps-Tenant`). | | Pagination | Cursor-based via `pageToken`; defaults to 50 items, max 200. Cursors are opaque, base64url, and signed. | | Sorting | Findings sorted by `(severity desc, exploitScore desc, findingId asc)`. Statements sorted by `(lastUpdated desc, statementId asc)`. | | Dates | RFC 3339 / ISO-8601 UTC (e.g., `2025-01-02T03:04:05Z`). | | Determinism | Arrays are pre-sorted; no server-generated random UUIDs in responses. | ## 3. Vulnerability workspace (`/console/vuln/*`) ### 3.1 `GET /console/vuln/findings` Query parameters: | Parameter | Type | Notes | | --- | --- | --- | | `pageToken` | string | Optional cursor from previous response. | | `pageSize` | int | 1-200, default 50. | | `severity` | string[] | `critical`, `high`, `medium`, `low`, `info`. | | `product` | string[] | SBOM `purl` or image digest anchors. | | `policyBadge` | string[] | `pass`, `warn`, `fail`, `waived`. | | `vexState` | string[] | `not_affected`, `fixed`, `under_investigation`, etc. | | `reachability` | string[] | `reachable`, `unreachable`, `unknown`. | | `search` | string | Substring match on CVE/GHSA/KEV id (case-insensitive). | Response body (example): ```jsonc { "items": [ { "findingId": "tenant-default:advisory-ai:sha256:5d1a", "coordinates": { "advisoryId": "CVE-2024-12345", "package": "pkg:npm/jsonwebtoken@9.0.2", "component": "jwt-auth-service", "image": "registry.local/ops/auth:2025.10.0" }, "summary": "jsonwebtoken <10.0.0 allows algorithm downgrade.", "severity": "high", "cvss": 8.1, "kev": true, "policyBadge": "fail", "vex": { "statementId": "vex:tenant-default:jwt-auth:5d1a", "state": "under_investigation", "justification": "Operator triage pending." }, "reachability": { "status": "reachable", "lastObserved": "2025-01-02T03:04:05Z", "signalsVersion": "signals-" }, "evidence": { "sbomDigest": "sha256:6c81deadbeef...", "policyRunId": "policy-run::", "attestationId": "dsse://authority/attest/" }, "timestamps": { "firstSeen": "2025-01-01T00:00:00Z", "lastSeen": "2025-01-02T03:05:06Z" } } ], "facets": { "severity": [ { "value": "critical", "count": 2 }, { "value": "high", "count": 7 } ], "policyBadge": [ { "value": "fail", "count": 6 }, { "value": "warn", "count": 3 }, { "value": "waived", "count": 1 } ], "reachability": [ { "value": "reachable", "count": 5 }, { "value": "unreachable", "count": 2 }, { "value": "unknown", "count": 1 } ] }, "nextPageToken": "eyJjdXJzb3IiOiJmZjg0NiJ9" } ``` ### 3.2 `GET /console/vuln/facets` Returns the full facet catalog (counts by severity, product, policy badge, VEX state, reachability, KEV flag). Designed for sidebar filters without paging; identical parameter surface as `/findings`. ### 3.3 `GET /console/vuln/{findingId}` Returns a full finding document, including evidence timeline, policy overlays, and export-ready metadata. ### 3.4 `POST /console/vuln/tickets` Create ticket/export payloads in a deterministic, auditable way. ```jsonc POST /console/vuln/tickets { "tenant": "tenant-default", "selection": [ "tenant-default:advisory-ai:sha256:5d1a", "tenant-default:advisory-ai:sha256:9bf4" ], "targetSystem": "servicenow", "metadata": { "assignmentGroup": "runtime-security", "priority": "P1" } } ``` ## 4. VEX workspace (`/console/vex/*`) ### 4.1 `GET /console/vex/statements` Parameters mirror `/console/vuln/findings` plus: | Parameter | Type | Notes | | --- | --- | --- | | `advisoryId` | string[] | CVE/GHSA/OVAL identifiers. | | `justification` | string[] | `exploit_observed`, `component_not_present`, etc. | | `statementType` | string[] | `vex`, `openvex`, `custom`, `advisory_ai`. | | `prefer` | string | `prefer=stream` enables chunked streaming (NDJSON). | Response (paged JSON): ```jsonc { "items": [ { "statementId": "vex:tenant-default:jwt-auth:5d1a", "advisoryId": "CVE-2024-12345", "product": "registry.local/ops/auth:2025.10.0", "status": "under_investigation", "justification": "exploit_observed", "lastUpdated": "2025-01-02T03:04:05Z", "source": { "type": "advisory_ai", "modelBuild": "aiai-console-", "confidence": 0.74 }, "links": [ { "rel": "finding", "href": "/console/vuln/findings/tenant-default:advisory-ai:sha256:5d1a" } ] } ], "nextPageToken": null } ``` ### 4.2 SSE streaming Some deployments expose live updates as SSE (`text/event-stream`). When enabled, stream payloads SHOULD be valid NDJSON and remain deterministic for a given event id. ## 5. Samples and fixtures Deterministic samples live under `docs/api/console/samples/` and are used by documentation and offline validation: - `docs/api/console/samples/vuln-findings-sample.json` - `docs/api/console/samples/vex-statement-sse.ndjson` - `docs/api/console/samples/console-export-manifest.json` - `docs/api/console/samples/exception-schema-sample.json` When contracts change, update the fixtures in lockstep and keep diffs deterministic (stable key ordering, stable timestamps, stable ids).