up
This commit is contained in:
@@ -1,66 +1,63 @@
|
||||
# Signals Reachability API Contract (draft placeholder)
|
||||
# Signals API (Reachability)
|
||||
|
||||
**Status:** Draft v0.2 · owner-proposed
|
||||
**Status:** Working contract (aligns with `src/Signals/StellaOps.Signals/Program.cs`).
|
||||
|
||||
## Scope
|
||||
- `/signals/callgraphs`, `/signals/facts`, reachability scoring overlays feeding UI/Web.
|
||||
- Deterministic fixtures for SIG-26 chain (columns/badges, call paths, timelines, overlays, coverage).
|
||||
## Auth, scopes, sealed mode
|
||||
|
||||
- **Scopes:** `signals:read`, `signals:write`, `signals:admin` (endpoint-specific; see below).
|
||||
- **Dev fallback:** when Authority auth is disabled, requests must include `X-Scopes: <space-separated scopes>` (example: `X-Scopes: signals:write`).
|
||||
- **Sealed mode:** when enabled, Signals may return `503` with `{ "error": "sealed-mode evidence invalid", ... }`.
|
||||
|
||||
## Endpoints
|
||||
- `GET /signals/callgraphs` — returns call paths contributing to reachability.
|
||||
- `GET /signals/facts` — returns reachability/coverage facts.
|
||||
|
||||
Common headers: `Authorization: DPoP <token>`, `DPoP: <proof>`, `X-StellaOps-Tenant`, optional `If-None-Match`.
|
||||
Pagination: cursor via `pageToken`; default 50, max 200.
|
||||
ETag: required on responses; clients must send `If-None-Match` for cache validation.
|
||||
### Health & status
|
||||
|
||||
### Callgraphs response (draft)
|
||||
```jsonc
|
||||
{
|
||||
"tenantId": "tenant-default",
|
||||
"assetId": "registry.local/library/app@sha256:abc123",
|
||||
"paths": [
|
||||
{
|
||||
"id": "path-1",
|
||||
"source": "api-gateway",
|
||||
"target": "jwt-auth-service",
|
||||
"hops": [
|
||||
{ "service": "api-gateway", "endpoint": "/login", "timestamp": "2025-12-05T10:00:00Z" },
|
||||
{ "service": "jwt-auth-service", "endpoint": "/verify", "timestamp": "2025-12-05T10:00:01Z" }
|
||||
],
|
||||
"evidence": { "traceId": "trace-abc", "spanCount": 2, "score": 0.92 }
|
||||
}
|
||||
],
|
||||
"pagination": { "nextPageToken": null },
|
||||
"etag": "sig-callgraphs-etag"
|
||||
}
|
||||
```
|
||||
- `GET /healthz` (anonymous)
|
||||
- `GET /readyz` (anonymous; `503` when not ready or sealed-mode blocked)
|
||||
- `GET /signals/ping` (scope: `signals:read`, response: `204`)
|
||||
- `GET /signals/status` (scope: `signals:read`)
|
||||
|
||||
### Facts response (draft)
|
||||
```jsonc
|
||||
{
|
||||
"tenantId": "tenant-default",
|
||||
"facts": [
|
||||
{
|
||||
"id": "fact-1",
|
||||
"type": "reachability",
|
||||
"assetId": "registry.local/library/app@sha256:abc123",
|
||||
"component": "pkg:npm/jsonwebtoken@9.0.2",
|
||||
"status": "reachable",
|
||||
"confidence": 0.88,
|
||||
"observedAt": "2025-12-05T10:10:00Z",
|
||||
"signalsVersion": "signals-2025.310.1"
|
||||
}
|
||||
],
|
||||
"pagination": { "nextPageToken": "..." },
|
||||
"etag": "sig-facts-etag"
|
||||
}
|
||||
```
|
||||
### Callgraph ingestion & retrieval
|
||||
|
||||
### Samples
|
||||
- Callgraphs: `docs/api/signals/samples/callgraph-sample.json`
|
||||
- Facts: `docs/api/signals/samples/facts-sample.json`
|
||||
- `POST /signals/callgraphs` (scope: `signals:write`)
|
||||
- Body: `CallgraphIngestRequest` (`language`, `component`, `version`, `artifactContentBase64`, …).
|
||||
- Response: `202 Accepted` with `CallgraphIngestResponse` and `Location: /signals/callgraphs/{callgraphId}`.
|
||||
- Graph hash is computed deterministically from normalized nodes/edges/roots; see `graphHash` in the response.
|
||||
- `GET /signals/callgraphs/{callgraphId}` (scope: `signals:read`)
|
||||
- `GET /signals/callgraphs/{callgraphId}/manifest` (scope: `signals:read`)
|
||||
|
||||
### Outstanding
|
||||
- Finalize score model, accepted `type` values, and max page size.
|
||||
- Provide OpenAPI/JSON schema and error codes.
|
||||
Sample request: `docs/api/signals/samples/callgraph-sample.json`
|
||||
|
||||
### Runtime facts ingestion
|
||||
|
||||
- `POST /signals/runtime-facts` (scope: `signals:write`)
|
||||
- Body: `RuntimeFactsIngestRequest` with `subject`, `callgraphId`, and `events[]`.
|
||||
- `POST /signals/runtime-facts/ndjson?callgraphId=...&scanId=...` (scope: `signals:write`)
|
||||
- Body: NDJSON of `RuntimeFactEvent` objects; `Content-Encoding: gzip` supported.
|
||||
- `POST /signals/runtime-facts/synthetic` (scope: `signals:write`)
|
||||
- Generates a small deterministic sample set of runtime events for a callgraph to unblock testing.
|
||||
|
||||
### Unknowns ingestion & retrieval
|
||||
|
||||
- `POST /signals/unknowns` (scope: `signals:write`)
|
||||
- Body: `UnknownsIngestRequest` (`subject`, `callgraphId`, `unknowns[]`).
|
||||
- `GET /signals/unknowns/{subjectKey}` (scope: `signals:read`)
|
||||
|
||||
### Reachability scoring & facts
|
||||
|
||||
- `POST /signals/reachability/recompute` (scope: `signals:admin`)
|
||||
- Body: `ReachabilityRecomputeRequest` (`callgraphId`, `subject`, `entryPoints[]`, `targets[]`, optional `runtimeHits[]`, optional `blockedEdges[]`).
|
||||
- Response: `200 OK` with `{ id, callgraphId, subject, entryPoints, states, computedAt }`.
|
||||
- `GET /signals/facts/{subjectKey}` (scope: `signals:read`)
|
||||
- Response: `ReachabilityFactDocument` (per-target states, `score`, `riskScore`, unknowns pressure, optional uncertainty states, runtime facts snapshot).
|
||||
|
||||
Sample fact: `docs/api/signals/samples/facts-sample.json`
|
||||
|
||||
### Reachability union bundle ingestion (CAS layout)
|
||||
|
||||
- `POST /signals/reachability/union` (scope: `signals:write`)
|
||||
- Body: `application/zip` bundle containing `nodes.ndjson`, `edges.ndjson`, `meta.json`.
|
||||
- Optional header: `X-Analysis-Id` (defaults to a new GUID if omitted).
|
||||
- Response: `202 Accepted` with `ReachabilityUnionIngestResponse` and `Location: /signals/reachability/union/{analysisId}/meta`.
|
||||
- `GET /signals/reachability/union/{analysisId}/meta` (scope: `signals:read`)
|
||||
- `GET /signals/reachability/union/{analysisId}/files/{fileName}` (scope: `signals:read`)
|
||||
|
||||
Reference in New Issue
Block a user