Console Workspaces API

The Console Workspaces API exposes tenant-scoped, read-only aggregates that power the StellaOps Console’s vulnerability and VEX views. This document is the contract for those endpoints — request conventions, response shapes, and determinism guarantees.

Audience: Console and SDK developers, plus automation that reads findings and VEX context programmatically.

1. Goals and scope

Console workspaces provide tenant-scoped, read-only aggregates for operators and automation:

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

RequirementDescription
Auth headersAuthorization: Bearer <token> and optional proof headers (e.g., DPoP: <proof>) depending on deployment profile.
Tenant headerRequired. See docs/api/gateway/tenant-auth.md; prefer X-StellaOps-TenantId (legacy aliases: X-StellaOps-Tenant, X-Stella-Tenant).
PaginationCursor-based via pageToken; defaults to 50 items, max 200. Cursors are opaque, base64url, and signed.
SortingFindings sorted by (severity desc, exploitScore desc, findingId asc). Statements sorted by (lastUpdated desc, statementId asc).
DatesRFC 3339 / ISO-8601 UTC (e.g., 2025-01-02T03:04:05Z).
DeterminismArrays are pre-sorted; no server-generated random UUIDs in responses.

3. Vulnerability workspace (/console/vuln/*)

3.1 GET /console/vuln/findings

Query parameters:

ParameterTypeNotes
pageTokenstringOptional cursor from previous response.
pageSizeint1-200, default 50.
severitystring[]critical, high, medium, low, info.
productstring[]SBOM purl or image digest anchors.
policyBadgestring[]pass, warn, fail, waived.
vexStatestring[]not_affected, fixed, under_investigation, etc.
reachabilitystring[]reachable, unreachable, unknown.
searchstringSubstring 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

Status: design draft — not implemented. Authority Console does not register a standalone GET /console/vuln/facets endpoint. The implemented vuln workspace routes are GET /console/vuln/findings, GET /console/vuln/{findingId}, and POST /console/vuln/tickets (see StellaOps.Authority/Console/ConsoleEndpointExtensions.cs). Facet counts are returned inline in the facets object of the GET /console/vuln/findings response (see §3.1), so a dedicated facet endpoint is currently redundant. Tenant-wide filter categories/counts are also available via GET /console/filters.

Intended behavior (not yet implemented): return the full facet catalog (counts by severity, product, policy badge, VEX state, reachability, KEV flag) for sidebar filters without paging, sharing the parameter surface of /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:

ParameterTypeNotes
advisoryIdstring[]CVE/GHSA/OVAL identifiers.
justificationstring[]exploit_observed, component_not_present, etc.
statementTypestring[]vex, openvex, custom, advisory_ai.
preferstringprefer=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 Live streaming status

Authority Console does not currently implement live VEX SSE because Authority has no durable tenant-scoped VEX event source. GET /console/vex/events is kept as an explicit fail-closed contract:

{
  "error": "vex_events_stream_unsupported",
  "message": "Authority Console does not expose live VEX SSE because no durable VEX event source is configured. Use /console/vex/statements for deterministic polling.",
  "feature": "console_vex_events",
  "streamEnabled": false
}

The response status is 501 Not Implemented, requires the same ui.read and vex:read authorization as VEX statement reads, and emits authority.console.vex.events with reason vex_events_stream_unsupported. Future streaming implementations must be backed by a real durable event source, remain tenant-scoped, honor request cancellation, and emit deterministic event ids and payloads.

5. Samples and fixtures

Deterministic samples live under docs/api/console/samples/ and are used by documentation and offline validation:

When contracts change, update the fixtures in lockstep and keep diffs deterministic (stable key ordering, stable timestamps, stable ids).