Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Findings Ledger CI / build-test (push) Has been cancelled
Findings Ledger CI / migration-validation (push) Has been cancelled
Findings Ledger CI / generate-manifest (push) Has been cancelled
mock-dev-release / package-mock-release (push) Has been cancelled
- Added ConsoleExportClient for managing export requests and responses. - Introduced ConsoleExportRequest and ConsoleExportResponse models. - Implemented methods for creating and retrieving exports with appropriate headers. feat(crypto): Add Software SM2/SM3 Cryptography Provider - Implemented SmSoftCryptoProvider for software-only SM2/SM3 cryptography. - Added support for signing and verification using SM2 algorithm. - Included hashing functionality with SM3 algorithm. - Configured options for loading keys from files and environment gate checks. test(crypto): Add unit tests for SmSoftCryptoProvider - Created comprehensive tests for signing, verifying, and hashing functionalities. - Ensured correct behavior for key management and error handling. feat(api): Enhance Console Export Models - Expanded ConsoleExport models to include detailed status and event types. - Added support for various export formats and notification options. test(time): Implement TimeAnchorPolicyService tests - Developed tests for TimeAnchorPolicyService to validate time anchors. - Covered scenarios for anchor validation, drift calculation, and policy enforcement.
394 lines
14 KiB
Markdown
394 lines
14 KiB
Markdown
# Console Workspaces API
|
||
|
||
_Tracking: CONSOLE-VULN-29-001, CONSOLE-VEX-30-001, DOCS-AIAI-31-004_
|
||
|
||
## 1. Goals & Scope
|
||
|
||
The console workspaces provide read-only aggregates for Advisory AI operators:
|
||
|
||
- `/console/vuln/*` surfaces tenant-scoped findings annotated with policy verdicts, VEX justifications, Scheduler reachability signals, and Advisory AI rationale.
|
||
- `/console/vex/*` streams the underlying VEX statements, conflicts, and justification summaries (with SSE support for live updates).
|
||
|
||
All endpoints MUST:
|
||
|
||
1. Remain deterministic offline (stable sort keys, ISO-8601 UTC timestamps, hashed assets).
|
||
2. Operate with Authority-issued DPoP or mTLS client credentials that include `console:read` and either `vuln:read` or `vex:read`.
|
||
3. Respect tenant isolation – every request carries `X-StellaOps-Tenant`.
|
||
|
||
## 2. Shared Request/Response Conventions
|
||
|
||
| Requirement | Description |
|
||
| --- | --- |
|
||
| Headers | `Authorization: DPoP <token>`, `DPoP: <proof>`, `X-StellaOps-Tenant: <tenantId>`, `Accept: application/json` (or `text/event-stream` for SSE). |
|
||
| Pagination | Cursor-based via `pageToken`; defaults to 50 items, max 200. Cursors are opaque, base64url, 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-11-08T12:02:11Z`). |
|
||
| Determinism | All arrays must be pre-sorted; no server-generated 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[] | Accepts `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:
|
||
|
||
```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": "Advisory AI flagged reachable path via Scheduler run 42."
|
||
},
|
||
"reachability": {
|
||
"status": "reachable",
|
||
"lastObserved": "2025-11-07T23:11:04Z",
|
||
"signalsVersion": "signals-2025.310.1"
|
||
},
|
||
"evidence": {
|
||
"sbomDigest": "sha256:6c81…",
|
||
"policyRunId": "policy-run::2025-11-07::ca9f",
|
||
"attestationId": "dsse://authority/attest/84a2"
|
||
},
|
||
"timestamps": {
|
||
"firstSeen": "2025-10-31T04:22:18Z",
|
||
"lastSeen": "2025-11-07T23:16:51Z"
|
||
}
|
||
}
|
||
],
|
||
"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 the full finding document, including evidence timeline, policy overlays, and export-ready metadata:
|
||
|
||
```jsonc
|
||
{
|
||
"findingId": "tenant-default:advisory-ai:sha256:5d1a",
|
||
"details": {
|
||
"description": "jsonwebtoken <10.0.0 allows algorithm downgrade.",
|
||
"references": [
|
||
"https://nvd.nist.gov/vuln/detail/CVE-2024-12345",
|
||
"https://github.com/auth0/node-jsonwebtoken/security/advisories/GHSA-45mw-4jw3-g2wg"
|
||
],
|
||
"exploitAvailability": "known_exploit"
|
||
},
|
||
"policyBadges": [
|
||
{
|
||
"policyId": "policy://tenant-default/runtime-hardening",
|
||
"verdict": "fail",
|
||
"explainUrl": "https://console.local/policy/runs/policy-run::2025-11-07::ca9f"
|
||
}
|
||
],
|
||
"vex": {
|
||
"statementId": "vex:tenant-default:jwt-auth:5d1a",
|
||
"state": "under_investigation",
|
||
"justification": "Runtime telemetry confirmed exploitation path.",
|
||
"impactStatement": "Token exchange service remains exposed until patch 2025.11.2.",
|
||
"remediations": [
|
||
{
|
||
"type": "patch",
|
||
"description": "Upgrade jwt-auth-service to 2025.11.2.",
|
||
"deadline": "2025-11-12T00:00:00Z"
|
||
}
|
||
]
|
||
},
|
||
"reachability": {
|
||
"status": "reachable",
|
||
"callPathSamples": [
|
||
"api-gateway -> jwt-auth-service -> jsonwebtoken.verify"
|
||
],
|
||
"lastUpdated": "2025-11-07T23:11:04Z"
|
||
},
|
||
"evidence": {
|
||
"sbom": {
|
||
"digest": "sha256:6c81…",
|
||
"componentPath": [
|
||
"/src/jwt-auth/package.json",
|
||
"/src/jwt-auth/node_modules/jsonwebtoken"
|
||
]
|
||
},
|
||
"attestations": [
|
||
{
|
||
"type": "scan-report",
|
||
"attestationId": "dsse://authority/attest/84a2",
|
||
"signer": "attestor@stella-ops.org",
|
||
"bundleDigest": "sha256:e2bb…"
|
||
}
|
||
]
|
||
},
|
||
"timestamps": {
|
||
"firstSeen": "2025-10-31T04:22:18Z",
|
||
"lastSeen": "2025-11-07T23:16:51Z",
|
||
"vexLastUpdated": "2025-11-07T23:10:09Z"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.4 `POST /console/vuln/tickets`
|
||
|
||
```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"
|
||
}
|
||
}
|
||
```
|
||
|
||
Response:
|
||
|
||
```jsonc
|
||
{
|
||
"ticketId": "console-ticket::tenant-default::2025-11-08::00018",
|
||
"payload": {
|
||
"version": "2025-11-01",
|
||
"tenant": "tenant-default",
|
||
"findings": [
|
||
{ "findingId": "tenant-default:advisory-ai:sha256:5d1a", "severity": "high" },
|
||
{ "findingId": "tenant-default:advisory-ai:sha256:9bf4", "severity": "critical" }
|
||
],
|
||
"policyBadge": "fail",
|
||
"vexSummary": "2 reachable findings pending patch.",
|
||
"attachments": [
|
||
{
|
||
"type": "json",
|
||
"name": "console-ticket-20251108.json",
|
||
"digest": "sha256:1fdd…",
|
||
"contentType": "application/json",
|
||
"expiresAt": "2025-11-15T00:00:00Z"
|
||
}
|
||
]
|
||
},
|
||
"auditEventId": "console.ticket.export::2025-11-08::00018"
|
||
}
|
||
```
|
||
|
||
Requests emit `console.ticket.export` audit events (tenant, user, selection counts, target system).
|
||
|
||
## 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-11-07T23:10:09Z",
|
||
"source": {
|
||
"type": "advisory_ai",
|
||
"modelBuild": "aiai-console-2025-10-28",
|
||
"confidence": 0.74
|
||
},
|
||
"links": [
|
||
{
|
||
"rel": "finding",
|
||
"href": "/console/vuln/findings/tenant-default:advisory-ai:sha256:5d1a"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"nextPageToken": null
|
||
}
|
||
```
|
||
|
||
When `Accept: text/event-stream`, the endpoint emits events (see §4.3) instead of paged JSON.
|
||
|
||
### 4.2 `GET /console/vex/statements/{statementId}`
|
||
|
||
Returns the canonical statement plus provenance extracts. SSE clients can call this endpoint when they need full bodies after receiving a summary event.
|
||
|
||
### 4.3 `GET /console/vex/events` (SSE)
|
||
|
||
Streams live updates for VEX statements affecting the tenant:
|
||
|
||
- Event types: `statement.created`, `statement.updated`, `statement.deleted`, `statement.conflict`.
|
||
- Fields: `id`, `advisoryId`, `product`, `vexState`, `severityHint`, `policyBadge`, `conflictSummary`, `sequence`.
|
||
- Replay: Clients include `Last-Event-ID`; server resumes from sequence.
|
||
- Heartbeats every 15 seconds (`event: keepalive`, `data: {}`).
|
||
|
||
Example event payload:
|
||
|
||
```jsonc
|
||
event: statement.updated
|
||
data: {
|
||
"statementId": "vex:tenant-default:jwt-auth:5d1a",
|
||
"advisoryId": "CVE-2024-12345",
|
||
"product": "registry.local/ops/auth:2025.10.0",
|
||
"state": "fixed",
|
||
"justification": "solution_available",
|
||
"sequence": 4182,
|
||
"updatedAt": "2025-11-08T11:44:32Z"
|
||
}
|
||
```
|
||
|
||
## 5. Signals & Scheduler Integration
|
||
|
||
- Reachability data is materialized by Scheduler delta jobs (`SCHED-CONSOLE-23-001`). `/console/vuln/findings` should cache the most recent job ID and expose `signalsVersion`.
|
||
- VEX justification fields reference Excititor statement IDs; ensure the gateway checks Excititor availability and degrades gracefully (returns `state: unavailable` plus telemetry).
|
||
- Scheduler must publish `console.vuln.refresh` events whenever advisory/VEX deltas warrant workspace refresh; console SSE endpoint may piggyback on the same Redis/NATS channel.
|
||
|
||
## 6. Determinism & Offline Notes
|
||
|
||
1. All responses are compressible JSON; no CDN fonts/assets referenced.
|
||
2. SSE endpoints must tolerate sealed mode by operating on loopback addresses only.
|
||
3. `authority-sealed-ci.json` (see DEVOPS-AIRGAP-57-002) is the evidence Authority consumes before enabling these APIs for sealed tenants; configure `airGap.sealedMode` and set `requiresAirgapSealConfirmation: true` on the Console client so `/token` refuses requests until the sealed harness uploads a fresh, passing artefact. Console responses echo `sealed: true/false` flags for UI badges once Authority has confirmed the evidence.
|
||
|
||
## 7. Sample Payloads for Docs
|
||
|
||
- `docs/api/console/samples/vuln-findings-sample.json` – exported via `scripts/generate-console-samples.ts` (placeholder script to be added when backend lands).
|
||
- `docs/api/console/samples/vex-statement-sse.ndjson` – contains 5 chronological SSE events for screenshot reproduction.
|
||
|
||
> Until backend implementations ship, use the examples above to unblock DOCS-AIAI-31-004; replace them with live captures once the gateway endpoints are available in staging.
|
||
|
||
## Exports (draft contract v0.3)
|
||
|
||
### Routes
|
||
- `POST /console/exports` — start an evidence bundle export job.
|
||
- `GET /console/exports/{exportId}` — fetch job status and download locations.
|
||
- `GET /console/exports/{exportId}/events` — SSE stream of job progress (optional).
|
||
|
||
### Security / headers
|
||
- `Authorization: DPoP <token>`
|
||
- `DPoP: <proof>`
|
||
- `X-StellaOps-Tenant: <tenantId>`
|
||
- `Idempotency-Key: <uuid>` (recommended for POST)
|
||
- `Accept: application/json` (status) or `text/event-stream` (events)
|
||
- Required scopes: `console:read` AND `console:export` (proposal).
|
||
|
||
### Request body (POST)
|
||
```jsonc
|
||
{
|
||
"scope": { "tenantId": "t1", "projectId": "p1" },
|
||
"sources": [ { "type": "advisory", "ids": ["CVE-2024-12345"] } ],
|
||
"formats": ["json", "ndjson", "csv"],
|
||
"attestations": { "include": true, "sigstoreBundle": true },
|
||
"notify": { "webhooks": ["https://hooks.local/export"], "email": ["secops@example.com"] },
|
||
"priority": "normal"
|
||
}
|
||
```
|
||
|
||
### Response: 202 Accepted
|
||
- `exportId`: string
|
||
- `status`: `queued|running|succeeded|failed|expired`
|
||
- `estimateSeconds`: int
|
||
- `retryAfter`: int seconds (for polling)
|
||
- `links`: `{ status: url, events?: url }`
|
||
|
||
### Response: GET status
|
||
```jsonc
|
||
{
|
||
"exportId": "console-export::tenant-default::2025-12-06::0007",
|
||
"status": "running",
|
||
"estimateSeconds": 420,
|
||
"outputs": [
|
||
{ "type": "manifest", "format": "json", "url": "https://.../manifest.json?sig=...", "sha256": "...", "expiresAt": "2025-12-06T13:10:00Z" }
|
||
],
|
||
"progress": { "percent": 42, "itemsCompleted": 210, "itemsTotal": 500, "assetsReady": 12 },
|
||
"errors": []
|
||
}
|
||
```
|
||
|
||
### Response: SSE events
|
||
- `started`: `{ exportId, status }`
|
||
- `progress`: `{ exportId, percent, itemsCompleted, itemsTotal }`
|
||
- `asset_ready`: `{ exportId, type, id, url, sha256 }`
|
||
- `completed`: `{ exportId, status: "succeeded", manifestUrl }`
|
||
- `failed`: `{ exportId, status: "failed", code, message }`
|
||
|
||
### Manifest shape (downloaded via outputs)
|
||
- `version`: string (date)
|
||
- `exportId`, `tenantId`, `generatedAt`
|
||
- `items[]`: `{ type: advisory|vex|policy|scan, id, url, sha256 }`
|
||
- `checksums`: `{ manifest, bundle }`
|
||
|
||
### Limits (proposed)
|
||
- Max request body 256 KiB; max sources 50; max outputs 1000 assets/export.
|
||
- Default job timeout 30 minutes; idle SSE timeout 60s; backoff via `Retry-After`.
|
||
|
||
### Error codes (proposal)
|
||
- `ERR_CONSOLE_EXPORT_INVALID_SOURCE`
|
||
- `ERR_CONSOLE_EXPORT_TOO_LARGE`
|
||
- `ERR_CONSOLE_EXPORT_RATE_LIMIT`
|
||
- `ERR_CONSOLE_EXPORT_UNAVAILABLE`
|
||
|
||
### Samples
|
||
- Request: `docs/api/console/samples/console-export-request.json`
|
||
- Status: `docs/api/console/samples/console-export-status.json`
|
||
- Manifest: `docs/api/console/samples/console-export-manifest.json`
|
||
- Events: `docs/api/console/samples/console-export-events.ndjson`
|
||
|
||
### Open items (needs guild sign-off)
|
||
- Final scopes list (`console:export` vs broader `console:*`).
|
||
- Final limits and error codes; checksum manifest format; attestation options.
|
||
- Caching/tie-break rules for downstream `/console/search` and `/console/downloads`.
|