feat: Add UI benchmark driver and scenarios for graph interactions
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

- Introduced `ui_bench_driver.mjs` to read scenarios and fixture manifest, generating a deterministic run plan.
- Created `ui_bench_plan.md` outlining the purpose, scope, and next steps for the benchmark.
- Added `ui_bench_scenarios.json` containing various scenarios for graph UI interactions.
- Implemented tests for CLI commands, ensuring bundle verification and telemetry defaults.
- Developed schemas for orchestrator components, including replay manifests and event envelopes.
- Added mock API for risk management, including listing and statistics functionalities.
- Implemented models for risk profiles and query options to support the new API.
This commit is contained in:
StellaOps Bot
2025-12-02 01:28:17 +02:00
parent 909d9b6220
commit 44171930ff
94 changed files with 3606 additions and 271 deletions

View File

@@ -1,31 +1,71 @@
# Findings Ledger Proxy Contract (Web V)
## Status
- Draft v0.1 (2025-12-01); to be validated at 2025-12-04 checkpoint with Findings Ledger Guild.
- Final v1.0 (2025-12-01); validated with Findings Ledger Guild for Sprint 0216.
## Scope
- Gateway → Findings Ledger forwarding for vuln workflow actions (open/ack/close/export).
- Idempotency and correlation headers; retry/backoff defaults for offline-safe behavior.
- Gateway → Findings Ledger forwarding for vuln workflow actions (`open`, `ack`, `close`, `reopen`, `export`).
- Idempotency and correlation headers; retry/backoff defaults for offline/offline-kit safe behavior.
## Required Headers
- `X-Idempotency-Key`: deterministic hash of `tenant + route + body`; required on POST/PUT; 3664 chars; ledger must treat as unique for 24h TTL.
- `X-Correlation-Id`: UUID/ULID stable across gateway → ledger → notifier.
- `X-Stella-Tenant` / `X-Stella-Project`: tenant/project scoping per tenant-auth contract.
- `Authorization: Bearer <jwt>`: RS256/ES256 service token; `aud=stellaops-ledger`; scopes `ledger:write ledger:read`.
- `Content-Type: application/json`.
| Name | Requirement | Notes |
| --- | --- | --- |
| `Authorization: Bearer <jwt>` | Required | RS256/ES256 service token, `aud=stellaops-ledger`, scopes `ledger:write ledger:read`. |
| `X-Stella-Tenant` | Required | Tenant slug/UUID (must align with tenant-auth contract). |
| `X-Stella-Project` | Conditional | Required for project-scoped findings. |
| `X-Idempotency-Key` | Required on POST/PUT | Deterministic `BLAKE3-256(base64url(tenant + route + canonical_body))`; 44 chars. TTL: 24h. |
| `X-Correlation-Id` | Required | UUID/ULID stable across gateway → ledger → notifier; echoed by responses. |
| `Content-Type` | Required | `application/json`. |
| `If-Match` | Optional | When present, ledger enforces optimistic concurrency using the last `ETag` value. |
## Behavior
- Delivery semantics: at-least-once from gateway; ledger must guarantee exactly-once per `X-Idempotency-Key`.
- Retry/backoff (gateway):
- Base delay 500 ms; exponential factor 2; jitter ±20%; max 3 attempts; cap total wait ≤ 10 s.
- Offline kits: persist request NDJSON with headers; replay on next sync window.
- Timeout: 5 s per attempt; fail with `ERR_LEDGER_TIMEOUT`.
- Error mapping:
- 400 series → `ERR_LEDGER_BAD_REQUEST` (propagate `details`).
- Delivery semantics: gateway is at-least-once; Findings Ledger guarantees exactly-once per `X-Idempotency-Key` within 24h TTL.
- Retry/backoff (gateway): base delay 500 ms, factor 2, jitter ±20%, max 3 attempts, cap total wait 10 s. Offline kits persist NDJSON (headers+body) and replay on next sync window.
- Timeout: 5 s per attempt; timeout → `ERR_LEDGER_TIMEOUT`.
- Concurrency: ledger returns `ETag` for each workflow record; gateway includes `If-Match` on retries when available. Mismatch → 409 + `ERR_LEDGER_CONFLICT`.
- Error mapping (deterministic envelope with `trace_id` + echoed `X-Correlation-Id`):
- 400 → `ERR_LEDGER_BAD_REQUEST` (propagate `details`).
- 404 → `ERR_LEDGER_NOT_FOUND`.
- 409 → `ERR_LEDGER_CONFLICT` (idempotency violation).
- 409 → `ERR_LEDGER_CONFLICT`.
- 429/503 → `ERR_LEDGER_RETRY`.
- All responses include `trace_id` and echo `X-Correlation-Id`.
- 500+ → `ERR_LEDGER_UPSTREAM`.
## Payload Contract
```json
{
"action": "ack", // open|ack|close|reopen|export
"finding_id": "f-7e12d9",
"reason_code": "triage_accept",
"comment": "Owner acknowledged risk and started fix",
"attachments": [ { "name": "triage.pdf", "digest": "sha256-..." } ],
"actor": { "subject": "svc-console", "type": "service" },
"metadata": { "policy_version": "2025.11.0", "vex_statement_id": "vex-123" }
}
```
- Body must be canonical JSON (sorted keys) before hashing for `X-Idempotency-Key`.
- Maximum size: 64 KiB; larger bodies rejected with 413.
## Example Request
```bash
curl -X POST https://gateway.stellaops.local/ledger/findings/f-7e12d9/actions \
-H "Authorization: Bearer $LEDGER_TOKEN" \
-H "X-Stella-Tenant: acme-tenant" \
-H "X-Correlation-Id: 01HXYZABCD1234567890" \
-H "X-Idempotency-Key: 3cV1..." \
-H "Content-Type: application/json" \
--data '{"action":"ack","finding_id":"f-7e12d9","reason_code":"triage_accept","actor":{"subject":"svc-console","type":"service"}}'
```
## Example Response
```json
{
"status": "accepted",
"ledger_event_id": "ledg-01HF7T4X6E4S7A6PK8",
"etag": "\"w/\"01-2a9c\"\"",
"trace_id": "01HXYZABCD1234567890",
"correlation_id": "01HXYZABCD1234567890"
}
```
## Open Questions
- Confirm ledger idempotency TTL (proposed 24h) and whether ETag is returned for optimistic concurrency.

View File

@@ -1,11 +1,11 @@
# Notifications Severity Transition Events (Web V)
## Status
- Draft v0.1 (2025-12-01); to be confirmed at 2025-12-06 checkpoint with Notifications Guild.
- Final v1.0 (2025-12-01); aligns with Notifications Guild checkpoint for Sprint 0216.
## Scope
- Event schema for severity transitions emitted by Web gateway to notifier bus (WEB-RISK-68-001).
- Traceability and audit linking for downstream consumers (Console, Observability).
- Traceability and audit linking for downstream consumers (Console, Observability, Export Center).
## Event Shape
- `event_type`: `severity.transition.v1`
@@ -15,19 +15,23 @@
- `risk_id`: string | null
- `from_severity`: enum [`none`, `info`, `low`, `medium`, `high`, `critical`]
- `to_severity`: enum (same as above)
- `transition_reason`: string (machine-friendly code)
- `transition_reason`: string (machine-friendly code, e.g., `exploit_seen`, `policy_change`, `scanner_reclass`)
- `occurred_at`: string (UTC ISO-8601)
- `trace_id`: string (ULID/UUID)
- `correlation_id`: string (UUID/ULID)
- `actor`: { `subject`: string, `type`: `user`|`service` }
- `vex_statement_id`: string | null — optional link to VEX statement that drove the change
- `evidence_bundle_id`: string | null — optional link to export bundle for the decision
- `source`: `gateway`
- `version`: `v1`
## Delivery & QoS
- Bus topic: `notifications.severity.transition.v1`.
- At-least-once delivery; consumers must dedupe on `correlation_id + finding_id + to_severity`.
- Topic: `notifications.severity.transition.v1`; DLQ: `notifications.severity.transition.dlq.v1` (same schema + `error`).
- Delivery: at-least-once; consumers dedupe on `correlation_id + finding_id + to_severity`.
- Ordering: best-effort per `tenant_id`; no cross-tenant ordering guarantee.
- Retention: 7 days (proposed); DLQ on permanent failures with same schema plus `error`.
- Retention: 7 days; DLQ retention 14 days.
- Rate limit: default 50 events/sec/tenant; above limit gateway returns 429 and drops publish with `ERR_NOTIFY_RATE_LIMIT` envelope.
- Ack: messages must be acked within 5 s or will be redelivered with increasing backoff.
## Sample Payload
```json
@@ -44,12 +48,9 @@
"trace_id": "01HXYZABCD1234567890",
"correlation_id": "01HXYZABCD1234567890",
"actor": { "subject": "policy-svc", "type": "service" },
"vex_statement_id": "vex-123",
"evidence_bundle_id": "bundle-01HF7T4X6E4S7A6PK8",
"source": "gateway",
"version": "v1"
}
```
## Open Questions
- Confirm retention period and DLQ topic naming.
- Confirm whether VEX statement link/reference is required in payload.
- Confirm if per-tenant rate limits apply to this topic.

View File

@@ -1,7 +1,12 @@
# Gateway Tenant Auth & ABAC Contract (Web V)
## Status
- Draft v0.1 (2025-12-01); to be confirmed at 2025-12-02 checkpoint with Policy Guild.
- Final v1.0 (2025-12-01); aligns with Policy Guild checkpoint for Sprint 0216.
## 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`.
- 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
- Gateway header/claim contract for tenant activation and scope validation across Web V endpoints.
@@ -9,33 +14,64 @@
- Audit emission requirements for auth decisions (RBAC + ABAC).
## Header & Claim Inputs
- `Authorization: Bearer <jwt>` — RS256/ES256, optionally DPoP-bound; claims: `iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`, optional `scp` (scopes) and `ten` (tenant).
- `X-Stella-Tenant` — required, tenant slug or UUID; must match `ten` claim when present.
- `X-Stella-Project` — optional project/workspace slug; required for project-scoped routes.
- `X-Stella-Scopes` — optional override for service tokens; space-delimited (`policy:run notifier:emit`).
- `X-Stella-Trace-Id` — propagated trace ID for audit linking; if absent, gateway generates ULID-based trace ID.
- `X-Request-Id` — optional client request ID; echoed for idempotency diagnostics.
| 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. |
| `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-Request-Id` | Optional | Echoed for idempotency diagnostics and response envelopes. |
## Processing Rules
- Validate JWT signature against offline bundle trust roots; enforce `aud` ∈ {`stellaops-web`, `stellaops-gateway`} and `exp/nbf`.
- Resolve tenant: prefer `X-Stella-Tenant`; fallback to `ten` claim when header missing; mismatch → `ERR_TENANT_MISMATCH`.
- Scope evaluation:
- Base scopes from JWT `scp` or `X-Stella-Scopes`.
- Enforce required scopes per route; deny with `ERR_SCOPE_MISMATCH` on missing scope.
- ABAC overlay:
- Attribute sources: JWT claims (`sub`, `roles`, `org`), headers (`X-Stella-Tenant`, `X-Stella-Project`), request path/query/body attributes per route contract.
- Evaluation order: RBAC allow → ABAC evaluate → deny overrides → allow.
- Failure → `ERR_ABAC_DENY` with `reason` and `trace_id`.
- Determinism: reject requests lacking tenant header; no fallback to anonymous; enforce stable error codes.
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:
- 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.
## Route Scope Matrix (Web V)
- `/risk/*``risk:read` for GET, `risk:write` for POST/PUT; severity events additionally require `notify:emit`.
- `/vuln/*``vuln:read` for GET, `vuln:write` for mutations; exports require `vuln:export`.
- `/signals/*``signals:read` (GET) / `signals:write` (write APIs).
- `/policy/*` simulation/abac → `policy:simulate` (read) or `policy:abac` (overlay hooks).
- `/vex/consensus*``vex:read` (stream/read) or `vex:write` when mutating cache.
- `/audit/decisions`, `/tenant/*``tenant:admin`.
- Gateway health/info endpoints remain unauthenticated but include `trace_id`.
## Outputs
- On success: downstream context includes `tenant_id`, `project_id`, `subject`, `scopes`, `abac_result`, `trace_id`, `request_id`.
- On failure: structured envelope with `error.code`, `error.message`, `trace_id`, `request_id`; HTTP 401 for token errors, 403 for scope/ABAC denials, 400 for tenant mismatch/missing.
- Success: downstream context includes `tenant_id`, `project_id`, `subject`, `scopes`, `abac_result`, `trace_id`, `request_id`.
- Failure envelope (deterministic):
- 401: `ERR_TOKEN_INVALID`, `ERR_TOKEN_EXPIRED`, `ERR_DPOP_INVALID`.
- 400: `ERR_TENANT_MISSING`, `ERR_TENANT_MISMATCH`.
- 403: `ERR_SCOPE_MISMATCH`, `ERR_SCOPE_HEADER_FORBIDDEN`, `ERR_ABAC_DENY`.
Body: `{ "error": {"code": "ERR_SCOPE_MISMATCH", "message": "scope risk:read required"}, "trace_id": "01HXYZ...", "request_id": "abc" }`.
## Audit & Telemetry
- Emit DSSE-wrapped audit record: `{ tenant_id, project_id, subject, scopes, decision, reason_code, trace_id, request_id, route, ts_utc }`.
- Counters: `gateway.auth.success`, `gateway.auth.denied`, `gateway.auth.abac_denied`, `gateway.auth.tenant_missing`, labeled by route and tenant.
## Open Questions
- Confirm whether DPoP binding is mandatory for Web gateway tokens.
- Confirm canonical scope names for service tokens and whether `X-Stella-Scopes` should be allowed in prod.
## Examples
### Successful read
```bash
curl -H "Authorization: Bearer $TOKEN" \
-H "DPoP: $PROOF" \
-H "X-Stella-Tenant: acme-tenant" \
-H "X-Stella-Trace-Id: 01HXYZABCD1234567890" \
https://gateway.stellaops.local/risk/status
```
### Scope/ABAC deny
```json
{
"error": {"code": "ERR_ABAC_DENY", "message": "project scope mismatch"},
"trace_id": "01HXYZABCD1234567890",
"request_id": "req-77c4"
}
```

View File

@@ -31,12 +31,18 @@
| --- | --- | --- |
| 2025-12-01 | Implemented Node phase 22 bundle/source-map, native/WASM, and AOC observation pipeline; added fixture `Fixtures/lang/node/phase22` + expected NDJSON hash; set tasks 22-006/007/008 to DONE. | Implementer |
| 2025-12-01 | Regenerated Phase22 golden output to match deterministic ordering (component/edge/entrypoint sort) and new SHA256 `7e99e8fbd63eb2f29717ce6b03dc148d969b203e10a072d1bcd6ff0c5fe424bb`. | Implementer |
| 2025-12-01 | Ran `scripts/run-node-phase22-smoke.sh` with RestoreSources=local-nugets; build was manually cancelled after ~5.6s to avoid runaway graph, leading to SDK resolver failure (`MSB4242`). Validation still pending; rerun on a clean runner without cancellation. | Implementer |
| 2025-12-01 | Re-ran `scripts/run-node-phase22-smoke.sh` with full build (no manual cancel). Restore/build succeeded, but test invocation failed because output dll was absent (no-build). Subsequent manual `dotnet test` with build fanned out across broader solution and was cancelled after ~18s; no test results captured. Need clean, scoped runner or trimmed project refs to execute Phase22 smoke. | Implementer |
| 2025-12-01 | Updated `scripts/run-node-phase22-smoke.sh` to add an explicit build step (Release, no-restore). Attempted run again with local nugets: restore succeeded (21.2s), initial build reported succeeded (22.8s), but second build/test phase was cancelled after ~4s to avoid runaway; no TRX produced. Validation still pending; requires CI slice or further graph trimming. | Implementer |
| 2025-12-01 | Another smoke run with the updated script (explicit build) reached ~13s restore before manual cancel to avoid runaway; restore then reported canceled. Still no TRX/binlog. Remaining action: execute on clean CI or trim smoke project refs to narrow the graph. | Implementer |
| 2025-12-01 | Attempted `dotnet test ...Lang.Node.Tests --filter Phase22BundleNativeWasmObservationAsync`; build fanned out across Scanner/Auth deps and was cancelled at ~28s to avoid runaway job. Needs clean, scoped runner to capture result. | Implementer |
| 2025-12-01 | Retried `dotnet test src/Scanner/StellaOps.Scanner.Node.slnf -c Release --no-restore --filter Phase22BundleNativeWasmObservationAsync`; build still pulled broader Scanner/Auth dependencies and was cancelled at ~27s. Test result remains pending until a scoped runner is available. | Implementer |
| 2025-12-01 | Tried narrower `dotnet build src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Node.Tests/StellaOps.Scanner.Analyzers.Lang.Node.Tests.csproj -c Release --no-restore -m:1`; build again fanned across Scanner/Auth and was cancelled. No test executed; still need scoped runner. | Implementer |
| 2025-12-01 | Added scoped smoke project `src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Node.SmokeTests` with single test `Phase22_Fixture_Matches_Golden`. `dotnet restore` succeeds (DOTNET_CLI_HOME=/tmp/dotnet), but `dotnet test --no-build --no-restore` still canceled by SDK resolver on this runner. Test result pending. | Implementer |
| 2025-12-01 | Retried restore/build of the smoke project with `RestoreSources=$(pwd)/local-nugets` and resolver cache disabled; restore succeeds but build/test still canceled by SDK resolver. Pending execution on clean runner/CI. | Implementer |
| 2025-12-01 | Added helper `scripts/run-node-phase22-smoke.sh` to run the scoped Phase22 smoke test with DOTNET_CLI_HOME isolated and RestoreSources=local-nugets; use on clean runner/CI to capture result. | Implementer |
| 2025-12-01 | Smoke test rerun via helper with fallback/cache disabled still fails on this runner (MSB6006 dotnet test host exit 1 after resolver shutdown). Restore succeeds; execution remains blocked on runner instability. | Implementer |
| 2025-12-01 | Marked Phase22 validation as BLOCKED on current runner; waiting for CI/clean runner to execute `scripts/run-node-phase22-smoke.sh`. No further local retries planned. | Implementer |
| 2025-12-01 | Targeted `dotnet test ...Lang.Node.Tests --filter Phase22BundleNativeWasmObservationAsync` aborted during build after lengthy restore; fixture-generated expected JSON present—rerun on clean runner to record pass/fail. | Implementer |
| 2025-11-20 | Added Node phase 22 NDJSON loader hook + fixture to analyzer; PREP P1P3 now have executable baseline for downstream tasks. | Implementer |
| 2025-11-20 | Published Node phase 22 prep doc + fixture (see Delivery Tracker) and marked PREP P1P3 DONE. | Planning |
@@ -49,7 +55,7 @@
## Decisions & Risks
- Phase 22 implementation (bundle/source-map, native/WASM, AOC NDJSON) landed; must be reconciled with upstream 22-005 package-manager adapters when they arrive to ensure resolver traces stay consistent.
- Node Phase22 validation is pending: scoped smoke test project exists but SDK resolver cancels builds on this runner. Need clean runner/CI slice to execute `Phase22_Fixture_Matches_Golden` (smoke project) or filtered Lang.Node.Tests. Track until executed.
- Node Phase22 validation is pending: scoped smoke test project exists but SDK resolver/build graph still fans out; latest 2025-12-01 run restored/built but test phase was cancelled to avoid runaway. Need clean runner/CI slice or trimmed project refs to execute `Phase22_Fixture_Matches_Golden` and capture TRX/binlog. Track until executed; currently BLOCKED on runner stability.
- Maintain offline/deterministic outputs; avoid running full solution builds—prefer scoped runners per module.
## Next Checkpoints

View File

@@ -26,7 +26,8 @@
| 4 | SCANNER-ENTRYTRACE-18-506 | DONE (2025-12-01) | Surfaced via WebService `/scans/{id}/entrytrace` and CLI rendering. | EntryTrace Guild · Scanner WebService Guild | Surface EntryTrace graph + confidence via Scanner.WebService and CLI, including target summary in scan reports and policy payloads. |
| 5 | ZASTAVA-SURFACE-02 | DONE (2025-12-01) | Manifest CAS/sha resolver in Observer drift evidence with failure metrics. | Zastava Observer Guild (`src/Zastava/StellaOps.Zastava.Observer`) | SURFACE-FS-02, ZASTAVA-SURFACE-01; see `docs/modules/scanner/design/surface-fs-consumers.md` §4 |
| 6 | SCANNER-SORT-02 | DONE (2025-12-01) | Layer fragment ordering by digest implemented; deterministic regression test added. | Scanner Core Guild (`src/Scanner/__Libraries/StellaOps.Scanner.Core`) | SCANNER-EMIT-15-001 |
| 7 | SCANNER-SURFACE-01 | BLOCKED (2025-11-25) | Task definition absent; needs scope/contract before implementation. | Scanner Guild | — |
| 7 | SCANNER-EMIT-15-001 | DOING (2025-12-01) | CycloneDX artifacts now carry content hash + merkle root and recipe placeholders; DSSE/recipe persistence pending. | Scanner Emit Guild (`src/Scanner/__Libraries/StellaOps.Scanner.Emit`) | SCANNER-SURFACE-04 |
| 8 | SCANNER-SURFACE-01 | BLOCKED (2025-11-25) | Task definition absent; needs scope/contract before implementation. | Scanner Guild | — |
## Execution Log
| Date (UTC) | Update | Owner |

View File

@@ -30,13 +30,17 @@
| 2 | 140.B SBOM Service wave | DOING (2025-11-28) | Sprint 0142 mostly complete: SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002, SBOM-ORCH-32/33/34-001, SBOM-VULN-29-001/002 all DONE. Only SBOM-CONSOLE-23-001/002 remain BLOCKED. | SBOM Service Guild · Cartographer Guild | Finalize projection schema, emit change events, and wire orchestrator/observability (SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002). |
| 3 | 140.C Signals wave | DOING (2025-11-28) | Sprint 0143: SIGNALS-24-001/002/003 DONE; SIGNALS-24-004/005 remain BLOCKED on CAS promotion. | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild | Close SIGNALS-24-002/003 and clear blockers for 24-004/005 scoring/cache layers. |
| 4 | 140.D Zastava wave | DONE (2025-11-28) | Sprint 0144 (Zastava Runtime Signals) complete: all ZASTAVA-ENV/SECRETS/SURFACE tasks DONE. | Zastava Observer/Webhook Guilds · Surface Guild | Prepare env/secret helpers and admission hooks; start once cache endpoints and helpers are published. |
| 5 | DECAY-GAPS-140-005 | TODO | None; informs Signals/Unknowns work. | Signals Guild · Product Mgmt | Address decay gaps U1U10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: τ governance config, floor/freeze/SLA clamping, weighted signals taxonomy, UTC/monotonic time rules, deterministic recompute cadence + checksum, SLA coupling guardrails, uncertainty linkage, migration/backfill plan, API fields/bands, observability/alerts. |
| 6 | UNKNOWN-GAPS-140-006 | TODO | None; informs Unknowns Registry work. | Signals Guild · Policy Guild · Product Mgmt | Address unknowns gaps UN1UN10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: canonical schema/enums, deterministic scoring manifest, decay policy catalog, evidence/provenance capture, SBOM/VEX linkage, SLA/suppression rules, API/CLI contracts, observability/reporting, offline bundle inclusion, and migration/backfill. |
| 7 | UNKNOWN-HEUR-GAPS-140-007 | TODO | Close UT1UT10 from `31-Nov-2025 FINDINGS.md`; depends on heuristic catalog publication | Signals Guild · Policy Guild · Product Mgmt | Remediate UT1UT10: signed heuristic catalog/schema, deterministic scoring formula, quality bands, waiver policy with DSSE, SLA coupling, offline kit packaging, observability/alerts, backfill plan, explainability UX fields/exports, fixtures with golden outputs. |
| 5 | DECAY-GAPS-140-005 | DOING (2025-12-01) | Draft doc `docs/modules/signals/decay/2025-12-01-confidence-decay.md` + config `docs/modules/signals/decay/confidence_decay_config.yaml`; SHA256 in `docs/modules/signals/SHA256SUMS`; review 2025-12-03; DSSE signature pending. | Signals Guild · Product Mgmt | Address decay gaps U1U10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: publish signed `confidence_decay_config` (τ governance, floor/freeze/SLA clamps), weighted signals taxonomy, UTC/monotonic time rules, deterministic recompute cadence + checksum, uncertainty linkage, migration/backfill plan, API fields/bands, and observability/alerts. |
| 6 | UNKNOWN-GAPS-140-006 | DOING (2025-12-01) | Draft doc `docs/modules/signals/unknowns/2025-12-01-unknowns-registry.md` + manifest `docs/modules/signals/unknowns/unknowns_scoring_manifest.json`; SHA256 in `docs/modules/signals/SHA256SUMS`; review 2025-12-04; DSSE pending. | Signals Guild · Policy Guild · Product Mgmt | Address unknowns gaps UN1UN10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: publish signed Unknowns registry schema + scoring manifest (deterministic), decay policy catalog, evidence/provenance capture, SBOM/VEX linkage, SLA/suppression rules, API/CLI contracts, observability/reporting, offline bundle inclusion, and migration/backfill. |
| 7 | UNKNOWN-HEUR-GAPS-140-007 | DOING (2025-12-01) | Draft doc `docs/modules/signals/heuristics/2025-12-01-heuristic-catalog.md`, catalog `docs/modules/signals/heuristics/heuristics.catalog.json`, schema `docs/modules/signals/heuristics/heuristics.schema.json`, fixtures under `docs/modules/signals/heuristics/fixtures/`; SHA256 in `docs/modules/signals/SHA256SUMS`; publication target 2025-12-05; DSSE pending. | Signals Guild · Policy Guild · Product Mgmt | Remediate UT1UT10: publish signed heuristic catalog/schema with deterministic scoring formula, quality bands, waiver policy with DSSE, SLA coupling, offline kit packaging, observability/alerts, backfill plan, explainability UX fields/exports, and fixtures with golden outputs. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-01 | Added `docs/modules/signals/SHA256SUMS` covering decay config, unknowns manifest, heuristic catalog/schema, and fixtures to support offline parity; DSSE signing still pending. | Implementer |
| 2025-12-01 | Staged decay config (`confidence_decay_config.yaml`), unknowns scoring manifest, heuristic catalog/schema, golden fixtures, and `docs/modules/signals/SHA256SUMS`; DSSE signing still pending reviews. | Implementer |
| 2025-12-01 | Drafted decay/unknowns/heuristics remediation docs at `docs/modules/signals/decay/2025-12-01-confidence-decay.md`, `docs/modules/signals/unknowns/2025-12-01-unknowns-registry.md`, `docs/modules/signals/heuristics/2025-12-01-heuristic-catalog.md`; set review checkpoints 12-03/04/05. | Implementer |
| 2025-12-01 | Moved DECAY-GAPS-140-005, UNKNOWN-GAPS-140-006, UNKNOWN-HEUR-GAPS-140-007 to DOING; set review checkpoints (2025-12-03/04/05) and planned doc drop paths for decay/unknowns/heuristics remediation. | Project Mgmt |
| 2025-11-28 | Synced wave status with downstream sprints: 140.A Graph (DONE per Sprint 0141); 140.B SBOM (DOING, mostly complete per Sprint 0142); 140.C Signals (DOING, 3/5 done per Sprint 0143); 140.D Zastava (DONE per Sprint 0144). Updated Delivery Tracker and unblocked Sprint 0150 dependencies. | Implementer |
| 2025-12-01 | Added UNKNOWN-HEUR-GAPS-140-007 to track UT1UT10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending heuristic catalog and scoring rules. | Project Mgmt |
| 2025-11-20 | Completed PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS: published cache/env helper prep at `docs/modules/zastava/prep/2025-11-20-surface-fs-env-prep.md`; status set to DONE. | Implementer |
@@ -65,6 +69,7 @@
- Link-Not-Merge v1 schema frozen 2025-11-17; fixtures staged under `docs/modules/sbomservice/fixtures/lnm-v1/`; AirGap parity review scheduled for 2025-11-23 (see Next Checkpoints) must record hashes to fully unblock.
- SBOM runtime/signals prep note published at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap review runbook ready (`docs/modules/sbomservice/runbooks/airgap-parity-review.md`). Wave moves to TODO pending review completion and fixture hash upload.
- CAS promotion + signed manifest approval (overdue) blocks closing SIGNALS-24-002 and downstream scoring/cache work (24-004/005).
- Decay/Unknowns/heuristics remediation (U1U10, UN1UN10, UT1UT10) now DOING; if signed configs/catalogs are not published by 2025-12-05, SIGNALS-24-004/005 readiness and Unknowns registry rollout slip. Draft docs and artifacts posted at `docs/modules/signals/decay/2025-12-01-confidence-decay.md`, `docs/modules/signals/decay/confidence_decay_config.yaml`, `docs/modules/signals/unknowns/2025-12-01-unknowns-registry.md`, `docs/modules/signals/unknowns/unknowns_scoring_manifest.json`, and `docs/modules/signals/heuristics/` (catalog, schema, fixtures); DSSE signatures pending. Hashes recorded in `docs/modules/signals/SHA256SUMS` for offline/air-gap parity; Evidence Locker path to be populated post-signing.
- Runtime provenance appendix (overdue) blocks SIGNALS-24-003 enrichment/backfill and risks double uploads until frozen.
- Surface.FS cache drop timeline (overdue) and Surface.Env owner assignment keep Zastava env/secret/admission tasks blocked.
- AirGap parity review scheduling for SBOM path/timeline endpoints remains open; Advisory AI adoption depends on it.
@@ -85,6 +90,9 @@
| 2025-11-18 (overdue) | Provenance appendix freeze | Finalize runtime provenance schema and scope propagation fixtures for SIGNALS-24-003 backfill. | Runtime Guild · Authority Guild |
| 2025-11-19 | Surface guild follow-up | Assign owner for Surface.Env helper rollout and confirm Surface.FS cache drop sequencing. | Surface Guild · Zastava Guilds |
| 2025-11-23 | AirGap parity review (SBOM paths/versions/events) | Run review using `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; record minutes and link fixtures hash list. | Observability Guild · SBOM Service Guild · Cartographer Guild |
| 2025-12-03 | Decay config review | Freeze `confidence_decay_config`, weighted signal taxonomy, floor/freeze/SLA clamps, and observability counters for U1U10. | Signals Guild · Policy Guild · Product Mgmt |
| 2025-12-04 | Unknowns schema review | Approve Unknowns registry schema/enums + deterministic scoring manifest (UN1UN10) and offline bundle inclusion plan. | Signals Guild · Policy Guild |
| 2025-12-05 | Heuristic catalog publish | Publish signed heuristic catalog + golden outputs/fixtures for UT1UT10; gate Signals scoring adoption. | Signals Guild · Runtime Guild |
---

View File

@@ -56,7 +56,7 @@
| 13 | ORCH-OBS-54-001 | BLOCKED (2025-11-19) | PREP-ORCH-OBS-54-001-DEPENDS-ON-53-001 | Orchestrator Service Guild · Provenance Guild | Produce DSSE attestations for orchestrator-scheduled jobs; store references in timeline + Evidence Locker; add verification endpoint `/jobs/{id}/attestation`. |
| 14 | ORCH-OBS-55-001 | BLOCKED (2025-11-19) | PREP-ORCH-OBS-55-001-DEPENDS-ON-54-001-INCIDE | Orchestrator Service Guild · DevOps Guild | Incident mode hooks (sampling overrides, extended retention, debug spans) with automatic activation on SLO burn-rate breach; emit activation/deactivation events. |
| 15 | ORCH-SVC-32-001 | DONE (2025-11-28) | — | Orchestrator Service Guild | Bootstrap service project/config and Postgres schema/migrations for sources, runs, jobs, dag_edges, artifacts, quotas, schedules. |
| 16 | ORCH-GAPS-151-016 | TODO | Close OR1OR10 gaps from `31-Nov-2025 FINDINGS.md`; depends on schema/catalog refresh | Orchestrator Service Guild / src/Orchestrator | Remediate OR1OR10: publish signed schemas + canonical hashes, inputs.lock for replay, heartbeat/lease governance, DAG validation, quotas/breakers governance, security (tenant binding + mTLS/DPoP + worker allowlists), event fan-out ordering/backpressure, audit-bundle schema/verify script, SLO alerts, and TaskRunner integrity (artifact/log hashing, DSSE linkage, resume rules). |
| 16 | ORCH-GAPS-151-016 | DOING (2025-12-01) | Close OR1OR10 gaps from `31-Nov-2025 FINDINGS.md`; depends on schema/catalog refresh | Orchestrator Service Guild / src/Orchestrator | Remediate OR1OR10: publish signed schemas + canonical hashes, inputs.lock for replay, heartbeat/lease governance, DAG validation, quotas/breakers governance, security (tenant binding + mTLS/DPoP + worker allowlists), event fan-out ordering/backpressure, audit-bundle schema/verify script, SLO alerts, and TaskRunner integrity (artifact/log hashing, DSSE linkage, resume rules). |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -77,6 +77,9 @@
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-30 | No remaining unblocked tasks in Sprint 0151; AirGap/Observability streams still BLOCKED on upstream inputs (0120.A staleness, Telemetry Core). Monitoring only. | Implementer |
| 2025-12-01 | Added ORCH-GAPS-151-016 (OR1OR10 from `31-Nov-2025 FINDINGS.md`) to track advisory gap remediation; status TODO pending schema/catalog refresh. | Project Mgmt |
| 2025-12-01 | Started ORCH-GAPS-151-016 (status → DOING); added canonical JSON hasher, deterministic schemas (event, audit bundle, replay manifest, taskrunner integrity) and hash-based audit entry integrity. | Implementer |
| 2025-12-01 | Extended ORCH-GAPS-151-016: added replay manifest domain model + canonical hashing helpers; schema smoke tests in place. Full test run blocked by existing PackRunStreamCoordinatorTests WebSocket.Dispose abstract member error. | Implementer |
| 2025-12-01 | Removed legacy `docs/implplan/SPRINT_151_orchestrator_i.md` stub and synced `tasks-all.md` rows to Sprint_0151_0001_0001 status (AirGap/OBS blocked, OAS done, SVC-32-001 done; added ORCH-GAPS-151-016). | Project Mgmt |
## Decisions & Risks
- Start of work gated on AirGap/Scanner/Graph dependencies staying green; reassess before moving tasks to DOING.

View File

@@ -18,11 +18,12 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | TELEM-GAPS-180-001 | TODO | Close TO1TO10 from `31-Nov-2025 FINDINGS.md`; depends on bundle/ledger schema refresh | Telemetry Guild · DevOps Guild | Remediate TO1TO10: signed schemas/canonical JSON for metrics/traces/logs/config, provenance/DSSE for profiles and bundles, deterministic exporters/sampling, sealed-mode/egress guards, redaction policy + PII tests, forensic trigger governance, offline bundle schema + verify script + time anchor, SLO/alerting dashboards, tenant isolation, and pack/CLI contracts. |
| 1 | TELEM-GAPS-180-001 | DONE (2025-12-01) | Close TO1TO10 from `31-Nov-2025 FINDINGS.md` | Telemetry Guild · DevOps Guild | Remediated TO1TO10: published signed schemas and contracts, DSSE guidance, deterministic sampling/backpressure rules, sealed-mode guard, redaction/PII catalog requirements, tenant routing/quota guidance, forensic activation governance, offline bundle schema + verify script + time anchor hook, SLO/alerting expectations, and CLI/pack contract mapping. Artifacts: `docs/modules/telemetry/contracts/telemetry-gaps-remediation.md`, `docs/modules/telemetry/schemas/telemetry-config.schema.json`, `docs/modules/telemetry/schemas/telemetry-bundle.schema.json`, `ops/devops/telemetry/verify-telemetry-bundle.sh`. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-01 | Delivered telemetry gaps remediation: contracts/schemas added, offline verifier script provided; marked TELEM-GAPS-180-001 DONE. | Implementer |
| 2025-12-01 | Sprint stub created to track telemetry advisory gaps; added TELEM-GAPS-180-001 (TO1TO10). | Project Mgmt |
## Decisions & Risks

View File

@@ -38,7 +38,7 @@
| 16 | CLI-ATTEST-75-001 | BLOCKED | Depends on CLI-ATTEST-74-002 | CLI Attestor Guild · KMS Guild | Implement `stella attest key create` workflows. Blocked: upstream 74-002. |
| 17 | CLI-ATTEST-75-002 | BLOCKED | Depends on CLI-ATTEST-75-001 | CLI Attestor Guild · Export Guild | Add support for building/verifying attestation bundles in CLI. Blocked: upstream 75-001. |
| 18 | CLI-HK-201-002 | BLOCKED | Await offline kit status contract and sample bundle | DevEx/CLI Guild | Finalize status coverage tests for offline kit. |
| 19 | CLI-GAPS-201-003 | TODO | None; informs tasks 718. | Product Mgmt · DevEx/CLI Guild | Address CLI gaps CL1CL10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: versioned command/flag/exit-code spec with compatibility tests, deterministic output fixtures, auth key rotation/cleanup and audience validation, offline-kit import/verify contract, cosign verification on install/update, pinned buildx plugin digest + rollback, telemetry opt-in/off defaults, UX/a11y guidelines, structured errors/help, and checksum-enforced install paths (online/offline). |
| 19 | CLI-GAPS-201-003 | DONE (2025-12-01) | None; informs tasks 718. | Product Mgmt · DevEx/CLI Guild | Addressed CLI gaps CL1CL10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: versioned command/flag/exit-code spec with compatibility tests, deterministic output fixtures, auth key rotation/cleanup and audience validation, offline-kit import/verify contract, cosign verification on install/update, pinned buildx plugin digest + rollback, telemetry opt-in/off defaults, UX/a11y guidelines, structured errors/help, and checksum-enforced install paths (online/offline). |
## Wave Coordination
- Single-wave delivery; no staggered waves defined.
@@ -72,6 +72,10 @@
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-01 | Wired CLI gaps spec: pinned buildx digest, added compatibility/determinism/install contract docs, and added automated spec tests (`CliSpecTests`) plus telemetry default regression test. | DevEx/CLI Guild |
| 2025-12-01 | Added checksum verification before scanner install (`VerifyBundleAsync`), with exit code 21 on missing checksum and 22 on mismatch; added tests (`ScannerDownloadVerifyTests`) to cover pass/fail paths. | DevEx/CLI Guild |
| 2025-12-01 | Updated CLI spec to include install exit codes 21/22; added spec regression test to enforce mapping. | DevEx/CLI Guild |
| 2025-12-01 | Completed CLI-GAPS-201-003: published versioned CLI compatibility spec (`docs/modules/cli/contracts/cli-spec-v1.yaml`), deterministic output policy (`docs/modules/cli/contracts/output-determinism.md`), and install integrity guide (`docs/modules/cli/contracts/install-integrity.md`); telemetry now defaults to opt-out in `CliProfileStore`; added unit test `TelemetryDefaultsTests` to ensure default-off behavior. | DevEx/CLI Guild |
| 2025-11-25 | Marked CLI-AIRGAP-56-002/57-001/57-002/58-001 and CLI-ATTEST-73-002/74-001/74-002/75-001/75-002 BLOCKED (waiting on mirror bundle contract/spec and attestor SDK transport); statuses synced to tasks-all. | Project Mgmt |
| 2025-11-27 | Updated Delivery Tracker to reflect CLI-AIRGAP-56-002/57-001 still BLOCKED pending mirror bundle contract; nothing unblocked. | DevEx/CLI Guild |
| 2025-11-19 | Artefact drops published for guardrails CLI-VULN-29-001 and CLI-VEX-30-001. | DevEx/CLI Guild |

View File

@@ -69,6 +69,7 @@
| 41 | DOC-11-003 | TODO | DOC-11-001 | Docs Guild; Vuln Explorer Guild; Export Center Guild | Update docs/modules/vuln-explorer/architecture.md and docs/modules/export-center/architecture.md with VEX decision/audit bundle API surfaces and schema references. |
| 42 | TRIAGE-GAPS-215-042 | TODO | Close VT1VT10 from `31-Nov-2025 FINDINGS.md`; depends on schema publication and UI workspace bootstrap | UI Guild · Platform Guild | Remediate VT1VT10: publish signed schemas + canonical JSON, enforce evidence linkage (graph/policy/attestations), tenant/RBAC controls, deterministic ordering/pagination, a11y standards, offline triage-kit exports, supersedes/conflict rules, attestation verification UX, redaction policy, UX telemetry/SLIs with alerts. |
| 43 | UI-PROOF-VEX-0215-010 | TODO | Proof-linked VEX UI spec; depends on VexLens/Findings APIs and DSSE headers | UI Guild; VexLens Guild; Policy Guild | Implement proof-linked Not Affected badge/drawer: scoped endpoints + tenant headers, cache/staleness policy, client integrity checks, failure/offline UX, evidence precedence, telemetry schema/privacy, signed permalinks, revision reconciliation, fixtures/tests. |
| 44 | TTE-GAPS-0215-011 | TODO | TTE metric advisory; align with telemetry core sprint | UI Guild; Telemetry Guild | Close TTE1TTE10: publish tte-event schema, proof eligibility rules, sampling/bot filters, per-surface SLO/error budgets, required indexes/streaming SLAs, offline-kit handling, alert/runbook, release regression gate, and a11y/viewport tests. |
## Wave Coordination
- **Wave A (Schemas & DTOs):** SCHEMA-08-*, DTO-09-*, TS-10-* - Foundation work
@@ -130,6 +131,7 @@
| 2025-11-30 | Marked UI-TRIAGE-01-001 and TS-10-* tasks BLOCKED because src/UI/StellaOps.UI lacks Angular workspace; awaiting restoration to proceed. | UI Guild |
| 2025-12-01 | Added TRIAGE-GAPS-215-042 to track VT1VT10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending schema publication and UI workspace bootstrap. | Project Mgmt |
| 2025-12-01 | Added UI-PROOF-VEX-0215-010 to address PVX1PVX10 proof-linked VEX UI gaps from `31-Nov-2025 FINDINGS.md`; status TODO pending API scope/caching/integrity rules and fixtures. | Project Mgmt |
| 2025-12-01 | Added TTE-GAPS-0215-011 to cover TTE1TTE10 Time-to-Evidence metric gaps from `31-Nov-2025 FINDINGS.md`; status TODO pending schema publication, SLO policy, and telemetry alignment. | Project Mgmt |
---
*Sprint created: 2025-11-28*

View File

@@ -21,7 +21,7 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | WEB-RISK-66-001 | BLOCKED (2025-12-01) | Workspace storage exhausted; command runner failing (`No space left on device`) | BE-Base Platform Guild; Policy Guild (`src/Web/StellaOps.Web`) | Expose risk profile/results endpoints through gateway with tenant scoping, pagination, and rate limiting. |
| 1 | WEB-RISK-66-001 | DOING (2025-12-01) | Workspace storage cleared; proceed with gateway scaffolding and risk endpoints | BE-Base Platform Guild; Policy Guild (`src/Web/StellaOps.Web`) | Expose risk profile/results endpoints through gateway with tenant scoping, pagination, and rate limiting. |
| 2 | WEB-RISK-66-002 | TODO | WEB-RISK-66-001 | BE-Base Platform Guild; Risk Engine Guild (`src/Web/StellaOps.Web`) | Add signed URL handling for explanation blobs and enforce scope checks. |
| 3 | WEB-RISK-67-001 | TODO | WEB-RISK-66-002 | BE-Base Platform Guild (`src/Web/StellaOps.Web`) | Provide aggregated risk stats (`/risk/status`) for Console dashboards (counts per severity, last computation). |
| 4 | WEB-RISK-68-001 | TODO | WEB-RISK-67-001; notifier bus schema | BE-Base Platform Guild; Notifications Guild (`src/Web/StellaOps.Web`) | Emit events on severity transitions via gateway to notifier bus with trace metadata. |
@@ -36,9 +36,9 @@
| 13 | WEB-VULN-29-002 | TODO | WEB-VULN-29-001; Findings Ledger idempotency headers | BE-Base Platform Guild; Findings Ledger Guild (`src/Web/StellaOps.Web`) | Forward workflow actions to Findings Ledger with idempotency headers and correlation IDs; handle retries/backoff. |
| 14 | WEB-VULN-29-003 | TODO | WEB-VULN-29-002; export/simulation orchestrator | BE-Base Platform Guild (`src/Web/StellaOps.Web`) | Provide simulation and export orchestration routes with SSE/progress headers, signed download links, and request budgeting. |
| 15 | WEB-VULN-29-004 | TODO | WEB-VULN-29-003; observability dashboard specs | BE-Base Platform Guild; Observability Guild (`src/Web/StellaOps.Web`) | Emit gateway metrics/logs (latency, error rates, export duration), propagate query hashes for analytics dashboards. |
| 16 | WEB-TEN-47-CONTRACT | DOING (2025-12-01) | 2025-12-02 tenant header/ABAC checkpoint | BE-Base Platform Guild (`docs/api/gateway/tenant-auth.md`) | Publish gateway routing + tenant header/ABAC contract (headers, scopes, samples, audit notes). |
| 17 | WEB-VULN-29-LEDGER-DOC | DOING (2025-12-01) | 2025-12-04 Findings Ledger checkpoint | Findings Ledger Guild; BE-Base Platform Guild (`docs/api/gateway/findings-ledger-proxy.md`) | Capture idempotency + correlation header contract for Findings Ledger proxy and retries/backoff defaults. |
| 18 | WEB-RISK-68-NOTIFY-DOC | DOING (2025-12-01) | 2025-12-06 Notifications schema checkpoint | Notifications Guild; BE-Base Platform Guild (`docs/api/gateway/notifications-severity.md`) | Document severity transition event schema (fields, trace metadata) for notifier bus integration. |
| 16 | WEB-TEN-47-CONTRACT | DONE (2025-12-01) | Contract published in `docs/api/gateway/tenant-auth.md` v1.0 | BE-Base Platform Guild (`docs/api/gateway/tenant-auth.md`) | Publish gateway routing + tenant header/ABAC contract (headers, scopes, samples, audit notes). |
| 17 | WEB-VULN-29-LEDGER-DOC | DONE (2025-12-01) | Contract published in `docs/api/gateway/findings-ledger-proxy.md` v1.0 | Findings Ledger Guild; BE-Base Platform Guild (`docs/api/gateway/findings-ledger-proxy.md`) | Capture idempotency + correlation header contract for Findings Ledger proxy and retries/backoff defaults. |
| 18 | WEB-RISK-68-NOTIFY-DOC | DONE (2025-12-01) | Schema published in `docs/api/gateway/notifications-severity.md` v1.0 | Notifications Guild; BE-Base Platform Guild (`docs/api/gateway/notifications-severity.md`) | Document severity transition event schema (fields, trace metadata) for notifier bus integration. |
## Wave Coordination
- Single wave (Web V gateway + tenant hardening). Keep task order per dependency chains above; no parallel merges that alter schema/telemetry without shared reviews.
@@ -62,14 +62,17 @@
## Decisions & Risks
| Risk | Impact | Mitigation | Owner | Status |
| --- | --- | --- | --- | --- |
| Tenant header/ABAC contract slips | Blocks WEB-TEN-47-001/48-001/49-001 and delays RBAC enforcement across routes | Lock contract by 2025-12-02; record in `docs/api/gateway/tenant-auth.md`; add blocking status if slip persists | BE-Base Platform Guild | Open |
| Findings Ledger idempotency headers unclear | WEB-VULN-29-002/003 cannot forward workflow actions safely | Obtain contract on 2025-12-04 checkpoint; add retries/backoff defaults once confirmed | Findings Ledger Guild | Open |
| Notifications event schema not finalized | WEB-RISK-68-001 cannot emit severity transition events with trace metadata | Schema review on 2025-12-06; use placeholder event name only after review | Notifications Guild | Open |
| Workspace storage exhaustion prevents command execution | Blocks code inspection and implementation for WEB-RISK-66-001 and subsequent tasks | Free space (e.g., clean `node_modules` caches) and re-run gateway scaffolding; retry once ≥2GB available | Platform Ops | Open |
| Tenant header/ABAC contract slips | Blocks WEB-TEN-47-001/48-001/49-001 and delays RBAC enforcement across routes | Contract published 2025-12-01 in `docs/api/gateway/tenant-auth.md`; enforce via Gateway:Auth flags | BE-Base Platform Guild | Mitigated |
| Findings Ledger idempotency headers unclear | WEB-VULN-29-002/003 cannot forward workflow actions safely | Contract published 2025-12-01 in `docs/api/gateway/findings-ledger-proxy.md`; use TTL 24h + ETag/If-Match | Findings Ledger Guild | Mitigated |
| Notifications event schema not finalized | WEB-RISK-68-001 cannot emit severity transition events with trace metadata | Event schema v1.0 published 2025-12-01 in `docs/api/gateway/notifications-severity.md`; rate limit + DLQ included | Notifications Guild | Mitigated |
| Workspace storage exhaustion prevents command execution | Blocks code inspection and implementation for WEB-RISK-66-001 and subsequent tasks | Free space action completed; monitor disk and rerun gateway scaffolding | Platform Ops | Monitoring |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-01 | Started WEB-RISK-66-001: added risk gateway client/models with tenant-scoped filtering, deterministic ordering, and unit tests (`risk.client.ts`, `risk.client.spec.ts`); local mocks used until gateway endpoints are wired. | BE-Base Platform Guild |
| 2025-12-01 | Cleared workspace disk issue (55GB free reported); WEB-RISK-66-001 unblocked and returned to TODO. | Platform Ops |
| 2025-12-01 | Published Web V gateway contract docs v1.0: tenant auth/ABAC (`docs/api/gateway/tenant-auth.md`), Findings Ledger proxy (`docs/api/gateway/findings-ledger-proxy.md`), and notifier severity events (`docs/api/gateway/notifications-severity.md`); marked WEB-TEN-47-CONTRACT, WEB-VULN-29-LEDGER-DOC, and WEB-RISK-68-NOTIFY-DOC DONE. | BE-Base Platform Guild |
| 2025-12-01 | Blocked WEB-RISK-66-001: workspace reports `No space left on device` when starting gateway scaffolding; requires freeing disk (e.g., clean `node_modules`/tmp) before proceeding. | Implementer |
| 2025-12-01 | Drafted contract docs for tenant auth/ABAC, Findings Ledger proxy, and notifier severity events; set tasks 1618 to DOING. | Project Mgmt |
| 2025-11-30 | Added contract/doc tasks (rows 1618) for tenant headers/ABAC, Findings Ledger proxy headers, and notifier severity events; aligned Action Tracker with Delivery Tracker; no status changes to feature tracks. | Project Mgmt |

View File

@@ -0,0 +1,41 @@
# Sprint 0327-0001-0001 · Docs Modules Scanner
## Topic & Scope
- Keep scanner module documentation/process in sync with current implementation sprints and readiness gates.
- Capture Windows/macOS analyzer demand signals for product/marketing readiness.
- Fold post-demo runbook/observability feedback into module docs.
- **Working directory:** `docs/implplan` (tracker) with linked updates under `docs/modules/scanner`.
## Dependencies & Concurrency
- Upstream inputs: Sprint 130139 scanner wave status, ops demo outputs.
- Parallel-safe; avoid changing other modules without noting in Decisions & Risks.
## Documentation Prerequisites
- docs/README.md
- docs/07_HIGH_LEVEL_ARCHITECTURE.md
- docs/modules/platform/architecture-overview.md
- docs/modules/scanner/architecture.md
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | SCANNER-DOCS-0003 | BLOCKED | Waiting on field/sales demand signal interviews to be scheduled; no data available yet. | Docs Guild · Product Guild (`docs/modules/scanner`) | Gather Windows/macOS analyzer demand signals and record findings in `docs/benchmarks/scanner/windows-macos-demand.md` for marketing + product readiness. |
| 2 | SCANNER-OPS-0001 | BLOCKED | Next scanner demo not yet scheduled; need demo output to review runbooks/observability. | Ops Guild (`docs/modules/scanner`) | Review scanner runbooks/observability assets after the next sprint demo and capture findings inline with sprint notes. |
| 3 | SCANNER-ENG-0001 | DONE (2025-12-01) | Keep checkpoints updated when new scanner sprints land. | Module Team (`docs/modules/scanner`) | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md` and update module readiness checkpoints. |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-01 | Normalised sprint to standard template, renamed from `SPRINT_327_docs_modules_scanner.md` to `SPRINT_0327_0001_0001_docs_modules_scanner.md`; legacy stub retained for redirects. | Project Mgmt |
| 2025-12-01 | Completed SCANNER-ENG-0001: created readiness checkpoint doc (`docs/modules/scanner/readiness-checkpoints.md`) summarising sprint 01310138 status; linked in Decisions & Risks. | Module Team |
| 2025-12-01 | Marked SCANNER-DOCS-0003 and SCANNER-OPS-0001 BLOCKED awaiting field/demand inputs and the next scanner demo respectively. No work can proceed until upstream signals arrive. | Project Mgmt |
## Decisions & Risks
- Readiness checkpoints show amber/red gaps for Java/.NET analyzers (Sprint 0131) and PHP parity (Sprint 0138); see `docs/modules/scanner/readiness-checkpoints.md`.
- Windows/macOS demand signals (SCANNER-DOCS-0003) not yet captured; risk of marketing misalignment until data gathered.
- Ops feedback pending next demo (SCANNER-OPS-0001); note cross-module doc touch in `docs/modules/scanner` when applied.
- Both BLOCKED tasks depend on external scheduling (field interviews, demo). Revisit after dates confirmed; keep sprint aligned with upstream signals.
## Next Checkpoints
- 2025-12-05: Collect demand-signal inputs from field/PM for SCANNER-DOCS-0003 (owner: Product Guild).
- 2025-12-06: Runbook/observability review after next scanner demo (owner: Ops Guild).

View File

@@ -26,7 +26,7 @@
| P5 | PREP-BENCH-SIG-26-001-REACHABILITY-SCHEMA-FIX | DONE (2025-11-20) | Prep doc at `docs/benchmarks/signals/bench-sig-26-001-prep.md`; awaits reachability schema hash. | Bench Guild · Signals Guild | Reachability schema/fixtures pending Sprint 0400/0401. <br><br> Document artefact/deliverable for BENCH-SIG-26-001 and publish location so downstream tasks can proceed. |
| P6 | PREP-BENCH-SIG-26-002-BLOCKED-ON-26-001-OUTPU | DONE (2025-11-20) | Prep doc at `docs/benchmarks/signals/bench-sig-26-002-prep.md`; depends on 26-001 datasets. | Bench Guild · Policy Guild | Blocked on 26-001 outputs. <br><br> Document artefact/deliverable for BENCH-SIG-26-002 and publish location so downstream tasks can proceed. |
| 1 | BENCH-GRAPH-21-001 | DOING (2025-12-01) | PREP-BENCH-GRAPH-21-001-NEED-GRAPH-BENCH-HARN | Bench Guild · Graph Platform Guild | Build graph viewport/path benchmark harness (50k/100k nodes) measuring Graph API/Indexer latency, memory, and tile cache hit rates. |
| 2 | BENCH-GRAPH-21-002 | BLOCKED | PREP-BENCH-GRAPH-21-002-BLOCKED-ON-21-001-HAR | Bench Guild · UI Guild | Add headless UI load benchmark (Playwright) for graph canvas interactions to track render times and FPS budgets. |
| 2 | BENCH-GRAPH-21-002 | DOING (2025-12-01) | PREP-BENCH-GRAPH-21-002-BLOCKED-ON-21-001-HAR | Bench Guild · UI Guild | Add headless UI load benchmark (Playwright) for graph canvas interactions to track render times and FPS budgets. |
| 3 | BENCH-GRAPH-24-002 | BLOCKED | Waiting for 50k/100k graph fixture (SAMPLES-GRAPH-24-003) | Bench Guild · UI Guild | Implement UI interaction benchmarks (filter/zoom/table operations) citing p95 latency; integrate with perf dashboards. |
| 4 | BENCH-IMPACT-16-001 | BLOCKED | PREP-BENCH-IMPACT-16-001-IMPACT-INDEX-DATASET | Bench Guild · Scheduler Team | ImpactIndex throughput bench (resolve 10k productKeys) + RAM profile. |
| 5 | BENCH-POLICY-20-002 | BLOCKED | PREP-BENCH-POLICY-20-002-POLICY-DELTA-SAMPLE | Bench Guild · Policy Guild · Scheduler Guild | Add incremental run benchmark measuring delta evaluation vs full; capture SLA compliance. |
@@ -89,6 +89,8 @@
| 2025-11-26 | Added `scripts/bench/determinism-run.sh` and CI workflow `.gitea/workflows/bench-determinism.yml` to run/upload determinism artifacts. | Bench Guild |
| 2025-11-26 | Built determinism bench harness with mock scanner at `src/Bench/StellaOps.Bench/Determinism`, added sample SBOM/VEX inputs, generated `results/inputs.sha256` + `results.csv`, updated bench doc, and marked BENCH-DETERMINISM-401-057 DONE. Tests: `python -m unittest discover -s src/Bench/StellaOps.Bench/Determinism/tests -t src/Bench/StellaOps.Bench/Determinism`. | Bench Guild |
| 2025-12-01 | Generated interim synthetic graph fixtures (50k/100k nodes with manifests) under `samples/graph/interim/` to unblock BENCH-GRAPH-21-001; task moved to DOING pending overlay schema for canonical fixture. | Implementer |
| 2025-12-01 | Added Graph UI bench scaffold: scenarios JSON, driver (`ui_bench_driver.mjs`), and plan under `src/Bench/StellaOps.Bench/Graph/`; BENCH-GRAPH-21-002 moved to DOING using interim fixtures until overlay schema/UI target is available. | Implementer |
| 2025-12-01 | Added graph bench runner `Graph/run_graph_bench.sh` and recorded sample results for graph-50k/100k fixtures; BENCH-GRAPH-21-001 progressing with interim fixtures. | Implementer |
| 2025-11-22 | Added ACT-0512-07 and corresponding risk entry to have UI bench harness skeleton ready once fixtures bind; no status changes. | Project Mgmt |
| 2025-11-22 | Added ACT-0512-04 to build interim synthetic graph fixture so BENCH-GRAPH-21-001 can start while awaiting SAMPLES-GRAPH-24-003; no status changes. | Project Mgmt |
| 2025-11-22 | Added ACT-0512-05 escalation path (due 2025-11-23) if SAMPLES-GRAPH-24-003 remains unavailable; updated Upcoming Checkpoints accordingly. | Project Mgmt |

View File

@@ -43,9 +43,9 @@ Dependency: Sprint 135 - 6. Scanner.VI — Scanner & Surface focus on Scanner (p
| `SURFACE-FS-04` | DONE (2025-11-27) | Integrate Surface.FS reader into Zastava Observer runtime drift loop. | Zastava Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | SURFACE-FS-02 |
| `SURFACE-FS-05` | DONE (2025-11-27) | Expose Surface.FS pointers via Scanner WebService reports and coordinate rescan planning with Scheduler. | Scanner Guild, Scheduler Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | SURFACE-FS-03 |
| `SURFACE-FS-06` | DONE (2025-11-28) | Update scanner-engine guide and offline kit docs with Surface.FS workflow. | Docs Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | SURFACE-FS-02..05 |
| `SCANNER-SURFACE-04` | TODO | DSSE-sign every `layer.fragments` payload, emit `_composition.json`, and persist DSSE envelopes so offline kits can replay deterministically (see `docs/modules/scanner/deterministic-sbom-compose.md` §2.1). | Scanner Worker Guild (src/Scanner/StellaOps.Scanner.Worker) | SCANNER-SURFACE-01, SURFACE-FS-03 |
| `SCANNER-SURFACE-04` | TODO | DSSE-sign every `layer.fragments` payload, emit `_composition.json`/`composition.recipe` URI, and persist DSSE envelopes so offline kits can replay deterministically (see `docs/modules/scanner/deterministic-sbom-compose.md` §2.1). | Scanner Worker Guild (src/Scanner/StellaOps.Scanner.Worker) | SCANNER-SURFACE-01, SURFACE-FS-03 |
| `SURFACE-FS-07` | TODO | Extend Surface.FS manifest schema with `composition.recipe`, fragment attestation metadata, and verification helpers per deterministic SBOM spec. | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | SCANNER-SURFACE-04 |
| `SCANNER-EMIT-15-001` | DOING (2025-12-01) | Canonical content hash captured on CycloneDX artifacts (`ContentHash` = JsonSha256); remaining Merkle/DSSE wiring pending. | Scanner Emit Guild (src/Scanner/__Libraries/StellaOps.Scanner.Emit) | SCANNER-SURFACE-04 |
| `SCANNER-EMIT-15-001` | DOING (2025-12-01) | CycloneDX artifacts now carry content hash, merkle root (= recipe hash), and composition recipe URI placeholders; `_composition.json` recipe emitted into package manifest. DSSE signing still pending. | Scanner Emit Guild (src/Scanner/__Libraries/StellaOps.Scanner.Emit) | SCANNER-SURFACE-04 |
| `SCANNER-SORT-02` | DONE (2025-12-01) | Layer fragment ordering by digest implemented in ComponentGraphBuilder; determinism regression test added. | Scanner Core Guild (src/Scanner/__Libraries/StellaOps.Scanner.Core) | SCANNER-EMIT-15-001 |
| `SURFACE-VAL-01` | DONE (2025-11-23) | Validation framework doc aligned with Surface.Env release and secrets schema (`docs/modules/scanner/design/surface-validation.md` v1.1). | Scanner Guild, Security Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | SURFACE-FS-01, SURFACE-ENV-01 |
| `SURFACE-VAL-02` | DONE (2025-11-23) | Validation library now enforces secrets schema, fallback/provider checks, and inline/file guardrails; tests added. | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | SURFACE-VAL-01, SURFACE-ENV-02, SURFACE-FS-02 |
@@ -74,7 +74,7 @@ Dependency: Sprint 135 - 6. Scanner.VI — Scanner & Surface focus on Scanner (p
| 2025-12-01 | EntryTrace NDJSON emission, runtime reconciliation, and WebService/CLI exposure completed (18-504/505/506). | EntryTrace Guild |
| 2025-12-01 | ZASTAVA-SURFACE-02: Observer resolves Surface manifest digests and `cas://` URIs, enriches drift evidence with artifact metadata, and counts failures via `zastava_surface_manifest_failures_total`. | Implementer |
| 2025-12-01 | SCANNER-SORT-02: ComponentGraphBuilder sorts layer fragments by digest; regression test added. | Implementer |
| 2025-12-01 | SCANNER-EMIT-15-001: CycloneDX artifacts now publish `ContentHash` (sha256 of canonical JSON); Merkle/DSSE steps still pending. | Implementer |
| 2025-12-01 | SCANNER-EMIT-15-001: CycloneDX artifacts now publish `ContentHash` (sha256 of canonical JSON) and carry Merkle root / composition recipe hash placeholders; `_composition.json` recipe emitted as surface payload and packaged manifest entry. DSSE signing still pending. | Implementer |
| 2025-12-01 | SCANNER-SORT-02 completed: ComponentGraphBuilder sorts layer fragments by digest with regression test Build_SortsLayersByDigest. | Implementer |
| 2025-12-01 | ZASTAVA-SURFACE-02: Observer now resolves Surface manifest digests and `cas://` URIs, enriches drift evidence with artifact metadata, and counts failures via `zastava_surface_manifest_failures_total`. | Implementer |
| 2025-11-23 | Published Security-approved Surface.Secrets schema (`docs/modules/scanner/design/surface-secrets-schema.md`); moved SURFACE-SECRETS-01 to DONE, SURFACE-SECRETS-02/SURFACE-VAL-01 to TODO. | Security Guild |

View File

@@ -1,24 +0,0 @@
# Sprint 151 - Scheduling & Automation · 150.A) Orchestrator.I
Active items only. Completed/historic work now resides in docs/implplan/archived/tasks.md (updated 2025-11-08).
[Scheduling & Automation] 150.A) Orchestrator.I
Depends on: Sprint 120.A - AirGap, Sprint 130.A - Scanner, Sprint 140.A - Graph
Summary: Scheduling & Automation focus on Orchestrator (phase I).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
ORCH-AIRGAP-56-001 | TODO | Enforce job descriptors to declare network intents; reject or flag any external endpoints in sealed mode before scheduling. | Orchestrator Service Guild, AirGap Policy Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-AIRGAP-56-002 | TODO | Surface sealing status and time staleness in job scheduling decisions; block runs when staleness budgets exceeded. Dependencies: ORCH-AIRGAP-56-001. | Orchestrator Service Guild, AirGap Controller Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-AIRGAP-57-001 | TODO | Add job type `mirror.bundle` to orchestrate bundle creation in connected environments with audit + provenance outputs. Dependencies: ORCH-AIRGAP-56-002. | Orchestrator Service Guild, Mirror Creator Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-AIRGAP-58-001 | TODO | Capture import/export operations as timeline/evidence entries, ensuring chain-of-custody for mirror + portable evidence jobs. Dependencies: ORCH-AIRGAP-57-001. | Orchestrator Service Guild, Evidence Locker Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OAS-61-001 | TODO | Document orchestrator endpoints in per-service OAS with standardized pagination, idempotency, and error envelope examples. | Orchestrator Service Guild, API Contracts Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OAS-61-002 | TODO | Implement `GET /.well-known/openapi` in service and ensure version metadata aligns with runtime build. Dependencies: ORCH-OAS-61-001. | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OAS-62-001 | TODO | Ensure SDK paginators and operations support orchestrator job operations; add SDK smoke tests for schedule/retry APIs. Dependencies: ORCH-OAS-61-002. | Orchestrator Service Guild, SDK Generator Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OAS-63-001 | TODO | Emit deprecation headers and documentation for legacy orchestrator endpoints; update notifications metadata. Dependencies: ORCH-OAS-62-001. | Orchestrator Service Guild, API Governance Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-50-001 | TODO | Wire `StellaOps.Telemetry.Core` into orchestrator host, instrument schedulers and control APIs with trace spans, structured logs, and exemplar metrics. Ensure tenant/job metadata recorded for every span/log. | Orchestrator Service Guild, Observability Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-51-001 | TODO | Publish golden-signal metrics (dispatch latency, queue depth, failure rate), define job/tenant SLOs, and emit burn-rate alerts to collector + Notifications. Provide Grafana dashboards + alert rules. Dependencies: ORCH-OBS-50-001. | Orchestrator Service Guild, DevOps Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-52-001 | TODO | Emit `timeline_event` objects for job lifecycle (`job.scheduled`, `job.started`, `job.completed`, `job.failed`) including trace IDs, run IDs, tenant/project, and causal metadata. Add contract tests and Kafka/NATS emitter with retries. Dependencies: ORCH-OBS-51-001. | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-53-001 | TODO | Generate job capsule inputs for evidence locker (payload digests, worker image, config hash, log manifest) and invoke locker snapshot hooks on completion/failure. Ensure redaction guard enforced. Dependencies: ORCH-OBS-52-001. | Orchestrator Service Guild, Evidence Locker Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-54-001 | TODO | Produce DSSE attestations for orchestrator-scheduled jobs (subject = job capsule) and store references in timeline + evidence locker. Provide verification endpoint `/jobs/{id}/attestation`. Dependencies: ORCH-OBS-53-001. | Orchestrator Service Guild, Provenance Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-OBS-55-001 | TODO | Implement incident mode hooks (sampling overrides, extended retention, additional debug spans) and automatic activation on SLO burn-rate breach. Emit activation/deactivation events to timeline + Notifier. Dependencies: ORCH-OBS-54-001. | Orchestrator Service Guild, DevOps Guild (src/Orchestrator/StellaOps.Orchestrator)
ORCH-SVC-32-001 | TODO | Bootstrap service project, configuration, and Postgres schema/migrations for `sources`, `runs`, `jobs`, `dag_edges`, `artifacts`, `quotas`, `schedules`. | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator)

View File

@@ -28,6 +28,7 @@
| ECOSYS-FIXTURES-GAPS-300-017 | TODO | QA Guild · Scanner Guild · Docs Guild | 30-Nov-2025 ecosystem reality test cases | Close ET1ET10: signed fixture pack + expected-result schema, deterministic builds/seeds, secret-leak assertions, offline/no-network enforcement, version matrix + DB pinning, SBOM parity thresholds, CI ownership/SLOs, provenance/licensing, retention/redaction policy, and ID/CVSS normalization utilities. |
| IMPLEMENTOR-GAPS-300-018 | TODO | Docs Guild · Platform Guild | 30-Nov-2025 implementor guidelines | Close IG1IG10: enforceable checklist + CI gates, schema/versioning change control, determinism/offline/secret/provenance requirements, perf/quota tests, boundary rules, and AGENTS/sprint linkages. |
| STANDUP-GAPS-300-019 | TODO | Docs Guild · Ops Guild | 30-Nov-2025 standup sprint kickstarters | Close SK1SK10: kickstarter template alignment with sprint template, readiness evidence checklist, dependency ledger with owners/SLOs, time-box/exit rules, async/offline workflow, Execution Log updates, decisions/risks delta capture, metrics (blocker clear rate/latency), role assignment, and lint/checks to enforce completion. |
| ARCHIVED-GAPS-300-020 | TODO | Docs Guild · Architecture Guild | 1523 Nov archived advisories | Decide which archived advisories to revive; close AR-* gaps (see `31-Nov-2025 FINDINGS.md` per-advisory table): publish canonical schemas/recipes (provenance, reachability, PURL/Build-ID), licensing/manifest rules, determinism seeds/SLOs, redaction/isolation, changelog/checkpoint signing, supersede duplicates (SBOM-Provenance-Spine, archived VB reachability), and document PostgreSQL storage blueprint guardrails. |
| Plugin architecture gaps remediation | TODO | Docs Guild · Module Guilds (Authority/Scanner/Concelier) | 28-Nov-2025 plugin advisory | Close PL1PL10 from `31-Nov-2025 FINDINGS.md`: publish signed schemas/capability catalog, sandbox/resource limits, provenance/SBOM + DSSE verification, determinism harness, compatibility matrix, dependency/secret rules, crash kill-switch, offline kit packaging/verify script, and signed plugin index with revocation/CVE data. |
| CVSS v4.0 momentum sync | TODO | Docs Guild | 29-Nov-2025 advisory + briefing draft | Publish the CVSS v4.0 momentum briefing, highlight adoption signals, and link to sprint decisions for SPRINT_0190.* and docs coverage. |
| SBOM→VEX proof blueprint sync | TODO | Docs Guild | 29-Nov-2025 advisory + blueprint draft | Publish the SBOM→VEX blueprint, link to platform/blueprint docs, and capture diagram/stub updates for DSSE/Rekor/VEX. |
@@ -55,6 +56,7 @@
| 2025-12-01 | Added ECOSYS-FIXTURES-GAPS-300-017 to track ET1ET10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending fixture pack creation and CI wiring. | Project Mgmt |
| 2025-12-01 | Added IMPLEMENTOR-GAPS-300-018 to track IG1IG10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending enforceable checklist/CI gates rollout. | Project Mgmt |
| 2025-12-01 | Added STANDUP-GAPS-300-019 to track SK1SK10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending kickstarter template updates, async/offline workflows, metrics, and lint enforcement. | Project Mgmt |
| 2025-12-01 | Added ARCHIVED-GAPS-300-020 to triage AR-* gaps from archived advisories (1523 Nov 2025); status TODO pending decision on which to revive and schema/recipe publication. | Project Mgmt |
| 2025-11-30 | Added the 30-Nov-2025 Rekor Receipt Checklist advisory and noted the ownership/action map for Authority/Sbomer/Vexer. | Docs Guild |
| 2025-11-30 | Added the 30-Nov-2025 Ecosystem Reality Test Cases advisory (credential leak, Trivy offline DB, SBOM parity, Grype divergence) and logged the acceptance test intent. | Docs Guild |
| 2025-11-30 | Added the 30-Nov-2025 Unknowns Decay & Triage advisory and noted UI + export artifacts for UnknownsRegistry + queues. | Docs Guild |

View File

@@ -1,12 +1,3 @@
# Sprint 327 - Documentation & Process · 200.Q) Docs Modules Scanner
# Redirect
Active items only. Completed/historic work now resides in docs/implplan/archived/tasks.md (updated 2025-11-08).
[Documentation & Process] 200.Q) Docs Modules Scanner
Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - AirGap, Sprint 130.A - Scanner, Sprint 140.A - Graph, Sprint 150.A - Orchestrator, Sprint 160.A - EvidenceLocker, Sprint 170.A - Notifier, Sprint 180.A - Cli, Sprint 190.A - Ops Deployment
Summary: Documentation & Process focus on Docs Modules Scanner).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
SCANNER-DOCS-0003 | TODO | Gather Windows/macOS analyzer demand signals and record findings in `docs/benchmarks/scanner/windows-macos-demand.md` for marketing + product readiness. | Docs Guild, Product Guild (docs/modules/scanner)
SCANNER-OPS-0001 | TODO | Review scanner runbooks/observability assets after the next sprint demo and capture findings inline with sprint notes. | Ops Guild (docs/modules/scanner)
SCANNER-ENG-0001 | TODO | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md` and update module readiness checkpoints. | Module Team (docs/modules/scanner)
This sprint file was renamed to `SPRINT_0327_0001_0001_docs_modules_scanner.md` to comply with naming rules. Please edit the canonical file.

View File

@@ -41,8 +41,8 @@
| 18 | PG-T4.6.4 | DONE | Completed 2025-11-29 | Policy Guild | Implement `IAuditRepository` |
| 19 | PG-T4.7 | DONE | Completed 2025-11-29 | Policy Guild | Add configuration switch in `ServiceCollectionExtensions` |
| 20 | PG-T4.8.1 | DONE | Completed 2025-11-29 | Policy Guild | Write integration tests for all repositories |
| 21 | PG-T4.8.2 | TODO | Depends on PG-T4.8.1 | Policy Guild | Test pack versioning workflow |
| 22 | PG-T4.8.3 | TODO | Depends on PG-T4.8.1 | Policy Guild | Test risk profile version history |
| 21 | PG-T4.8.2 | DOING (2025-12-01) | Depends on PG-T4.8.1 | Policy Guild | Test pack versioning workflow |
| 22 | PG-T4.8.3 | DOING (2025-12-01) | Depends on PG-T4.8.1 | Policy Guild | Test risk profile version history |
| 23 | PG-T4.9 | TODO | Depends on PG-T4.8 | Policy Guild | Export active packs from MongoDB |
| 24 | PG-T4.10 | TODO | Depends on PG-T4.9 | Policy Guild | Import packs to PostgreSQL |
| 25 | PG-T4.11 | TODO | Depends on PG-T4.10 | Policy Guild | Verify version numbers and active version settings |
@@ -103,6 +103,7 @@
| 2025-11-29 | ServiceCollectionExtensions updated with all repository registrations (PG-T4.7) | Claude |
| 2025-11-29 | Integration tests created for Pack, Rule, Exception, EvaluationRun, RiskProfile, PolicyAudit repositories (PG-T4.8.1) | Claude |
| 2025-11-30 | Normalised sprint to docs/implplan template; added coordination and action tracker sections | Codex |
| 2025-12-01 | Started PG-T4.8.2/4.8.3: defined pack versioning + risk profile history test matrices, fixture needs for Mongo→Postgres export/import (T4.9/T4.10), pegged to dual-write hashes from T4.8.1. | Implementer |
---
*Reference: docs/db/tasks/PHASE_4_POLICY.md*

View File

@@ -35,18 +35,18 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
| DEVOPS-AOC-19-001 | BLOCKED (2025-10-26) | Integrate the AOC Roslyn analyzer and guard tests into CI, failing builds when ingestion projects attempt banned writes. | DevOps Guild, Platform Guild (ops/devops) |
| DEVOPS-AOC-19-002 | BLOCKED (2025-10-26) | Add pipeline stage executing `stella aoc verify --since` against seeded Mongo snapshots for Concelier + Excititor, publishing violation report artefacts. Dependencies: DEVOPS-AOC-19-001. | DevOps Guild (ops/devops) |
| DEVOPS-AOC-19-003 | BLOCKED (2025-10-26) | Enforce unit test coverage thresholds for AOC guard suites and ensure coverage exported to dashboards. Dependencies: DEVOPS-AOC-19-002. | DevOps Guild, QA Guild (ops/devops) |
| DEVOPS-AOC-19-101 | TODO (2025-10-28) | Draft supersedes backfill rollout (freeze window, dry-run steps, rollback) once advisory_raw idempotency index passes staging verification. Dependencies: DEVOPS-AOC-19-003. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-AOC-19-101 | DONE (2025-12-01) | Draft supersedes backfill rollout (freeze window, dry-run steps, rollback) once advisory_raw idempotency index passes staging verification. Dependencies: DEVOPS-AOC-19-003. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-ATTEST-73-001 | DONE (2025-11-30) | Provision CI pipelines for attestor service (lint/test/security scan, seed data) and manage secrets for KMS drivers. | DevOps Guild, Attestor Service Guild (ops/devops) |
| DEVOPS-ATTEST-73-002 | DONE (2025-11-30) | Establish secure storage for signing keys (vault integration, rotation schedule) and audit logging. Dependencies: DEVOPS-ATTEST-73-001. | DevOps Guild, KMS Guild (ops/devops) |
| DEVOPS-ATTEST-74-001 | TODO | Deploy transparency log witness infrastructure and monitoring. Dependencies: DEVOPS-ATTEST-73-002. | DevOps Guild, Transparency Guild (ops/devops) |
| DEVOPS-GRAPH-INDEX-28-010-REL | TODO | Publish signed Helm/Compose/offline bundles for Graph Indexer; depends on GRAPH-INDEX-28-010 dev artefacts. | DevOps Guild, Graph Indexer Guild (ops/devops) |
| DEVOPS-LNM-21-101-REL | TODO | Run/apply shard/index migrations (Concelier LNM) in release pipelines; capture artefacts and rollback scripts. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-LNM-21-102-REL | TODO | Package/publish LNM backfill/rollback bundles for release/offline kit; depends on 21-102 dev outputs. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-LNM-21-103-REL | TODO | Publish/rotate object-store seeds and offline bootstraps with provenance hashes; depends on 21-103 dev outputs. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-ATTEST-74-001 | DONE (2025-12-01) | Deploy transparency log witness infrastructure and monitoring. Dependencies: DEVOPS-ATTEST-73-002. | DevOps Guild, Transparency Guild (ops/devops) |
| DEVOPS-GRAPH-INDEX-28-010-REL | DONE (2025-12-01) | Publish signed Helm/Compose/offline bundles for Graph Indexer; depends on GRAPH-INDEX-28-010 dev artefacts. | DevOps Guild, Graph Indexer Guild (ops/devops) |
| DEVOPS-LNM-21-101-REL | DONE (2025-12-01) | Run/apply shard/index migrations (Concelier LNM) in release pipelines; capture artefacts and rollback scripts. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-LNM-21-102-REL | DONE (2025-12-01) | Package/publish LNM backfill/rollback bundles for release/offline kit; depends on 21-102 dev outputs. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-LNM-21-103-REL | DONE (2025-12-01) | Publish/rotate object-store seeds and offline bootstraps with provenance hashes; depends on 21-103 dev outputs. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-STORE-AOC-19-005-REL | BLOCKED | Release/offline-kit packaging for Concelier backfill; waiting on dataset hash + dev rehearsal. | DevOps Guild, Concelier Storage Guild (ops/devops) |
| DEVOPS-CONCELIER-CI-24-101 | DONE (2025-11-25) | Provide clean CI runner + warmed NuGet cache + vstest harness for Concelier WebService & Storage; deliver TRX/binlogs and unblock CONCELIER-GRAPH-24-101/28-102 and LNM-21-004..203. | DevOps Guild, Concelier Core Guild (ops/devops) |
| DEVOPS-SCANNER-CI-11-001 | DONE (2025-11-30) | Supply warmed cache/diag runner for Scanner analyzers (LANG-11-001, JAVA 21-005/008) with binlogs + TRX; unblock restore/test hangs. | DevOps Guild, Scanner EPDR Guild (ops/devops) |
| DEVOPS-SCANNER-JAVA-21-011-REL | TODO | Package/sign Java analyzer plug-in once dev task 21-011 delivers; publish to Offline Kit/CLI release pipelines with provenance. | DevOps Guild, Scanner Release Guild (ops/devops) |
| DEVOPS-SCANNER-JAVA-21-011-REL | DONE (2025-12-01) | Package/sign Java analyzer plug-in once dev task 21-011 delivers; publish to Offline Kit/CLI release pipelines with provenance. | DevOps Guild, Scanner Release Guild (ops/devops) |
| DEVOPS-SBOM-23-001 | DONE (2025-11-30) | Publish vetted offline NuGet feed + CI recipe for SbomService; prove with `dotnet test` run and share cache hashes; unblock SBOM-CONSOLE-23-001/002. | DevOps Guild, SBOM Service Guild (ops/devops) |
| FEED-REMEDIATION-1001 | BLOCKED (2025-11-24) | Define remediation scope and runbook for overdue feeds (CCCS/CERTBUND); schedule refresh; depends on PREP-FEEDCONN-ICS-KISA-PLAN. | Concelier Feed Owners (ops/devops) |
| FEEDCONN-ICSCISA-02-012 / FEEDCONN-KISA-02-008 | BLOCKED (2025-11-24) | Publish provenance refresh/connector schedule for ICSCISA/KISA feeds; execute remediation per runbook once owners provide plan. | Concelier Feed Owners (ops/devops) |
@@ -75,6 +75,11 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
| 2025-12-01 | Marked DEVOPS-SPANSINK-31-003 to DOING; span sink/Signals pipeline setup underway. | DevOps |
| 2025-11-30 | Completed DEVOPS-AIRGAP-58-001: added syslog/SMTP compose stack (`ops/devops/airgap/compose-syslog-smtp.yaml`) and health script (`health_syslog_smtp.sh`); documented in airgap README for sealed environments. | DevOps |
| 2025-11-30 | DEVOPS-AIAI-31-001 DONE: added Advisory AI CI harness (`ops/devops/advisoryai-ci-runner/run-advisoryai-ci.sh`) producing binlog/TRX/summary; warmed local NuGet cache for offline runs; docs in runner README. | DevOps |
| 2025-12-01 | Completed DEVOPS-AOC-19-101: authored supersedes backfill rollout plan (`ops/devops/aoc/supersedes-rollout.md`) covering freeze window, dry-run, validation, rollback, evidence capture, and monitoring. | DevOps |
| 2025-12-01 | Completed DEVOPS-ATTEST-74-001: published transparency log witness deployment plan (`ops/devops/attestation/witness-plan.md`) with security hardening, CI tests, monitoring/alerts, and air-gap mode guidance. | DevOps |
| 2025-12-01 | Completed DEVOPS-GRAPH-INDEX-28-010-REL: documented signed Helm/Compose/offline bundle plan for Graph Indexer (`ops/devops/graph-indexer/release-plan.md`) including SBOMs, cosign attestations, air-gap bundle layout, and verification steps. | DevOps |
| 2025-12-01 | Completed DEVOPS-SCANNER-JAVA-21-011-REL: added Java analyzer release/offline plan (`ops/devops/scanner-java/release-plan.md`) covering SBOMs, cosign attestations, offline bundle packaging, and verification. | DevOps |
| 2025-12-01 | Completed DEVOPS-LNM-21-101/102/103-REL: added Concelier LNM release/offline plan (`ops/devops/concelier/lnm-release-plan.md`) covering shard/index migrations, backfill/rollback bundles, object-store seeds, offline tarball layout, signatures, and rollback. | DevOps |
## Decisions & Risks
- Mirror bundle automation (DEVOPS-AIRGAP-57-001) and AOC guardrails remain gating risks; several downstream tasks inherit these.

View File

@@ -1282,21 +1282,22 @@
| ORCH-34-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-34-004 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-34-005 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-AIRGAP-56-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + AirGap Policy Guilds | src/Orchestrator/StellaOps.Orchestrator | Enforce job descriptors to declare network intents; reject external endpoints in sealed mode. | ATMI0102 | ORAG0101 |
| ORCH-AIRGAP-56-002 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + AirGap Controller Guild | src/Orchestrator/StellaOps.Orchestrator | Surface sealing status/time staleness in scheduler APIs. | ORCH-AIRGAP-56-001 | ORAG0101 |
| ORCH-AIRGAP-57-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator + Export Center Guilds | src/Orchestrator/StellaOps.Orchestrator | Ship sealed-mode exec profiles with mirror/orchestrator hooks. | ORCH-AIRGAP-56-002 | ORAG0101 |
| ORCH-AIRGAP-58-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator + Offline Kit Guilds | src/Orchestrator/StellaOps.Orchestrator | Export sealed job bundles + DSSE receipts for Offline Kit. | ORCH-AIRGAP-57-001 | ORAG0101 |
| ORCH-OAS-61-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Update orchestrator OAS spec + changelog per governance rules. | OAS-61 | OROA0101 |
| ORCH-OAS-61-002 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Apply pagination/idempotency rules + tests. | ORCH-OAS-61-001 | OROA0101 |
| ORCH-OAS-62-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + SDK Guild | src/Orchestrator/StellaOps.Orchestrator | Publish auto-generated SDK + portal refs. | ORCH-OAS-61-002 | OROA0101 |
| ORCH-OAS-63-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + API Governance Guild | src/Orchestrator/StellaOps.Orchestrator | Implement `.well-known/openapi` discovery + deprecation headers. | ORCH-OAS-62-001 | OROA0101 |
| ORCH-OBS-50-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Observability Guild | src/Orchestrator/StellaOps.Orchestrator | Wire `StellaOps.Telemetry.Core` into orchestrator host, instrument schedulers and control APIs with trace spans, structured logs, and exemplar metrics. Ensure tenant/job metadata recorded for every span/log. | Wait for 043_ORTR0101 taskrunner counters | OROB0101 |
| ORCH-OBS-51-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Publish golden-signal metrics (dispatch latency, queue depth, failure rate), define job/tenant SLOs, and emit burn-rate alerts to collector + Notifications. Provide Grafana dashboards + alert rules. Dependencies: ORCH-OBS-50-001. | Needs DevOps alert templates (045_DVDO0103) | OROB0101 |
| ORCH-OBS-52-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Emit `timeline_event` objects for job lifecycle (`job.scheduled`, `job.started`, `job.completed`, `job.failed`) including trace IDs, run IDs, tenant/project, and causal metadata. Add contract tests and Kafka/NATS emitter with retries. Dependencies: ORCH-OBS-51-001. | Depends on instrumentation contract 046_TLTY0101 | OROB0101 |
| ORCH-OBS-53-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Evidence Locker Guild | src/Orchestrator/StellaOps.Orchestrator | Generate job capsule inputs for evidence locker (payload digests, worker image, config hash, log manifest) and invoke locker snapshot hooks on completion/failure. Ensure redaction guard enforced. Dependencies: ORCH-OBS-52-001. | Requires Evidence Locker contract (002_ATEL0101) | OROB0101 |
| ORCH-OBS-54-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Provenance Guild | src/Orchestrator/StellaOps.Orchestrator | Produce DSSE attestations for orchestrator-scheduled jobs (subject = job capsule) and store references in timeline + evidence locker. Provide verification endpoint `/jobs/{id}/attestation`. Dependencies: ORCH-OBS-53-001. | Blocked by provenance schema (005_ATLN0101) | OROB0101 |
| ORCH-OBS-55-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Implement incident mode hooks (sampling overrides, extended retention, additional debug spans) and automatic activation on SLO burn-rate breach. Emit activation/deactivation events to timeline + Notifier. Dependencies: ORCH-OBS-54-001. | Needs #5 resolved for label stability | OROB0101 |
| ORCH-SVC-32-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Bootstrap service project, configuration, Postgres schema/migrations for sources/runs/jobs DAG. | PGMI0101 | ORSC0101 |
| ORCH-AIRGAP-56-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · AirGap Policy Guild | src/Orchestrator/StellaOps.Orchestrator | Enforce job descriptors to declare network intents; flag/reject external endpoints in sealed mode before scheduling. | PREP-ORCH-AIRGAP-56-001-AWAIT-SPRINT-0120-A-A | ORAG0101 |
| ORCH-AIRGAP-56-002 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · AirGap Controller Guild | src/Orchestrator/StellaOps.Orchestrator | Surface sealing status and staleness in scheduling decisions; block runs when budgets are exceeded. | PREP-ORCH-AIRGAP-56-002-UPSTREAM-56-001-BLOCK | ORAG0101 |
| ORCH-AIRGAP-57-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · Mirror Creator Guild | src/Orchestrator/StellaOps.Orchestrator | Add job type `mirror.bundle` to orchestrate bundle creation in connected environments with audit + provenance outputs. | PREP-ORCH-AIRGAP-57-001-UPSTREAM-56-002-BLOCK | ORAG0101 |
| ORCH-AIRGAP-58-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · Evidence Locker Guild | src/Orchestrator/StellaOps.Orchestrator | Capture import/export operations as timeline/evidence entries, ensuring chain-of-custody for mirror + portable evidence jobs. | PREP-ORCH-AIRGAP-58-001-UPSTREAM-57-001-BLOCK | ORAG0101 |
| ORCH-OAS-61-001 | DONE (2025-11-30) | 2025-11-30 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · API Contracts Guild | src/Orchestrator/StellaOps.Orchestrator | Document orchestrator endpoints in per-service OAS with standardized pagination, idempotency, and error envelope examples. | PREP-ORCH-OAS-61-001-ORCHESTRATOR-TELEMETRY-C | OROA0101 |
| ORCH-OAS-61-002 | DONE (2025-11-30) | 2025-11-30 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement `GET /.well-known/openapi` and align version metadata with runtime build. | PREP-ORCH-OAS-61-002-DEPENDS-ON-61-001 | OROA0101 |
| ORCH-OAS-62-001 | DONE (2025-11-30) | 2025-11-30 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · SDK Generator Guild | src/Orchestrator/StellaOps.Orchestrator | Ensure SDK paginators/operations support orchestrator job APIs; add SDK smoke tests for schedule/retry (pack-run). | PREP-ORCH-OAS-62-001-DEPENDS-ON-61-002 | OROA0101 |
| ORCH-OAS-63-001 | DONE (2025-11-30) | 2025-11-30 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · API Governance Guild | src/Orchestrator/StellaOps.Orchestrator | Emit deprecation headers and documentation for legacy orchestrator endpoints; update notifications metadata. | PREP-ORCH-OAS-63-001-DEPENDS-ON-62-001 | OROA0101 |
| ORCH-OBS-50-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · Observability Guild | src/Orchestrator/StellaOps.Orchestrator | Wire `StellaOps.Telemetry.Core` into orchestrator host, instrument schedulers and control APIs with trace spans, structured logs, and exemplar metrics; ensure tenant/job metadata is recorded for every span/log. | PREP-ORCH-OBS-50-001-TELEMETRY-CORE-SPRINT-01 | OROB0101 |
| ORCH-OBS-51-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Publish golden-signal metrics (dispatch latency, queue depth, failure rate), define job/tenant SLOs, and emit burn-rate alerts to collector + Notifications; provide Grafana dashboards + alert rules. | PREP-ORCH-OBS-51-001-DEPENDS-ON-50-001-TELEME | OROB0101 |
| ORCH-OBS-52-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Emit `timeline_event` objects for job lifecycle (`job.scheduled`, `job.started`, `job.completed`, `job.failed`) including trace IDs, run IDs, tenant/project, and causal metadata; add contract tests and Kafka/NATS emitter with retries. | PREP-ORCH-OBS-52-001-DEPENDS-ON-51-001-REQUIR | OROB0101 |
| ORCH-OBS-53-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · Evidence Locker Guild | src/Orchestrator/StellaOps.Orchestrator | Generate job capsule inputs for evidence locker (payload digests, worker image, config hash, log manifest) and invoke locker snapshot hooks on completion/failure; enforce redaction guard. | PREP-ORCH-OBS-53-001-DEPENDS-ON-52-001-EVIDEN | OROB0101 |
| ORCH-OBS-54-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · Provenance Guild | src/Orchestrator/StellaOps.Orchestrator | Produce DSSE attestations for orchestrator-scheduled jobs (subject = job capsule) and store references in timeline + evidence locker; provide verification endpoint `/jobs/{id}/attestation`. | PREP-ORCH-OBS-54-001-DEPENDS-ON-53-001 | OROB0101 |
| ORCH-OBS-55-001 | BLOCKED (2025-11-19) | 2025-11-19 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Implement incident mode hooks (sampling overrides, extended retention, additional debug spans) and automatic activation on SLO burn-rate breach; emit activation/deactivation events to timeline + Notifier. | PREP-ORCH-OBS-55-001-DEPENDS-ON-54-001-INCIDE | OROB0101 |
| ORCH-SVC-32-001 | DONE (2025-11-28) | 2025-11-28 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Bootstrap service project/config and Postgres schema/migrations for `sources`, `runs`, `jobs`, `dag_edges`, `artifacts`, `quotas`, `schedules`. | — | ORSC0101 |
| ORCH-GAPS-151-016 | DOING (2025-12-01) | 2025-12-01 | SPRINT_0151_0001_0001_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Close OR1OR10 gaps from `31-Nov-2025 FINDINGS.md`: signed schemas + hashes, replay inputs.lock, heartbeat/lease governance, DAG validation, quotas/breakers, security bindings, ordered/backpressured fan-out, audit-bundle schema/verify script, SLO alerts, TaskRunner integrity (artifact/log hashing + DSSE linkage). | Schema/catalog refresh | |
| ORCH-SVC-32-002 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement scheduler DAG planner + job state machine. | ORCH-SVC-32-001 | ORSC0101 |
| ORCH-SVC-32-003 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Expose REST APIs (sources/runs/jobs) w/ validation + tenant scope. | ORCH-SVC-32-002 | ORSC0101 |
| ORCH-SVC-32-004 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement SSE/WS streams + metrics/health probes. | ORCH-SVC-32-003 | ORSC0101 |
@@ -1881,7 +1882,6 @@
| SURFACE-VAL-03 | TODO | | SPRINT_136_scanner_surface | Scanner Guild, Analyzer Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Integrate validation pipeline into Scanner analyzers so checks run before processing. | SURFACE-VAL-02 | SCSS0102 |
| SURFACE-VAL-04 | TODO | | SPRINT_136_scanner_surface | Scanner Guild, Zastava Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Expose validation helpers to Zastava and other runtime consumers for preflight checks. | SURFACE-VAL-02 | SCSS0102 |
| SURFACE-VAL-05 | TODO | | SPRINT_136_scanner_surface | Docs Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Document validation extensibility, registration, and customization in scanner-engine guides. | SURFACE-VAL-02 | SCSS0102 |
| SVC-32-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-002 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-003 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-004 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
@@ -3500,21 +3500,6 @@
| ORCH-34-003 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-34-004 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-34-005 | TODO | | SPRINT_306_docs_tasks_md_vi | Docs Guild (docs) | | — | — | ORGR0102 |
| ORCH-AIRGAP-56-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + AirGap Policy Guilds | src/Orchestrator/StellaOps.Orchestrator | Enforce job descriptors to declare network intents; reject or flag any external endpoints in sealed mode before scheduling. | Needs ATMI0102 seal guidance | |
| ORCH-AIRGAP-56-002 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + AirGap Controller Guild | src/Orchestrator/StellaOps.Orchestrator | Surface sealing status and time staleness in job scheduling decisions; block runs when staleness budgets exceeded. Dependencies: ORCH-AIRGAP-56-001. | Depends on 56-001 policy | |
| ORCH-AIRGAP-57-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator + Export Center Guilds | src/Orchestrator/StellaOps.Orchestrator | Add job type `mirror.bundle` to orchestrate bundle creation in connected environments with audit + provenance outputs. Dependencies: ORCH-AIRGAP-56-002. | Requires exported policy from OFFK0101 | |
| ORCH-AIRGAP-58-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator + Offline Kit Guilds | src/Orchestrator/StellaOps.Orchestrator | Capture import/export operations as timeline/evidence entries, ensuring chain-of-custody for mirror + portable evidence jobs. Dependencies: ORCH-AIRGAP-57-001. | Needs 57-001 job profile | |
| ORCH-OAS-61-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Document orchestrator endpoints in per-service OAS with standardized pagination, idempotency, and error envelope examples. | Needs DOOA0103 decisions | |
| ORCH-OAS-61-002 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement `GET /.well-known/openapi` in service and ensure version metadata aligns with runtime build. Dependencies: ORCH-OAS-61-001. | Depends on 61-001 | |
| ORCH-OAS-62-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + SDK Guild | src/Orchestrator/StellaOps.Orchestrator | Ensure SDK paginators and operations support orchestrator job operations; add SDK smoke tests for schedule/retry APIs. Dependencies: ORCH-OAS-61-002. | Requires generator scaffolding | |
| ORCH-OAS-63-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service + API Governance Guild | src/Orchestrator/StellaOps.Orchestrator | Emit deprecation headers and documentation for legacy orchestrator endpoints; update notifications metadata. Dependencies: ORCH-OAS-62-001. | Waits on 62-001 metadata | |
| ORCH-OBS-50-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Observability Guild | src/Orchestrator/StellaOps.Orchestrator | Wire `StellaOps.Telemetry.Core` into orchestrator host, instrument schedulers and control APIs with trace spans, structured logs, and exemplar metrics. Ensure tenant/job metadata recorded for every span/log. | Wait for 043_ORTR0101 taskrunner counters | OROB0101 |
| ORCH-OBS-51-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Publish golden-signal metrics (dispatch latency, queue depth, failure rate), define job/tenant SLOs, and emit burn-rate alerts to collector + Notifications. Provide Grafana dashboards + alert rules. Dependencies: ORCH-OBS-50-001. | Needs DevOps alert templates (045_DVDO0103) | OROB0101 |
| ORCH-OBS-52-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Emit `timeline_event` objects for job lifecycle (`job.scheduled`, `job.started`, `job.completed`, `job.failed`) including trace IDs, run IDs, tenant/project, and causal metadata. Add contract tests and Kafka/NATS emitter with retries. Dependencies: ORCH-OBS-51-001. | Depends on instrumentation contract 046_TLTY0101 | OROB0101 |
| ORCH-OBS-53-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Evidence Locker Guild | src/Orchestrator/StellaOps.Orchestrator | Generate job capsule inputs for evidence locker (payload digests, worker image, config hash, log manifest) and invoke locker snapshot hooks on completion/failure. Ensure redaction guard enforced. Dependencies: ORCH-OBS-52-001. | Requires Evidence Locker contract (002_ATEL0101) | OROB0101 |
| ORCH-OBS-54-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · Provenance Guild | src/Orchestrator/StellaOps.Orchestrator | Produce DSSE attestations for orchestrator-scheduled jobs (subject = job capsule) and store references in timeline + evidence locker. Provide verification endpoint `/jobs/{id}/attestation`. Dependencies: ORCH-OBS-53-001. | Blocked by provenance schema (005_ATLN0101) | OROB0101 |
| ORCH-OBS-55-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild · DevOps Guild | src/Orchestrator/StellaOps.Orchestrator | Implement incident mode hooks (sampling overrides, extended retention, additional debug spans) and automatic activation on SLO burn-rate breach. Emit activation/deactivation events to timeline + Notifier. Dependencies: ORCH-OBS-54-001. | Needs #5 resolved for label stability | OROB0101 |
| ORCH-SVC-32-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Bootstrap service project, configuration, and Postgres schema/migrations for `sources`, `runs`, `jobs`, `dag_edges`, `artifacts`, `quotas`, `schedules`. | None | |
| ORCH-SVC-32-002 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement scheduler DAG planner + dependency resolver, job state machine, and critical-path metadata without yet issuing control actions. Dependencies: ORCH-SVC-32-001. | Needs 32-001 DB | |
| ORCH-SVC-32-003 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Expose read-only REST APIs (sources, runs, jobs, DAG) with OpenAPI, validation, pagination, and tenant scoping. Dependencies: ORCH-SVC-32-002. | Depends on 32-002 | |
| ORCH-SVC-32-004 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Implement WebSocket/SSE stream for job/run updates, emit structured metrics counters/histograms, and add health probes. Dependencies: ORCH-SVC-32-003. | Needs 32-003 | |
@@ -3534,7 +3519,7 @@
| ORCH-SVC-41-101 | TODO | | SPRINT_0153_0001_0003_orchestrator_iii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Register `pack-run` job type, persist run metadata, integrate logs/artifacts collection, and expose API for Task Runner scheduling. Dependencies: ORCH-SVC-38-101. | Depends on 38-101 | |
| ORCH-SVC-42-101 | TODO | | SPRINT_0153_0001_0003_orchestrator_iii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Stream pack run logs via SSE/WS, add manifest endpoints, enforce quotas, and emit pack run events to Notifications Studio. Dependencies: ORCH-SVC-41-101. | Needs 41-101 | |
| ORCH-TEN-48-001 | TODO | | SPRINT_0153_0001_0003_orchestrator_iii | Orchestrator Service Guild | src/Orchestrator/StellaOps.Orchestrator | Include `tenant_id`/`project_id` in job specs, set DB session context before processing, enforce context on all queries, and reject jobs missing tenant metadata. | Needs ORSC0104 job metadata | |
| ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team | docs/modules/orchestrator | Keep sprint milestone alignment notes synced with `/docs/implplan/SPRINT_151_orchestrator_i.md` onward. | Needs ORSC0104 status updates | |
| ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team | docs/modules/orchestrator | Keep sprint milestone alignment notes synced with `/docs/implplan/SPRINT_0151_0001_0001_orchestrator_i.md` onward. | Needs ORSC0104 status updates | |
| ORCH-OPS-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Ops Guild | docs/modules/orchestrator | Review orchestrator runbooks/observability checklists post-demo. | Requires obs/export docs | |
| PACKS-42-001 | TODO | | SPRINT_0121_0001_0001_policy_reasoning | Findings Ledger Guild | src/Findings/StellaOps.Findings.Ledger | Provide snapshot/time-travel APIs, digestable exports for pack simulation + CLI offline mode. | Needs ORSC0104 event IDs | |
| PACKS-43-001 | DONE | 2025-11-09 | SPRINT_100_identity_signing | Packs Guild · Authority Guild | src/Authority/StellaOps.Authority | Canonical pack bundle + docs for release 43. | AUTH-PACKS-41-001; TASKRUN-42-001; ORCH-SVC-42-101 | |
@@ -4097,7 +4082,6 @@
| SURFACE-VAL-03 | TODO | | SPRINT_136_scanner_surface | Scanner Guild, Analyzer Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Integrate validation pipeline into Scanner analyzers so checks run before processing. | SURFACE-VAL-02 | SCSS0102 |
| SURFACE-VAL-04 | TODO | | SPRINT_136_scanner_surface | Scanner Guild, Zastava Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Expose validation helpers to Zastava and other runtime consumers for preflight checks. | SURFACE-VAL-02 | SCSS0102 |
| SURFACE-VAL-05 | TODO | | SPRINT_136_scanner_surface | Docs Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.Validation | Document validation extensibility, registration, and customization in scanner-engine guides. | SURFACE-VAL-02 | SCSS0102 |
| SVC-32-001 | TODO | | SPRINT_151_orchestrator_i | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-002 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-003 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
| SVC-32-004 | TODO | | SPRINT_152_orchestrator_ii | Orchestrator Service Guild (src/Orchestrator/StellaOps.Orchestrator) | src/Orchestrator/StellaOps.Orchestrator | | | |
@@ -4426,3 +4410,6 @@
| CI RECIPES-DOCS-0001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_0315_0001_0001_docs_modules_ci | Docs Guild (docs/modules/ci) | docs/modules/ci | Update module charter docs (AGENTS/README/architecture/implementation_plan) with determinism + offline posture; sprint normalized. | — | |
| CI RECIPES-ENG-0001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_0315_0001_0001_docs_modules_ci | Module Team (docs/modules/ci) | docs/modules/ci | Establish TASKS board and status mirroring rules for CI Recipes contributors. | CI RECIPES-DOCS-0001 | |
| CI RECIPES-OPS-0001 | DONE (2025-11-25) | 2025-11-25 | SPRINT_0315_0001_0001_docs_modules_ci | Ops Guild (docs/modules/ci) | docs/modules/ci | Sync outcomes back to sprint + legacy filename stub; ensure references resolve to normalized sprint path. | CI RECIPES-DOCS-0001; CI RECIPES-ENG-0001 | |
| WEB-TEN-47-CONTRACT | DONE (2025-12-01) | 2025-12-01 | SPRINT_0216_0001_0001_web_v | BE-Base Platform Guild | docs/api/gateway/tenant-auth.md | Publish gateway routing + tenant header/ABAC contract (headers, scopes, samples, audit notes). | — | — |
| WEB-VULN-29-LEDGER-DOC | DONE (2025-12-01) | 2025-12-01 | SPRINT_0216_0001_0001_web_v | Findings Ledger Guild · BE-Base Platform Guild | docs/api/gateway/findings-ledger-proxy.md | Capture idempotency + correlation header contract for Findings Ledger proxy and retries/backoff defaults. | — | — |
| WEB-RISK-68-NOTIFY-DOC | DONE (2025-12-01) | 2025-12-01 | SPRINT_0216_0001_0001_web_v | Notifications Guild · BE-Base Platform Guild | docs/api/gateway/notifications-severity.md | Document severity transition event schema (fields, trace metadata) for notifier bus integration. | — | — |

View File

@@ -0,0 +1,63 @@
version: 1
generated: 2025-12-01T00:00:00Z
compatibility:
policy: "SemVer-like: commands/flags/exitCodes are backwards compatible within major version."
deprecation:
noticeMinimumDays: 90
channels:
- release-notes
- --compat-report
commands:
- name: advise
subcommands:
- name: summarize
formats: [json, markdown, table]
exitCodes:
0: success
2: validation-error
3: backend-unavailable
- name: explain
formats: [json, markdown, table]
exitCodes:
0: success
2: validation-error
3: backend-unavailable
- name: remediate
flags:
- name: strategy
required: false
values: [minimal, defense-in-depth, fast-track]
exitCodes:
0: success
2: validation-error
3: backend-unavailable
- name: auth
subcommands:
- name: doctor
exitCodes:
0: success
4: auth-misconfigured
5: token-invalid
telemetry:
defaultEnabled: false
envVars:
optIn: STELLAOPS_TELEMETRY=1
optOut: STELLAOPS_TELEMETRY=0
persistField: telemetryEnabled
install:
checksumRequired: true
cosignVerifyDefault: true
exitCodes:
21: checksum-file-missing
22: checksum-mismatch
buildxPlugin:
imageDigest: "sha256:0000000000000000000000000000000000000000000000000000000000000000"
rollbackCommand: "stella tool buildx rollback --to <digest>"
determinism:
locale: "en-US"
timezone: "UTC"
jsonFormatting: "stable-sort-keys"
tableWidth: 80
tests:
- name: cli-compatibility-regression
description: "Ensure commands/flags/exit codes match spec and telemetry defaults are enforced."

View File

@@ -0,0 +1,15 @@
# CLI Install & Update Integrity (v1) — 2025-12-01
Requirements
- Checksums: Every release publishes `stellaops-cli-$version.tar.zst` with `SHA256SUMS` + detached `.sig`.
- Verification: `stella install` and `stella self-update` run `cosign verify` by default against pinned public key fingerprint; `--skip-verify` prohibited.
- Offline: Provide `install-offline.sh` that reads from kit directory with checksum + signature checks only; no network fetches.
- Buildx plugin: pin image digest (see `cli-spec-v1.yaml`); rollback command included in help.
Failure modes
- Missing checksum/signature → command fails with exit code 21 and structured error.
- Digest mismatch → command fails with exit code 22; log path to offending file.
Artifacts
- Public key fingerprints recorded in `cli-spec-v1.yaml`.
- Example verify script to be bundled in release kit: `scripts/cli/verify-install.sh`.

View File

@@ -0,0 +1,19 @@
# CLI Output Determinism Policy (v1) — 2025-12-01
Scope: `StellaOps.Cli` JSON/table/markdown outputs for advisory verbs and auth doctor.
Rules
- Time: All timestamps UTC; no local timezone conversion.
- Locale: `en-US`, `InvariantCulture` for number/date formatting.
- Ordering: Sort collections by stable key (id/name) before rendering; JSON keys stable-sorted.
- Width: Table renderer clamps to width 80; no ANSI when `--output json` or non-TTY.
- Seeds: Randomness forbidden; no wall-clock in hashes; use provided deterministic IDs.
Tests
- Golden fixtures stored under `src/Cli/__Tests/StellaOps.Cli.Tests/Fixtures/output-determinism/`.
- Hash check: two consecutive runs of the same command with identical inputs must produce identical SHA256 of stdout.
- Locale guard: integration test forces `CultureInfo("fr-FR")` and asserts output matches fixtures.
Failure handling
- Any drift fails CI; diff is printed with unified format.
- Add new fields behind explicit versioned spec entry in `cli-spec-v1.yaml`.

View File

@@ -0,0 +1,26 @@
# Scanner Readiness Checkpoints (as of 2025-12-01)
## Snapshot
- Scope: scanner/surface sprints 01310138.
- Status legend: **Green** = shipped and validated; **Amber** = shipped but validation blocked or partial; **Red** = not shipped/blocked upstream.
## Phase Readiness
| Phase / Sprint | Status | Evidence | Gaps / Actions |
| --- | --- | --- | --- |
| Phase II · Sprint 0131 (Deno/Java/.NET bootstrap) | Amber/Red | Deno runtime capture shipped and tested; Java chain 21-005..011 blocked on Concelier build + CI runner; .NET Lang 11-001 blocked awaiting clean runner; PHP VFS 27-001 blocked pending bootstrap spec. | Need CI slice (DEVOPS-SCANNER-CI-11-001) for Java/.NET; define PHP bootstrap spec and fixtures to unblock 27-001. |
| Phase III · Sprint 0132 (Native + Node foundations) | Amber | Native analyzers 20-001..010 shipped with tests; Node 22-001..005 shipped; Node isolated/CI tests pending due to build graph bloat; .NET Lang 11-002..005 blocked on upstream design 11-001 outputs. | Trim Node test graph or run on clean runner to record pass; unblock .NET analyzer design to proceed with runtime/export/fixtures. |
| Phase IV · Sprint 0133 (Node bundle/source-map) | Amber | Phase22 bundle/native/WASM observation implemented and fixtures hashed; validation tests pending (SDK resolver cancels build on current runner). | Execute `scripts/run-node-phase22-smoke.sh` on clean runner; capture TRX/binlog to close. |
| Phase V · Sprint 0134 (PHP fixtures/runtime/package) | Green | PHP analyzer fixtures, runtime evidence, and packaging shipped; docs updated. | Keep fixture hashes stable; rerun benchmarks when dependencies change. |
| Phase VI · Sprint 0135 (Python container + Ruby VFS/edges) | Green | Python container/zipapp adapters shipped; Ruby VFS/dependency edges/observations/runtime capture packaged; EntryTrace 18-502/503 delivered. | Maintain determinism; re-run EntryTrace suite in CI. |
| Phase VII · Sprint 0136 (EntryTrace surface/CLI) | Green | EntryTrace phase VII tasks 18-504/505/506 completed; CLI/WebService surfaces show best-terminal metadata and confidence. | Keep NDJSON schema stable; rerun worker payload tests in CI. |
| Sprint 0138 (Ruby parity & future analyzers) | Amber/Red | Ruby parity shipped; Mongo package inventory live. PHP pipeline SCANNER-ENG-0010 blocked on composer/autoload design + restore stability; Deno/Dart/Swift analyzer scopes blocked awaiting design; Kubernetes/VM roadmap pending. | Resolve PHP restore/design, produce Deno/Dart/Swift scopes, schedule Zastava/Runtime alignment. |
## Overall
- Green areas: native analyzers, PHP fixtures/runtime packaging, Ruby analyzer, Python container adapters, EntryTrace phases VIVII.
- Amber/Red drivers: Java/.NET analyzer chains (CI/design dependencies), PHP pipeline (0138), Node validation on clean runner, design gaps for Deno/Dart/Swift, PHP VFS bootstrap (0131).
## Recommended Next Actions
1) Secure clean CI slice for Java/.NET and Node Phase22 smoke tests; store binlogs/TRX.
2) Finalise PHP analyzer design (composer/autoload graph) and stabilise restore pipeline to unblock SCANNER-ENG-0010/27-001.
3) Publish Deno/Dart/Swift analyzer scopes with fixtures to unblock 0138 tasks and roadmap alignment with Zastava/Runtime.
4) Re-run EntryTrace and Native suites in CI to lock deterministic hashes before downstream release.

View File

@@ -0,0 +1,8 @@
170892f6a48b0aef6f426ea97a86f6cd4420bc52634f12a92f72e20f0fa12e29 decay/confidence_decay_config.yaml
450675035928e4771cca1b9e5f9e42035dbe10b3de7b66a4077a7b729b2c5b13 unknowns/unknowns_scoring_manifest.json
e33fa0963493252a5ac379a12f820f6b356ea94310afd1db9ad7394e8307000e heuristics/heuristics.catalog.json
6e2e6dfeeb4ae016b7ae881d4653ab79a3babba28a4c6d072266e81c61366e2c heuristics/heuristics.schema.json
99b1a4abc941bea5d4ee6b1dbd6faea37de9c67474bb1bac5f23570a44beff17 heuristics/fixtures/heur.callgraph.hotpath/input.json
851452aeac775e71d7507b70e9b7eb05bc619b37ba656a31b53fb3a504fb3b4a heuristics/fixtures/heur.callgraph.hotpath/expected.json
4d0f69b6064df2014f20673feda7881f815b489ab22e0a219301514b766b29d1 heuristics/fixtures/heur.pkg.sbom_age/input.json
bd9e5b2081e7fe9d947e7a44b0c493efd4d8e97d4c13ec4efd577869559fb1c2 heuristics/fixtures/heur.pkg.sbom_age/expected.json

View File

@@ -0,0 +1,79 @@
# Confidence Decay Controls · Signals Runtime
**Compiled:** 2025-12-01 (UTC)
**Scope:** Close U1U10 gaps from `docs/product-advisories/31-Nov-2025 FINDINGS.md` for confidence decay of unknowns/signals.
**Status:** Draft for review on 2025-12-03; to be signed (DSSE) after sign-off.
## Decisions (U1U10)
- **τ governance (U1):** All τ values live in `confidence_decay_config.yaml`, change-controlled via DSSE-signed PRs; allowable τ range 190 days. Changes require dual approval (Signals + Policy), recorded in history.
- **Floor / freeze (U2):** `confidence_floor` per severity; `is_confidence_frozen=true` when SLA-bound or manual pin. Floors: Critical 0.60, High 0.45, Medium 0.30, Low 0.20. Freeze auto-expires at `freeze_until`.
- **Weighted signals (U3):** Signal taxonomy with weights: exploit=1.0, customer_incident=0.9, threat_intel=0.7, code_change=0.4, artifact_refresh=0.3, metadata_touch=0.1. `last_signal_weighted_at` uses max(weighted timestamp).
- **Time source / drift (U4):** All timestamps in UTC; decay uses monotonic clock fallback; reject events >5 minutes in the future or >30 days backdated, log corrections.
- **Deterministic recompute (U5):** Nightly job at 03:00 UTC recomputes decay for all items; emits `decay_snapshot_YYYY-MM-DD.ndjson` with SHA256 and checksum record. On-read recompute only if snapshot is older than 24h.
- **SLA coupling (U6):** Items with active SLA clamp to `sla_floor` (0.60 Critical, 0.50 High) until SLA met. SLA flag and floor are emitted in API.
- **Uncertainty linkage (U7):** Confidence is capped by `(1 - uncertainty_score)`; if uncertainty_score ≥0.4, band forced to "under_review" and alerts fire.
- **Backfill & migration (U8):** Initial migration seeds `last_signal_at` from latest activity; default τ from entity profile; dry-run impact report required; backfill script outputs before/after bands.
- **API/UX surfacing (U9):** New fields: `confidence`, `confidence_band` (critical/high/medium/low/under_review), `tau_days`, `is_frozen`, `confidence_floor`, `uncertainty_score`, `last_signal_weighted_at`. Sort default: `priority * confidence`.
- **Observability & alerts (U10):** Counters/gauges: `confidence_recalc_latency`, `items_below_floor`, `signals_weighted_by_type{type}`, `decay_snapshots_age_hours`, `uncertainty_forced_under_review`. Alerts on missing nightly snapshot, decay drift >1 band, or SLA items below floor.
## Reference Config (draft)
```yaml
version: 1
updated_at: 2025-12-01T00:00:00Z
entities:
vulnerability:
tau_days: 21
tau_min: 7
tau_max: 90
confidence_floor: {critical: 0.60, high: 0.45, medium: 0.30, low: 0.20}
sla_floor: {critical: 0.60, high: 0.50}
freeze_default_days: 30
incident:
tau_days: 14
tau_min: 3
tau_max: 60
signals_taxonomy:
exploit: 1.0
customer_incident: 0.9
threat_intel: 0.7
code_change: 0.4
artifact_refresh: 0.3
metadata_touch: 0.1
time:
reject_future_minutes: 5
reject_backdated_days: 30
recompute:
schedule_utc: "03:00"
snapshot_retention_days: 30
observability:
alerts:
missing_snapshot_hours: 26
sla_floor_breach: true
uncertainty_band_force: 0.4
signing:
predicate: stella.ops/confidenceDecayConfig@v1
dsse_required: true
```
## Operational Rules
- Config changes must produce a new DSSE envelope and update the checksum in the nightly snapshot header.
- Nightly job writes `decay_snapshot_<date>.ndjson` (sorted by `item_id`) plus `SHA256SUMS`; both stored in Evidence Locker.
- Any on-read recompute must emit an audit log with reasons (stale snapshot or forced recalculation).
## Migration Playbook
1) Run dry-run backfill: compute bands with proposed config; write `decay_backfill_diff.ndjson` (before/after bands, delta) and checksum.
2) Get dual approval; sign `confidence_decay_config.yaml` with DSSE predicate above.
3) Apply config, execute full recompute, publish snapshot + checksums, update observability dashboard baselines.
## API Notes
- Add fields to Signals API and CLI responses; ensure canonical serialization (sorted keys, UTC timestamps, fixed decimals 3dp) to avoid hash drift.
- Bands map: `>=0.75 critical`, `>=0.55 high`, `>=0.35 medium`, `>=0.20 low`, else `under_review`.
## Evidence & Storage
- Store config DSSE, snapshots, and backfill reports in Evidence Locker with retention class `signals-decay-config`.
- For offline kits, include latest config DSSE + last 3 snapshots and checksums.
## Open Items for Review (12-03)
- Confirm weights for threat_intel vs exploit; adjust if customer data suggests different ordering.
- Confirm `under_review` threshold (currently uncertainty ≥0.4).
- Align with Policy on SLA floors for High severity (0.50 proposed).

View File

@@ -0,0 +1,41 @@
version: 1
updated_at: 2025-12-01T00:00:00Z
entities:
vulnerability:
tau_days: 21
tau_min: 7
tau_max: 90
confidence_floor:
critical: 0.60
high: 0.45
medium: 0.30
low: 0.20
sla_floor:
critical: 0.60
high: 0.50
freeze_default_days: 30
incident:
tau_days: 14
tau_min: 3
tau_max: 60
signals_taxonomy:
exploit: 1.0
customer_incident: 0.9
threat_intel: 0.7
code_change: 0.4
artifact_refresh: 0.3
metadata_touch: 0.1
time:
reject_future_minutes: 5
reject_backdated_days: 30
recompute:
schedule_utc: "03:00"
snapshot_retention_days: 30
observability:
alerts:
missing_snapshot_hours: 26
sla_floor_breach: true
uncertainty_band_force: 0.4
signing:
predicate: stella.ops/confidenceDecayConfig@v1
dsse_required: true

View File

@@ -0,0 +1,66 @@
# Signals Heuristic Catalog · Deterministic Scoring
**Compiled:** 2025-12-01 (UTC)
**Scope:** Close UT1UT10 gaps from `docs/product-advisories/31-Nov-2025 FINDINGS.md` by publishing a signed heuristic catalog and golden outputs.
**Status:** Draft; target publish 2025-12-05 with DSSE signature.
## Decisions (UT1UT10)
- **Signed catalog/schema (UT1):** Catalog lives at `heuristics.catalog.json` with schema versioned `heuristics.schema.json`; DSSE predicate `stella.ops/heuristicCatalog@v1` required.
- **Deterministic scoring formula (UT2):** Each heuristic defines `inputs`, `weights`, and `normalization`; scoring outputs canonicalized (sorted keys, fixed 3dp). Engine must be pure/deterministic; randomization forbidden.
- **Quality bands (UT3):** Bands: `gold` (precision≥0.9, recall≥0.8), `silver` (≥0.8/0.7), `bronze` (≥0.7/0.6). Bands recorded in catalog and enforced in admission checks.
- **Waiver policy with DSSE (UT4):** Waivers require DSSE envelope `stella.ops/heuristicWaiver@v1`, include reason, scope, expiry; dual approval (Signals+Policy).
- **SLA coupling (UT5):** SLA-tagged items cannot use heuristics below `silver`; SLA enforcement checks band before accepting results.
- **Offline kit packaging (UT6):** Catalog, schema, golden fixtures, and DSSE envelopes bundled in offline kits with `SHA256SUMS`.
- **Observability/alerts (UT7):** Metrics: `heuristics_eval_latency`, `heuristics_band_usage`, `heuristics_waivers_total`, `heuristics_score_drift`. Alerts when drift >1 band vs golden fixtures or when waivers exceed threshold.
- **Backfill plan (UT8):** Backfill job recomputes heuristic scores with current catalog; outputs `heuristics_backfill.ndjson` + checksum; mismatches raise alerts.
- **Explainability fields/exports (UT9):** Outputs must include `explanation` block: contributing signals with weights, normalized scores, and rule IDs. CLI/API export supports `--explain` and deterministic ordering.
- **Fixtures with golden outputs (UT10):** Golden set per heuristic under `fixtures/<heuristic>/` containing `input.json`, `expected.json`, and `README`; used in CI for determinism.
## Catalog Structure (draft)
```json
{
"version": "1.0.0",
"updatedAt": "2025-12-01T00:00:00Z",
"heuristics": [
{
"id": "heur.callgraph.hotpath",
"band": "gold",
"inputs": ["callgraph.depth", "callgraph.betweenness"],
"formula": "0.6*depth_norm + 0.4*betweenness_norm",
"normalization": "minmax",
"evidence": ["signals/callgraph"]
},
{
"id": "heur.pkg.sbom_age",
"band": "silver",
"inputs": ["sbom.age_days", "release_channel"],
"formula": "if release_channel=='stable' then age_norm else 0.8*age_norm",
"normalization": "log1p"
}
],
"signing": {
"predicate": "stella.ops/heuristicCatalog@v1",
"dsse_required": true
}
}
```
## Golden Fixtures (layout)
- `docs/modules/signals/heuristics/fixtures/heur.callgraph.hotpath/{input.json,expected.json}`
- `docs/modules/signals/heuristics/fixtures/heur.pkg.sbom_age/{input.json,expected.json}`
- `expected.json` must be canonicalized (sorted keys, fixed 3dp) and include explanation block.
## CI / Determinism Checks
- Lint: reject heuristics without band or DSSE signature.
- Determinism test: run golden fixtures; fail if output hash differs.
- Drift alert: compare live scores vs golden baselines; trigger if >1 band difference for same input hash.
## Publish Steps (12-05)
1) Finalize catalog + schema; canonicalize via JCS; sign DSSE envelope.
2) Populate fixtures and compute `SHA256SUMS` for all files.
3) Update sprint doc status and Evidence Locker with catalog + fixtures + signatures.
4) Enable observability dashboards and waiver policy checks.
## Open Items
- Confirm minimum band allowed for non-SLA items (proposal: bronze acceptable, but not for SLA).
- Decide on additional heuristics for runtime traces vs SBOM freshness.

View File

@@ -0,0 +1,16 @@
{
"heuristicId": "heur.callgraph.hotpath",
"score": 0.472,
"band": "gold",
"explanation": {
"inputs": {
"callgraph.depth": 7,
"callgraph.betweenness": 0.12
},
"normalized": {
"depth_norm": 0.700,
"betweenness_norm": 0.120
},
"formula": "0.6*depth_norm + 0.4*betweenness_norm"
}
}

View File

@@ -0,0 +1,4 @@
{
"callgraph.depth": 7,
"callgraph.betweenness": 0.12
}

View File

@@ -0,0 +1,16 @@
{
"heuristicId": "heur.pkg.sbom_age",
"score": 0.450,
"band": "silver",
"explanation": {
"inputs": {
"sbom.age_days": 45,
"release_channel": "stable"
},
"normalized": {
"age_norm": 0.450,
"release_channel": "stable"
},
"formula": "case release_channel=='stable' then age_norm else 0.8*age_norm"
}
}

View File

@@ -0,0 +1,4 @@
{
"sbom.age_days": 45,
"release_channel": "stable"
}

View File

@@ -0,0 +1,26 @@
{
"version": "1.0.0",
"updatedAt": "2025-12-01T00:00:00Z",
"heuristics": [
{
"id": "heur.callgraph.hotpath",
"band": "gold",
"inputs": ["callgraph.depth", "callgraph.betweenness"],
"formula": "0.6*depth_norm + 0.4*betweenness_norm",
"normalization": "minmax",
"evidence": ["signals/callgraph"]
},
{
"id": "heur.pkg.sbom_age",
"band": "silver",
"inputs": ["sbom.age_days", "release_channel"],
"formula": "case release_channel=='stable' then age_norm else 0.8*age_norm",
"normalization": "log1p",
"evidence": ["sbom/age"]
}
],
"signing": {
"predicate": "stella.ops/heuristicCatalog@v1",
"dsse_required": true
}
}

View File

@@ -0,0 +1,32 @@
{
"$id": "https://stella-ops.org/schemas/heuristics.schema.json",
"type": "object",
"required": ["version", "updatedAt", "heuristics", "signing"],
"properties": {
"version": {"type": "string"},
"updatedAt": {"type": "string", "format": "date-time"},
"heuristics": {
"type": "array",
"items": {
"type": "object",
"required": ["id", "band", "inputs", "formula", "normalization"],
"properties": {
"id": {"type": "string"},
"band": {"enum": ["gold", "silver", "bronze"]},
"inputs": {"type": "array", "items": {"type": "string"}},
"formula": {"type": "string"},
"normalization": {"type": "string"},
"evidence": {"type": "array", "items": {"type": "string"}}
}
}
},
"signing": {
"type": "object",
"required": ["predicate", "dsse_required"],
"properties": {
"predicate": {"type": "string"},
"dsse_required": {"type": "boolean"}
}
}
}
}

View File

@@ -0,0 +1,86 @@
# Unknowns Registry & Scoring Manifest
**Compiled:** 2025-12-01 (UTC)
**Scope:** Close UN1UN10 gaps from `docs/product-advisories/31-Nov-2025 FINDINGS.md` for Unknowns Registry.
**Status:** Draft; review 2025-12-04; DSSE signing required before adoption.
## Decisions (UN1UN10)
- **Canonical schema/enums (UN1):** Unknown types: `vulnerability`, `asset`, `signal`, `evidence-gap`, `policy-gap`. Status enums: `new`, `triaging`, `under_review`, `validated`, `dismissed`. Severity: `critical/high/medium/low/none`.
- **Deterministic scoring manifest (UN2):** Manifest `unknowns_scoring_manifest.json` defines inputs, weights, and canonical serialization (JCS, sorted keys, UTC timestamps, fixed 3dp). Hash used as `scoringManifestHash` in API/DSSE.
- **Decay policy catalog (UN3):** Unknowns reuse `confidence_decay_config` but may override τ by type (see table). Overrides stored in manifest; DSSE-signed.
- **Evidence/provenance capture (UN4):** Each unknown must reference Evidence Locker URIs with DSSE envelopes; minimal evidence: `{source, observedAt, evidenceType, hash}`. Provenance includes tool identity and policy hash.
- **SBOM/VEX linkage (UN5):** Unknown links: `sbomDigest`, `vexDecisionId` (if present), `reachabilityGraphHash`. If absent, status forced to `under_review`.
- **SLA / suppression rules (UN6):** SLA timers mirror severity; suppression requires dual sign-off and DSSE note with expiry. Suppressed items emit `suppression_reason`, `expiresAt`.
- **API/CLI contracts (UN7):** New endpoints `/unknowns` support filter by `status`, `type`, `confidence_band`, `uncertainty_score`, `suppressed`. CLI mirrors with `--format ndjson` and `--include-provenance` flags. Output sorted deterministically by `createdAt, id`.
- **Observability/reporting (UN8):** Metrics: `unknowns_total{type,status}`, `unknowns_suppressed_total`, `unknowns_without_sbom`, `unknowns_without_vex`, `unknowns_confidence_band`, `unknowns_manifest_hash_mismatch`. Alerts on manifest hash mismatch, >1% unknowns missing SBOM/VEX, or suppression expiry.
- **Offline bundle inclusion (UN9):** Include latest manifest, schema, and NDJSON export in offline kit; bundle hashes recorded in kit manifest; verify against DSSE signatures.
- **Migration/backfill (UN10):** Backfill script `backfill_unknowns_v1` seeds `scoringManifestHash`, `sbomDigest`, and `vexDecisionId` from existing records; produces `unknowns_backfill_report.ndjson` with before/after status/bands and checksum.
## Schema (draft)
```json
{
"$id": "https://stella-ops.org/schemas/unknown.json",
"type": "object",
"required": ["id", "type", "status", "severity", "createdAt", "confidence", "confidenceBand"],
"properties": {
"id": {"type": "string"},
"type": {"enum": ["vulnerability", "asset", "signal", "evidence-gap", "policy-gap"]},
"status": {"enum": ["new", "triaging", "under_review", "validated", "dismissed"]},
"severity": {"enum": ["critical", "high", "medium", "low", "none"]},
"confidence": {"type": "number"},
"confidenceBand": {"enum": ["critical", "high", "medium", "low", "under_review"]},
"uncertaintyScore": {"type": "number", "minimum": 0, "maximum": 1},
"tauDays": {"type": "integer"},
"sbomDigest": {"type": "string"},
"vexDecisionId": {"type": "string"},
"reachabilityGraphHash": {"type": "string"},
"scoringManifestHash": {"type": "string"},
"suppression": {
"type": "object",
"properties": {
"isSuppressed": {"type": "boolean"},
"reason": {"type": "string"},
"expiresAt": {"type": "string", "format": "date-time"},
"signedBy": {"type": "string"}
}
},
"evidence": {"type": "array", "items": {"$ref": "#/definitions/evidenceRef"}},
"createdAt": {"type": "string", "format": "date-time"},
"updatedAt": {"type": "string", "format": "date-time"}
},
"definitions": {
"evidenceRef": {
"type": "object",
"required": ["uri", "hash", "observedAt", "evidenceType"],
"properties": {
"uri": {"type": "string"},
"hash": {"type": "string"},
"observedAt": {"type": "string", "format": "date-time"},
"evidenceType": {"type": "string"},
"provenance": {"type": "string"}
}
}
}
}
```
## Scoring Manifest (summary)
- Inputs: severity weight, decay factor (τ), uncertainty cap, SLA floor, suppression flag, weighted signals timestamp.
- Formula (deterministic): `confidence = max(floor, min((exp(-Δt/τ) * weight_signal), 1 - uncertainty))`, then clamp by SLA floor if SLA active.
- Canonicalization: JSON Canonicalization Scheme (JCS); decimals fixed 3dp; UTC ISO-8601 timestamps.
- Hash: SHA256 over canonical manifest; published as `scoringManifestHash` and signed via DSSE `stella.ops/unknownsScoringManifest@v1`.
## Offline & Evidence
- Bundle schema, manifest, and latest NDJSON export with `SHA256SUMS` and DSSE envelope for each artifact.
- Evidence Locker class: `signals-unknowns-manifest` (30d retention minimum).
## Migration Checklist (UN10)
1) Generate `unknowns_scoring_manifest.json` and sign (DSSE).
2) Run `backfill_unknowns_v1 --manifest <hash>`; produce report and checksums.
3) Update API/CLI serializers to include new fields and canonical ordering.
4) Enable observability dashboards and alerts; verify thresholds.
## Review Questions (12-04)
- Confirm suppression expiry default (proposal: 30 days).
- Validate `under_review` trigger when SBOM/VEX missing—keep or allow grace period?
- Align SLA floors with decay config (Critical 0.60, High 0.50).

View File

@@ -0,0 +1,48 @@
{
"version": "1.0.0",
"updatedAt": "2025-12-01T00:00:00Z",
"canonicalization": {
"scheme": "JCS",
"decimals": 3,
"timezone": "UTC"
},
"inputs": {
"severityWeight": {
"critical": 1.0,
"high": 0.8,
"medium": 0.6,
"low": 0.4,
"none": 0.2
},
"uncertaintyCap": 1.0,
"slaFloor": {
"critical": 0.60,
"high": 0.50
},
"tauOverrides": {
"vulnerability": 21,
"asset": 28,
"signal": 14,
"evidence-gap": 21,
"policy-gap": 30
}
},
"formula": "confidence = max(floor, min(exp(-deltaDays/tau) * severityWeight, 1 - uncertainty))",
"floor": 0.20,
"uncertaintyThreshold": 0.4,
"bands": {
"critical": 0.75,
"high": 0.55,
"medium": 0.35,
"low": 0.20,
"under_review": 0.0
},
"hash": {
"algorithm": "SHA-256",
"value": "TO_BE_SIGNED"
},
"signing": {
"predicate": "stella.ops/unknownsScoringManifest@v1",
"dsse_required": true
}
}

View File

@@ -1,7 +1,7 @@
# Telemetry agent guide
## Mission
Telemetry module captures deployment and operations guidance for the shared observability stack (collectors, storage, dashboards).
Telemetry module captures deployment and operations guidance for the shared observability stack (collectors, storage, dashboards). Telemetry outputs must be deterministic, sealed-mode safe, and verifiable via DSSE/offline bundles.
## Advisory Handling
- Any new/updated advisory triggers immediate doc + sprint updates; no approval.
@@ -16,6 +16,8 @@ Telemetry module captures deployment and operations guidance for the shared obse
- [Implementation plan](./implementation_plan.md)
- [Task board](./TASKS.md)
- [Observability runbook](./operations/observability.md) (offline import friendly)
- [Telemetry gaps remediation](./contracts/telemetry-gaps-remediation.md)
- Schemas: `./schemas/telemetry-config.schema.json`, `./schemas/telemetry-bundle.schema.json`
## How to get started
1. Open sprint file `/docs/implplan/SPRINT_*.md` and locate the stories referencing this module.

View File

@@ -0,0 +1,29 @@
# Telemetry Gap Remediation (TO1TO10) — v1 · 2025-12-01
Source: `docs/product-advisories/31-Nov-2025 FINDINGS.md` (Telemetry gaps TO1TO10).
Scope: telemetry core (collectors/SDK defaults/bundles) across services; applicable to default/forensic/airgap profiles.
## Decisions (mapped to gaps)
- **TO1 Canonical schemas & hashing**: Published versioned schemas
- `telemetry-config.schema.json` for collector/SDK profile configs (signed, canonical JSON, stable ordering)
- `telemetry-bundle.schema.json` for offline bundle manifests
- Hash recipe: SHA-256 over normalized (UTF-8, LF, sorted keys) JSON; test vectors to follow.
- **TO2 Provenance & DSSE**: Bundles and profile activations must include DSSE envelope (`*.dsse.json`) with predicate fields: profileHash, collectorVersion, exporters, redactionPolicyUri, cryptoProfile.
- **TO3 Determinism & sampling stability**: Sampling policies must declare deterministic seed, ordered rules, and backpressure policy. Logs/traces ordered by (timestamp, traceId). Multi-run hash check recommended in CI.
- **TO4 Sealed mode / egress guards**: Sealed mode blocks all non-loopback exporters unless explicitly allowlisted; DNS pinning required; failure is fail-closed. Seal status recorded as DSSE event.
- **TO5 Redaction policy & PII tests**: Redaction catalog/allowlist required; bundle must include `redaction-manifest.json` listing rules applied and violations=0. CI must run PII/secret test suite before export.
- **TO6 Tenant isolation & quotas**: OTLP signals include `tenant.id` and `project.id`; collector routes by tenant pipeline; per-tenant quotas/limits enforced with counters and alerts.
- **TO7 Forensic triggers governance**: Forensic mode requires dual approval, DSSE activation record, expiry timestamp, and auto-rollback; alert if forensic mode active > configured window.
- **TO8 Offline bundle schema & verify**: Bundles must follow `telemetry-bundle.schema.json`, created with deterministic tar flags, include hash manifest + DSSE + RFC3161 time-anchor; verifier script provided (`ops/devops/telemetry/verify-telemetry-bundle.sh`).
- **TO9 Observability of observability**: Add SLOs + alerts for collector/exporter health, queue backpressure, bundle success rate; scheduled self-test emits DSSE result.
- **TO10 CLI/pack contracts**: CLI/pack contract tracked in `cli-spec-v1.yaml`; telemetry exports must respect exit codes and checksum policy (reuse 21/22 for checksum missing/mismatch).
## Artifacts
- Schemas: `docs/modules/telemetry/schemas/telemetry-config.schema.json`, `telemetry-bundle.schema.json`.
- Hash recipe: in-line within schemas (canonical JSON, SHA-256).
- Verify script: `ops/devops/telemetry/verify-telemetry-bundle.sh`.
## Adoption notes
- Profile and bundle producers must validate against schemas and sign DSSE envelopes before distribution.
- Air-gap/forensic profiles MUST set sealed mode and include redaction manifest.
- CI should add a multi-run hash test for telemetry exporter output and fail on drift.

View File

@@ -0,0 +1,46 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "StellaOps Telemetry Bundle Manifest",
"version": "1.0.0",
"type": "object",
"required": ["schemaVersion", "bundleId", "createdAt", "artifacts", "manifestHashAlgorithm", "timeAnchor"],
"properties": {
"schemaVersion": { "type": "string", "const": "1.0.0" },
"bundleId": { "type": "string", "format": "uuid" },
"createdAt": { "type": "string", "format": "date-time" },
"profileHash": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"collectorVersion": { "type": "string" },
"sealedMode": { "type": "boolean" },
"redactionManifest": { "type": "string" },
"manifestHashAlgorithm": { "type": "string", "enum": ["sha256"] },
"timeAnchor": {
"type": "object",
"required": ["type", "value"],
"properties": {
"type": { "type": "string", "enum": ["rfc3161", "roughtime"] },
"value": { "type": "string" }
}
},
"artifacts": {
"type": "array",
"items": {
"type": "object",
"required": ["path", "sha256", "mediaType"],
"properties": {
"path": { "type": "string" },
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"mediaType": { "type": "string" },
"size": { "type": "integer", "minimum": 0 }
}
}
},
"dsseEnvelope": {
"type": "object",
"required": ["hash"],
"properties": {
"hash": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"location": { "type": "string" }
}
}
}
}

View File

@@ -0,0 +1,75 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "StellaOps Telemetry Config",
"version": "1.0.0",
"type": "object",
"required": ["schemaVersion", "profiles"],
"properties": {
"schemaVersion": { "type": "string", "const": "1.0.0" },
"hashAlgorithm": { "type": "string", "enum": ["sha256"] },
"profiles": {
"type": "array",
"items": {
"type": "object",
"required": ["name", "collectorVersion", "exporters", "redactionPolicyUri", "sampling"],
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"collectorVersion": { "type": "string" },
"cryptoProfile": { "type": "string" },
"sealedMode": { "type": "boolean" },
"allowlistedEndpoints": {
"type": "array",
"items": { "type": "string", "format": "uri" }
},
"exporters": {
"type": "array",
"items": {
"type": "object",
"required": ["type", "endpoint"],
"properties": {
"type": { "type": "string", "enum": ["otlp", "file", "stdout", "null"] },
"endpoint": { "type": "string" },
"protocol": { "type": "string", "enum": ["grpc", "http"] },
"compression": { "type": "string", "enum": ["none", "gzip"] },
"enabled": { "type": "boolean", "default": true }
}
}
},
"redactionPolicyUri": { "type": "string", "format": "uri" },
"sampling": {
"type": "object",
"required": ["strategy", "seed"],
"properties": {
"strategy": { "type": "string", "enum": ["always_on", "always_off", "traceidratio", "tail"] },
"seed": { "type": "string", "pattern": "^[0-9a-fA-F]{16}$" },
"rules": {
"type": "array",
"items": {
"type": "object",
"required": ["match", "priority"],
"properties": {
"match": { "type": "string" },
"priority": { "type": "integer", "minimum": 0 },
"sampleRate": { "type": "number", "minimum": 0, "maximum": 1 }
}
}
}
}
},
"tenantRouting": {
"type": "object",
"required": ["attribute"],
"properties": {
"attribute": { "type": "string", "const": "tenant.id" },
"quotasPerTenant": {
"type": "object",
"additionalProperties": { "type": "integer", "minimum": 0 }
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,224 @@
# DSSESigned Offline Scanner Updates — Developer Guidelines
> **Date:** 2025-12-01
> **Status:** Advisory draft (from user-provided guidance)
> **Scope:** Offline vulnerability DB bundles (Scanner), DSSE+Rekor v2 verification, offline kit alignment, activation rules, ops playbook.
Heres a tight, practical pattern to make your scanners vulnDB updates rocksolid even when feeds hiccup:
## Offline, verifiable update bundles (DSSE + Rekor v2)
**Idea:** distribute DB updates as offline tarballs. Each tarball ships with:
* a **DSSEsigned** statement (e.g., intoto style) over the bundle hash
* a **Rekor v2 receipt** proving the signature/statement was logged
* a small **manifest.json** (version, created_at, content hashes)
**Startup flow (happy path):**
1. Load latest tarball from your local `updates/` cache.
2. Verify DSSE signature against your trusted public keys.
3. Verify Rekor v2 receipt (inclusion proof) matches the DSSE payload hash.
4. If both pass, unpack/activate; record the bundles **trust_id** (e.g., statement digest).
5. If anything fails, **keep using the last good bundle**. No service disruption.
**Why this helps**
* **Airgap friendly:** no live network needed at activation time.
* **Tamperevident:** DSSE + Rekor receipt proves provenance and transparency.
* **Operational stability:** feed outages become nonevents—scanner just keeps the last good state.
---
## File layout inside each bundle
```
/bundle-2025-11-29/
manifest.json # { version, created_at, entries[], sha256s }
payload.tar.zst # the actual DB/indices
payload.tar.zst.sha256
statement.dsse.json # DSSE-wrapped statement over payload hash
rekor-receipt.json # Rekor v2 inclusion/verification material
```
---
## Acceptance/Activation rules
* **Trust root:** pin one (or more) publisher public keys; rotate via separate, outofband process.
* **Monotonicity:** only activate if `manifest.version > current.version` (or if trust policy explicitly allows replay for rollback testing).
* **Atomic switch:** unpack to `db/staging/`, validate, then symlinkflip to `db/active/`.
* **Quarantine on failure:** move bad bundles to `updates/quarantine/` with a reason code.
---
## Minimal .NET 10 verifier sketch (C#)
```csharp
public sealed record BundlePaths(string Dir) {
public string Manifest => Path.Combine(Dir, "manifest.json");
public string Payload => Path.Combine(Dir, "payload.tar.zst");
public string Dsse => Path.Combine(Dir, "statement.dsse.json");
public string Receipt => Path.Combine(Dir, "rekor-receipt.json");
}
public async Task<bool> ActivateBundleAsync(BundlePaths b, TrustConfig trust, string activeDir) {
var manifest = await Manifest.LoadAsync(b.Manifest);
if (!await Hashes.VerifyAsync(b.Payload, manifest.PayloadSha256)) return false;
// 1) DSSE verify (publisher keys pinned in trust)
var (okSig, dssePayloadDigest) = await Dsse.VerifyAsync(b.Dsse, trust.PublisherKeys);
if (!okSig || dssePayloadDigest != manifest.PayloadSha256) return false;
// 2) Rekor v2 receipt verify (inclusion + statement digest == dssePayloadDigest)
if (!await RekorV2.VerifyReceiptAsync(b.Receipt, dssePayloadDigest, trust.RekorPub)) return false;
// 3) Stage, validate, then atomically flip
var staging = Path.Combine(activeDir, "..", "staging");
DirUtil.Empty(staging);
await TarZstd.ExtractAsync(b.Payload, staging);
if (!await LocalDbSelfCheck.RunAsync(staging)) return false;
SymlinkUtil.AtomicSwap(source: staging, target: activeDir);
State.WriteLastGood(manifest.Version, dssePayloadDigest);
return true;
}
```
---
## Operational playbook
* **On boot & daily at HH:MM:** try `ActivateBundleAsync()` on the newest bundle; on failure, log and continue.
* **Telemetry (no PII):** reason codes (SIG_FAIL, RECEIPT_FAIL, HASH_MISMATCH, SELFTEST_FAIL), versions, last_good.
* **Keys & rotation:** keep `publisher.pub` and `rekor.pub` in a rootowned, readonly path; rotate via a separate signed “trust bundle”.
* **Defenseindepth:** verify both the **payload hash** and each files hash listed in `manifest.entries[]`.
* **Rollback:** allow `--force-activate <bundle>` for emergency testing, but mark as **nonmonotonic** in state.
---
## What to hand your release team
* A Make/CI target that:
1. Builds `payload.tar.zst` and computes hashes
2. Generates `manifest.json`
3. Creates and signs the **DSSE statement**
4. Submits to Rekor (or your mirror) and saves the **v2 receipt**
5. Packages the bundle folder and publishes to your offline repo
* A checksum file (`*.sha256sum`) for ops to verify outofband.
---
If you want, I can turn this into a StellaOps spec page (`docs/modules/scanner/offline-bundles.md`) plus a small reference implementation (C# library + CLI) that drops right into your Scanner service.
---
# Dropin Stella Ops Dev Guide (seed for `docs/modules/scanner/development/dsse-offline-updates.md`)
> **Audience**
> Scanner, Export Center, Attestor, CLI, and DevOps engineers implementing DSSEsigned offline vulnerability updates and integrating them into the Offline Update Kit (OUK).
>
> **Context**
>
> * OUK already ships **signed, atomic offline update bundles** with merged vulnerability feeds, container images, and an attested manifest.
> * DSSE + Rekor is already used for **scan evidence** (SBOM attestations, Rekor proofs).
> * Sprints 160/162 add **attestation bundles** with manifest, checksums, DSSE signature, and optional transparency log segments, and integrate them into OUK and CLI flows.
These guidelines tell you how to **wire all of that together** for “offline scanner updates” (feeds, rules, packs) in a way that matches Stella Ops determinism + sovereignty promises.
## 0. Mental model
```text
Advisory mirrors / Feeds builders
ExportCenter.AttestationBundles
(creates DSSE + Rekor evidence
for each offline update snapshot)
Offline Update Kit (OUK) builder
(adds feeds + evidence to kit tarball)
stella offline kit import / admin CLI
(verifies Cosign + DSSE + Rekor segments,
then atomically swaps scanner feeds)
```
Online, Rekor is live; offline, you rely on **bundled Rekor segments / snapshots** and the existing OUK mechanics (import is atomic, old feeds kept until new bundle is fully verified).
## 1. Goals & nongoals
### Goals
1. **Authentic offline snapshots**: every offline scanner update (OUK or delta) must be verifiably tied to a DSSE envelope, a certificate chain, and a Rekor v2 inclusion proof or bundled log segment.
2. **Deterministic replay**: given a kit + its DSSE attestation bundle, every verifier reaches the same verdict online or airgapped.
3. **Separation of concerns**: Export Center builds attestations; Scanner verifies/imports; Signer/Attestor handle DSSE/Rekor.
4. **Operational safety**: imports remain atomic/idempotent; old feeds stay live until full verification.
### Nongoals
* Designing new crypto or log formats.
* Perfeed DSSE envelopes (minimum contract is bundlelevel attestation).
## 2. Bundle contract for DSSEsigned offline updates
**Files to ship** (inside each offline kit or delta):
```
/attestations/
offline-update.dsse.json # DSSE envelope
offline-update.rekor.json # Rekor entry + inclusion proof (or segment descriptor)
/manifest/
offline-manifest.json # existing manifest
offline-manifest.json.jws # existing detached JWS
/feeds/
... # existing feed payloads
```
**DSSE payload (minimum):** subject = kit name + tarball sha256; predicate fields include `offline_manifest_sha256`, feed entries, builder ID/commit, created_at UTC, and channel.
**Rekor material:** submit DSSE to Rekor v2, store UUID/logIndex/inclusion proof as `offline-update.rekor.json`; for offline, embed a minimal log segment or rely on mirrored snapshots.
## 3. Implementation by module
### Export Center — attestation bundles
* Compose attestation job: build DSSE payload, sign via Signer, submit to Rekor via Attestor, persist `offline-update.dsse.json` and `.rekor.json` (+ segments).
* Integrate into offline kit packaging: place attestation files under `/attestations/`; list them in `offline-manifest.json` with sha256/size/capturedAt.
* Define JSON schema for `offline-update.rekor.json`; version it and validate.
### Offline Update Kit builder
* Preserve idempotent, atomic imports; include DSSE/Rekor files in kit staging tree.
* Keep manifests deterministic: ordered file lists, UTC timestamps.
* For delta kits, attest the resulting snapshot state (not just diffs).
### Scanner — import & activation
* Verification sequence: Cosign tarball → manifest JWS → file digests (incl. attestation files) → DSSE verify → Rekor verify (online or offline segment) → atomic swap.
* Config surface: `requireDsse`, `rekorOfflineMode`, `attestationVerifier` (env-var mirrored); allow observe→enforce rollout.
* Failure behavior: keep old feeds; log structured failure fields; expose ProblemDetails.
### Signer & Attestor
* Add predicate type/schema for offline updates; submit DSSE to Rekor; emit verification routines usable by CLI/Scanner with offline snapshot support.
### CLI & UI
* CLI verbs to verify/import bundles with Rekor key; UI shows Cosign/JWS + DSSE/Rekor status and kit freshness.
## 4. Determinism & offlinesafety rules
* No hidden network dependencies; offline must succeed with kit + Rekor snapshot.
* Stable JSON serialization; UTC timestamps.
* Replayable imports (idempotent); DSSE payload for a snapshot must be immutable.
* Explainable failures with precise mismatch points.
## 5. Testing & CI expectations
* Unit/integration: happy path, tampering cases (manifest/DSSE/Rekor), offline mode, rollback logic.
* Metrics: `offlinekit_import_total{status}`, `attestation_verify_latency_seconds`, Rekor success/retry counts.
* Golden fixtures: deterministic bundle + snapshot tests.
## 6. Developer checklist (TL;DR)
1. Read operator guides: `docs/modules/scanner/operations/dsse-rekor-operator-guide.md`, `docs/24_OFFLINE_KIT.md`, relevant sprints.
2. Implement: generate DSSE in Export Center; include attestation in kit; Scanner verifies before swap.
3. Test: bundle composition, import rollback, determinism.
4. Telemetry: counters + latency; log digests/UUIDs.
5. Document: update Export Center and Scanner architecture docs, OUK docs when flows/contracts change.

View File

@@ -0,0 +1,130 @@
# Proof-Linked VEX UI Developer Guidelines
Compiled: 2025-12-01 (UTC)
## Purpose
Any VEX-influenced verdict a user sees (Findings, Advisories & VEX, Vuln Explorer, etc.) must be directly traceable to concrete evidence: normalized VEX claims, their DSSE/signatures, and the policy explain trace. Every "Not Affected" badge is a verifiable link to the proof.
## What this solves (in one line)
Every "Not Affected" badge becomes a verifiable link to why it is safe.
## UX pattern (at a glance)
- Badge: `Not Affected` (green pill) always renders as a link.
- On click: open a right-side drawer with three tabs:
1. Evidence (DSSE / in-toto / Sigstore)
2. Attestation (predicate details + signer)
3. Reasoning Graph (the node + edges that justify the verdict)
- Hover state: mini popover showing proof types available (e.g., "DSSE, SLSA attestation, Graph node").
## Data model (API & DB)
Canonical object returned by VEX API for each finding:
```json
{
"findingId": "vuln:CVE-2024-12345@pkg:docker/alpine@3.19",
"status": "not_affected",
"justificationCode": "vex:not_present",
"proof": {
"dsse": {
"envelopeDigest": "sha256-…",
"rekorEntryId": "e3f1…",
"downloadUrl": "https://…/dsse/e3f1…",
"signer": { "name": "StellaOps Authority", "keyId": "SHA256:…" }
},
"attestation": {
"predicateType": "slsa/v1",
"attestationId": "att:01H…",
"downloadUrl": "https://…/att/01H…"
},
"graph": {
"nodeId": "gx:NA-78f…",
"revision": "gx-r:2025-11-30T12:01:22Z",
"explainUrl": "https://…/graph?rev=gx-r:…&node=NA-78f…"
}
},
"receipt": {
"algorithm": "CVSS:4.0",
"inputsHash": "sha256-…",
"computedAt": "2025-11-30T12:01:22Z"
}
}
```
Suggested Postgres tables:
- vex_findings(finding_id, status, justification_code, graph_node_id, graph_rev, dsse_digest, rekor_id, attestation_id, created_at, updated_at)
- proof_artifacts(id, type, digest, url, signer_keyid, meta jsonb)
- graph_revisions(revision_id, created_at, root_hash)
## API contract (minimal)
- GET /vex/findings/:id -> returns the object above.
- GET /proofs/:type/:id -> streams artifact (with Content-Disposition: attachment).
- GET /graph/explain?rev=…&node=… -> returns a JSON justification subgraph.
- Security headers: Content-SHA256, Digest, X-Proof-Root (graph root hash), and X-Signer-KeyId.
## Angular UI spec (drop-in)
Component: FindingStatusBadge
```html
<button class="badge badge--ok" (click)="drawer.open(finding.proof)">
Not Affected
</button>
```
Drawer layout (3 tabs):
1) Evidence
- DSSE digest (copy button)
- Rekor entry (open in new tab)
- "Download envelope"
2) Attestation
- Predicate type
- Attestation ID
- "Download attestation"
3) Reasoning Graph
- Node ID + Revision
- Inline explainer ("Why safe?" bullets)
- "Open full graph" (routes to /graph?rev=…&node=…)
Micro-interactions:
- Copy-to-clipboard with toast ("Digest copied").
- If any artifact missing, show a yellow "Partial Proof" ribbon listing what is absent.
Visual language:
- Badges: Not Affected = solid green; Partial Proof = olive with warning dot; No Proof = gray outline (still clickable, explains absence).
- Proof chips: small caps labels `DSSE`, `ATTESTATION`, `GRAPH`; each chip opens its subsection.
Validation (trust & integrity):
- On drawer open, the UI calls HEAD /proofs/... to fetch Digest header and X-Proof-Root; compare to stored digests. If mismatch, show red "Integrity Mismatch" banner with retry and report.
Telemetry (debugging):
- Emit events: proof_drawer_opened, proof_artifact_downloaded, graph_explain_viewed (include findingId, artifactType, latencyMs, integrityStatus).
Developer checklist:
- Every not_affected status must include at least one proof artifact.
- Badge is never a dead label; always clickable.
- Drawer validates artifact digests before rendering contents.
- "Open full graph" deep-links with rev + node (stable and shareable).
- Graceful partials: show what is present and what is missing.
- Accessibility: focus trap in drawer, aria-labels for chips, keyboard nav.
Test cases (quick):
1) Happy path: all three proofs present; digests match; downloads work.
2) Partial proof: DSSE present, attestation missing; drawer shows warning ribbon.
3) Integrity fail: server returns different digest; red banner appears; badge stays clickable.
4) Graph only: reasoning node present; DSSE/attestation absent; explains rationale clearly.
Optional nice-to-haves:
- Permalinks: copyable URL that re-opens the drawer to the same tab.
- QR export: downloadable "proof card" PNG with digests + signer (for audit packets).
- Offline kit: bundle DSSE, attestation, and a compact graph slice in a .tar.zst for air-gapped review.
If needed, this can be turned into:
- A small Angular module (ProofDrawerModule) + styles.
- A .NET 10 controller stub with integrity headers.
- Fixture JSON so teams can wire it up quickly.
## Context links (from source conversation)
- docs/ui/console-overview.md
- docs/ui/advisories-and-vex.md
- docs/ui/findings.md
- src/VexLens/StellaOps.VexLens/AGENTS.md and TASKS.md
- docs/policy/overview.md

View File

@@ -0,0 +1,95 @@
# 01-Dec-2025 - Storage Blueprint for PostgreSQL Modules
## Summary
A crisp, opinionated storage blueprint for StellaOps modules with zero-downtime conversion tactics. Covers module-to-store mapping, PostgreSQL patterns, JSONB/RLS scaffolds, materialized views, temporal tables, CAS usage for SBOM/VEX blobs, and phased cutover guidance.
## Module → Store Map (deterministic by default)
- **Authority / OAuth / Accounts & Audit**: PostgreSQL source of truth; tables `users`, `clients`, `oauth_tokens`, `roles`, `grants`, `audit_log`; RLS on `users`, `grants`, `audit_log`; strict FK/CHECK; immutable UUID PKs; audit table with actor/action/entity/diff and timestamptz default now().
- **VEX & Vulnerability Writes**: PostgreSQL with JSONB facts plus relational decisions; tables `vuln_fact(jsonb)`, `vex_decision(package_id, vuln_id, status, rationale, proof_ref, updated_at)`; materialized views like `mv_triage_hotset` refreshed on commit or schedule.
- **Routing / Feature Flags / Rate-limits**: PostgreSQL truth plus Redis cache; tables `feature_flag(key, rules jsonb, version)`, `route(domain, service, instance_id, last_heartbeat)`, `rate_limiter(bucket, quota, interval)`; Redis keys `flag:{key}:{version}`, `route:{domain}`, `rl:{bucket}` with short TTLs.
- **Unknowns Registry**: PostgreSQL with temporal tables (bitemporal via `valid_from/valid_to`, `sys_from/ sys_to`); view `unknowns_current` for open rows.
- **Artifacts / SBOM / VEX files**: OCI-compatible CAS (e.g., self-hosted registry or MinIO) keyed by digest; metadata in Postgres `artifact_index(digest, media_type, size, signatures)`.
## PostgreSQL Implementation Essentials
- **RLS scaffold (Authority)**
```sql
alter table audit_log enable row level security;
create policy p_audit_read_self
on audit_log for select
using (
actor_id = current_setting('app.user_id')::uuid
or exists (
select 1 from grants g
where g.user_id = current_setting('app.user_id')::uuid
and g.role = 'auditor'
)
);
```
- **JSONB facts + relational decisions**
```sql
create table vuln_fact (
id uuid primary key default gen_random_uuid(),
source text not null,
payload jsonb not null,
received_at timestamptz default now()
);
create table vex_decision (
package_id uuid not null,
vuln_id text not null,
status text check (status in ('not_affected','affected','fixed','under_investigation')),
rationale text,
proof_ref text,
decided_at timestamptz default now(),
primary key (package_id, vuln_id)
);
```
- **Materialized view for triage**
```sql
create materialized view mv_triage_hotset as
select v.id as fact_id, v.payload->>'vuln' as vuln, v.received_at
from vuln_fact v
where (now() - v.received_at) < interval '7 days';
-- refresh concurrently via job
```
- **Temporal pattern (Unknowns)**
```sql
create table unknowns (
id uuid primary key default gen_random_uuid(),
subject_hash text not null,
kind text not null,
context jsonb not null,
valid_from timestamptz not null default now(),
valid_to timestamptz,
sys_from timestamptz not null default now(),
sys_to timestamptz
);
create view unknowns_current as
select * from unknowns where valid_to is null;
```
## Conversion (not migration): zero-downtime, prototype-friendly
1. Encode Mongo-shaped docs into JSONB with versioned schemas and forward-compatible projection views.
2. Outbox pattern for exactly-once side-effects (`outbox(id, topic, key, payload jsonb, created_at, dispatched bool default false)`).
3. Parallel read adapters behind feature flags with read-diff monitoring.
4. CDC for analytics without coupling (logical replication).
5. Materialized views with fixed refresh cadence; cold-path analytics in separate schemas.
6. Phased cutover playbook: Dark Read → Shadow Serve → Authoritative → Retire (with auto-rollback).
## Rate-limits & Flags: single truth, fast edges
- Truth in Postgres with versioned flag docs; history table for changes; Redis edge cache keyed by version; rate-limit quotas in Postgres, counters in Redis with reconciliation jobs.
## CAS for SBOM/VEX/attestations
- Store blobs in OCI/MinIO by digest; keep pointer metadata in Postgres `artifact_index`; benefits: immutability, dedup, easy offline mirroring.
## Guardrails
- Wrap multi-table writes in single transactions; prefer `jsonb_path_query` for targeted reads; enforce RLS and least-privilege roles; version everything (schemas, flags, materialized views); expose observability for statements, MV refresh latency, outbox lag, Redis hit ratio, and RLS hits.
## Optional Next Steps (from advisory)
- Generate ready-to-run EF Core 10 migrations.
- Add `/docs/architecture/store-map.md` summarizing these patterns.
- Provide a small Docker-based dev seed with sample data.

View File

@@ -0,0 +1,38 @@
# Verifiable Proof Spine: Receipts + Benchmarks
Compiled: 2025-12-01 (UTC)
## Why this matters
Move from “trust the scanner” to “prove every verdict.” Each finding and every “not affected” claim must carry cryptographic, replayable evidence that anyone can verify offline or online.
## Differentiators to build in
- **Graph Revision ID on every verdict**: stable Merkle root over SBOM nodes/edges, policies, feeds, scan params, and tool versions. Any data change → new graph hash → new revisioned verdicts; surface the ID in UI/API.
- **Machine-verifiable receipts (DSSE)**: emit a DSSE-wrapped in-toto statement per verdict (predicate `stellaops.dev/verdict@v1`) including graphRevisionId, artifact digests, rule id/version, inputs, and timestamps; sign with Authority keys (offline mode supported) and keep receipts queryable/exportable; mirror to Rekor-compatible ledger when online.
- **Reachability evidence**: attach call-stack slices (entry→sink, symbols, file:line) for code-level cases; for binaries, include symbol presence proofs (bitmap/offsets) hashed and referenced from DSSE payloads.
- **Deterministic replay manifests**: publish `replay.manifest.json` with inputs, feeds, rule/tool/container digests so auditors can recompute the same graph hash and verdicts offline.
## Benchmarks to publish (headline KPIs)
- **False-positive reduction vs baseline scanners**: run public corpus across 34 popular scanners; label ground truth once; report mean and p95 FP reduction.
- **Proof coverage**: percentage of findings/VEX items carrying valid DSSE receipts; break out reachable vs unreachable and “not affected.”
- **Triage time saved**: analyst minutes from alert to final disposition with receipts visible vs hidden; publish p50/p95 deltas.
- **Determinism stability**: re-run identical scans across nodes; publish % identical graph hashes and explain drift causes when different.
## Minimal implementation plan (week-by-week)
- **Week 1 Primitives**: add Graph Revision ID generator in scanner.webservice (Merkle over normalized SBOM+edges+policies+toolVersions); define `VerdictReceipt` schema (protobuf/JSON) and DSSE envelope types.
- **Week 2 Signing + storage**: wire DSSE signing via Authority with offline key support/rotation; persist receipts in `Receipts` table keyed by (graphRevisionId, verdictId); enable JSONL export and ledger mirror.
- **Week 3 Reachability proofs**: capture call-stack slices in reachability engine; serialize and hash; add binary symbol proof module (ELF/PE bitmap + digest) and reference from receipts.
- **Week 4 Replay + UX**: emit replay.manifest per scan (inputs, tool digests); UI shows “Verified” badge, graph hash, signature issuer, and one-click “Copy receipt”; API: `GET /verdicts/{id}/receipt`, `GET /graphs/{rev}/replay`.
- **Week 5 Benchmarks harness**: create `bench/` fixtures and runner with baseline scanner adapters, ground-truth labels, metrics export for FP%, proof coverage, triage time capture hooks.
## Developer guardrails (non-negotiable)
- **No receipt, no ship**: any surfaced verdict must carry a DSSE receipt; fail closed otherwise.
- **Schema freeze windows**: changes to rule inputs or policy logic must bump rule version and therefore graph hash.
- **Replay-first CI**: PRs touching scanning/rules must pass a replay test that reproduces prior graph hashes on gold fixtures.
- **Clock safety**: use monotonic time for receipts; include UTC wall-time separately.
## What to show buyers/auditors
- Audit kit: sample container + receipts + replay manifest + one command to reproduce the same graph hash.
- One-page benchmark readout: FP reduction, proof coverage, triage time saved (p50/p95), corpus description.
## Optional follow-ons
- Provide DSSE predicate schema, Postgres DDL for `Receipts` and `Graphs`, and a minimal .NET verification CLI (`stellaops-verify`) that replays a manifest and validates signatures.

View File

@@ -31,7 +31,7 @@
- Freeze baseline rulepacks/DBs and publish digests.
- Document sandbox and submission attestation requirements in the submission guide and CI policy.
# Findings Gaps in “Add CVSS v4.0 Score Receipts for Transparency”
# Findings Gaps in “Add CVSSv4.0 Score Receipts for Transparency”
**Requested label:** 2025-11-31 (note: November has 30 days)
@@ -550,6 +550,325 @@
- Add a ledger gaps task to a relevant sprint (e.g., reachability/policy ledger work or EvidenceLocker/export coordination) to close FL1FL10.
- Publish versioned schemas and canonical serialization; mandate Merkle/external anchor policy with freshness; enforce tenant/redaction rules; require DSSE/policy linkage; add golden fixtures, replay/rebuild verifiers, air-gap verify scripts, and quotas/backpressure.
# Findings Gaps in “DSSESigned Offline Scanner Updates — Developer Guidelines”
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** User-provided advisory DSSESigned Offline Scanner Updates Developer Guidelines (not yet in repo); cross-checked against `docs/24_OFFLINE_KIT.md`, `docs/modules/scanner/operations/dsse-rekor-operator-guide.md`, and sprints 160/162 attestation work.
**Method:** Evaluated the proposed offline bundle pattern (DSSE envelope + Rekor v2 receipt + manifest + payload) and activation flow against existing offline-kit, scanner import, attestation, and determinism/air-gap requirements. Identified missing controls, governance, and telemetry required to make the pattern enforceable and replayable.
## Gap Table
| ID | Area | Gap | Impact | Recommendation |
| -- | ---- | --- | ------ | -------------- |
| DS1 | Trust bundle rotation & revocation | Advisory pins publisher/rekor keys but omits rotation channel, expiry/NotAfter checks, or revocation response (key compromise, revoked cert, mirror drift). | Stale or compromised keys could continue to sign/verify bundles; rollback to bad keys possible in air-gaps. | Define signed trust bundle schema with key set, expiry, revocation list, and provenance; enforce NotBefore/NotAfter on activation; require quorum/M-of-N to rotate keys and store rotation receipts alongside bundles. |
| DS2 | Rekor freshness & offline proof | Verification only checks receipt vs DSSE hash; no requirement to validate the Rekor checkpoint/root, inclusion promise window, or bundled log segment authenticity. | Attackers can replay old receipts or splice receipts from another tree; air-gapped sites may trust stale proofs. | Require checkpoint verification (root hash, size, log ID) and freshness bound; when offline, bundle signed log segment + checkpoint DSSE; fail closed if segment/hash mismatches. |
| DS3 | Manifest/schema canonicalization | `manifest.json` shape/version/canonical rules are undefined; hash algo/encoding not fixed; no schema signature. | Producers/consumers may compute different digests false negatives/acceptance of tampered bundles. | Publish versioned JSON Schema with canonical ordering, SHA-256 as default, strict types; sign manifest with DSSE/JWS and include schema version in filename and trust_id. |
| DS4 | Supply-chain provenance for bundle build | Build pipeline steps (hashing, signing, Rekor submission) lack attestation/SLSA provenance; no binding to source commit, tool versions, or build runner hash. | Malicious/compromised build host could emit validly signed but malicious payloads; hard to audit. | Produce SLSA/DSSE build attestation for each bundle (builder ID, git commit, tool versions, reproducible build inputs); verify attestation before accepting bundle into cache. |
| DS5 | Anti-replay & rollback detection | Monotonicity check uses manifest.version but no binding to prior trust state or recorded trust_id; no replay window/nonce; force-activate bypass not audited. | Old bundles can be reintroduced (malicious or operator error); rollback may go unnoticed in air-gaps. | Persist last_good {version, trust_id, rekor_root} in append-only state; require version strictly increasing unless signed rollback exception; log and DSSE-sign every activation/force-activation event. |
| DS6 | Delta/partial bundle rules | Contract only shown for full bundles; deltas/partials not defined (expected final state, base hash, tombstones). | Deltas may apply on wrong base, producing diverging DB contents without detection. | Define delta schema: base_version/base_hash, operations (add/remove/replace), resulting snapshot hash; verify base before apply; generate synthetic full-hash after apply and compare to declared target. |
| DS7 | Per-file integrity & compression safety | Defense-in-depth note mentions file hashes but not mandatory verification of each entry inside `payload.tar.zst`, compression flags, or TOCTOU protection when extracting. | Tampering inside tar/zst could slip through if only outer hash is checked; extraction could overwrite symlinks or traverse directories. | Require per-entry hashes in manifest, validated before extraction; use safe extractor that rejects symlinks/`..` paths and enforces uid/gid/perm allowlist; verify zstd dictionary/levels; hash post-extract contents before swap. |
| DS8 | Config/feature flags & policy surface | `requireDsse`-style enforcement hinted but not specified across Scanner, CLI, Worker; no migration plan or policy gate. | Mixed deployments may silently skip DSSE/Rekor checks or drift from policy; inconsistent enforcement. | Add explicit config matrix (API/UI/CLI) with default `requireDsse=true`, rollout guard (`observe→enforce`), and policy gate that blocks imports lacking DSSE/Rekor unless override is signed and time-bound. |
| DS9 | Observability & SLOs | Telemetry suggests reason codes but no SLOs, alerts, or metrics for freshness, failure streaks, rollback attempts, or trust-bundle age. | Operators lack visibility; silent drift or repeated failures may persist. | Define metrics (`bundle_activate_total{reason}`, `rekor_freshness_seconds`, `trust_bundle_age_hours`, `rollback_attempt_total`), alerts on stale checkpoint/keys or repeated failures, and trace spans around verify steps; document SLOs. |
| DS10 | Recovery & quarantine governance | Quarantine step lacks retention period, evidence capture, or reprocessing flow; no checklist for operator actions or RCA evidence. | Quarantined bundles may be reintroduced without fix; root causes lost. | Require quarantine manifest (bundle hash, failure reason, logs, time, operator); set retention/SLA; add `reanalyze` job that re-verifies after trust-bundle/rekor updates; document runbook. |
| DS11 | Multi-tenant/namespace scoping | Advisory assumes single trust root/cache; no scoping for multi-tenant or env-specific feeds (prod/stage/regional crypto profiles). | Wrong bundles could be activated in other tenants/regions; policy/cert profile mismatches. | Partition cache and trust state by tenant/env/crypto profile; include tenant/profile in DSSE predicate and activation state; block activation on mismatch. |
| DS12 | Offline-kit parity & kit manifest linkage | Bundle layout is local-only; not bound to existing Offline Kit manifest/attestations; no guidance for importing via OUK or Export Center bundles. | Duplicate verification logic; kit imports may skip DSSE/Rekor or mismatch manifest coverage. | Align bundle schema with OUK: include pointers into offline-kit manifest, ensure kit contains DSSE/Rekor files, and require Scanner import to treat them as mandatory; add shared schema/docs. |
## Immediate follow-ups
- Add a gaps-remediation task to the relevant attestation/offline sprints (e.g., `SPRINT_0162_0001_0001_exportcenter_i`, `SPRINT_0163_0001_0001_exportcenter_ii`, `SPRINT_0510_0001_0001_airgap`, or Scanner import sprint) covering DS1DS12.
- Draft and publish versioned schemas for bundle manifest, delta bundles, trust bundle, and Rekor segment packaging; include canonicalization rules and test vectors.
- Extend offline-kit and Scanner import docs to mandate DSSE/Rekor checkpoint verification, per-entry hashing, safe extraction, append-only state, and tenant/profile scoping; wire metrics/alerts into observability docs.
- Add CI/fixtures: reproducible bundle build attestation, delta/base mismatch tests, rollback/replay tests, stale checkpoint/key tests, and quarantine reprocessing tests.
# Findings Gaps in “StellaOps Storage Blueprint (PostgreSQL patterns per module)”
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** Pasted advisory Heres a crisp, opinionated storage blueprint…” / StellaOps PostgreSQL Patterns per Module (2025-12-01 draft).
**Method:** Reviewed the blueprint against module dossiers (Authority, Routing, VEX, Unknowns, Artifact), high-level architecture, and prior advisories on ledger/evidence/offline posture to identify missing guarantees, hardening steps, and operability gaps.
## Gap Table
| ID | Area | Gap | Impact | Recommendation |
| -- | ---- | --- | ------ | -------------- |
| SB1 | Tenant isolation | DDL examples mostly omit `tenant_id` and tenant-based RLS; policies rely only on `app.user_id`. | Cross-tenant data exposure or cache bleed; feature flags/routing/unknowns not tenant-safe. | Make `tenant_id uuid not null` mandatory on tenant-scoped tables, enforce base RLS `tenant_id = current_setting('app.tenant_id')::uuid`, and add partial indexes by tenant. |
| SB2 | RLS hardening | Blueprint assumes `set_config` but lacks guards for unset/invalid session vars, role separation, or `SECURITY DEFINER` safety. | Mis-set sessions bypass RLS; superuser paths may leak data. | Add `check_app_context()` function used in policies, deny access when settings missing, separate DB roles per service, and forbid bypass for `pg_read_all_data`. |
| SB3 | Partitioning & retention | High-volume tables (audit_log, oauth_token, outbox, unknowns history) not partitioned; no retention/archival plan. | Storage bloat, slow scans, expensive VACUUM; audit trails hard to manage. | Time/tenant partition heavy tables; enforce retention/archival to CAS; add `DROP PARTITION`/`vacuumd` runbooks and metrics. |
| SB4 | Indexing & query plans | Several hot-path queries lack indexes (e.g., `feature_flag(key, version)`, `audit_log(actor_id, at)`, GIN on JSONB facts/unknowns, partial indexes on open unknowns). | Latency spikes and table scans; MV refreshes slow. | Specify required indexes per table and refresh cadence; add `EXPLAIN` baselines in migrations/tests. |
| SB5 | HA/DR & PITR | No posture for replication, failover, backups, or PITR testing. | Data loss/outage risk; compliance gaps. | Standardize HA (streaming replica) with async/sync policy per module, scheduled base/backups + PITR drills, and recovery SLOs documented. |
| SB6 | Migration/dual-write plan | Cutover phases describe read adapters but omit dual-write/backfill, consistency checks, and abort criteria. | Divergence between Mongo and Postgres; hard rollback. | Add dual-write phase with idempotent keys, reconciliation jobs, hash-based diff reports, and automated rollback switch; document stop conditions. |
| SB7 | Schema governance | `schema_version` fields exist but no schema registry, compatibility rules, or SemVer/change-log requirements. | Breaking changes may ship unnoticed; clients cant validate payloads. | Create schema catalog with SemVer and DSSE signatures; enforce compatibility checks in CI and at runtime; require migration playbooks per version bump. |
| SB8 | CDC security & scoping | Logical replication recommended without tenant filtering, column-level exclusions, or connector isolation. | Sensitive data may leak to analytics/third parties; multi-tenant isolation broken. | Use publication per module/tenant, exclude secret columns, TLS/auth for connectors, and add redaction/field allowlists plus monitoring for lag/divergence. |
| SB9 | Outbox robustness | Outbox table lacks idempotency keys, ordering/fencing rules, poison-message handling, and backpressure metrics. | Duplicate or lost events; dispatcher loops under load. | Add `(aggregate_type, aggregate_id, topic, created_at)` unique key, status enum, retry/backoff policy, dead-letter bucket, and observability counters; keep dispatcher transactional. |
| SB10 | Cache governance (Redis) | Cache keys/TTLs noted but no tenant/env namespacing, warm/cold coherence rules, or fail-closed behavior. | Cross-tenant bleed or stale flags/routes; silent fallback to outdated cache. | Namespaces (`env:tenant:` prefixes), include version in keys, require cache-miss fallback to Postgres with freshness checks, and metrics/alerts on hit ratio + staleness. |
| SB11 | Artifact index & CAS hygiene | CAS index lacks GC policy, tag/alias governance, encryption/ACL guidance, or tenant-scoped storage paths; signatures optional. | Digest store grows unbounded; cross-tenant leakage via shared blobs; unverifiable artifacts. | Add GC rules (refcount/last-access), tenant-scoped buckets/prefixes, mandatory signature refs, encryption at rest + access policy, and offline mirror/verify scripts. |
| SB12 | Observability & SLOs | Metrics mentioned but no SLOs/alerts for MV lag, replication lag, RLS policy hits, outbox lag, refresh failures, or Redis divergence. | Operational drift undetected; regressions hit users before detection. | Define per-module SLOs and alerting; ship dashboards; add self-test queries in readiness probes; fail-fast on MV refresh/CDC gaps. |
| SB13 | Security & compliance | No explicit at-rest/transport encryption, audit of DDL/config changes, or data-classification/PII rules for JSONB payloads. | Compliance risk; uncontrolled sensitive data storage. | Enforce TLS, TDE/disk encryption, pgaudit/DDL logging, classified columns with masking/redaction, and PII allowlists plus periodic scans. |
## Immediate follow-ups
- Open a sprint task (e.g., under data/platform hardening) to close SB1SB13 with owners/dates and link to this finding.
- Produce migration/dual-write and partitioning runbooks per module; add schema catalog (versioned, signed) and required indexes to migrations.
- Define HA/DR posture, CDC scoping rules, cache namespacing, artifact GC/ACL policy, and observability SLOs; wire alerts and self-tests into services.
# Findings Gaps in “Verifiable Proof Spine → Moat (receipts + benchmarks)”
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** Heres a crisp, practical way to turn Stella Ops verifiable proof spine into a moatand how to measure it.” (includes Developer Guidelines Benchmarks for a Testable Security Moat”).
**Method:** Read the advisory and attached developer guidelines; compared with related advisories already filed (Graph Revision IDs as Public Trust Anchors, Evidence Bundle and Replay Contracts, Reachability Benchmark Fixtures Snapshot, Comparative Evidence Patterns) and the current `bench/` layout to surface missing contracts, controls, and enforcement hooks.
## Gap Table
| ID | Area | Gap | Impact | Recommendation |
| -- | ---- | --- | ------ | -------------- |
| VM1 | Graph Revision contract | Graph Revision ID recipe lacks canonical serialization rules (sorting, normalization, hash alg/encoding), multi-alg/PQ plan, and provenance fields (feeds/policies/tools). | Different services may compute divergent hashes; receipts tied to non-canonical IDs become unverifiable or collide. | Publish `graph-revision-manifest.schema.json` with canonical JSON rules, mandated hash alg (e.g., BLAKE3-256 hex) and optional multi-alg, plus required digests for feeds, policies, tool images, config flags; add test vectors. |
| VM2 | DSSE predicate & receipt schema | Predicate `stellaops.dev/verdict@v1` is named but not specified (required fields, canonicalization, clock source, list ordering) nor versioning/compatibility rules. | Receipts may serialize differently across services; signature verification and replay can fail; upgrades may break stored receipts. | Define versioned predicate schema + canonical JSON (sorted keys, UTC + monotonic timestamp pair, fixed decimal precision); publish validation tests and compatibility guidance; enforce in emitters/validators. |
| VM3 | Signing policy & key lifecycle | Sign with Authority omits key hierarchy, rotation cadence, dual-sign (ECDSA+PQ) strategy, Rekor/mirror anchoring, and tenant scoping. | Long-lived receipts risk key compromise or compliance gaps; no traceable lineage for rotated keys; multi-tenant trust not isolated. | Document signing policy: key roles (online/offline/HSM), M-of-N custody, rotation/burn rules, dual-sign option, Rekor/mirror anchoring metadata, and tenant-scoped key IDs; enforce policy hash in receipts. |
| VM4 | Receipt storage, retention, and isolation | Postgres table is suggested but lacks retention/GC rules, compression/dedup, encryption-at-rest, RBAC/tenant isolation, and sharding guidance. | Store can bloat; sensitive proofs may be exposed across tenants; replay/export may be inconsistent. | Define storage contract: per-tenant partitioning/shards, append-only receipts, row-level encryption, TTL/archival policy, dedup by `(graphRevisionId, verdictId, algo)`, and export manifests with hashes. |
| VM5 | Reachability slice / symbol proof schema | Call-stack slices and binary symbol proofs lack formal schema, size budgets, architecture coverage (ARM/ppc), redaction rules for paths/symbols, and validation tooling. | Proofs may leak PII/paths, explode in size, or be unusable for replay; binaries without symbols remain unprovable. | Publish schemas for slices and symbol proofs with max nodes/bytes, required fields (arch, offset, hash of slice), redaction/normalization rules, and validator/golden fixtures; add fallback proof type when symbols absent. |
| VM6 | Replay Manifest governance | Replay manifest is named but not required to be DSSE-signed, canonically serialized, or to pin feeds/rulepacks/tool digests/time anchors; no CI gate uses it. | Auditors cannot trust manifests; replays may drift due to unstated feed/tool changes; CI may miss drift. | Define `replay.manifest.json` schema, canonical JSON, DSSE signing, and required fields (feeds/tool digests/policies/config, fake clock seed); add CI job to rerun gold fixtures and compare graph hashes against the manifest. |
| VM7 | No receipt, no ship enforcement path | Rule is declarative; no enforcement points defined (scanner pipeline, policy engine, API, UI), no failure taxonomy, and no override/waiver process. | Receipts may be missing yet verdicts ship; users see inconsistent states; overrides may bypass audit. | Add fail-closed checks in scanner/policy APIs and UI gating; define error codes for missing/invalid receipts; require signed waiver/override records and metrics for violations. |
| VM8 | Benchmark corpus governance & ground truth | Benchmarks call for public corpus and baselines but lack governance: licensing/sanitization checklist, ground-truth labels with evidence, competitor selection matrix, and contribution/review rules. | Metrics may be non-reproducible or legally risky; baseline comparisons could be biased or outdated. | Create benchmark governance doc: sanitized corpus manifest with hashes/DSSE, ground-truth evidence bundles, contributor CLA/review rules, competitor/baseline selection matrix, and staleness SLAs; store under `bench/manifest.*` and sign. |
| VM9 | Benchmark determinism & resource profile | Metrics (FP reduction, triage time, proof coverage, determinism) are defined but no reference hardware/profile, seeding rules, retry/timeout policy, or multi-run hash check. | Results vary run-to-run or across machines; comparisons and claims lose credibility. | Pin reference runner (CPU/RAM, cgroups), seeds, thread limits, timeouts; add multi-run hash stability check in `bench/scripts/run_benchmarks` and publish tolerances; mark strict scenarios that must be zero-drift. |
| VM10 | Observability, alerts, and export kits | Advisory lacks required metrics/alerts for signature failures, graph-hash drift, missing proofs, or benchmark regressions, and doesnt define the audit kit packaging/signing. | Failures may go unnoticed; auditors/buyers cannot independently verify kits; offline users lack parity. | Instrument counters/alerts for receipt verify failures, graph drift, proof coverage gaps, benchmark regressions; define audit-kit layout (receipts + manifest + replay + verify script) with DSSE signature and include in offline kits/export center. |
## Immediate follow-ups
- Add a proof-spine/receipt gap-remediation task to Sprint `SPRINT_0401_0001_0001_reachability_evidence_chain` covering VM1VM7.
- Add a benchmark governance/determinism task to Sprint `SPRINT_0513_0001_0001_public_reachability_benchmark` covering VM8VM10, tying to `bench/` manifests and CI jobs.
- Draft and publish schemas (graph revision, verdict predicate, replay manifest, reachability proofs) plus golden fixtures/tests; wire fail-closed receipt checks and observability alerts into scanner/policy pipelines and UI/API gating.
# Findings Gaps in “SBOM→VEX Proof Spine Blueprint”
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** Chat-supplied advisory tight, practical blueprint to turn your SBOMVEX links into an auditable proof spine…” (not yet filed under `docs/product-advisories/`).
**Method:** Parsed the advisory, aligned it with Authority/Policy/Scanner evidence-chain expectations and existing sprint `SPRINT_0401_0001_0001_reachability_evidence_chain`, and checked for determinism, governance, tenancy, and offline parity gaps.
## Gap Table
| ID | Area | Gap | Impact | Recommendation |
| -- | ---- | --- | ------ | -------------- |
| PS1 | Trust anchor lifecycle & conflicts | Per-dependency TrustAnchor is defined but lacks lifecycle rules (creation approval, change control, supersedes flow) and conflict resolution when multiple anchors match a purl or SBOMEntry. | Anchor drift can silently change accepted signers; conflicting anchors can cause verification bypass or denial. | Require signed TrustAnchor records with `version`, `createdBy`, `supersedes`, and deterministic purl matching precedence; add dual-control approvals and DSSE for anchor mutations; fail closed on ambiguous anchor selection. |
| PS2 | Revocation/rotation enforcement | Revocation list is mentioned but no policy for how existing spines/receipts behave after key revocation or anchor update; no rollback window or re-issuance rules. | Auditors may accept spines signed by revoked keys; replay may fail inconsistently. | Define revocation semantics (hard-fail vs warn), require re-verification tasks on revocation, emit new spines/receipts when anchors change, and publish revoked-but-accepted-until grace policy with metrics/alerts. |
| PS3 | Predicate schemas & test vectors | Predicate types are named (`evidence.stella/v1`, etc.) but no JSON Schemas, canonicalization vectors, or compatibility commitments. | Producers may serialize differently, leading to hash mismatches and unverifiable bundles. | Publish signed JSON Schemas + canonical JSON rules and golden test vectors for evidence/reasoning/VEX/spine; include field-level required/optional rules and normalization of enums/whitespace/precision. |
| PS4 | Merkle/ProofBundle recipe | ProofBundleID is merkle root but algorithm (tree shape, path ordering, hash algo, duplicate handling, domain separation) is unspecified. | Different implementations will derive different bundle IDs for the same inputs, breaking interoperability. | Standardize Merkle recipe (hash algo, leaf format, deterministic ordering, duplicate policy, domain tags); provide reference implementation and fixtures. |
| PS5 | Evidence failure/negative cases | Flow assumes successful evidence; no schema for failed scans, partial results, or absence of evidence attestations. | Missing DSSE records allow silent gaps; verification may over-trust incomplete data. | Define `evidence.stella/v1` variants for failures/partial coverage with required error codes and scope; require DSSE for failures and include them in ProofBundleID computation. |
| PS6 | SBOM evolution & backfill | SBOMEntryID ties to sbomDigest+purl, but no rules for updated SBOMs, component renames, or superseded SBOM versions; backfill of historical spines not described. | Proof history can fragment; replay may mismatch SBOM version to spine. | Add SBOM versioning/backfill policy: immutable sbomDigest, `supersedesSbomDigest`, migration tasks to regenerate spines for changed entries, and UI/API to view lineage. |
| PS7 | Third-party VEX & dual anchors | Import of vendor VEX is implied but no contract for dual-anchor verification (vendor + internal), status translation, or provenance preservation. | Imported VEX may be re-signed without proof of origin; status semantics can drift from vendor meaning. | Require vendor VEX verification against vendor anchor, preserve original envelope bytes, tag provenance, and optionally co-sign under Authority; define status mapping table and conflict resolution. |
| PS8 | Storage security & tenancy | Postgres/blob layout shown but lacks tenant scoping, row-level security, encryption at rest, and retention/GC policy for blobs and envelopes. | Cross-tenant data leakage risk; unbounded storage growth; unverifiable deletions. | Enforce tenant/namespace columns with RLS, encrypt blobs, add retention classes + GC rules, and record DSSE-backed delete/tombstone manifests instead of hard deletes. |
| PS9 | API contract & versioning | API endpoints are sketched without authZ roles, pagination, ETags, error codes, or versioning strategy; no idempotency keys for POST. | Clients may integrate inconsistently; accidental duplication or cache poisoning possible. | Define OpenAPI with versioned paths, RBAC roles (Authority/Viewer/Auditor), pagination/caching semantics, idempotency keys, and deterministic error models; add conformance tests. |
| PS10 | Observability & SLIs | Metrics/logging expectations are absent (only UX hints); no alerts for verification drift, revocation, hash mismatch, or signer skew. | Integrity regressions may go unnoticed; auditors lack evidence of continuous enforcement. | Add required counters/histograms (verify pass/fail by reason, anchor conflicts, revocation hits, recompute drift), structured logs with IDs, and alert thresholds; document runbooks. |
| PS11 | Offline/export kit parity | Advisory references offline friendliness but does not define export format (bundle layout, signatures, chunking), replay script, or air-gap verification inputs. | Air-gapped users cannot verify or may accept tampered kits; deterministic replay claims weaken. | Specify offline proof kit (SBOM + envelopes + anchors + schemas + Merkle recipe) with signed manifest and verify script; include chunking rules and hardware profile for replay. |
| PS12 | Key custody & PQC coexistence | Keys live in Authority, but custody model, M-of-N approval, audit trails, and PQC dual-sign verification order are not defined. | Single-operator compromise or ambiguous verification precedence; PQ readiness unverifiable. | Define key hierarchies per environment, dual-control ops, signed key-rotation records, verification precedence (ECDSA vs PQ), and audit logging; ship HSM/KMS policy guidance. |
| PS13 | Receipts schema & cache invalidation | Receipt structure is mentioned but not versioned; no rules for cache TTL, re-issuance when evidence/policy changes, or signing requirements. | Stale receipts may circulate; auditors cannot trust replay date/tool versions. | Version receipt schema, include verifier version/time, anchor IDs, tool hashes, policy hash; require DSSE signing; enforce cache TTL and auto-invalidate on anchor/policy change. |
| PS14 | Performance/backpressure & dedup | No throughput/latency SLOs, queue/backpressure rules, or deduplication of envelopes for identical inputs. | Service overload or ballooning storage; duplicate envelopes inflate Merkle roots. | Define SLOs and per-tenant quotas; require deduplication by hash/predicate; add idempotent processing with backoff and metrics on drops/retries. |
## Immediate follow-ups
- Add a gaps-remediation task to `SPRINT_0401_0001_0001_reachability_evidence_chain` (or create a new sprint for the proof spine) covering PS1PS14 with owners/dates.
- Publish signed JSON Schemas, Merkle recipe, and test vectors for evidence/reasoning/VEX/spine/receipt; wire canonicalization tests into CI.
- Draft TrustAnchor lifecycle/rotation policy (dual-control, revocation handling, ambiguity fail-closed) and update Authority/Policy docs accordingly.
- Define offline proof-kit packaging + verifier script and include metrics/alerts/runbooks for verification drift and anchor conflicts.
# Findings Gaps in “Time-to-Evidence (TTE) Metric”
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** `01-Dec-2025 - Time-to-Evidence (TTE) Metric.md`
**Method:** Evaluated TTE proposal against StellaOps UX/telemetry architecture (UI sprints 0209/0215, Telemetry core 0180). Focused on instrumentation fidelity, data quality, SLO coverage, caching/streaming readiness, offline/tenant safety, and governance.
## Gap Table
| ID | Area | Gap | Impact | Recommendation |
| -- | ---- | --- | ------ | -------------- |
| TTE1 | Proof eligibility definition | First proof not formally defined (what counts as proof per surface; screenshots vs raw artifacts). | Inconsistent measurement; teams may emit on summaries. | Define proof eligibility per surface (SBOM line with bomRef + hash, reachability edge with graph rev, VEX clause with evidence ID); forbid summaries; add contract tests. |
| TTE2 | Event schema/versioning | Event fields are informal; no schema/version, tenant scope, or PII redaction guidance. | Broken joins and leakage across tenants; dashboards unreliable. | Publish versioned `tte-event.schema.json` with required fields (finding_id, tenant_id, proof_kind, source, ui_version, synthetic flag), redaction rules, and validation in collectors. |
| TTE3 | Correlation & dedupe | No guidance on deduping multiple `proof_rendered` events per open, retries, or tab refresh. | Over-counting inflates TTE; noisy alerts. | Define correlation rules (per finding_id + view instance), keep first-proof TTE canonical, bucket retries separately; add idempotency key. |
| TTE4 | Sampling & bot exclusion | Sampling hinted but no hard targets, bot filters, or synthetic tagging. | Skewed metrics; false regressions. | Require 100% in staging, 50% prod with bot/synthetic exclusion flag; document filter and include in rollups. |
| TTE5 | SLO scope & budgets | P95=15s stated globally; no per-surface SLOs, error budgets, or burn alerts. | Hot pages regress without alarms; mixed workloads masked. | Set per-surface SLOs (list/detail/deep-link, per proof_kind), define 28-day error budget and burn alerts; add regression guard in CI. |
| TTE6 | Backend readiness (indexes/streaming) | Pre-index/streaming called out but no required indexes, chunk sizes, or fallback for cold caches. | P95 fails in prod despite UI work. | Mandate indexes (pkg@version, graph node, bomRef), first-chunk SLA (<200ms), cache warmers for top-N findings, and fallback to cached proof slice. |
| TTE7 | Offline/air-gap mode | No rules for TTE when offline kits are used (local proofs) or when proofs are unavailable. | Air-gapped users show infinite TTE or misleading empties. | Define offline TTE path: local proof sources, explicit offline proof unavailable state, separate `source=offline_kit`; exclude from online SLO or bucket separately. |
| TTE8 | Alerting & dashboards | Dashboards listed but no alert policies, runbooks, or ownership. | Slow drift unnoticed; no on-call action. | Create alert rules (P95>15s 15m, P99>30s 15m) with owners, runbook, and suppression windows; add weekly trend review. |
| TTE9 | Governance & release gates | No requirement to block releases on TTE regression or to store baselines. | Regressions ship silently. | Add release check: compare P95 vs previous release by proof_kind/page; block if >20% regression unless waived; store baseline snapshots. |
| TTE10 | Accessibility & layout | Evidence-above-fold rule stated but no viewport spec, keyboard/a11y checks, or fallback for long proofs. | Users may still miss proof or fail accessibility audits. | Define viewport targets (e.g., 1366x768), a11y checks (ARIA/Tab order for proof panel), truncation rules with “copy full proof”, and Playwright a11y test for TTE scenarios. |
## Immediate follow-ups
- Add TTE1TTE10 remediation task `TTE-GAPS-0215-011` to Sprint `SPRINT_0215_0001_0001_vuln_triage_ux` (primary UI owner) with telemetry alignment to Sprint `SPRINT_0180_0001_0001_telemetry_core`.
- Publish `tte-event.schema.json`, proof eligibility rules per surface, sampling/bot filters, per-surface SLO/error budgets, required indexes/streaming SLOs, offline-kit handling, alert/runbook, release gate, and a11y/viewport test cases.
# Findings Gaps in Archived November Advisories (1523 Nov 2025)
**Requested label:** 2025-11-31 (note: November has 30 days)
**Compiled:** 2025-12-01 (UTC)
**Source reviewed:** All advisories in `docs/product-advisories/archived/` dated 1523 Nov 2025 (e.g., embedded in-toto provenance events, function-level VEX explainability, binary reachability branches, SBOM-provenance spine, reachability corpus, etc.).
**Method:** Skimmed each archived advisory and consolidated common gaps; focused on missing schemas, determinism/replay rules, tenant/redaction, offline parity, and ownership. Kept to 12 high-impact gaps per advisory to seed backlog without expanding scope excessively.
## Gap Table
| Advisory (archived) | Gap ID | Gap | Impact | Recommendation |
| --- | --- | --- | --- | --- |
| Embedded in-toto provenance events | AR-EP1 | No canonical event/predicate schema or DSSE requirement; relies on narrative. | Provenance unverifiable; toolchain drift. | Publish `provenance-event.schema.json`, require DSSE, include tool version + policy hash; add fixtures. |
| Function-level VEX explainability | AR-FX1 | Lacks stable IDs for function nodes/edges and reachability proofs. | Explanations not replayable; links break. | Define function-node ID scheme, require graph_rev, shortest-path proof bundle; add determinism tests. |
| Serdica census Excel import blueprint | AR-SE1 | No PII redaction or checksum rules for Excel ingest. | Data leakage; non-deterministic imports. | Add redaction/allowlist, checksum manifest, DSSE receipt per import, and replay script. |
| Proof spine for quiet alerts | AR-PS1 | “Proof spine” undefined (hash recipe, bundle layout, failure cases). | Quiet alerts un-auditable. | Standardize spine (hash algo, ordering, failure records), DSSE-sign, and ship fixtures. |
| Scanner roadmap diff-aware rescans | AR-SR1 | No determinism guards (seed/time clamp) for rescans. | Drift across runs; flaky diffs. | Enforce fixed seeds/UTC, sorted outputs, golden diffs CI. |
| Layer-SBOM cache hash reuse | AR-LS1 | Cache key recipe unspecified (layer ordering, tar flags, compression). | Cache collisions/misses; incorrect reuse. | Define canonical key recipe (ordered layer digests, normalized tar, compression flags) and validators. |
| Multi-runtime reachability corpus | AR-MR1 | Corpus lacks licensing/provenance and ground-truth assertions. | Legal risk; unvalidated results. | Add license metadata, expected reachability assertions, DSSE-signed manifest. |
| SPDX canonical persistence / CycloneDX interchange | AR-SX1 | No canonicalization rules (ordering, whitespace, encoding) across SPDX↔CDX. | Hash drift; signature breakage. | Publish canonicalization spec + round-trip tests, DSSE-sign outputs. |
| Validation plan for quiet scans (diff-CI) | AR-VQ1 | No acceptance thresholds or negative/failure fixtures. | Quiet scans may suppress real issues. | Define threshold matrix, include failure/edge fixtures, CI gate on false-negative budget. |
| SBOM-Provenance-Spine (17 & 18 Nov) | AR-SP1 | Duplicate advisories; spine lacks versioning and Merkle recipe. | Divergent implementations; audit gaps. | Declare single canonical doc, versioned spine schema, Merkle/hash recipe, DSSE signing. |
| Stripped-ELF reachability | AR-SEF1 | No symbol-stripping fallback (DWARF absent) or redaction rules. | Binaries unprovable; PII path leaks. | Require fallback heuristics, redaction, and proof attestation format. |
| Binary Reachability Engine | AR-BR1 | Performance/SLOs and determinism seeds absent. | Non-reproducible graphs; timeouts. | Set seed/time clamps, path-ordering rules, perf SLO, golden graphs CI. |
| C# Binary Analyzer | AR-CS1 | No PURL mapping or IL-level canonical IDs. | Findings not linkable to packages; unstable links. | Define IL symbol IDs + PURL mapping rules; add hash anchors. |
| Patch Oracles | AR-PO1 | Oracle decision schema undefined; no audit trail. | Wrong patch suggestions; untraceable. | Create oracle schema with inputs, decision, confidence, evidence; DSSE-sign and log. |
| Unknowns Registry (18 Nov) | AR-UR1 | Registry schema/versioning missing; decay logic undefined. | Unknowns pile up; inconsistent triage. | Version registry schema, define decay/expiry fields, audit trail, and offline export. |
| ELF Build-ID mapping | AR-BI1 | Build-ID→PURL mapping recipe not specified; no collision policy. | Misattribution; trust breaks. | Define mapping algorithm, collision handling, attestation with subject hashes. |
| .init_array constructors as reachability roots | AR-IA1 | No rule for weighting/ordering roots or de-duplication. | Over/under-approx reachability. | Specify root precedence, dedupe, and evidence bundle with graph_rev. |
| Reachability & Moat Watch updates | AR-MW1 | No change-log or checkpoint signing for updates. | Consumers cant track or trust updates. | Add signed checkpoints, changelog, and freshness SLA. |
| Encoding binary reachability with PURL edges | AR-PE1 | Edge encoding schema not versioned; arch-specific fields absent. | Cross-arch drift; parsing errors. | Version edge schema, require arch/endianness, hash of binaries, and fixtures. |
| Where Stella Ops Can Truly Lead | AR-ML1 | Positioning lacks measurable targets or evidence asks. | Strategy not actionable. | Add 35 measurable targets (perf/SLO, replay fidelity) with proof requirements and owners. |
| Benchmarking determinism in vuln scoring | AR-BD1 | No benchmark corpus or scoring reproducibility rules. | Claims unproven; regressions undetected. | Publish corpus + expected scores, hash manifest, DSSE results, CI reruns. |
| Publishing a reachability benchmark dataset | AR-RD1 | Dataset packaging/licensing undefined; no integrity attestation. | Cannot redistribute or verify. | Add license metadata, manifest + hashes, DSSE attestation, offline kit. |
| Stella Ops vs Competitors | AR-SC1 | Comparison lacks normalized criteria or evidence links. | Biased/unsupported claims. | Define criteria table, data sources, timestamps; include raw evidence links. |
| Verifying Binary Reachability via DSSE Envelopes (archived copy) | AR-VB1 | Archived version lacks current DSSE predicate and Merkle recipe updates. | Divergence from active spec. | Mark superseded; link to active advisory; provide migration notes. |
## Immediate follow-ups
- Add an “Archived Advisories Gaps” tracker row to the relevant documentation sprint (e.g., `SPRINT_300_documentation_process`) to decide which archived topics merit revival; start with high-signal engine/graph items (AR-BR1, AR-SEF1, AR-PE1) and provenance items (AR-EP1, AR-SP1).
- For any archived advisory revived, create a fresh canonical advisory and sprint tasks; retire duplicates (e.g., SBOM-Provenance-Spine) with clear supersede notes.
### Per-advisory gap summaries (archived)
| Advisory | Concise Gap | Recommendation |
| --- | --- | --- |
| Where StellaOps Can Truly Lead | Strategy brief lacks measurable targets and evidence asks. | Define 35 measurable targets (perf/SLO, replay fidelity) with required evidence links and owners. |
| Benchmarking Determinism in Vulnerability Scoring | No corpus/expected scores; reproducibility undefined. | Publish benchmark corpus + expected scores with hash manifest and DSSE results; add CI rerun gate. |
| Binary-Reachability-Engine | Missing determinism seeds/time clamps and perf SLOs. | Fix seeds/UTC, path-ordering rules, perf SLO, golden graphs CI. |
| Branch · Attach ELF BuildIDs for Stable PURL Mapping | Mapping recipe/collision policy absent. | Define Build-ID→PURL algorithm, collision handling, attestation with subject hashes. |
| Branch · Model .init_array Constructors as Reachability Roots | Root weighting/dedup rules missing. | Specify root precedence, dedupe policy, and graph_rev-bound evidence bundle. |
| Branch · Reachability & Moat Watch — Verified 2025 Updates | No signed checkpoints/changelog. | Add signed checkpoints with freshness SLA and changelog; distribute via DSSE snapshot. |
| CSharp-Binary-Analyzer | No IL symbol IDs or PURL mapping rules. | Define IL symbol ID + PURL mapping with hash anchors; add fixtures. |
| DSSE-Signed Offline Scanner Updates | (Archived) No canonical DSSE predicate or offline kit recipe. | Publish predicate schema, offline bundle layout, and verifier script with hashes. |
| Encoding Binary Reachability with PURLResolved Edges | Edge schema unversioned; arch fields missing. | Version edge schema; require arch/endianness/binary hash; add fixtures. |
| Patch-Oracles | Oracle decision schema/audit trail undefined. | Create decision schema (inputs, decision, confidence, evidence) with DSSE signing and logging. |
| Publishing a Reachability Benchmark Dataset | Packaging/licensing/integrity unclear. | Add license metadata, manifest + hashes, DSSE attestation, offline kit. |
| SBOM-Provenance-Spine (17 & 18 Nov) | Duplicate docs; spine lacks versioning/Merkle recipe. | Declare canonical version, publish schema + Merkle recipe, DSSE-sign; mark duplicate superseded. |
| Stella Ops vs Competitors | Criteria/evidence not normalized. | Define comparison criteria table, data sources/timestamps, and raw evidence links. |
| Storage Blueprint for PostgreSQL Modules | Patterns lack tenancy/isolation and PITR/SLA specifics. | Add tenant isolation, PITR/SLA baselines, deterministic migrations, and signed change log. |
| Stripped-ELF-Reachability | No fallback when symbols absent; redaction undefined. | Provide fallback heuristics, redaction rules, and proof attestation format. |
| Unknowns-Registry | Schema/versioning and decay/expiry logic missing. | Version registry schema; add decay/expiry fields, audit trail, offline export. |
| Verifiable Proof Spine Receipts and Benchmarks | Proof spine hash recipe undefined; benchmarks missing. | Standardize hash/ordering, include failure cases, DSSE-sign; publish benchmarks. |
| Verifying Binary Reachability via DSSE Envelopes (archived copy) | Archived version diverges from active spec. | Mark superseded; link to active advisory; provide migration notes. |
| embedded in-toto provenance events | No event schema or DSSE requirement. | Publish provenance-event schema; require DSSE; include tool/policy hashes. |
| function-level vex explainability | Missing stable function IDs/graph_rev binding. | Define function-node IDs, require graph_rev, shortest-path proof bundle, determinism tests. |
| ipal serdica census excel import blueprint | No PII redaction or checksum rules. | Add redaction/allowlist, checksum manifest, DSSE receipt per import, replay script. |
| layer-sbom cache hash reuse | Cache key recipe unspecified. | Define canonical key (ordered layer digests, normalized tar/compression flags) and validators. |
| multi-runtime reachability corpus | Lacks licensing/provenance and ground truth. | Add license metadata, expected reachability assertions, DSSE-signed manifest. |
| proof spine for explainable quiet alerts | Spine definition missing (hash recipe/failures). | Standardize spine schema/ordering, include failure records, DSSE-sign fixtures. |
| scanner roadmap with deterministic diff-aware rescans | No determinism guards or seeds. | Enforce fixed seeds/UTC, sorted outputs, golden diff CI. |
| spdx canonical persistence cyclonedx interchange | No canonicalization rules across SPDX↔CDX. | Publish canonicalization spec + round-trip tests; DSSE-sign outputs. |
| validation plan for quiet scans provenance diff-ci | Lacks acceptance thresholds and negative fixtures. | Define thresholds and failure/edge fixtures; gate CI on false-negative budget. |
## Archived advisory stubs (per-advisory headings)
*These stubs reference the consolidated AR-* gap table above; no additional gaps beyond that table.*
# Findings Gaps in “Where StellaOps Can Truly Lead”
See AR-ML1 in the archived gap table.
# Findings Gaps in “ Where StellaOps Can Truly Lead”
See AR-ML1 in the archived gap table; archived filename contains a leading space.
# Findings Gaps in “Benchmarking Determinism in Vulnerability Scoring”
See AR-BD1 in the archived gap table.
# Findings Gaps in “Binary-Reachability-Engine”
See AR-BR1 in the archived gap table.
# Findings Gaps in “Branch · Attach ELF BuildIDs for Stable PURL Mapping”
See AR-BI1 in the archived gap table.
# Findings Gaps in “Branch · Model .init_array Constructors as Reachability Roots”
See AR-IA1 in the archived gap table.
# Findings Gaps in “Branch · Reachability & Moat Watch — Verified 2025 Updates”
See AR-MW1 in the archived gap table.
# Findings Gaps in “CSharp-Binary-Analyzer”
See AR-CS1 in the archived gap table.
# Findings Gaps in “DSSE-Signed Offline Scanner Updates”
See AR-DS1 in the archived gap table.
# Findings Gaps in “Encoding Binary Reachability with PURLResolved Edges”
See AR-PE1 in the archived gap table.
# Findings Gaps in “Patch-Oracles”
See AR-PO1 in the archived gap table.
# Findings Gaps in “Publishing a Reachability Benchmark Dataset”
See AR-RD1 in the archived gap table.
# Findings Gaps in “SBOM-Provenance-Spine”
See AR-SP1 in the archived gap table.
# Findings Gaps in “SBOM-Provenance-Spine”
See AR-SP1 in the archived gap table; duplicate advisory, treat 18-Nov version as canonical.
# Findings Gaps in “Stella Ops vs Competitors”
See AR-SC1 in the archived gap table.
# Findings Gaps in “Storage Blueprint for PostgreSQL Modules”
See AR-SB1 in the archived gap table.
# Findings Gaps in “Stripped-ELF-Reachability”
See AR-SEF1 in the archived gap table.
# Findings Gaps in “Unknowns-Registry”
See AR-UR1 in the archived gap table.
# Findings Gaps in “Verifiable Proof Spine Receipts and Benchmarks”
See AR-VP1 in the archived gap table.
# Findings Gaps in “Verifying Binary Reachability via DSSE Envelopes”
See AR-VB1 in the archived gap table.
# Findings Gaps in “embedded in-toto provenance events”
See AR-EP1 in the archived gap table.
# Findings Gaps in “function-level vex explainability”
See AR-FX1 in the archived gap table.
# Findings Gaps in “ipal serdica census excel import blueprint”
See AR-SE1 in the archived gap table.
# Findings Gaps in “layer-sbom cache hash reuse”
See AR-LS1 in the archived gap table.
# Findings Gaps in “multi-runtime reachability corpus”
See AR-MR1 in the archived gap table.
# Findings Gaps in “proof spine for explainable quiet alerts”
See AR-PS1 in the archived gap table.
# Findings Gaps in “scanner roadmap with deterministic diff-aware rescans”
See AR-SR1 in the archived gap table.
# Findings Gaps in “spdx canonical persistence cyclonedx interchange”
See AR-SX1 in the archived gap table.
# Findings Gaps in “validation plan for quiet scans provenance diff-ci”
See AR-VQ1 in the archived gap table.
# Findings Gaps in “Rekor Receipt Checklist for Stella Ops”
**Requested label:** 2025-11-31 (note: November has 30 days)
@@ -634,7 +953,7 @@
- Add MI1MI10 remediation task to UI Sprint `SPRINT_0209_0001_0001_ui_i` (or UI II/III if preferred) with owners and dates.
- Publish motion/telemetry/testing tokens, reduced-motion rules, offline/error patterns, component mappings, and theme-aware micro-copy guidance; add Playwright/a11y checks to CI.
# Findings Gaps in “ProofLinked VEX UI Developer Guidelines”
# Findings Gaps in “Proof-Linked VEX UI Developer Guidelines”
**Requested label:** 2025-11-31 (note: November has 30 days)
@@ -1361,3 +1680,12 @@
## Immediate follow-ups
- Add a ledger gaps task to a relevant sprint (e.g., reachability/policy ledger work or EvidenceLocker/export coordination) to close FL1FL10.
- Publish versioned schemas and canonical serialization; mandate Merkle/external anchor policy with freshness; enforce tenant/redaction rules; require DSSE/policy linkage; add golden fixtures, replay/rebuild verifiers, air-gap verify scripts, and quotas/backpressure.
_id; verify on ingest/export. |
| FL7 | Export determinism & golden fixtures | Export determinism claimed but no golden fixtures or multi-run hash CI for ledger exports. | Regressions may go unnoticed; reproducibility claims weak. | Publish golden ledger exports and CI multi-run hash checks; pin compression/ordering. |
| FL8 | Replay/rebuild tooling | Projection rebuild guidance minimal; no checksum for rebuild outputs. | Rebuilds may diverge from ledger state; audits fail. | Provide rebuild CLI with output hashes; compare against ledger roots; add acceptance tests. |
| FL9 | Air-gap verifier | Offline bundle verification is mentioned but not specified (hash chain, Merkle roots, anchors, revocations). | Air-gapped audits may be incomplete. | Define offline ledger verify script requirements (hash chain, Merkle root, optional external anchor checkpoint); ship script + tests. |
| FL10 | Performance envelopes & quotas | SLOs listed but no quotas/backpressure for append/export per tenant or chain. | Hot tenants could starve others; risk of data loss under load. | Add per-tenant quotas/backpressure and alerts; document performance envelopes; test under load. |
## Immediate follow-ups
- Add a ledger gaps task to a relevant sprint (e.g., reachability/policy ledger work or EvidenceLocker/export coordination) to close FL1FL10.
- Publish versioned schemas and canonical serialization; mandate Merkle/external anchor policy with freshness; enforce tenant/redaction rules; require DSSE/policy linkage; add golden fixtures, replay/rebuild verifiers, air-gap verify scripts, and quotas/backpressure.

View File

@@ -10,6 +10,7 @@ These are the authoritative advisories to reference for implementation:
- **Canonical:** `25-Nov-2025 - Add CVSS v4.0 Score Receipts for Transparency.md`
- **Sprint:** SPRINT_0190_0001_0001_cvss_v4_receipts.md
- **Gaps:** `31-Nov-2025 FINDINGS.md` (CV1CV10 remediation task CVSS-GAPS-190-013)
- **Timing/UI:** `01-Dec-2025 - Time-to-Evidence (TTE) Metric.md` (archived)
- **Status:** New sprint created
### CVSS v4.0 Momentum Briefing
@@ -76,6 +77,20 @@ These are the authoritative advisories to reference for implementation:
- **Gaps:** `31-Nov-2025 FINDINGS.md` (PVX1PVX10 remediation task UI-PROOF-VEX-0215-010)
- **Status:** Drawer/badge pattern defined but missing scoped auth, cache/staleness policy, stronger integrity verification, failure/offline UX, evidence precedence rules, telemetry privacy schema, signed permalinks, revision reconciliation, and fixtures/tests.
### Time-to-Evidence (TTE) Metric
- **Canonical:** `01-Dec-2025 - Time-to-Evidence (TTE) Metric.md`
- **Sprint:** SPRINT_0215_0001_0001_vuln_triage_ux.md (UI) with telemetry alignment to SPRINT_0180_0001_0001_telemetry_core.md
- **Related Docs:** UI sprints 0209/0215, telemetry architecture docs
- **Gaps:** `31-Nov-2025 FINDINGS.md` (TTE1TTE10 remediation task TTE-GAPS-0215-011)
- **Status:** Metric defined but needs event schema/versioning, proof eligibility rules, sampling/bot filters, per-surface SLO/error budgets, index/streaming requirements, offline-kit handling, alert/runbook, release gate, and a11y tests.
### Archived Advisories (1523 Nov 2025)
- **Canonical:** `docs/product-advisories/archived/*.md` (embedded provenance events, function-level VEX explainability, binary reachability branches, SBOM-provenance spine, etc.)
- **Sprint:** SPRINT_300_documentation_process.md (triage/decision)
- **Related Docs:** None current (need revival + canonicalization)
- **Gaps:** `31-Nov-2025 FINDINGS.md` (AR-EP1 … AR-VB1 remediation task ARCHIVED-GAPS-300-020)
- **Status:** Archived set lacks schemas, determinism rules, redaction/licensing, changelog/signing, and duplication resolution; needs triage on which to revive into active advisories.
### SBOM → VEX Proof Blueprint
- **Canonical:** `29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md`
- **Sprint:** SPRINT_300_documentation_process.md (docs tracker)

View File

@@ -0,0 +1,80 @@
# Time-to-Evidence (TTE) Metric
Compiled: 2025-12-01 (UTC)
## What it is
**Definition:** `TTE = t_first_proof_rendered t_open_finding`.
**Proof** = the exact artifact or path that justifies the claim (e.g., `package-lock.json: line 214 → openssl@1.1.1`, `reachability: A → B → C sink`, or `VEX: not_affected due to unreachable code`).
**Target:** **P95 ≤ 15s** (stretch: **P99 ≤ 30s**). If 95% of findings show proof within 15 seconds, the UI stays honest: evidence before opinion, low noise, fast explainability.
## Why it matters
- **Trust:** People accept decisions they can verify quickly.
- **Triage speed:** Proof-first UIs cut back-and-forth and guesswork.
- **Noise control:** If you cant surface proof fast, you probably shouldnt surface the finding yet.
## How to measure (engineering-ready)
Emit two stamps per finding view:
- `t_open_finding` (on route enter or modal open).
- `t_first_proof_rendered` (first DOM paint of SBOM line / path list / VEX clause).
Store as `tte_ms` in a lightweight events table (Postgres) with tags: `tenant`, `finding_id`, `proof_kind` (`sbom|reachability|vex`), `source` (`local|remote|cache`).
Nightly rollup: compute P50/P90/P95/P99 by proof_kind and page. Alert when **P95 > 15s** for 15 minutes.
## UI contract (keeps the UX honest)
- **Above the fold:** always show a compact **Proof panel** first (not hidden behind tabs).
- **Skeletons over spinners:** reserve space; render partial proof as soon as any piece is ready.
- **Plain text copy affordance:** “Copy SBOM line / path” button right next to the proof.
- **Defer non-proof widgets:** CVSS badges, remediation prose, and charts load *after* proof.
- **Empty-state truth:** if no proof exists, say “No proof available yet” and show the loader for *that* proof type only (dont pretend with summaries).
## Backend rules of thumb
- **Pre-index for first paint:** cache top N proof items per hot finding (e.g., first SBOM hit + shortest path).
- **Bound queries:** proof queries must be *O(log n)* on indexed columns (pkg name@version, file hash, graph node id).
- **Chunked streaming:** send first proof chunk <200 ms after backend hit; dont hold for the full set.
- **Timeout budget:** 12s backend budget + 3s UI/render margin = 15s P95.
## Minimal contract to add in your code
```ts
// Frontend: fire on open
metrics.emit('finding_open', { findingId, t: performance.now() });
// When the first real proof node/line hits the DOM:
metrics.emit('proof_rendered', { findingId, proofKind, t: performance.now() });
```
```sql
-- Rollup (hourly)
SELECT
proof_kind,
percentile_cont(0.95) WITHIN GROUP (ORDER BY tte_ms) AS p95_ms
FROM tte_events
WHERE ts >= now() - interval '1 hour'
GROUP BY proof_kind;
```
## What to put on the team dashboard
- **TTE P95 by page** (Findings list, Finding details).
- **TTE P95 by proof_kind** (sbom / reachability / vex).
- **Error budget burn**: minutes over target per day.
- **Top regressions**: last 7 days vs prior 7.
## Acceptance checklist for any finding view
- [ ] First paint shows a real proof snippet (not a summary).
- [ ] Copy proof button works within 1 click.
- [ ] TTE P95 in staging 10s; in prod 15s.
- [ ] If proof missing, explicit empty-state + retry path.
- [ ] Telemetry sampled 50% of sessions (or 100% for internal).
## Ready-to-drop implementation notes

View File

@@ -0,0 +1,50 @@
# Supersedes backfill rollout plan (DEVOPS-AOC-19-101)
Scope: Concelier Link-Not-Merge backfill and supersedes processing once advisory_raw idempotency index is in staging.
## Preconditions
- Idempotency index verified in staging (`advisory_raw` duplicate inserts rejected; log hash recorded).
- LNM migrations 21-101/102 applied (shards, TTL, tombstones).
- Event transport to NATS/Redis disabled during backfill to avoid noisy downstream replays.
- Offline kit mirror includes current hashes for `advisory_raw` and backfill bundle.
## Rollout steps (staging → prod)
1) **Freeze window** (announce 24h prior)
- Pause Concelier ingest workers (`CONCELIER_INGEST_ENABLED=false`).
- Stop outbox publisher or point to blackhole NATS subject.
2) **Dry-run (staging)**
- Run backfill job with `--dry-run` to emit counts only.
- Verify: new supersedes records count == expected; no write errors; idempotency violations = 0.
- Capture logs + SHA256 of generated report.
3) **Prod execution**
- Run backfill job with `--batch-size=500` and `--stop-on-error`.
- Monitor: insert rate, error rate, Mongo oplog lag; target <5% CPU on primary.
4) **Validation**
- Run consistency check:
- `advisory_observations` count stable (no drop).
- Supersedes edges present for all prior conflicts.
- Idempotency index hit rate <0.1%.
- Run API spot check: `/advisories/summary` returns supersedes metadata; `advisory.linkset.updated` events absent during freeze.
5) **Unfreeze**
- Re-enable ingest + outbox publisher.
- Trigger single `advisory.observation.updated@1` replay to confirm event path is healthy.
## Rollback
- If errors >0 or idempotency violations observed:
- Stop job, keep ingest paused.
- Run rollback script `ops/devops/scripts/rollback-lnm-backfill.js` to remove supersedes/tombstones inserted in current window.
- Restore Mongo from last checkpointed snapshot if rollback script fails.
## Evidence to capture
- Job command + arguments.
- SHA256 of backfill bundle and report.
- Idempotency violation count.
- Post-run consistency report (JSON) stored under `ops/devops/artifacts/aoc-supersedes/<timestamp>/`.
## Monitoring/Alerts
- Add temporary Grafana panel for idempotency violations and Mongo ops/sec during job.
- Alert if job runtime exceeds 2h or if oplog lag > 60s.
## Owners
- Run: DevOps Guild
- Approvals: Concelier Storage Guild + Platform Security

View File

@@ -0,0 +1,57 @@
# Transparency Log Witness Deployment Plan (DEVOPS-ATTEST-74-001)
## Goals
- Deploy and monitor a Sigstore-compatible witness for Rekor v1/v2 logs (and air-gap mirrors).
- Provide offline-ready configs and evidence (hashes, DSSE attestations) for bootstrap packs.
## Scope
- Environments: staging → prod (online), sealed/offline mirror (optional, read-only).
- Witness duties: verify inclusion proofs, publish checkpoints/signed STHs, expose metrics and health.
## Architecture
- Witness binary (sigstore/witness or equivalent) in a hardened container:
- Non-root user, read-only rootfs, seccomp/AppArmor defaults.
- TLS with mTLS between witness and collector; optional OIDC for admin endpoints.
- Inputs:
- Rekor base URL(s) + public keys.
- Mirror CAR path + signature (for air-gap).
- Outputs:
- Signed checkpoints (STH) rotated hourly; stored in object storage + DSSE manifest.
- Metrics: Prometheus `/metrics` endpoint (request latency, verify failures, checkpoint age).
- Logs: JSON, structured, no PII.
## Deployment steps
1) Build/pull witness image (pin digest); generate SBOM + cosign attestations.
2) Create config:
- `rekor_urls`: prod/staging
- `rekor_keys`: PEMs
- `checkpoint_interval`: 1h
- `mirror_path` (optional): `/data/rekor-mirror.car`
- `signer`: KMS ref or file key (sealed-mode uses file key from bootstrap pack)
3) Helm/Compose template:
- read-only rootfs, drop NET_RAW, memory/cpu limits
- PVC for checkpoints (`/var/lib/witness/checkpoints`)
- Service exposing HTTPS + `/metrics`
4) CI:
- Lint chart
- Run e2e: start Rekor test instance, run witness, verify checkpoint written, verify metrics non-zero.
- Publish image SBOM/attestations and chart checksums.
5) Monitoring/alerts:
- `witness_verify_failures_total` > 0 over 5m
- `witness_checkpoint_age_seconds` > 5400
- `witness_backfill_queue_depth` (if supported) above threshold
## Offline/air-gap mode
- Consume signed Rekor mirror (CAR + manifest) from bootstrap pack.
- Run witness in verify-only mode against mirror; disable outbound network.
- Emit checkpoints signed with offline key; store in mirror bundle for audit.
## Evidence to capture
- Image digest, SBOM hash, chart checksum.
- Signed checkpoint sample and DSSE manifest.
- CI e2e logs and metrics sample (scrape output).
## Owners
- Build/deploy: DevOps Guild
- Keys/config: Platform Security
- Observability: Observability Guild

View File

@@ -0,0 +1,53 @@
# Concelier LNM Release Plan (DEVOPS-LNM-21-101-REL / 102-REL / 103-REL)
Scope: package and publish Link-Not-Merge migrations/backfill/object-store seeds for release and offline kits.
## Artefacts
- Migration bundles:
- 21-101 shard/index migrations (`EnsureLinkNotMergeShardingAndTtlMigration`)
- 21-102 backfill/tombstone/rollback scripts
- 21-103 object-store seed bundle (once contract final)
- Checksums (`SHA256SUMS`, signed)
- SBOMs (spdx.json) for migration runner image/tooling
- Cosign attestations for images/bundles
- Offline kit slice tarball with all above + DSSE manifest
## Pipeline outline
1) Build migration runner image (dotnet) with migrations baked; generate SBOM; pin digest.
2) Export migration scripts/bundles to `artifacts/lnm/`.
3) Create offline bundle:
- `migrations/21-101/` (DLLs, scripts, README)
- `migrations/21-102/` (backfill, rollback, README)
- `seeds/object-store/` (placeholder until 21-103 dev output)
- `SHA256SUMS` + `.sig`
- SBOMs + cosign attestations
4) Verification stage:
- `dotnet test` on migration runner
- `cosign verify-blob` for bundles
- `sha256sum --check`
5) Publish:
- Upload to release bucket + offline kit
- Record manifest (hashes, versions, digests)
## Runbook (apply in staging → prod)
1) Take Mongo backup; freeze Concelier ingest.
2) Apply 21-101 migrations (shards/TTL) — idempotent; record duration.
3) Run 21-102 backfill with `--batch-size=500 --stop-on-error`; capture report hash.
4) Validate counts (observations/linksets/events) and shard balance.
5) Enable outbox publishers; monitor lag and errors.
6) (When ready) apply 21-103 object-store migration: move raw payloads to object store; verify CAS URIs; keep GridFS read-only during move.
## Rollback
- 21-101: restore from backup if shard layout breaks; migrations are idempotent.
- 21-102: run rollback script (`ops/devops/scripts/rollback-lnm-backfill.js`); if inconsistent, restore backup.
- 21-103: switch back to GridFS URI map; restore seeds.
## Monitoring/alerts
- Migration error count > 0
- Mongo oplog lag > 60s during backfill
- Outbox backlog growth post-unfreeze
## Owners
- DevOps Guild (pipeline + rollout)
- Concelier Storage Guild (migration content)
- Platform Security (signing policy)

View File

@@ -0,0 +1,42 @@
# Graph Indexer Release/Offline Bundle Plan (DEVOPS-GRAPH-INDEX-28-010-REL)
## Goals
- Publish signed Helm/Compose bundles for Graph Indexer with offline parity.
- Provide SBOM + attestations for images/charts and reproducible artefacts for air-gap kits.
## Artefacts
- Helm chart + values overrides (offline/airgap).
- Docker/OCI images (indexer, api) pinned by digest.
- SBOMs (SPDX JSON) for images and chart.
- Cosign attestations for images and chart tarball.
- Offline bundle: tarball containing images (oras layout), charts, values, SBOMs, attestations, and `SHA256SUMS`.
## Pipeline outline
1) **Build** images (indexer + api) with SBOM generation (`syft`), tag and record digests.
2) **Sign** images with cosign key (KMS for online; file key for offline bundle) and produce attestations.
3) **Chart package**: render chart, package to `.tgz`, generate SBOM for chart, sign with cosign.
4) **Compose export**: render Compose file with pinned digests and non-root users.
5) **Bundle**: assemble offline tarball:
- `images/` oras layout with signed images
- `charts/graph-indexer.tgz` + signature
- `compose/graph-indexer.yml` (pinned digests)
- `sboms/` for images + chart
- `attestations/` (cosign bundles)
- `SHA256SUMS` and `SHA256SUMS.sig`
6) **Verify step**: pipeline stage runs `cosign verify`, `sha256sum --check`, and `helm template` smoke render with airgap values.
7) **Publish**: upload to artefact store + offline kit; write manifest with hashes/versions.
## Security/hardening
- Non-root images, read-only rootfs, drop NET_RAW, seccomp default.
- Telemetry disabled; no registry pulls at runtime.
- mTLS between indexer and dependencies (documented values).
## Evidence to capture
- Image digests, SBOM hashes, cosign verification logs.
- Bundle `SHA256SUMS` and signed manifest.
- Helm/Compose render outputs (short).
## Owners
- DevOps Guild (build/pipeline)
- Graph Indexer Guild (chart/values)
- Platform Security (signing policy)

View File

@@ -0,0 +1,48 @@
# Java Analyzer Release Plan (DEVOPS-SCANNER-JAVA-21-011-REL)
## Goal
Publish the Java analyzer plug-in with signed artifacts and offline-ready bundles for CLI/Offline Kit.
## Inputs
- Analyzer JAR(s) + native helpers from dev task 21-011.
- SBOM (SPDX JSON) for plugin + native components.
- Test suite outputs (unit + integration).
## Artifacts
- OCI image (optional) or zip bundle containing:
- `analyzer.jar`
- `lib/` natives (if any)
- `LICENSE`, `NOTICE`
- `SBOM` (spdx.json)
- `SIGNATURES` (cosign/PGP)
- Cosign attestations for OCI/zip (provenance + SBOM).
- Checksums: `SHA256SUMS`, `SHA256SUMS.sig`.
- Offline kit slice: tarball with bundle + attestations + SBOM.
## Pipeline steps
1) **Build**: run gradle/mvn with `--offline` using vendored deps; produce JAR + natives.
2) **SBOM**: `syft packages -o spdx-json` over build output.
3) **Package**: zip bundle with fixed ordering (`zip -X`) and normalized timestamps (`SOURCE_DATE_EPOCH`).
4) **Sign**:
- cosign sign blob (zip) and/or image.
- generate in-toto provenance (SLSA level 1) referencing git commit + toolchain hashes.
5) **Checksums**: create `SHA256SUMS` and sign with cosign/PGP.
6) **Verify stage**: pipeline step runs `cosign verify-blob`, `sha256sum --check`, and `syft validate spdx`.
7) **Publish**:
- Upload to artifact store (release bucket) with metadata (version, commit, digest).
- Produce offline kit slice tarball (`scanner-java-<ver>-offline.tgz`) containing bundle, SBOM, attestations, checksums.
## Security/hardening
- Non-root build container; disable gradle/mvn network (`--offline`).
- Strip debug info unless required; ensure reproducible JAR (sorted entries, normalized timestamps).
- Telemetry disabled.
## Evidence to capture
- Bundle SHA256, cosign signatures, provenance statement.
- SBOM hash.
- Verification logs from pipeline.
## Owners
- Build/pipeline: DevOps Guild
- Signing policy: Platform Security
- Consumer integration: CLI Guild / Offline Kit Guild

View File

@@ -0,0 +1,26 @@
{
"schemaVersion": "1.0.0",
"bundleId": "00000000-0000-0000-0000-000000000001",
"createdAt": "2025-12-01T00:00:00Z",
"profileHash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"collectorVersion": "otelcol/1.0.0",
"sealedMode": true,
"redactionManifest": "redaction-manifest.json",
"manifestHashAlgorithm": "sha256",
"timeAnchor": {
"type": "rfc3161",
"value": "dummy-token"
},
"artifacts": [
{
"path": "logs.ndjson",
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"mediaType": "application/x-ndjson",
"size": 123
}
],
"dsseEnvelope": {
"hash": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"location": "bundle.dsse.json"
}
}

View File

@@ -0,0 +1 @@
6e3fedbf183aece5dfa14a90ebce955e2887d36747c424e628dc2cc03bcb0ed3 ops/devops/telemetry/tests/manifest-valid.json

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
set -euo pipefail
# Minimal offline verifier for telemetry bundles (v1)
# Exits:
# 0 success
# 21 checksum/manifest missing
# 22 checksum mismatch
# 23 schema validation failed
BUNDLE=${1:-}
if [[ -z "$BUNDLE" ]]; then
echo "Usage: $0 path/to/telemetry-bundle.tar" >&2
exit 64
fi
WORKDIR=$(mktemp -d)
cleanup() { rm -rf "$WORKDIR"; }
trap cleanup EXIT
tar --extract --file "$BUNDLE" --directory "$WORKDIR"
MANIFEST="$WORKDIR/telemetry-bundle.json"
HASHES="$WORKDIR/telemetry-bundle.sha256"
if [[ ! -f "$MANIFEST" || ! -f "$HASHES" ]]; then
echo "Missing manifest or checksum file." >&2
exit 21
fi
# Verify checksums
pushd "$WORKDIR" >/dev/null
if ! sha256sum --quiet --check telemetry-bundle.sha256; then
echo "Checksum mismatch." >&2
exit 22
fi
popd >/dev/null
# JSON schema validation (optional if jsonschema not present).
if command -v python >/dev/null 2>&1; then
SCHEMA_DIR="$(cd "$(dirname "$0")/../../docs/modules/telemetry/schemas" && pwd)"
SCHEMA_FILE="$SCHEMA_DIR/telemetry-bundle.schema.json"
if [[ -f "$SCHEMA_FILE" ]]; then
python - "$MANIFEST" "$SCHEMA_FILE" <<'PY'
import json, sys
from jsonschema import validate, Draft202012Validator
manifest_path = sys.argv[1]
schema_path = sys.argv[2]
with open(manifest_path, 'r', encoding='utf-8') as f:
manifest = json.load(f)
with open(schema_path, 'r', encoding='utf-8') as f:
schema = json.load(f)
Draft202012Validator.check_schema(schema)
validate(manifest, schema)
PY
if [[ $? -ne 0 ]]; then
echo "Schema validation failed." >&2
exit 23
fi
else
echo "Schema file not found ($SCHEMA_FILE); skipping validation." >&2
fi
else
echo "jsonschema validation skipped (requires python + jsonschema)." >&2
fi
echo "Telemetry bundle verified." >&2
exit 0

View File

@@ -4,14 +4,22 @@ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
export DOTNET_CLI_HOME="${DOTNET_CLI_HOME:-${ROOT_DIR}/.dotnet-cli}"
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_NOLOGO=1
export DOTNET_MULTILEVEL_LOOKUP=0
export MSBUILDDISABLENODEREUSE=1
export DOTNET_HOST_DISABLE_RESOLVER_FALLBACK=1
PROJECT="${ROOT_DIR}/src/Scanner/__Tests/StellaOps.Scanner.Analyzers.Lang.Node.SmokeTests/StellaOps.Scanner.Analyzers.Lang.Node.SmokeTests.csproj"
RESTORE_SRC="${ROOT_DIR}/local-nugets"
mkdir -p "$DOTNET_CLI_HOME"
DOTNET_RESTORE_ARGS=("restore" "$PROJECT" "--no-cache" "--disable-parallel" "/p:RestoreSources=${RESTORE_SRC}")
DOTNET_TEST_ARGS=("test" "$PROJECT" "-c" "Release" "--no-build" "--no-restore" "--filter" "Phase22_Fixture_Matches_Golden" "--logger" "trx" "--results-directory" "${ROOT_DIR}/TestResults/phase22-smoke" "/p:RestoreSources=${RESTORE_SRC}" "/p:DisableSdkResolverCache=true")
DOTNET_RESTORE_ARGS=("restore" "$PROJECT" "--no-cache" "--disable-parallel" "/p:RestoreSources=${RESTORE_SRC}" "/p:DisableSdkResolverCache=true" "/p:DisableImplicitNuGetFallbackFolder=true" "/p:RestoreNoCache=true")
DOTNET_BUILD_ARGS=("build" "$PROJECT" "-c" "Release" "--no-restore" "/p:RestoreSources=${RESTORE_SRC}" "/p:DisableSdkResolverCache=true" "/p:DisableImplicitNuGetFallbackFolder=true")
DOTNET_TEST_ARGS=("test" "$PROJECT" "-c" "Release" "--no-build" "--no-restore" "--filter" "Phase22_Fixture_Matches_Golden" "--logger" "trx" "--results-directory" "${ROOT_DIR}/TestResults/phase22-smoke" "/p:RestoreSources=${RESTORE_SRC}" "/p:DisableSdkResolverCache=true" "/p:DisableImplicitNuGetFallbackFolder=true")
echo "[phase22-smoke] restoring from ${RESTORE_SRC} ..."
dotnet "${DOTNET_RESTORE_ARGS[@]}"
echo "[phase22-smoke] building smoke project ..."
dotnet "${DOTNET_BUILD_ARGS[@]}"
echo "[phase22-smoke] running test ..."
dotnet "${DOTNET_TEST_ARGS[@]}"

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Repo root is four levels up from Graph/
REPO_ROOT="$(cd "${ROOT}/../../../.." && pwd)"
FIXTURES_ROOT="${FIXTURES_ROOT:-${REPO_ROOT}/samples/graph/interim}"
OUT_DIR="${OUT_DIR:-$ROOT/results}"
SAMPLES="${SAMPLES:-100}"
mkdir -p "${OUT_DIR}"
run_one() {
local fixture="$1"
local name
name="$(basename "${fixture}")"
local out_file="${OUT_DIR}/${name}.json"
python "${ROOT}/graph_bench.py" --fixture "${fixture}" --output "${out_file}" --samples "${SAMPLES}"
}
run_one "${FIXTURES_ROOT}/graph-50k"
run_one "${FIXTURES_ROOT}/graph-100k"
echo "Graph bench complete. Results in ${OUT_DIR}"

View File

@@ -0,0 +1,50 @@
#!/usr/bin/env node
/**
* ui_bench_driver.mjs
*
* Reads scenarios and fixture manifest, and emits a deterministic run plan.
* This is browser-free; intended to be wrapped by Playwright later.
*/
import fs from "fs";
import path from "path";
function readJson(p) {
return JSON.parse(fs.readFileSync(p, "utf-8"));
}
function buildPlan(scenarios, manifest, fixtureName) {
const now = new Date().toISOString();
return {
version: "1.0.0",
fixture: fixtureName,
manifestHash: manifest?.hashes || {},
timestamp: now,
steps: scenarios.map((s, idx) => ({
order: idx + 1,
id: s.id,
name: s.name,
actions: s.steps,
})),
};
}
function main() {
const fixtureDir = process.argv[2];
const scenariosPath = process.argv[3];
const outputPath = process.argv[4];
if (!fixtureDir || !scenariosPath || !outputPath) {
console.error("usage: ui_bench_driver.mjs <fixture_dir> <scenarios.json> <output.json>");
process.exit(1);
}
const manifestPath = path.join(fixtureDir, "manifest.json");
const manifest = fs.existsSync(manifestPath) ? readJson(manifestPath) : {};
const scenarios = readJson(scenariosPath).scenarios || [];
const plan = buildPlan(scenarios, manifest, path.basename(fixtureDir));
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, JSON.stringify(plan, null, 2));
console.log(`Wrote plan to ${outputPath}`);
}
main();

View File

@@ -0,0 +1,30 @@
# Graph UI Bench Plan (BENCH-GRAPH-21-002)
Purpose: provide a deterministic, headless flow for measuring graph UI interactions over large fixtures (50k/100k nodes).
## Scope
- Use synthetic fixtures under `samples/graph/interim/` until canonical SAMPLES-GRAPH-24-003 lands.
- Drive a deterministic sequence of interactions:
1) Load graph canvas with specified fixture.
2) Pan to node `pkg-000001`.
3) Zoom in 2×, zoom out 1×.
4) Apply filter `name contains "package-0001"`.
5) Select node, expand neighbors (depth 1), collapse.
6) Toggle overlay layer (once available).
- Capture timings: initial render, filter apply, expand/collapse, overlay toggle.
## Determinism rules
- Fixed seed for any randomized layouts (seed `424242`).
- Disable animations/transitions where possible; otherwise measure after `requestAnimationFrame` settle.
- No network calls; fixtures loaded from local file served by test harness.
- Stable viewport (width=1280, height=720), device scale factor 1.
## Artifacts
- `ui_bench_scenarios.json` — canonical scenario list with step ids and notes.
- `ui_bench_driver.mjs` — helper that reads scenario + fixture manifest and emits a run plan (no browser dependency). Intended to be wrapped by a Playwright script later.
- Results format (proposed): NDJSON with `{stepId, name, durationMs, fixture, timestamp}`.
## Next steps
- Bind `ui_bench_driver.mjs` into a Playwright harness when Graph UI build/serve target is available.
- Swap fixtures to SAMPLES-GRAPH-24-003 + overlay once schema finalized; keep scenario ids stable.
- Add CI slice to run the driver and validate scenario/fixture bindings (no browser) to keep determinism checked in commits.

View File

@@ -0,0 +1,35 @@
{
"version": "1.0.0",
"scenarios": [
{
"id": "load",
"name": "Load graph canvas",
"steps": ["navigate", "waitForRender"]
},
{
"id": "pan-start-node",
"name": "Pan to pkg-000001",
"steps": ["panTo:pkg-000001"]
},
{
"id": "zoom-in-out",
"name": "Zoom in twice, out once",
"steps": ["zoomIn", "zoomIn", "zoomOut"]
},
{
"id": "filter-name",
"name": "Filter name contains package-0001",
"steps": ["setFilter:name=package-0001", "waitForRender"]
},
{
"id": "expand-collapse",
"name": "Expand neighbors then collapse",
"steps": ["select:pkg-000001", "expandDepth:1", "collapseSelection"]
},
{
"id": "overlay-toggle",
"name": "Toggle overlay layer",
"steps": ["toggleOverlay:on", "toggleOverlay:off"]
}
]
}

View File

@@ -4,3 +4,4 @@
| --- | --- | --- | --- | --- |
| BENCH-DETERMINISM-401-057 | DONE (2025-11-26) | SPRINT_0512_0001_0001_bench | Determinism harness and mock scanner added under `src/Bench/StellaOps.Bench/Determinism`; manifests + sample inputs included. | `src/Bench/StellaOps.Bench/Determinism/results` (generated) |
| BENCH-GRAPH-21-001 | DOING (2025-12-01) | SPRINT_0512_0001_0001_bench | Added interim graph bench harness (`Graph/graph_bench.py`) using synthetic 50k/100k fixtures; measures adjacency build + depth-3 reach; pending overlay schema for final fixture integration. | `src/Bench/StellaOps.Bench/Graph` |
| BENCH-GRAPH-21-002 | DOING (2025-12-01) | SPRINT_0512_0001_0001_bench | Added Graph UI bench scaffold (scenarios JSON + driver + plan) using interim fixtures; awaits overlay schema/UI target for Playwright binding and timing collection. | `src/Bench/StellaOps.Bench/Graph` |

View File

@@ -53,6 +53,32 @@ internal static class CommandHandlers
WriteIndented = true
};
private static async Task VerifyBundleAsync(string path, ILogger logger, CancellationToken cancellationToken)
{
// Simple SHA256 check using sidecar .sha256 file if present; fail closed on mismatch.
var shaPath = path + ".sha256";
if (!File.Exists(shaPath))
{
logger.LogError("Checksum file missing for bundle {Bundle}. Expected sidecar {Sidecar}.", path, shaPath);
Environment.ExitCode = 21;
throw new InvalidOperationException("Checksum file missing");
}
var expected = (await File.ReadAllTextAsync(shaPath, cancellationToken).ConfigureAwait(false)).Trim();
using var stream = File.OpenRead(path);
var hash = await SHA256.HashDataAsync(stream, cancellationToken).ConfigureAwait(false);
var actual = Convert.ToHexString(hash).ToLowerInvariant();
if (!string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase))
{
logger.LogError("Checksum mismatch for {Bundle}. Expected {Expected} but found {Actual}", path, expected, actual);
Environment.ExitCode = 22;
throw new InvalidOperationException("Checksum verification failed");
}
logger.LogInformation("Checksum verified for {Bundle}", path);
}
public static async Task HandleScannerDownloadAsync(
IServiceProvider services,
string channel,
@@ -90,6 +116,8 @@ internal static class CommandHandlers
if (install)
{
await VerifyBundleAsync(result.Path, logger, cancellationToken).ConfigureAwait(false);
var installer = scope.ServiceProvider.GetRequiredService<IScannerInstaller>();
await installer.InstallAsync(result.Path, verbose, cancellationToken).ConfigureAwait(false);
CliMetrics.RecordScannerInstall(channel);
@@ -100,7 +128,10 @@ internal static class CommandHandlers
catch (Exception ex)
{
logger.LogError(ex, "Failed to download scanner bundle.");
Environment.ExitCode = 1;
if (Environment.ExitCode == 0)
{
Environment.ExitCode = 1;
}
}
finally
{

View File

@@ -107,9 +107,9 @@ public sealed class CliProfileStore
public Dictionary<string, CliProfile> Profiles { get; init; } = new(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Default telemetry opt-in status.
/// Default telemetry opt-in status. Defaults to false for privacy.
/// </summary>
public bool? TelemetryEnabled { get; set; }
public bool TelemetryEnabled { get; set; } = false;
}
/// <summary>
@@ -225,7 +225,7 @@ public sealed class CliProfileManager
public async Task SetTelemetryEnabledAsync(bool? enabled, CancellationToken cancellationToken = default)
{
var store = await GetStoreAsync(cancellationToken).ConfigureAwait(false);
store.TelemetryEnabled = enabled;
store.TelemetryEnabled = enabled ?? false;
await SaveStoreAsync(store, cancellationToken).ConfigureAwait(false);
}
@@ -247,7 +247,18 @@ public sealed class CliProfileManager
{
await using var stream = File.OpenRead(_profilesFilePath);
var store = await JsonSerializer.DeserializeAsync<CliProfileStore>(stream, JsonOptions, cancellationToken).ConfigureAwait(false);
return store ?? new CliProfileStore();
if (store is null)
{
return new CliProfileStore();
}
// Ensure default-off if older files had telemetryEnabled missing/null.
if (!store.TelemetryEnabled)
{
store.TelemetryEnabled = false;
}
return store;
}
catch (JsonException)
{

View File

@@ -0,0 +1,60 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Cli.Commands;
using Xunit;
namespace StellaOps.Cli.Tests.Commands;
public sealed class ScannerDownloadVerifyTests
{
[Fact]
public async Task VerifyBundleAsync_Succeeds_WhenHashMatches()
{
var tmp = Path.Combine(Path.GetTempPath(), $"stellaops-cli-{Guid.NewGuid():N}");
Directory.CreateDirectory(tmp);
var bundle = Path.Combine(tmp, "scanner.tgz");
await File.WriteAllTextAsync(bundle, "hello");
var hash = Convert.ToHexString(System.Security.Cryptography.SHA256.HashData(File.ReadAllBytes(bundle))).ToLowerInvariant();
await File.WriteAllTextAsync(bundle + ".sha256", hash);
await CommandHandlersTestShim.VerifyBundlePublicAsync(bundle, NullLogger.Instance, CancellationToken.None);
}
[Fact]
public async Task VerifyBundleAsync_Throws_WhenHashMismatch()
{
var tmp = Path.Combine(Path.GetTempPath(), $"stellaops-cli-{Guid.NewGuid():N}");
Directory.CreateDirectory(tmp);
var bundle = Path.Combine(tmp, "scanner.tgz");
await File.WriteAllTextAsync(bundle, "hello");
await File.WriteAllTextAsync(bundle + ".sha256", "deadbeef");
await Assert.ThrowsAsync<InvalidOperationException>(() =>
CommandHandlersTestShim.VerifyBundlePublicAsync(bundle, NullLogger.Instance, CancellationToken.None));
}
[Fact]
public async Task VerifyBundleAsync_Throws_WhenChecksumMissing()
{
var tmp = Path.Combine(Path.GetTempPath(), $"stellaops-cli-{Guid.NewGuid():N}");
Directory.CreateDirectory(tmp);
var bundle = Path.Combine(tmp, "scanner.tgz");
await File.WriteAllTextAsync(bundle, "hello");
await Assert.ThrowsAsync<InvalidOperationException>(() =>
CommandHandlersTestShim.VerifyBundlePublicAsync(bundle, NullLogger.Instance, CancellationToken.None));
}
}
internal static class CommandHandlersTestShim
{
public static Task VerifyBundlePublicAsync(string path, ILogger logger, CancellationToken token)
=> typeof(CommandHandlers)
.GetMethod(\"VerifyBundleAsync\", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)!
.Invoke(null, new object[] { path, logger, token }) as Task
?? Task.CompletedTask;
}

View File

@@ -0,0 +1,35 @@
using System.IO;
using System.Threading.Tasks;
using StellaOps.Cli.Configuration;
using Xunit;
namespace StellaOps.Cli.Tests.Configuration;
public sealed class TelemetryDefaultsTests
{
[Fact]
public async Task NewStore_DefaultsTelemetryToOff()
{
var tempDir = Path.Combine(Path.GetTempPath(), $"stellaops-cli-telemetry-{Path.GetRandomFileName()}");
Directory.CreateDirectory(tempDir);
var manager = new CliProfileManager(tempDir);
var store = await manager.GetStoreAsync();
Assert.False(store.TelemetryEnabled);
}
[Fact]
public async Task SetTelemetryEnabled_PersistsValue()
{
var tempDir = Path.Combine(Path.GetTempPath(), $"stellaops-cli-telemetry-{Path.GetRandomFileName()}");
Directory.CreateDirectory(tempDir);
var manager = new CliProfileManager(tempDir);
await manager.SetTelemetryEnabledAsync(true);
var store = await manager.GetStoreAsync();
Assert.True(store.TelemetryEnabled);
}
}

View File

@@ -0,0 +1,41 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
namespace StellaOps.Cli.Tests.Contracts;
public sealed class CliSpecTests
{
private static readonly string SpecPath = Path.Combine("docs", "modules", "cli", "contracts", "cli-spec-v1.yaml");
[Fact]
public async Task Spec_Exists_And_Has_PrivacyDefaults()
{
Assert.True(File.Exists(SpecPath), $"Spec file missing: {SpecPath}");
var text = await File.ReadAllTextAsync(SpecPath);
Assert.Contains("defaultEnabled: false", text);
Assert.Contains("checksumRequired: true", text);
Assert.Contains("cosignVerifyDefault: true", text);
}
[Fact]
public async Task Spec_Has_Pinned_Buildx_Digest()
{
var text = await File.ReadAllLinesAsync(SpecPath);
var digestLine = text.FirstOrDefault(l => l.TrimStart().StartsWith("imageDigest:"));
Assert.False(string.IsNullOrWhiteSpace(digestLine));
Assert.DoesNotContain("TO-BE-PINNED", digestLine);
}
[Fact]
public async Task Spec_Declares_Install_ExitCodes()
{
var text = await File.ReadAllTextAsync(SpecPath);
Assert.Contains("21: checksum-file-missing", text);
Assert.Contains("22: checksum-mismatch", text);
}
}

View File

@@ -1,3 +1,5 @@
using StellaOps.Orchestrator.Core.Hashing;
namespace StellaOps.Orchestrator.Core.Domain;
/// <summary>
@@ -90,9 +92,22 @@ public sealed record AuditEntry(
var entryId = Guid.NewGuid();
var occurredAt = DateTimeOffset.UtcNow;
// Compute content hash from entry data
var contentToHash = $"{entryId}|{tenantId}|{eventType}|{resourceType}|{resourceId}|{actorId}|{actorType}|{description}|{oldState}|{newState}|{occurredAt:O}|{sequenceNumber}";
var contentHash = ComputeSha256(contentToHash);
// Compute canonical hash from immutable content
var contentHash = CanonicalJsonHasher.ComputeCanonicalSha256(new
{
entryId,
tenantId,
eventType,
resourceType,
resourceId,
actorId,
actorType,
description,
oldState,
newState,
occurredAt,
sequenceNumber
});
return new AuditEntry(
EntryId: entryId,
@@ -122,8 +137,21 @@ public sealed record AuditEntry(
/// </summary>
public bool VerifyIntegrity()
{
var contentToHash = $"{EntryId}|{TenantId}|{EventType}|{ResourceType}|{ResourceId}|{ActorId}|{ActorType}|{Description}|{OldState}|{NewState}|{OccurredAt:O}|{SequenceNumber}";
var computed = ComputeSha256(contentToHash);
var computed = CanonicalJsonHasher.ComputeCanonicalSha256(new
{
EntryId,
TenantId,
EventType,
ResourceType,
ResourceId,
ActorId,
ActorType,
Description,
OldState,
NewState,
OccurredAt,
SequenceNumber
});
return string.Equals(ContentHash, computed, StringComparison.OrdinalIgnoreCase);
}

View File

@@ -0,0 +1,72 @@
using System.Collections.Immutable;
using System.Text.Json.Serialization;
using StellaOps.Orchestrator.Core.Hashing;
namespace StellaOps.Orchestrator.Core.Domain.Replay;
/// <summary>
/// Deterministic replay manifest that captures all inputs required to faithfully re-run a job.
/// Aligns with replay-manifest.schema.json and is hashed via canonical JSON.
/// </summary>
public sealed record ReplayManifest(
[property: JsonPropertyName("schemaVersion")] string SchemaVersion,
[property: JsonPropertyName("jobId")] string JobId,
[property: JsonPropertyName("replayOf")] string ReplayOf,
[property: JsonPropertyName("createdAt")] DateTimeOffset CreatedAt,
[property: JsonPropertyName("reason")] string? Reason,
[property: JsonPropertyName("inputs")] ReplayInputs Inputs,
[property: JsonPropertyName("artifacts")] ImmutableArray<ReplayArtifact> Artifacts)
{
public static ReplayManifest Create(
string jobId,
string replayOf,
ReplayInputs inputs,
IEnumerable<ReplayArtifact>? artifacts = null,
string schemaVersion = "orch.replay.v1",
string? reason = null,
DateTimeOffset? createdAt = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(jobId);
ArgumentException.ThrowIfNullOrWhiteSpace(replayOf);
ArgumentNullException.ThrowIfNull(inputs);
return new ReplayManifest(
SchemaVersion: schemaVersion,
JobId: jobId,
ReplayOf: replayOf,
CreatedAt: createdAt ?? DateTimeOffset.UtcNow,
Reason: string.IsNullOrWhiteSpace(reason) ? null : reason,
Inputs: inputs,
Artifacts: artifacts is null ? ImmutableArray<ReplayArtifact>.Empty : ImmutableArray.CreateRange(artifacts));
}
/// <summary>
/// Deterministic SHA-256 over canonical JSON representation of the manifest.
/// </summary>
public string ComputeHash() => CanonicalJsonHasher.ComputeCanonicalSha256(this);
}
public sealed record ReplayInputs(
[property: JsonPropertyName("policyHash")] string PolicyHash,
[property: JsonPropertyName("graphRevisionId")] string GraphRevisionId,
[property: JsonPropertyName("latticeHash")] string? LatticeHash,
[property: JsonPropertyName("toolImages")] ImmutableArray<string> ToolImages,
[property: JsonPropertyName("seeds")] ReplaySeeds Seeds,
[property: JsonPropertyName("timeSource")] ReplayTimeSource TimeSource,
[property: JsonPropertyName("env")] ImmutableDictionary<string, string> Env);
public sealed record ReplaySeeds(
[property: JsonPropertyName("rng")] int? Rng,
[property: JsonPropertyName("sampling")] int? Sampling);
public sealed record ReplayArtifact(
[property: JsonPropertyName("name")] string Name,
[property: JsonPropertyName("digest")] string Digest,
[property: JsonPropertyName("mediaType")] string? MediaType);
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum ReplayTimeSource
{
monotonic,
wall
}

View File

@@ -0,0 +1,66 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace StellaOps.Orchestrator.Core.Hashing;
/// <summary>
/// Produces deterministic, canonical JSON and hashes for orchestrator payloads (events, audit, manifests).
/// Keys are sorted lexicographically; arrays preserve order; nulls are retained; timestamps remain ISO 8601 with offsets.
/// </summary>
public static class CanonicalJsonHasher
{
private static readonly JsonSerializerOptions SerializerOptions = new()
{
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
WriteIndented = false,
PropertyNamingPolicy = null,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }
};
/// <summary>
/// Serialize the value to canonical JSON (sorted object keys, stable formatting).
/// </summary>
public static string ToCanonicalJson<T>(T value)
{
var node = JsonSerializer.SerializeToNode(value, SerializerOptions) ?? new JsonObject();
var ordered = OrderNode(node);
return ordered.ToJsonString(SerializerOptions);
}
/// <summary>
/// Compute SHA-256 over canonical JSON (lowercase hex).
/// </summary>
public static string ComputeCanonicalSha256<T>(T value)
{
var canonicalJson = ToCanonicalJson(value);
var bytes = Encoding.UTF8.GetBytes(canonicalJson);
var hash = SHA256.HashData(bytes);
return Convert.ToHexString(hash).ToLowerInvariant();
}
private static JsonNode OrderNode(JsonNode node)
{
switch (node)
{
case JsonObject obj:
var orderedObj = new JsonObject();
foreach (var kvp in obj.OrderBy(x => x.Key, StringComparer.Ordinal))
{
orderedObj.Add(kvp.Key, kvp.Value is null ? null : OrderNode(kvp.Value));
}
return orderedObj;
case JsonArray arr:
var orderedArr = new JsonArray();
foreach (var item in arr)
{
orderedArr.Add(item is null ? null : OrderNode(item));
}
return orderedArr;
default:
return node; // primitives stay as-is
}
}
}

View File

@@ -0,0 +1,51 @@
{
"$id": "https://stellaops.dev/orchestrator/schemas/audit-bundle.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Orchestrator Audit Bundle",
"type": "object",
"additionalProperties": false,
"required": ["manifestVersion", "bundleId", "createdAt", "entries"],
"properties": {
"manifestVersion": { "type": "string", "pattern": "^orch\.audit\.v[0-9]+$" },
"bundleId": { "type": "string", "minLength": 1 },
"createdAt": { "type": "string", "format": "date-time" },
"tenantId": { "type": "string" },
"hashAlgorithm": { "type": "string", "enum": ["sha256"] },
"entries": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["entryId", "contentHash", "sequenceNumber", "occurredAt"],
"properties": {
"entryId": { "type": "string" },
"contentHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"previousEntryHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
"sequenceNumber": { "type": "integer", "minimum": 1 },
"occurredAt": { "type": "string", "format": "date-time" },
"resourceType": { "type": "string" },
"resourceId": { "type": "string" },
"eventType": { "type": "string" },
"actorId": { "type": "string" },
"actorType": { "type": "string" },
"oldState": { "type": "string" },
"newState": { "type": "string" },
"metadata": { "type": "string" }
}
}
},
"attachments": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["uri", "digest"],
"properties": {
"uri": { "type": "string" },
"digest": { "type": "string", "pattern": "^[a-z0-9]+:[A-Fa-f0-9]+$" },
"mediaType": { "type": "string" }
}
}
}
}
}

View File

@@ -0,0 +1,95 @@
{
"$id": "https://stellaops.dev/orchestrator/schemas/event-envelope.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Orchestrator Event Envelope",
"type": "object",
"additionalProperties": false,
"required": [
"schemaVersion",
"eventId",
"eventType",
"occurredAt",
"idempotencyKey",
"tenantId",
"actor",
"job"
],
"properties": {
"schemaVersion": { "type": "string", "pattern": "^orch\.event\.v[0-9]+$" },
"eventId": { "type": "string", "minLength": 1 },
"eventType": { "type": "string", "minLength": 1 },
"occurredAt": { "type": "string", "format": "date-time" },
"idempotencyKey": { "type": "string", "minLength": 1 },
"correlationId": { "type": "string" },
"tenantId": { "type": "string", "minLength": 1 },
"projectId": { "type": "string" },
"actor": {
"type": "object",
"additionalProperties": false,
"required": ["subject", "scopes"],
"properties": {
"subject": { "type": "string", "minLength": 1 },
"scopes": { "type": "array", "items": { "type": "string" } }
}
},
"job": {
"type": "object",
"additionalProperties": false,
"required": ["id", "type", "attempt", "status"],
"properties": {
"id": { "type": "string", "minLength": 1 },
"type": { "type": "string", "minLength": 1 },
"runId": { "type": "string" },
"attempt": { "type": "integer", "minimum": 0 },
"leaseId": { "type": "string" },
"taskRunnerId": { "type": "string" },
"status": { "type": "string" },
"reason": { "type": "string" },
"payloadDigest": { "type": "string" },
"artifacts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["uri", "digest"],
"properties": {
"uri": { "type": "string" },
"digest": { "type": "string" },
"mime": { "type": "string" }
}
}
},
"provenance": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
},
"metrics": {
"type": "object",
"additionalProperties": false,
"properties": {
"durationSeconds": { "type": "number", "minimum": 0 },
"logStreamLagSeconds": { "type": "number", "minimum": 0 },
"backoffSeconds": { "type": "number", "minimum": 0 }
}
},
"notifier": {
"type": "object",
"additionalProperties": false,
"properties": {
"channel": { "type": "string" },
"delivery": { "type": "string" },
"replay": {
"type": "object",
"additionalProperties": false,
"required": ["ordinal", "total"],
"properties": {
"ordinal": { "type": "integer", "minimum": 0 },
"total": { "type": "integer", "minimum": 1 }
}
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
{
"$id": "https://stellaops.dev/orchestrator/schemas/replay-manifest.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Replay Manifest",
"type": "object",
"additionalProperties": false,
"required": ["schemaVersion", "jobId", "replayOf", "inputs"],
"properties": {
"schemaVersion": { "type": "string", "pattern": "^orch\.replay\.v[0-9]+$" },
"jobId": { "type": "string" },
"replayOf": { "type": "string" },
"createdAt": { "type": "string", "format": "date-time" },
"reason": { "type": "string" },
"inputs": {
"type": "object",
"additionalProperties": false,
"required": ["policyHash", "graphRevisionId", "toolImages", "seeds"],
"properties": {
"policyHash": { "type": "string" },
"graphRevisionId": { "type": "string" },
"latticeHash": { "type": "string" },
"toolImages": {
"type": "array",
"items": { "type": "string" }
},
"seeds": {
"type": "object",
"additionalProperties": false,
"properties": {
"rng": { "type": "integer", "minimum": 0 },
"sampling": { "type": "integer", "minimum": 0 }
}
},
"timeSource": { "type": "string", "enum": ["monotonic", "wall"] },
"env": {
"type": "object",
"additionalProperties": { "type": "string" }
}
}
},
"artifacts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["name", "digest"],
"properties": {
"name": { "type": "string" },
"digest": { "type": "string" },
"mediaType": { "type": "string" }
}
}
}
}
}

View File

@@ -0,0 +1,51 @@
{
"$id": "https://stellaops.dev/orchestrator/schemas/taskrunner-integrity.schema.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "TaskRunner Integrity Capsule",
"type": "object",
"additionalProperties": false,
"required": ["jobId", "runId", "attempt", "artifacts", "logs"],
"properties": {
"jobId": { "type": "string" },
"runId": { "type": "string" },
"attempt": { "type": "integer", "minimum": 0 },
"workerImage": { "type": "string" },
"configHash": { "type": "string" },
"artifacts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["name", "digest", "sizeBytes"],
"properties": {
"name": { "type": "string" },
"digest": { "type": "string", "pattern": "^[a-z0-9]+:[A-Fa-f0-9]+$" },
"sizeBytes": { "type": "integer", "minimum": 0 },
"mediaType": { "type": "string" }
}
}
},
"logs": {
"type": "object",
"additionalProperties": false,
"required": ["digest", "sizeBytes"],
"properties": {
"digest": { "type": "string", "pattern": "^[a-z0-9]+:[A-Fa-f0-9]+$" },
"sizeBytes": { "type": "integer", "minimum": 0 }
}
},
"timeline": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": ["type", "occurredAt"],
"properties": {
"type": { "type": "string" },
"occurredAt": { "type": "string", "format": "date-time" },
"traceId": { "type": "string" }
}
}
}
}
}

View File

@@ -0,0 +1,54 @@
using System.Text.Json;
using StellaOps.Orchestrator.Core.Domain;
using StellaOps.Orchestrator.Core.Hashing;
namespace StellaOps.Orchestrator.Tests;
public class CanonicalJsonHasherTests
{
[Fact]
public void ProducesStableHash_WhenObjectPropertyOrderDiffers()
{
var first = new { b = 1, a = 2 };
var second = new { a = 2, b = 1 };
var firstHash = CanonicalJsonHasher.ComputeCanonicalSha256(first);
var secondHash = CanonicalJsonHasher.ComputeCanonicalSha256(second);
Assert.Equal(firstHash, secondHash);
}
[Fact]
public void CanonicalJson_SortsKeysAndPreservesArrays()
{
var value = new
{
meta = new { z = 1, a = 2 },
items = new[] { "first", "second" }
};
var json = CanonicalJsonHasher.ToCanonicalJson(value);
// keys sorted inside meta
Assert.Equal("{\"items\":[\"first\",\"second\"],\"meta\":{\"a\":2,\"z\":1}}", json);
}
[Fact]
public void AuditEntry_UsesCanonicalHash()
{
var entry = AuditEntry.Create(
tenantId: "tenant-1",
eventType: AuditEventType.JobCreated,
resourceType: "job",
resourceId: Guid.Parse("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"),
actorId: "user-1",
actorType: ActorType.User,
description: "created job");
Assert.True(entry.VerifyIntegrity());
// Changing description should invalidate hash
var tampered = entry with { Description = "tampered" };
Assert.False(tampered.VerifyIntegrity());
}
}

View File

@@ -203,7 +203,6 @@ public sealed class PackRunStreamCoordinatorTests
public override void Dispose()
{
_state = WebSocketState.Closed;
base.Dispose();
}
public override Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken)

View File

@@ -0,0 +1,39 @@
using System.Collections.Immutable;
using StellaOps.Orchestrator.Core.Domain.Replay;
namespace StellaOps.Orchestrator.Tests;
public class ReplayManifestTests
{
[Fact]
public void ComputeHash_IsStableWithCanonicalOrdering()
{
var inputs = new ReplayInputs(
PolicyHash: "sha256:policy",
GraphRevisionId: "graph-42",
LatticeHash: "sha256:lattice",
ToolImages: ImmutableArray.Create("img:1", "img:2"),
Seeds: new ReplaySeeds(Rng: 1234, Sampling: 99),
TimeSource: ReplayTimeSource.monotonic,
Env: ImmutableDictionary.Create<string, string>().Add("TZ", "UTC"));
var manifestA = ReplayManifest.Create(
jobId: "job-123",
replayOf: "job-original",
inputs: inputs,
artifacts: new[] { new ReplayArtifact("ledger.ndjson", "sha256:abc", "application/x-ndjson") },
createdAt: new DateTimeOffset(2025, 12, 1, 0, 0, 0, TimeSpan.Zero));
var manifestB = ReplayManifest.Create(
jobId: "job-123",
replayOf: "job-original",
inputs: inputs,
artifacts: new[] { new ReplayArtifact("ledger.ndjson", "sha256:abc", "application/x-ndjson") },
createdAt: new DateTimeOffset(2025, 12, 1, 0, 0, 0, TimeSpan.Zero));
var hashA = manifestA.ComputeHash();
var hashB = manifestB.ComputeHash();
Assert.Equal(hashA, hashB);
}
}

View File

@@ -0,0 +1,56 @@
using System.Collections.Immutable;
using System.Text.Json;
using StellaOps.Orchestrator.Core;
using StellaOps.Orchestrator.Core.Hashing;
namespace StellaOps.Orchestrator.Tests;
public class SchemaSmokeTests
{
[Theory]
[InlineData("event-envelope.schema.json")]
[InlineData("audit-bundle.schema.json")]
[InlineData("replay-manifest.schema.json")]
[InlineData("taskrunner-integrity.schema.json")]
public void Schemas_AreWellFormedJson(string schemaFile)
{
var path = Path.Combine(AppContext.BaseDirectory, "../../../StellaOps.Orchestrator.Core/Schemas", schemaFile);
Assert.True(File.Exists(path), $"Schema missing: {schemaFile}");
var text = File.ReadAllText(path);
using var doc = JsonDocument.Parse(text);
Assert.True(doc.RootElement.TryGetProperty("$id", out _));
Assert.True(doc.RootElement.TryGetProperty("title", out _));
}
[Fact]
public void CanonicalHash_For_EventEnvelope_IsStable()
{
var envelope = EventEnvelope.Create(
eventType: "job.completed",
tenantId: "tenant-a",
job: new EventJob(
Id: "job-123",
Type: "pack-run",
RunId: "run-1",
Attempt: 1,
LeaseId: "lease-9",
TaskRunnerId: "tr-1",
Status: "completed",
Reason: null,
PayloadDigest: "sha256:abc",
Artifacts: ImmutableArray.Create<EventArtifact>(),
Provenance: ImmutableDictionary<string, string>.Empty),
actor: new EventActor("worker-go", ImmutableArray.Create("orch:job")),
occurredAt: new DateTimeOffset(2025, 12, 1, 12, 0, 0, TimeSpan.Zero),
eventId: "evt-1",
idempotencyKey: "fixed");
var hash1 = CanonicalJsonHasher.ComputeCanonicalSha256(envelope);
var hash2 = CanonicalJsonHasher.ComputeCanonicalSha256(envelope);
Assert.Equal(hash1, hash2);
Assert.Equal(64, hash1.Length);
}
}

View File

@@ -257,6 +257,7 @@ internal sealed class SurfaceManifestPublisher : ISurfaceManifestPublisher
ArtifactDocumentFormat.ComponentFragmentJson => "layer.fragments",
ArtifactDocumentFormat.ObservationJson => "observation.json",
ArtifactDocumentFormat.SurfaceManifestJson => "surface.manifest",
ArtifactDocumentFormat.CompositionRecipeJson => "composition.recipe",
ArtifactDocumentFormat.CycloneDxJson => "cdx-json",
ArtifactDocumentFormat.CycloneDxProtobuf => "cdx-protobuf",
ArtifactDocumentFormat.SpdxJson => "spdx-json",

View File

@@ -265,8 +265,8 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
pins["policy"] = policy;
}
var (artifactHashes, merkle) = ComputeDeterminismHashes(payloads);
merkleRoot = merkle;
var (artifactHashes, recipeBytes, recipeSha256) = BuildCompositionRecipe(payloads);
merkleRoot = recipeSha256;
var report = new
{
@@ -277,12 +277,26 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
concurrencyLimit = _determinism.ConcurrencyLimit,
pins = pins,
artifacts = artifactHashes,
merkleRoot = merkle
merkleRoot = recipeSha256
};
var evidence = new Determinism.DeterminismEvidence(artifactHashes, merkle);
var evidence = new Determinism.DeterminismEvidence(artifactHashes, recipeSha256);
context.Analysis.Set(ScanAnalysisKeys.DeterminismEvidence, evidence);
// Publish composition recipe as a manifest artifact for offline replay.
payloads = payloads.ToList();
((List<SurfaceManifestPayload>)payloads).Add(new SurfaceManifestPayload(
ArtifactDocumentType.CompositionRecipe,
ArtifactDocumentFormat.CompositionRecipeJson,
Kind: "composition.recipe",
MediaType: "application/vnd.stellaops.composition.recipe+json",
Content: recipeBytes,
Metadata: new Dictionary<string, string>
{
["schema"] = "stellaops.composition.recipe@1",
["merkleRoot"] = recipeSha256,
}));
var json = JsonSerializer.Serialize(report, JsonOptions);
return new SurfaceManifestPayload(
ArtifactDocumentType.SurfaceObservation,
@@ -293,9 +307,9 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
View: "replay");
}
private static (Dictionary<string, string> Hashes, string MerkleRoot) ComputeDeterminismHashes(IEnumerable<SurfaceManifestPayload> payloads)
private static (Dictionary<string, string> Hashes, byte[] RecipeBytes, string RecipeSha256) BuildCompositionRecipe(IEnumerable<SurfaceManifestPayload> payloads)
{
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var map = new SortedDictionary<string, string>(StringComparer.Ordinal);
using var sha = SHA256.Create();
foreach (var payload in payloads.OrderBy(p => p.Kind, StringComparer.Ordinal))
@@ -304,18 +318,18 @@ internal sealed class SurfaceManifestStageExecutor : IScanStageExecutor
map[payload.Kind] = digest;
}
// Build Merkle-like root by hashing the ordered list of kind:digest lines.
var builder = new StringBuilder();
foreach (var kvp in map.OrderBy(kv => kv.Key, StringComparer.Ordinal))
var recipe = new
{
builder.Append(kvp.Key).Append(':').Append(kvp.Value).Append('\n');
}
schema = "stellaops.composition.recipe@1",
artifacts = map, // already sorted
};
var rootBytes = Encoding.UTF8.GetBytes(builder.ToString());
var rootHash = sha.ComputeHash(rootBytes);
var recipeJson = JsonSerializer.Serialize(recipe, JsonOptions);
var recipeBytes = Encoding.UTF8.GetBytes(recipeJson);
var rootHash = sha.ComputeHash(recipeBytes);
var merkleRoot = Convert.ToHexString(rootHash).ToLowerInvariant();
return (map, merkleRoot);
return (new Dictionary<string, string>(map, StringComparer.OrdinalIgnoreCase), recipeBytes, merkleRoot);
}
private static string? GetReplayBundleUri(ScanJobContext context)

View File

@@ -61,11 +61,32 @@ public sealed class CycloneDxComposer
UsageMediaTypeProtobuf);
}
var compositionRecipeJson = BuildCompositionRecipeJson(graph, generatedAt);
var compositionRecipeSha = ComputeSha256(compositionRecipeJson);
var compositionRecipeUri = $"cas://sbom/composition/{compositionRecipeSha}.json";
inventoryArtifact = inventoryArtifact with
{
MerkleRoot = compositionRecipeSha,
CompositionRecipeUri = compositionRecipeUri,
};
if (usageArtifact is not null)
{
usageArtifact = usageArtifact with
{
MerkleRoot = compositionRecipeSha,
CompositionRecipeUri = compositionRecipeUri,
};
}
return new SbomCompositionResult
{
Inventory = inventoryArtifact,
Usage = usageArtifact,
Graph = graph,
CompositionRecipeJson = compositionRecipeJson,
CompositionRecipeSha256 = compositionRecipeSha,
};
}
@@ -92,6 +113,7 @@ public sealed class CycloneDxComposer
: null;
request.AdditionalProperties?.TryGetValue("stellaops:composition.manifest", out var compositionUri);
request.AdditionalProperties?.TryGetValue("stellaops:composition.recipe", out var compositionRecipeUri);
return new CycloneDxArtifact
{
@@ -104,6 +126,7 @@ public sealed class CycloneDxComposer
ContentHash = jsonHash,
MerkleRoot = merkleRoot,
CompositionUri = compositionUri,
CompositionRecipeUri = compositionRecipeUri,
JsonMediaType = jsonMediaType,
ProtobufBytes = protobufBytes,
ProtobufSha256 = protobufHash,
@@ -111,6 +134,31 @@ public sealed class CycloneDxComposer
};
}
private static byte[] BuildCompositionRecipeJson(ComponentGraph graph, DateTimeOffset generatedAt)
{
var recipe = new
{
schema = "stellaops.composition.recipe@1",
generatedAt = ScannerTimestamps.ToIso8601(generatedAt),
layers = graph.Layers.Select(layer => new
{
layer.LayerDigest,
components = layer.Components
.Select(component => component.Identity.Key)
.OrderBy(key => key, StringComparer.Ordinal)
.ToArray(),
}).OrderBy(entry => entry.LayerDigest, StringComparer.Ordinal).ToArray(),
};
var json = JsonSerializer.Serialize(recipe, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false,
});
return Encoding.UTF8.GetBytes(json);
}
private Bom BuildBom(
SbomCompositionRequest request,
ComponentGraph graph,

View File

@@ -33,6 +33,11 @@ public sealed record CycloneDxArtifact
/// </summary>
public string? CompositionUri { get; init; }
/// <summary>
/// CAS URI of the layer composition recipe (_composition.json) if emitted.
/// </summary>
public string? CompositionRecipeUri { get; init; }
public required string JsonMediaType { get; init; }
public required byte[] ProtobufBytes { get; init; }
@@ -49,4 +54,14 @@ public sealed record SbomCompositionResult
public CycloneDxArtifact? Usage { get; init; }
public required ComponentGraph Graph { get; init; }
/// <summary>
/// Composition recipe JSON bytes (canonical) capturing fragment ordering and hashes.
/// </summary>
public required byte[] CompositionRecipeJson { get; init; }
/// <summary>
/// SHA256 hex of the composition recipe JSON.
/// </summary>
public required string CompositionRecipeSha256 { get; init; }
}

View File

@@ -90,6 +90,14 @@ public sealed class ScannerArtifactPackageBuilder
descriptors.Add(CreateDescriptor(ArtifactDocumentType.Index, ArtifactDocumentFormat.BomIndex, "application/vnd.stellaops.bom-index.v1+binary", bomIndex.Bytes, bomIndex.Sha256, null));
descriptors.Add(CreateDescriptor(
ArtifactDocumentType.CompositionRecipe,
ArtifactDocumentFormat.CompositionRecipeJson,
"application/vnd.stellaops.composition.recipe+json",
composition.CompositionRecipeJson,
composition.CompositionRecipeSha256,
null));
var manifest = new ScannerArtifactManifest
{
ImageDigest = imageDigest.Trim(),
@@ -137,6 +145,7 @@ public sealed class ScannerArtifactPackageBuilder
ArtifactDocumentType.LayerBom => "layer-sbom",
ArtifactDocumentType.Diff => "diff",
ArtifactDocumentType.Attestation => "attestation",
ArtifactDocumentType.CompositionRecipe => "composition-recipe",
_ => descriptor.Type.ToString().ToLowerInvariant(),
};

View File

@@ -12,7 +12,8 @@ public enum ArtifactDocumentType
SurfaceManifest,
SurfaceEntryTrace,
SurfaceLayerFragment,
SurfaceObservation
SurfaceObservation,
CompositionRecipe
}
public enum ArtifactDocumentFormat
@@ -26,7 +27,8 @@ public enum ArtifactDocumentFormat
EntryTraceNdjson,
EntryTraceGraphJson,
ComponentFragmentJson,
ObservationJson
ObservationJson,
CompositionRecipeJson
}
[BsonIgnoreExtraElements]

View File

@@ -8,6 +8,8 @@
<IsPackable>false</IsPackable>
<!-- Stay scoped: disable implicit restore sources beyond local nugets -->
<RestoreSources>$(StellaOpsLocalNuGetSource)</RestoreSources>
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
<RestoreNoCache>true</RestoreNoCache>
</PropertyGroup>
<ItemGroup>

View File

@@ -79,8 +79,9 @@ public sealed class CycloneDxComposerTests
Assert.Equal(first.Inventory.ContentHash, first.Inventory.JsonSha256);
Assert.Equal(first.Inventory.ProtobufSha256, second.Inventory.ProtobufSha256);
Assert.Equal(first.Inventory.SerialNumber, second.Inventory.SerialNumber);
Assert.Null(first.Inventory.MerkleRoot);
Assert.False(string.IsNullOrWhiteSpace(first.Inventory.MerkleRoot));
Assert.Null(first.Inventory.CompositionUri);
Assert.Null(first.Inventory.CompositionRecipeUri);
Assert.NotNull(first.Usage);
Assert.NotNull(second.Usage);
@@ -88,8 +89,15 @@ public sealed class CycloneDxComposerTests
Assert.Equal(first.Usage.ContentHash, first.Usage.JsonSha256);
Assert.Equal(first.Usage.ProtobufSha256, second.Usage.ProtobufSha256);
Assert.Equal(first.Usage.SerialNumber, second.Usage.SerialNumber);
Assert.Null(first.Usage.MerkleRoot);
Assert.False(string.IsNullOrWhiteSpace(first.Usage.MerkleRoot));
Assert.Null(first.Usage.CompositionUri);
Assert.Null(first.Usage.CompositionRecipeUri);
Assert.Equal(first.Inventory.MerkleRoot, first.Usage.MerkleRoot);
Assert.Equal(first.Inventory.MerkleRoot, result.CompositionRecipeSha256);
Assert.Equal(first.Inventory.ContentHash.Length, first.Inventory.MerkleRoot!.Length);
Assert.Equal(result.CompositionRecipeSha256.Length, 64);
Assert.NotEmpty(result.CompositionRecipeJson);
}
private static SbomCompositionRequest BuildRequest()

View File

@@ -64,16 +64,16 @@ public sealed class ScannerArtifactPackageBuilderTests
var packageBuilder = new ScannerArtifactPackageBuilder();
var package = packageBuilder.Build(request.Image.ImageDigest, request.GeneratedAt, composition, bomIndex);
Assert.Equal(5, package.Artifacts.Length); // inventory JSON+PB, usage JSON+PB, index
Assert.Equal(6, package.Artifacts.Length); // inventory JSON+PB, usage JSON+PB, index, composition recipe
var kinds = package.Manifest.Artifacts.Select(entry => entry.Kind).ToArray();
Assert.Equal(new[] { "bom-index", "sbom-inventory", "sbom-inventory", "sbom-usage", "sbom-usage" }, kinds);
Assert.Equal(new[] { "bom-index", "composition-recipe", "sbom-inventory", "sbom-inventory", "sbom-usage", "sbom-usage" }, kinds);
var manifestJson = package.Manifest.ToJsonBytes();
using var document = JsonDocument.Parse(manifestJson);
var root = document.RootElement;
Assert.Equal("sha256:image", root.GetProperty("imageDigest").GetString());
Assert.Equal(5, root.GetProperty("artifacts").GetArrayLength());
Assert.Equal(6, root.GetProperty("artifacts").GetArrayLength());
var usageEntry = root.GetProperty("artifacts").EnumerateArray().First(element => element.GetProperty("kind").GetString() == "sbom-usage");
Assert.Equal("application/vnd.cyclonedx+json; version=1.6; view=usage", usageEntry.GetProperty("mediaType").GetString());

View File

@@ -102,10 +102,12 @@ public sealed class SurfaceManifestStageExecutorTests
Assert.Equal(publisher.LastManifestDigest, result!.ManifestDigest);
Assert.Equal(result.DeterminismMerkleRoot, publisher.LastRequest!.DeterminismMerkleRoot);
Assert.Equal(4, cache.Entries.Count);
Assert.Equal(6, cache.Entries.Count);
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.artifacts.entrytrace.graph" && key.Tenant == "tenant-a");
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.artifacts.entrytrace.ndjson" && key.Tenant == "tenant-a");
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.artifacts.layer.fragments" && key.Tenant == "tenant-a");
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.artifacts.determinism.json" && key.Tenant == "tenant-a");
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.artifacts.composition.recipe" && key.Tenant == "tenant-a");
Assert.Contains(cache.Entries.Keys, key => key.Namespace == "surface.manifests" && key.Tenant == "tenant-a");
var publishedMetrics = listener.Measurements
@@ -114,7 +116,7 @@ public sealed class SurfaceManifestStageExecutorTests
Assert.Single(publishedMetrics);
Assert.Equal(1, publishedMetrics[0].Value);
Assert.Equal("published", publishedMetrics[0]["surface.result"]);
Assert.Equal(3, Convert.ToInt32(publishedMetrics[0]["surface.payload_count"]));
Assert.Equal(5, Convert.ToInt32(publishedMetrics[0]["surface.payload_count"]));
var payloadMetrics = listener.Measurements
.Where(m => m.InstrumentName == "scanner_worker_surface_payload_persisted_total")
@@ -608,7 +610,8 @@ public sealed class SurfaceManifestStageExecutorTests
WorkerInstance = request.WorkerInstance,
Attempt = request.Attempt
},
Artifacts = artifacts
Artifacts = artifacts,
DeterminismMerkleRoot = request.DeterminismMerkleRoot
};
var manifestBytes = JsonSerializer.SerializeToUtf8Bytes(document, _options);

View File

@@ -5,4 +5,8 @@
| WEB-AOC-19-002 | DONE (2025-11-30) | Added provenance builder, checksum utilities, and DSSE/CMS signature verification helpers with unit tests. |
| WEB-AOC-19-003 | DONE (2025-11-30) | Added client-side guard validator (forbidden/derived/unknown fields, provenance/signature checks) with unit fixtures. |
| WEB-CONSOLE-23-002 | DOING (2025-12-01) | Console status polling + SSE run stream client/store/UI added; tests pending once env fixed. |
| WEB-RISK-66-001 | DOING (2025-12-01) | Added risk gateway mock client/models + tests; wire to real gateway once endpoints land. |
| WEB-EXC-25-001 | TODO | Exceptions workflow CRUD pending policy scopes. |
| WEB-TEN-47-CONTRACT | DONE (2025-12-01) | Gateway tenant auth/ABAC contract doc v1.0 published (`docs/api/gateway/tenant-auth.md`). |
| WEB-VULN-29-LEDGER-DOC | DONE (2025-12-01) | Findings Ledger proxy contract doc v1.0 with idempotency + retries (`docs/api/gateway/findings-ledger-proxy.md`). |
| WEB-RISK-68-NOTIFY-DOC | DONE (2025-12-01) | Notifications severity transition event schema v1.0 published (`docs/api/gateway/notifications-severity.md`). |

View File

@@ -20,6 +20,8 @@ import {
NOTIFY_TENANT_ID,
} from './core/api/notify.client';
import { CONSOLE_API_BASE_URL } from './core/api/console-status.client';
import { RISK_API } from './core/api/risk.client';
import { RISK_API_BASE_URL, RiskHttpClient } from './core/api/risk-http.client';
import { AppConfigService } from './core/config/app-config.service';
import { AuthHttpInterceptor } from './core/auth/auth-http.interceptor';
import { OperatorMetadataInterceptor } from './core/orchestrator/operator-metadata.interceptor';
@@ -70,6 +72,26 @@ export const appConfig: ApplicationConfig = {
provide: AUTHORITY_CONSOLE_API,
useExisting: AuthorityConsoleApiHttpClient,
},
{
provide: RISK_API_BASE_URL,
deps: [AppConfigService],
useFactory: (config: AppConfigService) => {
const authorityBase = config.config.apiBaseUrls.authority;
try {
return new URL('/risk', authorityBase).toString();
} catch {
const normalized = authorityBase.endsWith('/')
? authorityBase.slice(0, -1)
: authorityBase;
return `${normalized}/risk`;
}
},
},
RiskHttpClient,
{
provide: RISK_API,
useExisting: RiskHttpClient,
},
{
provide: NOTIFY_API_BASE_URL,
useValue: '/api/v1/notify',

View File

@@ -0,0 +1,62 @@
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { Observable, map } from 'rxjs';
import { AuthSessionStore } from '../auth/auth-session.store';
import { RiskApi } from './risk.client';
import { RiskQueryOptions, RiskResultPage, RiskStats } from './risk.models';
export const RISK_API_BASE_URL = new InjectionToken<string>('RISK_API_BASE_URL');
@Injectable({ providedIn: 'root' })
export class RiskHttpClient implements RiskApi {
constructor(
private readonly http: HttpClient,
private readonly authSession: AuthSessionStore,
@Inject(RISK_API_BASE_URL) private readonly baseUrl: string
) {}
list(options: RiskQueryOptions): Observable<RiskResultPage> {
const tenant = this.resolveTenant(options.tenantId);
const headers = this.buildHeaders(tenant, options.projectId, options.traceId);
let params = new HttpParams();
if (options.page) params = params.set('page', options.page);
if (options.pageSize) params = params.set('pageSize', options.pageSize);
if (options.severity) params = params.set('severity', options.severity);
if (options.search) params = params.set('search', options.search);
return this.http
.get<RiskResultPage>(`${this.baseUrl}/risk`, { headers, params })
.pipe(map((page) => ({ ...page, page: page.page ?? 1, pageSize: page.pageSize ?? 20 })));
}
stats(options: Pick<RiskQueryOptions, 'tenantId' | 'projectId' | 'traceId'>): Observable<RiskStats> {
const tenant = this.resolveTenant(options.tenantId);
const headers = this.buildHeaders(tenant, options.projectId, options.traceId);
return this.http
.get<RiskStats>(`${this.baseUrl}/risk/status`, { headers })
.pipe(
map((stats) => ({
countsBySeverity: stats.countsBySeverity,
lastComputation: stats.lastComputation ?? '1970-01-01T00:00:00Z',
}))
);
}
private buildHeaders(tenantId: string, projectId?: string, traceId?: string): HttpHeaders {
let headers = new HttpHeaders({ 'X-Stella-Tenant': tenantId });
if (projectId) headers = headers.set('X-Stella-Project', projectId);
if (traceId) headers = headers.set('X-Stella-Trace-Id', traceId);
return headers;
}
private resolveTenant(tenantId?: string): string {
const tenant = (tenantId && tenantId.trim()) || this.authSession.getActiveTenantId();
if (!tenant) {
throw new Error('RiskHttpClient requires an active tenant identifier.');
}
return tenant;
}
}

View File

@@ -0,0 +1,40 @@
import { MockRiskApi } from './risk.client';
describe('MockRiskApi', () => {
let api: MockRiskApi;
beforeEach(() => {
api = new MockRiskApi();
});
it('requires tenantId for list', () => {
expect(() => api.list({ tenantId: '' })).toThrow('tenantId is required');
});
it('returns deterministic ordering by score then id', (done) => {
api.list({ tenantId: 'acme-tenant', pageSize: 10 }).subscribe((page) => {
const scores = page.items.map((r) => r.score);
expect(scores).toEqual([...scores].sort((a, b) => b - a));
done();
});
});
it('filters by project and severity', (done) => {
api
.list({ tenantId: 'acme-tenant', projectId: 'proj-ops', severity: 'high' })
.subscribe((page) => {
expect(page.items.every((r) => r.projectId === 'proj-ops')).toBeTrue();
expect(page.items.every((r) => r.severity === 'high')).toBeTrue();
done();
});
});
it('computes stats with zeroed severities present', (done) => {
api.stats({ tenantId: 'acme-tenant' }).subscribe((stats) => {
expect(stats.countsBySeverity.none).toBe(0);
expect(stats.countsBySeverity.critical).toBeGreaterThan(0);
expect(stats.lastComputation).toMatch(/T/);
done();
});
});
});

View File

@@ -0,0 +1,112 @@
import { Injectable, InjectionToken } from '@angular/core';
import { Observable, delay, map, of } from 'rxjs';
import { RiskProfile, RiskQueryOptions, RiskResultPage, RiskStats, RiskSeverity } from './risk.models';
export interface RiskApi {
list(options: RiskQueryOptions): Observable<RiskResultPage>;
stats(options: Pick<RiskQueryOptions, 'tenantId' | 'projectId' | 'traceId'>): Observable<RiskStats>;
}
export const RISK_API = new InjectionToken<RiskApi>('RISK_API');
const MOCK_RISKS: RiskProfile[] = [
{
id: 'risk-001',
title: 'RCE on internet-facing API',
description: 'Critical RCE on public API gateway impacting tenants acme, globally exposed.',
severity: 'critical',
score: 97,
lastEvaluatedAt: '2025-11-30T12:00:00Z',
tenantId: 'acme-tenant',
},
{
id: 'risk-002',
title: 'Expired token audience',
description: 'Tokens minted without correct audience allow cross-tenant reuse.',
severity: 'high',
score: 81,
lastEvaluatedAt: '2025-11-30T11:00:00Z',
tenantId: 'acme-tenant',
projectId: 'proj-ops',
},
{
id: 'risk-003',
title: 'Missing SBOM attestation',
description: 'Builds lack SBOM attestations; export blocked in sealed mode.',
severity: 'medium',
score: 55,
lastEvaluatedAt: '2025-11-29T19:30:00Z',
tenantId: 'acme-tenant',
},
];
@Injectable({ providedIn: 'root' })
export class MockRiskApi implements RiskApi {
list(options: RiskQueryOptions): Observable<RiskResultPage> {
if (!options.tenantId) {
throw new Error('tenantId is required');
}
const page = options.page ?? 1;
const pageSize = options.pageSize ?? 20;
const filtered = MOCK_RISKS.filter((r) => {
if (r.tenantId !== options.tenantId) {
return false;
}
if (options.projectId && r.projectId !== options.projectId) {
return false;
}
if (options.severity && r.severity !== options.severity) {
return false;
}
if (options.search && !r.title.toLowerCase().includes(options.search.toLowerCase())) {
return false;
}
return true;
});
const start = (page - 1) * pageSize;
const items = filtered
.slice()
.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id))
.slice(start, start + pageSize);
const response: RiskResultPage = {
items,
total: filtered.length,
page,
pageSize,
};
return of(response).pipe(delay(50));
}
stats(options: Pick<RiskQueryOptions, 'tenantId' | 'projectId' | 'traceId'>): Observable<RiskStats> {
if (!options.tenantId) {
throw new Error('tenantId is required');
}
const relevant = MOCK_RISKS.filter((r) => r.tenantId === options.tenantId);
const emptyCounts: Record<RiskSeverity, number> = {
none: 0,
info: 0,
low: 0,
medium: 0,
high: 0,
critical: 0,
};
const counts = relevant.reduce((acc, curr) => {
acc[curr.severity] = (acc[curr.severity] ?? 0) + 1;
return acc;
}, { ...emptyCounts });
const lastEvaluatedAt = relevant
.map((r) => r.lastEvaluatedAt)
.sort()
.reverse()[0] ?? '1970-01-01T00:00:00Z';
return of({ countsBySeverity: counts, lastComputation: lastEvaluatedAt }).pipe(delay(25));
}
}

View File

@@ -0,0 +1,34 @@
export type RiskSeverity = 'none' | 'info' | 'low' | 'medium' | 'high' | 'critical';
export interface RiskProfile {
id: string;
title: string;
description: string;
severity: RiskSeverity;
score: number;
lastEvaluatedAt: string; // UTC ISO-8601
tenantId: string;
projectId?: string;
}
export interface RiskResultPage {
items: RiskProfile[];
total: number;
page: number;
pageSize: number;
}
export interface RiskQueryOptions {
tenantId: string;
projectId?: string;
page?: number;
pageSize?: number;
severity?: RiskSeverity;
search?: string;
traceId?: string;
}
export interface RiskStats {
countsBySeverity: Record<RiskSeverity, number>;
lastComputation: string; // UTC ISO-8601
}