docs consolidation
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
- Deterministic pagination (`continuationToken`), stable sorting, and explicit audit trails.
|
||||
|
||||
## Headers
|
||||
- `X-StellaOps-Tenant` (required)
|
||||
- `X-Stella-Tenant` (required; legacy alias: `X-StellaOps-Tenant`)
|
||||
- `X-Stella-Project` (optional)
|
||||
- `X-Stella-Trace-Id` (required)
|
||||
- `X-Stella-Request-Id` (required; defaults to trace ID)
|
||||
|
||||
@@ -1,58 +1,57 @@
|
||||
# Console Search & Downloads · Draft v0.2
|
||||
# Console Search and Downloads
|
||||
|
||||
Scope: unblock WEB-CONSOLE-23-004/005 by defining deterministic ranking, caching rules, and the download manifest structure (including signed metadata option) for console search and offline bundle downloads. Final guild sign-off still required.
|
||||
This document defines deterministic ranking, caching rules, and the download manifest shape used by Console search and export-style workflows.
|
||||
|
||||
## 1) Deterministic search ranking
|
||||
- Primary sort: `severity (desc)` → `exploitScore (desc)` → `reachability (reachable > unknown > unreachable)` → `policyBadge (fail > warn > pass > waived)` → `vexState (under_investigation > fixed > not_affected > unknown)` → `findingId (asc)`.
|
||||
- Secondary tie-breakers (when above fields absent): `advisoryId (asc)` then `product (asc)`.
|
||||
- All pages are pre-sorted server-side; clients MUST NOT re-order.
|
||||
- Primary sort: `severity (desc)` then `exploitScore (desc)` then `reachability (reachable > unknown > unreachable)` then `policyBadge (fail > warn > pass > waived)` then `vexState (under_investigation > fixed > not_affected > unknown)` then `findingId (asc)`.
|
||||
- Secondary tie-breakers (when primary fields are absent): `advisoryId (asc)` then `product (asc)`.
|
||||
- Pages are pre-sorted server-side; clients MUST NOT re-order results.
|
||||
|
||||
## 2) Caching + freshness
|
||||
- Response headers: `Cache-Control: public, max-age=300, stale-while-revalidate=60, stale-if-error=300`.
|
||||
- `ETag` is a stable SHA-256 over the sorted payload; clients send `If-None-Match` for revalidation.
|
||||
- `Last-Modified` reflects the newest `updatedAt` in the result set.
|
||||
- Retry/backoff guidance: honor `Retry-After` when present; default client backoff `1s,2s,4s,8s` capped at 30s.
|
||||
- Deterministic page cursors: opaque base64url, signed; include `sortKeys` and `tenant` to avoid cross-tenant reuse.
|
||||
## 2) Caching and freshness
|
||||
- Response headers (recommended defaults): `Cache-Control: private, max-age=300, stale-while-revalidate=60, stale-if-error=300`.
|
||||
- `ETag` SHOULD be a stable SHA-256 over a canonicalized, sorted payload so identical inputs produce identical validators; clients send `If-None-Match` for revalidation.
|
||||
- `Last-Modified` SHOULD reflect the newest `updatedAt` present in the result set.
|
||||
- Retry/backoff: honor `Retry-After` when present; otherwise use deterministic client backoff (for example `1s, 2s, 4s, 8s` capped at 30s).
|
||||
- Page cursors: opaque base64url, signed; bind to `tenant` and effective sort keys to avoid cross-tenant or cross-sort reuse.
|
||||
|
||||
## 3) Download manifest (for `/console/downloads` and export outputs)
|
||||
Top-level:
|
||||
```jsonc
|
||||
{
|
||||
"version": "2025-12-07",
|
||||
"exportId": "console-export::tenant-default::2025-12-07::0009",
|
||||
"tenantId": "tenant-default",
|
||||
"generatedAt": "2025-12-07T10:15:00Z",
|
||||
"items": [
|
||||
{
|
||||
"type": "vuln", // advisory|vex|policy|scan|chart|bundle
|
||||
"id": "CVE-2024-12345",
|
||||
"format": "json",
|
||||
"url": "https://downloads.local/exports/0009/vuln/CVE-2024-12345.json?sig=...",
|
||||
"sha256": "f1c5…",
|
||||
"size": 18432
|
||||
}
|
||||
],
|
||||
"checksums": {
|
||||
"manifest": "sha256:8bbf…",
|
||||
"bundle": "sha256:12ae…" // optional when a tar/zip bundle is produced
|
||||
},
|
||||
"expiresAt": "2025-12-14T10:15:00Z"
|
||||
}
|
||||
```
|
||||
## 3) Download manifest
|
||||
When a Console workflow produces downloadable artifacts (individual documents or a bundle), services can return a manifest describing:
|
||||
- What items are available,
|
||||
- Where to download them (signed URLs or gateway-relative links),
|
||||
- How to verify them offline (checksums and optional signature metadata).
|
||||
|
||||
### 3.1 Signed metadata
|
||||
- Optional DSSE envelope for `checksums.manifest`, using `sha256` digest and `application/json` payload type `stellaops.console.manifest`.
|
||||
- Envelope is attached as `manifest.dsse` or provided via `Link: <...>; rel="alternate"; type="application/dsse+json"`.
|
||||
- Signers: Authority-issued short-lived key scoped to `console:export`.
|
||||
Top-level fields:
|
||||
- `version` (string): manifest schema/version label used by the producer.
|
||||
- `exportId` (string): stable export identifier (content-addressable or run-id style).
|
||||
- `tenantId` (string): tenant scope for this export.
|
||||
- `generatedAt` (RFC 3339 / ISO-8601 UTC): generation timestamp.
|
||||
- `items[]` (array): downloadable artifacts.
|
||||
- `checksums` (object): checksum(s) for the manifest itself and optional bundle artifact.
|
||||
- `expiresAt` (RFC 3339 / ISO-8601 UTC): optional expiry for signed URLs.
|
||||
|
||||
### 3.2 Error handling
|
||||
- Known error codes: `ERR_CONSOLE_DOWNLOAD_INVALID_CURSOR`, `ERR_CONSOLE_DOWNLOAD_EXPIRED`, `ERR_CONSOLE_DOWNLOAD_RATE_LIMIT`, `ERR_CONSOLE_DOWNLOAD_UNAVAILABLE`.
|
||||
- On error, respond with deterministic JSON body including `requestId` and `retryAfterSeconds` when applicable.
|
||||
Item fields:
|
||||
- `type` (string): artifact type (for example `vuln`, `vex`, `policy`, `scan`, `bundle`).
|
||||
- `id` (string): stable identifier within the type (CVE id, statement id, export id, etc).
|
||||
- `format` (string): `json`, `ndjson`, `tar.gz`, etc.
|
||||
- `url` (string): download URL (often signed).
|
||||
- `sha256` (string): lowercase hex digest of the bytes at `url`.
|
||||
- `size` (int): byte size.
|
||||
|
||||
## 4) Sample manifest
|
||||
- `docs/api/console/samples/console-download-manifest.json` illustrates the exact shape above.
|
||||
### Signed metadata (optional)
|
||||
Producers MAY ship a DSSE envelope for the manifest checksum:
|
||||
- Payload type: `stellaops.console.manifest`
|
||||
- Media type: `application/json`
|
||||
- Distribution: alongside the manifest (for example `manifest.dsse`) or via a link relation (for example `rel=\"alternate\"` with `type=\"application/dsse+json\"`).
|
||||
|
||||
## 4) Error handling
|
||||
Known error codes for download/manifest flows:
|
||||
- `ERR_CONSOLE_DOWNLOAD_INVALID_CURSOR`
|
||||
- `ERR_CONSOLE_DOWNLOAD_EXPIRED`
|
||||
- `ERR_CONSOLE_DOWNLOAD_RATE_LIMIT`
|
||||
- `ERR_CONSOLE_DOWNLOAD_UNAVAILABLE`
|
||||
|
||||
On error, return the standard error envelope with deterministic fields (stable code/message, plus request/trace identifiers).
|
||||
|
||||
## 5) Samples and fixtures
|
||||
- Download manifest example: `docs/api/console/samples/console-download-manifest.json`
|
||||
|
||||
## 5) Open items for guild sign-off
|
||||
- Final TTL values for `max-age` and `stale-*`.
|
||||
- Whether DSSE envelope is mandatory for sealed tenants.
|
||||
- Maximum bundle size / item count caps (proposal: 1000 items, 500 MiB compressed per export).
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
# Console Workspaces API
|
||||
|
||||
_Tracking: CONSOLE-VULN-29-001, CONSOLE-VEX-30-001, DOCS-AIAI-31-004_
|
||||
## 1. Goals and scope
|
||||
|
||||
## 1. Goals & Scope
|
||||
Console workspaces provide tenant-scoped, read-only aggregates for operators and automation:
|
||||
|
||||
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).
|
||||
- `/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.
|
||||
|
||||
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
|
||||
## 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. |
|
||||
| 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-11-08T12:02:11Z`). |
|
||||
| Determinism | All arrays must be pre-sorted; no server-generated uuids in responses. |
|
||||
| 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. Vulnerability workspace (`/console/vuln/*`)
|
||||
|
||||
### 3.1 `GET /console/vuln/findings`
|
||||
|
||||
@@ -35,14 +33,14 @@ Query parameters:
|
||||
| --- | --- | --- |
|
||||
| `pageToken` | string | Optional cursor from previous response. |
|
||||
| `pageSize` | int | 1-200, default 50. |
|
||||
| `severity` | string[] | Accepts `critical`, `high`, `medium`, `low`, `info`. |
|
||||
| `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). |
|
||||
| `search` | string | Substring match on CVE/GHSA/KEV id (case-insensitive). |
|
||||
|
||||
Response body:
|
||||
Response body (example):
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -63,21 +61,21 @@ Response body:
|
||||
"vex": {
|
||||
"statementId": "vex:tenant-default:jwt-auth:5d1a",
|
||||
"state": "under_investigation",
|
||||
"justification": "Advisory AI flagged reachable path via Scheduler run 42."
|
||||
"justification": "Operator triage pending."
|
||||
},
|
||||
"reachability": {
|
||||
"status": "reachable",
|
||||
"lastObserved": "2025-11-07T23:11:04Z",
|
||||
"signalsVersion": "signals-2025.310.1"
|
||||
"lastObserved": "2025-01-02T03:04:05Z",
|
||||
"signalsVersion": "signals-<version>"
|
||||
},
|
||||
"evidence": {
|
||||
"sbomDigest": "sha256:6c81…",
|
||||
"policyRunId": "policy-run::2025-11-07::ca9f",
|
||||
"attestationId": "dsse://authority/attest/84a2"
|
||||
"sbomDigest": "sha256:6c81deadbeef...",
|
||||
"policyRunId": "policy-run::<id>",
|
||||
"attestationId": "dsse://authority/attest/<id>"
|
||||
},
|
||||
"timestamps": {
|
||||
"firstSeen": "2025-10-31T04:22:18Z",
|
||||
"lastSeen": "2025-11-07T23:16:51Z"
|
||||
"firstSeen": "2025-01-01T00:00:00Z",
|
||||
"lastSeen": "2025-01-02T03:05:06Z"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -102,77 +100,17 @@ Response body:
|
||||
```
|
||||
|
||||
### 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"
|
||||
}
|
||||
}
|
||||
```
|
||||
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
|
||||
{
|
||||
@@ -189,37 +127,7 @@ POST /console/vuln/tickets
|
||||
}
|
||||
```
|
||||
|
||||
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. VEX workspace (`/console/vex/*`)
|
||||
|
||||
### 4.1 `GET /console/vex/statements`
|
||||
|
||||
@@ -243,17 +151,14 @@ Response (paged JSON):
|
||||
"product": "registry.local/ops/auth:2025.10.0",
|
||||
"status": "under_investigation",
|
||||
"justification": "exploit_observed",
|
||||
"lastUpdated": "2025-11-07T23:10:09Z",
|
||||
"lastUpdated": "2025-01-02T03:04:05Z",
|
||||
"source": {
|
||||
"type": "advisory_ai",
|
||||
"modelBuild": "aiai-console-2025-10-28",
|
||||
"modelBuild": "aiai-console-<build>",
|
||||
"confidence": 0.74
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"rel": "finding",
|
||||
"href": "/console/vuln/findings/tenant-default:advisory-ai:sha256:5d1a"
|
||||
}
|
||||
{ "rel": "finding", "href": "/console/vuln/findings/tenant-default:advisory-ai:sha256:5d1a" }
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -261,150 +166,16 @@ Response (paged JSON):
|
||||
}
|
||||
```
|
||||
|
||||
When `Accept: text/event-stream`, the endpoint emits events (see §4.3) instead of paged JSON.
|
||||
### 4.2 SSE streaming
|
||||
|
||||
### 4.2 `GET /console/vex/statements/{statementId}`
|
||||
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.
|
||||
|
||||
Returns the canonical statement plus provenance extracts. SSE clients can call this endpoint when they need full bodies after receiving a summary event.
|
||||
## 5. Samples and fixtures
|
||||
|
||||
### 4.3 `GET /console/vex/events` (SSE)
|
||||
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`
|
||||
|
||||
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.4 for sign-off)
|
||||
|
||||
### Routes
|
||||
- `POST /console/exports` — start an evidence bundle export job.
|
||||
- `GET /console/exports/{exportId}` — fetch job status, manifest link, 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"] },
|
||||
{ "type": "vex", "ids": ["vex:tenant-default:jwt-auth:5d1a"] }
|
||||
],
|
||||
"formats": ["json", "ndjson", "csv"],
|
||||
"attestations": { "include": true, "sigstoreBundle": true, "dsse": true },
|
||||
"notify": { "webhooks": ["https://hooks.local/export"], "email": ["secops@example.com"] },
|
||||
"priority": "normal"
|
||||
}
|
||||
```
|
||||
|
||||
### Response: 202 Accepted
|
||||
- `exportId`, `status: queued|running|succeeded|failed|expired`
|
||||
- `estimateSeconds`, `retryAfter` (seconds)
|
||||
- `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://exports.local/tenant-default/0007/manifest.json?sig=...",
|
||||
"sha256": "sha256:c0ffee...",
|
||||
"dsseUrl": "https://exports.local/tenant-default/0007/manifest.dsse?sig=...",
|
||||
"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, format }`
|
||||
- `completed`: `{ exportId, status: "succeeded", manifestUrl, manifestDsseUrl? }`
|
||||
- `failed`: `{ exportId, status: "failed", code, message, retryAfterSeconds? }`
|
||||
|
||||
### Manifest shape (downloaded via outputs)
|
||||
- Ordering: sort items by `(type asc, id asc, format asc, url asc)`.
|
||||
- `version`: string (date), `exportId`, `tenantId`, `generatedAt`, `expiresAt`
|
||||
- `items[]`: `{ type: advisory|vex|policy|scan|chart|bundle, id, format, url, sha256, size }`
|
||||
- `checksums`: `{ manifest: "sha256:<digest>", bundle?: "sha256:<digest>" }`
|
||||
- Optional DSSE envelope for manifest: `manifest.dsse` (payload type `stellaops.console.manifest`).
|
||||
|
||||
### Limits (proposed)
|
||||
- Max request body 256 KiB; max sources 50; max outputs 1000 assets/export.
|
||||
- Max bundle size 500 MiB compressed.
|
||||
- Default job timeout 30 minutes; idle SSE timeout 60s; backoff via `Retry-After`.
|
||||
|
||||
### Determinism, caching, retry
|
||||
- Responses set `Cache-Control: public, max-age=300, stale-while-revalidate=60, stale-if-error=300`.
|
||||
- `ETag` is SHA-256 over sorted payload; clients send `If-None-Match`.
|
||||
- Respect `Retry-After`; client backoff `1s,2s,4s,8s` capped at 30s.
|
||||
- Cursors (if introduced later) MUST be opaque, base64url, signed with tenant + sortKeys.
|
||||
|
||||
### Error codes (proposal)
|
||||
- `ERR_CONSOLE_EXPORT_INVALID_SOURCE`
|
||||
- `ERR_CONSOLE_EXPORT_TOO_LARGE`
|
||||
- `ERR_CONSOLE_EXPORT_RATE_LIMIT`
|
||||
- `ERR_CONSOLE_EXPORT_UNAVAILABLE`
|
||||
- `ERR_CONSOLE_EXPORT_EXPIRED`
|
||||
|
||||
### 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`.
|
||||
When contracts change, update the fixtures in lockstep and keep diffs deterministic (stable key ordering, stable timestamps, stable ids).
|
||||
|
||||
@@ -22,7 +22,7 @@ This document is the entry point for exception contracts. Concrete shapes live i
|
||||
Common requirements across endpoints:
|
||||
|
||||
- `Authorization: Bearer <token>` (or DPoP where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- Tenant header (required): prefer `X-Stella-Tenant` (legacy alias: `X-StellaOps-Tenant`); see `docs/api/gateway/tenant-auth.md`.
|
||||
|
||||
Scopes vary by deployment, but typically follow:
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Scope: proxy Advisory surfaces through the Web gateway with tenant scoping, dete
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- `X-Stella-Trace-Id: <traceId>` (optional; clients SHOULD send one)
|
||||
- Scopes: `advisory:read`
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
- Web clients must send tenant + trace headers and should avoid sending raw prompts in telemetry; use prompt hashes instead.
|
||||
|
||||
## Headers
|
||||
- `X-StellaOps-Tenant` (required)
|
||||
- `X-Stella-Tenant` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project` (optional)
|
||||
- `X-Stella-Trace-Id` (required)
|
||||
- `X-Stella-Request-Id` (required; defaults to trace ID)
|
||||
|
||||
@@ -4,7 +4,7 @@ Scope: stream exception workflow events (`exception.*`) for Console activity fee
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- Scopes: `exception:read`
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ Scope: proxy Export Center APIs through the Web gateway with tenant scoping, det
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: DPoP <token>`, `DPoP: <proof>`
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-StellaOps-Project: <projectId>` (optional)
|
||||
- `Idempotency-Key: <uuid>` (recommended for POST)
|
||||
- `Accept: application/json` (or `text/event-stream` for SSE)
|
||||
|
||||
@@ -6,7 +6,7 @@ This is an interim contract until the gateway is aligned to the Orchestrator Ope
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- `X-Stella-Trace-Id: <traceId>` (optional; clients SHOULD send one)
|
||||
- Scopes: `orch:read`, `orch:quota`, `orch:operate`, `orch:backfill` (endpoint-specific)
|
||||
|
||||
@@ -9,7 +9,7 @@ This contract is intended to reduce UI round-trips by composing existing gateway
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- `X-Stella-Trace-Id: <traceId>` (optional; clients SHOULD send one)
|
||||
- Scopes:
|
||||
|
||||
@@ -4,7 +4,7 @@ Scope: expose policy evaluation results that include exception metadata, plus si
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- `X-Stella-Trace-Id: <traceId>` (optional; clients SHOULD send one)
|
||||
- Scopes:
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
# Gateway Tenant Auth & ABAC Contract (Web V)
|
||||
|
||||
## Status
|
||||
- Final v1.0 (2025-12-01); aligns with Policy Guild checkpoint for Sprint 0216.
|
||||
- v1.1 (2025-12-24); updated for identity header hardening (Sprint 8100.0011.0002).
|
||||
- v1.0 (2025-12-01); aligns with Policy Guild checkpoint for Sprint 0216.
|
||||
|
||||
## Header Naming Migration
|
||||
As of Sprint 8100.0011.0002, the Gateway uses canonical `X-StellaOps-*` headers:
|
||||
- `X-StellaOps-Tenant`, `X-StellaOps-Project`, `X-StellaOps-Actor`, `X-StellaOps-Scopes`
|
||||
|
||||
Legacy `X-Stella-*` headers are emitted when `Gateway:Auth:EnableLegacyHeaders=true` (default) for backward compatibility. Clients should migrate to `X-StellaOps-*` headers.
|
||||
|
||||
## Security: Identity Header Hardening (v1.1)
|
||||
**CRITICAL:** As of Sprint 8100.0011.0002, the Gateway enforces a **strip-and-overwrite** policy for identity headers:
|
||||
1. All reserved identity headers (`X-StellaOps-*`, `X-Stella-*`, `sub`, `tid`, `scope`, `scp`, `cnf`) are **stripped** from incoming requests.
|
||||
2. Downstream identity headers are **overwritten** from validated JWT claims—clients cannot spoof identity.
|
||||
3. For anonymous requests, explicit `anonymous` identity is set to prevent ambiguity.
|
||||
|
||||
This replaces the legacy "set-if-missing" behavior which allowed header spoofing.
|
||||
|
||||
## Decisions (2025-12-01)
|
||||
- Proof-of-possession: DPoP is **optional** for Web V. If a `DPoP` header is present the gateway verifies it; interactive clients SHOULD send DPoP, service tokens MAY omit it. A cluster flag `Gateway:Auth:RequireDpopForInteractive` can make DPoP mandatory later without changing the contract.
|
||||
- Scope override header: `X-Stella-Scopes` is accepted only in pre-prod/offline bundles or when `Gateway:Auth:AllowScopeHeader=true`; otherwise the request is rejected with `ERR_SCOPE_HEADER_FORBIDDEN`.
|
||||
- Scope override header: `X-StellaOps-Scopes` (or legacy `X-Stella-Scopes`) is forbidden by default; accepted only when `Gateway:Auth:AllowScopeHeader=true` for offline/pre-prod bundles. Violation returns `ERR_SCOPE_HEADER_FORBIDDEN`.
|
||||
- ABAC overlay: evaluated on every tenant-scoped route after RBAC success; failures are hard denies (no fallback). Attribute sources are frozen for Web V as listed below to keep determism.
|
||||
|
||||
## Scope
|
||||
@@ -16,25 +31,38 @@
|
||||
## Header & Claim Inputs
|
||||
| Name | Required | Notes |
|
||||
| --- | --- | --- |
|
||||
| `Authorization: Bearer <jwt>` | Yes | RS256/ES256; claims: `iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`, optional `scp` (space-delimited), `ten` (tenant). DPoP proof verified when `DPoP` header present. |
|
||||
| `Authorization: Bearer <jwt>` | Yes | RS256/ES256; claims: `iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`, optional `scp`/`scope`, `stellaops:tenant`. DPoP proof verified when `DPoP` header present. |
|
||||
| `DPoP` | Cond. | Proof-of-possession JWS for interactive clients; validated against `htm`/`htu` and access token `jti`. Ignored for service tokens when absent. |
|
||||
| `X-Stella-Tenant` | Yes | Tenant slug/UUID; must equal `ten` claim when provided. Missing or mismatch → `ERR_TENANT_MISMATCH` (400). |
|
||||
| `X-Stella-Project` | Cond. | Required for project-scoped routes; otherwise optional. |
|
||||
| `X-Stella-Scopes` | Cond. | Only honored when `Gateway:Auth:AllowScopeHeader=true`; rejected with 403 otherwise. Value is space-delimited scopes. |
|
||||
| `X-Stella-Trace-Id` | Optional | If absent the gateway issues a ULID trace id and propagates downstream. |
|
||||
| `X-StellaOps-Trace-Id` | Optional | If absent the gateway issues a ULID trace id and propagates downstream. Legacy: `X-Stella-Trace-Id`. |
|
||||
| `X-Request-Id` | Optional | Echoed for idempotency diagnostics and response envelopes. |
|
||||
|
||||
### Reserved Identity Headers (Client-Provided Values Ignored)
|
||||
The following headers are **stripped** from client requests and **overwritten** from validated claims:
|
||||
| Header | Source Claim | Notes |
|
||||
| --- | --- | --- |
|
||||
| `X-StellaOps-Tenant` | `stellaops:tenant` (fallback: `tid`) | Tenant identifier from token claims. |
|
||||
| `X-StellaOps-Project` | `stellaops:project` | Project identifier (optional). |
|
||||
| `X-StellaOps-Actor` | `sub` | Subject/actor from token claims. |
|
||||
| `X-StellaOps-Scopes` | `scp` (individual) or `scope` (space-separated) | Scopes from token claims, sorted deterministically. |
|
||||
|
||||
Legacy `X-Stella-*` headers are emitted alongside canonical headers when `EnableLegacyHeaders=true`.
|
||||
|
||||
## Processing Rules
|
||||
1) Validate JWT signature against offline bundle trust roots; `aud` must be one of `stellaops-web` or `stellaops-gateway`; reject on `exp/nbf` drift > 60s.
|
||||
2) Resolve tenant: prefer `X-Stella-Tenant`, otherwise `ten` claim. Any mismatch → `ERR_TENANT_MISMATCH` (400).
|
||||
3) Resolve project: from `X-Stella-Project` when route is project-scoped; otherwise null.
|
||||
4) Build scope set: start from `scp` claim; if `X-Stella-Scopes` is allowed and present, replace the set with its value.
|
||||
5) RBAC: check required scopes per route (matrix below). Missing scope → `ERR_SCOPE_MISMATCH` (403).
|
||||
6) ABAC overlay:
|
||||
1) **Strip reserved headers:** Remove all reserved identity headers from the incoming request (see table above).
|
||||
2) **Validate JWT:** Verify signature against offline bundle trust roots; `aud` must be one of `stellaops-web` or `stellaops-gateway`; reject on `exp/nbf` drift > 60s.
|
||||
3) **Extract identity from claims:**
|
||||
- Tenant: `stellaops:tenant` claim, fallback to `tid` claim.
|
||||
- Project: `stellaops:project` claim (optional).
|
||||
- Actor: `sub` claim.
|
||||
- Scopes: `scp` claims (individual items) or `scope` claim (space-separated).
|
||||
4) **Write downstream headers:** Overwrite `X-StellaOps-*` headers from extracted claims. Legacy `X-Stella-*` headers written when enabled.
|
||||
5) **Anonymous handling:** If unauthenticated and `AllowAnonymous=true`, set explicit anonymous identity (`X-StellaOps-Actor: anonymous`, empty scopes).
|
||||
6) **RBAC:** Check required scopes per route (matrix below). Missing scope → `ERR_SCOPE_MISMATCH` (403).
|
||||
7) **ABAC overlay:**
|
||||
- Attributes: `subject`, `roles`, `org`, `tenant_id`, `project_id`, route vars (e.g., `finding_id`, `policy_id`), and request body keys explicitly listed in the route contract.
|
||||
- Order: RBAC allow → ABAC evaluate → deny overrides → allow.
|
||||
- Fail closed: on evaluation error or missing attributes return `ERR_ABAC_DENY` (403) with `reason` + `trace_id`.
|
||||
7) Determinism: tenant header is mandatory; anonymous/implicit tenants are not allowed. Error codes are stable and surfaced in the response envelope.
|
||||
8) **Determinism:** Identity headers are always overwritten from claims; error codes are stable and surfaced in the response envelope.
|
||||
|
||||
## Route Scope Matrix (Web V)
|
||||
- `/risk/*` → `risk:read` for GET, `risk:write` for POST/PUT; severity events additionally require `notify:emit`.
|
||||
|
||||
@@ -4,7 +4,7 @@ Scope: expose read-only VEX statement and evidence routes through the Web gatewa
|
||||
|
||||
## Security / headers
|
||||
- `Authorization: Bearer <token>` (or `DPoP` where configured)
|
||||
- `X-StellaOps-Tenant: <tenantId>` (required)
|
||||
- `X-Stella-Tenant: <tenantId>` (required; see `docs/api/gateway/tenant-auth.md`)
|
||||
- `X-Stella-Project: <projectId>` (optional)
|
||||
- `X-Stella-Trace-Id: <traceId>` (optional; clients SHOULD send one)
|
||||
- Scopes:
|
||||
|
||||
@@ -26,22 +26,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SearchRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of search tiles (NDJSON)
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TileEnvelope'
|
||||
examples:
|
||||
sample:
|
||||
summary: Node + cursor tiles
|
||||
value: |
|
||||
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:abc","kind":"component","tenant":"acme","attributes":{"purl":"pkg:npm/lodash@4.17.21"}},"cost":{"limit":1000,"remaining":999,"consumed":1}}
|
||||
{"type":"cursor","seq":1,"data":{"token":"cursor-123","resumeUrl":"https://gateway.local/api/graph/query?cursor=cursor-123"}}
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of search tiles (NDJSON)
|
||||
@@ -64,6 +48,9 @@ paths:
|
||||
description: Seconds until next request is allowed when rate limited.
|
||||
schema:
|
||||
type: integer
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
|
||||
/graph/query:
|
||||
post:
|
||||
@@ -79,23 +66,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/QueryRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of query tiles (NDJSON)
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TileEnvelope'
|
||||
examples:
|
||||
mixedTiles:
|
||||
summary: Node + edge + stats tiles
|
||||
value: |
|
||||
{"type":"node","seq":0,"data":{"id":"gn:tenant:artifact:sha256:...","tenant":"acme","kind":"artifact","attributes":{"sbom_digest":"sha256:abc"}}}
|
||||
{"type":"edge","seq":1,"data":{"id":"ge:tenant:CONTAINS:...","sourceId":"gn:tenant:artifact:...","targetId":"gn:tenant:component:...","kind":"CONTAINS"}}
|
||||
{"type":"stats","seq":2,"data":{"nodesEmitted":1,"edgesEmitted":1,"depthReached":2,"cacheHitRatio":0.8}}
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of query tiles (NDJSON)
|
||||
@@ -119,10 +89,13 @@ paths:
|
||||
description: Seconds until next request is allowed when rate limited.
|
||||
schema:
|
||||
type: integer
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
|
||||
/graph/paths:
|
||||
post:
|
||||
summary: Find constrained paths between node sets (depth ≤ 6)
|
||||
summary: Find constrained paths between node sets (depth <= 6)
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
@@ -134,23 +107,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PathsRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of path tiles ordered by hop
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TileEnvelope'
|
||||
examples:
|
||||
pathTiles:
|
||||
summary: Path tiles grouped by hop
|
||||
value: |
|
||||
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:src","kind":"component","tenant":"acme"}}
|
||||
{"type":"edge","seq":1,"data":{"id":"ge:tenant:DEPENDS_ON:1","sourceId":"gn:tenant:component:src","targetId":"gn:tenant:component:dst","kind":"DEPENDS_ON"}}
|
||||
{"type":"stats","seq":2,"data":{"nodesEmitted":2,"edgesEmitted":1,"depthReached":1}}
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
responses:
|
||||
'200':
|
||||
description: Stream of path tiles ordered by hop
|
||||
@@ -165,6 +121,18 @@ paths:
|
||||
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:src","kind":"component","tenant":"acme","attributes":{"purl":"pkg:npm/demo@1.0.0"},"pathHop":0}}
|
||||
{"type":"edge","seq":1,"data":{"id":"ge:tenant:DEPENDS_ON:1","sourceId":"gn:tenant:component:src","targetId":"gn:tenant:component:dst","kind":"DEPENDS_ON","pathHop":1}}
|
||||
{"type":"stats","seq":2,"data":{"nodesEmitted":2,"edgesEmitted":1,"depthReached":1}}
|
||||
headers:
|
||||
X-RateLimit-Remaining:
|
||||
description: Remaining request budget within the window.
|
||||
schema:
|
||||
type: integer
|
||||
Retry-After:
|
||||
description: Seconds until next request is allowed when rate limited.
|
||||
schema:
|
||||
type: integer
|
||||
'400': { $ref: '#/components/responses/ValidationError' }
|
||||
'401': { $ref: '#/components/responses/Unauthorized' }
|
||||
'429': { $ref: '#/components/responses/BudgetExceeded' }
|
||||
|
||||
/graph/diff:
|
||||
post:
|
||||
|
||||
@@ -1,123 +1,59 @@
|
||||
# Graph API
|
||||
# Graph Gateway API (draft)
|
||||
|
||||
Status: Draft (2025-11-26) — aligns with Sprint 0207 Graph API implementation (in-memory seed; RBAC + budgets enforced).
|
||||
This document describes the Graph Gateway HTTP surface at a high level and points to the authoritative contracts.
|
||||
|
||||
Base URL: `<gateway>/api/graph` (examples use relative paths).
|
||||
## Authoritative contracts
|
||||
|
||||
## Common headers
|
||||
- `X-Stella-Tenant` (required)
|
||||
- `Authorization: Bearer <token>` (required)
|
||||
- `X-Stella-Scopes`: space/comma/semicolon separated scopes
|
||||
- `/graph/search`: `graph:read` or `graph:query`
|
||||
- `/graph/query|paths|diff`: `graph:query`
|
||||
- `/graph/export`: `graph:export`
|
||||
Content-Type for requests: `application/json`
|
||||
Streaming responses: `application/x-ndjson`
|
||||
- OpenAPI (endpoints, schemas, responses): `docs/api/graph-gateway-spec-draft.yaml`
|
||||
- Overlay + tile cache schema (materialized/cached representation): `docs/api/graph/overlay-schema.md`
|
||||
- Sample cached tile: `docs/api/graph/samples/overlay-sample.json`
|
||||
|
||||
## POST /graph/search
|
||||
Returns NDJSON stream of tiles (`node`, optional `cursor`).
|
||||
## What the Graph Gateway is for
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"kinds": ["component", "artifact"],
|
||||
"query": "pkg:npm/",
|
||||
"filters": { "ecosystem": "npm" },
|
||||
"limit": 50,
|
||||
"cursor": "opaque"
|
||||
}
|
||||
```
|
||||
Errors:
|
||||
- 400 `GRAPH_VALIDATION_FAILED` (missing kinds/query/filters)
|
||||
- 401 missing auth; 403 missing scopes
|
||||
Graph Gateway provides deterministic, tenant-scoped graph queries used for:
|
||||
- Impact analysis and traversal (search/query/paths/diff)
|
||||
- Overlay enrichment (policy, VEX, advisory) when requested
|
||||
- Export workflows for offline analysis and audit
|
||||
|
||||
## POST /graph/query
|
||||
Streams nodes, edges (optional), stats, cursor with cost metadata.
|
||||
## Tenancy and authentication
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"kinds": ["component"],
|
||||
"query": "widget",
|
||||
"filters": { "tenant": "acme" },
|
||||
"includeEdges": true,
|
||||
"includeStats": true,
|
||||
"includeOverlays": true,
|
||||
"limit": 100,
|
||||
"cursor": "opaque",
|
||||
"budget": { "tiles": 6000, "nodes": 5000, "edges": 10000 }
|
||||
}
|
||||
```
|
||||
Error tile if edge budget exceeded: `{ "type":"error","data":{"error":"GRAPH_BUDGET_EXCEEDED",...}}`
|
||||
- Tenancy is mandatory for graph routes. The canonical tenant header name is deployment/profile dependent; see:
|
||||
- `docs/api/gateway/tenant-auth.md`
|
||||
- `docs/modules/gateway/identity-header-policy.md`
|
||||
- Authentication is typically `Authorization: Bearer <token>` with scopes per route.
|
||||
- Common scope families: `graph:read`, `graph:query`, `graph:export` (see OpenAPI for exact requirements).
|
||||
|
||||
## POST /graph/paths
|
||||
Finds paths up to depth 6 between sources/targets.
|
||||
## NDJSON tile streaming
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"sources": ["gn:acme:component:one"],
|
||||
"targets": ["gn:acme:component:two"],
|
||||
"kinds": ["depends_on"],
|
||||
"maxDepth": 4,
|
||||
"includeOverlays": false,
|
||||
"budget": { "tiles": 2000, "nodes": 1500, "edges": 3000 }
|
||||
}
|
||||
```
|
||||
Response: NDJSON tiles (`node`, `edge`, `stats`, `cursor`).
|
||||
Graph endpoints stream `application/x-ndjson`, where each line is a `TileEnvelope`.
|
||||
|
||||
## POST /graph/diff
|
||||
Diff two snapshots.
|
||||
Key fields:
|
||||
- `type`: `node`, `edge`, `stats`, `cursor`, `diagnostic`
|
||||
- `seq`: monotonic integer per response stream
|
||||
- `cost`: optional per-stream budget counters (`limit`, `remaining`, `consumed`)
|
||||
- `data`: payload varies by `type`
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"snapshotA": "snapA",
|
||||
"snapshotB": "snapB",
|
||||
"includeEdges": true,
|
||||
"includeStats": true,
|
||||
"budget": { "tiles": 2000 }
|
||||
}
|
||||
```
|
||||
Response tiles: `node`/`edge` with change types, `stats`, optional `cursor`.
|
||||
## Cursor and resume
|
||||
|
||||
## POST /graph/export
|
||||
Kicks off an in-memory export job and returns manifest.
|
||||
When paging/resume is supported, responses can include a `cursor` tile with an opaque token.
|
||||
Requests can pass a `cursor` field to resume from a prior stream.
|
||||
|
||||
Body:
|
||||
```json
|
||||
{
|
||||
"format": "ndjson", // ndjson|csv|graphml|png|svg
|
||||
"includeEdges": true,
|
||||
"snapshotId": "snapA", // optional
|
||||
"kinds": ["component"], // optional
|
||||
"query": "pkg:", // optional
|
||||
"filters": { "ecosystem": "npm" }
|
||||
}
|
||||
```
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"jobId": "job-123",
|
||||
"status": "completed",
|
||||
"format": "ndjson",
|
||||
"sha256": "...",
|
||||
"size": 1234,
|
||||
"downloadUrl": "/graph/export/job-123",
|
||||
"completedAt": "2025-11-26T00:00:00Z"
|
||||
}
|
||||
```
|
||||
Download: `GET /graph/export/{jobId}` (returns file, headers include `X-Content-SHA256`).
|
||||
## Budgets and rate limits
|
||||
|
||||
## Health
|
||||
`GET /healthz` → 200 when service is ready; no auth/scopes required.
|
||||
Budget/rate-limit enforcement is explicit and deterministic:
|
||||
- Responses may include headers such as `X-RateLimit-Remaining` and `Retry-After`
|
||||
- `429` responses use a stable error envelope (see OpenAPI `components.responses`)
|
||||
|
||||
## Error envelope
|
||||
```json
|
||||
{ "error": "GRAPH_VALIDATION_FAILED", "message": "details", "requestId": "optional" }
|
||||
```
|
||||
## Overlays
|
||||
|
||||
## Notes
|
||||
- All timestamps UTC ISO-8601.
|
||||
- Ordering is deterministic; cursors are opaque base64 offsets.
|
||||
- Overlays use `policy.overlay.v1` and `openvex.v1` payloads. Budgeted tiles reserve room for cursors when `hasMore` is true.
|
||||
`node` and `edge` tiles may include overlays when requested. Overlays are keyed by overlay kind and carry `{kind, version, data}` so clients can render and cache without guessing schema.
|
||||
|
||||
For the cache/materialized representation used by gateway/UI tile caches, see `docs/api/graph/overlay-schema.md`.
|
||||
|
||||
## Errors and determinism
|
||||
|
||||
- Error shape follows platform conventions (see `docs/api/overview.md`), plus graph-specific error codes in the OpenAPI contract.
|
||||
- Determinism requirements:
|
||||
- stable ordering for equivalent requests
|
||||
- stable ids for nodes/edges where defined by schema
|
||||
- UTC ISO-8601 timestamps
|
||||
|
||||
@@ -1,42 +1,82 @@
|
||||
# Graph Overlay & Cache Schema (draft placeholder)
|
||||
# Graph overlay and tile cache schema (draft)
|
||||
|
||||
**Status:** Draft v0.2 · owner-proposed
|
||||
## Overview
|
||||
|
||||
## Scope
|
||||
- Overlay/cache schema for graph tiles used by Web gateway and UI overlays.
|
||||
- Validation rules for bbox/zoom/path; pagination tokens; deterministic ordering.
|
||||
- Error codes and sampling/telemetry fields.
|
||||
This document describes the cached/materialized tile representation used by gateway/UI components to store graph tiles alongside overlay data.
|
||||
|
||||
This cache schema is separate from the streaming NDJSON tile protocol:
|
||||
- Streaming API contract: `docs/api/graph-gateway-spec-draft.yaml`
|
||||
- Sample cached tile: `docs/api/graph/samples/overlay-sample.json`
|
||||
|
||||
## Cached tile shape
|
||||
|
||||
A cached tile document is a single JSON object with:
|
||||
- `version`: cache schema version (string; bump only for breaking changes)
|
||||
- `tenantId`: tenant partition for the cache entry
|
||||
- `tile`: tile identity + spatial key (`id`, `bbox`, `zoom`) and cache validator (`etag`)
|
||||
- `nodes`: node records
|
||||
- `edges`: edge records
|
||||
- `overlays`: overlay arrays keyed by overlay kind
|
||||
- `telemetry`: generation/caching metadata
|
||||
|
||||
## Schema (draft)
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"version": "2025-12-06",
|
||||
"version": "0.2",
|
||||
"tenantId": "tenant-default",
|
||||
"tile": {
|
||||
"id": "graph-tile::asset::<hash>::z8/x12/y5",
|
||||
"id": "graph-tile::<scope>::<hash>::z8/x12/y5",
|
||||
"bbox": { "minX": -122.41, "minY": 37.77, "maxX": -122.38, "maxY": 37.79 },
|
||||
"zoom": 8,
|
||||
"etag": "c0ffee-etag"
|
||||
},
|
||||
"nodes": [ { "id": "asset:...", "kind": "asset|component|vuln", "label": "", "severity": "high|medium|low|info", "reachability": "reachable|unreachable|unknown", "attributes": {} } ],
|
||||
"edges": [ { "id": "edge-1", "source": "nodeId", "target": "nodeId", "type": "depends_on|contains|evidence", "weight": 0.0 } ],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "asset:...",
|
||||
"kind": "asset|component|vuln",
|
||||
"label": "optional display label",
|
||||
"severity": "critical|high|medium|low|info",
|
||||
"reachability": "reachable|unreachable|unknown",
|
||||
"attributes": {}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-1",
|
||||
"source": "nodeId",
|
||||
"target": "nodeId",
|
||||
"type": "depends_on|contains|evidence",
|
||||
"weight": 0.0,
|
||||
"attributes": {}
|
||||
}
|
||||
],
|
||||
"overlays": {
|
||||
"policy": [ { "nodeId": "nodeId", "badge": "pass|warn|fail|waived", "policyId": "", "verdictAt": "2025-12-05T09:00:00Z" } ],
|
||||
"vex": [ { "nodeId": "nodeId", "state": "not_affected|fixed|under_investigation|affected", "statementId": "", "lastUpdated": "2025-12-05T09:10:00Z" } ],
|
||||
"aoc": [ { "nodeId": "nodeId", "status": "pass|fail|warn", "lastVerified": "2025-12-05T10:11:12Z" } ]
|
||||
"policy": [
|
||||
{ "nodeId": "nodeId", "badge": "pass|warn|fail|waived", "policyId": "policy://...", "verdictAt": "2025-01-02T03:04:05Z" }
|
||||
],
|
||||
"vex": [
|
||||
{ "nodeId": "nodeId", "state": "not_affected|fixed|under_investigation|affected", "statementId": "vex:...", "lastUpdated": "2025-01-02T03:04:05Z" }
|
||||
],
|
||||
"aoc": [
|
||||
{ "nodeId": "nodeId", "status": "pass|fail|warn", "lastVerified": "2025-01-02T03:04:05Z" }
|
||||
]
|
||||
},
|
||||
"telemetry": { "generationMs": 0, "cache": "hit|miss", "samples": 0 }
|
||||
}
|
||||
```
|
||||
|
||||
## Constraints (proposal)
|
||||
- Max nodes per tile: 2,000; max edges: 4,000.
|
||||
- Zoom range: 0–12; tiles must include bbox and etag.
|
||||
- Arrays must be pre-sorted: nodes by `id`, edges by `id`, overlays by `nodeId` then `policyId|statementId`.
|
||||
## Determinism rules
|
||||
|
||||
## Samples
|
||||
- `docs/api/graph/samples/overlay-sample.json`
|
||||
- Arrays are pre-sorted:
|
||||
- `nodes` by `id`
|
||||
- `edges` by `id`
|
||||
- overlay arrays by `nodeId` then secondary key (`policyId`, `statementId`, etc.)
|
||||
- Timestamps are ISO-8601 UTC.
|
||||
- Hashes are lower-case hex.
|
||||
|
||||
## Outstanding
|
||||
- Confirm max sizes, allowed edge types, and etag hashing rule.
|
||||
- Provide validation error example and rate-limit headers for gateway responses.
|
||||
## Constraints (draft)
|
||||
|
||||
- Max nodes per tile: 2,000
|
||||
- Max edges per tile: 4,000
|
||||
- Zoom range: 0-12
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2025-12-06",
|
||||
"version": "0.2",
|
||||
"tenantId": "tenant-default",
|
||||
"tile": {
|
||||
"id": "graph-tile::asset::sha256:abc123::z8/x12/y5",
|
||||
@@ -19,7 +19,6 @@
|
||||
"label": "app:1.2.3",
|
||||
"severity": "high",
|
||||
"reachability": "reachable",
|
||||
"aoc": { "summary": "pass", "lastVerified": "2025-12-05T10:11:12Z" },
|
||||
"attributes": {
|
||||
"purl": "pkg:docker/app@sha256:abc123",
|
||||
"componentCount": 42
|
||||
@@ -48,22 +47,22 @@
|
||||
"nodeId": "component:pkg:npm/jsonwebtoken@9.0.2",
|
||||
"badge": "fail",
|
||||
"policyId": "policy://tenant-default/runtime-hardening",
|
||||
"verdictAt": "2025-12-05T09:00:00Z"
|
||||
"verdictAt": "2025-01-02T03:04:05Z"
|
||||
}
|
||||
],
|
||||
"vex": [
|
||||
{
|
||||
"nodeId": "component:pkg:npm/jsonwebtoken@9.0.2",
|
||||
"state": "under_investigation",
|
||||
"statementId": "vex:tenant-default:jwt:2025-12-05",
|
||||
"lastUpdated": "2025-12-05T09:10:00Z"
|
||||
"statementId": "vex:tenant-default:jwt:0001",
|
||||
"lastUpdated": "2025-01-02T03:04:05Z"
|
||||
}
|
||||
],
|
||||
"aoc": [
|
||||
{
|
||||
"nodeId": "asset:registry.local/library/app@sha256:abc123",
|
||||
"status": "pass",
|
||||
"lastVerified": "2025-12-05T10:11:12Z"
|
||||
"lastVerified": "2025-01-02T03:04:05Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Scanner API Docs — Windows/macOS Coverage (Draft)
|
||||
|
||||
This directory collects interim artefacts tracking customer demand and roadmap readiness for extending Scanner coverage to Windows and macOS.
|
||||
|
||||
## Files
|
||||
- `windows-coverage.md` — narrative summary of customer signals and required artefacts.
|
||||
- `windows-macos-summary.md` — dashboard-style snapshot (counts, cross-references) updated after each discovery cycle.
|
||||
|
||||
## Related resources
|
||||
- `../../modules/scanner/design/README.md`
|
||||
- `../../benchmarks/scanner/windows-macos-demand.md`
|
||||
- `../../benchmarks/scanner/windows-macos-interview-template.md`
|
||||
- `../../modules/scanner/design/macos-analyzer.md`
|
||||
- `../../modules/scanner/design/windows-analyzer.md`
|
||||
- `../../modules/policy/windows-package-readiness.md`
|
||||
- `../../modules/policy/secret-leak-detection-readiness.md`
|
||||
|
||||
> Note: replace these working notes with formal API documentation once Windows/macOS analyzer endpoints are defined.
|
||||
@@ -1,50 +0,0 @@
|
||||
# Scanner API — Windows/macOS Coverage Signals (Draft)
|
||||
|
||||
> Audience: Solutions engineers, product managers, guild leads coordinating Windows/macOS roadmap
|
||||
> Status: Informational; update as interviews conclude
|
||||
|
||||
## Summary
|
||||
| Region | Accounts referenced | Primary workloads | Demand strength (1-5) | Blocking? | Notes |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| North America | Northwind Health Services; FinSecure Corp | macOS CI runners; Windows Server 2019 workloads | 4-5 | macOS: evaluation; Windows: blocking | Demo 2025-11-10; Security decision due 2025-11-07. |
|
||||
| EMEA | — | — | — | — | — |
|
||||
| APAC | — | — | — | — | — |
|
||||
| Gov / Regulated | — | — | — | — | — |
|
||||
|
||||
### Key drivers
|
||||
- Customers with regulated Windows Server/desktop estates lack deterministic SBOM coverage and provenance.
|
||||
- macOS development shops (Mobile, Gaming) require entitlements/notarization evidence for compliance.
|
||||
- Offline/air-gapped environments need signed rule bundles and feed mirrors for Windows/macOS ecosystems.
|
||||
|
||||
### Competitive landscape
|
||||
- Trivy/Grype/Snyk remain Linux-focused; Windows/macOS features are roadmap items or SaaS-only.
|
||||
- Opportunity to differentiate via deterministic evidence, policy integration, and offline parity.
|
||||
|
||||
### Design references
|
||||
- `../../modules/scanner/design/macos-analyzer.md`
|
||||
- `../../modules/scanner/design/windows-analyzer.md`
|
||||
|
||||
### Action items
|
||||
- Maintain region rows using interview summaries from `docs/benchmarks/scanner/windows-macos-demand.md` (last update 2025-11-03; capture via the interview template).
|
||||
- Track readiness decisions by updating POLICY-READINESS-0001/0002 status and recording outcomes in the summary table.
|
||||
- Align backlog references (`SCANNER-ENG-0020..0027`, `DOCS-SCANNER-BENCH-62-016`) with product prioritisation after each roadmap review.
|
||||
|
||||
### Open blockers
|
||||
- FinSecure PCI audit pending POLICY-READINESS-0002 decision (due 2025-11-07); unblock Windows analyzer spike scheduling.
|
||||
- Northwind macOS readiness workshop scheduled 2025-11-10; capture masking/telemetry decisions for POLICY-READINESS-0001.
|
||||
|
||||
## Interview log (selected)
|
||||
| Date | Customer | Platform focus | Signal summary | Strength (1-5) | Follow-up |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2025-11-03 | Northwind Health Services | macOS | Needs notarization/entitlement visibility for CI runners | 4 | Demo 2025-11-10 with Product; feed findings into POLICY-READINESS-0001. |
|
||||
| 2025-11-03 | FinSecure Corp | Windows | Requires MSI/WinSxS SBOM + signed driver attestations for PCI audit | 5 | Security guild to resolve Authenticode posture (POLICY-READINESS-0002) by 2025-11-07. |
|
||||
|
||||
## Required artefacts
|
||||
- Maintain interview notes using `docs/benchmarks/scanner/windows-macos-interview-template.md`.
|
||||
- Update demand tracker tables in `docs/benchmarks/scanner/windows-macos-demand.md`.
|
||||
- Sync backlog entries in `docs/modules/scanner/TASKS.md` and `docs/scanner/design/*.md`.
|
||||
|
||||
## Next steps
|
||||
1. Collect at least three qualified Windows and macOS requests; update summary table.
|
||||
2. Present findings to Scanner Guild for prioritisation (target Sprint 133 design spike).
|
||||
3. Coordinate policy readiness briefs (`docs/modules/policy/windows-package-readiness.md`) and design docs (`design/macos-analyzer.md`, `design/windows-analyzer.md`).
|
||||
@@ -1,37 +0,0 @@
|
||||
# Scanner API — Windows/macOS Coverage Dashboard (Draft)
|
||||
|
||||
> Owners: Product Guild, Scanner Guild • Status: living document updated every sprint
|
||||
|
||||
## At-a-glance metrics (Sprint 132 intake)
|
||||
- macOS demand entries logged: 1 (Northwind Health Services, 2025-11-03)
|
||||
- Windows demand entries logged: 1 (FinSecure Corp, 2025-11-03)
|
||||
- Qualified customers awaiting roadmap response: 1 (FinSecure PCI blocker)
|
||||
- Open policy readiness items: POLICY-READINESS-0001, POLICY-READINESS-0002
|
||||
|
||||
## Cross-reference
|
||||
| Resource | Purpose |
|
||||
| --- | --- |
|
||||
| docs/benchmarks/scanner/windows-macos-demand.md | Signal log & next actions |
|
||||
| docs/benchmarks/scanner/windows-macos-interview-template.md | Interview capture template |
|
||||
| docs/benchmarks/scanner/deep-dives/macos.md | macOS implementation roadmap |
|
||||
| docs/benchmarks/scanner/deep-dives/windows.md | Windows implementation roadmap |
|
||||
| docs/modules/scanner/design/macos-analyzer.md | Detailed macOS design |
|
||||
| docs/modules/scanner/design/windows-analyzer.md | Detailed Windows design |
|
||||
| docs/modules/policy/windows-package-readiness.md | Policy readiness for Windows packages |
|
||||
| docs/modules/policy/secret-leak-detection-readiness.md | Policy readiness for secrets |
|
||||
| docs/modules/scanner/TASKS.md | Engineering backlog (SCANNER-ENG-0020..0027) |
|
||||
| docs/modules/policy/TASKS.md | Policy readiness tasks |
|
||||
| docs/api/scanner/windows-coverage.md | Narrative summary |
|
||||
|
||||
## Maintenance cadence
|
||||
- Update metrics and cross-links after each customer signal or roadmap checkpoint.
|
||||
- Ensure DOCS-SCANNER-BENCH-62-002/016 status mirrors demand tracker progress.
|
||||
|
||||
## Upcoming milestones
|
||||
- 2025-11-07: POLICY-READINESS-0002 Authenticode/feed decision for FinSecure (unblocks Windows analyzer spike).
|
||||
- 2025-11-10: POLICY-READINESS-0001 workshop during Northwind demo to finalise masking/telemetry posture.
|
||||
|
||||
## Recent updates
|
||||
- 2025-11-03: Logged Northwind Health Services (macOS) & FinSecure Corp (Windows); awaiting POLICY-READINESS-0001/0002 decisions before scheduling analyzer spikes.
|
||||
|
||||
Last updated: 2025-11-03 (initial demand entries logged).
|
||||
@@ -1,29 +0,0 @@
|
||||
# Vulnerability API (placeholder)
|
||||
|
||||
Status: Draft (2025-11-26) — awaiting Vuln Explorer v1 surface. This doc reserves the path and headers to align with upcoming releases.
|
||||
|
||||
## Base URL
|
||||
`<gateway>/api/vuln` (subject to final routing via API gateway).
|
||||
|
||||
## Common headers
|
||||
- `X-Stella-Tenant` (required)
|
||||
- `Authorization: Bearer <token>`
|
||||
- `X-Stella-Scopes`: expect `vuln:read` (TBD) and/or `graph:read` when graph-backed queries are invoked.
|
||||
- `Content-Type: application/json`
|
||||
|
||||
## Planned endpoints (subject to change)
|
||||
- `POST /vuln/search` — filter vulnerabilities by component (purl/digest), advisory id, status, exploitability (OpenVEX).
|
||||
- `POST /vuln/impact` — compute impacted assets using Graph overlays; may proxy to Graph API internally.
|
||||
- `GET /vuln/{id}` — details with references, VEX status, nearest safe version.
|
||||
- `GET /vuln/{id}/evidence` — raw evidence (SBOM snapshot refs, observations).
|
||||
- `GET /vuln/kev` — Known Exploited Vulnerabilities view (cached).
|
||||
|
||||
## Error envelope
|
||||
Follows Graph/Platform standard:
|
||||
```json
|
||||
{ "error": "VULN_VALIDATION_FAILED", "message": "details", "requestId": "optional" }
|
||||
```
|
||||
|
||||
## Notes
|
||||
- This placeholder will be updated once Vuln Explorer API is finalized. Keep gateway clients tolerant to minor shape changes until status flips to READY.
|
||||
- For current graph-backed queries, use `/graph/search` or `/graph/query` (see `docs/api/graph.md`).
|
||||
Reference in New Issue
Block a user