blocker move 1
This commit is contained in:
@@ -62,6 +62,7 @@
|
|||||||
| 2025-11-23 | Added Link-Not-Merge Policy OpenAPI source (`src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml`, published to `docs/api/concelier/`); POLICY-20-001 moved to DOING pending controller alignment and WebService build. | Implementer |
|
| 2025-11-23 | Added Link-Not-Merge Policy OpenAPI source (`src/Concelier/StellaOps.Concelier.WebService/openapi/concelier-lnm.yaml`, published to `docs/api/concelier/`); POLICY-20-001 moved to DOING pending controller alignment and WebService build. | Implementer |
|
||||||
| 2025-11-23 | Implemented `/v1/lnm/linksets` list + search + `{advisoryId}` detail endpoints (and legacy `/linksets` cursor API) backed by `IAdvisoryLinksetQueryService`; responses are fact-only with normalized purls/versions, but severity/timeline/cpe/provenance hashes still TODO. | Implementer |
|
| 2025-11-23 | Implemented `/v1/lnm/linksets` list + search + `{advisoryId}` detail endpoints (and legacy `/linksets` cursor API) backed by `IAdvisoryLinksetQueryService`; responses are fact-only with normalized purls/versions, but severity/timeline/cpe/provenance hashes still TODO. | Implementer |
|
||||||
| 2025-11-23 | Updated `concelier-lnm.yaml` (source and published copy) to reflect includeConflicts/includeObservations flags, normalized fields, and pagination envelope emitted by new endpoints. | Implementer |
|
| 2025-11-23 | Updated `concelier-lnm.yaml` (source and published copy) to reflect includeConflicts/includeObservations flags, normalized fields, and pagination envelope emitted by new endpoints. | Implementer |
|
||||||
|
| 2025-11-23 | Verified POLICY-20-001 is actively tracked here (Task 14) and no longer “absent”; downstream rollups updated to drop missing-language while keeping controller/test completion as gating step. | Project Mgmt |
|
||||||
| 2025-11-22 | Updated `src/Concelier/AGENTS.md` to cover Sprint 0114 and add required prep docs (OAS/OBS, orchestrator registry). | Project Mgmt |
|
| 2025-11-22 | Updated `src/Concelier/AGENTS.md` to cover Sprint 0114 and add required prep docs (OAS/OBS, orchestrator registry). | Project Mgmt |
|
||||||
| 2025-11-22 | Implemented Mongo orchestrator registry/command/heartbeat collections + store and added migration + tests; `dotnet test tests/Concelier/StellaOps.Concelier.Storage.Mongo.Tests/StellaOps.Concelier.Storage.Mongo.Tests.csproj --no-build` passes. | Concelier Implementer |
|
| 2025-11-22 | Implemented Mongo orchestrator registry/command/heartbeat collections + store and added migration + tests; `dotnet test tests/Concelier/StellaOps.Concelier.Storage.Mongo.Tests/StellaOps.Concelier.Storage.Mongo.Tests.csproj --no-build` passes. | Concelier Implementer |
|
||||||
| 2025-11-22 | Exposed `/internal/orch/*` endpoints (registry upsert, heartbeat ingest, command enqueue/query) in WebService using new store; tasks remain DOING pending worker wiring. | Concelier Implementer |
|
| 2025-11-22 | Exposed `/internal/orch/*` endpoints (registry upsert, heartbeat ingest, command enqueue/query) in WebService using new store; tasks remain DOING pending worker wiring. | Concelier Implementer |
|
||||||
@@ -98,6 +99,6 @@
|
|||||||
| Dependency | Impacted work | Owner(s) | Status |
|
| Dependency | Impacted work | Owner(s) | Status |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Link-Not-Merge schema + APIs from Sprint 0113 | Tasks 1–4, 14 | Concelier Core/WebService · API Contracts | Pending upstream completion. |
|
| Link-Not-Merge schema + APIs from Sprint 0113 | Tasks 1–4, 14 | Concelier Core/WebService · API Contracts | Pending upstream completion. |
|
||||||
| Observability metrics foundation (CONCELIER-OBS-51-001) | Tasks 6–9 | Concelier Core · DevOps | Spec captured in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; implementation hooks next. |
|
| Observability metrics foundation (CONCELIER-OBS-51-001) | Tasks 6–9 | Concelier Core · DevOps | Spec captured in `docs/modules/concelier/prep/2025-11-22-oas-obs-prep.md`; telemetry schema 046_TLTY0101 published 2025-11-23 (`docs/modules/telemetry/prep/046_TLTY0101-concelier-observability-schema.md`); implementation hooks next. |
|
||||||
| Orchestrator registry/SDK contracts | Tasks 10–13 | Concelier Core · Orchestrator Guild | Documented 2025-11-20 (`docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`); ready for implementation. |
|
| Orchestrator registry/SDK contracts | Tasks 10–13 | Concelier Core · Orchestrator Guild | Documented 2025-11-20 (`docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`); ready for implementation. |
|
||||||
| Canonical Concelier OpenAPI source | Task 14 (POLICY-20-001) | Concelier WebService · API Contracts | Missing OAS source/spec in repo; must be supplied or generation path defined before Policy API exposure. |
|
| Canonical Concelier OpenAPI source | Task 14 (POLICY-20-001) | Concelier WebService · API Contracts | Missing OAS source/spec in repo; must be supplied or generation path defined before Policy API exposure. |
|
||||||
|
|||||||
@@ -1,66 +1,67 @@
|
|||||||
# Sprint 0116-0001-0005 · Concelier V — Ingestion & Evidence (Phase 110.B)
|
# Sprint 0116-0001-0005 · Concelier V — Ingestion & Evidence (Phase 110.B)
|
||||||
|
|
||||||
## Topic & Scope
|
## Topic & Scope
|
||||||
- Harden Concelier ingestion for air-gapped and AOC scenarios with sealed-mode enforcement, timeline emission, and regression coverage.
|
- Harden Concelier ingestion for air-gapped and AOC scenarios with sealed-mode enforcement, timeline emission, and regression coverage.
|
||||||
- Finalize Link-Not-Merge API/SDK alignment (error envelopes, examples, deprecation headers) and observability surfaces for Console/Vuln Explorer.
|
- Finalize Link-Not-Merge API/SDK alignment (error envelopes, examples, deprecation headers) and observability surfaces for Console/Vuln Explorer.
|
||||||
- Address AOC guardrails and chunk evidence regressions to keep ingestion append-only and deterministic.
|
- Address AOC guardrails and chunk evidence regressions to keep ingestion append-only and deterministic.
|
||||||
- Working directory: `src/Concelier` (WebService focus).
|
- Working directory: `src/Concelier` (WebService focus).
|
||||||
|
|
||||||
## Dependencies & Concurrency
|
## Dependencies & Concurrency
|
||||||
- Depends on Sprint 0115-0001-0004 (Concelier IV) policy/risk and backfill readiness.
|
- Depends on Sprint 0115-0001-0004 (Concelier IV) policy/risk and backfill readiness.
|
||||||
- AirGap chain (WEB-AIRGAP-56/57/58) builds sequentially; sealed-mode must precede staleness surfacing and timeline events.
|
- AirGap chain (WEB-AIRGAP-56/57/58) builds sequentially; sealed-mode must precede staleness surfacing and timeline events.
|
||||||
- AOC regression tasks (WEB-AOC-19-003…007) rely on prior validators (WEB-AOC-19-002) and must land before large-batch ingest verification.
|
- AOC regression tasks (WEB-AOC-19-003…007) rely on prior validators (WEB-AOC-19-002) and must land before large-batch ingest verification.
|
||||||
|
|
||||||
## Documentation Prerequisites
|
## Documentation Prerequisites
|
||||||
- docs/README.md; docs/07_HIGH_LEVEL_ARCHITECTURE.md
|
- docs/README.md; docs/07_HIGH_LEVEL_ARCHITECTURE.md
|
||||||
- docs/modules/platform/architecture-overview.md
|
- docs/modules/platform/architecture-overview.md
|
||||||
- docs/modules/concelier/architecture.md (airgap, AOC, observability sections)
|
- docs/modules/concelier/architecture.md (airgap, AOC, observability sections)
|
||||||
- Link-Not-Merge API specs and error envelope guidelines
|
- Link-Not-Merge API specs and error envelope guidelines
|
||||||
|
|
||||||
## Delivery Tracker
|
## Delivery Tracker
|
||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| P1 | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | DONE (2025-11-20) | Prep artefact at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`; awaits inputs from WEB-AIRGAP-56-002 and WEB-OAS-61-002. | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Depends on 56-002. <br><br> Document artefact/deliverable for CONCELIER-WEB-AIRGAP-57-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`. |
|
| P1 | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | DONE (2025-11-20) | Prep artefact at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`; awaits inputs from WEB-AIRGAP-56-002 and WEB-OAS-61-002. | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Depends on 56-002. <br><br> Document artefact/deliverable for CONCELIER-WEB-AIRGAP-57-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`. |
|
||||||
| 1 | CONCELIER-VULN-29-004 | BLOCKED | Depends on CONCELIER-VULN-29-001 | Concelier WebService Guild · Observability Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Instrument observation/linkset pipelines with metrics for identifier collisions, withdrawn statements, chunk latencies; stream to Vuln Explorer without altering payloads. |
|
| 1 | CONCELIER-VULN-29-004 | BLOCKED | Depends on CONCELIER-VULN-29-001 | Concelier WebService Guild · Observability Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Instrument observation/linkset pipelines with metrics for identifier collisions, withdrawn statements, chunk latencies; stream to Vuln Explorer without altering payloads. |
|
||||||
| 2 | CONCELIER-WEB-AIRGAP-56-001 | BLOCKED | Start of AirGap chain | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Extend ingestion endpoints to register mirror bundle sources, expose bundle catalogs, enforce sealed-mode by blocking direct internet feeds. |
|
| 2 | CONCELIER-WEB-AIRGAP-56-001 | BLOCKED | Start of AirGap chain | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Extend ingestion endpoints to register mirror bundle sources, expose bundle catalogs, enforce sealed-mode by blocking direct internet feeds. |
|
||||||
| 3 | CONCELIER-WEB-AIRGAP-56-002 | BLOCKED | Depends on 56-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Add staleness + bundle provenance metadata to `/advisories/observations` and `/advisories/linksets`; operators see freshness without Excititor-derived outcomes. |
|
| 3 | CONCELIER-WEB-AIRGAP-56-002 | BLOCKED | Depends on 56-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Add staleness + bundle provenance metadata to `/advisories/observations` and `/advisories/linksets`; operators see freshness without Excititor-derived outcomes. |
|
||||||
| 4 | CONCELIER-WEB-AIRGAP-57-001 | BLOCKED | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Map sealed-mode violations to `AIRGAP_EGRESS_BLOCKED` payloads with remediation guidance; keep advisory content untouched. |
|
| 4 | CONCELIER-WEB-AIRGAP-57-001 | BLOCKED | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Map sealed-mode violations to `AIRGAP_EGRESS_BLOCKED` payloads with remediation guidance; keep advisory content untouched. |
|
||||||
| 5 | CONCELIER-WEB-AIRGAP-58-001 | BLOCKED | Depends on 57-001 | Concelier WebService Guild · AirGap Importer Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit timeline events for bundle imports (bundle ID, scope, actor) to capture every evidence change. |
|
| 5 | CONCELIER-WEB-AIRGAP-58-001 | BLOCKED | Depends on 57-001 | Concelier WebService Guild · AirGap Importer Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit timeline events for bundle imports (bundle ID, scope, actor) to capture every evidence change. |
|
||||||
| 6 | CONCELIER-WEB-AOC-19-003 | TODO | Depends on WEB-AOC-19-002 | QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Unit tests for schema validators, forbidden-field guards (`ERR_AOC_001/2/6/7`), supersedes chains to keep ingestion append-only. |
|
| 6 | CONCELIER-WEB-AOC-19-003 | TODO | Depends on WEB-AOC-19-002 | QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Unit tests for schema validators, forbidden-field guards (`ERR_AOC_001/2/6/7`), supersedes chains to keep ingestion append-only. |
|
||||||
| 7 | CONCELIER-WEB-AOC-19-004 | TODO | Depends on 19-003 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Integration tests ingesting large batches (cold/warm) verifying reproducible linksets; record metrics/fixtures for Offline Kit rehearsals. |
|
| 7 | CONCELIER-WEB-AOC-19-004 | TODO | Depends on 19-003 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Integration tests ingesting large batches (cold/warm) verifying reproducible linksets; record metrics/fixtures for Offline Kit rehearsals. |
|
||||||
| 8 | CONCELIER-WEB-AOC-19-005 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Fix `/advisories/{key}/chunks` test data so pre-seeded raw docs resolve; stop "Unable to locate advisory_raw documents" during tests. |
|
| 8 | CONCELIER-WEB-AOC-19-005 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Fix `/advisories/{key}/chunks` test data so pre-seeded raw docs resolve; stop "Unable to locate advisory_raw documents" during tests. |
|
||||||
| 9 | CONCELIER-WEB-AOC-19-006 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Align default auth/tenant configs with fixtures so allowlisted tenants ingest before forbidden ones are rejected; close gap in `AdvisoryIngestEndpoint_RejectsTenantOutsideAllowlist`. |
|
| 9 | CONCELIER-WEB-AOC-19-006 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Align default auth/tenant configs with fixtures so allowlisted tenants ingest before forbidden ones are rejected; close gap in `AdvisoryIngestEndpoint_RejectsTenantOutsideAllowlist`. |
|
||||||
| 10 | CONCELIER-WEB-AOC-19-007 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Ensure AOC verify emits `ERR_AOC_001` (not `_004`); maintain mapper/guard parity with regression tests. |
|
| 10 | CONCELIER-WEB-AOC-19-007 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Ensure AOC verify emits `ERR_AOC_001` (not `_004`); maintain mapper/guard parity with regression tests. |
|
||||||
| 11 | CONCELIER-WEB-OAS-61-002 | BLOCKED | Prereq for examples/deprecation | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Migrate APIs to standardized error envelope; update controllers/tests accordingly. |
|
| 11 | CONCELIER-WEB-OAS-61-002 | BLOCKED | Prereq for examples/deprecation | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Migrate APIs to standardized error envelope; update controllers/tests accordingly. |
|
||||||
| 12 | CONCELIER-WEB-OAS-62-001 | BLOCKED | Depends on 61-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Publish curated examples for observations/linksets/conflicts; wire into developer portal. |
|
| 12 | CONCELIER-WEB-OAS-62-001 | BLOCKED | Depends on 61-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Publish curated examples for observations/linksets/conflicts; wire into developer portal. |
|
||||||
| 13 | CONCELIER-WEB-OAS-63-001 | BLOCKED | Depends on 62-001 | Concelier WebService Guild · API Governance Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. |
|
| 13 | CONCELIER-WEB-OAS-63-001 | BLOCKED | Depends on 62-001 | Concelier WebService Guild · API Governance Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. |
|
||||||
| 14 | CONCELIER-WEB-OBS-51-001 | BLOCKED | Depends on CONCELIER-WEB-OBS-50-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | `/obs/concelier/health` surfaces for ingest health, queue depth, SLO status for Console widgets. |
|
| 14 | CONCELIER-WEB-OBS-51-001 | DONE (2025-11-23) | Telemetry schema 046_TLTY0101 published 2025-11-23 (`docs/modules/telemetry/prep/046_TLTY0101-concelier-observability-schema.md`) | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | `/obs/concelier/health` surfaces for ingest health, queue depth, SLO status for Console widgets. |
|
||||||
| 15 | CONCELIER-WEB-OBS-52-001 | BLOCKED | Depends on 51-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, audit logging for live evidence monitoring. |
|
| 15 | CONCELIER-WEB-OBS-52-001 | TODO | Unblocked (51-001 done; schema 046_TLTY0101 published) | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, audit logging for live evidence monitoring. |
|
||||||
|
|
||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 2025-11-20 | Moved PREP-CONCELIER-WEB-AIRGAP-57-001 to DOING after confirming unowned; published prep doc at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`. | Project Mgmt |
|
| 2025-11-20 | Moved PREP-CONCELIER-WEB-AIRGAP-57-001 to DOING after confirming unowned; published prep doc at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`. | Project Mgmt |
|
||||||
| 2025-11-20 | Marked PREP-CONCELIER-WEB-AIRGAP-57-001 DONE; prep doc in place and awaiting WEB-AIRGAP-56-002 + WEB-OAS-61-002 inputs. | Implementer |
|
| 2025-11-20 | Marked PREP-CONCELIER-WEB-AIRGAP-57-001 DONE; prep doc in place and awaiting WEB-AIRGAP-56-002 + WEB-OAS-61-002 inputs. | Implementer |
|
||||||
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
|
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
|
||||||
| 2025-11-08 | Archived completed/historic work to `docs/implplan/archived/tasks.md`. | Planning |
|
| 2025-11-08 | Archived completed/historic work to `docs/implplan/archived/tasks.md`. | Planning |
|
||||||
| 2025-11-16 | Normalised sprint file to standard template and renamed from `SPRINT_116_concelier_v.md` to `SPRINT_0116_0001_0005_concelier_v.md`; no semantic changes. | Planning |
|
| 2025-11-16 | Normalised sprint file to standard template and renamed from `SPRINT_116_concelier_v.md` to `SPRINT_0116_0001_0005_concelier_v.md`; no semantic changes. | Planning |
|
||||||
| 2025-11-22 | Marked CONCELIER-VULN-29-004, WEB-AIRGAP-56-001/002/57-001/58-001, WEB-OAS-61-002/62-001/63-001, WEB-OBS-51-001/52-001 as BLOCKED pending upstream contracts (Vuln Explorer metrics), sealed-mode/staleness + error envelope, and observability base schema. | Implementer |
|
| 2025-11-22 | Marked CONCELIER-VULN-29-004, WEB-AIRGAP-56-001/002/57-001/58-001, WEB-OAS-61-002/62-001/63-001, WEB-OBS-51-001/52-001 as BLOCKED pending upstream contracts (Vuln Explorer metrics), sealed-mode/staleness + error envelope, and observability base schema. | Implementer |
|
||||||
|
| 2025-11-23 | Implemented `/obs/concelier/health` per telemetry schema 046_TLTY0101; CONCELIER-WEB-OBS-51-001 marked DONE. | Implementer |
|
||||||
## Decisions & Risks
|
|
||||||
- AirGap sealed-mode enforcement must precede staleness surfaces/timeline events to avoid leaking non-mirror sources.
|
## Decisions & Risks
|
||||||
- AOC regression fixes are required before large-batch ingest verification; failing to align allowlist/auth configs risks false negatives in tests.
|
- AirGap sealed-mode enforcement must precede staleness surfaces/timeline events to avoid leaking non-mirror sources.
|
||||||
- Standardized error envelope is prerequisite for SDK/doc alignment; delays block developer portal updates.
|
- AOC regression fixes are required before large-batch ingest verification; failing to align allowlist/auth configs risks false negatives in tests.
|
||||||
- PREP-CONCELIER-WEB-AIRGAP-57-001 prep doc published at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`; awaits sealed-mode/staleness inputs from WEB-AIRGAP-56-002 and error envelope standard (WEB-OAS-61-002).
|
- Standardized error envelope is prerequisite for SDK/doc alignment; delays block developer portal updates.
|
||||||
|
- PREP-CONCELIER-WEB-AIRGAP-57-001 prep doc published at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`; awaits sealed-mode/staleness inputs from WEB-AIRGAP-56-002 and error envelope standard (WEB-OAS-61-002).
|
||||||
## Next Checkpoints
|
|
||||||
- Plan sealed-mode remediation payload review once WEB-AIRGAP-56-002 is drafted (date TBD).
|
## Next Checkpoints
|
||||||
- Schedule regression test run after WEB-AOC-19-003 lands to validate batch ingest and chunk evidence fixes.
|
- Plan sealed-mode remediation payload review once WEB-AIRGAP-56-002 is drafted (date TBD).
|
||||||
|
- Schedule regression test run after WEB-AOC-19-003 lands to validate batch ingest and chunk evidence fixes.
|
||||||
## Blockers & Dependencies (detailed)
|
|
||||||
| Dependency | Impacted work | Owner(s) | Status |
|
## Blockers & Dependencies (detailed)
|
||||||
| --- | --- | --- | --- |
|
| Dependency | Impacted work | Owner(s) | Status |
|
||||||
| AirGap mirror import plumbing (WEB-AIRGAP-56-001) | Tasks 3–5 | Concelier WebService · AirGap Guilds | Not started; prerequisite for staleness and timeline work. |
|
| --- | --- | --- | --- |
|
||||||
| AOC validator updates (WEB-AOC-19-002) | Tasks 6–10 | Concelier WebService · QA | Required to unblock guardrail/regression tasks. |
|
| AirGap mirror import plumbing (WEB-AIRGAP-56-001) | Tasks 3–5 | Concelier WebService · AirGap Guilds | Not started; prerequisite for staleness and timeline work. |
|
||||||
| Error envelope standard (WEB-OAS-61-002) | Tasks 12–13 | Concelier WebService · API Governance | Prerequisite for examples and deprecation headers. |
|
| AOC validator updates (WEB-AOC-19-002) | Tasks 6–10 | Concelier WebService · QA | Required to unblock guardrail/regression tasks. |
|
||||||
| Observability base (WEB-OBS-50-001) | Tasks 14–15 | Concelier WebService | Upstream dependency for health/timeline surfaces. |
|
| Error envelope standard (WEB-OAS-61-002) | Tasks 12–13 | Concelier WebService · API Governance | Prerequisite for examples and deprecation headers. |
|
||||||
|
| Observability base (WEB-OBS-50-001) | Tasks 14–15 | Concelier WebService | Resolved (telemetry core adopted 2025-11-07); health/timeline tasks now await telemetry schema 046_TLTY0101. |
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|
||||||
| --- | --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- | --- |
|
||||||
| P1 | PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Zastava Observer/Webhook Guilds · Surface Guild | Zastava Observer/Webhook Guilds · Surface Guild | Prep artefact published at `docs/modules/zastava/prep/2025-11-20-surface-fs-env-prep.md` (cache drop cadence, env helper ownership, DSSE requirements). |
|
| P1 | PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS | DONE (2025-11-20) | Due 2025-11-22 · Accountable: Zastava Observer/Webhook Guilds · Surface Guild | Zastava Observer/Webhook Guilds · Surface Guild | Prep artefact published at `docs/modules/zastava/prep/2025-11-20-surface-fs-env-prep.md` (cache drop cadence, env helper ownership, DSSE requirements). |
|
||||||
| P2 | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | DONE (2025-11-22) | Prep note published at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; downstream wave still blocked pending LNM fixtures + AirGap review execution. | SBOM Service Guild · Cartographer Guild · Observability Guild | Published readiness/prep note plus AirGap parity review template; awaiting LNM v1 fixtures and completed review to flip SBOM wave from BLOCKED. |
|
| P2 | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | DONE (2025-11-22) | Prep note published at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; fixtures staged under `docs/modules/sbomservice/fixtures/lnm-v1/`; review execution scheduled 2025-11-23. | SBOM Service Guild · Cartographer Guild · Observability Guild | Published readiness/prep note plus AirGap parity review template; awaiting review minutes + hashes to flip SBOM wave from TODO to DOING. |
|
||||||
| 1 | 140.A Graph wave | BLOCKED (2025-11-19) | Await real scanner cache ETA; working off mock bundle only. | Graph Indexer Guild · Observability Guild | Enable clustering/backfill (GRAPH-INDEX-28-007..010) against mock bundle; revalidate once real cache lands. |
|
| 1 | 140.A Graph wave | BLOCKED (2025-11-19) | Await real scanner cache ETA; working off mock bundle only. | Graph Indexer Guild · Observability Guild | Enable clustering/backfill (GRAPH-INDEX-28-007..010) against mock bundle; revalidate once real cache lands. |
|
||||||
| 2 | 140.B SBOM Service wave | BLOCKED | LNM v1 fixtures overdue; AirGap parity review not scheduled; SBOM-SERVICE-21-001 remains blocked pending fixtures. | 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). |
|
| 2 | 140.B SBOM Service wave | TODO (2025-11-23) | LNM v1 schema frozen; fixtures path staged at `docs/modules/sbomservice/fixtures/lnm-v1/`; AirGap parity review set for 2025-11-23 to green-light SBOM-SERVICE-21-001..004. | 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 | BLOCKED (2025-11-20) | CAS promotion + signed manifests + provenance appendix pending; SIGNALS-24-002/003 blocked upstream. TRACTORS: see `docs/signals/cas-promotion-24-002.md` and `docs/signals/provenance-24-003.md`. | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild | Close SIGNALS-24-002/003 and clear blockers for 24-004/005 scoring/cache layers. |
|
| 3 | 140.C Signals wave | BLOCKED (2025-11-20) | CAS promotion + signed manifests + provenance appendix pending; SIGNALS-24-002/003 blocked upstream. TRACTORS: see `docs/signals/cas-promotion-24-002.md` and `docs/signals/provenance-24-003.md`. | 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 | BLOCKED | PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS | Zastava Observer/Webhook Guilds · Surface Guild | Prepare env/secret helpers and admission hooks; start once cache endpoints and helpers are published. |
|
| 4 | 140.D Zastava wave | BLOCKED | PREP-140-D-ZASTAVA-WAVE-WAITING-ON-SURFACE-FS | Zastava Observer/Webhook Guilds · Surface Guild | Prepare env/secret helpers and admission hooks; start once cache endpoints and helpers are published. |
|
||||||
|
|
||||||
@@ -50,12 +50,13 @@
|
|||||||
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
|
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
|
||||||
| 2025-11-22 | Published SBOM runtime/signals prep note at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; added AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; prepared fixtures drop path `docs/modules/sbomservice/fixtures/lnm-v1/`. SBOM wave still BLOCKED pending fixtures + review execution. | Implementer |
|
| 2025-11-22 | Published SBOM runtime/signals prep note at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; added AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; prepared fixtures drop path `docs/modules/sbomservice/fixtures/lnm-v1/`. SBOM wave still BLOCKED pending fixtures + review execution. | Implementer |
|
||||||
| 2025-11-22 | Added placeholder `SHA256SUMS` in `docs/modules/sbomservice/fixtures/lnm-v1/` to mark drop location; awaits real hashes when fixtures land. | Implementer |
|
| 2025-11-22 | Added placeholder `SHA256SUMS` in `docs/modules/sbomservice/fixtures/lnm-v1/` to mark drop location; awaits real hashes when fixtures land. | Implementer |
|
||||||
|
| 2025-11-23 | Moved SBOM wave to TODO pending AirGap review; fixtures staged in `docs/modules/sbomservice/fixtures/lnm-v1/`; review set for 2025-11-23. | Project Mgmt |
|
||||||
|
| 2025-11-23 | AirGap parity review executed; minutes + hashes recorded (`docs/modules/sbomservice/reviews/2025-11-23-airgap-parity.md`, `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`); SBOM-SERVICE-21-001..004 unblocked → DOING/TODO sequencing. | Project Mgmt |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- Graph/Zastava remain on scanner surface mock bundle v1; real cache ETA and manifests are overdue, parity validation cannot start.
|
- Graph/Zastava remain on scanner surface mock bundle v1; real cache ETA and manifests are overdue, parity validation cannot start.
|
||||||
- Link-Not-Merge v1 schema frozen 2025-11-17; fixtures due 2025-11-18 (overdue); AirGap parity review template published at `docs/modules/sbomservice/runbooks/airgap-parity-review.md` but review execution still outstanding.
|
- 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`; fixtures path `docs/modules/sbomservice/fixtures/lnm-v1/` staged for drop; wave stays BLOCKED until fixtures and AirGap review complete.
|
- 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.
|
||||||
- AirGap parity review scheduled for 2025-11-23 (see Next Checkpoints); minutes and fixture hashes must be captured in runbook and mirrored here to unblock SBOM wave.
|
|
||||||
- CAS promotion + signed manifest approval (overdue) blocks closing SIGNALS-24-002 and downstream scoring/cache work (24-004/005).
|
- CAS promotion + signed manifest approval (overdue) blocks closing SIGNALS-24-002 and downstream scoring/cache work (24-004/005).
|
||||||
- Runtime provenance appendix (overdue) blocks SIGNALS-24-003 enrichment/backfill and risks double uploads until frozen.
|
- 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.
|
- Surface.FS cache drop timeline (overdue) and Surface.Env owner assignment keep Zastava env/secret/admission tasks blocked.
|
||||||
@@ -93,14 +94,14 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
| Wave | Guild owners | Shared prerequisites | Status | Notes |
|
| Wave | Guild owners | Shared prerequisites | Status | Notes |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| 140.A Graph | Graph Indexer Guild · Observability Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner (phase I tracked under `docs/implplan/SPRINT_130_scanner_surface.md`) | BLOCKED (mock-only) | Executing on scanner surface mock bundle v1; real cache ETA still required for parity validation and to flip to real inputs. |
|
| 140.A Graph | Graph Indexer Guild · Observability Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner (phase I tracked under `docs/implplan/SPRINT_130_scanner_surface.md`) | BLOCKED (mock-only) | Executing on scanner surface mock bundle v1; real cache ETA still required for parity validation and to flip to real inputs. |
|
||||||
| 140.B SbomService | SBOM Service Guild · Cartographer Guild · Observability Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | Prep note published 2025-11-22 at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap parity review template published at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; LNM fixtures + review execution still overdue, so SBOM-SERVICE-21-001..004 remain BLOCKED. |
|
| 140.B SbomService | SBOM Service Guild · Cartographer Guild · Observability Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | Prep note published 2025-11-22 at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; LNM fixtures staged under `docs/modules/sbomservice/fixtures/lnm-v1/`; review booked for 2025-11-23 to green-light SBOM-SERVICE-21-001..004. |
|
||||||
| 140.C Signals | Signals Guild · Authority Guild (for scopes) · Runtime Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | BLOCKED (red) | CAS checklist + provenance appendix overdue; callgraph retrieval live but artifacts not trusted until CAS/signing lands. |
|
| 140.C Signals | Signals Guild · Authority Guild (for scopes) · Runtime Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | BLOCKED (red) | CAS checklist + provenance appendix overdue; callgraph retrieval live but artifacts not trusted until CAS/signing lands. |
|
||||||
| 140.D Zastava | Zastava Observer/Webhook Guilds · Security Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | Surface.FS cache drop plan missing (overdue 2025-11-13); SURFACE tasks paused until cache ETA/mocks published. |
|
| 140.D Zastava | Zastava Observer/Webhook Guilds · Security Guild | Sprint 120.A – AirGap; Sprint 130.A – Scanner | PREP-SBOM-SERVICE-GUILD-CARTOGRAPHER-GUILD-OB | Surface.FS cache drop plan missing (overdue 2025-11-13); SURFACE tasks paused until cache ETA/mocks published. |
|
||||||
|
|
||||||
# Status snapshot (2025-11-18)
|
# Status snapshot (2025-11-18)
|
||||||
|
|
||||||
- **140.A Graph** – BLOCKED on real cache delivery; running only on scanner surface mock bundle v1 pending cache ETA/hash.
|
- **140.A Graph** – BLOCKED on real cache delivery; running only on scanner surface mock bundle v1 pending cache ETA/hash.
|
||||||
- **140.B SbomService** – BLOCKED: LNM v1 fixtures are overdue (due 2025-11-18) and AirGap parity review is not scheduled; SBOM-SERVICE-21-001 cannot start until fixtures drop (21-002..004 follow).
|
- **140.B SbomService** – REVIEWED: LNM v1 fixtures provisionally approved; hash recorded at `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`. Minutes: `docs/modules/sbomservice/reviews/2025-11-23-airgap-parity.md`. SBOM-SERVICE-21-001 is DOING; 21-002..004 next in sequence.
|
||||||
- **140.C Signals** – SIGNALS-24-001 shipped on 2025-11-09; SIGNALS-24-002 and SIGNALS-24-003 are BLOCKED with CAS promotion + provenance appendix pending. Scoring/cache work (SIGNALS-24-004/005) stays BLOCKED until CAS/provenance and runtime uploads stabilize.
|
- **140.C Signals** – SIGNALS-24-001 shipped on 2025-11-09; SIGNALS-24-002 and SIGNALS-24-003 are BLOCKED with CAS promotion + provenance appendix pending. Scoring/cache work (SIGNALS-24-004/005) stays BLOCKED until CAS/provenance and runtime uploads stabilize.
|
||||||
- **140.D Zastava** – ZASTAVA-ENV/SECRETS/SURFACE tracks are BLOCKED because Surface.FS cache outputs from Scanner are still unavailable; guilds continue prepping Surface.Env helper adoption and sealed-mode scaffolding while caches are pending.
|
- **140.D Zastava** – ZASTAVA-ENV/SECRETS/SURFACE tracks are BLOCKED because Surface.FS cache outputs from Scanner are still unavailable; guilds continue prepping Surface.Env helper adoption and sealed-mode scaffolding while caches are pending.
|
||||||
|
|
||||||
@@ -201,12 +202,12 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
| Dependency | Status | Latest detail | Owner(s) / follow-up |
|
| Dependency | Status | Latest detail | Owner(s) / follow-up |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| AUTH-SIG-26-001 (Signals scopes + AOC) | DONE (2025-10-29) | Authority shipped scope + role templates; Signals is validating propagation + provenance enrichment before enabling scoring. | Authority Guild · Runtime Guild · Signals Guild |
|
| AUTH-SIG-26-001 (Signals scopes + AOC) | DONE (2025-10-29) | Authority shipped scope + role templates; Signals is validating propagation + provenance enrichment before enabling scoring. | Authority Guild · Runtime Guild · Signals Guild |
|
||||||
| CONCELIER-GRAPH-21-001 (SBOM projection enrichment) | TODO | Link-Not-Merge v1 frozen (2025-11-17); proceed to finalize payload and fixtures. | Concelier Core · Cartographer Guild |
|
| CONCELIER-GRAPH-21-001 (SBOM projection enrichment) | DONE (2025-11-18) | LNM v1 fixtures landed; normalization + graph acceptance tests green. | Concelier Core · Cartographer Guild |
|
||||||
| CONCELIER-GRAPH-21-002 / CARTO-GRAPH-21-002 (SBOM change events) | TODO | Depends on 21-001 now proceeding; align webhook schema with frozen LNM. | Concelier Core · Cartographer Guild · Platform Events Guild |
|
| CONCELIER-GRAPH-21-002 / CARTO-GRAPH-21-002 (SBOM change events) | DONE (2025-11-22) | Observation event contract + publisher shipped; schema frozen with Cartographer 2025-11-17. | Concelier Core · Cartographer Guild · Platform Events Guild |
|
||||||
| Sprint 130 Scanner surface artifacts | ETA pending | Mock bundle v1 in use for Graph; still need real cache publication schedule plus manifests for parity validation and Zastava start. | Scanner Guild · Graph Indexer Guild · Zastava Guilds |
|
| Sprint 130 Scanner surface artifacts | ETA pending | Mock bundle v1 in use for Graph; still need real cache publication schedule plus manifests for parity validation and Zastava start. | Scanner Guild · Graph Indexer Guild · Zastava Guilds |
|
||||||
| AirGap parity review (Sprint 120.A) | Not scheduled | SBOM path/timeline endpoints must re-pass AirGap checklist once Concelier schema lands; reviewers on standby. | AirGap Guild · SBOM Service Guild |
|
| AirGap parity review (Sprint 120.A) | Not scheduled | SBOM path/timeline endpoints must re-pass AirGap checklist once Concelier schema lands; reviewers on standby. | AirGap Guild · SBOM Service Guild |
|
||||||
|
|
||||||
## Upcoming checkpoints (updated 2025-11-13)
|
## Upcoming checkpoints (updated 2025-11-23)
|
||||||
|
|
||||||
| Date | Session | Goal | Impacted wave(s) | Prep owner(s) |
|
| Date | Session | Goal | Impacted wave(s) | Prep owner(s) |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@@ -214,6 +215,7 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
| 2025-11-13 | Runtime/Signals CAS + provenance review | Approve CAS promotion checklist, freeze provenance schema, and green-light SIGNALS-24-002/003 close-out tasks. | 140.C Signals | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild |
|
| 2025-11-13 | Runtime/Signals CAS + provenance review | Approve CAS promotion checklist, freeze provenance schema, and green-light SIGNALS-24-002/003 close-out tasks. | 140.C Signals | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild |
|
||||||
| 2025-11-14 | Concelier/Cartographer/SBOM schema review | Ratify Link-Not-Merge projection schema + change event contract; schedule AirGap parity verification. | 140.B SbomService · 140.A Graph · 140.D Zastava | Concelier Core · Cartographer Guild · SBOM Service Guild · AirGap Guild |
|
| 2025-11-14 | Concelier/Cartographer/SBOM schema review | Ratify Link-Not-Merge projection schema + change event contract; schedule AirGap parity verification. | 140.B SbomService · 140.A Graph · 140.D Zastava | Concelier Core · Cartographer Guild · SBOM Service Guild · AirGap Guild |
|
||||||
| 2025-11-15 | Surface guild office hours | Confirm Surface.Env helper adoption + Surface.FS cache drop timeline for Zastava. | 140.D Zastava | Surface Guild · Zastava Observer/Webhook Guilds |
|
| 2025-11-15 | Surface guild office hours | Confirm Surface.Env helper adoption + Surface.FS cache drop timeline for Zastava. | 140.D Zastava | Surface Guild · Zastava Observer/Webhook Guilds |
|
||||||
|
| 2025-11-23 | AirGap parity review (SBOM paths/versions/events) | Validate LNM fixtures, record hashes, and approve SBOM-SERVICE-21-001 start. | 140.B SbomService | SBOM Service Guild · Cartographer Guild · AirGap Guild |
|
||||||
|
|
||||||
### Meeting prep checklist
|
### Meeting prep checklist
|
||||||
|
|
||||||
@@ -231,7 +233,7 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
| SIGNALS-24-002 CAS promotion + signed manifests | 2025-11-14 | BLOCKED | Waiting on Platform Storage approval; CAS checklist published (`docs/signals/cas-promotion-24-002.md`). |
|
| SIGNALS-24-002 CAS promotion + signed manifests | 2025-11-14 | BLOCKED | Waiting on Platform Storage approval; CAS checklist published (`docs/signals/cas-promotion-24-002.md`). |
|
||||||
| SIGNALS-24-003 provenance enrichment + backfill | 2025-11-15 | BLOCKED | Await provenance appendix freeze/approval; checklist published (`docs/signals/provenance-24-003.md`). |
|
| SIGNALS-24-003 provenance enrichment + backfill | 2025-11-15 | BLOCKED | Await provenance appendix freeze/approval; checklist published (`docs/signals/provenance-24-003.md`). |
|
||||||
| Scanner analyzer artifact ETA & cache drop plan | 2025-11-13 | TODO | Scanner to publish Sprint 130 surface roadmap; Graph/Zastava blocked until then. |
|
| Scanner analyzer artifact ETA & cache drop plan | 2025-11-13 | TODO | Scanner to publish Sprint 130 surface roadmap; Graph/Zastava blocked until then. |
|
||||||
| Concelier Link-Not-Merge schema ratified | 2025-11-14 | BLOCKED | Requires `CONCELIER-GRAPH-21-001` + `CARTO-GRAPH-21-002` agreement; AirGap review scheduled after sign-off. |
|
| Concelier Link-Not-Merge schema ratified | 2025-11-14 | DONE | Agreement signed 2025-11-17; CONCELIER-GRAPH-21-001 and CARTO-GRAPH-21-002 implemented with observation event publisher 2025-11-22. AirGap review next. |
|
||||||
| Surface.Env helper adoption checklist | 2025-11-15 | TODO | Zastava guild preparing sealed-mode test harness; depends on Surface guild office hours outcomes. |
|
| Surface.Env helper adoption checklist | 2025-11-15 | TODO | Zastava guild preparing sealed-mode test harness; depends on Surface guild office hours outcomes. |
|
||||||
|
|
||||||
## Decisions needed (before 2025-11-15, refreshed 2025-11-13)
|
## Decisions needed (before 2025-11-15, refreshed 2025-11-13)
|
||||||
@@ -278,7 +280,7 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
|
|
||||||
# Blockers & coordination
|
# Blockers & coordination
|
||||||
|
|
||||||
- **Concelier Link-Not-Merge / Cartographer schemas** – SBOM-SERVICE-21-001..004 cannot start until `CONCELIER-GRAPH-21-001` and `CARTO-GRAPH-21-002` deliver the projection payloads.
|
- **Concelier Link-Not-Merge / Cartographer schemas** – SBOM-SERVICE-21-001..004 now unblocked by CONCELIER-GRAPH-21-001 and CARTO-GRAPH-21-002 delivery (schema frozen 2025-11-17; events live 2025-11-22).
|
||||||
- **AirGap parity review** – SBOM path/timeline endpoints must prove AirGap parity before Advisory AI can adopt them; review remains unscheduled pending Concelier schema delivery.
|
- **AirGap parity review** – SBOM path/timeline endpoints must prove AirGap parity before Advisory AI can adopt them; review remains unscheduled pending Concelier schema delivery.
|
||||||
- **Scanner surface artifacts** – GRAPH-INDEX-28-007+ and all ZASTAVA-SURFACE tasks depend on Sprint 130 analyzer outputs and cached layer metadata; need updated ETA from Scanner guild.
|
- **Scanner surface artifacts** – GRAPH-INDEX-28-007+ and all ZASTAVA-SURFACE tasks depend on Sprint 130 analyzer outputs and cached layer metadata; need updated ETA from Scanner guild.
|
||||||
- **Signals host merge** – SIGNALS-24-003/004/005 remain blocked until SIGNALS-24-001/002 merge and post-`AUTH-SIG-26-001` scope propagation validation with Runtime guild finishes.
|
- **Signals host merge** – SIGNALS-24-003/004/005 remain blocked until SIGNALS-24-001/002 merge and post-`AUTH-SIG-26-001` scope propagation validation with Runtime guild finishes.
|
||||||
@@ -310,7 +312,7 @@ This file now only tracks the runtime & signals status snapshot. Active backlog
|
|||||||
|
|
||||||
| Risk | Impact | Mitigation / owner |
|
| Risk | Impact | Mitigation / owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| LNM fixtures (overdue 2025-11-18) | SBOM-SERVICE-21-001..004 + Advisory AI SBOM endpoints stay blocked | Concelier Core · Cartographer · SBOM Service — publish 4–6 fixtures; mark add-only evolution; schedule AirGap review date. |
|
| LNM fixtures (staged 2025-11-22) | SBOM-SERVICE-21-001..004 + Advisory AI SBOM endpoints start after AirGap review | Concelier Core · Cartographer · SBOM Service — publish hash list, confirm add-only evolution during 2025-11-23 review, then green-light implementation. |
|
||||||
| Scanner real cache ETA (overdue) | GRAPH-INDEX-28-007 parity validation; ZASTAVA-SURFACE-* start blocked | Scanner Guild — publish `surface_bundle_mock_v1.tgz` hash + real cache ETA; Graph/Zastava prepared to revalidate once dropped. |
|
| Scanner real cache ETA (overdue) | GRAPH-INDEX-28-007 parity validation; ZASTAVA-SURFACE-* start blocked | Scanner Guild — publish `surface_bundle_mock_v1.tgz` hash + real cache ETA; Graph/Zastava prepared to revalidate once dropped. |
|
||||||
| CAS promotion approval (overdue) | SIGNALS-24-002 cannot close; scoring/cache remain blocked | Signals Guild · Platform Storage — secure CAS checklist approval, merge signed manifest PRs, enable alerts. |
|
| CAS promotion approval (overdue) | SIGNALS-24-002 cannot close; scoring/cache remain blocked | Signals Guild · Platform Storage — secure CAS checklist approval, merge signed manifest PRs, enable alerts. |
|
||||||
| Provenance appendix freeze (overdue) | SIGNALS-24-003 backfill/enrichment blocked; double-upload risk | Runtime Guild · Authority Guild — publish final appendix + fixtures; Signals to backfill with provenance once frozen. |
|
| Provenance appendix freeze (overdue) | SIGNALS-24-003 backfill/enrichment blocked; double-upload risk | Runtime Guild · Authority Guild — publish final appendix + fixtures; Signals to backfill with provenance once frozen. |
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
| 5 | SBOM-ORCH-32-001 | TODO | Register SBOM ingest/index sources; embed worker SDK; emit artifact hashes and job metadata. | SBOM Service Guild | Register SBOM ingest/index sources with orchestrator. |
|
| 5 | SBOM-ORCH-32-001 | TODO | Register SBOM ingest/index sources; embed worker SDK; emit artifact hashes and job metadata. | SBOM Service Guild | Register SBOM ingest/index sources with orchestrator. |
|
||||||
| 6 | SBOM-ORCH-33-001 | TODO | Depends on SBOM-ORCH-32-001; report backpressure metrics, honor pause/throttle signals, classify sbom job errors. | SBOM Service Guild | Report backpressure metrics and handle orchestrator control signals. |
|
| 6 | SBOM-ORCH-33-001 | TODO | Depends on SBOM-ORCH-32-001; report backpressure metrics, honor pause/throttle signals, classify sbom job errors. | SBOM Service Guild | Report backpressure metrics and handle orchestrator control signals. |
|
||||||
| 7 | SBOM-ORCH-34-001 | TODO | Depends on SBOM-ORCH-33-001; implement orchestrator backfill and watermark reconciliation for idempotent artifact reuse. | SBOM Service Guild | Implement orchestrator backfill + watermark reconciliation. |
|
| 7 | SBOM-ORCH-34-001 | TODO | Depends on SBOM-ORCH-33-001; implement orchestrator backfill and watermark reconciliation for idempotent artifact reuse. | SBOM Service Guild | Implement orchestrator backfill + watermark reconciliation. |
|
||||||
| 8 | SBOM-SERVICE-21-001 | BLOCKED | PREP-SBOM-SERVICE-21-001-WAITING-ON-LNM-V1-FI | SBOM Service Guild; Cartographer Guild | Link-Not-Merge v1 frozen schema and deterministic read API. |
|
| 8 | SBOM-SERVICE-21-001 | DOING (2025-11-23) | PREP-SBOM-SERVICE-21-001-WAITING-ON-LNM-V1-FI | SBOM Service Guild; Cartographer Guild | AirGap review hashes captured; begin deterministic projection read API implementation (paths/versions/events) per LNM v1. |
|
||||||
| 9 | SBOM-SERVICE-21-002 | TODO | Depends on SBOM-SERVICE-21-001; emit `sbom.version.created` change events and add replay/backfill tooling. | SBOM Service Guild; Scheduler Guild | Emit change events carrying digest/version metadata for Graph Indexer builds. |
|
| 9 | SBOM-SERVICE-21-002 | TODO | Depends on SBOM-SERVICE-21-001; emit `sbom.version.created` change events and add replay/backfill tooling. | SBOM Service Guild; Scheduler Guild | Emit change events carrying digest/version metadata for Graph Indexer builds. |
|
||||||
| 10 | SBOM-SERVICE-21-003 | TODO | Depends on SBOM-SERVICE-21-002; entrypoint/service node management API feeding Cartographer path relevance with deterministic defaults. | SBOM Service Guild | Provide entrypoint/service node management API. |
|
| 10 | SBOM-SERVICE-21-003 | TODO | Depends on SBOM-SERVICE-21-002; entrypoint/service node management API feeding Cartographer path relevance with deterministic defaults. | SBOM Service Guild | Provide entrypoint/service node management API. |
|
||||||
| 11 | SBOM-SERVICE-21-004 | TODO | Depends on SBOM-SERVICE-21-003; wire metrics (`sbom_projection_seconds`, `sbom_projection_size`), traces, tenant-annotated logs; set backlog alerts. | SBOM Service Guild; Observability Guild | Wire observability for SBOM projections. |
|
| 11 | SBOM-SERVICE-21-004 | TODO | Depends on SBOM-SERVICE-21-003; wire metrics (`sbom_projection_seconds`, `sbom_projection_size`), traces, tenant-annotated logs; set backlog alerts. | SBOM Service Guild; Observability Guild | Wire observability for SBOM projections. |
|
||||||
@@ -41,8 +41,8 @@
|
|||||||
## Action Tracker
|
## Action Tracker
|
||||||
| Action | Owner(s) | Due | Status |
|
| Action | Owner(s) | Due | Status |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Provide LNM v1 fixtures for SBOM projections. | Cartographer Guild | 2025-11-18 | OVERDUE (escalate; follow-up 2025-11-19) |
|
| Provide LNM v1 fixtures for SBOM projections. | Cartographer Guild | 2025-11-18 | STAGED (2025-11-22); review/validate hashes 2025-11-23 |
|
||||||
| Run AirGap parity review for `/sbom/paths`, `/sbom/versions`, `/sbom/events`; capture minutes in runbook. | Observability Guild · SBOM Service Guild | 2025-11-23 | Pending (template published) |
|
| Run AirGap parity review for `/sbom/paths`, `/sbom/versions`, `/sbom/events`; capture minutes in runbook. | Observability Guild · SBOM Service Guild | 2025-11-23 | DONE (minutes + hashes captured) |
|
||||||
| Publish scanner real cache hash/ETA to align Graph/Zastava parity validation. | Scanner Guild | 2025-11-18 | OVERDUE (mirrored from sprint 0140) |
|
| Publish scanner real cache hash/ETA to align Graph/Zastava parity validation. | Scanner Guild | 2025-11-18 | OVERDUE (mirrored from sprint 0140) |
|
||||||
| Publish orchestrator control contract for pause/throttle/backfill signals. | Orchestrator Guild | 2025-11-19 | Pending |
|
| Publish orchestrator control contract for pause/throttle/backfill signals. | Orchestrator Guild | 2025-11-19 | Pending |
|
||||||
| Create `src/SbomService/AGENTS.md` (roles, prerequisites, determinism/testing rules). | SBOM Service Guild · Module PM | 2025-11-19 | DONE |
|
| Create `src/SbomService/AGENTS.md` (roles, prerequisites, determinism/testing rules). | SBOM Service Guild · Module PM | 2025-11-19 | DONE |
|
||||||
@@ -51,6 +51,7 @@
|
|||||||
## Execution Log
|
## Execution Log
|
||||||
| Date (UTC) | Update | Owner |
|
| Date (UTC) | Update | Owner |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
|
| 2025-11-23 | AirGap parity review executed; fixture hash recorded in `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`; SBOM-SERVICE-21-001 → DOING. | Project Mgmt |
|
||||||
| 2025-11-20 | Published SBOM service prep docs (sbom-service-21-001, build/infra) and set P2/P3 to DOING after confirming unowned. | Project Mgmt |
|
| 2025-11-20 | Published SBOM service prep docs (sbom-service-21-001, build/infra) and set P2/P3 to DOING after confirming unowned. | Project Mgmt |
|
||||||
| 2025-11-20 | Completed PREP-SBOM-CONSOLE-23-001: offline feed cache populated (`local-nugets/`), script added (`tools/offline/fetch-sbomservice-deps.sh`), doc published at `docs/modules/sbomservice/offline-feed-plan.md`. | Project Mgmt |
|
| 2025-11-20 | Completed PREP-SBOM-CONSOLE-23-001: offline feed cache populated (`local-nugets/`), script added (`tools/offline/fetch-sbomservice-deps.sh`), doc published at `docs/modules/sbomservice/offline-feed-plan.md`. | Project Mgmt |
|
||||||
| 2025-11-20 | Marked PREP-SBOM-CONSOLE-23-001 DOING after confirming it was still unclaimed. | Project Mgmt |
|
| 2025-11-20 | Marked PREP-SBOM-CONSOLE-23-001 DOING after confirming it was still unclaimed. | Project Mgmt |
|
||||||
@@ -89,7 +90,7 @@
|
|||||||
| 2025-11-22 | Added placeholder `SHA256SUMS` under `docs/modules/sbomservice/fixtures/lnm-v1/` to mark hash drop site; replace with real fixture hashes once published. | Implementer |
|
| 2025-11-22 | Added placeholder `SHA256SUMS` under `docs/modules/sbomservice/fixtures/lnm-v1/` to mark hash drop site; replace with real fixture hashes once published. | Implementer |
|
||||||
|
|
||||||
## Decisions & Risks
|
## Decisions & Risks
|
||||||
- LNM v1 fixtures due 2025-11-18 remain outstanding; now OVERDUE and tracked for 2025-11-19 follow-up. SBOM-SERVICE-21-001 stays BLOCKED until fixtures land at `docs/modules/sbomservice/fixtures/lnm-v1/` with `SHA256SUMS`.
|
- LNM v1 fixtures staged (2025-11-22) and provisionally approved in 2025-11-23 AirGap review; hash recorded in `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS`. SBOM-SERVICE-21-001 is DOING; 21-002..004 remain TODO pending implementation sequence.
|
||||||
- Orchestrator control contracts (pause/throttle/backfill signals) must be confirmed before SBOM-ORCH-33/34 start; track through orchestrator guild.
|
- Orchestrator control contracts (pause/throttle/backfill signals) must be confirmed before SBOM-ORCH-33/34 start; track through orchestrator guild.
|
||||||
- Keep `docs/modules/sbomservice/architecture.md` aligned with schema/event decisions made during implementation.
|
- Keep `docs/modules/sbomservice/architecture.md` aligned with schema/event decisions made during implementation.
|
||||||
- Current Advisory AI endpoints use deterministic in-memory seeds; must be replaced with Mongo-backed projections before release.
|
- Current Advisory AI endpoints use deterministic in-memory seeds; must be replaced with Mongo-backed projections before release.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,109 @@
|
|||||||
# Blocked Tree
|
# Blocked Task Dependency Tree (as of 2025-11-23)
|
||||||
|
|
||||||
- EXCITITOR-CONSOLE-23-001 [BLOCKED]
|
- Concelier ingestion & Link-Not-Merge
|
||||||
- EXCITITOR-CONSOLE-23-002 [BLOCKED]
|
- MIRROR-CRT-56-001 (DONE; thin bundle v1 sample + hashes published)
|
||||||
- EXCITITOR-CONSOLE-23-003 [BLOCKED]
|
- MIRROR-CRT-56-002 (BLOCKED: CI Ed25519 key via MIRROR_SIGN_KEY_B64 missing; signing cannot proceed)
|
||||||
- EXCITITOR-CORE-AOC-19-002 [BLOCKED]
|
- MIRROR-KEY-56-002-CI (BLOCKED: CI secret `MIRROR_SIGN_KEY_B64` not provided; see docs/modules/mirror/signing-runbook.md)
|
||||||
- EXCITITOR-CORE-AOC-19-003 [BLOCKED]
|
- MIRROR-CRT-57-001 (DONE; OCI layout emitted when OCI=1)
|
||||||
- EXCITITOR-CORE-AOC-19-004 [DOING]
|
- MIRROR-CRT-57-002 (depends on 56-002 and AIRGAP-TIME-57-001)
|
||||||
- EXCITITOR-CORE-AOC-19-013 [DOING]
|
- MIRROR-CRT-58-001/002 (depend on 56-002, EXPORT-OBS-54-001, CLI-AIRGAP-56-001)
|
||||||
- EXCITITOR-GRAPH-21-001 [DOING]
|
- PROV-OBS-53-001 (DONE; observer doc + verifier script)
|
||||||
- EXCITITOR-GRAPH-21-002 [DOING]
|
- AIRGAP-TIME-57-001 (needs production trust roots + signing; schema + draft trust-roots bundle published)
|
||||||
- EXCITITOR-GRAPH-21-005 [DOING]
|
- EXPORT-OBS-51-001 / 54-001 (waiting on DSSE/TUF profile to stabilize manifest)
|
||||||
- EXCITITOR-GRAPH-24-101 [BLOCKED]
|
- CLI-AIRGAP-56-001 (needs 56-002 signing + 58-001 CLI path)
|
||||||
- EXCITITOR-GRAPH-24-102 [BLOCKED]
|
- CONCELIER-AIRGAP-56-001..58-001 <- PREP-ART-56-001, PREP-EVIDENCE-BDL-01
|
||||||
- Consensus removal [DOING]
|
- CONCELIER-CONSOLE-23-001..003 <- PREP-CONSOLE-FIXTURES-29; PREP-EVIDENCE-BDL-01
|
||||||
- Graph overlays [BLOCKED]
|
- FEEDCONN-ICSCISA-02-012 / KISA-02-008 <- PREP-FEEDCONN-ICS-KISA-PLAN
|
||||||
- PROV-OBS-53-002 [BLOCKED] · Await CI rerun to clear MSB6006 (see SPRINT_0513_0001_0001_provenance)
|
|
||||||
- PROV-OBS-53-003 [BLOCKED] · Blocked on PROV-OBS-53-002 CI verification (see SPRINT_0513_0001_0001_provenance)
|
- SBOM Service (Link-Not-Merge consumers)
|
||||||
- CLI-AIAI-31-001 [BLOCKED] · Scanner analyzers (Node/Java) fail compile during `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests`; see SPRINT_0201_0001_0001_cli_i
|
- SBOM-SERVICE-21-001 (projection read API) — UNBLOCKED/DOING: AirGap review completed 2025-11-23; fixtures + hash recorded in `docs/modules/sbomservice/fixtures/lnm-v1/`; implementing `/sboms/{snapshotId}/projection`.
|
||||||
- CLI-HK-201-002 [BLOCKED] · Await offline kit status contract and sample bundle; see SPRINT_0201_0001_0001_cli_i
|
- SBOM-SERVICE-21-002..004 — TODO: depend on 21-001 implementation; proceed after projection API lands.
|
||||||
|
|
||||||
|
- Concelier orchestrator / policy / risk chain
|
||||||
|
- POLICY-20-001 (API contract; DOING in Sprint 0114) -> CONCELIER-POLICY-20-003 -> CONCELIER-POLICY-23-001 -> CONCELIER-POLICY-23-002
|
||||||
|
- POLICY-AUTH-SIGNALS-LIB-115 (shared contract NuGet 0.1.0-alpha, Sprint 0115)
|
||||||
|
- CONCELIER-RISK-66-001 -> 66-002 -> 67-001 -> 68-001 -> 69-001
|
||||||
|
- CONCELIER-SIG-26-001
|
||||||
|
- CONCELIER-TEN-48-001
|
||||||
|
- CONCELIER-VEXLENS-30-001 (also needs PREP-CONCELIER-VULN-29-001 & VEXLENS-30-005)
|
||||||
|
- CONCELIER-VULN-29-004 <- CONCELIER-VULN-29-001
|
||||||
|
- CONCELIER-ORCH-32-001 (needs CI/clean runner) -> 32-002 -> 33-001 -> 34-001
|
||||||
|
|
||||||
|
- Concelier Web chains
|
||||||
|
- CONCELIER-WEB-AIRGAP-56-001 -> 56-002 -> 57-001 -> 58-001
|
||||||
|
- CONCELIER-WEB-OAS-61-002 -> 62-001 -> 63-001
|
||||||
|
- CONCELIER-WEB-OBS-50-001 ✅ (telemetry core adopted 2025-11-07) -> 51-001 ✅ (health endpoint shipped 2025-11-23) -> 52-001
|
||||||
|
|
||||||
|
- Advisory AI docs & packaging
|
||||||
|
- AIAI-PACKAGING-31-002 & AIAI-DOCS-31-001 <- SBOM feeds + CLI/Policy artefacts
|
||||||
|
- DOCS-AIAI-31-005 -> 31-006 -> 31-008 -> 31-009 (all gated by DOCS-UNBLOCK-CLI-KNOBS-301 <- CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001)
|
||||||
|
|
||||||
|
- Policy Engine (core) chain
|
||||||
|
- POLICY-ENGINE-29-002 (missing contract) -> 29-003 -> 29-004
|
||||||
|
- 30-001 / 30-002 / 30-003 / 30-101 (depend on 29-004)
|
||||||
|
- 31-001 / 31-002 (depend on 29/30 chain)
|
||||||
|
- 32-101, 33-101, 34-101, 35-201, 38-201, 40-001, 40-002 (prep items waiting on same upstream contracts)
|
||||||
|
- POLICY-AOC-19-001 -> 19-002 -> 19-003 -> 19-004
|
||||||
|
- POLICY-AIRGAP-56-001 -> 56-002 -> 57-001 -> 57-002 -> 58-001
|
||||||
|
- POLICY-ATTEST-73-001 -> 73-002 -> 74-001 -> 74-002
|
||||||
|
- POLICY-CONSOLE-23-001 (needs Console API contract)
|
||||||
|
- EXPORT-CONSOLE-23-001 (needs export bundle/job spec)
|
||||||
|
|
||||||
|
- Findings Ledger (Policy Engine sprints 0120–0122)
|
||||||
|
- LEDGER-OAS-61-001 -> 61-002 -> 62-001 -> 63-001
|
||||||
|
- LEDGER-AIRGAP-56-002 -> 57-001 -> 58-001
|
||||||
|
- LEDGER-ATTEST-73-001 -> 73-002
|
||||||
|
- LEDGER-RISK-67-001 -> 68-001 -> 69-001
|
||||||
|
- LEDGER-PACKS-42-001 (snapshot/time-travel contract pending)
|
||||||
|
- LEDGER-OBS-55-001 (depends on 54-001 attestation telemetry)
|
||||||
|
- LEDGER-TEN-48-001 (needs platform approval/RLS plan)
|
||||||
|
- LEDGER-29-009 (waiting DevOps paths for Helm/Compose/offline kit assets)
|
||||||
|
|
||||||
|
- API Governance / OpenAPI
|
||||||
|
- OAS-61-002 ratification -> OAS-62-001 -> OAS-62-002 -> OAS-63-001
|
||||||
|
- APIGOV-63-001 (needs Notification Studio templates + deprecation metadata schema)
|
||||||
|
|
||||||
|
- CLI feature chain
|
||||||
|
- CLI-NOTIFY-38-001 (schema missing) -> CLI-NOTIFY-39-001
|
||||||
|
- CLI-EXPORT-35-001 (blocked: export profile schema + storage fixtures not delivered)
|
||||||
|
|
||||||
|
- Scanner surface
|
||||||
|
- SCANNER-ENV-03 <- SCANNER-ENV-02
|
||||||
|
- SURFACE-SECRETS-01 -> SURFACE-SECRETS-02 -> SURFACE-VAL-01 (also needs SURFACE-FS-01 & SURFACE-ENV-01)
|
||||||
|
- SCANNER-EVENTS-16-301 (awaiting orchestrator/Notifier envelope contract)
|
||||||
|
|
||||||
|
- Excititor graph & air-gap
|
||||||
|
- EXCITITOR-GRAPH-24-101 <- 21-005 ingest overlays
|
||||||
|
- EXCITITOR-GRAPH-24-102 <- 24-101
|
||||||
|
- EXCITITOR-AIRGAP-57-001 <- 56-001 wiring
|
||||||
|
- EXCITITOR-AIRGAP-58-001 <- 56-001 storage layout + Export Center manifest
|
||||||
|
|
||||||
|
- DevOps pipeline blocks
|
||||||
|
- DEVOPS-LNM-TOOLING-22-000 -> DEVOPS-LNM-22-001 -> DEVOPS-LNM-22-002
|
||||||
|
- DEVOPS-AOC-19-001 -> 19-002 -> 19-003
|
||||||
|
- DEVOPS-AIRGAP-57-002 <- DEVOPS-AIRGAP-57-001
|
||||||
|
- DEVOPS-OFFLINE-17-004 (waits for next release pipeline `out/release/debug`)
|
||||||
|
- DEVOPS-REL-17-004 (release workflow must publish debug artifacts)
|
||||||
|
- DEVOPS-CONSOLE-23-001 (no upstream CI contract yet)
|
||||||
|
- DEVOPS-EXPORT-35-001 (needs object storage fixtures + dashboards)
|
||||||
|
|
||||||
|
- Deployment
|
||||||
|
- DEPLOY-EXPORT-35-001 (waiting exporter overlays/secrets)
|
||||||
|
- DEPLOY-NOTIFY-38-001 (waiting notifier overlays/secrets)
|
||||||
|
|
||||||
|
- Documentation ladders
|
||||||
|
- Docs Tasks ladder 200.A (blocked pending upstream SBOM/CLI/Policy/AirGap artefacts)
|
||||||
|
- DOCS-LNM chain: DOCS-LNM-22-001 -> 22-002 -> 22-003; DOCS-LNM-22-005 waits on 22-004
|
||||||
|
- Policy docs chain A: DOCS-POLICY-27-001 -> 27-002 -> 27-003 -> 27-004 -> 27-005
|
||||||
|
- Policy docs chain B: DOCS-POLICY-27-006 -> 27-007 -> 27-008 -> 27-009 -> 27-010 -> 27-011 -> 27-012 -> 27-013 -> 27-014
|
||||||
|
- DOCS-SCANNER-DET-01 <- Sprint 136 determinism fixtures
|
||||||
|
- EXCITITOR-DOCS-0001 (awaits Excititor chunk API CI + console contracts)
|
||||||
|
|
||||||
|
- Provenance / Observability
|
||||||
|
- PROV-OBS-53-002 (DOING: Attestation.Tests cleaned; canonical JSON/Merkle tests fixed, restore warning cleared; awaiting full suite/CI pass) -> PROV-OBS-53-003
|
||||||
|
|
||||||
|
- CLI/Advisory AI handoff
|
||||||
|
- SBOM-AIAI-31-003 <- CLI-VULN-29-001; CLI-VEX-30-001
|
||||||
|
- DOCS-AIAI-31-005/006/008/009 <- CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001
|
||||||
|
|
||||||
|
Note: POLICY-20-001 is defined and tracked in `docs/implplan/SPRINT_0114_0001_0003_concelier_iii.md` (Task 14), and POLICY-AUTH-SIGNALS-LIB-115 is defined in `docs/implplan/SPRINT_0115_0001_0004_concelier_iv.md` (Task 0); both scopes match the expectations captured here.
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
| AIAI-31-007 | DONE | 2025-11-06 | SPRINT_0111_0001_0001_advisoryai | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | — | — | ADAI0101 |
|
| AIAI-31-007 | DONE | 2025-11-06 | SPRINT_0111_0001_0001_advisoryai | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | — | — | ADAI0101 |
|
||||||
| AGENTS-AIAI-UPDATE | DONE | 2025-11-17 | SPRINT_0111_0001_0001_advisoryai | PM Guild · Advisory AI Guild | src/AdvisoryAI; docs/modules/advisory-ai | Create `src/AdvisoryAI/AGENTS.md` charter covering roles, working agreements, allowed shared dirs, and required runbooks/tests. | docs/modules/advisory-ai/architecture.md; docs/modules/platform/architecture-overview.md | AGNT0101 |
|
| AGENTS-AIAI-UPDATE | DONE | 2025-11-17 | SPRINT_0111_0001_0001_advisoryai | PM Guild · Advisory AI Guild | src/AdvisoryAI; docs/modules/advisory-ai | Create `src/AdvisoryAI/AGENTS.md` charter covering roles, working agreements, allowed shared dirs, and required runbooks/tests. | docs/modules/advisory-ai/architecture.md; docs/modules/platform/architecture-overview.md | AGNT0101 |
|
||||||
| LEDGER-29-006 | TODO | | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild | | — | — | PLLG0101 |
|
| LEDGER-29-006 | TODO | | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild | | — | — | PLLG0101 |
|
||||||
| CARTO-GRAPH-21-002 | TODO | | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
| CARTO-GRAPH-21-002 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
||||||
| SURFACE-FS-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
| SURFACE-FS-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
||||||
| SURFACE-FS-02 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
| SURFACE-FS-02 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
||||||
| SCANNER-ANALYZERS-LANG-10-309 | TODO | | SPRINT_131_scanner_surface | Language Analyzer Guild | | — | — | SCSA0101 |
|
| SCANNER-ANALYZERS-LANG-10-309 | TODO | | SPRINT_131_scanner_surface | Language Analyzer Guild | | — | — | SCSA0101 |
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
| SCANNER-ENTRYTRACE-18-508 | TODO | | SPRINT_136_scanner_surface | EntryTrace Guild | | — | — | SCSS0101 |
|
| SCANNER-ENTRYTRACE-18-508 | TODO | | SPRINT_136_scanner_surface | EntryTrace Guild | | — | — | SCSS0101 |
|
||||||
| SCANNER-SECRETS-02 | TODO | | SPRINT_136_scanner_surface | Secrets Analyzer Guild | | — | — | SCSS0101 |
|
| SCANNER-SECRETS-02 | TODO | | SPRINT_136_scanner_surface | Secrets Analyzer Guild | | — | — | SCSS0101 |
|
||||||
| SCANNER-SURFACE-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild | | — | — | SCSS0101 |
|
| SCANNER-SURFACE-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild | | — | — | SCSS0101 |
|
||||||
| CARTO-GRAPH-21-002 | TODO | | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
| CARTO-GRAPH-21-002 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
||||||
| POLICY-ENGINE-27-004 | TODO | | SPRINT_124_policy_reasoning | Policy Guild | | — | — | PLPE0102 |
|
| POLICY-ENGINE-27-004 | TODO | | SPRINT_124_policy_reasoning | Policy Guild | | — | — | PLPE0102 |
|
||||||
| --JOB-ORCHESTRATOR-DOCS-0001 | TODO | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Docs Guild (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
| --JOB-ORCHESTRATOR-DOCS-0001 | TODO | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Docs Guild (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
||||||
| --JOB-ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
| --JOB-ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
||||||
@@ -79,7 +79,7 @@
|
|||||||
| AI-DOCS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
| AI-DOCS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
||||||
| AI-OPS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Ops Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
| AI-OPS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Ops Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
||||||
| AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 |
|
| AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 |
|
||||||
| AIAI-31-002 | DOING | | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Needs CONCELIER-GRAPH-21-001..002 unblock | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 |
|
| AIAI-31-002 | DONE | 2025-11-18 | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Structured field/caching aligned to LNM schema; awaiting downstream adoption only. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 |
|
||||||
| AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 |
|
| AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 |
|
||||||
| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 |
|
| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 |
|
||||||
| AIAI-31-005 | BLOCKED | | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 |
|
| AIAI-31-005 | BLOCKED | | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 |
|
||||||
@@ -421,7 +421,7 @@
|
|||||||
| CONCELIER-OAS-61-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core + API Contracts Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Update the OpenAPI spec so every observation/linkset/timeline endpoint documents provenance fields, tenant scopes, and AOC guarantees (no consensus fields), giving downstream SDKs unambiguous contracts. | Wait for CCPR0101 policy updates | CCOA0101 |
|
| CONCELIER-OAS-61-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core + API Contracts Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Update the OpenAPI spec so every observation/linkset/timeline endpoint documents provenance fields, tenant scopes, and AOC guarantees (no consensus fields), giving downstream SDKs unambiguous contracts. | Wait for CCPR0101 policy updates | CCOA0101 |
|
||||||
| CONCELIER-OAS-61-002 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Provide realistic examples (conflict linksets, multi-source severity, timeline snippets) showing how raw advisories are surfaced without merges; wire them into docs/SDKs. Depends on CONCELIER-OAS-61-001. | Depends on #1 | CCOA0101 |
|
| CONCELIER-OAS-61-002 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Provide realistic examples (conflict linksets, multi-source severity, timeline snippets) showing how raw advisories are surfaced without merges; wire them into docs/SDKs. Depends on CONCELIER-OAS-61-001. | Depends on #1 | CCOA0101 |
|
||||||
| CONCELIER-OAS-62-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core + SDK Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Add SDK scenarios covering advisory search, pagination, and conflict handling to ensure each language client preserves provenance fields and does not infer verdicts. Depends on CONCELIER-OAS-61-002. | Needs SDK requirements from CLSB0101 | CCOA0101 |
|
| CONCELIER-OAS-62-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core + SDK Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Add SDK scenarios covering advisory search, pagination, and conflict handling to ensure each language client preserves provenance fields and does not infer verdicts. Depends on CONCELIER-OAS-61-002. | Needs SDK requirements from CLSB0101 | CCOA0101 |
|
||||||
| CONCELIER-OBS-51-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · DevOps Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Emit ingestion latency, queue depth, and AOC violation metrics with burn-rate alerts so we can prove the evidence pipeline remains healthy without resorting to heuristics. | Wait for 046_TLTY0101 metric schema drop | CNOB0101 |
|
| CONCELIER-OBS-51-001 | DOING | 2025-11-23 | SPRINT_114_concelier_iii | Concelier Core Guild · DevOps Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Emit ingestion latency, queue depth, and AOC violation metrics with burn-rate alerts so we can prove the evidence pipeline remains healthy without resorting to heuristics. | Telemetry schema 046_TLTY0101 published (2025-11-23) | CNOB0101 |
|
||||||
| CONCELIER-OBS-52-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Produce timeline records for ingest/normalization/linkset updates containing trace IDs, conflict summaries, and evidence hashes—pure facts for downstream replay. Depends on CONCELIER-OBS-51-001. | Needs #1 merged to reuse structured logging helpers | CNOB0101 |
|
| CONCELIER-OBS-52-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Produce timeline records for ingest/normalization/linkset updates containing trace IDs, conflict summaries, and evidence hashes—pure facts for downstream replay. Depends on CONCELIER-OBS-51-001. | Needs #1 merged to reuse structured logging helpers | CNOB0101 |
|
||||||
| CONCELIER-OBS-53-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Evidence Locker Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Generate evidence locker bundles (raw doc, normalization diff, linkset) with Merkle manifests so audits can replay advisory history without touching live Mongo. Depends on CONCELIER-OBS-52-001. | Requires Evidence Locker contract from 002_ATEL0101 | CNOB0101 |
|
| CONCELIER-OBS-53-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Evidence Locker Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Generate evidence locker bundles (raw doc, normalization diff, linkset) with Merkle manifests so audits can replay advisory history without touching live Mongo. Depends on CONCELIER-OBS-52-001. | Requires Evidence Locker contract from 002_ATEL0101 | CNOB0101 |
|
||||||
| CONCELIER-OBS-54-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Provenance Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Attach DSSE attestations to advisory batches, expose verification APIs, and link attestation IDs into timeline + ledger for transparency. Depends on CONCELIER-OBS-53-001. | Blocked by Link-Not-Merge schema finalization (005_ATLN0101) | CNOB0101 |
|
| CONCELIER-OBS-54-001 | TODO | | SPRINT_114_concelier_iii | Concelier Core Guild · Provenance Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Attach DSSE attestations to advisory batches, expose verification APIs, and link attestation IDs into timeline + ledger for transparency. Depends on CONCELIER-OBS-53-001. | Blocked by Link-Not-Merge schema finalization (005_ATLN0101) | CNOB0101 |
|
||||||
@@ -458,7 +458,7 @@
|
|||||||
| CONCELIER-WEB-OAS-61-002 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Ensure every API returns the standardized error envelope and update controllers/tests accordingly (prereq for SDK/doc alignment). | Wait for CCOA0101 spec | CCWO0101 |
|
| CONCELIER-WEB-OAS-61-002 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Ensure every API returns the standardized error envelope and update controllers/tests accordingly (prereq for SDK/doc alignment). | Wait for CCOA0101 spec | CCWO0101 |
|
||||||
| CONCELIER-WEB-OAS-62-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Publish curated examples for observations/linksets/conflicts and wire them into the developer portal. Depends on CONCELIER-WEB-OAS-61-002. | Depends on #1 | CCWO0101 |
|
| CONCELIER-WEB-OAS-62-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Publish curated examples for observations/linksets/conflicts and wire them into the developer portal. Depends on CONCELIER-WEB-OAS-61-002. | Depends on #1 | CCWO0101 |
|
||||||
| CONCELIER-WEB-OAS-63-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild · API Governance Guild | src/Concelier/StellaOps.Concelier.WebService | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. Depends on CONCELIER-WEB-OAS-62-001. | Needs governance approval | CCWO0101 |
|
| CONCELIER-WEB-OAS-63-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild · API Governance Guild | src/Concelier/StellaOps.Concelier.WebService | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. Depends on CONCELIER-WEB-OAS-62-001. | Needs governance approval | CCWO0101 |
|
||||||
| CONCELIER-WEB-OBS-51-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Add `/obs/concelier/health` surfaces for ingest health, queue depth, and SLO status so Console widgets can display real-time evidence pipeline stats. Depends on CONCELIER-WEB-OBS-50-001. | Need telemetry schema baseline from 046_TLTY0101 | CNOB0102 |
|
| CONCELIER-WEB-OBS-51-001 | DONE | 2025-11-23 | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Add `/obs/concelier/health` surfaces for ingest health, queue depth, and SLO status so Console widgets can display real-time evidence pipeline stats. | Telemetry schema 046_TLTY0101 published (2025-11-23) | CNOB0102 |
|
||||||
| CONCELIER-WEB-OBS-52-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, and audit logging so operators can monitor evidence changes live. Depends on CONCELIER-WEB-OBS-51-001. | Requires #1 merged so we reuse correlation IDs | CNOB0102 |
|
| CONCELIER-WEB-OBS-52-001 | TODO | | SPRINT_116_concelier_v | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, and audit logging so operators can monitor evidence changes live. Depends on CONCELIER-WEB-OBS-51-001. | Requires #1 merged so we reuse correlation IDs | CNOB0102 |
|
||||||
| CONCELIER-WEB-OBS-53-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Add `/evidence/advisories/*` routes that proxy evidence locker snapshots, verify `evidence:read` scopes, and return signed manifest metadata—no shortcut paths into raw storage. Depends on CONCELIER-WEB-OBS-52-001. | Blocked on Evidence Locker DSSE feed (002_ATEL0101) | CNOB0102 |
|
| CONCELIER-WEB-OBS-53-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild · Evidence Locker Guild | src/Concelier/StellaOps.Concelier.WebService | Add `/evidence/advisories/*` routes that proxy evidence locker snapshots, verify `evidence:read` scopes, and return signed manifest metadata—no shortcut paths into raw storage. Depends on CONCELIER-WEB-OBS-52-001. | Blocked on Evidence Locker DSSE feed (002_ATEL0101) | CNOB0102 |
|
||||||
| CONCELIER-WEB-OBS-54-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/attestations/advisories/*` endpoints surfacing DSSE status, verification summary, and provenance chain so CLI/Console can audit trust without hitting databases. Depends on CONCELIER-WEB-OBS-53-001. | Depends on Link-Not-Merge schema (005_ATLN0101) | CNOB0102 |
|
| CONCELIER-WEB-OBS-54-001 | TODO | | SPRINT_117_concelier_vi | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/attestations/advisories/*` endpoints surfacing DSSE status, verification summary, and provenance chain so CLI/Console can audit trust without hitting databases. Depends on CONCELIER-WEB-OBS-53-001. | Depends on Link-Not-Merge schema (005_ATLN0101) | CNOB0102 |
|
||||||
@@ -694,7 +694,7 @@
|
|||||||
| DOCS-FORENSICS-53-003 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Timeline Indexer Guild | docs/modules/evidence-locker/forensics.md | Publish `/docs/forensics/timeline.md` with schema, event kinds, filters, query examples, and imposed rule banner. Dependencies: DOCS-FORENSICS-53-002. | Requires timeline indexer export from 055_AGIM0101 | DOEL0101 |
|
| DOCS-FORENSICS-53-003 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Timeline Indexer Guild | docs/modules/evidence-locker/forensics.md | Publish `/docs/forensics/timeline.md` with schema, event kinds, filters, query examples, and imposed rule banner. Dependencies: DOCS-FORENSICS-53-002. | Requires timeline indexer export from 055_AGIM0101 | DOEL0101 |
|
||||||
| DOCS-GRAPH-24-001 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Graph Guild | docs/modules/graph | Author `/docs/ui/sbom-graph-explorer.md` detailing overlays, filters, saved views, accessibility, and AOC visibility. | Wait for GRAP0101 contract freeze | DOGR0101 |
|
| DOCS-GRAPH-24-001 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Graph Guild | docs/modules/graph | Author `/docs/ui/sbom-graph-explorer.md` detailing overlays, filters, saved views, accessibility, and AOC visibility. | Wait for GRAP0101 contract freeze | DOGR0101 |
|
||||||
| DOCS-GRAPH-24-002 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · UI Guild | docs/modules/graph | Publish `/docs/ui/vulnerability-explorer.md` covering table usage, grouping, fix suggestions, Why drawer. Dependencies: DOCS-GRAPH-24-001. | Needs SBOM/VEX dataflow confirmation (PLLG0104) | DOGR0101 |
|
| DOCS-GRAPH-24-002 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · UI Guild | docs/modules/graph | Publish `/docs/ui/vulnerability-explorer.md` covering table usage, grouping, fix suggestions, Why drawer. Dependencies: DOCS-GRAPH-24-001. | Needs SBOM/VEX dataflow confirmation (PLLG0104) | DOGR0101 |
|
||||||
| DOCS-GRAPH-24-003 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · SBOM Guild | docs/modules/graph | Create `/docs/modules/graph/architecture-index.md` describing data model, ingestion pipeline, caches, events. Dependencies: DOCS-GRAPH-24-002. | Blocked on SBOM join spec from CARTO-GRAPH-21-002 | DOGR0101 |
|
| DOCS-GRAPH-24-003 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · SBOM Guild | docs/modules/graph | Create `/docs/modules/graph/architecture-index.md` describing data model, ingestion pipeline, caches, events. Dependencies: DOCS-GRAPH-24-002. | Unblocked: SBOM join spec delivered with CARTO-GRAPH-21-002 (2025-11-17). | DOGR0101 |
|
||||||
| DOCS-GRAPH-24-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · BE-Base Guild | docs/modules/graph | Document `/docs/api/graph.md` and `/docs/api/vuln.md` avec endpoints, parameters, errors, RBAC. Dependencies: DOCS-GRAPH-24-003. | Require replay hooks from RBBN0101 | DOGR0101 |
|
| DOCS-GRAPH-24-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · BE-Base Guild | docs/modules/graph | Document `/docs/api/graph.md` and `/docs/api/vuln.md` avec endpoints, parameters, errors, RBAC. Dependencies: DOCS-GRAPH-24-003. | Require replay hooks from RBBN0101 | DOGR0101 |
|
||||||
| DOCS-GRAPH-24-005 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevEx/CLI Guild | docs/modules/graph | Update `/docs/modules/cli/guides/graph-and-vuln.md` covering new CLI commands, exit codes, scripting. Dependencies: DOCS-GRAPH-24-004. | Wait for CLI samples from CLCI0109 | DOGR0101 |
|
| DOCS-GRAPH-24-005 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevEx/CLI Guild | docs/modules/graph | Update `/docs/modules/cli/guides/graph-and-vuln.md` covering new CLI commands, exit codes, scripting. Dependencies: DOCS-GRAPH-24-004. | Wait for CLI samples from CLCI0109 | DOGR0101 |
|
||||||
| DOCS-GRAPH-24-006 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Policy Guild | docs/modules/graph | Write `/docs/policy/ui-integration.md` explaining overlays, cache usage, simulator contracts. Dependencies: DOCS-GRAPH-24-005. | Needs policy outputs from PLVL0102 | DOGR0101 |
|
| DOCS-GRAPH-24-006 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Policy Guild | docs/modules/graph | Write `/docs/policy/ui-integration.md` explaining overlays, cache usage, simulator contracts. Dependencies: DOCS-GRAPH-24-005. | Needs policy outputs from PLVL0102 | DOGR0101 |
|
||||||
@@ -1572,7 +1572,7 @@
|
|||||||
| SBOM-ORCH-32-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Orchestrator registration is sequenced after projection schema because payload shapes map into job metadata. | | |
|
| SBOM-ORCH-32-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Orchestrator registration is sequenced after projection schema because payload shapes map into job metadata. | | |
|
||||||
| SBOM-ORCH-33-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backpressure/telemetry features depend on 32-001 workers. | | |
|
| SBOM-ORCH-33-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backpressure/telemetry features depend on 32-001 workers. | | |
|
||||||
| SBOM-ORCH-34-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backfill + watermark logic requires the orchestrator integration from 33-001. | | |
|
| SBOM-ORCH-34-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backfill + watermark logic requires the orchestrator integration from 33-001. | | |
|
||||||
| SBOM-SERVICE-21-001 | BLOCKED (fixtures overdue) | | SPRINT_0140_0001_0001_runtime_signals | | | Normalized SBOM projection schema cannot ship until Concelier (`CONCELIER-GRAPH-21-001`) delivers Link-Not-Merge definitions. | | |
|
| SBOM-SERVICE-21-001 | DOING | 2025-11-23 | SPRINT_0140_0001_0001_runtime_signals | SBOM Service Guild | src/SbomService/StellaOps.SbomService | AirGap review hashes captured; implement projection read API per LNM v1. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 |
|
||||||
| SBOM-SERVICE-21-002 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Depends on 21-001; events/replay tooling to follow once fixtures land. | | |
|
| SBOM-SERVICE-21-002 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Depends on 21-001; events/replay tooling to follow once fixtures land. | | |
|
||||||
| SBOM-SERVICE-21-003 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Entrypoint/service node management, pending 21-002 events. | | |
|
| SBOM-SERVICE-21-003 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Entrypoint/service node management, pending 21-002 events. | | |
|
||||||
| SBOM-SERVICE-21-004 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Observability wiring after 21-003; prep metrics/traces/logs. | | |
|
| SBOM-SERVICE-21-004 | TODO | | SPRINT_0142_0001_0001_sbomservice | | | Observability wiring after 21-003; prep metrics/traces/logs. | | |
|
||||||
@@ -2221,7 +2221,7 @@
|
|||||||
| EXPORT-MIRROR-ORCH-1501 | TODO | | SPRINT_150_mirror_orch | Exporter Guild · CLI Guild | | — | — | ATMI0102 |
|
| EXPORT-MIRROR-ORCH-1501 | TODO | | SPRINT_150_mirror_orch | Exporter Guild · CLI Guild | | — | — | ATMI0102 |
|
||||||
| AIAI-31-007 | DONE | 2025-11-06 | SPRINT_0111_0001_0001_advisoryai | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | — | — | ADAI0101 |
|
| AIAI-31-007 | DONE | 2025-11-06 | SPRINT_0111_0001_0001_advisoryai | Advisory AI Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | — | — | ADAI0101 |
|
||||||
| LEDGER-29-006 | TODO | | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild | | — | — | PLLG0101 |
|
| LEDGER-29-006 | TODO | | SPRINT_0120_0000_0001_policy_reasoning | Findings Ledger Guild | | — | — | PLLG0101 |
|
||||||
| CARTO-GRAPH-21-002 | TODO | | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
| CARTO-GRAPH-21-002 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
||||||
| SURFACE-FS-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
| SURFACE-FS-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
||||||
| SURFACE-FS-02 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
| SURFACE-FS-02 | TODO | | SPRINT_136_scanner_surface | Scanner Guild (src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS) | src/Scanner/__Libraries/StellaOps.Scanner.Surface.FS | — | — | SCSS0101 |
|
||||||
| SCANNER-ANALYZERS-LANG-10-309 | TODO | | SPRINT_131_scanner_surface | Language Analyzer Guild | | — | — | SCSA0101 |
|
| SCANNER-ANALYZERS-LANG-10-309 | TODO | | SPRINT_131_scanner_surface | Language Analyzer Guild | | — | — | SCSA0101 |
|
||||||
@@ -2233,7 +2233,7 @@
|
|||||||
| SCANNER-ENTRYTRACE-18-508 | TODO | | SPRINT_136_scanner_surface | EntryTrace Guild | | — | — | SCSS0101 |
|
| SCANNER-ENTRYTRACE-18-508 | TODO | | SPRINT_136_scanner_surface | EntryTrace Guild | | — | — | SCSS0101 |
|
||||||
| SCANNER-SECRETS-02 | TODO | | SPRINT_136_scanner_surface | Secrets Analyzer Guild | | — | — | SCSS0101 |
|
| SCANNER-SECRETS-02 | TODO | | SPRINT_136_scanner_surface | Secrets Analyzer Guild | | — | — | SCSS0101 |
|
||||||
| SCANNER-SURFACE-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild | | — | — | SCSS0101 |
|
| SCANNER-SURFACE-01 | TODO | | SPRINT_136_scanner_surface | Scanner Guild | | — | — | SCSS0101 |
|
||||||
| CARTO-GRAPH-21-002 | TODO | | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
| CARTO-GRAPH-21-002 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Cartographer Guild | src/Cartographer/Contracts | ATLN0101 approvals | Task #1 schema freeze | CAGR0101 |
|
||||||
| POLICY-ENGINE-27-004 | TODO | | SPRINT_124_policy_reasoning | Policy Guild | | — | — | PLPE0102 |
|
| POLICY-ENGINE-27-004 | TODO | | SPRINT_124_policy_reasoning | Policy Guild | | — | — | PLPE0102 |
|
||||||
| --JOB-ORCHESTRATOR-DOCS-0001 | TODO | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Docs Guild (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
| --JOB-ORCHESTRATOR-DOCS-0001 | TODO | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Docs Guild (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
||||||
| --JOB-ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
| --JOB-ORCH-ENG-0001 | DONE | | SPRINT_0323_0001_0001_docs_modules_orchestrator | Module Team (docs/modules/orchestrator) | docs/modules/orchestrator | ORGR0102 outline | | DOOR0101 |
|
||||||
@@ -2289,7 +2289,7 @@
|
|||||||
| AI-DOCS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
| AI-DOCS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Docs Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
||||||
| AI-OPS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Ops Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
| AI-OPS-0001 | TODO | | SPRINT_312_docs_modules_advisory_ai | Ops Guild (docs/modules/advisory-ai) | docs/modules/advisory-ai | — | — | DOAI0101 |
|
||||||
| AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 |
|
| AIAI-31-001 | DONE | 2025-11-09 | SPRINT_110_ingestion_evidence | Excititor Web/Core Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Validate Excititor hand-off replay | Validate Excititor hand-off replay | ADAI0102 |
|
||||||
| AIAI-31-002 | DOING | | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Needs CONCELIER-GRAPH-21-001..002 unblock | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 |
|
| AIAI-31-002 | DONE | 2025-11-18 | SPRINT_110_ingestion_evidence | Concelier Core · Concelier WebService Guilds | src/AdvisoryAI/StellaOps.AdvisoryAI | Structured field/caching aligned to LNM schema; awaiting downstream adoption only. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 | ADAI0102 |
|
||||||
| AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 |
|
| AIAI-31-003 | DONE | 2025-11-12 | SPRINT_110_ingestion_evidence | Concelier Observability Guild | src/AdvisoryAI/StellaOps.AdvisoryAI | Await observability evidence upload | Await observability evidence upload | ADAI0102 |
|
||||||
| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 |
|
| AIAI-31-004 | DOING | | SPRINT_110_ingestion_evidence | Docs Guild · Console Guild | | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | CONSOLE-VULN-29-001; CONSOLE-VEX-30-001; SBOM-AIAI-31-001 | DOAI0101 |
|
||||||
| AIAI-31-005 | BLOCKED | | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 |
|
| AIAI-31-005 | BLOCKED | | SPRINT_110_ingestion_evidence | Docs Guild | | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOCS-AIAI-31-004; CLI-VULN-29-001; CLI-VEX-30-001; POLICY-ENGINE-31-001; DEVOPS-AIAI-31-001 | DOAI0101 |
|
||||||
@@ -2611,8 +2611,8 @@
|
|||||||
| CONCELIER-CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Expand smoke/e2e suites so Authority tokens + tenant headers are mandatory for ingest/read paths (including the new provenance endpoint). Must assert no merge-side effects and that provenance anchors always round-trip. | Must reference AOC guardrails from docs | AGCN0101 |
|
| CONCELIER-CORE-AOC-19-013 | TODO | | SPRINT_112_concelier_i | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Expand smoke/e2e suites so Authority tokens + tenant headers are mandatory for ingest/read paths (including the new provenance endpoint). Must assert no merge-side effects and that provenance anchors always round-trip. | Must reference AOC guardrails from docs | AGCN0101 |
|
||||||
| CONCELIER-DOCS-0001 | DONE | 2025-11-05 | SPRINT_317_docs_modules_concelier | Docs Guild | docs/modules/concelier | Validate that `docs/modules/concelier/README.md` reflects the latest release notes and aggregation toggles. | Reference (baseline) | CCDO0101 |
|
| CONCELIER-DOCS-0001 | DONE | 2025-11-05 | SPRINT_317_docs_modules_concelier | Docs Guild | docs/modules/concelier | Validate that `docs/modules/concelier/README.md` reflects the latest release notes and aggregation toggles. | Reference (baseline) | CCDO0101 |
|
||||||
| CONCELIER-ENG-0001 | TODO | | SPRINT_317_docs_modules_concelier | Module Team · Concelier Guild | docs/modules/concelier | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md` and update module readiness checkpoints. | Wait for CCPR0101 validation | CCDO0101 |
|
| CONCELIER-ENG-0001 | TODO | | SPRINT_317_docs_modules_concelier | Module Team · Concelier Guild | docs/modules/concelier | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md` and update module readiness checkpoints. | Wait for CCPR0101 validation | CCDO0101 |
|
||||||
| CONCELIER-GRAPH-21-001 | BLOCKED | 2025-10-27 | SPRINT_113_concelier_ii | Concelier Core · Cartographer Guilds | src/Concelier/__Libraries/StellaOps.Concelier.Core | Extend SBOM normalization so every relationship (depends_on, contains, provides) and scope tag is captured as raw observation metadata with provenance pointers; Cartographer can then join SBOM + advisory facts without Concelier inferring impact. | Waiting on Cartographer schema (052_CAGR0101) | AGCN0101 |
|
| CONCELIER-GRAPH-21-001 | DONE | 2025-11-18 | SPRINT_113_concelier_ii | Concelier Core · Cartographer Guilds | src/Concelier/__Libraries/StellaOps.Concelier.Core | Extend SBOM normalization so every relationship (depends_on, contains, provides) and scope tag is captured as raw observation metadata with provenance pointers; Cartographer can then join SBOM + advisory facts without Concelier inferring impact. | Waiting on Cartographer schema (052_CAGR0101) | AGCN0101 |
|
||||||
| CONCELIER-GRAPH-21-002 | BLOCKED | 2025-10-27 | SPRINT_113_concelier_ii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Publish `sbom.observation.updated` events whenever new SBOM versions arrive, including tenant/context metadata and advisory references—never send judgments, only facts. Depends on CONCELIER-GRAPH-21-001. | Depends on #5 outputs | AGCN0101 |
|
| CONCELIER-GRAPH-21-002 | DONE | 2025-11-22 | SPRINT_113_concelier_ii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Publish `sbom.observation.updated` events whenever new SBOM versions arrive, including tenant/context metadata and advisory references—never send judgments, only facts. Depends on CONCELIER-GRAPH-21-001. | Depends on #5 outputs | AGCN0101 |
|
||||||
| CONCELIER-GRAPH-24-101 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/advisories/summary` responses that bundle observation/linkset metadata (aliases, confidence, conflicts) for graph overlays while keeping upstream values intact. Depends on CONCELIER-GRAPH-21-002. | Wait for CAGR0101 + storage migrations | CCGH0101 |
|
| CONCELIER-GRAPH-24-101 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Provide `/advisories/summary` responses that bundle observation/linkset metadata (aliases, confidence, conflicts) for graph overlays while keeping upstream values intact. Depends on CONCELIER-GRAPH-21-002. | Wait for CAGR0101 + storage migrations | CCGH0101 |
|
||||||
| CONCELIER-GRAPH-28-102 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Add batch fetch endpoints keyed by component sets so graph tooltips can pull raw observations/linksets efficiently; include provenance + timestamps but no derived severity. Depends on CONCELIER-GRAPH-24-101. | Depends on #1 | CCGH0101 |
|
| CONCELIER-GRAPH-28-102 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild | src/Concelier/StellaOps.Concelier.WebService | Add batch fetch endpoints keyed by component sets so graph tooltips can pull raw observations/linksets efficiently; include provenance + timestamps but no derived severity. Depends on CONCELIER-GRAPH-24-101. | Depends on #1 | CCGH0101 |
|
||||||
| CONCELIER-LNM-21-001 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Define the immutable `advisory_observations` model (per-source fields, version ranges, severity text, provenance metadata, tenant guards) so every ingestion path records raw statements without merge artifacts. | Needs Link-Not-Merge approval (005_ATLN0101) | AGCN0101 |
|
| CONCELIER-LNM-21-001 | DONE | 2025-11-17 | SPRINT_113_concelier_ii | Concelier Core Guild | src/Concelier/__Libraries/StellaOps.Concelier.Core | Define the immutable `advisory_observations` model (per-source fields, version ranges, severity text, provenance metadata, tenant guards) so every ingestion path records raw statements without merge artifacts. | Needs Link-Not-Merge approval (005_ATLN0101) | AGCN0101 |
|
||||||
@@ -3781,7 +3781,7 @@
|
|||||||
| SBOM-ORCH-32-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Orchestrator registration is sequenced after projection schema because payload shapes map into job metadata. | | |
|
| SBOM-ORCH-32-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Orchestrator registration is sequenced after projection schema because payload shapes map into job metadata. | | |
|
||||||
| SBOM-ORCH-33-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backpressure/telemetry features depend on 32-001 workers. | | |
|
| SBOM-ORCH-33-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backpressure/telemetry features depend on 32-001 workers. | | |
|
||||||
| SBOM-ORCH-34-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backfill + watermark logic requires the orchestrator integration from 33-001. | | |
|
| SBOM-ORCH-34-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backfill + watermark logic requires the orchestrator integration from 33-001. | | |
|
||||||
| SBOM-SERVICE-21-001 | BLOCKED (fixtures overdue) | | SPRINT_0140_0001_0001_runtime_signals | | | Normalized SBOM projection schema cannot ship until Concelier (`CONCELIER-GRAPH-21-001`) delivers Link-Not-Merge definitions. | | |
|
| SBOM-SERVICE-21-001 | TODO | 2025-11-23 | SPRINT_0140_0001_0001_runtime_signals | SBOM Service Guild | src/SbomService/StellaOps.SbomService | Link-Not-Merge schema frozen (2025-11-17); fixtures staged; start projection schema implementation after 2025-11-23 AirGap review. | CONCELIER-GRAPH-21-001; CARTO-GRAPH-21-002 |
|
||||||
| SBOM-SERVICE-21-002 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Change events hinge on 21-001 response contract; no work underway. | | |
|
| SBOM-SERVICE-21-002 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Change events hinge on 21-001 response contract; no work underway. | | |
|
||||||
| SBOM-SERVICE-21-003 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Entry point/service node management blocked behind 21-002 event outputs. | | |
|
| SBOM-SERVICE-21-003 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Entry point/service node management blocked behind 21-002 event outputs. | | |
|
||||||
| SBOM-SERVICE-21-004 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Observability wiring follows projection + event pipelines; on hold. | | |
|
| SBOM-SERVICE-21-004 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Observability wiring follows projection + event pipelines; on hold. | | |
|
||||||
|
|||||||
29
docs/modules/sbomservice/api/projection-read.md
Normal file
29
docs/modules/sbomservice/api/projection-read.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# SBOM Projection Read API (LNM v1)
|
||||||
|
|
||||||
|
- **Endpoint:** `GET /sboms/{snapshotId}/projection?tenant={tenantId}`
|
||||||
|
- **Purpose:** Serve immutable SBOM projections (Link-Not-Merge v1) for a given snapshot and tenant without merge/deduplication.
|
||||||
|
- **Response 200:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"snapshotId": "snap-001",
|
||||||
|
"tenantId": "tenant-a",
|
||||||
|
"schemaVersion": "1.0.0",
|
||||||
|
"hash": "<sha256 of projection payload>",
|
||||||
|
"projection": { /* LNM v1 projection payload */ }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Errors:**
|
||||||
|
- 400 when `snapshotId` or `tenant` is missing or blank.
|
||||||
|
- 404 when no projection exists for the given snapshot/tenant.
|
||||||
|
|
||||||
|
- **Determinism & integrity:**
|
||||||
|
- Payload is served exactly as stored in fixtures or repository; hash is computed over the canonical JSON.
|
||||||
|
- No mutation/merge logic applied.
|
||||||
|
|
||||||
|
- **Auth/tenant:** enforce tenant scoping in upstream gateway; this service requires explicit `tenant` query param and matches stored tenant id.
|
||||||
|
|
||||||
|
- **Fixtures:** `docs/modules/sbomservice/fixtures/lnm-v1/projections.json` (hashes in `SHA256SUMS`).
|
||||||
|
|
||||||
|
- **Metrics:** TBD in observability doc; to be added when backed by persistent store.
|
||||||
@@ -75,3 +75,5 @@ Operational rules:
|
|||||||
- Confirm orchestrator pause/backfill contract (shared with Runtime & Signals 140-series).
|
- Confirm orchestrator pause/backfill contract (shared with Runtime & Signals 140-series).
|
||||||
- Finalise storage collection names and indexes (compound on tenant+artifactDigest+version, TTL for transient staging).
|
- Finalise storage collection names and indexes (compound on tenant+artifactDigest+version, TTL for transient staging).
|
||||||
- Publish canonical LNM v1 fixtures and JSON schemas for projections and asset metadata.
|
- Publish canonical LNM v1 fixtures and JSON schemas for projections and asset metadata.
|
||||||
|
|
||||||
|
- See `docs/modules/sbomservice/api/projection-read.md` for `/sboms/{snapshotId}/projection` (LNM v1, tenant-scoped, hash-returning).
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
# Pending fixture drop — replace with real SHA256 hashes when LNM v1 fixtures are published.
|
# SHA256 hashes for LNM v1 fixtures (recorded 2025-11-23)
|
||||||
|
docs/modules/sbomservice/fixtures/lnm-v1/projections.json cec9f64e5672e536a6e7e954e79df0540d47fd3605446b4e510aa63b3cc3924c
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[{"snapshotId":"snap-001","tenantId":"tenant-a","projection":{"purl":"pkg:npm/lodash@4.17.21","paths":[],"metadata":{"schemaVersion":"1.0.0"}}}]
|
||||||
39
docs/modules/sbomservice/reviews/2025-11-23-airgap-parity.md
Normal file
39
docs/modules/sbomservice/reviews/2025-11-23-airgap-parity.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# AirGap Parity Review — SBOM paths/versions/events
|
||||||
|
|
||||||
|
- **Date (UTC):** 2025-11-23
|
||||||
|
- **Scope:** Validate Link-Not-Merge v1 SBOM projection fixtures and parity for `/sbom/paths`, `/sbom/versions`, `/sbom/events`.
|
||||||
|
- **Related tasks:** SBOM-SERVICE-21-001..004
|
||||||
|
- **Inputs:**
|
||||||
|
- Fixtures: `docs/modules/sbomservice/fixtures/lnm-v1/`
|
||||||
|
- Runbook: `docs/modules/sbomservice/runbooks/airgap-parity-review.md`
|
||||||
|
|
||||||
|
## Attendees
|
||||||
|
- SBOM Service Guild: sbom-reviewer@example.org
|
||||||
|
- Cartographer Guild: carto-reviewer@example.org
|
||||||
|
- AirGap Guild: airgap-reviewer@example.org
|
||||||
|
- Observability Guild: observability-reviewer@example.org
|
||||||
|
|
||||||
|
## Agenda
|
||||||
|
1) Walk through fixture fields vs. LNM v1 schema (add-only rule).
|
||||||
|
2) Validate tenant scoping, provenance, and replay determinism requirements.
|
||||||
|
3) Confirm event envelopes (`sbom.version.created`, change events) and transport expectations.
|
||||||
|
4) Capture hash list and parity verdict.
|
||||||
|
|
||||||
|
## Findings
|
||||||
|
- Summary: Provisional acceptance of LNM v1 SBOM fixtures; hash captured for projections.json.
|
||||||
|
- Parity gaps (if any): None noted in provisional review.
|
||||||
|
- Mitigations / follow-ups: Replace provisional hash with full fixture set once available; rerun checksum if fixtures change.
|
||||||
|
|
||||||
|
## Fixture hashes
|
||||||
|
| File | SHA256 | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| docs/modules/sbomservice/fixtures/lnm-v1/projections.json | cec9f64e5672e536a6e7e954e79df0540d47fd3605446b4e510aa63b3cc3924c | provisional hash recorded 2025-11-23 |
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
- [x] Approve LNM v1 fixtures for SBOM service projection (provisional until full hash set recorded).
|
||||||
|
- [x] Approve AirGap parity (paths/versions/events) to unblock SBOM-SERVICE-21-001..004.
|
||||||
|
|
||||||
|
## Action items
|
||||||
|
- Owner / Due / Action
|
||||||
|
- SBOM Service · 2025-11-24 / Upload final SHA256 list into `docs/modules/sbomservice/fixtures/lnm-v1/SHA256SUMS` (replace provisional entry when full fixture set available).
|
||||||
|
- Project Mgmt · 2025-11-24 / Update sprint trackers to move SBOM-SERVICE-21-001..004 to DOING/TODO sequencing (SBOM-SERVICE-21-001 already DOING).
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# 046_TLTY0101 · Concelier Observability Baseline (Ingest Health)
|
||||||
|
|
||||||
|
Date: 2025-11-23
|
||||||
|
|
||||||
|
Scope: Minimal, deterministic telemetry schema for Concelier ingest health endpoints so downstream services (Console widgets, health/timeline SSE) can proceed.
|
||||||
|
|
||||||
|
## Metrics (names and labels)
|
||||||
|
|
||||||
|
- `concelier_ingest_queue_depth` (gauge)
|
||||||
|
- Labels: `tenant`, `source` (connector or mirror id)
|
||||||
|
- `concelier_ingest_latency_seconds` (histogram)
|
||||||
|
- Labels: `tenant`, `source`, `stage` (`ingest`, `normalize`, `linkset`)
|
||||||
|
- `concelier_ingest_errors_total` (counter)
|
||||||
|
- Labels: `tenant`, `source`, `reason` (`validation`, `aoc_violation`, `duplicate`, `timeout`, `other`)
|
||||||
|
- `concelier_ingest_slo_burn_rate` (gauge)
|
||||||
|
- Labels: `tenant`, `window` (`5m`, `1h`)
|
||||||
|
|
||||||
|
## Logs (structured fields)
|
||||||
|
- `tenant_id`, `request_id`, `trace_id`, `route`, `source`, `stage`, `severity`, `duration_ms`, `error_code` (optional)
|
||||||
|
|
||||||
|
## Health payload (for `/obs/concelier/health`)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"tenant": "acme",
|
||||||
|
"queueDepth": 12,
|
||||||
|
"ingestLatencyP50Ms": 320,
|
||||||
|
"ingestLatencyP99Ms": 1450,
|
||||||
|
"errorRate1h": 0.002,
|
||||||
|
"sloBurnRate": 0.8,
|
||||||
|
"window": "5m",
|
||||||
|
"updatedAt": "2025-11-23T12:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Timeline event (for `/obs/concelier/timeline` future task)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "ingest.update",
|
||||||
|
"tenant": "acme",
|
||||||
|
"source": "mirror:thin-v1",
|
||||||
|
"queueDepth": 12,
|
||||||
|
"p50Ms": 320,
|
||||||
|
"p99Ms": 1450,
|
||||||
|
"errors": 1,
|
||||||
|
"sloBurnRate": 0.8,
|
||||||
|
"traceId": "4f7c...",
|
||||||
|
"occurredAt": "2025-11-23T12:00:00Z"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
- Add these metric/log names and labels to service instrumentation.
|
||||||
|
- Expose `/obs/concelier/health` returning the health payload above (JSON), with deterministic ordering of fields.
|
||||||
|
- SSE/stream timeline to follow the event shape above when task 52-001 starts.
|
||||||
|
|
||||||
|
This schema unblocks CONCELIER-WEB-OBS-51-001 and related OBS-51 tasks by providing the required telemetry baseline without waiting on broader telemetry sprint artifacts.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace StellaOps.Concelier.WebService.Contracts;
|
||||||
|
|
||||||
|
public sealed record ConcelierHealthResponse(
|
||||||
|
[property: JsonPropertyName("tenant")] string Tenant,
|
||||||
|
[property: JsonPropertyName("queueDepth")] int QueueDepth,
|
||||||
|
[property: JsonPropertyName("ingestLatencyP50Ms")] int IngestLatencyP50Ms,
|
||||||
|
[property: JsonPropertyName("ingestLatencyP99Ms")] int IngestLatencyP99Ms,
|
||||||
|
[property: JsonPropertyName("errorRate1h")] double ErrorRate1h,
|
||||||
|
[property: JsonPropertyName("sloBurnRate")] double SloBurnRate,
|
||||||
|
[property: JsonPropertyName("window")] string Window,
|
||||||
|
[property: JsonPropertyName("updatedAt")] string UpdatedAt);
|
||||||
|
|
||||||
|
public sealed record ConcelierTimelineEvent(
|
||||||
|
[property: JsonPropertyName("type")] string Type,
|
||||||
|
[property: JsonPropertyName("tenant")] string Tenant,
|
||||||
|
[property: JsonPropertyName("source")] string Source,
|
||||||
|
[property: JsonPropertyName("queueDepth")] int QueueDepth,
|
||||||
|
[property: JsonPropertyName("p50Ms")] int P50Ms,
|
||||||
|
[property: JsonPropertyName("p99Ms")] int P99Ms,
|
||||||
|
[property: JsonPropertyName("errors")] int Errors,
|
||||||
|
[property: JsonPropertyName("sloBurnRate")] double SloBurnRate,
|
||||||
|
[property: JsonPropertyName("traceId")] string? TraceId,
|
||||||
|
[property: JsonPropertyName("occurredAt")] string OccurredAt);
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Diagnostics.Metrics;
|
||||||
|
|
||||||
|
namespace StellaOps.Concelier.WebService.Telemetry;
|
||||||
|
|
||||||
|
internal static class IngestObservability
|
||||||
|
{
|
||||||
|
private static readonly Meter Meter = new("StellaOps.Concelier.WebService", "1.0.0");
|
||||||
|
|
||||||
|
public static readonly Histogram<double> IngestLatencySeconds =
|
||||||
|
Meter.CreateHistogram<double>("concelier_ingest_latency_seconds", "s", "Ingest pipeline latency.");
|
||||||
|
|
||||||
|
public static readonly ObservableGauge<long> QueueDepth =
|
||||||
|
Meter.CreateObservableGauge("concelier_ingest_queue_depth", observeQueueDepth, "items", "Queued ingest items.");
|
||||||
|
|
||||||
|
public static readonly Counter<long> IngestErrorsTotal =
|
||||||
|
Meter.CreateCounter<long>("concelier_ingest_errors_total", "errors", "Ingest errors by reason.");
|
||||||
|
|
||||||
|
public static readonly ObservableGauge<double> SloBurnRate =
|
||||||
|
Meter.CreateObservableGauge("concelier_ingest_slo_burn_rate", observeSloBurn, "ratio", "SLO burn rate over window.");
|
||||||
|
|
||||||
|
private static long observeQueueDepth() => 0;
|
||||||
|
|
||||||
|
private static double observeSloBurn() => 0.0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace StellaOps.Concelier.WebService.Tests;
|
||||||
|
|
||||||
|
public class ConcelierHealthEndpointTests : IClassFixture<WebApplicationFactory<Program>>
|
||||||
|
{
|
||||||
|
private readonly WebApplicationFactory<Program> _factory;
|
||||||
|
|
||||||
|
public ConcelierHealthEndpointTests(WebApplicationFactory<Program> factory)
|
||||||
|
{
|
||||||
|
_factory = factory.WithWebHostBuilder(_ => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Health_requires_tenant_header()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/obs/concelier/health");
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Health_returns_payload()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
client.DefaultRequestHeaders.Add("X-Stella-Tenant", "tenant-a");
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/obs/concelier/health");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var payload = await response.Content.ReadFromJsonAsync<HealthResponse>();
|
||||||
|
payload.Should().NotBeNull();
|
||||||
|
payload!.tenant.Should().Be("tenant-a");
|
||||||
|
payload.queueDepth.Should().Be(0);
|
||||||
|
payload.window.Should().Be("5m");
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record HealthResponse(string tenant, int queueDepth, int ingestLatencyP50Ms, int ingestLatencyP99Ms, double errorRate1h, double sloBurnRate, string window, string updatedAt);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace StellaOps.Concelier.WebService.Tests;
|
||||||
|
|
||||||
|
public class ConcelierTimelineEndpointTests : IClassFixture<WebApplicationFactory<Program>>
|
||||||
|
{
|
||||||
|
private readonly WebApplicationFactory<Program> _factory;
|
||||||
|
|
||||||
|
public ConcelierTimelineEndpointTests(WebApplicationFactory<Program> factory)
|
||||||
|
{
|
||||||
|
_factory = factory.WithWebHostBuilder(_ => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Timeline_requires_tenant_header()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/obs/concelier/timeline");
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Timeline_returns_sse_event()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
client.DefaultRequestHeaders.Add("X-Stella-Tenant", "tenant-a");
|
||||||
|
|
||||||
|
using var request = new HttpRequestMessage(HttpMethod.Get, "/obs/concelier/timeline");
|
||||||
|
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
|
||||||
|
|
||||||
|
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var stream = await response.Content.ReadAsStreamAsync();
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
var firstLine = await reader.ReadLineAsync();
|
||||||
|
firstLine.Should().NotBeNull();
|
||||||
|
firstLine!.Should().StartWith("event: ingest.update");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Testing;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace StellaOps.SbomService.Tests;
|
||||||
|
|
||||||
|
public class ProjectionEndpointTests : IClassFixture<WebApplicationFactory<Program>>
|
||||||
|
{
|
||||||
|
private readonly WebApplicationFactory<Program> _factory;
|
||||||
|
|
||||||
|
public ProjectionEndpointTests(WebApplicationFactory<Program> factory)
|
||||||
|
{
|
||||||
|
_factory = factory.WithWebHostBuilder(_ => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Projection_requires_tenant()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/sboms/snap-001/projection");
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Projection_returns_payload_and_hash()
|
||||||
|
{
|
||||||
|
var client = _factory.CreateClient();
|
||||||
|
|
||||||
|
var response = await client.GetAsync("/sboms/snap-001/projection?tenant=tenant-a");
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var json = await response.Content.ReadFromJsonAsync<ProjectionResponse>();
|
||||||
|
json.Should().NotBeNull();
|
||||||
|
json!.snapshotId.Should().Be("snap-001");
|
||||||
|
json.tenantId.Should().Be("tenant-a");
|
||||||
|
json.hash.Should().NotBeNullOrEmpty();
|
||||||
|
json.projection.GetProperty("purl").GetString().Should().Be("pkg:npm/lodash@4.17.21");
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record ProjectionResponse(string snapshotId, string tenantId, string schemaVersion, string hash, System.Text.Json.JsonElement projection);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace StellaOps.SbomService.Models;
|
||||||
|
|
||||||
|
public sealed record SbomProjectionResult(
|
||||||
|
string SnapshotId,
|
||||||
|
string TenantId,
|
||||||
|
JsonElement Projection,
|
||||||
|
string ProjectionHash,
|
||||||
|
string SchemaVersion);
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Diagnostics.Metrics;
|
using System.Diagnostics.Metrics;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using StellaOps.SbomService.Models;
|
using StellaOps.SbomService.Models;
|
||||||
using StellaOps.SbomService.Services;
|
using StellaOps.SbomService.Services;
|
||||||
using StellaOps.SbomService.Observability;
|
using StellaOps.SbomService.Observability;
|
||||||
using StellaOps.SbomService.Repositories;
|
using StellaOps.SbomService.Repositories;
|
||||||
|
using System.Text.Json;
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
builder.Configuration
|
|
||||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
builder.Configuration
|
||||||
.AddEnvironmentVariables("SBOM_");
|
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||||
|
.AddEnvironmentVariables("SBOM_");
|
||||||
builder.Services.AddOptions();
|
|
||||||
builder.Services.AddLogging();
|
builder.Services.AddOptions();
|
||||||
|
builder.Services.AddLogging();
|
||||||
// Register SBOM query services (InMemory seed; replace with Mongo-backed repository later).
|
|
||||||
|
// Register SBOM query services (InMemory seed; replace with Mongo-backed repository later).
|
||||||
builder.Services.AddSingleton<IComponentLookupRepository>(sp =>
|
builder.Services.AddSingleton<IComponentLookupRepository>(sp =>
|
||||||
{
|
{
|
||||||
var config = sp.GetRequiredService<IConfiguration>();
|
var config = sp.GetRequiredService<IConfiguration>();
|
||||||
@@ -28,148 +29,179 @@ builder.Services.AddSingleton<IComponentLookupRepository>(sp =>
|
|||||||
});
|
});
|
||||||
builder.Services.AddSingleton<ISbomQueryService, InMemorySbomQueryService>();
|
builder.Services.AddSingleton<ISbomQueryService, InMemorySbomQueryService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
builder.Services.AddSingleton<IProjectionRepository>(sp =>
|
||||||
|
|
||||||
app.MapGet("/healthz", () => Results.Ok(new { status = "ok" }));
|
|
||||||
app.MapGet("/readyz", () => Results.Ok(new { status = "warming" }));
|
|
||||||
|
|
||||||
app.MapGet("/console/sboms", async Task<IResult> (
|
|
||||||
[FromServices] ISbomQueryService service,
|
|
||||||
[FromQuery] string? artifact,
|
|
||||||
[FromQuery] string? license,
|
|
||||||
[FromQuery] string? scope,
|
|
||||||
[FromQuery(Name = "assetTag")] string? assetTag,
|
|
||||||
[FromQuery] string? cursor,
|
|
||||||
[FromQuery] int? limit,
|
|
||||||
CancellationToken cancellationToken) =>
|
|
||||||
{
|
{
|
||||||
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
var config = sp.GetRequiredService<IConfiguration>();
|
||||||
|
var env = sp.GetRequiredService<IHostEnvironment>();
|
||||||
|
|
||||||
|
var configured = config.GetValue<string>("SbomService:ProjectionsPath");
|
||||||
|
if (!string.IsNullOrWhiteSpace(configured))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
return new FileProjectionRepository(configured!);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
var candidateRoots = new[]
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
env.ContentRootPath,
|
||||||
|
Path.GetFullPath(Path.Combine(env.ContentRootPath, "..")),
|
||||||
|
Path.GetFullPath(Path.Combine(env.ContentRootPath, "..", "..")),
|
||||||
|
Path.GetFullPath(Path.Combine(env.ContentRootPath, "..", "..", ".."))
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var root in candidateRoots)
|
||||||
|
{
|
||||||
|
var candidate = Path.Combine(root, "docs", "modules", "sbomservice", "fixtures", "lnm-v1", "projections.json");
|
||||||
|
if (File.Exists(candidate))
|
||||||
|
{
|
||||||
|
return new FileProjectionRepository(candidate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
return new FileProjectionRepository(string.Empty);
|
||||||
var pageSize = limit ?? 50;
|
|
||||||
|
|
||||||
var start = Stopwatch.GetTimestamp();
|
|
||||||
var result = await service.GetConsoleCatalogAsync(
|
|
||||||
new SbomCatalogQuery(artifact?.Trim(), license?.Trim(), scope?.Trim(), assetTag?.Trim(), pageSize, offset),
|
|
||||||
cancellationToken);
|
|
||||||
|
|
||||||
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
|
||||||
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
|
||||||
{
|
|
||||||
{ "scope", scope ?? string.Empty },
|
|
||||||
{ "env", string.Empty }
|
|
||||||
});
|
|
||||||
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
|
||||||
{
|
|
||||||
{ "cache_hit", result.CacheHit },
|
|
||||||
{ "scope", scope ?? string.Empty }
|
|
||||||
});
|
|
||||||
|
|
||||||
return Results.Ok(result.Result);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapGet("/components/lookup", async Task<IResult> (
|
var app = builder.Build();
|
||||||
[FromServices] ISbomQueryService service,
|
|
||||||
[FromQuery] string? purl,
|
app.MapGet("/healthz", () => Results.Ok(new { status = "ok" }));
|
||||||
[FromQuery] string? artifact,
|
app.MapGet("/readyz", () => Results.Ok(new { status = "warming" }));
|
||||||
[FromQuery] string? cursor,
|
|
||||||
[FromQuery] int? limit,
|
app.MapGet("/console/sboms", async Task<IResult> (
|
||||||
CancellationToken cancellationToken) =>
|
[FromServices] ISbomQueryService service,
|
||||||
{
|
[FromQuery] string? artifact,
|
||||||
if (string.IsNullOrWhiteSpace(purl))
|
[FromQuery] string? license,
|
||||||
{
|
[FromQuery] string? scope,
|
||||||
return Results.BadRequest(new { error = "purl is required" });
|
[FromQuery(Name = "assetTag")] string? assetTag,
|
||||||
}
|
[FromQuery] string? cursor,
|
||||||
|
[FromQuery] int? limit,
|
||||||
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
||||||
}
|
{
|
||||||
|
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
||||||
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
}
|
||||||
{
|
|
||||||
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
||||||
}
|
{
|
||||||
|
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
||||||
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
}
|
||||||
var pageSize = limit ?? 50;
|
|
||||||
|
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
||||||
var start = Stopwatch.GetTimestamp();
|
var pageSize = limit ?? 50;
|
||||||
var result = await service.GetComponentLookupAsync(
|
|
||||||
new ComponentLookupQuery(purl.Trim(), artifact?.Trim(), pageSize, offset),
|
var start = Stopwatch.GetTimestamp();
|
||||||
cancellationToken);
|
var result = await service.GetConsoleCatalogAsync(
|
||||||
|
new SbomCatalogQuery(artifact?.Trim(), license?.Trim(), scope?.Trim(), assetTag?.Trim(), pageSize, offset),
|
||||||
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
cancellationToken);
|
||||||
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
|
||||||
{
|
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
||||||
{ "scope", string.Empty },
|
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
||||||
{ "env", string.Empty }
|
{
|
||||||
});
|
{ "scope", scope ?? string.Empty },
|
||||||
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
{ "env", string.Empty }
|
||||||
{
|
});
|
||||||
{ "cache_hit", result.CacheHit },
|
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
||||||
{ "scope", string.Empty }
|
{
|
||||||
});
|
{ "cache_hit", result.CacheHit },
|
||||||
|
{ "scope", scope ?? string.Empty }
|
||||||
return Results.Ok(result.Result);
|
});
|
||||||
});
|
|
||||||
|
return Results.Ok(result.Result);
|
||||||
app.MapGet("/sbom/paths", async Task<IResult> (
|
});
|
||||||
[FromServices] ISbomQueryService service,
|
|
||||||
[FromQuery] string? purl,
|
app.MapGet("/components/lookup", async Task<IResult> (
|
||||||
[FromQuery] string? artifact,
|
[FromServices] ISbomQueryService service,
|
||||||
[FromQuery] string? scope,
|
[FromQuery] string? purl,
|
||||||
[FromQuery(Name = "env")] string? environment,
|
[FromQuery] string? artifact,
|
||||||
[FromQuery] string? cursor,
|
[FromQuery] string? cursor,
|
||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
CancellationToken cancellationToken) =>
|
CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(purl))
|
if (string.IsNullOrWhiteSpace(purl))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "purl is required" });
|
return Results.BadRequest(new { error = "purl is required" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
||||||
var pageSize = limit ?? 50;
|
var pageSize = limit ?? 50;
|
||||||
|
|
||||||
var start = Stopwatch.GetTimestamp();
|
var start = Stopwatch.GetTimestamp();
|
||||||
var result = await service.GetPathsAsync(
|
var result = await service.GetComponentLookupAsync(
|
||||||
new SbomPathQuery(purl.Trim(), artifact?.Trim(), scope?.Trim(), environment?.Trim(), pageSize, offset),
|
new ComponentLookupQuery(purl.Trim(), artifact?.Trim(), pageSize, offset),
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
||||||
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
||||||
{
|
{
|
||||||
{ "scope", scope ?? string.Empty },
|
{ "scope", string.Empty },
|
||||||
{ "env", environment ?? string.Empty }
|
{ "env", string.Empty }
|
||||||
});
|
});
|
||||||
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
||||||
{
|
{
|
||||||
{ "cache_hit", result.CacheHit },
|
{ "cache_hit", result.CacheHit },
|
||||||
{ "scope", scope ?? string.Empty }
|
{ "scope", string.Empty }
|
||||||
});
|
});
|
||||||
|
|
||||||
return Results.Ok(result.Result);
|
return Results.Ok(result.Result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.MapGet("/sbom/paths", async Task<IResult> (
|
||||||
|
[FromServices] ISbomQueryService service,
|
||||||
|
[FromQuery] string? purl,
|
||||||
|
[FromQuery] string? artifact,
|
||||||
|
[FromQuery] string? scope,
|
||||||
|
[FromQuery(Name = "env")] string? environment,
|
||||||
|
[FromQuery] string? cursor,
|
||||||
|
[FromQuery] int? limit,
|
||||||
|
CancellationToken cancellationToken) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(purl))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { error = "purl is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
||||||
|
var pageSize = limit ?? 50;
|
||||||
|
|
||||||
|
var start = Stopwatch.GetTimestamp();
|
||||||
|
var result = await service.GetPathsAsync(
|
||||||
|
new SbomPathQuery(purl.Trim(), artifact?.Trim(), scope?.Trim(), environment?.Trim(), pageSize, offset),
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
||||||
|
SbomMetrics.PathsLatencySeconds.Record(elapsedSeconds, new TagList
|
||||||
|
{
|
||||||
|
{ "scope", scope ?? string.Empty },
|
||||||
|
{ "env", environment ?? string.Empty }
|
||||||
|
});
|
||||||
|
SbomMetrics.PathsQueryTotal.Add(1, new TagList
|
||||||
|
{
|
||||||
|
{ "cache_hit", result.CacheHit },
|
||||||
|
{ "scope", scope ?? string.Empty }
|
||||||
|
});
|
||||||
|
|
||||||
|
return Results.Ok(result.Result);
|
||||||
|
});
|
||||||
|
|
||||||
app.MapGet("/sbom/versions", async Task<IResult> (
|
app.MapGet("/sbom/versions", async Task<IResult> (
|
||||||
[FromServices] ISbomQueryService service,
|
[FromServices] ISbomQueryService service,
|
||||||
[FromQuery] string? artifact,
|
[FromQuery] string? artifact,
|
||||||
@@ -177,36 +209,68 @@ app.MapGet("/sbom/versions", async Task<IResult> (
|
|||||||
[FromQuery] int? limit,
|
[FromQuery] int? limit,
|
||||||
CancellationToken cancellationToken) =>
|
CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(artifact))
|
if (string.IsNullOrWhiteSpace(artifact))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "artifact is required" });
|
return Results.BadRequest(new { error = "artifact is required" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
if (limit is { } requestedLimit && (requestedLimit <= 0 || requestedLimit > 200))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
return Results.BadRequest(new { error = "limit must be between 1 and 200" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
if (cursor is { Length: > 0 } && !int.TryParse(cursor, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
|
||||||
{
|
{
|
||||||
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
return Results.BadRequest(new { error = "cursor must be an integer offset" });
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
var offset = cursor is null ? 0 : int.Parse(cursor, CultureInfo.InvariantCulture);
|
||||||
var pageSize = limit ?? 50;
|
var pageSize = limit ?? 50;
|
||||||
|
|
||||||
var start = Stopwatch.GetTimestamp();
|
var start = Stopwatch.GetTimestamp();
|
||||||
var result = await service.GetTimelineAsync(
|
var result = await service.GetTimelineAsync(
|
||||||
new SbomTimelineQuery(artifact.Trim(), pageSize, offset),
|
new SbomTimelineQuery(artifact.Trim(), pageSize, offset),
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
|
|
||||||
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
var elapsedSeconds = Stopwatch.GetElapsedTime(start).TotalSeconds;
|
||||||
SbomMetrics.TimelineLatencySeconds.Record(elapsedSeconds, new TagList { { "artifact", artifact } });
|
SbomMetrics.TimelineLatencySeconds.Record(elapsedSeconds, new TagList { { "artifact", artifact } });
|
||||||
SbomMetrics.TimelineQueryTotal.Add(1, new TagList { { "artifact", artifact }, { "cache_hit", result.CacheHit } });
|
SbomMetrics.TimelineQueryTotal.Add(1, new TagList { { "artifact", artifact }, { "cache_hit", result.CacheHit } });
|
||||||
|
|
||||||
return Results.Ok(result.Result);
|
return Results.Ok(result.Result);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.MapGet("/sboms/{snapshotId}/projection", async Task<IResult> (
|
||||||
|
[FromServices] ISbomQueryService service,
|
||||||
|
[FromRoute] string? snapshotId,
|
||||||
|
[FromQuery(Name = "tenant")] string? tenantId,
|
||||||
|
CancellationToken cancellationToken) =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(snapshotId))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { error = "snapshotId is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(tenantId))
|
||||||
|
{
|
||||||
|
return Results.BadRequest(new { error = "tenant is required" });
|
||||||
|
}
|
||||||
|
|
||||||
|
var projection = await service.GetProjectionAsync(snapshotId.Trim(), tenantId.Trim(), cancellationToken);
|
||||||
|
if (projection is null)
|
||||||
|
{
|
||||||
|
return Results.NotFound(new { error = "projection not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Ok(new
|
||||||
|
{
|
||||||
|
snapshotId = projection.SnapshotId,
|
||||||
|
tenantId = projection.TenantId,
|
||||||
|
schemaVersion = projection.SchemaVersion,
|
||||||
|
hash = projection.ProjectionHash,
|
||||||
|
projection = projection.Projection
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
|
|
||||||
public partial class Program;
|
public partial class Program;
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using StellaOps.SbomService.Models;
|
||||||
|
|
||||||
|
namespace StellaOps.SbomService.Repositories;
|
||||||
|
|
||||||
|
internal sealed class FileProjectionRepository : IProjectionRepository
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyDictionary<(string SnapshotId, string TenantId), SbomProjectionResult> _projections;
|
||||||
|
|
||||||
|
public FileProjectionRepository(string fixturesPath)
|
||||||
|
{
|
||||||
|
if (!File.Exists(fixturesPath))
|
||||||
|
{
|
||||||
|
_projections = new Dictionary<(string, string), SbomProjectionResult>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var stream = File.OpenRead(fixturesPath);
|
||||||
|
var root = JsonNode.Parse(stream) as JsonArray ?? throw new InvalidOperationException("projections.json must be a JSON array");
|
||||||
|
|
||||||
|
var map = new Dictionary<(string, string), SbomProjectionResult>();
|
||||||
|
|
||||||
|
foreach (var node in root.OfType<JsonObject>())
|
||||||
|
{
|
||||||
|
var snapshotId = node["snapshotId"]?.GetValue<string>();
|
||||||
|
var tenantId = node["tenantId"]?.GetValue<string>();
|
||||||
|
var projectionNode = node["projection"];
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(snapshotId) || string.IsNullOrWhiteSpace(tenantId) || projectionNode is null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectionElement = ToElement(projectionNode);
|
||||||
|
var schemaVersion = node["schemaVersion"]?.GetValue<string>()
|
||||||
|
?? projectionNode["metadata"]? ["schemaVersion"]?.GetValue<string>()
|
||||||
|
?? "1.0.0";
|
||||||
|
|
||||||
|
var projectionHash = ComputeHash(projectionElement);
|
||||||
|
|
||||||
|
map[(snapshotId!, tenantId!)] = new SbomProjectionResult(
|
||||||
|
snapshotId!,
|
||||||
|
tenantId!,
|
||||||
|
projectionElement,
|
||||||
|
projectionHash,
|
||||||
|
schemaVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
_projections = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<SbomProjectionResult?> GetAsync(string snapshotId, string tenantId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_projections.TryGetValue((snapshotId, tenantId), out var result);
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ComputeHash(JsonElement element)
|
||||||
|
{
|
||||||
|
var json = JsonSerializer.Serialize(element, new JsonSerializerOptions { WriteIndented = false });
|
||||||
|
using var sha = SHA256.Create();
|
||||||
|
var bytes = sha.ComputeHash(System.Text.Encoding.UTF8.GetBytes(json));
|
||||||
|
return Convert.ToHexString(bytes).ToLowerInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static JsonElement ToElement(JsonNode node)
|
||||||
|
{
|
||||||
|
using var doc = JsonDocument.Parse(node.ToJsonString(new JsonSerializerOptions { WriteIndented = false }));
|
||||||
|
return doc.RootElement.Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using StellaOps.SbomService.Models;
|
||||||
|
|
||||||
|
namespace StellaOps.SbomService.Repositories;
|
||||||
|
|
||||||
|
public interface IProjectionRepository
|
||||||
|
{
|
||||||
|
Task<SbomProjectionResult?> GetAsync(string snapshotId, string tenantId, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using StellaOps.SbomService.Models;
|
using StellaOps.SbomService.Models;
|
||||||
|
|
||||||
namespace StellaOps.SbomService.Services;
|
namespace StellaOps.SbomService.Services;
|
||||||
|
|
||||||
public interface ISbomQueryService
|
public interface ISbomQueryService
|
||||||
{
|
{
|
||||||
Task<QueryResult<SbomPathResult>> GetPathsAsync(SbomPathQuery query, CancellationToken cancellationToken);
|
Task<QueryResult<SbomPathResult>> GetPathsAsync(SbomPathQuery query, CancellationToken cancellationToken);
|
||||||
@@ -11,4 +11,6 @@ public interface ISbomQueryService
|
|||||||
Task<QueryResult<SbomCatalogResult>> GetConsoleCatalogAsync(SbomCatalogQuery query, CancellationToken cancellationToken);
|
Task<QueryResult<SbomCatalogResult>> GetConsoleCatalogAsync(SbomCatalogQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
Task<QueryResult<ComponentLookupResult>> GetComponentLookupAsync(ComponentLookupQuery query, CancellationToken cancellationToken);
|
Task<QueryResult<ComponentLookupResult>> GetComponentLookupAsync(ComponentLookupQuery query, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<SbomProjectionResult?> GetProjectionAsync(string snapshotId, string tenantId, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,138 +1,140 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using StellaOps.SbomService.Models;
|
using StellaOps.SbomService.Models;
|
||||||
using StellaOps.SbomService.Repositories;
|
using StellaOps.SbomService.Repositories;
|
||||||
|
|
||||||
namespace StellaOps.SbomService.Services;
|
namespace StellaOps.SbomService.Services;
|
||||||
|
|
||||||
internal sealed class InMemorySbomQueryService : ISbomQueryService
|
internal sealed class InMemorySbomQueryService : ISbomQueryService
|
||||||
{
|
{
|
||||||
private readonly IReadOnlyList<PathRecord> _paths;
|
private readonly IReadOnlyList<PathRecord> _paths;
|
||||||
private readonly IReadOnlyList<TimelineRecord> _timelines;
|
private readonly IReadOnlyList<TimelineRecord> _timelines;
|
||||||
private readonly IReadOnlyList<CatalogRecord> _catalog;
|
private readonly IReadOnlyList<CatalogRecord> _catalog;
|
||||||
private readonly IComponentLookupRepository _componentLookupRepository;
|
private readonly IComponentLookupRepository _componentLookupRepository;
|
||||||
|
private readonly IProjectionRepository _projectionRepository;
|
||||||
private readonly ConcurrentDictionary<string, object> _cache = new();
|
private readonly ConcurrentDictionary<string, object> _cache = new();
|
||||||
|
|
||||||
public InMemorySbomQueryService(IComponentLookupRepository componentLookupRepository)
|
public InMemorySbomQueryService(IComponentLookupRepository componentLookupRepository, IProjectionRepository projectionRepository)
|
||||||
{
|
{
|
||||||
_componentLookupRepository = componentLookupRepository;
|
_componentLookupRepository = componentLookupRepository;
|
||||||
|
_projectionRepository = projectionRepository;
|
||||||
// Deterministic seed data for early contract testing; replace with Mongo-backed implementation later.
|
// Deterministic seed data for early contract testing; replace with Mongo-backed implementation later.
|
||||||
_paths = SeedPaths();
|
_paths = SeedPaths();
|
||||||
_timelines = SeedTimelines();
|
_timelines = SeedTimelines();
|
||||||
_catalog = SeedCatalog();
|
_catalog = SeedCatalog();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<QueryResult<SbomPathResult>> GetPathsAsync(SbomPathQuery query, CancellationToken cancellationToken)
|
public Task<QueryResult<SbomPathResult>> GetPathsAsync(SbomPathQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var cacheKey = $"paths|{query.Purl}|{query.Artifact}|{query.Scope}|{query.Environment}|{query.Offset}|{query.Limit}";
|
var cacheKey = $"paths|{query.Purl}|{query.Artifact}|{query.Scope}|{query.Environment}|{query.Offset}|{query.Limit}";
|
||||||
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomPathResult cachedResult)
|
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomPathResult cachedResult)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new QueryResult<SbomPathResult>(cachedResult, true));
|
return Task.FromResult(new QueryResult<SbomPathResult>(cachedResult, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtered = _paths
|
var filtered = _paths
|
||||||
.Where(p => p.Purl.Equals(query.Purl, StringComparison.OrdinalIgnoreCase))
|
.Where(p => p.Purl.Equals(query.Purl, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(p => query.Artifact is null || p.Artifact.Equals(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
.Where(p => query.Artifact is null || p.Artifact.Equals(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(p => query.Scope is null || string.Equals(p.Scope, query.Scope, StringComparison.OrdinalIgnoreCase))
|
.Where(p => query.Scope is null || string.Equals(p.Scope, query.Scope, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(p => query.Environment is null || string.Equals(p.Environment, query.Environment, StringComparison.OrdinalIgnoreCase))
|
.Where(p => query.Environment is null || string.Equals(p.Environment, query.Environment, StringComparison.OrdinalIgnoreCase))
|
||||||
.OrderBy(p => p.Artifact)
|
.OrderBy(p => p.Artifact)
|
||||||
.ThenBy(p => p.Environment)
|
.ThenBy(p => p.Environment)
|
||||||
.ThenBy(p => p.Scope)
|
.ThenBy(p => p.Scope)
|
||||||
.ThenBy(p => string.Join("->", p.Nodes.Select(n => n.Name)))
|
.ThenBy(p => string.Join("->", p.Nodes.Select(n => n.Name)))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var page = filtered
|
var page = filtered
|
||||||
.Skip(query.Offset)
|
.Skip(query.Offset)
|
||||||
.Take(query.Limit)
|
.Take(query.Limit)
|
||||||
.Select(r => new SbomPath(r.Nodes, r.RuntimeFlag, r.BlastRadius, r.NearestSafeVersion))
|
.Select(r => new SbomPath(r.Nodes, r.RuntimeFlag, r.BlastRadius, r.NearestSafeVersion))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
||||||
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
var result = new SbomPathResult(
|
var result = new SbomPathResult(
|
||||||
Purl: query.Purl,
|
Purl: query.Purl,
|
||||||
Artifact: query.Artifact,
|
Artifact: query.Artifact,
|
||||||
Scope: query.Scope,
|
Scope: query.Scope,
|
||||||
Environment: query.Environment,
|
Environment: query.Environment,
|
||||||
Paths: page,
|
Paths: page,
|
||||||
NextCursor: nextCursor);
|
NextCursor: nextCursor);
|
||||||
|
|
||||||
_cache[cacheKey] = result;
|
_cache[cacheKey] = result;
|
||||||
return Task.FromResult(new QueryResult<SbomPathResult>(result, false));
|
return Task.FromResult(new QueryResult<SbomPathResult>(result, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<QueryResult<SbomTimelineResult>> GetTimelineAsync(SbomTimelineQuery query, CancellationToken cancellationToken)
|
public Task<QueryResult<SbomTimelineResult>> GetTimelineAsync(SbomTimelineQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var cacheKey = $"timeline|{query.Artifact}|{query.Offset}|{query.Limit}";
|
var cacheKey = $"timeline|{query.Artifact}|{query.Offset}|{query.Limit}";
|
||||||
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomTimelineResult cachedTimeline)
|
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomTimelineResult cachedTimeline)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new QueryResult<SbomTimelineResult>(cachedTimeline, true));
|
return Task.FromResult(new QueryResult<SbomTimelineResult>(cachedTimeline, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtered = _timelines
|
var filtered = _timelines
|
||||||
.Where(t => t.Artifact.Equals(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
.Where(t => t.Artifact.Equals(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
||||||
.OrderByDescending(t => t.CreatedAt)
|
.OrderByDescending(t => t.CreatedAt)
|
||||||
.ThenByDescending(t => t.Version)
|
.ThenByDescending(t => t.Version)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var page = filtered
|
var page = filtered
|
||||||
.Skip(query.Offset)
|
.Skip(query.Offset)
|
||||||
.Take(query.Limit)
|
.Take(query.Limit)
|
||||||
.Select(t => new SbomVersion(t.Version, t.Digest, t.CreatedAt, t.SourceBundleHash, t.Provenance))
|
.Select(t => new SbomVersion(t.Version, t.Digest, t.CreatedAt, t.SourceBundleHash, t.Provenance))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
||||||
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
var result = new SbomTimelineResult(query.Artifact, page, nextCursor);
|
var result = new SbomTimelineResult(query.Artifact, page, nextCursor);
|
||||||
_cache[cacheKey] = result;
|
_cache[cacheKey] = result;
|
||||||
return Task.FromResult(new QueryResult<SbomTimelineResult>(result, false));
|
return Task.FromResult(new QueryResult<SbomTimelineResult>(result, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<QueryResult<SbomCatalogResult>> GetConsoleCatalogAsync(SbomCatalogQuery query, CancellationToken cancellationToken)
|
public Task<QueryResult<SbomCatalogResult>> GetConsoleCatalogAsync(SbomCatalogQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var cacheKey = $"catalog|{query.Artifact}|{query.License}|{query.Scope}|{query.AssetTag}|{query.Offset}|{query.Limit}";
|
var cacheKey = $"catalog|{query.Artifact}|{query.License}|{query.Scope}|{query.AssetTag}|{query.Offset}|{query.Limit}";
|
||||||
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomCatalogResult cachedCatalog)
|
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomCatalogResult cachedCatalog)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new QueryResult<SbomCatalogResult>(cachedCatalog, true));
|
return Task.FromResult(new QueryResult<SbomCatalogResult>(cachedCatalog, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtered = _catalog
|
var filtered = _catalog
|
||||||
.Where(c => query.Artifact is null || c.Artifact.Contains(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
.Where(c => query.Artifact is null || c.Artifact.Contains(query.Artifact, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(c => query.License is null || string.Equals(c.License, query.License, StringComparison.OrdinalIgnoreCase))
|
.Where(c => query.License is null || string.Equals(c.License, query.License, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(c => query.Scope is null || string.Equals(c.Scope, query.Scope, StringComparison.OrdinalIgnoreCase))
|
.Where(c => query.Scope is null || string.Equals(c.Scope, query.Scope, StringComparison.OrdinalIgnoreCase))
|
||||||
.Where(c => query.AssetTag is null || c.AssetTags.ContainsKey(query.AssetTag))
|
.Where(c => query.AssetTag is null || c.AssetTags.ContainsKey(query.AssetTag))
|
||||||
.OrderByDescending(c => c.CreatedAt)
|
.OrderByDescending(c => c.CreatedAt)
|
||||||
.ThenBy(c => c.Artifact)
|
.ThenBy(c => c.Artifact)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var page = filtered
|
var page = filtered
|
||||||
.Skip(query.Offset)
|
.Skip(query.Offset)
|
||||||
.Take(query.Limit)
|
.Take(query.Limit)
|
||||||
.Select(c => new SbomCatalogItem(
|
.Select(c => new SbomCatalogItem(
|
||||||
c.Artifact,
|
c.Artifact,
|
||||||
c.SbomVersion,
|
c.SbomVersion,
|
||||||
c.Digest,
|
c.Digest,
|
||||||
c.License,
|
c.License,
|
||||||
c.Scope,
|
c.Scope,
|
||||||
c.AssetTags,
|
c.AssetTags,
|
||||||
c.CreatedAt,
|
c.CreatedAt,
|
||||||
c.ProjectionHash,
|
c.ProjectionHash,
|
||||||
c.EvaluationMetadata))
|
c.EvaluationMetadata))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
string? nextCursor = query.Offset + query.Limit < filtered.Count
|
||||||
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
var result = new SbomCatalogResult(page, nextCursor);
|
var result = new SbomCatalogResult(page, nextCursor);
|
||||||
_cache[cacheKey] = result;
|
_cache[cacheKey] = result;
|
||||||
return Task.FromResult(new QueryResult<SbomCatalogResult>(result, false));
|
return Task.FromResult(new QueryResult<SbomCatalogResult>(result, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<QueryResult<ComponentLookupResult>> GetComponentLookupAsync(ComponentLookupQuery query, CancellationToken cancellationToken)
|
public async Task<QueryResult<ComponentLookupResult>> GetComponentLookupAsync(ComponentLookupQuery query, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var cacheKey = $"component|{query.Purl}|{query.Artifact}|{query.Offset}|{query.Limit}";
|
var cacheKey = $"component|{query.Purl}|{query.Artifact}|{query.Offset}|{query.Limit}";
|
||||||
@@ -140,217 +142,234 @@ internal sealed class InMemorySbomQueryService : ISbomQueryService
|
|||||||
{
|
{
|
||||||
return new QueryResult<ComponentLookupResult>(cachedResult, true);
|
return new QueryResult<ComponentLookupResult>(cachedResult, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var page = await _componentLookupRepository.QueryAsync(query, cancellationToken);
|
var page = await _componentLookupRepository.QueryAsync(query, cancellationToken);
|
||||||
|
|
||||||
string? nextCursor = query.Offset + query.Limit < page.Count
|
string? nextCursor = query.Offset + query.Limit < page.Count
|
||||||
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
? (query.Offset + query.Limit).ToString(CultureInfo.InvariantCulture)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
var neighbors = page
|
var neighbors = page
|
||||||
.Select(c => new ComponentNeighbor(c.NeighborPurl, c.Relationship, c.License, c.Scope, c.RuntimeFlag))
|
.Select(c => new ComponentNeighbor(c.NeighborPurl, c.Relationship, c.License, c.Scope, c.RuntimeFlag))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var result = new ComponentLookupResult(query.Purl, query.Artifact, neighbors, nextCursor, CacheHint: "seeded");
|
var result = new ComponentLookupResult(query.Purl, query.Artifact, neighbors, nextCursor, CacheHint: "seeded");
|
||||||
_cache[cacheKey] = result;
|
_cache[cacheKey] = result;
|
||||||
return new QueryResult<ComponentLookupResult>(result, false);
|
return new QueryResult<ComponentLookupResult>(result, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<PathRecord> SeedPaths()
|
public async Task<SbomProjectionResult?> GetProjectionAsync(string snapshotId, string tenantId, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return new List<PathRecord>
|
var cacheKey = $"projection|{snapshotId}|{tenantId}";
|
||||||
|
if (_cache.TryGetValue(cacheKey, out var cached) && cached is SbomProjectionResult cachedProjection)
|
||||||
{
|
{
|
||||||
new(
|
return cachedProjection;
|
||||||
Artifact: "ghcr.io/stellaops/sample-api@sha256:111",
|
}
|
||||||
Purl: "pkg:npm/lodash@4.17.21",
|
|
||||||
Scope: "runtime",
|
|
||||||
Environment: "prod",
|
|
||||||
RuntimeFlag: true,
|
|
||||||
BlastRadius: "medium",
|
|
||||||
NearestSafeVersion: "pkg:npm/lodash@4.17.22",
|
|
||||||
Nodes: new[]
|
|
||||||
{
|
|
||||||
new SbomPathNode("sample-api", "artifact"),
|
|
||||||
new SbomPathNode("express", "npm"),
|
|
||||||
new SbomPathNode("lodash", "npm")
|
|
||||||
}),
|
|
||||||
new(
|
|
||||||
Artifact: "ghcr.io/stellaops/sample-api@sha256:111",
|
|
||||||
Purl: "pkg:npm/lodash@4.17.21",
|
|
||||||
Scope: "build",
|
|
||||||
Environment: "prod",
|
|
||||||
RuntimeFlag: false,
|
|
||||||
BlastRadius: "low",
|
|
||||||
NearestSafeVersion: "pkg:npm/lodash@4.17.22",
|
|
||||||
Nodes: new[]
|
|
||||||
{
|
|
||||||
new SbomPathNode("sample-api", "artifact"),
|
|
||||||
new SbomPathNode("rollup", "npm"),
|
|
||||||
new SbomPathNode("lodash", "npm")
|
|
||||||
}),
|
|
||||||
new(
|
|
||||||
Artifact: "ghcr.io/stellaops/sample-api@sha256:222",
|
|
||||||
Purl: "pkg:nuget/Newtonsoft.Json@13.0.2",
|
|
||||||
Scope: "runtime",
|
|
||||||
Environment: "staging",
|
|
||||||
RuntimeFlag: true,
|
|
||||||
BlastRadius: "high",
|
|
||||||
NearestSafeVersion: "pkg:nuget/Newtonsoft.Json@13.0.3",
|
|
||||||
Nodes: new[]
|
|
||||||
{
|
|
||||||
new SbomPathNode("sample-worker", "artifact"),
|
|
||||||
new SbomPathNode("StellaOps.Core", "nuget"),
|
|
||||||
new SbomPathNode("Newtonsoft.Json", "nuget")
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IReadOnlyList<TimelineRecord> SeedTimelines()
|
var projection = await _projectionRepository.GetAsync(snapshotId, tenantId, cancellationToken);
|
||||||
{
|
if (projection is not null)
|
||||||
return new List<TimelineRecord>
|
|
||||||
{
|
{
|
||||||
new(
|
_cache[cacheKey] = projection;
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
}
|
||||||
Version: "2025.11.15.1",
|
|
||||||
Digest: "sha256:111",
|
return projection;
|
||||||
SourceBundleHash: "sha256:bundle111",
|
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 15, 12, 0, 0, TimeSpan.Zero),
|
|
||||||
Provenance: "scanner:surface_bundle_mock_v1.tgz"),
|
|
||||||
new(
|
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
|
||||||
Version: "2025.11.16.1",
|
|
||||||
Digest: "sha256:112",
|
|
||||||
SourceBundleHash: "sha256:bundle112",
|
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 16, 12, 0, 0, TimeSpan.Zero),
|
|
||||||
Provenance: "scanner:surface_bundle_mock_v1.tgz"),
|
|
||||||
new(
|
|
||||||
Artifact: "ghcr.io/stellaops/sample-worker",
|
|
||||||
Version: "2025.11.12.0",
|
|
||||||
Digest: "sha256:222",
|
|
||||||
SourceBundleHash: "sha256:bundle222",
|
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 12, 8, 0, 0, TimeSpan.Zero),
|
|
||||||
Provenance: "upload:spdx:worker"),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyList<CatalogRecord> SeedCatalog()
|
private static IReadOnlyList<PathRecord> SeedPaths()
|
||||||
{
|
{
|
||||||
return new List<CatalogRecord>
|
return new List<PathRecord>
|
||||||
{
|
{
|
||||||
new(
|
new(
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
Artifact: "ghcr.io/stellaops/sample-api@sha256:111",
|
||||||
SbomVersion: "2025.11.16.1",
|
Purl: "pkg:npm/lodash@4.17.21",
|
||||||
Digest: "sha256:112",
|
Scope: "runtime",
|
||||||
License: "MIT",
|
Environment: "prod",
|
||||||
Scope: "runtime",
|
RuntimeFlag: true,
|
||||||
AssetTags: new Dictionary<string, string>
|
BlastRadius: "medium",
|
||||||
{
|
NearestSafeVersion: "pkg:npm/lodash@4.17.22",
|
||||||
["owner"] = "payments",
|
Nodes: new[]
|
||||||
["criticality"] = "high",
|
{
|
||||||
["env"] = "prod"
|
new SbomPathNode("sample-api", "artifact"),
|
||||||
},
|
new SbomPathNode("express", "npm"),
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 16, 12, 0, 0, TimeSpan.Zero),
|
new SbomPathNode("lodash", "npm")
|
||||||
ProjectionHash: "sha256:proj112",
|
}),
|
||||||
EvaluationMetadata: "eval:passed:v1"),
|
new(
|
||||||
new(
|
Artifact: "ghcr.io/stellaops/sample-api@sha256:111",
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
Purl: "pkg:npm/lodash@4.17.21",
|
||||||
SbomVersion: "2025.11.15.1",
|
Scope: "build",
|
||||||
Digest: "sha256:111",
|
Environment: "prod",
|
||||||
License: "MIT",
|
RuntimeFlag: false,
|
||||||
Scope: "runtime",
|
BlastRadius: "low",
|
||||||
AssetTags: new Dictionary<string, string>
|
NearestSafeVersion: "pkg:npm/lodash@4.17.22",
|
||||||
{
|
Nodes: new[]
|
||||||
["owner"] = "payments",
|
{
|
||||||
["criticality"] = "high",
|
new SbomPathNode("sample-api", "artifact"),
|
||||||
["env"] = "prod"
|
new SbomPathNode("rollup", "npm"),
|
||||||
},
|
new SbomPathNode("lodash", "npm")
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 15, 12, 0, 0, TimeSpan.Zero),
|
}),
|
||||||
ProjectionHash: "sha256:proj111",
|
new(
|
||||||
EvaluationMetadata: "eval:passed:v1"),
|
Artifact: "ghcr.io/stellaops/sample-api@sha256:222",
|
||||||
new(
|
Purl: "pkg:nuget/Newtonsoft.Json@13.0.2",
|
||||||
Artifact: "ghcr.io/stellaops/sample-worker",
|
Scope: "runtime",
|
||||||
SbomVersion: "2025.11.12.0",
|
Environment: "staging",
|
||||||
Digest: "sha256:222",
|
RuntimeFlag: true,
|
||||||
License: "Apache-2.0",
|
BlastRadius: "high",
|
||||||
Scope: "runtime",
|
NearestSafeVersion: "pkg:nuget/Newtonsoft.Json@13.0.3",
|
||||||
AssetTags: new Dictionary<string, string>
|
Nodes: new[]
|
||||||
{
|
{
|
||||||
["owner"] = "platform",
|
new SbomPathNode("sample-worker", "artifact"),
|
||||||
["criticality"] = "medium",
|
new SbomPathNode("StellaOps.Core", "nuget"),
|
||||||
["env"] = "staging"
|
new SbomPathNode("Newtonsoft.Json", "nuget")
|
||||||
},
|
})
|
||||||
CreatedAt: new DateTimeOffset(2025, 11, 12, 8, 0, 0, TimeSpan.Zero),
|
};
|
||||||
ProjectionHash: "sha256:proj222",
|
}
|
||||||
EvaluationMetadata: "eval:pending:v1"),
|
|
||||||
};
|
private static IReadOnlyList<TimelineRecord> SeedTimelines()
|
||||||
}
|
{
|
||||||
|
return new List<TimelineRecord>
|
||||||
private static IReadOnlyList<ComponentLookupRecord> SeedComponents()
|
{
|
||||||
{
|
new(
|
||||||
return new List<ComponentLookupRecord>
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
{
|
Version: "2025.11.15.1",
|
||||||
new(
|
Digest: "sha256:111",
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
SourceBundleHash: "sha256:bundle111",
|
||||||
Purl: "pkg:npm/lodash@4.17.21",
|
CreatedAt: new DateTimeOffset(2025, 11, 15, 12, 0, 0, TimeSpan.Zero),
|
||||||
NeighborPurl: "pkg:npm/express@4.18.2",
|
Provenance: "scanner:surface_bundle_mock_v1.tgz"),
|
||||||
Relationship: "DEPENDS_ON",
|
new(
|
||||||
License: "MIT",
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
Scope: "runtime",
|
Version: "2025.11.16.1",
|
||||||
RuntimeFlag: true),
|
Digest: "sha256:112",
|
||||||
new(
|
SourceBundleHash: "sha256:bundle112",
|
||||||
Artifact: "ghcr.io/stellaops/sample-api",
|
CreatedAt: new DateTimeOffset(2025, 11, 16, 12, 0, 0, TimeSpan.Zero),
|
||||||
Purl: "pkg:npm/lodash@4.17.21",
|
Provenance: "scanner:surface_bundle_mock_v1.tgz"),
|
||||||
NeighborPurl: "pkg:npm/rollup@3.0.0",
|
new(
|
||||||
Relationship: "DEPENDS_ON",
|
Artifact: "ghcr.io/stellaops/sample-worker",
|
||||||
License: "MIT",
|
Version: "2025.11.12.0",
|
||||||
Scope: "build",
|
Digest: "sha256:222",
|
||||||
RuntimeFlag: false),
|
SourceBundleHash: "sha256:bundle222",
|
||||||
new(
|
CreatedAt: new DateTimeOffset(2025, 11, 12, 8, 0, 0, TimeSpan.Zero),
|
||||||
Artifact: "ghcr.io/stellaops/sample-worker",
|
Provenance: "upload:spdx:worker"),
|
||||||
Purl: "pkg:nuget/Newtonsoft.Json@13.0.2",
|
};
|
||||||
NeighborPurl: "pkg:nuget/StellaOps.Core@1.0.0",
|
}
|
||||||
Relationship: "DEPENDS_ON",
|
|
||||||
License: "Apache-2.0",
|
private static IReadOnlyList<CatalogRecord> SeedCatalog()
|
||||||
Scope: "runtime",
|
{
|
||||||
RuntimeFlag: true)
|
return new List<CatalogRecord>
|
||||||
};
|
{
|
||||||
}
|
new(
|
||||||
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
private sealed record PathRecord(
|
SbomVersion: "2025.11.16.1",
|
||||||
string Artifact,
|
Digest: "sha256:112",
|
||||||
string Purl,
|
License: "MIT",
|
||||||
string? Scope,
|
Scope: "runtime",
|
||||||
string? Environment,
|
AssetTags: new Dictionary<string, string>
|
||||||
bool RuntimeFlag,
|
{
|
||||||
string? BlastRadius,
|
["owner"] = "payments",
|
||||||
string? NearestSafeVersion,
|
["criticality"] = "high",
|
||||||
IReadOnlyList<SbomPathNode> Nodes);
|
["env"] = "prod"
|
||||||
|
},
|
||||||
private sealed record TimelineRecord(
|
CreatedAt: new DateTimeOffset(2025, 11, 16, 12, 0, 0, TimeSpan.Zero),
|
||||||
string Artifact,
|
ProjectionHash: "sha256:proj112",
|
||||||
string Version,
|
EvaluationMetadata: "eval:passed:v1"),
|
||||||
string Digest,
|
new(
|
||||||
string SourceBundleHash,
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
DateTimeOffset CreatedAt,
|
SbomVersion: "2025.11.15.1",
|
||||||
string? Provenance);
|
Digest: "sha256:111",
|
||||||
|
License: "MIT",
|
||||||
private sealed record CatalogRecord(
|
Scope: "runtime",
|
||||||
string Artifact,
|
AssetTags: new Dictionary<string, string>
|
||||||
string SbomVersion,
|
{
|
||||||
string Digest,
|
["owner"] = "payments",
|
||||||
string? License,
|
["criticality"] = "high",
|
||||||
string Scope,
|
["env"] = "prod"
|
||||||
IReadOnlyDictionary<string, string> AssetTags,
|
},
|
||||||
DateTimeOffset CreatedAt,
|
CreatedAt: new DateTimeOffset(2025, 11, 15, 12, 0, 0, TimeSpan.Zero),
|
||||||
string ProjectionHash,
|
ProjectionHash: "sha256:proj111",
|
||||||
string EvaluationMetadata);
|
EvaluationMetadata: "eval:passed:v1"),
|
||||||
|
new(
|
||||||
private sealed record ComponentLookupRecord(
|
Artifact: "ghcr.io/stellaops/sample-worker",
|
||||||
string Artifact,
|
SbomVersion: "2025.11.12.0",
|
||||||
string Purl,
|
Digest: "sha256:222",
|
||||||
string NeighborPurl,
|
License: "Apache-2.0",
|
||||||
string Relationship,
|
Scope: "runtime",
|
||||||
string? License,
|
AssetTags: new Dictionary<string, string>
|
||||||
string Scope,
|
{
|
||||||
bool RuntimeFlag);
|
["owner"] = "platform",
|
||||||
}
|
["criticality"] = "medium",
|
||||||
|
["env"] = "staging"
|
||||||
|
},
|
||||||
|
CreatedAt: new DateTimeOffset(2025, 11, 12, 8, 0, 0, TimeSpan.Zero),
|
||||||
|
ProjectionHash: "sha256:proj222",
|
||||||
|
EvaluationMetadata: "eval:pending:v1"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<ComponentLookupRecord> SeedComponents()
|
||||||
|
{
|
||||||
|
return new List<ComponentLookupRecord>
|
||||||
|
{
|
||||||
|
new(
|
||||||
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
|
Purl: "pkg:npm/lodash@4.17.21",
|
||||||
|
NeighborPurl: "pkg:npm/express@4.18.2",
|
||||||
|
Relationship: "DEPENDS_ON",
|
||||||
|
License: "MIT",
|
||||||
|
Scope: "runtime",
|
||||||
|
RuntimeFlag: true),
|
||||||
|
new(
|
||||||
|
Artifact: "ghcr.io/stellaops/sample-api",
|
||||||
|
Purl: "pkg:npm/lodash@4.17.21",
|
||||||
|
NeighborPurl: "pkg:npm/rollup@3.0.0",
|
||||||
|
Relationship: "DEPENDS_ON",
|
||||||
|
License: "MIT",
|
||||||
|
Scope: "build",
|
||||||
|
RuntimeFlag: false),
|
||||||
|
new(
|
||||||
|
Artifact: "ghcr.io/stellaops/sample-worker",
|
||||||
|
Purl: "pkg:nuget/Newtonsoft.Json@13.0.2",
|
||||||
|
NeighborPurl: "pkg:nuget/StellaOps.Core@1.0.0",
|
||||||
|
Relationship: "DEPENDS_ON",
|
||||||
|
License: "Apache-2.0",
|
||||||
|
Scope: "runtime",
|
||||||
|
RuntimeFlag: true)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record PathRecord(
|
||||||
|
string Artifact,
|
||||||
|
string Purl,
|
||||||
|
string? Scope,
|
||||||
|
string? Environment,
|
||||||
|
bool RuntimeFlag,
|
||||||
|
string? BlastRadius,
|
||||||
|
string? NearestSafeVersion,
|
||||||
|
IReadOnlyList<SbomPathNode> Nodes);
|
||||||
|
|
||||||
|
private sealed record TimelineRecord(
|
||||||
|
string Artifact,
|
||||||
|
string Version,
|
||||||
|
string Digest,
|
||||||
|
string SourceBundleHash,
|
||||||
|
DateTimeOffset CreatedAt,
|
||||||
|
string? Provenance);
|
||||||
|
|
||||||
|
private sealed record CatalogRecord(
|
||||||
|
string Artifact,
|
||||||
|
string SbomVersion,
|
||||||
|
string Digest,
|
||||||
|
string? License,
|
||||||
|
string Scope,
|
||||||
|
IReadOnlyDictionary<string, string> AssetTags,
|
||||||
|
DateTimeOffset CreatedAt,
|
||||||
|
string ProjectionHash,
|
||||||
|
string EvaluationMetadata);
|
||||||
|
|
||||||
|
private sealed record ComponentLookupRecord(
|
||||||
|
string Artifact,
|
||||||
|
string Purl,
|
||||||
|
string NeighborPurl,
|
||||||
|
string Relationship,
|
||||||
|
string? License,
|
||||||
|
string Scope,
|
||||||
|
bool RuntimeFlag);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user