6.2 KiB
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:
- Remain deterministic (stable sort keys, ISO-8601 UTC timestamps, stable identifiers).
- Enforce tenant isolation for every request.
- 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 <token> and optional proof headers (e.g., DPoP: <proof>) 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):
{
"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-<version>"
},
"evidence": {
"sbomDigest": "sha256:6c81deadbeef...",
"policyRunId": "policy-run::<id>",
"attestationId": "dsse://authority/attest/<id>"
},
"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.
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):
{
"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-<build>",
"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.jsondocs/api/console/samples/vex-statement-sse.ndjsondocs/api/console/samples/console-export-manifest.jsondocs/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).