Advisory Gateway Contract (draft v0.1)
This contract defines a proposed proxy for advisory surfaces through the StellaOps Web gateway: tenant-scoped, deterministic responses with ETag caching and offline-friendly pagination. It is the reference shape for the Console advisory client and offline samples.
Audience: gateway and Console integrators. Read the Status section first — the plain list/detail surface below is a forward design contract, not a live route today.
Status
- Forward design contract — NOT served at this gateway path today. No gateway route table entry maps
GET /advisoriesorGET /advisories/{advisoryId}to a backend; the only consumer of theAdvisoryListResponse/AdvisoryDetailshape described below is the Console clientAdvisoryApiHttpClient(src/Web/StellaOps.Web/src/app/core/api/advisories.client.ts), which targets a configurableADVISORY_API_BASE_URLinjection token, plus the offline sample fixtures insamples/. The base URL is currently unwired to a live upstream. - Live Concelier advisory surface (ground truth,
StellaOps.Concelier.WebService/Program.cs):GET /advisories/raw,GET /advisories/raw/{id},GET /advisories/raw/{id}/provenanceGET /advisories/observations,GET /advisories/linksets,GET /advisories/linksets/exportGET /advisories/summary,GET /advisories/{advisoryKey}/chunks- Canonical advisory service under
GET /api/v1/canonical,GET /api/v1/canonical/{id:guid},POST /api/v1/canonical/ingest/{source}(seeExtensions/CanonicalAdvisoryEndpointExtensions.cs). - Gateway routes that exist today:
^/advisories/raw(.*)and^/concelier/advisories/raw(.*)→ Concelier, and^/api/v1/advisory-sources(.*)→ Concelier (seeGatewayRouteSearchMappingsTests.cs). The plain list/detail contract below is additive and unrouted.
- The field and enum names in this contract are reconciled against the Console models (
src/Web/StellaOps.Web/src/app/core/api/advisories.models.ts) and the offline samples; treat them as the canonical shape for the proposed proxy.
Security / headers
Authorization: Bearer <token>(or DPoP where configured; seedocs/api/gateway/tenant-auth.md).X-StellaOps-TenantId: <tenantId>(required; seedocs/api/gateway/tenant-auth.md).X-StellaOps-Project: <projectId>(optional). Header constantStellaOpsHeaders.Project.X-StellaOps-TraceId: <traceId>(optional; the Console client always sends one, auto-generated when omitted).X-StellaOps-RequestId: <requestId>(the Console client sends this mirroringX-StellaOps-TraceId).If-None-Match: <etag>(optional; for conditional GET).- Scopes:
advisory:read(StellaOpsScopes.AdvisoryRead). Ingestion/write surfaces useadvisory:ingest(StellaOpsScopes.AdvisoryIngest).
Endpoints
GET /advisories— list advisories (tenant-scoped).- Query params:
search,severity,sortBy,sortOrder,limit,continuationToken. severity∈critical | high | medium | low | none | unknown.sortBy∈updatedAt | publishedAt | severity | advisoryId.sortOrder∈asc | desc.- Response:
AdvisoryListResponse(see fields and sample below).
- Query params:
GET /advisories/{advisoryId}— advisory detail (tenant-scoped).- Response:
AdvisoryDetail(see fields and sample below).
- Response:
Response shapes
Reconciled against advisories.models.ts and the offline samples.
AdvisoryListResponse:items: AdvisorySummary[]count: numbercontinuationToken: string | nulletag?: stringtraceId?: string
AdvisorySummary:advisoryId: stringsource: cve | ghsa | vendor | distro | othertitle: stringseverity: critical | high | medium | low | none | unknownpublishedAt: string(ISO-8601 UTC)updatedAt?: stringcveIds?: string[]affectedPurls?: string[]etag?: string
AdvisoryDetailextendsAdvisorySummaryand adds:description?: stringreferences?: { label: string; url: string }[]advisoryUrl?: string
Caching & pagination
limitmax:200(enforced client-side asAdvisoryApiHttpClient.MAX_PAGE_SIZE; requests above the cap are rejected before dispatch).- Cursor/paging uses
continuationToken(opaque string); the list response returns the nextcontinuationToken(ornullwhen exhausted). ETagMUST be a stable hash over a sorted payload; clients MAY sendIf-None-Match.- Recommended headers:
Cache-Control: private, max-age=60, stale-if-error=300.
Determinism rules
- Ordering:
itemssorted by(advisoryId asc)unlesssortByis supplied; ties break byadvisoryId. - Timestamps: ISO-8601 UTC.
Samples
docs/api/gateway/samples/advisories-list.jsondocs/api/gateway/samples/advisory-detail.json
