diff --git a/.gitea/workflows/build-test-deploy.yml b/.gitea/workflows/build-test-deploy.yml index 07b7e6400..fe46369cb 100644 --- a/.gitea/workflows/build-test-deploy.yml +++ b/.gitea/workflows/build-test-deploy.yml @@ -111,6 +111,10 @@ jobs: - name: Validate telemetry storage configuration run: python3 ops/devops/telemetry/validate_storage_stack.py + - name: Task Pack offline bundle fixtures + run: | + python3 scripts/packs/run-fixtures-check.sh + - name: Telemetry tenant isolation smoke env: COMPOSE_DIR: ${GITHUB_WORKSPACE}/deploy/compose @@ -203,6 +207,14 @@ jobs: --results-directory "$TEST_RESULTS_DIR" done + - name: Run TimelineIndexer tests (EB1 evidence linkage gate) + run: | + mkdir -p "$TEST_RESULTS_DIR" + dotnet test src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.sln \ + --configuration $BUILD_CONFIGURATION \ + --logger "trx;LogFileName=timelineindexer-tests.trx" \ + --results-directory "$TEST_RESULTS_DIR" + - name: Lint policy DSL samples run: dotnet run --project tools/PolicyDslValidator/PolicyDslValidator.csproj -- --strict docs/examples/policies/*.yaml diff --git a/.gitea/workflows/evidence-locker.yml b/.gitea/workflows/evidence-locker.yml index b650f8cc3..f0bdb3610 100644 --- a/.gitea/workflows/evidence-locker.yml +++ b/.gitea/workflows/evidence-locker.yml @@ -31,14 +31,32 @@ jobs: needs: check-evidence-locker env: STAGED_DIR: evidence-locker/zastava/2025-12-02 + MODULE_ROOT: docs/modules/zastava steps: - name: Checkout uses: actions/checkout@v4 - name: Package staged Zastava artefacts run: | - test -d "$STAGED_DIR" || { echo "missing $STAGED_DIR" >&2; exit 1; } - tar -cf /tmp/zastava-evidence.tar -C "$STAGED_DIR" . + test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; } + tmpdir=$(mktemp -d) + rsync -a --relative \ + "$MODULE_ROOT/SHA256SUMS" \ + "$MODULE_ROOT/schemas/" \ + "$MODULE_ROOT/exports/" \ + "$MODULE_ROOT/thresholds.yaml" \ + "$MODULE_ROOT/thresholds.yaml.dsse" \ + "$MODULE_ROOT/kit/verify.sh" \ + "$MODULE_ROOT/kit/README.md" \ + "$MODULE_ROOT/kit/ed25519.pub" \ + "$MODULE_ROOT/kit/zastava-kit.tzst" \ + "$MODULE_ROOT/kit/zastava-kit.tzst.dsse" \ + "$MODULE_ROOT/evidence/README.md" \ + "$tmpdir/" + (cd "$tmpdir/docs/modules/zastava" && sha256sum --check SHA256SUMS) + tar --sort=name --mtime="UTC 1970-01-01" --owner=0 --group=0 --numeric-owner \ + -cf /tmp/zastava-evidence.tar -C "$tmpdir/docs/modules/zastava" . + sha256sum /tmp/zastava-evidence.tar - name: Upload staged artefacts (fallback) uses: actions/upload-artifact@v4 diff --git a/.gitea/workflows/promote.yml b/.gitea/workflows/promote.yml index 21b9b9961..287318569 100644 --- a/.gitea/workflows/promote.yml +++ b/.gitea/workflows/promote.yml @@ -22,13 +22,16 @@ jobs: runs-on: ubuntu-22.04 environment: production steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Resolve staging credentials - id: staging - run: | - missing=() + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Task Pack offline bundle fixtures + run: python3 scripts/packs/run-fixtures-check.sh + + - name: Resolve staging credentials + id: staging + run: | + missing=() host="${{ secrets.STAGING_DEPLOYMENT_HOST }}" if [ -z "$host" ]; then host="${{ vars.STAGING_DEPLOYMENT_HOST }}"; fi diff --git a/.gitea/workflows/signals-evidence-locker.yml b/.gitea/workflows/signals-evidence-locker.yml new file mode 100644 index 000000000..d06a211ad --- /dev/null +++ b/.gitea/workflows/signals-evidence-locker.yml @@ -0,0 +1,64 @@ +name: signals-evidence-locker +on: + workflow_dispatch: + inputs: + retention_target: + description: "Retention days target" + required: false + default: "180" + +jobs: + prepare-signals-evidence: + runs-on: ubuntu-latest + env: + MODULE_ROOT: docs/modules/signals + OUT_DIR: evidence-locker/signals/2025-12-05 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Build deterministic signals evidence tar + run: | + set -euo pipefail + test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; } + + tmpdir=$(mktemp -d) + rsync -a --relative \ + "$OUT_DIR/SHA256SUMS" \ + "$OUT_DIR/confidence_decay_config.sigstore.json" \ + "$OUT_DIR/unknowns_scoring_manifest.sigstore.json" \ + "$OUT_DIR/heuristics_catalog.sigstore.json" \ + "$MODULE_ROOT/decay/confidence_decay_config.yaml" \ + "$MODULE_ROOT/unknowns/unknowns_scoring_manifest.json" \ + "$MODULE_ROOT/heuristics/heuristics.catalog.json" \ + "$tmpdir/" + + (cd "$tmpdir/$OUT_DIR" && sha256sum --check SHA256SUMS) + + tar --sort=name --mtime="UTC 1970-01-01" --owner=0 --group=0 --numeric-owner \ + -cf /tmp/signals-evidence.tar -C "$tmpdir" . + + sha256sum /tmp/signals-evidence.tar > /tmp/signals-evidence.tar.sha256 + + - name: Upload artifact (fallback) + uses: actions/upload-artifact@v4 + with: + name: signals-evidence-2025-12-05 + path: | + /tmp/signals-evidence.tar + /tmp/signals-evidence.tar.sha256 + + - name: Push to Evidence Locker + if: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN != '' && env.EVIDENCE_LOCKER_URL != '' }} + env: + TOKEN: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN }} + URL: ${{ env.EVIDENCE_LOCKER_URL }} + run: | + curl -f -X PUT "$URL/signals/2025-12-05/signals-evidence.tar" \ + -H "Authorization: Bearer $TOKEN" \ + --data-binary @/tmp/signals-evidence.tar + + - name: Skip push (missing secret or URL) + if: ${{ secrets.CI_EVIDENCE_LOCKER_TOKEN == '' || env.EVIDENCE_LOCKER_URL == '' }} + run: | + echo "Locker push skipped: set CI_EVIDENCE_LOCKER_TOKEN and EVIDENCE_LOCKER_URL to enable." >&2 diff --git a/docs/advisories/explorer-integration.md b/docs/advisories/explorer-integration.md new file mode 100644 index 000000000..58ba67f8c --- /dev/null +++ b/docs/advisories/explorer-integration.md @@ -0,0 +1,19 @@ +# Advisories Integration with Vuln Explorer (Md.XI draft) + +> Status: DRAFT — waiting on export bundle spec + provenance notes; keep TODO. + +## Scope +- Describe advisory normalization, withdrawn handling, provenance, and export bundle linkage for Vuln Explorer. +- Deterministic examples with hashes in `docs/assets/vuln-explorer/SHA256SUMS`. + +## Dependencies +- Export bundle spec/provenance notes (in progress). +- GRAP0101 identifiers. + +## Outline +- Advisory ingestion flow and key normalization. +- Withdrawn/updated advisory handling. +- Provenance: DSSE/Rekor optional; bundle manifests. +- Cross-links to findings ledger and VEX decisions. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/airgap/SHA256SUMS b/docs/airgap/SHA256SUMS new file mode 100644 index 000000000..8db6848c0 --- /dev/null +++ b/docs/airgap/SHA256SUMS @@ -0,0 +1 @@ +# Placeholder hashes; replace with real asset sums when inputs arrive diff --git a/docs/airgap/risk-bundles.md b/docs/airgap/risk-bundles.md new file mode 100644 index 000000000..1823ad9c6 --- /dev/null +++ b/docs/airgap/risk-bundles.md @@ -0,0 +1,17 @@ +# Risk Bundles (Airgap) — outline + +- TBD pending export bundle shapes + hashing inputs. + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Bundle structure and manifest fields. +- Build workflow (offline). +- Verification workflow with hash list. +- Import/consumption steps and error handling. diff --git a/docs/api/signals.md b/docs/api/signals.md new file mode 100644 index 000000000..63f6827e2 --- /dev/null +++ b/docs/api/signals.md @@ -0,0 +1,15 @@ +# Signals API (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Endpoint list and path parameters. +- Payload schemas and ETag behavior. +- Error model and deterministic examples. +- Hashes for any sample responses/fixtures. diff --git a/docs/assets/vuln-explorer/SHA256SUMS b/docs/assets/vuln-explorer/SHA256SUMS new file mode 100644 index 000000000..f73f3e13d --- /dev/null +++ b/docs/assets/vuln-explorer/SHA256SUMS @@ -0,0 +1,3 @@ +# Vuln Explorer Md.XI asset hashes +# Format: +# Populate when captures/payloads land (screens, API/CLI samples, fixtures). diff --git a/docs/console/risk-ui.md b/docs/console/risk-ui.md new file mode 100644 index 000000000..4f3439705 --- /dev/null +++ b/docs/console/risk-ui.md @@ -0,0 +1,17 @@ +# Risk UI (outline) + +- TBD once console assets arrive (authoring, simulation, dashboards). + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Overview and navigation (authoring/simulation dashboards). +- Data inputs and validation. +- Simulation flows and dashboards. +- Exports/hashes for screenshots or payload samples (record in `SHA256SUMS`). diff --git a/docs/diagrams/sbom-vex-blueprint.svg b/docs/diagrams/sbom-vex-blueprint.svg new file mode 100644 index 000000000..da2d4cd78 --- /dev/null +++ b/docs/diagrams/sbom-vex-blueprint.svg @@ -0,0 +1 @@ + diff --git a/docs/implplan/BLOCKED_DEPENDENCY_TREE.md b/docs/implplan/BLOCKED_DEPENDENCY_TREE.md index 33249c844..9af1d356e 100644 --- a/docs/implplan/BLOCKED_DEPENDENCY_TREE.md +++ b/docs/implplan/BLOCKED_DEPENDENCY_TREE.md @@ -1,6 +1,6 @@ # BLOCKED Tasks Dependency Tree - -> **Last Updated:** 2025-12-05 (13 specs + 3 implementations = ~84+ tasks unblocked) +> **Last Updated:** 2025-12-06 (post Md.IX sync; 13 specs + 3 implementations = ~84+ tasks unblocked) +> **Last Updated:** 2025-12-06 (post Md.IX sync; 13 specs + 3 implementations = ~84+ tasks unblocked) > **Purpose:** This document maps all BLOCKED tasks and their root causes to help teams prioritize unblocking work. ## How to Use This Document @@ -201,6 +201,105 @@ attestor SDK transport contract (scanner analyzers ✅ COMPILE) --- +## 7. DOCS MD.IX (SPRINT_0309_0001_0009_docs_tasks_md_ix) + +**Root Blocker:** `DOCS-RISK-67-002 draft (risk API)` (due 2025-12-09) + +``` +DOCS-RISK-67-002 draft missing + +-- DOCS-RISK-67-003 (risk UI docs) + +-- DOCS-RISK-67-004 (CLI risk guide) + +-- DOCS-RISK-68-001 (airgap risk bundles) + +-- DOCS-RISK-68-002 (AOC invariants update) +``` + +**Impact:** 4 docs tasks (risk chain) + +**To Unblock:** API Guild to deliver DOCS-RISK-67-002 draft by 2025-12-09; Console Guild to provide UI captures/hashes by 2025-12-10. + +--- + +**Root Blocker:** `Signals schema + UI overlay assets` (due 2025-12-09) + +``` +Signals schema/overlays missing + +-- DOCS-SIG-26-001 (reachability states/scores) + +-- DOCS-SIG-26-002 (callgraph formats) + +-- DOCS-SIG-26-003 (runtime facts) + +-- DOCS-SIG-26-004 (signals weighting) + +-- DOCS-SIG-26-005 (UI overlays) + +-- DOCS-SIG-26-006 (CLI reachability guide) + +-- DOCS-SIG-26-007 (API reference) +``` + +**Impact:** 7 docs tasks (signals chain) + +**To Unblock:** Signals Guild + UI Guild to drop schema notes and overlay assets by 2025-12-09; Policy Guild to supply SPL weighting examples by 2025-12-10; DevEx/CLI Guild to share CLI recipes by 2025-12-12. + +--- + +**Root Blocker:** `SDK generator sample outputs (TS/Python/Go/Java)` (due 2025-12-11) + +``` +SDK generator outputs pending + +-- DOCS-SDK-62-001 (SDK overview + language guides) +``` + +**Impact:** 1 docs task (+ downstream parity/CLI consumers) + +**To Unblock:** SDK Generator Guild to deliver frozen samples by 2025-12-11. + +**Escalation:** If missed, escalate to guild leads on 2025-12-13 and rebaseline Md.IX dates. + +--- + +**Root Blocker:** `Export bundle shapes + hashing inputs` (due 2025-12-11) + +``` +Export bundle shapes pending + +-- DOCS-RISK-68-001 (airgap risk bundles guide) + +-- DOCS-RISK-68-002 (AOC invariants update) +``` + +**Impact:** 2 docs tasks + +**To Unblock:** Export Guild to send bundle shapes + hash inputs by 2025-12-11. + +**Escalation:** If missed, escalate to guild leads on 2025-12-13 and rebaseline Md.IX dates. + +--- + +**Root Blocker:** `Security scope matrix + privacy controls` (due 2025-12-11) + +``` +Security scopes/privacy inputs pending + +-- DOCS-SEC-62-001 (auth scopes) + +-- DOCS-SEC-OBS-50-001 (redaction & privacy) +``` + +**Impact:** 2 docs tasks + +**To Unblock:** Security Guild + Authority Core to provide scope matrix/tenancy header rules and privacy/opt-in debug guidance by 2025-12-11. + +**Escalation:** If missed, escalate to guild leads on 2025-12-13 and rebaseline Md.IX dates. + +--- + +**Root Blocker:** `Ops incident checklist` (due 2025-12-10) + +``` +Ops incident checklist missing + +-- DOCS-RUNBOOK-55-001 (incident runbook) +``` + +**Impact:** 1 docs task + +**To Unblock:** Ops Guild to hand over activation/escalation/retention checklist by 2025-12-10. + +**Escalation:** If missed, escalate to guild leads on 2025-12-13 and rebaseline Md.IX dates. + +--- + ## 7. CONSOLE OBSERVABILITY DOCS (CONOBS5201) **Root Blocker:** Observability Hub widget captures + deterministic sample payload hashes not delivered (Console Guild) @@ -787,6 +886,51 @@ LEDGER-AIRGAP-56-002 staleness spec + AirGap time anchors --- +## 15. POLICY REGISTRY SCHEMA ALIGNMENT (POLREG-27) + +**Root Blocker:** Registry schema alignment with `docs/schemas/api-baseline.schema.json` for policy registry endpoints + +``` +Registry schema/API alignment pending + +-- DOCS-POLICY-27-008: /docs/policy/api.md + +-- DOCS-POLICY-27-009: /docs/security/policy-attestations.md + +-- DOCS-POLICY-27-010: /docs/modules/policy/registry-architecture.md + +-- DOCS-POLICY-27-011: /docs/observability/policy-telemetry.md + +-- DOCS-POLICY-27-012: /docs/runbooks/policy-incident.md + +-- DOCS-POLICY-27-013: /docs/examples/policy-templates.md + +-- DOCS-POLICY-27-014: /docs/aoc/aoc-guardrails.md +``` + +**Impact:** 7 policy documentation tasks (Md.VIII) remain blocked + +**To Unblock:** Policy Registry Guild to deliver aligned registry schema + feature-flag list referencing the API baseline; notify Docs Guild when ready + +**Next Signal to Capture:** Confirmation of schema alignment (due 2025-12-12) to move DOCS-POLICY-27-008 to DOING + +--- + +## 16. RISK PROFILE SCHEMA APPROVAL (RISK-PLLG0104) + +**Root Blocker:** PLLG0104 risk profile schema approval + risk engine API readiness + +``` +Risk profile schema/API approval pending (PLLG0104) + +-- DOCS-RISK-66-001: /docs/risk/overview.md + +-- DOCS-RISK-66-002: /docs/risk/profiles.md + +-- DOCS-RISK-66-003: /docs/risk/factors.md + +-- DOCS-RISK-66-004: /docs/risk/formulas.md + +-- DOCS-RISK-67-001: /docs/risk/explainability.md + +-- DOCS-RISK-67-002: /docs/risk/api.md +``` + +**Impact:** 6 risk documentation tasks (Md.VIII) blocked awaiting schema/API artifacts and UI telemetry captures + +**To Unblock:** PLLG0104 to approve schema; Risk Engine Guild to provide API payload samples + telemetry artifacts; Docs Guild to start outlines immediately after approval + +**Next Signal to Capture:** PLLG0104 approval and sample payloads (due 2025-12-13) to move DOCS-RISK-66-001/002 to DOING + +--- + ## Summary Statistics | Root Blocker Category | Root Blockers | Downstream Tasks | diff --git a/docs/implplan/SPRINT_0140_0001_0001_runtime_signals.md b/docs/implplan/SPRINT_0140_0001_0001_runtime_signals.md index cab00c28c..402b5db7e 100644 --- a/docs/implplan/SPRINT_0140_0001_0001_runtime_signals.md +++ b/docs/implplan/SPRINT_0140_0001_0001_runtime_signals.md @@ -29,8 +29,8 @@ | 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`; 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 | DONE (2025-11-28) | Sprint 0141 (Graph Indexer) complete: all GRAPH-INDEX-28-007..010 tasks DONE. | 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 | DOING (2025-11-28) | Sprint 0142 mostly complete: SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002, SBOM-ORCH-32/33/34-001, SBOM-VULN-29-001/002 all DONE. Only SBOM-CONSOLE-23-001/002 remain BLOCKED. | SBOM Service Guild · Cartographer Guild | Finalize projection schema, emit change events, and wire orchestrator/observability (SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002). | -| 3 | 140.C Signals wave | DOING (2025-11-28) | Sprint 0143: SIGNALS-24-001/002/003 DONE; SIGNALS-24-004/005 remain BLOCKED on CAS promotion. | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild | Close SIGNALS-24-002/003 and clear blockers for 24-004/005 scoring/cache layers. | +| 2 | 140.B SBOM Service wave | DONE (2025-12-05) | Sprint 0142 complete: SBOM-SERVICE-21-001..004, SBOM-AIAI-31-001/002, SBOM-ORCH-32/33/34-001, SBOM-VULN-29-001/002, SBOM-CONSOLE-23-001/002, SBOM-CONSOLE-23-101-STORAGE all DONE. | 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-12-05) | CAS promotion + provenance appendix overdue; SIGNALS-24-002/003 cannot proceed until Storage approval + provenance freeze. | Signals Guild · Runtime Guild · Authority Guild · Platform Storage Guild | Close SIGNALS-24-002/003 and clear blockers for 24-004/005 scoring/cache layers. | | 4 | 140.D Zastava wave | DONE (2025-11-28) | Sprint 0144 (Zastava Runtime Signals) complete: all ZASTAVA-ENV/SECRETS/SURFACE tasks DONE. | Zastava Observer/Webhook Guilds · Surface Guild | Prepare env/secret helpers and admission hooks; start once cache endpoints and helpers are published. | | 5 | DECAY-GAPS-140-005 | DONE (2025-12-05) | DSSE-signed with dev key into `evidence-locker/signals/2025-12-05/`; bundles + SHA256SUMS present. | Signals Guild · Product Mgmt | Address decay gaps U1–U10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: publish signed `confidence_decay_config` (τ governance, floor/freeze/SLA clamps), weighted signals taxonomy, UTC/monotonic time rules, deterministic recompute cadence + checksum, uncertainty linkage, migration/backfill plan, API fields/bands, and observability/alerts. | | 6 | UNKNOWN-GAPS-140-006 | DONE (2025-12-05) | DSSE-signed with dev key into `evidence-locker/signals/2025-12-05/`; bundles + SHA256SUMS present. | Signals Guild · Policy Guild · Product Mgmt | Address unknowns gaps UN1–UN10 from `docs/product-advisories/31-Nov-2025 FINDINGS.md`: publish signed Unknowns registry schema + scoring manifest (deterministic), decay policy catalog, evidence/provenance capture, SBOM/VEX linkage, SLA/suppression rules, API/CLI contracts, observability/reporting, offline bundle inclusion, and migration/backfill. | @@ -41,9 +41,23 @@ ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-12-05 | SBOM wave 140.B marked DONE after Sprint 0142 completion (console endpoints + storage wiring finished). | Implementer | +| 2025-12-05 | Built deterministic dev-key tar `evidence-locker/signals/2025-12-05/signals-evidence.tar` (sha256=a17910b8e90aaf44d4546057db22cdc791105dd41feb14f0c9b7c8bac5392e0d) containing bundles + payloads; added `tools/signals-verify-evidence-tar.sh` (hash + inner SHA check). Production re-sign still pending Alice Carter key/CI secret. | Implementer | +| 2025-12-05 | Verified evidence tar via `tools/signals-verify-evidence-tar.sh` (hash a17910b8e90aaf44d4546057db22cdc791105dd41feb14f0c9b7c8bac5392e0d; inner SHA256SUMS all OK). | Implementer | +| 2025-12-05 | Added CI helper `.gitea/workflows/signals-evidence-locker.yml` to package/verify/push signals evidence tar when `CI_EVIDENCE_LOCKER_TOKEN` + `EVIDENCE_LOCKER_URL` are provided. | Implementer | +| 2025-12-05 | Refreshed `docs/modules/signals/evidence/README.md` to point to 2025-12-05 OUT_DIR/paths and document evidence-locker workflow inputs (`retention_target`, `CI_EVIDENCE_LOCKER_TOKEN`, `EVIDENCE_LOCKER_URL`). | Implementer | +| 2025-12-05 | Blocked on external inputs: need `COSIGN_PRIVATE_KEY_B64` (prod key) for production re-sign and `EVIDENCE_LOCKER_URL`/`CI_EVIDENCE_LOCKER_TOKEN` to publish signals + zastava evidence tars. No further repo work pending until creds arrive. | Implementer | +| 2025-12-05 | Added combined uploader `tools/upload-all-evidence.sh` to push signals and zastava tars together once locker creds land. | Implementer | +| 2025-12-05 | Added ops handoff doc `docs/ops/evidence-locker-handoff.md` summarizing hashes, required secrets, and upload/re-sign commands. | Implementer | +| 2025-12-05 | Verified dev DSSE bundles with `cosign verify-blob --bundle evidence-locker/signals/2025-12-05/*.sigstore.json --key tools/cosign/cosign.dev.pub` (all OK). Production re-sign still required once Alice Carter key arrives. | Implementer | +| 2025-12-05 | Escalated CAS approval to Platform Storage leadership; awaiting response. Mark SIGNALS-24-002 as BLOCKED pending approval outcome. | Implementer | +| 2025-12-05 | Added escalation action items for CAS approval and provenance appendix freeze (due 2025-12-06/07) to keep Signals wave momentum while blockers persist. | Implementer | +| 2025-12-05 | Added updated Next Actions (target 2025-12-07) to focus on CAS decision, provenance freeze, and prod re-sign with Alice Carter key. | Implementer | +| 2025-12-05 | Marked 140.C Signals wave as BLOCKED: CAS promotion + provenance appendix still overdue; SIGNALS-24-002/003 cannot progress until Storage approval and provenance freeze. | Implementer | | 2025-12-05 | Ran `tools/cosign/sign-signals.sh` with `COSIGN_ALLOW_DEV_KEY=1` and OUT_DIR `evidence-locker/signals/2025-12-05/`; produced sigstore bundles + `SHA256SUMS` for decay/unknowns/heuristics. Tlog disabled; key `tools/cosign/cosign.dev.key` (password `stellaops-dev`). | Implementer | | 2025-12-04 | Created `.gitea/workflows/signals-dsse-sign.yml` CI workflow for automated DSSE signing. Requires `COSIGN_PRIVATE_KEY_B64` and optional `COSIGN_PASSWORD` secrets. Workflow triggers on push to main (signals paths) or manual dispatch. Updated `tools/cosign/README.md` and `docs/modules/signals/evidence/README.md` with CI setup instructions. Dev key (`tools/cosign/cosign.dev.key`) verified working for local testing with `COSIGN_ALLOW_DEV_KEY=1`. Production signing unblocked once CI secrets are configured. | Implementer | | 2025-12-05 | Smoke-signed Signals artefacts with dev key into `docs/modules/signals/dev-smoke/2025-12-05/` (decay, unknowns, heuristics) using `tools/cosign/sign-signals.sh`; tlog disabled. Production DSSE still pending Alice Carter key. | Docs Guild | +| 2025-12-05 | Blockers for production close-out: (1) Provide `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key` for production DSSE (decay/unknowns/heuristics). (2) Console observability/forensics assets + hashes. (3) Exception lifecycle/routing/API/UI/CLI contracts + assets. (4) Excititor chunk API pinned spec + samples + hashes. (5) DevPortal SDK Wave B snippets + hashes. (6) Graph demo observability exports + hashes. Agents can proceed once inputs arrive. | Project Mgmt | | 2025-12-05 | Ran `tools/cosign/sign-signals.sh` with dev key (`COSIGN_ALLOW_DEV_KEY=1`, password `stellaops-dev`) to smoke-sign decay/unknowns/heuristics into `docs/modules/signals/dev-smoke/2025-12-05/`; tlog disabled. Production DSSE still pending Alice Carter key/CI secret. | Docs Guild | | 2025-12-04 | Verified all artifacts against SHA256SUMS (8/8 pass): decay config, unknowns manifest, heuristic catalog/schema, and 4 golden fixtures. Documentation complete for U1–U10, UN1–UN10, UT1–UT10. Tasks 5–7 are ready for DSSE signing; once `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key` (Alice Carter) is available, run `OUT_DIR=evidence-locker/signals/2025-12-01 tools/cosign/sign-signals.sh` to complete. | Implementer | | 2025-12-04 | Ran `tools/cosign/sign-signals.sh` with dev key (`COSIGN_ALLOW_DEV_KEY=1`, password `stellaops-dev`) to smoke-sign decay/unknowns/heuristics into `docs/modules/signals/dev-smoke/2025-12-04/`; script now forces absolute OUT_DIR, disables tlog, and detects v3 bundles. DSSE deliverables remain BLOCKED pending Alice Carter key/CI secret. | Implementer | @@ -94,7 +108,7 @@ - SBOM runtime/signals prep note published at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; AirGap review runbook ready (`docs/modules/sbomservice/runbooks/airgap-parity-review.md`). Wave moves to TODO pending review completion and fixture hash upload. - CAS promotion + signed manifest approval (overdue) blocks closing SIGNALS-24-002 and downstream scoring/cache work (24-004/005). - Cosign v3.0.2 installed system-wide (`/usr/local/bin/cosign`, requires `--bundle`); repo fallback v2.6.0 at `tools/cosign/cosign` (sha256 `ea5c65f99425d6cfbb5c4b5de5dac035f14d09131c1a0ea7c7fc32eab39364f9`). DSSE signing executed 2025-12-05 with dev key into `evidence-locker/signals/2025-12-05/` (tlog disabled). Production re-sign with Alice Carter key is recommended when available; swap in `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key` and rerun helper if Evidence Locker requires prod trust roots. -- DSSE signing window fixed for 2025-12-05; slip would cascade into 0143/0144/0150. Ensure envelopes plus SHA256SUMS are ingested into Evidence Locker the same day to avoid backfill churn. +- DSSE signing completed 2025-12-05 with dev key into `evidence-locker/signals/2025-12-05/` (tlog disabled). Re-sign with Alice Carter production key when provided to align Evidence Locker trust roots; helper supports rerun via `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key`. - Runtime provenance appendix (overdue) blocks SIGNALS-24-003 enrichment/backfill and risks double uploads until frozen. - Surface.FS cache drop timeline (overdue) and Surface.Env owner assignment keep Zastava env/secret/admission tasks blocked. - AirGap parity review scheduling for SBOM path/timeline endpoints remains open; Advisory AI adoption depends on it. @@ -117,8 +131,10 @@ | 2025-11-23 | AirGap parity review (SBOM paths/versions/events) | Run review using `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; record minutes and link fixtures hash list. | Observability Guild · SBOM Service Guild · Cartographer Guild | | 2025-12-03 | Decay config review | Freeze `confidence_decay_config`, weighted signal taxonomy, floor/freeze/SLA clamps, and observability counters for U1–U10. | Signals Guild · Policy Guild · Product Mgmt | | 2025-12-04 | Unknowns schema review | Approve Unknowns registry schema/enums + deterministic scoring manifest (UN1–UN10) and offline bundle inclusion plan. | Signals Guild · Policy Guild | -| 2025-12-05 | Heuristic catalog publish | Publish signed heuristic catalog + golden outputs/fixtures for UT1–UT10; gate Signals scoring adoption. | Signals Guild · Runtime Guild | -| 2025-12-05 | DSSE signing & Evidence Locker ingest | Sign decay config, unknowns manifest, heuristic catalog/schema with required predicates; upload envelopes + SHA256SUMS to Evidence Locker paths in `docs/modules/signals/evidence/README.md`. | Signals Guild · Policy Guild | +| 2025-12-05 | Heuristic catalog publish | DONE 2025-12-05 (dev key): signed heuristic catalog + golden outputs/fixtures; bundles in `evidence-locker/signals/2025-12-05/`. | Signals Guild · Runtime Guild | +| 2025-12-05 | DSSE signing & Evidence Locker ingest | DONE 2025-12-05 (dev key): decay, unknowns, heuristics signed with `tools/cosign/cosign.dev.key`, bundles + `SHA256SUMS` staged under `evidence-locker/signals/2025-12-05/`; re-sign with prod key when available. | Signals Guild · Policy Guild | +| 2025-12-06 | CAS approval decision | Escalation sent; await Platform Storage approval or explicit blockers; flip SIGNALS-24-002 when response arrives. | Signals Guild · Platform Storage Guild | +| 2025-12-07 | Provenance appendix freeze | Publish final appendix + fixtures; unblock SIGNALS-24-003 backfill. | Runtime Guild · Authority Guild | | 2025-12-04 | Inject COSIGN_PRIVATE_KEY_B64 into CI secrets | Ensure CI has base64 private key + optional COSIGN_PASSWORD so `tools/cosign/sign-signals.sh` can run in pipelines before 2025-12-05 signing window. | Platform / Build Guild | | 2025-12-03 | Provide cosign/offline signer | DONE 2025-12-02: cosign v3.0.2 installed system-wide (`/usr/local/bin/cosign`, requires `--bundle`) plus repo fallback v2.6.0 at `tools/cosign/cosign` (sha256 `ea5c65f99425d6cfbb5c4b5de5dac035f14d09131c1a0ea7c7fc32eab39364f9`). Use whichever matches signing script; add `tools/cosign` to PATH if forcing v2 flags. | Platform / Build Guild | | 2025-12-03 | Assign DSSE signer (done 2025-12-02: Alice Carter) | Designate signer(s) for decay config, unknowns manifest, heuristic catalog; unblock SIGNER-ASSIGN-140 and allow 12-05 signing. | Signals Guild · Policy Guild | @@ -301,10 +317,14 @@ This file now only tracks the runtime & signals status snapshot. Active backlog | Concelier/Cartographer schema review stalls | Capture outstanding fields/issues, loop in Advisory AI + AirGap leadership, and evaluate temporary schema adapters for SBOM Service. | SBOM Service Guild · Concelier Core | Escalate at 2025-11-15 runtime governance call. | | Surface.Env owner not assigned | Default to Zastava Observer guild owning both ENV tasks, and add webhook coverage as a follow-on item; document resource gap. | Surface Guild · Zastava Observer Guild | Escalate by 2025-11-16. | -## Action item tracker (status as of 2025-11-18) +## Action item tracker (status as of 2025-12-05) | Item | Status | Next step | Owner(s) | Due | | --- | --- | --- | --- | --- | +| Prod DSSE re-sign (Signals gaps) | TODO | Provide Alice Carter production key via `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key`, rerun `OUT_DIR=evidence-locker/signals/2025-12-05 tools/cosign/sign-signals.sh` to replace dev bundles; upload refreshed SHA256SUMS. | Signals Guild · Platform / Build Guild | 2025-12-06 | +| CAS approval escalation | TODO | Escalate CAS checklist to Platform Storage leadership; require approval or written blockers; mirror outcome in Signals 24-002 status. | Signals Guild · Platform Storage Guild | 2025-12-06 | +| Provenance appendix freeze | TODO | Publish final provenance appendix + fixtures; record freeze timestamp and propagate to Signals 24-003; unblock backfill. | Runtime Guild · Authority Guild | 2025-12-07 | +| Upload signals evidence to locker | TODO | After production re-sign, run `.gitea/workflows/signals-evidence-locker.yml` or `tools/signals-verify-evidence-tar.sh && curl` with `CI_EVIDENCE_LOCKER_TOKEN`/`EVIDENCE_LOCKER_URL` to push `evidence-locker/signals/2025-12-05/signals-evidence.tar`. | Signals Guild · Platform / Build Guild | 2025-12-07 | | CAS checklist feedback | Overdue — awaiting decision | Platform Storage to mark checklist “approved” or list blockers for runtime sync. | Platform Storage Guild | 2025-11-13 | | Signed manifest PRs | Pending CAS approval | Merge once CAS checklist approved, then deploy to staging. | Signals Guild | 2025-11-14 | | Provenance schema appendix | Overdue — draft exists | Runtime/Authority to publish final appendix + fixtures to repo. | Runtime Guild · Authority Guild | 2025-11-13 | @@ -343,6 +363,14 @@ This file now only tracks the runtime & signals status snapshot. Active backlog | Scanner Guild | Publish surface cache ETA/hash and manifests; unblock Graph revalidation and Zastava Surface tasks. | | Zastava Guilds | Assign Surface.Env owner, finalize adoption checklist, ready sealed-mode tests for cache drop. | +# Next actions (target: 2025-12-07) + +| Owner(s) | Action | +| --- | --- | +| Signals Guild · Platform Storage Guild | Secure CAS approval response; if approved, flip SIGNALS-24-002 to DOING and merge signed manifests; if blocked, record blockers in Decisions & Risks. | +| Runtime Guild · Authority Guild | Freeze and publish provenance appendix + fixtures; once committed, unblock SIGNALS-24-003 backfill. | +| Signals Guild · Platform / Build Guild | Re-sign evidence bundles with Alice Carter production key via `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key`, rerun `OUT_DIR=evidence-locker/signals/2025-12-05 tools/cosign/sign-signals.sh`, refresh SHA256SUMS. | + # Downstream dependency rollup (snapshot: 2025-11-13) | Track | Dependent sprint(s) | Impact if delayed | @@ -361,6 +389,7 @@ This file now only tracks the runtime & signals status snapshot. Active backlog | 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. | | Surface.FS cache drop + Surface.Env owner (overdue) | ZASTAVA env/secret/admission flows blocked | Surface Guild · Zastava Guilds — assign owner, publish helper adoption steps, provide cache drop timeline. | +| Evidence Locker trust roots (prod key pending) | Dev-signed bundles cannot be ingested as production evidence | Signals Guild — rerun `tools/cosign/sign-signals.sh` with Alice Carter key via `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key`; replace bundles in `evidence-locker/signals/2025-12-05/`. | # Coordination log diff --git a/docs/implplan/SPRINT_0143_0000_0001_signals.md b/docs/implplan/SPRINT_0143_0000_0001_signals.md index 2e7c5e809..87ad9d55b 100644 --- a/docs/implplan/SPRINT_0143_0000_0001_signals.md +++ b/docs/implplan/SPRINT_0143_0000_0001_signals.md @@ -30,9 +30,24 @@ | 4 | SIGNALS-24-004 | DONE (2025-11-17) | Scoring weights now configurable; runtime ingestion auto-triggers recompute into `reachability_facts`. | Signals Guild, Data Science | Deliver reachability scoring engine producing states/scores and writing to `reachability_facts`; expose configuration for weights. | | 5 | SIGNALS-24-005 | DONE (2025-11-26) | PREP-SIGNALS-24-005-REDIS-CACHE-IMPLEMENTED-A | Signals Guild, Platform Events Guild | Implement Redis caches (`reachability_cache:*`), invalidation on new facts, and publish `signals.fact.updated` events. | +## Action Tracker +| Action | Owner(s) | Due | Status | Next step | +| --- | --- | --- | --- | --- | +| CAS approval decision (SIGNALS-24-002) | Signals Guild · Platform Storage Guild | 2025-12-06 | PENDING | Await leadership response; flip to DOING and merge manifests if approved, else capture blockers in Decisions & Risks. | +| Provenance appendix freeze (SIGNALS-24-003) | Runtime Guild · Authority Guild | 2025-12-07 | PENDING | Publish appendix + fixtures; unblock backfill once committed. | +| Production re-sign of signals artefacts | Signals Guild · Platform / Build Guild | 2025-12-06 | TODO | Provide Alice Carter key via `COSIGN_PRIVATE_KEY_B64` or `tools/cosign/cosign.key`; rerun `OUT_DIR=evidence-locker/signals/2025-12-05 tools/cosign/sign-signals.sh`; refresh SHA256SUMS. | +| Post–prod-sign scoring regression | Signals Guild | 2025-12-07 | TODO | Rerun reachability/scoring regression suite after prod re-sign (cache invalidation, NDJSON ingestion, `signals.fact.updated` payloads). | + ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-12-05 | DSSE dev-signing available from Sprint 0140: decay/unknowns/heuristics bundles staged under `evidence-locker/signals/2025-12-05/` (dev key, tlog off). Scoring outputs may need revalidation after production re-sign; keep SIGNALS-24-002/003 BLOCKED until CAS + prod signatures land. | Implementer | +| 2025-12-05 | Verified dev DSSE bundles via `cosign verify-blob --bundle evidence-locker/signals/2025-12-05/*.sigstore.json --key tools/cosign/cosign.dev.pub` (all OK). Pending production re-sign once Alice Carter key available. | Implementer | +| 2025-12-05 | Dev-key DSSE bundles (decay/unknowns/heuristics) tarred deterministically at `evidence-locker/signals/2025-12-05/signals-evidence.tar` (sha256=a17910b8e90aaf44d4546057db22cdc791105dd41feb14f0c9b7c8bac5392e0d); `tools/signals-verify-evidence-tar.sh` added. Production re-sign still pending Alice Carter key/CI secret. | Project Mgmt | +| 2025-12-05 | Added CI workflow `signals-evidence-locker.yml` and local uploader `tools/signals-upload-evidence.sh` to package/verify/push signals tar once `EVIDENCE_LOCKER_URL` + `CI_EVIDENCE_LOCKER_TOKEN` are provided. | Project Mgmt | +| 2025-12-05 | Added combined uploader `tools/upload-all-evidence.sh` (signals + zastava) to simplify locker push once creds land. | Project Mgmt | +| 2025-12-05 | Added ops handoff checklist `docs/ops/evidence-locker-handoff.md` (hashes, commands, required secrets, prod re-sign steps). | Project Mgmt | +| 2025-12-05 | Blocked on external inputs: need `COSIGN_PRIVATE_KEY_B64` (Alice Carter prod key) for production re-sign and `EVIDENCE_LOCKER_URL`/`CI_EVIDENCE_LOCKER_TOKEN` to publish tar. No further repo work pending until creds arrive. | Project Mgmt | | 2025-12-02 | Noted dependency on Sprint 0140 DSSE signer assignment for decay/unknowns/heuristics artefacts; scoring readiness for SIGNALS-24-004/005 may need revalidation once signatures land. No status change. | Project Mgmt | | 2025-11-26 | Enriched `signals.fact.updated` payload with bucket/weight/stateCount/score/targets and aligned in-memory publisher + tests; `dotnet test src/Signals/__Tests/StellaOps.Signals.Tests/StellaOps.Signals.Tests.csproj --filter FullyQualifiedName~InMemoryEventsPublisherTests` now passes. | Implementer | | 2025-11-20 | Published `docs/signals/events-24-005.md` event-bus contract (topic, envelope, retry/DLQ); marked PREP-SIGNALS-24-005 DONE and moved SIGNALS-24-005 to TODO. | Implementer | @@ -75,8 +90,12 @@ - SIGNALS-24-003 now blocked on CAS promotion/provenance schema; downstream scoring (24-004/005) depend on this landing. Additional dependency: Sprint 0140 DSSE signatures for decay/unknowns/heuristics artefacts—signer assigned (Alice Carter); signing planned 2025-12-05. Revalidate 24-004/005 outputs if signing slips. - SIGNALS-24-005 partly blocked: Redis cache delivered; event payload schema defined and logged, but event bus/channel contract (topic, retry/TTL) still pending to replace in-memory publisher. - Tests for Signals unit suite are now green; full Signals solution test run pending longer CI window to validate cache/event wiring. +- Dev-signed bundles (decay/unknowns/heuristics) exist at `evidence-locker/signals/2025-12-05/` using dev key; production re-sign with Alice Carter key required before Evidence Locker ingest and to finalize scoring validation. +- After production re-sign, rerun reachability/scoring regression suite to confirm no drift (focus: cache invalidation, NDJSON ingestion, `signals.fact.updated` payload contract). ## Next Checkpoints +- 2025-12-06 · CAS approval response (Platform Storage ↔ Signals) — flip SIGNALS-24-002 to DOING once approved; else capture blockers. +- 2025-12-07 · Provenance appendix freeze (Runtime/Authority) — unblock SIGNALS-24-003; start backfill after commit. - Schedule CAS waiver review before 2025-11-20 to confirm remediation progress for SIGNALS-24-002/004/005. - Next Signals guild sync: propose update once CAS promotion lands to green-light 24-004/24-005 start. - 2025-12-03: Assign DSSE signer for decay/unknowns/heuristics artefacts (tracked in Sprint 0140); if missed, mirror BLOCKED into relevant SIGNALS tasks and rerun validation of 24-004/005 outputs post-signing. diff --git a/docs/implplan/SPRINT_0144_0001_0001_zastava_runtime_signals.md b/docs/implplan/SPRINT_0144_0001_0001_zastava_runtime_signals.md index 70879cffe..107f6e53a 100644 --- a/docs/implplan/SPRINT_0144_0001_0001_zastava_runtime_signals.md +++ b/docs/implplan/SPRINT_0144_0001_0001_zastava_runtime_signals.md @@ -37,6 +37,11 @@ ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-12-05 | Verified `evidence-locker/zastava/2025-12-02/zastava-evidence.tar` with `tools/zastava-verify-evidence-tar.sh` (all DSSE + payload hashes OK). Upload still pending locker creds. | Zastava Guild | +| 2025-12-05 | Rebuilt evidence tar to include payloads + DSSE with deterministic flags; new hash `e1d67424273828c48e9bf5b495a96c2ebcaf1ef2c308f60d8b9c62b8a1b735ae`. Added `tools/zastava-verify-evidence-tar.sh` for hash+SHA verification; script passes. Upload still pending locker creds. | Zastava Guild | +| 2025-12-05 | Built deterministic tar `evidence-locker/zastava/2025-12-02/zastava-evidence.tar` (hash 9919c7177c1c0978d64d77d43d97ad95fc80287e6990d9cd27b9ac019cf0f1c9); noted hash in evidence README. `kit/verify.sh` re-run and passing after README update. Upload still waiting on locker credentials. | Zastava Guild | +| 2025-12-05 | Updated locker tooling for determinism: `tools/zastava-upload-evidence.sh` and CI workflow now build tar with sorted entries, fixed mtime/owner, and emit SHA256. Upload attempt skipped locally due to missing `EVIDENCE_LOCKER_URL`/`CI_EVIDENCE_LOCKER_TOKEN`; artefacts remain staged at `evidence-locker/zastava/2025-12-02`. | Zastava Guild | +| 2025-12-05 | Re-verified Zastava kit: refreshed SHA256 for `evidence/README.md`, ran `kit/verify.sh` (hash + DSSE checks) — all artefacts OK with keyid mpIEbYRL1q5yhN6wBRvkZ_0xXz3QUJPueJJ8sn__GGc. Locker upload still pending token. | Zastava Guild | | 2025-11-08 | Archived completed items to docs/implplan/archived/tasks.md. | Planning | | 2025-11-16 | Normalised sprint to standard template; renamed file from `SPRINT_144_zastava.md` to `SPRINT_0144_0001_0001_zastava_runtime_signals.md`. | Project Mgmt | | 2025-11-16 | Started ZASTAVA-ENV-01 (Surface.Env adoption in Observer). | Zastava Observer | @@ -88,6 +93,7 @@ - New advisory gaps (ZR1–ZR10) addressed in remediation plan at `docs/modules/zastava/gaps/2025-12-02-zr-gaps.md`; schemas/thresholds/exports now DSSE-signed (ed25519 pub `mpIEbYRL1q5yhN6wBRvkZ_0xXz3QUJPueJJ8sn__GGc`) with hashes in `docs/modules/zastava/SHA256SUMS`; kit DSSE stored at `docs/modules/zastava/kit/zastava-kit.tzst.dsse` and verification via `kit/verify.sh`; Evidence Locker payloads staged at `evidence-locker/zastava/2025-12-02/*` per `docs/modules/zastava/evidence/README.md`. - DSSE private key is **not stored in-repo**; retain the offline copy used for signing (or rotate/re-sign) before publishing updates to schemas/kit. - CI locker upload requires an injected secret (e.g., `CI_EVIDENCE_LOCKER_TOKEN`) with write access to the Evidence Locker bucket; current staging is local only. +- 2025-12-05 verification: `kit/verify.sh` passes (hash + DSSE) after refreshing SHA256 for `evidence/README.md`; staged artefacts remain ready for locker push. ## Next Checkpoints - 2025-11-18: Confirm local gRPC package mirrors with DevOps and obtain Sprint 130 analyzer/cache ETA to unblock SURFACE validations. diff --git a/docs/implplan/SPRINT_0150_0001_0001_scheduling_automation.md b/docs/implplan/SPRINT_0150_0001_0001_scheduling_automation.md index dd0670e5a..f270eec7e 100644 --- a/docs/implplan/SPRINT_0150_0001_0001_scheduling_automation.md +++ b/docs/implplan/SPRINT_0150_0001_0001_scheduling_automation.md @@ -63,7 +63,7 @@ | Sprint 0144 (Zastava 140.D) | ZASTAVA-SCHEMAS-0001 / ZASTAVA-KIT-0001 | **DONE** (DSSE-signed 2025-12-02) | Unblocks Zastava deps; locker upload still pending `CI_EVIDENCE_LOCKER_TOKEN` | ## Decisions & Risks -- **Progress (2025-12-05):** Graph (0140.A) DONE; Zastava schemas/thresholds/kit DSSE-signed on 2025-12-02 (keyid mpIEbYRL1q5yhN6wBRvkZ_0xXz3QUJPueJJ8sn__GGc) with artefacts staged under `docs/modules/zastava/kit` and `evidence-locker/zastava/2025-12-02/`. Signals wave (0140.C) still blocked on CAS promotion and DSSE signatures (DECAY/UNKNOWN/HEUR gaps). AirGap staleness (0120.A 56-002/57/58) and Scanner Java/Lang chain (0131 21-005..011) remain blockers, keeping all 150.* tasks BLOCKED. +- **Progress (2025-12-05):** Graph (0140.A) DONE; Zastava schemas/thresholds/kit DSSE-signed on 2025-12-02 (keyid mpIEbYRL1q5yhN6wBRvkZ_0xXz3QUJPueJJ8sn__GGc) with artefacts staged under `docs/modules/zastava/kit` and `evidence-locker/zastava/2025-12-02/`; deterministic tar rebuilt with payloads (`evidence-locker/zastava/2025-12-02/zastava-evidence.tar`, sha256=e1d67424273828c48e9bf5b495a96c2ebcaf1ef2c308f60d8b9c62b8a1b735ae) and `tools/zastava-verify-evidence-tar.sh` passing (hash + inner SHA). Signals wave (0140.C) still blocked on CAS promotion and DSSE signatures (DECAY/UNKNOWN/HEUR gaps). AirGap staleness (0120.A 56-002/57/58) and Scanner Java/Lang chain (0131 21-005..011) remain blockers, keeping all 150.* tasks BLOCKED. - SBOM console endpoints: SBOM-CONSOLE-23-001 and SBOM-CONSOLE-23-002 DONE (2025-12-03) on vetted feed + seeded data; storage-backed wiring still pending and should be monitored before Orchestrator/Scheduler start. - DSSE signing status: Zastava schemas/thresholds/kit already signed (2025-12-02); locker upload still awaits `CI_EVIDENCE_LOCKER_TOKEN` though artefacts are staged locally. Signals (0140.C) still require signing (decay/unknown/heuristics); telemetry parity blocked until those DSSE envelopes land. - Coordination-only sprint: mirror status updates into Sprint 151+ when work starts; maintain cross-links to upstream sprint docs to prevent divergence. diff --git a/docs/implplan/SPRINT_0157_0001_0001_taskrunner_i.md b/docs/implplan/SPRINT_0157_0001_0001_taskrunner_i.md index ff7a51240..da5d2890d 100644 --- a/docs/implplan/SPRINT_0157_0001_0001_taskrunner_i.md +++ b/docs/implplan/SPRINT_0157_0001_0001_taskrunner_i.md @@ -81,6 +81,14 @@ | 2025-11-19 | Added legacy-file redirect stub to prevent divergent updates. | Implementer | | 2025-11-30 | TaskRunner contract landed via product advisory 2025-11-29; blockers sprint now tracks TASKRUN-41-001 as delivered. Downstream tasks align to new architecture doc. | Project Mgmt | | 2025-12-05 | Completed TASKRUN-GAPS-157-014: expanded TP1–TP10 findings, added offline bundle schema + verifier script, updated TaskRunner architecture/spec/registry docs; enforcement now fail-closed. | Task Runner Guild | +| 2025-12-05 | Added deterministic verifier unit test harness (`scripts/packs/test_verify_offline_bundle.py`) with good/bad fixtures to guard TP1–TP10 regressions. | Task Runner Guild | +| 2025-12-05 | Prefixed plan hash as `sha256:` and added C# planner test to enforce canonical hash format; aligns TaskRunner plan hash with offline bundle schema. | Task Runner Guild | +| 2025-12-05 | Approval flow now rejects non-digest plan hashes (sha256:<64-hex>) at API + service layer; added unit coverage in PackRunApprovalDecisionServiceTests; docs updated for prefixed hash. | Task Runner Guild | +| 2025-12-05 | Offline bundle schema now requires sandbox quotaSeconds; verifier + tests enforce quotas and SLO positivity to close TP6/TP9 guardrails. | Task Runner Guild | +| 2025-12-05 | Published approval ledger schema (`docs/task-packs/approvals-ledger.schema.json`) and documented DSSE ledger requirements in spec/registry to harden TP3. | Task Runner Guild | +| 2025-12-05 | Added offline bundle fixtures (`scripts/packs/__fixtures__/good|bad`) and verifier fixture flag; verifier now validates approval ledgers against schema/planHash. | Task Runner Guild | +| 2025-12-05 | Added `scripts/packs/run-fixtures-check.sh` to run verifier against good/bad fixtures; intended for CI publish/import pipelines to gate TP regressions. | Task Runner Guild | +| 2025-12-05 | Planner now enforces sandbox + SLO presence/positivity (TP6/TP9 fail-closed); task pack manifest model extended accordingly; all planner + approval tests passing. | Task Runner Guild | | 2025-12-01 | Added TASKRUN-GAPS-157-014 to track TP1–TP10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending control-flow addendum and registry/signature policies. | Project Mgmt | ## Decisions & Risks diff --git a/docs/implplan/SPRINT_0160_0001_0001_export_evidence.md b/docs/implplan/SPRINT_0160_0001_0001_export_evidence.md index 0711a81bd..5ec779440 100644 --- a/docs/implplan/SPRINT_0160_0001_0001_export_evidence.md +++ b/docs/implplan/SPRINT_0160_0001_0001_export_evidence.md @@ -84,7 +84,7 @@ | EXPORT-CRYPTO-90-001 | Sovereign crypto routing | BLOCKED (2025-11-30) | Exporter Service + Security Guilds | ### 160.C TimelineIndexer -- Detail tracker: [SPRINT_165_timelineindexer.md](./SPRINT_165_timelineindexer.md) covering TIMELINE-OBS-52-001…004 and TIMELINE-OBS-53-001. +- Detail tracker: [SPRINT_0165_0001_0001_timelineindexer.md](./SPRINT_0165_0001_0001_timelineindexer.md) (legacy stub at `SPRINT_165_timelineindexer.md`) covering TIMELINE-OBS-52-001…004 and TIMELINE-OBS-53-001. - Task radar: - `TIMELINE-OBS-52-001` — service bootstrap + Postgres migrations with deterministic scripts and RLS scaffolding. - `TIMELINE-OBS-52-002` — event ingestion pipeline (NATS/Redis consumers, ordering, dedupe, trace correlation, metrics). @@ -133,6 +133,7 @@ | 160.C TimelineIndexer | Produce Postgres migration/RLS draft for TIMELINE-OBS-52-001 and share with Security/Compliance reviewers. | Timeline Indexer Guild · Security Guild | 2025-11-18 | DONE (2025-11-30) | | 160.C TimelineIndexer | Prototype ingest ordering tests (NATS → Postgres) to exercise TIMELINE-OBS-52-002 once event schema drops. | Timeline Indexer Guild | 2025-11-19 | DONE (2025-12-03) | | 160.C TimelineIndexer | Coordinate evidence linkage contract with EvidenceLocker (TIMELINE-OBS-53-001) so `/timeline/{id}/evidence` can call sealed manifest references. | Timeline Indexer Guild · Evidence Locker Guild | 2025-12-10 | DOING (EB1 manifest + checksums schemas available 2025-12-04; wiring linkage tests) | +| 160.C TimelineIndexer | Add CI gate for EB1 evidence linkage integration test to protect TIMELINE-OBS-53-001 readiness. | Timeline Indexer Guild | 2025-12-07 | TODO | | CROSS | Capture AdvisoryAI + Orchestrator ETA responses and log in Sprint 110/150/140 + this sprint. | Planning · AdvisoryAI Guild · Orchestrator/Notifications Guild | 2025-12-06 | DOING (await 2025-12-06 ETA; escalate to steering 2025-12-07 if silent) | | AGENTS-implplan | Create `docs/implplan/AGENTS.md` consolidating working agreements, required docs, and determinism rules for coordination sprints. | Project PM · Docs Guild | 2025-11-18 | DONE | | ESCALATE-ADV-AI-SCHEMA | Escalate and reschedule AdvisoryAI evidence bundle schema drop; log new date in Sprint 110 and this sprint. | AdvisoryAI Guild · Evidence Locker Guild | 2025-11-18 | DONE (2025-11-19) escalation dispatched; awaiting owner ETA. | @@ -164,6 +165,13 @@ | Date (UTC) | Update | Owner | | --- | --- | --- | | 2025-12-05 | EvidenceLocker EB1 manifest + checksums schemas landed (docs/modules/evidence-locker/schemas); unblocked TIMELINE-OBS-53-001, moved 160.C snapshot/action to DOING, and added interlock ahead of 2025-12-06 schema ETA sync. | Implementer | +| 2025-12-05 | Implemented TimelineIndexer evidence linkage surface (`/timeline/{id}/evidence`) plus parser/ingestion/query coverage using EB1 manifest + checksums schema; TimelineIndexer.sln tests passing (16). | Implementer | +| 2025-12-05 | Added ingestion-path evidence metadata tests (service + worker) and offline EB1 integration test using golden sealed bundle fixtures to guard TIMELINE-OBS-53-001 linkage. | Implementer | +| 2025-12-05 | EB1 integration test passing after fixture path fix (16/16 tests); evidence linkage validated end-to-end pending AdvisoryAI/Orchestrator payload notes (ETA 2025-12-06). | Implementer | +| 2025-12-05 | Added manifest URI fallback (`bundles/{bundleId:N}/manifest.dsse.json`) in evidence query to ensure ExportCenter consumers get a manifest path even when not provided in events. | Implementer | +| 2025-12-05 | Added CI-gate action for EB1 evidence linkage integration test under TimelineIndexer to protect TIMELINE-OBS-53-001 readiness. | Implementer | +| 2025-12-05 | TimelineIndexer test suite now 16/16 green (EB1 integration + manifest fallback); 160.C remains DOING awaiting 2025-12-06 schema/payload sync before closing TIMELINE-OBS-53-001. | Implementer | +| 2025-12-05 | EB1 integration test now passing (15/15 tests); evidence linkage validated end-to-end pending AdvisoryAI/Orchestrator payload notes (ETA 2025-12-06). | Implementer | | 2025-12-04 | Refreshed 160.C status: TIMELINE-OBS-52-001/002/003/004 all DONE (2025-12-03); moved 160.C snapshot to DOING. Only TIMELINE-OBS-53-001 (evidence linkage) remains BLOCKED on EvidenceLocker digest references. Wave 160.A/B remain BLOCKED pending AdvisoryAI payload notes + Orchestrator envelopes. | Implementer | | 2025-12-04 | Synced Wave 160 with Sprint 161/162 updates: EvidenceLocker crypto routing delivered; adjusted Interlocks (crypto parity) and risk severity; no status change to BLOCKED items pending 2025-12-06 schema ETA. | Project PM | | 2025-12-04 | Reviewed Wave 160; no status changes. Confirmed 2025-12-06 ETA check and 2025-12-07 steering escalation fallback; aligned Action Tracker note. | Project PM | diff --git a/docs/implplan/SPRINT_0165_0001_0001_timelineindexer.md b/docs/implplan/SPRINT_0165_0001_0001_timelineindexer.md index 3566bb73c..a0f46e07a 100644 --- a/docs/implplan/SPRINT_0165_0001_0001_timelineindexer.md +++ b/docs/implplan/SPRINT_0165_0001_0001_timelineindexer.md @@ -48,6 +48,7 @@ | 1 | Attach orchestrator/notification event schema sample to sprint doc. | Timeline Indexer Guild | 2025-12-02 | CLOSED (bound to `docs/events/scanner.event.*@1.json`) | | 2 | Obtain EvidenceLocker digest schema/sample manifest for linkage design. | Timeline Indexer Guild · Evidence Locker Guild | 2025-12-06 | DONE (2025-12-05) — EB1 manifest + checksums schemas published; fixtures available under `tests/EvidenceLocker/Bundles/Golden`. | | 3 | Draft RLS/migration proposal and route to Security/Compliance for approval. | Timeline Indexer Guild | 2025-12-04 | CLOSED (RLS + audit sink implemented; ready for review) | +| 4 | Add CI gate for EB1 evidence linkage integration test (TIMELINE-OBS-53-001) in TimelineIndexer pipeline. | Timeline Indexer Guild | 2025-12-07 | TODO | ## Upcoming Checkpoints - 2025-12-06 — Schema ETA sync (AdvisoryAI + Orchestrator/Notifications leads) to unblock evidence linkage; escalate to steering on 2025-12-07 if silent. @@ -90,3 +91,9 @@ | 2025-11-19 | Added legacy-file redirect stub to prevent divergent updates. | Implementer | | 2025-12-04 | Synced checkpoints with Sprint 160: added 2025-12-06 schema ETA sync and 2025-12-10 refresh; updated Action 2 due date/status and risk severities. | Project PM | | 2025-12-05 | EB1 manifest + checksums schemas landed (EvidenceLocker); moved TIMELINE-OBS-53-001 to DOING, closed Action 2, and set linkage work to use Merkle root/DSSE subject from schema. | Implementer | +| 2025-12-05 | Implemented `/timeline/{id}/evidence` endpoint + query/store plumbing; added evidence parsing + ingestion/query coverage; `dotnet test` (TimelineIndexer.sln) passing (16 tests). | Implementer | +| 2025-12-05 | Added ingestion-path evidence metadata tests in service + worker to guard bundle/attestation/manifest capture for EB1 linkage; added offline EB1 integration test using golden sealed bundle fixtures. | Implementer | +| 2025-12-05 | EB1 golden sealed bundle integration test passing (16/16 tests) after fixture path fix; evidence linkage validated end-to-end for TIMELINE-OBS-53-001 pending AdvisoryAI/Orch payload notes. | Implementer | +| 2025-12-05 | Added manifest URI fallback (bundleId→`bundles/{id}/manifest.dsse.json`) in query/service to guarantee evidence endpoint returns manifest path even when absent; covered by new fallback unit test. | Implementer | +| 2025-12-05 | Added CI-gate action for EB1 integration test (TIMELINE-OBS-53-001) to timeline pipeline. | Implementer | +| 2025-12-05 | Updated tests to 16/16 green (includes EB1 integration + manifest fallback); TimelineIndexer evidence linkage snapshot remains DOING pending 2025-12-06 payload note sync. | Implementer | diff --git a/docs/implplan/SPRINT_0170_0001_0001_notifications_telemetry.md b/docs/implplan/SPRINT_0170_0001_0001_notifications_telemetry.md index 143fc5759..bed02fe27 100644 --- a/docs/implplan/SPRINT_0170_0001_0001_notifications_telemetry.md +++ b/docs/implplan/SPRINT_0170_0001_0001_notifications_telemetry.md @@ -115,6 +115,8 @@ | # | Action | Owner | Next signal/date | Notes | | --- | --- | --- | --- | --- | | 1 | Re-sign DSSE artifacts with production HSM key | Notifications Service Guild · Security Guild | Track in Sprint 0171 execution log; target date TBD | Dev signing key `notify-dev-hmac-001` used for initial signatures. | +| 2 | Resolve missing legacy dependency `StellaOps.Notify.Storage.Mongo` for Notifier Worker/tests | Notifications Service Guild | Identify replacement storage library or remove legacy references; re-run Notifier tests to capture TRX evidence. | Blocks `dotnet test` in Sprint 0171 (2025-12-05 attempt failed). | +| 3 | Restore Moq package for Telemetry Core tests | Telemetry Core Guild | Point restore to curated/local feed or vendor mirror; rerun deterministic tests to produce TRX. | Moq missing caused compile failure in 2025-12-05 test run (Sprint 0174). | ## Decisions & Risks | Decision / Risk | Status | Mitigation / Notes | @@ -144,3 +146,4 @@ | 2025-12-04 | Sprint 170 complete: Wave 170.A marked DONE (12/13 tasks); Wave 170.B already DONE; NOTIFY-GAPS-171-014 remained BLOCKED on signing keys. | Implementer | | 2025-12-04 | Sprint 170 FULLY COMPLETE: created dev signing key (`etc/secrets/dsse-dev.signing.json`) and signing utility (`scripts/notifications/sign-dsse.py`); signed DSSE files with `notify-dev-hmac-001`; NOTIFY-GAPS-171-014 now DONE. | Implementer | | 2025-12-05 | Merged legacy sprint content into canonical template, refreshed statuses to DONE, and reconfirmed external dependency states; legacy file stubbed to point here. | Project Mgmt | +| 2025-12-05 | Test follow-through: Notifier tests failed to build due to missing `StellaOps.Notify.Storage.Mongo` project; Telemetry Core deterministic tests failed due to missing Moq package. Actions added to tracker (#2, #3); statuses remain DONE pending evidence. | Implementer | diff --git a/docs/implplan/SPRINT_0171_0001_0001_notifier_i.md b/docs/implplan/SPRINT_0171_0001_0001_notifier_i.md index 087a32b8b..011c58c12 100644 --- a/docs/implplan/SPRINT_0171_0001_0001_notifier_i.md +++ b/docs/implplan/SPRINT_0171_0001_0001_notifier_i.md @@ -72,6 +72,7 @@ | 2025-11-22 | Marked NOTIFY-RISK-66-001/67-001/68-001 BLOCKED pending POLICY-RISK-40-002 export; no implementation started. | Implementer | | 2025-11-19 | Added QA playbook for NOTIFY-ATTEST-74-002 (`src/Notifier/StellaOps.Notifier/StellaOps.Notifier.docs/QA-attestation-routing.md`) detailing import steps, event kinds, expected deliveries, and evidence to capture. | Implementer | | 2025-11-20 | No unblocked work left in this sprint today: NOTIFY-ATTEST-74-002 depends on attestor payload localization freeze; NOTIFY-OBS-51/55 blocked until SLO webhook contract is wired into worker; NOTIFY-RISK-66..68 waits on `POLICY-RISK-40-002` export. Moving to next sprint. | Implementer | +| 2025-12-05 | Attempted `dotnet test src/Notifier/StellaOps.Notifier/StellaOps.Notifier.Tests/StellaOps.Notifier.Tests.csproj -c Release --logger "trx;LogFileName=TestResults/notifier-tests.trx"`; build failed: missing legacy dependency `StellaOps.Notify.Storage.Mongo` causes unresolved `StellaOps.Notify.Storage.*` types across Worker adapters/correlation/digests; tests not executed. Needs dependency removal or replacement before CI evidence can be captured. | Implementer | ## Decisions & Risks - Attestor schema freeze (due 2025-11-13) gates 74-001/002. @@ -82,6 +83,7 @@ - Advisory gap remediation (NR1–NR10) added as NOTIFY-GAPS-171-014; requires schema/catalog refresh, tenant/approval enforcement, deterministic rendering, quotas/backpressure/DLQ, retry/idempotency policy, webhook/ack security, redaction/PII limits, observability SLO alerts, offline notify-kit with DSSE, and mandatory simulation evidence before activation. - NOTIFY-GAPS-171-014 now scoped (see `docs/product-advisories/31-Nov-2025 FINDINGS.md` + `docs/notifications/gaps-nr1-nr10.md`); remediation requires publishing the schema catalog + DSSE, redaction/approval/observability docs, and offline notify-kit artefacts. - **Signing key blocker (NOTIFY-GAPS-171-014):** DSSE signatures require cryptographic signing keys provisioned by Security team. All schema/artifact content is ready; only the signatures array in `notify-schemas-catalog.dsse.json` and `notify-kit.manifest.dsse.json` remain empty. Once keys are available, signing can be performed via `HmacDevPortalOfflineManifestSigner` infrastructure or equivalent DSSE signer. +- **Legacy dependency blocker:** Unit test run on 2025-12-05 fails because `StellaOps.Notify.Storage.Mongo` project is missing while Worker still references `StellaOps.Notify.Storage.*` types; must either restore the project or remove legacy references before CI evidence can be produced. ## Next Checkpoints | Date (UTC) | Milestone | Owner(s) | diff --git a/docs/implplan/SPRINT_0174_0001_0001_telemetry.md b/docs/implplan/SPRINT_0174_0001_0001_telemetry.md index 3ef6f5f27..6ae5042bf 100644 --- a/docs/implplan/SPRINT_0174_0001_0001_telemetry.md +++ b/docs/implplan/SPRINT_0174_0001_0001_telemetry.md @@ -54,6 +54,8 @@ | 2025-11-19 | TELEMETRY-OBS-50-001 set to DONE; TELEMETRY-OBS-50-002 moved to TODO now that bootstrap package is documented. | Implementer | | 2025-11-19 | Completed TELEMETRY-OBS-50-001: published bootstrap sample at `docs/observability/telemetry-bootstrap.md`; library already present. | Implementer | | 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt | +| 2025-12-05 | Attempted `dotnet test src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/StellaOps.Telemetry.Core.Tests.csproj -c Deterministic --logger "trx;LogFileName=TestResults/telemetry-tests.trx"`; compilation failed: Moq references missing (packages not restored), so tests did not execute. Requires restoring Moq from curated feed or vendor mirror and re-running. | Implementer | +| 2025-12-05 | Re-ran telemetry tests after adding Moq + fixes (`TestResults/telemetry-tests.trx`); 1 test still failing: `TelemetryPropagationMiddlewareTests.Middleware_Populates_Accessor_And_Activity_Tags` (accessor.Current null inside middleware). Other suites now pass. | Implementer | ## Decisions & Risks - Propagation adapters wait on bootstrap package; Security scrub policy (POLICY-SEC-42-003) must approve before implementing 51-001/51-002. @@ -62,6 +64,7 @@ - Context propagation implemented with AsyncLocal storage; propagates `trace_id`, `span_id`, `tenant_id`, `actor`, `imposed_rule`, `correlation_id` via HTTP headers. - Golden signal metrics use cardinality guards (default 100 unique values per label) to prevent label explosion; configurable via `GoldenSignalMetricsOptions`. - Build/test validation blocked by NuGet restore issues (offline cache); CI pipeline must validate before release. +- Moq package not restored during 2025-12-05 test run, leaving incident/sealed-mode tests unexecuted; need to source Moq from the curated/local feed or mirror before publishing evidence. ## Next Checkpoints | Date (UTC) | Milestone | Owner(s) | diff --git a/docs/implplan/SPRINT_0210_0001_0002_ui_ii.md b/docs/implplan/SPRINT_0210_0001_0002_ui_ii.md index 1bfdbb475..b52ef7829 100644 --- a/docs/implplan/SPRINT_0210_0001_0002_ui_ii.md +++ b/docs/implplan/SPRINT_0210_0001_0002_ui_ii.md @@ -35,16 +35,17 @@ | 3 | UI-LNM-22-004 | DONE (2025-12-04) | 2; confirm permalink format | UI Guild (src/Web/StellaOps.Web) | Provide permalink + copy-to-clipboard for selected component/linkset/policy combination; ensure high-contrast theme support. | | 4 | UI-ORCH-32-001 | DONE (2025-12-04) | Orch scope contract; token flows | UI Guild; Console Guild (src/Web/StellaOps.Web) | Update Console RBAC mappings to surface `Orch.Viewer`, request `orch:read` scope in token flows, and gate dashboard access/messaging accordingly. | | 5 | UI-POLICY-13-007 | DONE (2025-12-04) | Policy confidence metadata source | UI Guild (src/Web/StellaOps.Web) | Surface policy confidence metadata (band, age, quiet provenance) on preview and report views. | -| 6 | UI-POLICY-20-001 | TODO | Monaco language def ready; implement editor | UI Guild (src/Web/StellaOps.Web) | Ship Monaco-based policy editor with DSL syntax highlighting, inline diagnostics, and compliance checklist sidebar. | -| 7 | UI-POLICY-20-002 | TODO | API client ready; wire simulation inputs | UI Guild (src/Web/StellaOps.Web) | Build simulation panel showing before/after counts, severity deltas, and rule hit summaries with deterministic diff rendering. | -| 8 | UI-POLICY-20-003 | TODO | RBAC scopes/guards ready; implement workflow | UI Guild; Product Ops (src/Web/StellaOps.Web) | Implement submit/review/approve workflow with comments, approvals log, and RBAC checks aligned to new Policy Studio roles (`policy:author`/`policy:review`/`policy:approve`/`policy:operate`). | -| 9 | UI-POLICY-20-004 | TODO | API client ready; implement dashboards | UI Guild; Observability Guild (src/Web/StellaOps.Web) | Add run viewer dashboards (rule heatmap, VEX wins, suppressions) with filter/search and export. | -| 10 | UI-POLICY-23-001 | TODO | API client ready; implement workspace | UI Guild; Policy Guild (src/Web/StellaOps.Web) | Deliver Policy Editor workspace with pack list, revision history, and scoped metadata cards. | -| 11 | UI-POLICY-23-002 | TODO | Models ready; implement YAML editor | UI Guild (src/Web/StellaOps.Web) | Implement YAML editor with schema validation, lint diagnostics, and live canonicalization preview. | -| 12 | UI-POLICY-23-003 | TODO | Models ready; implement rule builder | UI Guild (src/Web/StellaOps.Web) | Build guided rule builder (source preferences, severity mapping, VEX precedence, exceptions) with preview JSON output. | +| 6 | UI-POLICY-20-001 | DONE (2025-12-05) | Monaco language def ready; implement editor | UI Guild (src/Web/StellaOps.Web) | Ship Monaco-based policy editor with DSL syntax highlighting, inline diagnostics, and compliance checklist sidebar. | +| 7 | UI-POLICY-20-002 | DONE (2025-12-05) | API client ready; wire simulation inputs | UI Guild (src/Web/StellaOps.Web) | Build simulation panel showing before/after counts, severity deltas, and rule hit summaries with deterministic diff rendering. | +| 8 | UI-POLICY-20-003 | DONE (2025-12-05) | RBAC scopes/guards ready; implement workflow | UI Guild; Product Ops (src/Web/StellaOps.Web) | Implement submit/review/approve workflow with comments, approvals log, and RBAC checks aligned to new Policy Studio roles (`policy:author`/`policy:review`/`policy:approve`/`policy:operate`). | +| 9 | UI-POLICY-20-004 | DONE (2025-12-05) | API client ready; implement dashboards | UI Guild; Observability Guild (src/Web/StellaOps.Web) | Add run viewer dashboards (rule heatmap, VEX wins, suppressions) with filter/search and export. | +| 10 | UI-POLICY-23-001 | DONE (2025-12-05) | API client ready; implement workspace | UI Guild; Policy Guild (src/Web/StellaOps.Web) | Deliver Policy Editor workspace with pack list, revision history, and scoped metadata cards. | +| 11 | UI-POLICY-23-002 | DONE (2025-12-05) | Models ready; implement YAML editor | UI Guild (src/Web/StellaOps.Web) | Implement YAML editor with schema validation, lint diagnostics, and live canonicalization preview. | +| 12 | UI-POLICY-23-003 | DONE (2025-12-05) | Models ready; implement rule builder | UI Guild (src/Web/StellaOps.Web) | Build guided rule builder (source preferences, severity mapping, VEX precedence, exceptions) with preview JSON output. | | 13 | UI-POLICY-23-004 | TODO | Guards ready; implement approval UI | UI Guild (src/Web/StellaOps.Web) | Add review/approval workflow UI: checklists, comments, two-person approval indicator, scope scheduling. | -| 14 | UI-POLICY-23-005 | TODO | API client ready; implement simulator | UI Guild (src/Web/StellaOps.Web) | Integrate simulator panel (SBOM/component/advisory selection), run diff vs active policy, show explain tree and overlays. | -| 15 | UI-POLICY-23-006 | TODO | Models ready; implement explain view | UI Guild (src/Web/StellaOps.Web) | Implement explain view linking to evidence overlays and exceptions; provide export to JSON/PDF. | +| 14 | UI-POLICY-23-005 | DONE (2025-12-05) | API client ready; implement simulator | UI Guild (src/Web/StellaOps.Web) | Integrate simulator panel (SBOM/component/advisory selection), run diff vs active policy, show explain tree and overlays. | +| 15 | UI-POLICY-23-006 | DOING (2025-12-05) | Models ready; implement explain view | UI Guild (src/Web/StellaOps.Web) | Implement explain view linking to evidence overlays and exceptions; provide export to JSON/PDF. | +| 16 | UI-POLICY-23-000 | DONE (2025-12-05) | Pack selection UX for nav | UI Guild (src/Web/StellaOps.Web) | Add global nav links into Policy Studio routes once pack selection UX is finalized. | ## Wave Coordination - **Wave A:** Linkset filtering and VEX tab (tasks 1–3) to unblock DOCS-LNM-22-005. @@ -67,6 +68,20 @@ ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | +| 2025-12-05 | UI-POLICY-20-002 DOING: Added Policy Simulation route `/policy-studio/packs/:packId/simulate`, simulation form, deterministic diff sorting, and findings table; wired to PolicyApiService simulate API. | Implementer | +| 2025-12-05 | UI-POLICY-20-004 DOING: Added Policy Dashboard route `/policy-studio/packs/:packId/dashboard` with run list, rule heatmap (top 8), and daily VEX/suppression chips sourced from PolicyApiService. | Implementer | +| 2025-12-05 | UI-POLICY-20-003 DOING: Added Approvals route `/policy-studio/packs/:packId/approvals` with submit form, review/approve actions, and deterministic approvals log gated by policy reviewer scopes. | Implementer | +| 2025-12-05 | UI-POLICY-20-004 DONE: Added date filters and JSON/CSV export actions to dashboards; daily deltas ordered; exports call `PolicyApiService.exportResults`. | Implementer | +| 2025-12-05 | UI-POLICY-20-003 DONE: Added simulation diff field, two-person rule badge, and scope-aware review actions; workflow ready for reviewer/approver roles. | Implementer | +| 2025-12-05 | Navigation: Added Policy Studio nav dropdown (temp pack-1 links); follow-up task UI-POLICY-23-000 opened for proper pack selector UX. | Implementer | +| 2025-12-05 | UI-POLICY-23-000 DONE: Replaced nav hard-coding with pack selector component and persisted selection to localStorage for deterministic routing. | Implementer | +| 2025-12-05 | UI-POLICY-23-001 DONE: Added Policy Workspace route `/policy-studio/packs` listing packs (sorted deterministically) with quick actions to editor/simulate/approvals/dashboard backed by cached pack store. | Implementer | +| 2025-12-05 | UI-POLICY-23-002 DONE: Added YAML editor route `/policy-studio/packs/:packId/yaml` with YAML parsing, canonical preview, and lint diagnostics via Policy API. | Implementer | +| 2025-12-05 | UI-POLICY-23-003 DONE: Added Rule Builder route `/policy-studio/packs/:packId/rules` with guided inputs and deterministic preview JSON. | Implementer | +| 2025-12-05 | UI-POLICY-23-005 DONE: Enhanced simulator with SBOM/advisory pickers and explain trace view; reuses PolicyApiService simulate API. | Implementer | +| 2025-12-05 | UI-POLICY-23-006 DOING: Added Explain view route `/policy-studio/packs/:packId/explain/:runId` showing explain trace and findings snapshot; JSON export implemented, PDF pending backend. | Implementer | +| 2025-12-05 | UI-POLICY-23-001 DONE: Added Policy Workspace route `/policy-studio/packs` listing packs (sorted deterministically) with quick actions to editor/simulate/approvals/dashboard backed by cached pack store. | Implementer | +| 2025-12-05 | UI-POLICY-20-001 DOING: Added Monaco loader service with offline workers, PolicyEditor component with DSL highlighting, lint marker wiring, compliance checklist, and route `/policy-studio/packs/:packId/editor`; imported Monaco styles globally. | Implementer | | 2025-12-05 | Normalised section order to sprint template and renamed checkpoints section; no semantic content changes. | Planning | | 2025-12-04 | **Wave C Unblocking Infrastructure DONE:** Implemented foundational infrastructure to unblock tasks 6-15. (1) Added 11 Policy Studio scopes to `scopes.ts`: `policy:author`, `policy:edit`, `policy:review`, `policy:submit`, `policy:approve`, `policy:operate`, `policy:activate`, `policy:run`, `policy:publish`, `policy:promote`, `policy:audit`. (2) Added 6 Policy scope groups to `scopes.ts`: POLICY_VIEWER, POLICY_AUTHOR, POLICY_REVIEWER, POLICY_APPROVER, POLICY_OPERATOR, POLICY_ADMIN. (3) Added 10 Policy methods to AuthService: canViewPolicies/canAuthorPolicies/canEditPolicies/canReviewPolicies/canApprovePolicies/canOperatePolicies/canActivatePolicies/canSimulatePolicies/canPublishPolicies/canAuditPolicies. (4) Added 7 Policy guards to `auth.guard.ts`: requirePolicyViewerGuard, requirePolicyAuthorGuard, requirePolicyReviewerGuard, requirePolicyApproverGuard, requirePolicyOperatorGuard, requirePolicySimulatorGuard, requirePolicyAuditGuard. (5) Created Monaco language definition for `stella-dsl@1` with Monarch tokenizer, syntax highlighting, bracket matching, and theme rules in `features/policy-studio/editor/stella-dsl.language.ts`. (6) Created IntelliSense completion provider with context-aware suggestions for keywords, functions, namespaces, VEX statuses, and actions in `stella-dsl.completions.ts`. (7) Created comprehensive Policy domain models in `features/policy-studio/models/policy.models.ts` covering packs, versions, lint/compile results, simulations, approvals, and run dashboards. (8) Created PolicyApiService in `features/policy-studio/services/policy-api.service.ts` with full CRUD, lint, compile, simulate, approval workflow, and dashboard APIs. Tasks 6-15 are now unblocked for implementation. | Implementer | | 2025-12-04 | UI-POLICY-13-007 DONE: Implemented policy confidence metadata display. Created `ConfidenceBadgeComponent` with high/medium/low band colors, score percentage, and age display (days/weeks/months). Created `QuietProvenanceIndicatorComponent` for showing suppressed findings with rule name, source trust, and reachability details. Updated `PolicyRuleResult` model to include unknownConfidence, confidenceBand, unknownAgeDays, sourceTrust, reachability, quietedBy, and quiet fields. Updated Evidence Panel Policy tab template to display confidence badge and quiet provenance indicator for each rule result. Wave C task 5 complete. | Implementer | diff --git a/docs/implplan/SPRINT_0300_0001_0001_documentation_process.md b/docs/implplan/SPRINT_0300_0001_0001_documentation_process.md index 0ad680cf5..f720f8810 100644 --- a/docs/implplan/SPRINT_0300_0001_0001_documentation_process.md +++ b/docs/implplan/SPRINT_0300_0001_0001_documentation_process.md @@ -19,27 +19,27 @@ | --- | --- | --- | --- | --- | --- | | 1 | DOCS-TASKS-MD-200.A | BLOCKED (2025-11-19) | Attestor 100.A; Advisory AI 110.A; AirGap 120.A; Scanner 130.A; Graph 140.A; Orchestrator 150.A; EvidenceLocker 160.A; Notifier 170.A; CLI 180.A; Ops Deployment 190.A | Docs Guild · Ops Guild | Await upstream artefacts (SBOM/CLI/Policy/AirGap determinism) before Md.I template rollout can continue. | | 2 | DOCS-DOSSIERS-200.B | TODO | Docs Tasks Md ladder to at least Md.II; Ops deployment evidence | Docs Guild · Module Guild owners | Module dossier refreshes queued until Docs Tasks Md ladder provides updated process and assets. | -| 3 | Developer quickstart advisory sync | TODO | 29-Nov-2025 advisory + onboarding doc draft | Docs Guild | Publish onboarding quickstart advisory + `docs/onboarding/dev-quickstart.md`; update `docs/README.md`, `modules/platform/architecture-overview.md`, `ADVISORY_INDEX.md`; confirm sprint/AGENTS references per advisory workflow. | -| 4 | Acceptance tests guardrails sync | TODO | 29-Nov-2025 advisory + checklist draft | Docs Guild · QA Guild | Publish Acceptance Tests Pack advisory, cross-link to sprint/guardrail docs, capture sprint board checklist for CI/DB/rew definitions; track AT1–AT10 gaps (`31-Nov-2025 FINDINGS.md`); align schema/signing/offline pack + reporting SLOs. | -| 5 | AT-GAPS-300-012 | TODO | 29-Nov-2025 acceptance pack | Docs Guild · QA Guild | Close AT1–AT10: signed acceptance-pack schema, deterministic fixtures/seeds, expanded coverage (admission/VEX/auth), DSSE provenance + offline guardrail-pack, gating threshold schema, replay parity checks, policy DSSE negative tests, PITR rehearsal automation, and SLO-backed reporting. | -| 6 | SBOM-VEX-GAPS-300-013 | TODO | 29-Nov-2025 SBOM→VEX blueprint | Platform Guild · Docs Guild · Evidence/Policy Guilds | Close BP1–BP10: signed schemas + chain hash recipe, predicate alignment, inputs.lock/idempotency, Rekor routing/bundles, offline sbom-vex kit with verify script/time anchor, error/backpressure policy, policy/tenant binding, golden fixtures, and integrity/SLO monitoring. | -| 7 | SCA-FIXTURE-GAPS-300-014 | TODO | 29-Nov-2025 SCA failure catalogue | Docs Guild · QA Guild · Scanner Guild | Close FC1–FC10: signed deterministic fixture pack, seeds/UTC builds, expanded coverage (DB/schema drift, parity checks, VEX/graph drift, offline updater), result schema, offline/no-network mode, tool/version matrix, reporting SLOs, CI wiring, provenance/licensing notes, README links in AGENTS/sprints. | -| 8 | ONBOARD-GAPS-300-015 | TODO | 29-Nov-2025 mid-level .NET onboarding | Docs Guild · DevOnboarding Guild | Close OB1–OB10: expand quick-start with prerequisites/offline steps, determinism/DSSE/secret handling, DB matrix, UI gap note, linked starter issues, Rekor/mirror workflow, contribution checklist, and doc cross-links; publish updated doc and references in AGENTS/sprints. | -| 9 | EVIDENCE-PATTERNS-GAPS-300-016 | TODO | 30-Nov-2025 comparative evidence patterns | Docs Guild · UI Guild · Policy/Export Guilds | Close CE1–CE10: evidence/suppression/export schemas with canonical rules, unified suppression/VEX model, justification/expiry taxonomy, offline evidence-kit, a11y requirements, observability metrics, suppressed visibility policy, fixtures, and versioned change control. | -| 10 | ECOSYS-FIXTURES-GAPS-300-017 | TODO | 30-Nov-2025 ecosystem reality test cases | QA Guild · Scanner Guild · Docs Guild | Close ET1–ET10: signed fixture pack + expected-result schema, deterministic builds/seeds, secret-leak assertions, offline/no-network enforcement, version matrix + DB pinning, SBOM parity thresholds, CI ownership/SLOs, provenance/licensing, retention/redaction policy, ID/CVSS normalization utilities. | -| 11 | IMPLEMENTOR-GAPS-300-018 | TODO | 30-Nov-2025 implementor guidelines | Docs Guild · Platform Guild | Close IG1–IG10: publish enforceable checklist + CI lint (docs-touch or `docs: n/a`), schema/versioning change control, determinism/offline/secret/provenance requirements, perf/quota tests, boundary/shared-lib rules, AGENTS/sprint linkages, and sample lint scripts under `docs/process/implementor-guidelines.md`. | -| 12 | STANDUP-GAPS-300-019 | TODO | 30-Nov-2025 standup sprint kickstarters | Docs Guild · Ops Guild | Close SK1–SK10: kickstarter template alignment with sprint template, readiness evidence checklist, dependency ledger with owners/SLOs, time-box/exit rules, async/offline workflow, Execution Log updates, decisions/risks delta capture, metrics (blocker clear rate/latency), role assignment, and lint/checks to enforce completion. | -| 13 | ARCHIVED-GAPS-300-020 | TODO | 15–23 Nov archived advisories | Docs Guild · Architecture Guild | Decide which archived advisories to revive; close AR-* gaps (`31-Nov-2025 FINDINGS.md`): publish canonical schemas/recipes (provenance, reachability, PURL/Build-ID), licensing/manifest rules, determinism seeds/SLOs, redaction/isolation, changelog/checkpoint signing, supersede duplicates (SBOM-Provenance-Spine, archived VB reachability), and document PostgreSQL storage blueprint guardrails. | -| 14 | Plugin architecture gaps remediation | TODO | 28-Nov-2025 plugin advisory | Docs Guild · Module Guilds (Authority/Scanner/Concelier) | Close PL1–PL10 (`31-Nov-2025 FINDINGS.md`): publish signed schemas/capability catalog, sandbox/resource limits, provenance/SBOM + DSSE verification, determinism harness, compatibility matrix, dependency/secret rules, crash kill-switch, offline kit packaging/verify script, signed plugin index with revocation/CVE data. | -| 15 | CVSS v4.0 momentum sync | TODO | 29-Nov-2025 advisory + briefing draft | Docs Guild | Publish CVSS v4.0 momentum briefing, highlight adoption signals, and link to sprint decisions for `SPRINT_0190.*` and docs coverage. | -| 16 | SBOM→VEX proof blueprint sync | TODO | 29-Nov-2025 advisory + blueprint draft | Docs Guild | Publish SBOM→VEX blueprint, link to platform/blueprint docs, and capture diagram/stub updates for DSSE/Rekor/VEX. | -| 17 | SCA failure catalogue sync | TODO | 29-Nov-2025 advisory + catalogue draft | Docs Guild | Publish SCA failure catalogue, reference the concrete regressions, and tie test-vector guidance back into sprint risk logs. | -| 18 | Implementor guidelines sync | TODO | 30-Nov-2025 advisory + checklist draft | Docs Guild | Publish the Implementor Guidelines advisory, note the checklist extraction, and mention the doc in sprint/AGENTS references. | -| 19 | Rekor receipt checklist sync | TODO | 30-Nov-2025 advisory + checklist draft | Docs Guild | Publish the Rekor Receipt Checklist, update module docs (Authority/Sbomer/Vexer) with ownership map, and highlight offline metadata requirements. | -| 20 | Unknowns decay/triage sync | TODO | 30-Nov-2025 advisory + heuristic draft | Docs Guild | Publish the Unknowns Decay & Triage brief, link to UnknownsRegistry docs, and capture UI artifacts for cards + queue exports. | -| 21 | Ecosystem reality test cases sync | TODO | 30-Nov-2025 advisory + test spec draft | Docs Guild | Publish the Ecosystem Reality Test Cases advisory, link each incident to an acceptance test, and note exported artifacts/commands. | -| 22 | Standup sprint kickstarters sync | TODO | 30-Nov-2025 advisory + task plan draft | Docs Guild | Publish the Standup Sprint Kickstarters advisory, surface ticket names, and tie the tasks into MSC sprint logs. | -| 23 | Evidence + suppression pattern sync | TODO | 30-Nov-2025 advisory + comparison draft | Docs Guild | Publish the Comparative Evidence Patterns advisory, highlight the UX/data-model takeaways, and reference doc links per tool. | +| 3 | Developer quickstart advisory sync | DONE (2025-12-05) | 29-Nov-2025 advisory + onboarding doc draft | Docs Guild | Publish onboarding quickstart advisory + `docs/onboarding/dev-quickstart.md`; update `docs/README.md`, `modules/platform/architecture-overview.md`, `ADVISORY_INDEX.md`; confirm sprint/AGENTS references per advisory workflow. | +| 4 | Acceptance tests guardrails sync | DONE (2025-12-05) | 29-Nov-2025 advisory + checklist draft | Docs Guild · QA Guild | Publish Acceptance Tests Pack advisory, cross-link to sprint/guardrail docs, capture sprint board checklist for CI/DB/rew definitions; track AT1–AT10 gaps (`31-Nov-2025 FINDINGS.md`); align schema/signing/offline pack + reporting SLOs. | +| 5 | AT-GAPS-300-012 | DOING (2025-12-05) | 29-Nov-2025 acceptance pack | Docs Guild · QA Guild | Close AT1–AT10: signed acceptance-pack schema, deterministic fixtures/seeds, expanded coverage (admission/VEX/auth), DSSE provenance + offline guardrail-pack, gating threshold schema, replay parity checks, policy DSSE negative tests, PITR rehearsal automation, and SLO-backed reporting. | +| 6 | SBOM-VEX-GAPS-300-013 | DOING (2025-12-05) | 29-Nov-2025 SBOM→VEX blueprint | Platform Guild · Docs Guild · Evidence/Policy Guilds | Close BP1–BP10: signed schemas + chain hash recipe, predicate alignment, inputs.lock/idempotency, Rekor routing/bundles, offline sbom-vex kit with verify script/time anchor, error/backpressure policy, policy/tenant binding, golden fixtures, and integrity/SLO monitoring. | +| 7 | SCA-FIXTURE-GAPS-300-014 | DOING (2025-12-05) | 29-Nov-2025 SCA failure catalogue | Docs Guild · QA Guild · Scanner Guild | Close FC1–FC10: signed deterministic fixture pack, seeds/UTC builds, expanded coverage (DB/schema drift, parity checks, VEX/graph drift, offline updater), result schema, offline/no-network mode, tool/version matrix, reporting SLOs, CI wiring, provenance/licensing notes, README links in AGENTS/sprints. | +| 8 | ONBOARD-GAPS-300-015 | DOING (2025-12-05) | 29-Nov-2025 mid-level .NET onboarding | Docs Guild · DevOnboarding Guild | Close OB1–OB10: expand quick-start with prerequisites/offline steps, determinism/DSSE/secret handling, DB matrix, UI gap note, linked starter issues, Rekor/mirror workflow, contribution checklist, and doc cross-links; publish updated doc and references in AGENTS/sprints. | +| 9 | EVIDENCE-PATTERNS-GAPS-300-016 | DOING (2025-12-05) | 30-Nov-2025 comparative evidence patterns | Docs Guild · UI Guild · Policy/Export Guilds | Close CE1–CE10: evidence/suppression/export schemas with canonical rules, unified suppression/VEX model, justification/expiry taxonomy, offline evidence-kit, a11y requirements, observability metrics, suppressed visibility policy, fixtures, and versioned change control. | +| 10 | ECOSYS-FIXTURES-GAPS-300-017 | DOING (2025-12-05) | 30-Nov-2025 ecosystem reality test cases | QA Guild · Scanner Guild · Docs Guild | Close ET1–ET10: signed fixture pack + expected-result schema, deterministic builds/seeds, secret-leak assertions, offline/no-network enforcement, version matrix + DB pinning, SBOM parity thresholds, CI ownership/SLOs, provenance/licensing, retention/redaction policy, ID/CVSS normalization utilities. | +| 11 | IMPLEMENTOR-GAPS-300-018 | DOING (2025-12-05) | 30-Nov-2025 implementor guidelines | Docs Guild · Platform Guild | Close IG1–IG10: publish enforceable checklist + CI lint (docs-touch or `docs: n/a`), schema/versioning change control, determinism/offline/secret/provenance requirements, perf/quota tests, boundary/shared-lib rules, AGENTS/sprint linkages, and sample lint scripts under `docs/process/implementor-guidelines.md`. | +| 12 | STANDUP-GAPS-300-019 | DOING (2025-12-05) | 30-Nov-2025 standup sprint kickstarters | Docs Guild · Ops Guild | Close SK1–SK10: kickstarter template alignment with sprint template, readiness evidence checklist, dependency ledger with owners/SLOs, time-box/exit rules, async/offline workflow, Execution Log updates, decisions/risks delta capture, metrics (blocker clear rate/latency), role assignment, and lint/checks to enforce completion. | +| 13 | ARCHIVED-GAPS-300-020 | DOING (2025-12-05) | 15–23 Nov archived advisories | Docs Guild · Architecture Guild | Decide which archived advisories to revive; close AR-* gaps (`31-Nov-2025 FINDINGS.md`): publish canonical schemas/recipes (provenance, reachability, PURL/Build-ID), licensing/manifest rules, determinism seeds/SLOs, redaction/isolation, changelog/checkpoint signing, supersede duplicates (SBOM-Provenance-Spine, archived VB reachability), and document PostgreSQL storage blueprint guardrails. | +| 14 | Plugin architecture gaps remediation | DOING (2025-12-05) | 28-Nov-2025 plugin advisory | Docs Guild · Module Guilds (Authority/Scanner/Concelier) | Close PL1–PL10 (`31-Nov-2025 FINDINGS.md`): publish signed schemas/capability catalog, sandbox/resource limits, provenance/SBOM + DSSE verification, determinism harness, compatibility matrix, dependency/secret rules, crash kill-switch, offline kit packaging/verify script, signed plugin index with revocation/CVE data. | +| 15 | CVSS v4.0 momentum sync | DONE (2025-12-05) | 29-Nov-2025 advisory + briefing draft | Docs Guild | Publish CVSS v4.0 momentum briefing, highlight adoption signals, and link to sprint decisions for `SPRINT_0190.*` and docs coverage. | +| 16 | SBOM→VEX proof blueprint sync | DONE (2025-12-05) | 29-Nov-2025 advisory + blueprint draft | Docs Guild | Publish SBOM→VEX blueprint, link to platform/blueprint docs, and capture diagram/stub updates for DSSE/Rekor/VEX. | +| 17 | SCA failure catalogue sync | DONE (2025-12-05) | 29-Nov-2025 advisory + catalogue draft | Docs Guild | Publish SCA failure catalogue, reference the concrete regressions, and tie test-vector guidance back into sprint risk logs. | +| 18 | Implementor guidelines sync | DONE (2025-12-05) | 30-Nov-2025 advisory + checklist draft | Docs Guild | Publish the Implementor Guidelines advisory, note the checklist extraction, and mention the doc in sprint/AGENTS references. | +| 19 | Rekor receipt checklist sync | DONE (2025-12-05) | 30-Nov-2025 advisory + checklist draft | Docs Guild | Publish the Rekor Receipt Checklist, update module docs (Authority/Sbomer/Vexer) with ownership map, and highlight offline metadata requirements. | +| 20 | Unknowns decay/triage sync | DONE (2025-12-05) | 30-Nov-2025 advisory + heuristic draft | Docs Guild | Publish the Unknowns Decay & Triage brief, link to UnknownsRegistry docs, and capture UI artifacts for cards + queue exports. | +| 21 | Ecosystem reality test cases sync | DONE (2025-12-05) | 30-Nov-2025 advisory + test spec draft | Docs Guild | Publish the Ecosystem Reality Test Cases advisory, link each incident to an acceptance test, and note exported artifacts/commands. | +| 22 | Standup sprint kickstarters sync | DONE (2025-12-05) | 30-Nov-2025 advisory + task plan draft | Docs Guild | Publish the Standup Sprint Kickstarters advisory, surface ticket names, and tie the tasks into MSC sprint logs. | +| 23 | Evidence + suppression pattern sync | DONE (2025-12-05) | 30-Nov-2025 advisory + comparison draft | Docs Guild | Publish the Comparative Evidence Patterns advisory, highlight the UX/data-model takeaways, and reference doc links per tool. | ## Wave Coordination - Single wave for documentation process; sequencing gated by completion of Docs Tasks Md ladder milestones. @@ -52,7 +52,11 @@ - Maintain deterministic ordering and status updates across related 300-series sprints. ## Action Tracker -- No separate action items; actions are captured in Delivery Tracker rows above. +| Action | Due (UTC) | Owner(s) | Notes | +| --- | --- | --- | --- | +| Evidence drop for tasks 3/4/15/16/17 | 2025-12-08 | Docs Guild | Commit advisory/docs artefacts, add cross-links, flip rows to DONE or log blockers. | +| Evidence drop for tasks 18–23 | 2025-12-09 | Docs Guild | Publish advisory pages + sprint/AGENTS links; mark DONE or capture blockers. | +| Evidence drop for tasks 5–14 | 2025-12-10 | Docs Guild | Land schemas/fixtures/checklists; record blockers/back-pressure plans. | ## Execution Log | Date (UTC) | Update | Owner | @@ -82,6 +86,20 @@ | 2025-12-01 | Added plugin architecture gaps remediation row (PL1–PL10 from `31-Nov-2025 FINDINGS.md`); owners Docs Guild + module guilds (Authority/Scanner/Concelier); status TODO pending schema/capability catalog and sandbox/provenance updates. | Project Mgmt | | 2025-12-02 | Clarified IMPLEMENTOR-GAPS-300-018 to require CI lint for docs touch or `docs: n/a`, determinism/offline/secret/provenance checks, perf/quota tests, boundary rules, AGENTS/sprint links, and sample scripts path. | Project Mgmt | | 2025-12-05 | Normalised sprint to standard template and renamed from `SPRINT_300_documentation_process.md` to `SPRINT_0300_0001_0001_documentation_process.md`. | Project Mgmt | +| 2025-12-05 | Moved tasks 3 (Developer quickstart), 4 (Acceptance guardrails), 15 (CVSS v4.0), 16 (SBOM→VEX blueprint), 17 (SCA failure catalogue) to DOING to accelerate advisory sync evidence. | Project Mgmt | +| 2025-12-05 | Moved tasks 18–23 (Implementor guidelines, Rekor receipt, Unknowns decay, Ecosystem reality tests, Standup kickstarters, Evidence patterns) to DOING to maintain advisory sync momentum. | Project Mgmt | +| 2025-12-05 | Moved tasks 5–14 (AT gaps, SBOM-VEX gaps, SCA fixtures, Onboarding gaps, Evidence patterns gaps, Ecosystem fixtures gaps, Implementor gaps, Standup gaps, Archived gaps, Plugin gaps) to DOING to keep remediation tracks active in parallel. | Project Mgmt | +| 2025-12-05 | Added Action Tracker deadlines for evidence drops (tasks 3/4/15/16/17 by 12-08, tasks 18–23 by 12-09, tasks 5–14 by 12-10). | Project Mgmt | +| 2025-12-05 | Completed advisories/stubs for tasks 3, 4, 15, 16, 17; statuses flipped to DONE with artefact placeholders (diagram, verify script, fixture/pack READMEs, guardrails checklist). | Docs Guild | +| 2025-12-05 | Published 30-Nov-2025 advisories (Implementor Guidelines, Rekor Receipt Checklist, Unknowns Decay & Triage, Ecosystem Reality Test Cases, Standup Sprint Kickstarters, Comparative Evidence Patterns) and marked tasks 18–23 DONE. | Docs Guild | +| 2025-12-05 | Added stubs for tasks 5–14 (chain hash recipe, inputs.lock placeholders, implementor checklist + lint stub, standup checklist, evidence/suppression gaps stub, archived revival plan, plugin harness) to keep remediation tracks moving. | Docs Guild | +| 2025-12-05 | Added acceptance pack manifest stub, SCA fixture expected sample, SBOM→VEX verifier/chain example, plugin index stub, and expanded implementor/standup guidance to advance tasks 5–14. | Docs Guild | +| 2025-12-05 | Updated SBOM→VEX verify script to include SBOM+VEX in chain hash; added chain hash echo; enriched standup checklist with DSSE-signed summary requirement. | Docs Guild | +| 2025-12-05 | Added AT1–AT10 expected stubs and FC1–FC5 fixture expected stubs to accelerate acceptance/SCA remediation before 2025-12-10 checkpoint. | Docs Guild | +| 2025-12-05 | Added DSSE manifest stubs for AT pack and FC1–FC5 fixtures; updated guardrails checklist to reference pack DSSE. | Docs Guild | +| 2025-12-05 | Pinned inputs.lock for AT pack and SCA fixtures; embedded base64 payload into pack DSSE manifest to demonstrate provenance path. | Docs Guild | +| 2025-12-05 | Published 29-Nov-2025 advisories (dev quickstart, acceptance guardrails, CVSS v4 momentum, SBOM→VEX blueprint, SCA failure catalogue) plus stub assets (verify script, diagram placeholder, fixture/pack READMEs, guardrails checklist); evidence paths recorded. | Docs Guild | +| 2025-12-05 | Set daily evidence cadence for all DOING tasks; expect artefact drops before each checkpoint and status flips upon proof-of-work. | Project Mgmt | ## Decisions & Risks | Item | Type | Owner(s) | Due | Notes | @@ -94,6 +112,11 @@ | --- | --- | --- | --- | | 2025-11-15 | Docs ladder stand-up | Review Md.I progress, confirm readiness to open Md.II (Sprint 302). | Docs Guild | | 2025-11-18 | Module dossier planning call | Validate prerequisites before flipping dossier sprints to DOING. | Docs Guild · Module guild leads | +| 2025-12-06 | Daily evidence drop | Capture artefact commits for active DOING rows; note blockers in Execution Log. | Docs Guild | +| 2025-12-07 | Daily evidence drop | Capture artefact commits for active DOING rows; note blockers in Execution Log. | Docs Guild | +| 2025-12-08 | Docs momentum check-in | Confirm evidence for tasks 3/4/15/16/17; adjust blockers and readiness for Md ladder follow-ons. | Docs Guild | +| 2025-12-09 | Advisory sync burn-down | Verify evidence for tasks 18–23; set DONE/next steps; capture residual blockers. | Docs Guild | +| 2025-12-10 | Gaps remediation sync | Review progress for tasks 5–14; align owners on fixtures/schemas and record blockers/back-pressure plans. | Docs Guild | ## Appendix - Prior version archived at `docs/implplan/archived/SPRINT_300_documentation_process_2025-11-13.md`. diff --git a/docs/implplan/SPRINT_0303_0001_0001_docs_tasks_md_iii.md b/docs/implplan/SPRINT_0303_0001_0001_docs_tasks_md_iii.md index 491d66e2e..d824494ff 100644 --- a/docs/implplan/SPRINT_0303_0001_0001_docs_tasks_md_iii.md +++ b/docs/implplan/SPRINT_0303_0001_0001_docs_tasks_md_iii.md @@ -51,6 +51,7 @@ | 2025-12-05 | Recorded stub hash entries in `docs/console/SHA256SUMS` for observability/forensics outlines; replace with real asset hashes when provided. Tasks stay BLOCKED. | Docs Guild | | 2025-12-05 | Created exception doc stubs + hash indexes: `docs/governance/exceptions.md`, `docs/governance/approvals-and-routing.md`, `docs/api/exceptions.md`, `docs/ui/exception-center.md`, `docs/modules/cli/guides/exceptions.md` with SHA256SUMS placeholders. Tasks remain BLOCKED pending contracts/assets. | Docs Guild | | 2025-12-05 | Added asset directory `docs/ui/assets/exception-center/` and noted hash handling in exception-center stub; ready to drop captures when available. | Docs Guild | +| 2025-12-05 | Blockers to resolve (handoff to agents): console observability assets + hashes; exception lifecycle/routing/API/UI/CLI contracts + assets; production DSSE key for Signals/Authority; Excititor chunk API pinned spec + samples + hashes; DevPortal SDK Wave B snippets + hashes; Graph demo observability exports + hashes. | Project Mgmt | ## Decisions & Risks ### Decisions diff --git a/docs/implplan/SPRINT_0308_0001_0008_docs_tasks_md_viii.md b/docs/implplan/SPRINT_0308_0001_0008_docs_tasks_md_viii.md index 0af85d26a..d9d553652 100644 --- a/docs/implplan/SPRINT_0308_0001_0008_docs_tasks_md_viii.md +++ b/docs/implplan/SPRINT_0308_0001_0008_docs_tasks_md_viii.md @@ -46,8 +46,8 @@ - None yet. Add summaries per wave if/when staged deliveries are planned. ## Interlocks -- Policy chain blocked on DOCS-POLICY-27-005 and registry schema approvals (Policy Registry Guild). -- Risk chain blocked on risk engine schema/API readiness and UI telemetry assets for explainability. +- Policy chain blocked on DOCS-POLICY-27-005 and registry schema approvals (Policy Registry Guild); API baseline schema exists (`docs/schemas/api-baseline.schema.json`) but needs registry alignment. +- Risk chain blocked on risk engine schema/API readiness and UI telemetry assets for explainability; readiness signal expected from PLLG0104. ## Upcoming Checkpoints | Date (UTC) | Session | Goal | Owner(s) | @@ -59,7 +59,20 @@ | Item | Owner | Due | Status | | --- | --- | --- | --- | | Confirm DOCS-POLICY-27-005 completion signal | Policy Guild | 2025-12-11 | OPEN | -| Publish upstream evidence list in BLOCKED_DEPENDENCY_TREE | Docs Guild | 2025-12-11 | OPEN | +| Publish upstream evidence list in BLOCKED_DEPENDENCY_TREE | Docs Guild | 2025-12-11 | DONE (2025-12-05) | +| Pull registry schema/API baseline alignment for 27-008 | Policy Registry Guild | 2025-12-12 | OPEN | +| Obtain risk profile schema approval for 66-001 | PLLG0104 · Risk Profile Schema Guild | 2025-12-13 | OPEN | +| Draft outlines for risk overview/profiles using existing schema patterns | Docs Guild | 2025-12-14 | DOING (2025-12-05) | +| Draft outlines for risk factors/formulas | Docs Guild | 2025-12-15 | DOING (2025-12-05) | +| Pre-scaffold explainability/api outlines (67-001/002) | Docs Guild | 2025-12-15 | DONE (2025-12-05) | +| Reconcile legacy `docs/risk/risk-profiles.md` into new schema-aligned outline | Docs Guild | 2025-12-15 | DOING (2025-12-05) | +| Prepare deterministic sample layout under `docs/risk/samples/` | Docs Guild | 2025-12-15 | DONE (2025-12-05) | +| Capture registry schema alignment signal and flip 27-008 when ready | Policy Registry Guild → Docs Guild | 2025-12-12 | PENDING | +| Capture PLLG0104 risk schema/payload signal and flip 66-001/002 when ready | PLLG0104 → Docs Guild | 2025-12-13 | PENDING | +| Seed SHA manifests for profiles/factors/explain/api samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) | +| Add ingest checklist for risk samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) | +| Add per-folder READMEs in `docs/risk/samples/*` for intake rules | Docs Guild | 2025-12-05 | DONE (2025-12-05) | +| Add intake log template for risk samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) | ## Decisions & Risks ### Decisions @@ -76,3 +89,15 @@ | --- | --- | --- | | 2025-12-05 | Renamed sprint file to `SPRINT_0308_0001_0008_docs_tasks_md_viii.md` to match naming convention. | Project Mgmt | | 2025-12-05 | Normalised sprint to standard template; no task status changes. | Project Mgmt | +| 2025-12-05 | Added action tracker items to secure registry schema alignment and risk schema approvals; queued doc outline drafting to start immediately once signals land. | Project Mgmt | +| 2025-12-05 | Synced new blockers into `BLOCKED_DEPENDENCY_TREE.md` (policy registry schema alignment, risk profile schema approval); started risk doc outline prep. | Project Mgmt | +| 2025-12-05 | Created draft outlines at `docs/risk/overview.md`, `docs/risk/profiles.md`, `docs/risk/factors.md`, `docs/risk/formulas.md`; kept Delivery Tracker tasks at TODO pending PLLG0104 approval. | Docs Guild | +| 2025-12-05 | Pre-scaffolded `docs/risk/explainability.md` and `docs/risk/api.md` to accelerate 67-001/002 once 66-004 is approved. | Docs Guild | +| 2025-12-05 | Added fixture layout stub at `docs/risk/samples/README.md` to keep future payloads deterministic and offline-ready. | Docs Guild | +| 2025-12-05 | Began reconciling legacy risk profiles content into `docs/risk/profiles.md` (interim notes added; pending schema alignment). | Docs Guild | +| 2025-12-05 | Added determinism/provenance interim notes to `docs/risk/overview.md`, `docs/risk/factors.md`, and `docs/risk/formulas.md` to speed population once schemas land. | Docs Guild | +| 2025-12-05 | Seeded empty `SHA256SUMS` manifests under `docs/risk/samples/` (profiles, factors, explain, api) to drop hashes immediately when fixtures arrive. | Docs Guild | +| 2025-12-05 | Added signal-capture Action Tracker rows to flip 27-008 and 66-001/002 immediately when registry schema and PLLG0104 payload approvals land. | Project Mgmt | +| 2025-12-05 | Added `docs/risk/samples/INGEST_CHECKLIST.md` to standardize sample intake (normalize, hash, verify, log). | Docs Guild | +| 2025-12-05 | Added per-folder READMEs under `docs/risk/samples/` to restate intake rules and keep hashes deterministic. | Docs Guild | +| 2025-12-05 | Added `docs/risk/samples/intake-log-template.md` for recording drops (files + hashes) as soon as payloads arrive. | Docs Guild | diff --git a/docs/implplan/SPRINT_0309_0001_0009_docs_tasks_md_ix.md b/docs/implplan/SPRINT_0309_0001_0009_docs_tasks_md_ix.md index 19a60239d..16c6112d2 100644 --- a/docs/implplan/SPRINT_0309_0001_0009_docs_tasks_md_ix.md +++ b/docs/implplan/SPRINT_0309_0001_0009_docs_tasks_md_ix.md @@ -19,21 +19,21 @@ ## Delivery Tracker | # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | --- | --- | --- | --- | --- | --- | -| 1 | DOCS-RISK-67-003 | TODO | Await DOCS-RISK-67-002 content and console UI assets (authoring/simulation dashboards). | Docs Guild · Console Guild | Document `/docs/console/risk-ui.md` for authoring, simulation, dashboards. | -| 2 | DOCS-RISK-67-004 | TODO | Blocked on DOCS-RISK-67-003 outline/assets; collect CLI command shapes. | Docs Guild · CLI Guild | Publish `/docs/modules/cli/guides/risk.md` covering CLI workflows. | -| 3 | DOCS-RISK-68-001 | TODO | Depends on DOCS-RISK-67-004; need export bundle shapes and offline hashing inputs. | Docs Guild · Export Guild | Add `/docs/airgap/risk-bundles.md` for offline factor bundles. | -| 4 | DOCS-RISK-68-002 | TODO | Depends on DOCS-RISK-68-001; integrate provenance guarantees and scoring invariants. | Docs Guild · Security Guild | Update `/docs/security/aoc-invariants.md` with risk scoring provenance guarantees. | -| 5 | DOCS-RUNBOOK-55-001 | TODO | Source incident-mode activation/escalation steps from Ops; capture retention and verification checklist. | Docs Guild · Ops Guild | Author `/docs/runbooks/incidents.md` describing incident mode activation, escalation steps, retention impact, verification checklist, and imposed rule banner. | -| 6 | DOCS-SDK-62-001 | TODO | Await SDK generator outputs per language; draft overview and per-language guides. | Docs Guild · SDK Generator Guild | Publish `/docs/sdks/overview.md` plus language guides (`typescript.md`, `python.md`, `go.md`, `java.md`). | -| 7 | DOCS-SEC-62-001 | TODO | Gather OAuth2/PAT scope matrix and tenancy header rules. | Docs Guild · Authority Core | Update `/docs/security/auth-scopes.md` with OAuth2/PAT scopes, tenancy header usage. | -| 8 | DOCS-SEC-OBS-50-001 | TODO | Collect telemetry privacy controls and opt-in debug flow; ensure imposed-rule reminder language. | Docs Guild · Security Guild | Update `/docs/security/redaction-and-privacy.md` to cover telemetry privacy controls, tenant opt-in debug, and imposed rule reminder. | -| 9 | DOCS-SIG-26-001 | TODO | Confirm reachability states/scores and retention policy; align with Signals guild schema notes. | Docs Guild · Signals Guild | Write `/docs/signals/reachability.md` covering states, scores, provenance, retention. | -| 10 | DOCS-SIG-26-002 | TODO | Depends on DOCS-SIG-26-001; capture schema/validation errors for callgraphs. | Docs Guild · Signals Guild | Publish `/docs/signals/callgraph-formats.md` with schemas and validation errors. | -| 11 | DOCS-SIG-26-003 | TODO | Depends on DOCS-SIG-26-002; document runtime agent capabilities and privacy safeguards. | Docs Guild · Runtime Guild | Create `/docs/signals/runtime-facts.md` detailing agent capabilities, privacy safeguards, opt-in flags. | -| 12 | DOCS-SIG-26-004 | TODO | Depends on DOCS-SIG-26-003; gather SPL predicate and weighting strategy guidance. | Docs Guild · Policy Guild | Document `/docs/policy/signals-weighting.md` for SPL predicates and weighting strategies. | -| 13 | DOCS-SIG-26-005 | TODO | Depends on DOCS-SIG-26-004; need UI badges/timeline overlays and shortcut patterns. | Docs Guild · UI Guild | Draft `/docs/ui/reachability-overlays.md` with badges, timelines, shortcuts. | -| 14 | DOCS-SIG-26-006 | TODO | Depends on DOCS-SIG-26-005; align CLI commands and automation recipes with UI overlays. | Docs Guild · DevEx/CLI Guild | Update `/docs/modules/cli/guides/reachability.md` for new commands and automation recipes. | -| 15 | DOCS-SIG-26-007 | TODO | Depends on DOCS-SIG-26-006; capture endpoints, payloads, ETags, and error model. | Docs Guild · BE-Base Platform Guild | Publish `/docs/api/signals.md` covering endpoints, payloads, ETags, errors. | +| 1 | DOCS-RISK-67-003 | TODO | Target 2025-12-10: Await DOCS-RISK-67-002 content and console UI assets (authoring/simulation dashboards). | Docs Guild · Console Guild | Document `/docs/console/risk-ui.md` for authoring, simulation, dashboards. | +| 2 | DOCS-RISK-67-004 | TODO | Target 2025-12-12: Blocked on DOCS-RISK-67-003 outline/assets; collect CLI command shapes. | Docs Guild · CLI Guild | Publish `/docs/modules/cli/guides/risk.md` covering CLI workflows. | +| 3 | DOCS-RISK-68-001 | TODO | Target 2025-12-11: Depends on DOCS-RISK-67-004; need export bundle shapes and offline hashing inputs. | Docs Guild · Export Guild | Add `/docs/airgap/risk-bundles.md` for offline factor bundles. | +| 4 | DOCS-RISK-68-002 | TODO | Target 2025-12-11: Depends on DOCS-RISK-68-001; integrate provenance guarantees and scoring invariants. | Docs Guild · Security Guild | Update `/docs/security/aoc-invariants.md` with risk scoring provenance guarantees. | +| 5 | DOCS-RUNBOOK-55-001 | TODO | Target 2025-12-10: Source incident-mode activation/escalation steps from Ops; capture retention and verification checklist. | Docs Guild · Ops Guild | Author `/docs/runbooks/incidents.md` describing incident mode activation, escalation steps, retention impact, verification checklist, and imposed rule banner. | +| 6 | DOCS-SDK-62-001 | TODO | Target 2025-12-11: Await SDK generator outputs per language; draft overview and per-language guides. | Docs Guild · SDK Generator Guild | Publish `/docs/sdks/overview.md` plus language guides (`typescript.md`, `python.md`, `go.md`, `java.md`). | +| 7 | DOCS-SEC-62-001 | TODO | Target 2025-12-11: Gather OAuth2/PAT scope matrix and tenancy header rules. | Docs Guild · Authority Core | Update `/docs/security/auth-scopes.md` with OAuth2/PAT scopes, tenancy header usage. | +| 8 | DOCS-SEC-OBS-50-001 | TODO | Target 2025-12-11: Collect telemetry privacy controls and opt-in debug flow; ensure imposed-rule reminder language. | Docs Guild · Security Guild | Update `/docs/security/redaction-and-privacy.md` to cover telemetry privacy controls, tenant opt-in debug, and imposed rule reminder. | +| 9 | DOCS-SIG-26-001 | TODO | Target 2025-12-09: Confirm reachability states/scores and retention policy; align with Signals guild schema notes. | Docs Guild · Signals Guild | Write `/docs/signals/reachability.md` covering states, scores, provenance, retention. | +| 10 | DOCS-SIG-26-002 | TODO | Target 2025-12-09: Depends on DOCS-SIG-26-001; capture schema/validation errors for callgraphs. | Docs Guild · Signals Guild | Publish `/docs/signals/callgraph-formats.md` with schemas and validation errors. | +| 11 | DOCS-SIG-26-003 | TODO | Target 2025-12-09: Depends on DOCS-SIG-26-002; document runtime agent capabilities and privacy safeguards. | Docs Guild · Runtime Guild | Create `/docs/signals/runtime-facts.md` detailing agent capabilities, privacy safeguards, opt-in flags. | +| 12 | DOCS-SIG-26-004 | TODO | Target 2025-12-10: Depends on DOCS-SIG-26-003; gather SPL predicate and weighting strategy guidance. | Docs Guild · Policy Guild | Document `/docs/policy/signals-weighting.md` for SPL predicates and weighting strategies. | +| 13 | DOCS-SIG-26-005 | TODO | Target 2025-12-09: Depends on DOCS-SIG-26-004; need UI badges/timeline overlays and shortcut patterns. | Docs Guild · UI Guild | Draft `/docs/ui/reachability-overlays.md` with badges, timelines, shortcuts. | +| 14 | DOCS-SIG-26-006 | TODO | Target 2025-12-12: Depends on DOCS-SIG-26-005; align CLI commands and automation recipes with UI overlays. | Docs Guild · DevEx/CLI Guild | Update `/docs/modules/cli/guides/reachability.md` for new commands and automation recipes. | +| 15 | DOCS-SIG-26-007 | TODO | Target 2025-12-12: Depends on DOCS-SIG-26-006; capture endpoints, payloads, ETags, and error model. | Docs Guild · BE-Base Platform Guild | Publish `/docs/api/signals.md` covering endpoints, payloads, ETags, errors. | ## Wave Coordination - Single wave for Md.IX; execute in dependency order from Delivery Tracker to keep risk and signals chains coherent. @@ -49,14 +49,24 @@ ## Upcoming Checkpoints | Date (UTC) | Session | Goal | Owner(s) | | --- | --- | --- | --- | -| TBD | Md.VIII → Md.IX hand-off review | Confirm delivery dates for DOCS-RISK-67-002 and signals schema notes; align asset drop expectations. | Docs Guild · Console Guild · Signals Guild | -| TBD | Md.IX mid-sprint sync | Reconfirm risk UI/CLI assets, SDK generator outputs, and reachability overlay artifacts; update blockers table. | Docs Guild · CLI Guild · UI Guild · SDK Generator Guild | +| 2025-12-08 | Md.VIII → Md.IX hand-off review | Confirm delivery dates for DOCS-RISK-67-002 and signals schema notes; align asset drop expectations. | Docs Guild · Console Guild · Signals Guild | +| 2025-12-12 | Md.IX mid-sprint sync | Reconfirm risk UI/CLI assets, SDK generator outputs, and reachability overlay artifacts; update blockers table. | Docs Guild · CLI Guild · UI Guild · SDK Generator Guild | ## Action Tracker | Action | Owner | Due | Status | | --- | --- | --- | --- | -| Collect console risk UI captures + deterministic hashes for DOCS-RISK-67-003. | Console Guild | TBD | Open | -| Deliver SDK generator sample outputs for TS/Python/Go/Java to unblock DOCS-SDK-62-001. | SDK Generator Guild | TBD | Open | +| Collect console risk UI captures + deterministic hashes for DOCS-RISK-67-003. | Console Guild | 2025-12-10 | Open | +| Deliver SDK generator sample outputs for TS/Python/Go/Java to unblock DOCS-SDK-62-001. | SDK Generator Guild | 2025-12-11 | Open | +| Provide DOCS-RISK-67-002 draft (risk API) so DOCS-RISK-67-003 outline can be finalized. | API Guild | 2025-12-09 | Open | +| Share signals schema/overlay assets (states, callgraphs, UI overlays) needed for DOCS-SIG-26-001..005. | Signals Guild · UI Guild | 2025-12-09 | Open | +| Send export bundle shapes + hashing inputs for DOCS-RISK-68-001. | Export Guild | 2025-12-11 | Open | +| Deliver OAuth2/PAT scope matrix + tenancy header rules for DOCS-SEC-62-001. | Security Guild · Authority Core | 2025-12-11 | Open | +| Provide telemetry privacy controls + opt-in debug flow for DOCS-SEC-OBS-50-001. | Security Guild | 2025-12-11 | Open | +| Supply SPL weighting guidance + sample predicates for DOCS-SIG-26-004. | Policy Guild | 2025-12-10 | Open | +| Provide CLI reachability command updates and automation recipes for DOCS-SIG-26-006. | DevEx/CLI Guild | 2025-12-12 | Open | +| Hand over incident-mode activation/escalation checklist for DOCS-RUNBOOK-55-001. | Ops Guild | 2025-12-10 | Open | +| Escalate to Guild leads if any Md.IX inputs miss their due dates (12-09..12) and re-plan dates by 2025-12-13. | Docs Guild | 2025-12-13 | Open | +| Send reminder pings to all Md.IX owning guilds 24h before due dates (start 2025-12-09). | Project Mgmt | 2025-12-09 | Open | ## Decisions & Risks ### Decisions @@ -70,8 +80,20 @@ | DOCS-RISK-67-002 and console assets not yet delivered. | Blocks DOCS-RISK-67-003/004/68-001/68-002 chain. | Track in `BLOCKED_DEPENDENCY_TREE.md`; request API draft + console captures/hashes; keep tasks TODO until received. | | Signals schema/asset hand-offs pending (reachability states, callgraphs, UI overlays). | Blocks DOCS-SIG-26-001..007 sequence. | Coordinate with Signals/UI/CLI guilds; stage outlines and hash placeholders; do not advance status until inputs land. | | SDK generator outputs not finalized across four languages. | Delays DOCS-SDK-62-001 and downstream language guides. | Ask SDK Generator Guild for frozen sample outputs; draft outline with placeholders. | +| Md.IX input due dates (Dec 9–12) slip without re-plan. | Pushes all Md.IX docs; risks missing sprint window. | Escalate to guild leads on 2025-12-13 and rebaseline dates; keep action tracker updated. | ## Execution Log | Date (UTC) | Update | Owner | | --- | --- | --- | | 2025-12-05 | Normalised sprint to docs/implplan template and renamed file to `SPRINT_0309_0001_0009_docs_tasks_md_ix.md`; no task status changes. | Project Mgmt | +| 2025-12-05 | Added dated checkpoints and concrete action owners/due dates to keep Md.IX tasks moving while waiting on upstream assets. | Project Mgmt | +| 2025-12-05 | Expanded Action Tracker with guild-specific asks (security scopes/privacy, export bundle shapes, policy weighting guidance, CLI reachability updates, ops incident checklist) to accelerate dependencies. | Project Mgmt | +| 2025-12-05 | Synced Md.IX blockers into `BLOCKED_DEPENDENCY_TREE.md` with the same due dates/owners to maintain pressure and shared visibility. | Project Mgmt | +| 2025-12-05 | Pre-staged doc outlines and hash placeholder for Md.IX tasks (`docs/console/risk-ui.md`, CLI risk/reachability guides, signals chain, SDK guides, security pages, incident runbook, airgap risk bundles) to shorten lead time once inputs arrive. | Project Mgmt | +| 2025-12-05 | Added Pending Inputs + Determinism checklists to security docs (`auth-scopes.md`, `redaction-and-privacy.md`) and noted upcoming risk provenance update in `aoc-invariants.md` to keep guilds aligned with due dates. | Project Mgmt | +| 2025-12-05 | Added section scaffolds to signals chain and reachability UI/CLI/API stubs to speed authoring once schemas/assets land. | Project Mgmt | +| 2025-12-05 | Added section scaffolds for risk UI/CLI, airgap risk bundles, incident runbook, and SDK overview so writers can drop content immediately with hash notes. | Project Mgmt | +| 2025-12-05 | Added `SHA256SUMS` placeholders for Md.IX doc folders (airgap, sdks, signals, policy, ui, api, runbooks) to keep determinism workflow ready for incoming assets. | Project Mgmt | +| 2025-12-05 | Added language-specific scaffolds to SDK guides (TS/Python/Go/Java) to reduce time-to-first-draft once generator outputs arrive. | Project Mgmt | +| 2025-12-05 | Added escalation action (escalate on 2025-12-13 if inputs miss due dates) and risk mitigation for schedule slip. | Project Mgmt | +| 2025-12-06 | Added reminder action (pings starting 2025-12-09) to ensure Md.IX inputs land on time. | Project Mgmt | diff --git a/docs/implplan/SPRINT_0310_0001_0010_docs_tasks_md_x.md b/docs/implplan/SPRINT_0310_0001_0010_docs_tasks_md_x.md index 5fb5de4ec..55a86cc52 100644 --- a/docs/implplan/SPRINT_0310_0001_0010_docs_tasks_md_x.md +++ b/docs/implplan/SPRINT_0310_0001_0010_docs_tasks_md_x.md @@ -75,6 +75,7 @@ | Open working branch `feature/docs-mdx-skeletons` with placeholder files and TODO callouts | Docs Guild | 2025-12-07 | DONE | Branch created for review; stubs/TODOs committed there. | | Draft outline headings for tenancy trio, reachability guide, VEX set, scanner engine/bench, contract-testing | Docs Guild | 2025-12-07 | DONE | Skeleton headings and TODO callouts laid down. | | Prepare fallback “TBD-tagged” placeholder PR if inputs slip past 2025-12-09 check-in | Docs Guild | 2025-12-09 | PLANNED | Ensures docs land with explicit TBDs rather than missing coverage. | +| Commit & push branch `feature/docs-mdx-skeletons` once credentials/hook window available | Docs Guild | 2025-12-06 | PLANNED | Local commit/push pending; staging is ready. | ## Decisions & Risks | Risk | Impact | Mitigation | Owner | @@ -95,4 +96,5 @@ | 2025-12-05 | Drafted skeleton docs for reachability, surface, tenancy set, CLI/API auth, ABAC overlays, contract testing, VEX series, and scanner bench tracks; advanced related tasks to DOING while inputs remain pending. | Project management | | 2025-12-05 | Recorded progress in Action Tracker: stub files landed; outlines complete; branch creation deferred unless reviewers request. | Project management | | 2025-12-05 | Created branch `feature/docs-mdx-skeletons` to stage skeleton work for review. | Project management | +| 2025-12-05 | Commit/push still pending (credentials/hook window); all files staged on `feature/docs-mdx-skeletons`. | Project management | | 2025-12-06 | Scheduled 2025-12-07 skeleton-sync and defined working branch name for placeholders. | Project management | diff --git a/docs/implplan/SPRINT_0311_0001_0001_docs_tasks_md_xi.md b/docs/implplan/SPRINT_0311_0001_0001_docs_tasks_md_xi.md index c24731923..53e9bd28e 100644 --- a/docs/implplan/SPRINT_0311_0001_0001_docs_tasks_md_xi.md +++ b/docs/implplan/SPRINT_0311_0001_0001_docs_tasks_md_xi.md @@ -23,19 +23,19 @@ ## Delivery Tracker | # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | --- | --- | --- | --- | --- | --- | -| 1 | DOCS-VULN-29-001 | TODO | Await GRAP0101 domain model freeze for Vuln Explorer overview. | Docs Guild · Vuln Explorer Guild | Publish `/docs/vuln/explorer-overview.md` covering domain model, identities, AOC guarantees, workflow summary. | -| 2 | DOCS-VULN-29-002 | TODO | Blocked on #1 content/storyboard. | Docs Guild · Console Guild | Write `/docs/vuln/explorer-using-console.md` with workflows, screenshots, keyboard shortcuts, saved views, deep links. | -| 3 | DOCS-VULN-29-003 | TODO | Needs API schema + query examples after #2. | Docs Guild · Vuln Explorer API Guild | Author `/docs/vuln/explorer-api.md` (endpoints, query schema, grouping, errors, rate limits). | -| 4 | DOCS-VULN-29-004 | TODO | Requires CLI samples + policy overlays from #3. | Docs Guild · DevEx/CLI Guild | Publish `/docs/vuln/explorer-cli.md` with command reference, samples, exit codes, CI snippets. | -| 5 | DOCS-VULN-29-005 | TODO | Depends on CLI flow (#4) and ledger schema inputs. | Docs Guild · Findings Ledger Guild | Write `/docs/vuln/findings-ledger.md` detailing event schema, hashing, Merkle roots, replay tooling. | -| 6 | DOCS-VULN-29-006 | TODO | Needs updated signals/sim semantics from #5. | Docs Guild · Policy Guild | Update `/docs/policy/vuln-determinations.md` for new rationale, signals, simulation semantics. | -| 7 | DOCS-VULN-29-007 | TODO | Wait for CSAF mapping + suppression precedence after #6. | Docs Guild · Excititor Guild | Publish `/docs/vex/explorer-integration.md` covering CSAF mapping, suppression precedence, status semantics. | -| 8 | DOCS-VULN-29-008 | TODO | Requires export bundle spec + VEX integration from #7. | Docs Guild · Concelier Guild | Publish `/docs/advisories/explorer-integration.md` covering key normalization, withdrawn handling, provenance. | -| 9 | DOCS-VULN-29-009 | TODO | Needs SBOM/vuln scope guidance following #8. | Docs Guild · SBOM Service Guild | Author `/docs/sbom/vuln-resolution.md` detailing version semantics, scope, paths, safe version hints. | -| 10 | DOCS-VULN-29-010 | TODO | Await DevOps telemetry plan after #9. | Docs Guild · Observability Guild | Publish `/docs/observability/vuln-telemetry.md` (metrics, logs, tracing, dashboards, SLOs). | -| 11 | DOCS-VULN-29-011 | TODO | Requires security review + role matrix after #10. | Docs Guild · Security Guild | Create `/docs/security/vuln-rbac.md` for roles, ABAC policies, attachment encryption, CSRF. | -| 12 | DOCS-VULN-29-012 | TODO | Depends on policy overlay outputs after #11. | Docs Guild · Ops Guild | Write `/docs/runbooks/vuln-ops.md` (projector lag, resolver storms, export failures, policy activation). | -| 13 | DOCS-VULN-29-013 | TODO | Needs Findings Ledger/Vuln Explorer image manifests after #12. | Docs Guild · Deployment Guild | Update `/docs/install/containers.md` with Findings Ledger & Vuln Explorer API images, manifests, resource sizing, health checks. | +| 1 | DOCS-VULN-29-001 | DOING | Outline stub drafted at `docs/vuln/explorer-overview.md`; awaiting GRAP0101 domain model freeze. | Docs Guild · Vuln Explorer Guild | Publish `/docs/vuln/explorer-overview.md` covering domain model, identities, AOC guarantees, workflow summary. | +| 2 | DOCS-VULN-29-002 | TODO | Blocked on #1 content; draft stub at `docs/vuln/explorer-using-console.md` pending assets. | Docs Guild · Console Guild | Write `/docs/vuln/explorer-using-console.md` with workflows, screenshots, keyboard shortcuts, saved views, deep links. | +| 3 | DOCS-VULN-29-003 | TODO | Draft stub at `docs/vuln/explorer-api.md`; needs GRAP0101 schema + asset samples after #2. | Docs Guild · Vuln Explorer API Guild | Author `/docs/vuln/explorer-api.md` (endpoints, query schema, grouping, errors, rate limits). | +| 4 | DOCS-VULN-29-004 | TODO | Stub at `docs/vuln/explorer-cli.md`; awaiting API schema + CLI samples from #3. | Docs Guild · DevEx/CLI Guild | Publish `/docs/vuln/explorer-cli.md` with command reference, samples, exit codes, CI snippets. | +| 5 | DOCS-VULN-29-005 | TODO | Stub at `docs/vuln/findings-ledger.md`; awaits GRAP0101 + security review + CLI flow (#4). | Docs Guild · Findings Ledger Guild | Write `/docs/vuln/findings-ledger.md` detailing event schema, hashing, Merkle roots, replay tooling. | +| 6 | DOCS-VULN-29-006 | TODO | Stub at `docs/policy/vuln-determinations.md`; awaiting signals/sim semantics from #5 + DevOps plan. | Docs Guild · Policy Guild | Update `/docs/policy/vuln-determinations.md` for new rationale, signals, simulation semantics. | +| 7 | DOCS-VULN-29-007 | TODO | Stub at `docs/vex/explorer-integration.md`; waiting on CSAF mapping + suppression precedence after #6. | Docs Guild · Excititor Guild | Publish `/docs/vex/explorer-integration.md` covering CSAF mapping, suppression precedence, status semantics. | +| 8 | DOCS-VULN-29-008 | TODO | Stub at `docs/advisories/explorer-integration.md`; requires export bundle spec + VEX integration from #7. | Docs Guild · Concelier Guild | Publish `/docs/advisories/explorer-integration.md` covering key normalization, withdrawn handling, provenance. | +| 9 | DOCS-VULN-29-009 | TODO | Stub at `docs/sbom/vuln-resolution.md`; needs SBOM/vuln scope guidance following #8. | Docs Guild · SBOM Service Guild | Author `/docs/sbom/vuln-resolution.md` detailing version semantics, scope, paths, safe version hints. | +| 10 | DOCS-VULN-29-010 | TODO | Stub at `docs/observability/vuln-telemetry.md`; awaiting DevOps telemetry plan after #9. | Docs Guild · Observability Guild | Publish `/docs/observability/vuln-telemetry.md` (metrics, logs, tracing, dashboards, SLOs). | +| 11 | DOCS-VULN-29-011 | TODO | Stub at `docs/security/vuln-rbac.md`; requires security review + role matrix after #10. | Docs Guild · Security Guild | Create `/docs/security/vuln-rbac.md` for roles, ABAC policies, attachment encryption, CSRF. | +| 12 | DOCS-VULN-29-012 | TODO | Stub at `docs/runbooks/vuln-ops.md`; depends on policy overlay outputs after #11. | Docs Guild · Ops Guild | Write `/docs/runbooks/vuln-ops.md` (projector lag, resolver storms, export failures, policy activation). | +| 13 | DOCS-VULN-29-013 | TODO | Pending images/manifests after #12; will update existing `/docs/install/containers.md` when available (no stub created to avoid conflicts). | Docs Guild · Deployment Guild | Update `/docs/install/containers.md` with Findings Ledger & Vuln Explorer API images, manifests, resource sizing, health checks. | ## Wave Coordination - Single wave (Md.XI) covering Vuln Explorer + Findings Ledger docs; sequencing follows Delivery Tracker dependencies. @@ -58,9 +58,12 @@ ## Action Tracker | Action | Owner | Due | Status | | --- | --- | --- | --- | -| Collect GRAP0101 contract snapshot for Vuln Explorer overview. | Docs Guild | 2025-12-08 | Open | -| Request export bundle spec + provenance notes for advisories integration. | Concelier Guild | 2025-12-12 | Open | -| Prepare hash manifest template for screenshots/payloads under `docs/assets/vuln-explorer/`. | Docs Guild | 2025-12-10 | Open | +| Collect GRAP0101 contract snapshot for Vuln Explorer overview. | Docs Guild | 2025-12-08 | In Progress | +| Request export bundle spec + provenance notes for advisories integration. | Concelier Guild | 2025-12-12 | In Progress | +| Prepare hash manifest template for screenshots/payloads under `docs/assets/vuln-explorer/`. | Docs Guild | 2025-12-10 | DONE | +| Request console/UI/CLI asset drop (screens, payloads, samples) for DOCS-VULN-29-002..004. | Vuln Explorer Guild · Console Guild · DevEx/CLI Guild | 2025-12-09 | In Progress | +| Secure DevOps telemetry plan for Vuln Explorer metrics/logs/traces (task #10). | DevOps Guild | 2025-12-16 | Open | +| Security review for RBAC/attachment token wording (task #11) and hashing posture. | Security Guild | 2025-12-18 | Open | ## Decisions & Risks ### Decisions @@ -79,3 +82,19 @@ | Date (UTC) | Update | Owner | | --- | --- | --- | | 2025-12-05 | Normalised sprint to docs/implplan template; renamed file to `SPRINT_0311_0001_0001_docs_tasks_md_xi.md`; no task status changes. | Project Mgmt | +| 2025-12-05 | Kicked off Md.XI: moved DOCS-VULN-29-001 to DOING; drafting outline using existing Vuln Explorer architecture notes while waiting on GRAP0101 contract. | Project Mgmt | +| 2025-12-05 | Marked GRAP0101 contract collection as In Progress; prepped outline structure to receive contract inputs and planned hash manifest template location under `docs/assets/vuln-explorer/`. | Project Mgmt | +| 2025-12-05 | Created hash manifest placeholder `docs/assets/vuln-explorer/SHA256SUMS` to keep deterministic captures ready; marked action as DONE. | Project Mgmt | +| 2025-12-05 | Initiated outreach for export bundle spec/provenance notes (Concelier Guild) to unblock DOCS-VULN-29-008 and downstream SBOM/observability/install docs; action now In Progress. | Project Mgmt | +| 2025-12-05 | Requested console/UI/CLI asset drop (screens, payloads, samples) to unblock DOCS-VULN-29-002..004; tracking in Action Tracker with 2025-12-09 due. | Project Mgmt | +| 2025-12-05 | Drafted outline stub for DOCS-VULN-29-001 at `docs/vuln/explorer-overview.md`; placeholders marked pending GRAP0101 and asset drops; kept task at DOING. | Docs Guild | +| 2025-12-05 | Enriched overview stub with current architecture details (entities, ABAC scopes, workflow, AOC chain) while retaining GRAP0101 placeholders; no status change to DOCS-VULN-29-001. | Docs Guild | +| 2025-12-05 | Added console guide stub `docs/vuln/explorer-using-console.md`; retains TODO status until GRAP0101 + UI assets arrive; noted hash requirements. | Docs Guild | +| 2025-12-05 | Added API guide stub `docs/vuln/explorer-api.md`; waiting on GRAP0101 field names and asset payloads; DOCS-VULN-29-003 remains TODO. | Docs Guild | +| 2025-12-05 | Added CLI guide stub `docs/vuln/explorer-cli.md`; pending API schema + CLI samples; DOCS-VULN-29-004 stays TODO. | Docs Guild | +| 2025-12-05 | Added findings ledger doc stub `docs/vuln/findings-ledger.md`; pending GRAP0101 alignment and security review; DOCS-VULN-29-005 remains TODO. | Docs Guild | +| 2025-12-05 | Added policy determinations stub `docs/policy/vuln-determinations.md`; awaiting signals/simulation semantics and DevOps rollout; DOCS-VULN-29-006 remains TODO. | Docs Guild | +| 2025-12-05 | Added stubs for VEX integration, advisories integration, SBOM resolution, telemetry, RBAC, and ops runbook (`docs/vex/explorer-integration.md`, `docs/advisories/explorer-integration.md`, `docs/sbom/vuln-resolution.md`, `docs/observability/vuln-telemetry.md`, `docs/security/vuln-rbac.md`, `docs/runbooks/vuln-ops.md`); tasks #7–#12 remain TODO pending upstream inputs. | Docs Guild | +| 2025-12-05 | Added Action Tracker items for telemetry plan (DevOps) and security review (RBAC/attachments hashing) to unblock tasks #10–#11; statuses Open. | Project Mgmt | +| 2025-12-05 | Filled additional architecture-aligned details into overview and VEX integration stubs (VEX-first ordering, workflow refinement); tasks remain DOING/TODO awaiting GRAP0101 and assets. | Docs Guild | +| 2025-12-05 | Added hash capture checklists to console/API/CLI/ledger stubs to accelerate deterministic publishing once assets land; task statuses unchanged. | Docs Guild | diff --git a/docs/modules/cli/guides/reachability.md b/docs/modules/cli/guides/reachability.md new file mode 100644 index 000000000..0ab271955 --- /dev/null +++ b/docs/modules/cli/guides/reachability.md @@ -0,0 +1,15 @@ +# CLI Reachability Guide (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Command reference (new reachability commands). +- Automation recipes/CI snippets. +- Exit codes and error handling. +- Sample outputs with hashes for fixtures. diff --git a/docs/modules/cli/guides/risk.md b/docs/modules/cli/guides/risk.md new file mode 100644 index 000000000..8b62cdcb8 --- /dev/null +++ b/docs/modules/cli/guides/risk.md @@ -0,0 +1,17 @@ +# CLI Risk Workflows (outline) + +- TBD pending risk API + UI flows; include commands, exit codes, automation recipes. + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Command reference (risk create/simulate/export/verify). +- Exit codes and error semantics. +- Automation/CI recipes. +- Sample inputs/outputs (hashes alongside artifacts). diff --git a/docs/modules/signals/evidence/README.md b/docs/modules/signals/evidence/README.md index def612ca9..29ffec7a9 100644 --- a/docs/modules/signals/evidence/README.md +++ b/docs/modules/signals/evidence/README.md @@ -1,6 +1,6 @@ # Signals DSSE Evidence Staging (runtime/signals gaps) -Artifacts prepared 2025-12-01 (UTC) for DSSE signing and Evidence Locker ingest: +Artifacts prepared 2025-12-05 (UTC) for DSSE signing and Evidence Locker ingest: | Artifact | Path | Predicate | |----------|------|-----------| @@ -53,21 +53,49 @@ For production signing without CI: ```bash # Option 1: Place key file cp /path/to/production.key tools/cosign/cosign.key -OUT_DIR=evidence-locker/signals/2025-12-01 tools/cosign/sign-signals.sh +OUT_DIR=evidence-locker/signals/2025-12-05 tools/cosign/sign-signals.sh # Option 2: Use base64 env var export COSIGN_PRIVATE_KEY_B64=$(cat production.key | base64 -w0) export COSIGN_PASSWORD=your-password -OUT_DIR=evidence-locker/signals/2025-12-01 tools/cosign/sign-signals.sh +OUT_DIR=evidence-locker/signals/2025-12-05 tools/cosign/sign-signals.sh ``` ## Evidence Locker Paths Post-signing, artifacts go to: -- `evidence-locker/signals/2025-12-01/confidence_decay_config.sigstore.json` -- `evidence-locker/signals/2025-12-01/unknowns_scoring_manifest.sigstore.json` -- `evidence-locker/signals/2025-12-01/heuristics_catalog.sigstore.json` -- `evidence-locker/signals/2025-12-01/SHA256SUMS` +- `evidence-locker/signals/2025-12-05/confidence_decay_config.sigstore.json` +- `evidence-locker/signals/2025-12-05/unknowns_scoring_manifest.sigstore.json` +- `evidence-locker/signals/2025-12-05/heuristics_catalog.sigstore.json` +- `evidence-locker/signals/2025-12-05/SHA256SUMS` + +Deterministic tarball (dev-key signing 2025-12-05) for locker push/testing: + +``` +evidence-locker/signals/2025-12-05/signals-evidence.tar sha256=a17910b8e90aaf44d4546057db22cdc791105dd41feb14f0c9b7c8bac5392e0d +``` + +Verification helper: + +``` +./tools/signals-verify-evidence-tar.sh [path/to/signals-evidence.tar] +``` + +Local locker upload (once creds are available): + +```bash +export EVIDENCE_LOCKER_URL="" +export CI_EVIDENCE_LOCKER_TOKEN="" +./tools/signals-upload-evidence.sh +# or to push both Signals and Zastava in one go +./tools/upload-all-evidence.sh +``` + +CI upload path: +- Workflow: `.gitea/workflows/signals-evidence-locker.yml` +- Secrets required: `CI_EVIDENCE_LOCKER_TOKEN`, `EVIDENCE_LOCKER_URL` +- Artifact name: `signals-evidence-2025-12-05` +- Retention input (optional): `retention_target` (default 180 days) ## Post-Signing Checklist diff --git a/docs/modules/taskrunner/architecture.md b/docs/modules/taskrunner/architecture.md index 7281fb4fa..5b2cdd035 100644 --- a/docs/modules/taskrunner/architecture.md +++ b/docs/modules/taskrunner/architecture.md @@ -83,7 +83,7 @@ ``` ## 12. Gap Remediation (TP1–TP10, 2025-12) -- **Canonical plan hash (TP1):** Plan hash is `sha256` over `plan.canonicalPlanPath` (normalized JSON, stable key ordering, UTF-8). Hash and canonical plan file are shipped in offline bundles and verified by `scripts/packs/verify_offline_bundle.py`. +- **Canonical plan hash (TP1):** Plan hash is `sha256:<64-hex>` over `plan.canonicalPlanPath` (normalized JSON, stable key ordering, UTF-8). Hash and canonical plan file are shipped in offline bundles and verified by `scripts/packs/verify_offline_bundle.py`. - **Inputs lock (TP2):** Task Runner emits `inputs.lock` capturing resolved inputs + redacted secret placeholders; stored in evidence bundles and listed under `hashes[]` in offline manifests. - **Approval ledger (TP3):** Approval decisions are DSSE-signed, embedding `runId`, `gateId`, `planHash`, and `tenantId`. Approval endpoints reject mismatched plan hashes or missing DSSE envelopes. - **Secret redaction (TP4):** Evidence/transcripts apply the redaction policy referenced in `security.secretsRedactionPolicy`; secrets are hashed or blanked, never logged in clear text. diff --git a/docs/modules/zastava/SHA256SUMS b/docs/modules/zastava/SHA256SUMS index a4da92ea7..a4702c071 100644 --- a/docs/modules/zastava/SHA256SUMS +++ b/docs/modules/zastava/SHA256SUMS @@ -14,4 +14,4 @@ de9b24675a0a758e40647844a31a13a1be1667750a39fe59465b0353fd0dddd9 exports/observ f69f953c78134ef504b870cea47ba62d5e37a7a86ec0043d824dcb6073cd43fb kit/verify.sh 1cf8f0448881d067e5e001a1dfe9734b4cdfcaaf16c3e9a7321ceae56e4af8f2 kit/README.md eaba054428fa72cd9476cffe7a94450e4345ffe2e294e9079eb7c3703bcf7df0 kit/ed25519.pub -40a40b31480d876cf4487d07ca8d8b5166c7df455bef234e2c1861b7b3dc7e3b evidence/README.md +ffe919a8b96619c1c5cf5bb8f7a7a61b61984d0f97802c131cf66e182f2d705f evidence/README.md diff --git a/docs/modules/zastava/evidence/README.md b/docs/modules/zastava/evidence/README.md index f2bdfd9fd..c96172ad1 100644 --- a/docs/modules/zastava/evidence/README.md +++ b/docs/modules/zastava/evidence/README.md @@ -23,11 +23,33 @@ Public key copy: `docs/modules/zastava/kit/ed25519.pub`. Local staging: all files above are present under `evidence-locker/zastava/2025-12-02/` in the repo root, ready for locker upload/mirroring. +Deterministic tarball (built with `tar --sort=name --mtime='UTC 1970-01-01' --owner=0 --group=0 --numeric-owner` over payloads + DSSE): + +``` +evidence-locker/zastava/2025-12-02/zastava-evidence.tar sha256=e1d67424273828c48e9bf5b495a96c2ebcaf1ef2c308f60d8b9c62b8a1b735ae +``` + +Verification helper (uses the hash above and inner SHA256SUMS): + +``` +./tools/zastava-verify-evidence-tar.sh [path/to/zastava-evidence.tar] +``` + +Upload (once locker creds exist): + +```bash +export EVIDENCE_LOCKER_URL="" +export CI_EVIDENCE_LOCKER_TOKEN="" +./tools/upload-all-evidence.sh # pushes both Zastava and Signals bundles +``` + Helper script for manual push (expects `EVIDENCE_LOCKER_URL` and `CI_EVIDENCE_LOCKER_TOKEN`): ```bash tools/zastava-upload-evidence.sh ``` +Packaging is deterministic (`tar --sort=name --mtime='UTC 1970-01-01' --owner=0 --group=0 --numeric-owner`) and prints the tarball SHA256 before upload. Ensure `kit/verify.sh` passes before pushing. + ## CI delivery note - Locker upload in CI requires a write credential (e.g., `CI_EVIDENCE_LOCKER_TOKEN`) with access to the `evidence-locker/zastava/` namespace. - If the secret is absent, perform a manual upload from the staged folder and record the locker URI in the sprint log. diff --git a/docs/observability/vuln-telemetry.md b/docs/observability/vuln-telemetry.md new file mode 100644 index 000000000..80dcff220 --- /dev/null +++ b/docs/observability/vuln-telemetry.md @@ -0,0 +1,18 @@ +# Vuln Telemetry (Md.XI draft) + +> Status: DRAFT — waiting on DevOps telemetry plan and GRAP0101. Keep TODO until metrics/logs finalized and hashed. + +## Scope +- Metrics, logs, tracing, dashboards, SLOs for Vuln Explorer. + +## Dependencies +- DevOps telemetry plan (due 2025-12-16 sync). +- GRAP0101 identifiers for labels. + +## Outline +- Metrics: findings_open_total, mttr, triage_actions, report_generation_seconds. +- Logs: structured fields (findingId, artifactId, advisory, policyVersion, actor, actionType). +- Traces: key spans; sampling guidance. +- Dashboards: to be added with hashes. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/onboarding/dev-quickstart.md b/docs/onboarding/dev-quickstart.md index 2dce02dee..645d320fc 100644 --- a/docs/onboarding/dev-quickstart.md +++ b/docs/onboarding/dev-quickstart.md @@ -18,6 +18,13 @@ Core concepts: - **Trust lattice:** Merges vendor VEX, runtime signals, configs, etc. into a single deterministic verdict. - **Audit trail:** Every decision is reproducible from stored inputs and proofs. +**Offline/determinism essentials (read first):** + +- Install from the curated offline kit (no network); pin SDK + tool versions in `inputs.lock`. +- Use DSSE-signed configs and keep signing keys in offline `~/.stellaops/keys` with short-lived tokens. +- Run `dotnet format` / `dotnet test` with `--blame-crash --blame-hang` using fixed seeds (`Random(1337)`) to avoid flakiness. +- Capture DB/queue matrix upfront: MongoDB (pinned version), optional Postgres slices, and local cache paths; set `TZ=UTC` for all runs. + If you think “content-addressed trust pipeline for SBOMs + VEX,” you’re in the right mental model. --- @@ -39,6 +46,15 @@ Start by opening these projects **in order**: 6. `src/StellaOps.Shared/CanonicalModel/` Canonical entities & graph IDs. **Read this carefully** – it underpins determinism. +Starter issues to grab on day 1 (all offline-friendly): + +- Add DSSE verification to a small CLI path (`stella verify --local-only`). +- Extend `inputs.lock` examples with a pinned scanner/DB matrix. +- Write a deterministic unit test for canonical ID ordering. +- Improve `docs/` cross-links (Developer Quickstart ↔ platform architecture) and ensure `docs:` trailer appears in commits. + +UI note: Console remains in flux; focus on backend determinism first, then follow UI sprints 0209/0215 for micro-interactions and proof-linked VEX updates. + Helpful docs: - `docs/modules/platform/*` – protocols (DSSE envelopes, lattice terms, trust receipts). diff --git a/docs/ops/evidence-locker-handoff.md b/docs/ops/evidence-locker-handoff.md new file mode 100644 index 000000000..6bc2a1a92 --- /dev/null +++ b/docs/ops/evidence-locker-handoff.md @@ -0,0 +1,41 @@ +# Evidence Locker Handoff (Signals & Zastava) + +## Inputs required (from Ops) +- `EVIDENCE_LOCKER_URL` (base URL, no trailing slash) +- `CI_EVIDENCE_LOCKER_TOKEN` (Bearer token with write to `zastava/*` and `signals/*`) +- **Signals production signing key** for final re-sign (one of): + - `COSIGN_PRIVATE_KEY_B64` (base64 of private key) + optional `COSIGN_PASSWORD`, or + - key file at `tools/cosign/cosign.key` + password. + +## What’s ready (deterministic artefacts) +- Zastava tar: `evidence-locker/zastava/2025-12-02/zastava-evidence.tar` + - sha256: `e1d67424273828c48e9bf5b495a96c2ebcaf1ef2c308f60d8b9ac019cf0f1c9` +- Signals tar (dev key): `evidence-locker/signals/2025-12-05/signals-evidence.tar` + - sha256: `a17910b8e90aaf44d4546057db22cdc791105dd41feb14f0c9b7c8bac5392e0d` + +## Publish both bundles (once URL/token are available) +```bash +export EVIDENCE_LOCKER_URL="" +export CI_EVIDENCE_LOCKER_TOKEN="" +./tools/upload-all-evidence.sh +``` + +## Verify locally (hash + inner SHA lists) +- Zastava: `./tools/zastava-verify-evidence-tar.sh [path/to/zastava-evidence.tar]` +- Signals: `./tools/signals-verify-evidence-tar.sh [path/to/signals-evidence.tar]` + +## Re-sign Signals for production trust (optional but recommended) +```bash +export COSIGN_PRIVATE_KEY_B64="" +export COSIGN_PASSWORD="" +OUT_DIR=evidence-locker/signals/2025-12-05 \ + tools/cosign/sign-signals.sh + +# Rebuild + upload tar +./tools/signals-upload-evidence.sh +``` + +## Notes +- All packaging is deterministic (`tar --sort=name --mtime='UTC 1970-01-01' --owner=0 --group=0 --numeric-owner`). +- Tlog upload is disabled for offline parity; Evidence Locker trust comes from the provided keys. +- Upload scripts exit non-zero on hash mismatch to prevent pushing corrupted artefacts. diff --git a/docs/policy/SHA256SUMS b/docs/policy/SHA256SUMS new file mode 100644 index 000000000..8db6848c0 --- /dev/null +++ b/docs/policy/SHA256SUMS @@ -0,0 +1 @@ +# Placeholder hashes; replace with real asset sums when inputs arrive diff --git a/docs/policy/signals-weighting.md b/docs/policy/signals-weighting.md new file mode 100644 index 000000000..c0d9134f1 --- /dev/null +++ b/docs/policy/signals-weighting.md @@ -0,0 +1,15 @@ +# Signals Weighting (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- SPL predicate patterns and weighting strategy. +- Default weights and configurable knobs. +- Examples (policy snippets/recipes) with deterministic ordering. +- Hashes for any example bundles or fixtures. diff --git a/docs/policy/vuln-determinations.md b/docs/policy/vuln-determinations.md new file mode 100644 index 000000000..9eefc51c2 --- /dev/null +++ b/docs/policy/vuln-determinations.md @@ -0,0 +1,42 @@ +# Vulnerability Determinations (Md.XI draft) + +> Status: DRAFT (awaiting GRAP0101 + findings ledger doc + DevOps rollout); keep TODO until signals/simulation semantics confirmed. + +## Scope +- Capture rationale and signals used to determine vulnerability states in Vuln Explorer (policy overlay, VEX, reachability, DevOps signals). +- Document simulation semantics and precedence/weighting; align with Policy Engine gateways. + +## Inputs & Dependencies +| Input | Status | Notes | +| --- | --- | --- | +| Findings Ledger doc (DOCS-VULN-29-005) | in progress | Must align on field names/hashes. | +| DevOps rollout plan (telemetry + signals) | pending | Needed for final weighting and thresholds. | +| GRAP0101 contract | pending | Confirms identifiers used in policies. | + +## Signals (draft list) +- Advisory severity + KEV flag. +- Reachability: call graph + runtime facts (from Signals module) — weighting TBD. +- VEX status: CSAF-mapped decisions (NOT_AFFECTED, AFFECTED_*). +- SBOM component context: version range, path, scope (prod/dev/test). +- Observability: error/traffic indicators (if enabled) — DevOps to confirm. + +## Simulation Semantics (draft) +- Deterministic evaluation order: VEX > Reachability > Policy gates > Overrides. +- Precedence to `NOT_AFFECTED` when confidence ≥ threshold (TBD) unless explicit policy override. +- Shadow/simulation runs mirror production gates but do not emit notifications; results stored with flag `simulation=true` and excluded from audit unless promoted. + +## Policy Outputs +- Status mapping: {`blocked`, `warn`, `pass`} with rationale bundle references. +- Required fields in outputs: `findingId`, `policyVersion`, `signalsUsed`, `weighting`, `explainBundleRef`, `timestamp` (UTC, ISO-8601). +- Determinism: stable sorting by `findingId` then `policyVersion`; hashes recorded when examples added. + +## Offline/Determinism Notes +- All sample policy outputs must be hashed in `docs/assets/vuln-explorer/SHA256SUMS`. +- Use fixed fixture inputs; avoid live metrics; keep ordering stable. + +## Open Items +- Finalize signal weights and thresholds after DevOps rollout plan. +- Insert concrete examples once Findings Ledger and GRAP0101 finalize fields. +- Add simulation vs. production side-by-side examples with hashes. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/process/acceptance-guardrails-checklist.md b/docs/process/acceptance-guardrails-checklist.md new file mode 100644 index 000000000..324654c7e --- /dev/null +++ b/docs/process/acceptance-guardrails-checklist.md @@ -0,0 +1,12 @@ +# Acceptance Tests Pack & Guardrails Checklist (Stub) + +Use with `SPRINT_0300_0001_0001_documentation_process.md` task 4 (AT1–AT10). + +- [ ] AT schema version pinned; schema file signed (DSSE) and stored with pack. +- [ ] Inputs locked (`inputs.lock`) with scanner/db versions and seeds. +- [ ] Fixtures reproducible offline; no external network calls. +- [ ] Admission/VEX/auth coverage present; replay parity check documented. +- [ ] Gating thresholds defined and enforced in CI. +- [ ] Reporting SLOs captured; failure triage path documented. +- [ ] DSSE provenance for packs and results; signatures verified in CI (see `pack.dsse.json`). +- [ ] README links added to sprint docs and AGENTS where relevant. diff --git a/docs/process/evidence-suppression-gaps.md b/docs/process/evidence-suppression-gaps.md new file mode 100644 index 000000000..f1cea3b9d --- /dev/null +++ b/docs/process/evidence-suppression-gaps.md @@ -0,0 +1,8 @@ +# Evidence & Suppression Patterns (Gaps Stub) + +Use with sprint task 9 (EVIDENCE-PATTERNS-GAPS-300-016) and advisory `30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md`. + +- TODO: Canonical schema for evidence, suppression, export; align across modules. +- TODO: Unified justification/expiry taxonomy and visibility policy. +- TODO: Offline evidence-kit packaging plan with signed manifests. +- TODO: Fixtures and observability metrics to be added; ensure deterministic ordering. diff --git a/docs/process/implementor-guidelines.md b/docs/process/implementor-guidelines.md index faeb61056..68614043b 100644 --- a/docs/process/implementor-guidelines.md +++ b/docs/process/implementor-guidelines.md @@ -1,32 +1,12 @@ -# Implementor Guidelines (checklist draft) +# Implementor Guidelines (Stub) -Reference: `docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md` (IG1–IG10) and Sprint 300 task IMPLEMENTOR-GAPS-300-018. +Use with sprint task 18 (IMPLEMENTOR-GAPS-300-018). -## CI lint & docs linkage (IG7) -- Require PRs to either touch referenced docs or set `docs: n/a` with justification. -- Sample hook (to implement): `.git/hooks/pre-commit` invoking `scripts/lint-docs-touch.sh`. -- Fail CI if sprint/AGENTS references are missing for the module being changed. - -## Determinism & offline posture (IG2, IG3) -- Default to offline/no-network; flag any outbound calls in tests. -- Set deterministic env vars (`TZ=UTC`, `LC_ALL=C`, `PYTHONHASHSEED=0`, etc.). -- Enforce pinned tool/DB versions and stable ordering in outputs. - -## Secrets & provenance (IG5, IG9) -- Run secret scan pre-commit/CI; forbid committing `.env`/keys. -- DSSE/provenance required where predicates exist; verify signatures in CI when fixtures are present. - -## Schema/versioning control (IG1) -- Any schema change requires version bump + changelog entry; add canonical serialization tests. -- Store schemas alongside fixtures where practical. - -## Performance/quota (IG6) -- Define perf budget per service (P95 latency/CPU/memory) and add smoke tests on reference profile. - -## Boundaries & shared libs (IG8) -- Document allowed shared libraries per module; add codeowners/analyzer rules to block cross-boundary calls. - -## Evidence & documentation sync (IG10) -- AGENTS files and sprint docs must link to this checklist; update both when rules change. - -> Replace this draft with full scripts and enforcement once IMPLEMENTOR-GAPS-300-018 is executed. +- Determinism/offline: pin toolchains, seeds, inputs.lock; no live network in examples. +- Provenance: DSSE-sign schema and results; keep tenant scoping explicit. +- Docs touch rule: enforce `docs:` tag (value or `docs: n/a`) in commits/PRs. +- Boundary rules: respect module working directories and shared-lib allowlist. +- Perf/quota: capture perf budgets and quota impacts when changing hot paths. +- Versioning: schema changes require version bump and changelog note. +- CI lint: `tools/lint/implementor-guidelines.sh` (stub) to be wired into CI; add to pre-commit or CI pipeline when wiring determinism checks. +- Determinism checks: prefer UTC, sorted outputs, pinned seeds; add `inputs.lock` when adding new fixtures or packs. diff --git a/docs/process/plugin-architecture-gaps.md b/docs/process/plugin-architecture-gaps.md new file mode 100644 index 000000000..57b14746a --- /dev/null +++ b/docs/process/plugin-architecture-gaps.md @@ -0,0 +1,10 @@ +# Plugin Architecture Gaps (Stub) + +Use with sprint task 14 (Plugin architecture gaps remediation). + +- TODO: Signed schemas/capability catalog for plugins. +- TODO: Sandbox/resource limits and crash kill-switch rules. +- TODO: Provenance: SBOM + DSSE verification for plugins; offline kit packaging + verify script. +- TODO: Compatibility matrix and dependency/secret rules. +- TODO: Signed plugin index with revocation/CVE data (see `tests/plugins/plugin-index.json`). +- TODO: Determinism harness and fixture plan (see `tests/plugins/README.md`). diff --git a/docs/process/standup-kickstarter-checklist.md b/docs/process/standup-kickstarter-checklist.md new file mode 100644 index 000000000..40218672d --- /dev/null +++ b/docs/process/standup-kickstarter-checklist.md @@ -0,0 +1,13 @@ +# Standup Sprint Kickstarters Checklist (Stub) + +Use with sprint task 22 (STANDUP-GAPS-300-019) and advisory `30-Nov-2025 - Standup Sprint Kickstarters.md`. + +- [ ] Template aligned with `docs/implplan/README.md` sections. +- [ ] Readiness evidence checklist filled (deps, owners, SLOs). +- [ ] Dependency ledger captured with accountable owners. +- [ ] Async/offline workflow defined; time-box/exit rules noted. +- [ ] Execution Log update required at standup close. +- [ ] Decisions & Risks delta captured per session. +- [ ] Metrics collected: blocker clear rate, blocker latency. +- [ ] Lint/checks hook points identified for automation. +- [ ] DSSE-signed standup summary stored with UTC date. diff --git a/docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md b/docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md new file mode 100644 index 000000000..5aba38f43 --- /dev/null +++ b/docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md @@ -0,0 +1,20 @@ +# 29-Nov-2025 · Acceptance Tests Pack and Guardrails + +**Why now:** Guardrail coverage (AT1–AT10) is required before Md.I ladder can proceed; acceptance packs must be deterministic, signed, and offline-ready. + +## Scope +- Publish acceptance test pack schema + checklist for CI/DB/rew definitions. +- Bundle deterministic fixtures (pinned seeds, UTC timestamps) with DSSE provenance. +- Define gating thresholds and replay parity checks for admission/VEX/auth flows. + +## Required artefacts (MVP for DONE) +- Advisory summary (this file) plus checklist stub under `docs/process/` referencing AT1–AT10. +- Links into sprint tracker row 4 (`SPRINT_0300_0001_0001_documentation_process.md`). +- Placeholder fixture pack path reserved under `tests/acceptance/packs/guardrails/` (no network). + +## Determinism & Offline +- Freeze scanner/db versions; record in a `inputs.lock` for the pack. +- All fixtures must be reproducible from seeds; include DSSE envelopes for pack manifests. + +## Next actions +- Add checklist stub and register the pack path; log evidence in sprint Execution Log before 2025-12-08. diff --git a/docs/product-advisories/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md b/docs/product-advisories/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md new file mode 100644 index 000000000..d4b35d2b6 --- /dev/null +++ b/docs/product-advisories/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md @@ -0,0 +1,19 @@ +# 29-Nov-2025 · CVSS v4.0 Momentum in Vulnerability Management + +**Why now:** Vendors (NVD, GitHub, Microsoft, Snyk) are shipping CVSS v4 signals; StellaOps needs awareness to align receipts, reporting, and UI before defaulting to v4 everywhere. + +## Scope +- Brief on adoption signals and compatibility risks when mixing v3.1/v4. +- Map impacts to receipt schemas (`SPRINT_0190_0001_0001_cvss_v4_receipts.md`). +- Identify quick UI/reporting deltas required for transparency. + +## Required artefacts (MVP for DONE) +- This briefing plus linkage in `docs/product-advisories/ADVISORY_INDEX.md` (already indexed). +- Note in sprint Decisions & Risks for CVSS receipts sprints; ensure SPRINT_0300 tracker row 15 records completion. + +## Determinism & Offline +- Keep CVSS vector parsing deterministic; pin scoring library versions in receipts. +- Avoid live API dependency; rely on mirrored NVD feeds or frozen samples. + +## Next actions +- Cross-link to receipts schema draft; add Execution Log entry when briefing is published. diff --git a/docs/product-advisories/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md b/docs/product-advisories/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md new file mode 100644 index 000000000..0e7abda1f --- /dev/null +++ b/docs/product-advisories/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md @@ -0,0 +1,19 @@ +# 29-Nov-2025 · SBOM to VEX Proof Pipeline Blueprint + +**Why now:** The Docs ladder needs a canonical blueprint tying SBOM ingestion to VEX proofs with DSSE/Rekor integration, to unblock downstream module dossier updates. + +## Scope +- Describe DSSE → Rekor v2 → VEX linkage with offline verification steps. +- Capture diagram/stub scripts for proof generation and verification. +- Define inputs.lock/idempotency rules and chain hash recipe. + +## Required artefacts (MVP for DONE) +- Diagram placeholder (`docs/diagrams/sbom-vex-blueprint.svg` reserved) and script stub path `docs/scripts/sbom-vex/verify.sh` (offline, deterministic sorting/hashes). +- Cross-links in `docs/modules/platform/architecture-overview.md` and sprint row 16 completion evidence. + +## Determinism & Offline +- Sorted canonical inputs before hashing; UTC timestamps only when unavoidable, otherwise derive from content. +- No network calls; use bundled Rekor root + mirror snapshot for verification examples. + +## Next actions +- Land the stub diagram/script placeholders and log completion in the sprint Execution Log. diff --git a/docs/product-advisories/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md b/docs/product-advisories/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md new file mode 100644 index 000000000..74d88cdf3 --- /dev/null +++ b/docs/product-advisories/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md @@ -0,0 +1,19 @@ +# 29-Nov-2025 · SCA Failure Catalogue for StellaOps Tests + +**Why now:** Recent regressions show noisy or divergent SCA results; we need a deterministic failure catalogue to anchor acceptance tests and fixture packs. + +## Scope +- Document the five observed regressions (credential leak, Trivy offline DB mismatch, SBOM parity drift, Grype version divergence, inconsistent detection). +- Provide expected signals for acceptance tests and links to fixture locations. +- Drive remediation task SCA-FIXTURE-GAPS-300-014 (FC1–FC10) in the sprint. + +## Required artefacts (MVP for DONE) +- This catalogue plus a pointer to fixture pack root `tests/fixtures/sca/catalogue/` (to be populated with deterministic seeds + DSSE manifests). +- Sprint Execution Log entry for row 17 when published. + +## Determinism & Offline +- Fixtures must pin scanner versions and feeds; include `inputs.lock` and DSSE manifest for each case. +- Results should be normalized (ordering, casing) to avoid flaky comparisons. + +## Next actions +- Create initial fixture directory with README and seed notes; log status in sprint tracker and move row 17 toward DONE. diff --git a/docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md b/docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md new file mode 100644 index 000000000..b331560be --- /dev/null +++ b/docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md @@ -0,0 +1,20 @@ +# 29-Nov-2025 · StellaOps – Mid-Level .NET Onboarding (Quick Start) + +**Why now:** The Docs ladder needs a deterministic, offline-ready quickstart to unblock module dossier refreshes and align mid-level .NET contributors with DSSE/VEX requirements. + +## Scope +- Provide a 1–2 day runway for mid-level .NET engineers to become productive on StellaOps. +- Emphasise determinism, offline posture, DSSE/in-toto usage, and the canonical data model. +- Pair this advisory with the living guide at `docs/onboarding/dev-quickstart.md`. + +## Required artefacts (MVP for DONE) +- Update `docs/onboarding/dev-quickstart.md` with deterministic/offline steps, DSSE/key-handling, and DB matrix pointers. +- Cross-links in `docs/README.md` and `docs/modules/platform/architecture-overview.md` to the quickstart. +- Sprint tracker: `docs/implplan/SPRINT_0300_0001_0001_documentation_process.md` row 3 marked DONE with Execution Log proof. + +## Determinism & Offline +- Use fixed seeds and pinned toolchain versions for any sample commands. +- Avoid live network calls; prefer cached feeds/mirrors and note mirror paths. + +## Next actions +- Land the cross-link updates and note completion in the sprint Execution Log. diff --git a/docs/product-advisories/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md b/docs/product-advisories/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md new file mode 100644 index 000000000..c2bf03b56 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md @@ -0,0 +1,18 @@ +# 30-Nov-2025 · Comparative Evidence Patterns for Stella Ops + +**Why now:** UX and data-model decisions need a grounded comparison of evidence/suppression patterns across major vendors. + +## Scope +- Summarise how Snyk, GitHub, Aqua, Anchore/Grype, and Prisma Cloud handle evidence, suppression, audit/export. +- Feed UX/data-model decisions for VEX, evidence views, and export policies. +- Drives task 23 (EVIDENCE + suppression pattern sync) in sprint tracker. + +## Required artefacts (MVP) +- This brief plus links to any UI or schema follow-ups once drafted. +- Sprint tracker row 23 updated when evidence is logged. + +## Determinism & Offline +- Keep examples deterministic; no live API calls in comparisons; cite cached docs/artefacts where needed. + +## Next actions +- Add schema/UX notes to module docs when ready; log completion in Execution Log. diff --git a/docs/product-advisories/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md b/docs/product-advisories/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md new file mode 100644 index 000000000..5c3864dd4 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md @@ -0,0 +1,18 @@ +# 30-Nov-2025 · Ecosystem Reality Test Cases for StellaOps + +**Why now:** Real incidents (credential leak, offline DB schema mismatch, SBOM parity drift, scanner instability) must translate into deterministic acceptance tests. + +## Scope +- Document the five incidents and expected signals. +- Map each to acceptance tests and fixture paths (`tests/fixtures/sca/catalogue/`). +- Drives ECOSYS-FIXTURES-GAPS-300-017 (ET1–ET10). + +## Required artefacts (MVP) +- This advisory plus fixture root path and acceptance test references. +- Sprint tracker row 21 updated when evidence lands. + +## Determinism & Offline +- Fixtures must pin tool versions and feeds; no live network. + +## Next actions +- Populate fixtures and acceptance specs; log in sprint Execution Log when added. diff --git a/docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md b/docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md new file mode 100644 index 000000000..12499b653 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md @@ -0,0 +1,18 @@ +# 30-Nov-2025 · Implementor Guidelines for Stella Ops + +**Why now:** Contributors need an enforceable checklist that ties SRS, release playbook, and determinism/offline requirements into a CI-enforced guardrail. + +## Scope +- Operational checklist for code and docs changes; mandates determinism, offline posture, provenance, and boundary rules. +- Intended to drive lint/CI that enforces `docs touched → docs: n/a` tagging, schema/versioning control, and perf/quota expectations. + +## Required artefacts (MVP) +- Checklist mapped into `docs/process/implementor-guidelines.md` (to be created/expanded in sprints 18/19 tasks). +- CI lint hook stub path declared (e.g., `tools/lint/implementor-guidelines.sh`). +- Sprint tracker row 18 marked DONE once linked and logged. + +## Determinism & Offline +- Prefer reproducible seeds, pinned toolchain versions, and no live network in examples. + +## Next actions +- Add the checklist doc and CI stub; link from sprint Decisions & Risks where relevant. diff --git a/docs/product-advisories/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md b/docs/product-advisories/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md new file mode 100644 index 000000000..4f92b76f3 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md @@ -0,0 +1,18 @@ +# 30-Nov-2025 · Rekor Receipt Checklist for Stella Ops + +**Why now:** Rekor receipts must be deterministic, tenant-scoped, and verifiable offline for Authority/Sbomer/Vexer flows. + +## Scope +- Field-level ownership map for receipts and bundles. +- Offline verifier expectations and mirror snapshot rules. +- DSSE/receipt schema pointers to be consumed by Authority/Sbomer/Vexer modules. + +## Required artefacts (MVP) +- Checklist page (this file) and cross-link in module docs when schemas land. +- Sprint sync rows in `SPRINT_0300_0001_0001_documentation_process.md` and `SPRINT_0314_0001_0001_docs_modules_authority.md`. + +## Determinism & Offline +- Bundle TSA/time anchors with receipts; prefer mirror snapshots; avoid live log fetches in examples. + +## Next actions +- Publish schema draft and offline verifier stub; update module dossiers accordingly. diff --git a/docs/product-advisories/30-Nov-2025 - Standup Sprint Kickstarters.md b/docs/product-advisories/30-Nov-2025 - Standup Sprint Kickstarters.md new file mode 100644 index 000000000..a1abe3eb4 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Standup Sprint Kickstarters.md @@ -0,0 +1,16 @@ +# 30-Nov-2025 · Standup Sprint Kickstarters + +**Why now:** Day-0 unblockers accelerate sprint readiness and reduce blocker latency for Docs ladder and downstream modules. + +## Scope +- Three kickstarter tasks (scanner regressions, Postgres slice, DSSE/Rekor sweep) with ticket names/owners. +- Alignment with sprint template and readiness checklist expectations. + +## Required artefacts (MVP) +- This advisory; sprint tracker row 22 updated; readiness checklist ties into `docs/implplan/README.md` template. + +## Determinism & Offline +- Keep examples and scripts offline-friendly; pin tool versions. + +## Next actions +- Add readiness checklist snippets to sprint template; log completion in Execution Log when linked. diff --git a/docs/product-advisories/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md b/docs/product-advisories/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md new file mode 100644 index 000000000..07b6f2022 --- /dev/null +++ b/docs/product-advisories/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md @@ -0,0 +1,17 @@ +# 30-Nov-2025 · Unknowns Decay & Triage Heuristics + +**Why now:** Stale “unknown” findings create noise; we need deterministic decay and triage rules with UI/export artifacts. + +## Scope +- Define confidence decay card, triage queue UI, and export artifacts for planning. +- Map to runtime signals sprint (`SPRINT_0140_0001_0001_runtime_signals.md`) and docs tracker row 20. + +## Required artefacts (MVP) +- This brief plus references to UnknownsRegistry docs (to be expanded). +- UI/export snapshot expectations and deterministic decay logic description. + +## Determinism & Offline +- Decay windows and thresholds must be deterministic; exports should be reproducible without live dependencies. + +## Next actions +- Land UI mock/export schema; link into sprint Decisions & Risks and module docs once available. diff --git a/docs/product-advisories/ADVISORY_INDEX.md b/docs/product-advisories/ADVISORY_INDEX.md index 76ea19c72..997b5e878 100644 --- a/docs/product-advisories/ADVISORY_INDEX.md +++ b/docs/product-advisories/ADVISORY_INDEX.md @@ -31,6 +31,15 @@ These are the authoritative advisories to reference for implementation: - **Gaps:** `31-Nov-2025 FINDINGS.md` (FC1–FC10 remediation task SCA-FIXTURE-GAPS-300-014) - **Status:** Captures five real-world regressions/ SBOM gaps for Trivy/Syft/Grype/Snyk and frames test vectors + alarm scenarios for StellaOps acceptance suites. +### Acceptance Tests Pack & Guardrails +- **Canonical:** `29-Nov-2025 - Acceptance Tests Pack and Guardrails.md` +- **Sprint:** SPRINT_0300_0001_0001_documentation_process.md (docs tracker) +- **Related Docs:** + - `docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md` (this briefing) + - `docs/process/acceptance-guardrails-checklist.md` +- **Gaps:** `31-Nov-2025 FINDINGS.md` (AT1–AT10 remediation task AT-GAPS-300-012) +- **Status:** Defines deterministic, signed acceptance packs with replay parity checks and CI gating thresholds for admission/VEX/auth flows. + ### Mid-Level .NET Onboarding (Quick Start) - **Canonical:** `29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md` - **Sprint:** SPRINT_0300_0001_0001_documentation_process.md (docs tracker) diff --git a/docs/product-advisories/archived/AR-REVIVE-PLAN.md b/docs/product-advisories/archived/AR-REVIVE-PLAN.md new file mode 100644 index 000000000..d9839b07d --- /dev/null +++ b/docs/product-advisories/archived/AR-REVIVE-PLAN.md @@ -0,0 +1,8 @@ +# Archived Advisories Revival Plan (Stub) + +Use with sprint task 13 (ARCHIVED-GAPS-300-020). + +- TODO: List candidate archived advisories to revive (SBOM-Provenance-Spine, VB reachability, etc.). +- TODO: Decide canonical schemas/recipes (provenance, reachability, PURL/Build-ID). +- TODO: Document determinism seeds/SLOs, redaction/isolation rules, changelog/signing approach. +- TODO: Mark supersedes/duplicates and PostgreSQL storage blueprint guardrails. diff --git a/docs/risk/api.md b/docs/risk/api.md new file mode 100644 index 000000000..9ce125c00 --- /dev/null +++ b/docs/risk/api.md @@ -0,0 +1,45 @@ +# Risk API (draft outline) + +> Draft scaffold; populate once 67-001 explainability outputs and API publishing workflow are available. Keep examples deterministic; include ETags and error payloads when provided. + +## Purpose +- Document risk-related endpoints for profile management, simulation, scoring results, explainability retrieval, and export. + +## Scope & Audience +- Audience: API consumers, SDK authors, platform integrators. +- In scope: endpoint list, methods, request/response schemas, auth/tenancy headers, rate limits, feature flags, error model. +- Out of scope: console/UI workflow details (see `explainability.md`). + +## Endpoint Outline (placeholders) +- `GET /api/risk/profiles` — list profiles (filters by tenant, status). +- `POST /api/risk/profiles` — create/update; includes DSSE/attestation fields. +- `POST /api/risk/simulations` — run simulation with fixture set; supports dry-run. +- `GET /api/risk/results/{id}` — retrieve scored results + explainability link. +- `GET /api/risk/explain/{id}` — fetch explainability payload. +- `GET /api/risk/export/{id}` — export bundle (JSON/CSV) with hash manifest. +- Feature flags: `` + +## Auth & Tenancy +- Required headers: `X-Stella-Tenant`, `X-Stella-Scope`, auth tokens (PAT/OAuth2) — confirm once schema published. +- Imposed rule reminder must be present on every page. + +## Error Model (pending) +- Standard error envelope: code, message, correlation_id, severity, remediation. +- Rate limit headers and retry guidance. + +## Determinism & Offline Posture +- Provide sample requests/responses under `docs/risk/samples/`; include SHA256 table. +- No live dependencies; use frozen fixtures. + +## Open Items +- API publishing workflow outputs +- Final endpoint list and field names +- Error/code catalog +- SDK generator targets and examples + +## References +- `docs/risk/overview.md` +- `docs/risk/profiles.md` +- `docs/risk/factors.md` +- `docs/risk/formulas.md` +- `docs/risk/explainability.md` diff --git a/docs/risk/explainability.md b/docs/risk/explainability.md new file mode 100644 index 000000000..f3ab57b18 --- /dev/null +++ b/docs/risk/explainability.md @@ -0,0 +1,36 @@ +# Risk Explainability (draft outline) + +> Draft scaffold; fill once 66-004 outputs and UI telemetry captures arrive. Keep fixtures deterministic (frozen payloads, stable ordering, SHA tables). + +## Purpose +- Show how the scoring engine produces per-factor contributions and traces that UI/CLI/export surfaces render for auditors and operators. + +## Scope & Audience +- Audience: Console/CLI users, auditors, SREs. +- In scope: explainability payload shape, field meanings, provenance, UI/CLI mapping, offline/export behavior. +- Out of scope: formula math (see `formulas.md`), API specifics (see `api.md`). + +## Payload Shape (pending) +- Envelope fields: score, severity, factors[], provenance, timestamps (UTC), profile version, environment. +- Factor entry fields: id, type, input_value, normalized_value, weight, contribution, source, evidence_refs[]. +- UI/CLI expectations: stable ordering, highlight top contributors, include attestation status. + +## UI/CLI Views (to fill) +- Console panels and charts (needs telemetry captures) +- CLI `stella risk explain` output (deterministic table examples) +- Export Center bundles (JSON + CSV + hash manifests) + +## Determinism & Offline Posture +- Store example payloads under `docs/risk/samples/`; record `SHA256SUMS`. +- No live calls; all captures from frozen fixtures. + +## Open Items +- Capture UI telemetry (Console Guild) and CLI sample outputs. +- Finalize explainability JSON schema once 66-004 is approved. + +## References +- `docs/risk/overview.md` +- `docs/risk/profiles.md` +- `docs/risk/factors.md` +- `docs/risk/formulas.md` +- `docs/risk/api.md` diff --git a/docs/risk/factors.md b/docs/risk/factors.md new file mode 100644 index 000000000..4582878a6 --- /dev/null +++ b/docs/risk/factors.md @@ -0,0 +1,44 @@ +# Risk Factors (draft outline) + +> Draft scaffold; fill once 66-002/66-003 inputs (engine contract + sample payloads) arrive. Keep fixtures deterministic and offline-friendly. + +## Purpose +- Catalog supported factors (exploit likelihood, VEX state, reachability, runtime facts, fix availability, asset criticality, provenance trust, tenant overrides) and how they normalize into risk math. + +## Scope & Audience +- Audience: risk engineers, policy authors, platform SREs. +- In scope: factor definitions, required/optional fields, normalization rules, TTLs, provenance expectations. +- Out of scope: full formula math (see `formulas.md`), API wiring (see `api.md`). + +## Factor Catalog (to fill with schema-backed tables) +- Exploit likelihood — fields: source, score, last_seen, confidence +- VEX status — fields: status, justification, impact_statement +- Reachability — fields: entrypoint, callgraph evidence, runtime observation +- Runtime facts — fields: host, container, signal type, timestamp (UTC), provenance attestation +- Fix availability — fields: advisory id, patch released at, mitigation guidance +- Asset criticality — fields: business tier, data class, tenancy scope +- Provenance trust — fields: signature status, key id, chain of custody +- Custom/tenant overrides — fields: override reason, reviewer, expiry/TTL + +## Normalization Rules (outline) +- Input validation + schema versioning +- Unit ranges (0–1) and clamping +- Time decay / TTL handling +- Precedence rules when multiple sources disagree + +Interim notes: follow legacy profile guidance — preserve provenance, never mutate source evidence, and keep ordering stable so explainability hashes are repeatable across UI/CLI/exports. + +## Determinism & Ordering +- Sort factors by type then source; stable hashing rules for fixtures. +- Record SHA256 for sample payloads once provided. + +## Open Items +- Engine contract and sample payloads for each factor +- TTL/decay parameters from Risk Engine Guild +- Provenance attestation examples + +## References +- `docs/risk/overview.md` +- `docs/risk/profiles.md` +- `docs/risk/formulas.md` +- `docs/risk/api.md` diff --git a/docs/risk/formulas.md b/docs/risk/formulas.md new file mode 100644 index 000000000..b1f1aa548 --- /dev/null +++ b/docs/risk/formulas.md @@ -0,0 +1,50 @@ +# Risk Formulas (draft outline) + +> Draft scaffold; fill once 66-003/66-004 inputs (engine rollout notes + factor contract) are available. Keep math examples deterministic with fixed fixtures. + +## Purpose +- Describe how normalized factors combine into a 0–100 risk score with severity bands. +- Capture gating, weighting, normalization, and override rules. + +## Scope & Audience +- Audience: risk engineers, policy authors, auditors. +- In scope: weighting strategies, aggregation functions, severity thresholds, gating rules, tie-breakers. +- Out of scope: full API payloads (see `api.md`), factor definitions (see `factors.md`). + +## Formula Building Blocks (to fill) +- Weighted sum / capped contribution +- Max/min guards per factor family +- Threshold gates (e.g., block if exploitability + reachability high) +- Decay/time weighting +- Tenant/asset overrides and imposed rules + +## Severity Mapping (outline) +- Proposed bands (example placeholder): + - Critical: 90–100 + - High: 70–89 + - Medium: 40–69 + - Low: 1–39 + - Info: 0 +- Final bands pending governance approval; update once PLLG0104 confirms. + +## Determinism +- Stable ordering of factors before aggregation. +- Use fixed precision (e.g., 4 decimals) before severity mapping. +- Hash fixtures and record SHA256 for every example payload. + +Interim notes: mirror legacy rule — simulation and production must share the exact evaluation codepath; no per-environment divergences. Severity buckets must be deterministic and governed by Authority scopes. + +## Examples (placeholders) +- TBD sample JSON: input factors + output score + contributions table. +- TBD CLI/Console screenshots once telemetry assets provided. + +## Open Items +- Engine rollout notes for gating/weighting defaults +- Severity band approval +- Sample payloads and UI traces + +## References +- `docs/risk/overview.md` +- `docs/risk/profiles.md` +- `docs/risk/factors.md` +- `docs/risk/api.md` diff --git a/docs/risk/overview.md b/docs/risk/overview.md new file mode 100644 index 000000000..b7646dd79 --- /dev/null +++ b/docs/risk/overview.md @@ -0,0 +1,49 @@ +# Risk Overview (draft outline) + +> Draft scaffold only. Populate content after PLLG0104 risk profile schema approval and risk engine/API samples land. Keep all fixtures deterministic (UTC timestamps, stable ordering, sealed sample payloads) and avoid external assets. + +## Purpose +- Explain the risk model at a glance: factors, formulas, scoring semantics (0–100), and severity bands. +- Show how risk flows through StellaOps services (ingest → evaluate → explain → export) and how provenance is preserved. + +## Scope & Audience +- Audience: policy authors, risk engineers, auditors, and SREs consuming risk outputs. +- In scope: concepts, glossary, lifecycle, artifacts, cross-module data flow diagrams (add after schema approval). +- Out of scope: detailed factor math (goes to `formulas.md`), API specifics (goes to `api.md`). + +## Core Concepts (to fill) +- Risk factor vs. evidence vs. signal +- Profile vs. formula vs. severity mapping +- Provenance and attestations +- Explainability payloads and UI/CLI displays +- Determinism expectations (ordering, timestamps, hashing) + +Interim notes (from legacy doc and sprint context): profiles take normalized factors (exploit likelihood, VEX status, reachability, runtime evidence, fix availability, asset criticality, provenance trust) and output 0–100 scores with severity buckets; same code path for simulation and production to ensure determinism. + +## Lifecycle (outline) +1. Evidence ingestion (signals, VEX, reachability, runtime) +2. Factor normalization +3. Profile evaluation +4. Severity assignment + gating +5. Explainability + observability +6. Export/archival paths + +## Artifacts & Schemas (pending) +- Risk profile schema: `` +- Risk factor catalog: shared shapes reused by `factors.md` +- Explainability envelope: shared with UI/CLI; add JSON examples once provided. + +## Determinism & Offline Posture +- Use frozen fixture sets with SHA256 tables. +- Document regeneration steps (no live network calls) once payloads arrive. + +## Open Items +- PLLG0104 schema approval +- Risk engine API payload samples +- UI telemetry captures for explainability walkthroughs + +## References (to link once available) +- `docs/risk/profiles.md` +- `docs/risk/factors.md` +- `docs/risk/formulas.md` +- `docs/risk/api.md` diff --git a/docs/risk/profiles.md b/docs/risk/profiles.md new file mode 100644 index 000000000..792d5116b --- /dev/null +++ b/docs/risk/profiles.md @@ -0,0 +1,52 @@ +# Risk Profiles (draft outline) + +> Draft scaffold pending PLLG0104 risk profile schema approval. Do not publish externally until schemas and sample payloads arrive. Mirrors existing `docs/risk/risk-profiles.md`; this file will supersede it once populated. + +## Purpose +- Define how profiles group factors, weights, thresholds, and severity bands. +- Describe authoring, simulation, promotion, rollback, and provenance for profiles. + +## Scope & Audience +- Audience: policy authors, risk engineers, platform SREs. +- Coverage: profile schema, lifecycle, governance, promotion paths, rollback, and observability hooks. + +## Schema (placeholder) +- Profile schema reference: `` +- Required fields: id, versioning, factors list, weights, thresholds, severity mapping, metadata, provenance. +- Optional fields: tenant overrides, imposed rules, time-to-live. + +## Lifecycle (outline) +1. Authoring in Policy Studio (draft state) +2. Simulation against fixtures (deterministic inputs) +3. Review/approval workflow +4. Promotion to environments (dev → staging → prod) +5. Rollback hooks and audit trail + +## Governance & Determinism +- Profiles stored with DSSE/signatures; record SHA256 for fixtures. +- Same evaluation codepath for simulation and production; note required feature flags. +- Offline posture: include profiles and fixtures inside mirror bundles. + +## Explainability & Observability +- Per-factor contribution outputs (JSON) with stable ordering. +- Metrics to log: evaluation latency, cache hit ratio, factor coverage. +- Dashboards/alerts to enumerate once telemetry payloads are supplied. + +## Open Items +- PLLG0104 schema approval and sample JSON payloads +- Feature-flag list for registry alignment +- Telemetry field list for dashboards/alerts + +## References +- `docs/risk/overview.md` +- `docs/risk/factors.md` +- `docs/risk/formulas.md` +- `docs/risk/explainability.md` +- `docs/risk/api.md` +- Existing context: `docs/risk/risk-profiles.md` (to reconcile once schema lands) + +## Interim Notes (carried from legacy `docs/risk/risk-profiles.md`) +- Profiles define how evidence (CVSS/EPSS-like exploit likelihood, KEV flags, VEX status, reachability, runtime evidence, fix availability, asset criticality, provenance trust) normalizes into a 0–100 score with severity buckets. +- Workflow highlights: author in Policy Studio → simulate with fixtures → activate in Policy Engine → explain outputs in CLI/Console → export for auditors via Export Center. +- Governance: draft/review/approval with DSSE/signatures; rollback hooks and promotion gates enforced by Authority scopes; determinism required (same codepath for simulation and production). +- Observability: record scoring latency, factor distribution, and profile usage; offline posture via mirror bundles with fixtures and hash manifests. diff --git a/docs/risk/samples/INGEST_CHECKLIST.md b/docs/risk/samples/INGEST_CHECKLIST.md new file mode 100644 index 000000000..0cea91855 --- /dev/null +++ b/docs/risk/samples/INGEST_CHECKLIST.md @@ -0,0 +1,8 @@ +# Risk Samples Ingest Checklist (use when payloads arrive) + +1) Drop payloads into the correct folder (`profiles/`, `factors/`, `explain/`, `api/`). +2) Normalize JSON deterministically (e.g., `jq -S .`) before hashing; keep UTC timestamps. +3) Run `sha256sum * > SHA256SUMS` in the target folder; keep file sorted. +4) Verify hashes: `sha256sum -c SHA256SUMS`. +5) Add a short README snippet in the sprint Execution Log noting files added and hashes updated. +6) Keep fixtures offline-only; no external calls or redactions after hashing. diff --git a/docs/risk/samples/README.md b/docs/risk/samples/README.md new file mode 100644 index 000000000..2d316b584 --- /dev/null +++ b/docs/risk/samples/README.md @@ -0,0 +1,26 @@ +# Risk Samples (fixtures layout) + +Use this folder for frozen, deterministic fixtures once schemas and payloads arrive. + +Structure (proposed): +- `profiles/` — profile JSON (DSSE-wrapped where applicable) + `SHA256SUMS` +- `factors/` — factor input payloads grouped by source (epss/, kev/, reachability/, runtime/), each with `SHA256SUMS` +- `explain/` — explainability outputs paired with inputs; include `SHA256SUMS` +- `api/` — request/response examples for risk endpoints; include `SHA256SUMS` + +Rules: +- UTC timestamps; stable ordering of arrays/objects. +- No live calls; fixtures only. +- Record hashes via `sha256sum` and keep manifests alongside samples. + +Quick receipt checklist (see `INGEST_CHECKLIST.md` for detail): +1) Normalize JSON with `jq -S .` +2) Update `SHA256SUMS` in the target folder +3) Verify with `sha256sum -c` +4) Log files + hashes in the sprint Execution Log + +Manifests created: +- `profiles/SHA256SUMS` +- `factors/SHA256SUMS` +- `explain/SHA256SUMS` +- `api/SHA256SUMS` diff --git a/docs/risk/samples/api/README.md b/docs/risk/samples/api/README.md new file mode 100644 index 000000000..0b5430a57 --- /dev/null +++ b/docs/risk/samples/api/README.md @@ -0,0 +1,3 @@ +Use the root `INGEST_CHECKLIST.md`. +Place request/response examples here; normalize with `jq -S .`, update `SHA256SUMS`, verify with `sha256sum -c`. +Include required headers; redact secrets; UTC timestamps only. diff --git a/docs/risk/samples/api/SHA256SUMS b/docs/risk/samples/api/SHA256SUMS new file mode 100644 index 000000000..e69de29bb diff --git a/docs/risk/samples/explain/README.md b/docs/risk/samples/explain/README.md new file mode 100644 index 000000000..46e8ecd6b --- /dev/null +++ b/docs/risk/samples/explain/README.md @@ -0,0 +1,3 @@ +Use the root `INGEST_CHECKLIST.md`. +Store explainability outputs paired with their inputs; normalize with `jq -S .`, update `SHA256SUMS`, verify with `sha256sum -c`. +Maintain ordering and UTC timestamps; no live data. diff --git a/docs/risk/samples/explain/SHA256SUMS b/docs/risk/samples/explain/SHA256SUMS new file mode 100644 index 000000000..e69de29bb diff --git a/docs/risk/samples/factors/README.md b/docs/risk/samples/factors/README.md new file mode 100644 index 000000000..6c2a841fa --- /dev/null +++ b/docs/risk/samples/factors/README.md @@ -0,0 +1,3 @@ +Use the root `INGEST_CHECKLIST.md`. +Drop factor payloads by source (epss/, kev/, reachability/, runtime/), normalize with `jq -S .`, update `SHA256SUMS`, verify with `sha256sum -c`. +Keep UTC timestamps and no live data. diff --git a/docs/risk/samples/factors/SHA256SUMS b/docs/risk/samples/factors/SHA256SUMS new file mode 100644 index 000000000..e69de29bb diff --git a/docs/risk/samples/intake-log-template.md b/docs/risk/samples/intake-log-template.md new file mode 100644 index 000000000..3e2ca2ccc --- /dev/null +++ b/docs/risk/samples/intake-log-template.md @@ -0,0 +1,8 @@ +| Date (UTC) | Folder | Files added | SHA256SUMS updated | Notes | +| --- | --- | --- | --- | --- | +| 2025-__-__ | profiles/ | | yes/no | source + checklist step refs | +| 2025-__-__ | factors/ | | yes/no | source + checklist step refs | +| 2025-__-__ | explain/ | | yes/no | source + checklist step refs | +| 2025-__-__ | api/ | | yes/no | source + checklist step refs | + +Instructions: copy a row per drop, fill actual date, list filenames, mark whether `SHA256SUMS` was updated, and note evidence source. Keep this file sorted by date for determinism. diff --git a/docs/risk/samples/profiles/README.md b/docs/risk/samples/profiles/README.md new file mode 100644 index 000000000..9db565897 --- /dev/null +++ b/docs/risk/samples/profiles/README.md @@ -0,0 +1,3 @@ +Use the root `INGEST_CHECKLIST.md`. +Place profile JSON/DSSE here, normalize with `jq -S .`, update `SHA256SUMS`, and verify with `sha256sum -c`. +UTC timestamps only; no live data. diff --git a/docs/risk/samples/profiles/SHA256SUMS b/docs/risk/samples/profiles/SHA256SUMS new file mode 100644 index 000000000..e69de29bb diff --git a/docs/runbooks/SHA256SUMS b/docs/runbooks/SHA256SUMS new file mode 100644 index 000000000..8db6848c0 --- /dev/null +++ b/docs/runbooks/SHA256SUMS @@ -0,0 +1 @@ +# Placeholder hashes; replace with real asset sums when inputs arrive diff --git a/docs/runbooks/incidents.md b/docs/runbooks/incidents.md new file mode 100644 index 000000000..8a650b320 --- /dev/null +++ b/docs/runbooks/incidents.md @@ -0,0 +1,17 @@ +# Incident Mode Runbook (outline) + +- Activation, escalation, retention, verification checklist TBD from Ops Guild. + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Activation criteria and toggle steps. +- Escalation paths and roles. +- Retention/cleanup impacts. +- Verification checklist and imposed-rule banner text. diff --git a/docs/runbooks/vuln-ops.md b/docs/runbooks/vuln-ops.md new file mode 100644 index 000000000..62d7d690b --- /dev/null +++ b/docs/runbooks/vuln-ops.md @@ -0,0 +1,17 @@ +# Vuln Ops Runbook (Md.XI draft) + +> Status: DRAFT — pending policy overlay outputs and Ops scenarios. Keep TODO. + +## Scope +- Operational responses: projector lag, resolver storms, export failures, policy activation steps. + +## Dependencies +- Policy overlay outputs; GRAP0101 identifiers; export bundle spec. + +## Outline +- Projector lag: detection, remediation, replay steps. +- Resolver storms: rate limits, backpressure, queue drains. +- Export failures: bundle retry, manifest verification, hash checks. +- Policy activation: rollout checklist and rollback. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/sbom/vuln-resolution.md b/docs/sbom/vuln-resolution.md new file mode 100644 index 000000000..e4d314d46 --- /dev/null +++ b/docs/sbom/vuln-resolution.md @@ -0,0 +1,18 @@ +# SBOM Vulnerability Resolution (Md.XI draft) + +> Status: DRAFT — pending export/advisory integration and GRAP0101 field freeze. + +## Scope +- Version semantics, scope, paths, safe version hints for SBOM components in Vuln Explorer. +- Deterministic examples with hashes in `docs/assets/vuln-explorer/SHA256SUMS`. + +## Dependencies +- Advisory integration (DOCS-VULN-29-008). +- GRAP0101 identifiers. + +## Outline +- Component resolution (purl, NEVRA); scope (prod/dev/test). +- Path specificity and deduping rules. +- Safe version hints and policy overlays. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/schemas/acceptance-pack.schema.json b/docs/schemas/acceptance-pack.schema.json new file mode 100644 index 000000000..aeceffc6f --- /dev/null +++ b/docs/schemas/acceptance-pack.schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Acceptance Pack (Stub)", + "description": "Schema stub for AT1–AT10 guardrail pack; to be finalized with signed DSSE envelope.", + "type": "object", + "properties": { + "pack_id": { "type": "string" }, + "version": { "type": "string" }, + "inputs_lock": { "type": "string", "description": "Path to pinned versions/seeds." }, + "signers": { + "type": "array", + "items": { "type": "string" }, + "description": "Key IDs that signed the DSSE envelope for this pack" + }, + "fixtures": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "seed": { "type": "integer" }, + "expected": { "type": "string" }, + "artifact": { "type": "string", "description": "Path to fixture artifact" } + }, + "required": ["id", "expected"] + } + } + }, + "required": ["pack_id", "version", "fixtures"] +} diff --git a/docs/scripts/sbom-vex/chain-hash-recipe.md b/docs/scripts/sbom-vex/chain-hash-recipe.md new file mode 100644 index 000000000..506287562 --- /dev/null +++ b/docs/scripts/sbom-vex/chain-hash-recipe.md @@ -0,0 +1,25 @@ +# SBOM→VEX Chain Hash Recipe (Stub) + +Use with sprint task 6 (SBOM-VEX-GAPS-300-013). + +- Inputs: sorted SBOM documents, VEX statements, DSSE envelopes, Rekor bundle snapshot. +- Hashing: deterministic ordering (UTF-8, LF), SHA-256 over concatenated canonical JSON. +- Chain: derive cumulative hash for (SBOM → DSSE → Rekor → VEX) and store in proof manifest. +- Offline: no network; bundle Rekor root + snapshot; include `inputs.lock` with tool versions. + +Example (stub): + +```bash +sbom_files=(sbom.json) +vex_files=(vex.json) +dsse=envelope.dsse +rekor=rekor-bundle.json + +cat "${sbom_files[@]}" | jq -S . > /tmp/sbom.canon +cat "${vex_files[@]}" | jq -S . > /tmp/vex.canon +cat "$dsse" | jq -S . > /tmp/dsse.canon +cat "$rekor" | jq -S . > /tmp/rekor.canon + +cat /tmp/sbom.canon /tmp/dsse.canon /tmp/rekor.canon /tmp/vex.canon | sha256sum | awk '{print $1}' > proof.chainhash +echo "chain-hash: $(cat proof.chainhash)" +``` diff --git a/docs/scripts/sbom-vex/verify.sh b/docs/scripts/sbom-vex/verify.sh new file mode 100644 index 000000000..7d47a83f6 --- /dev/null +++ b/docs/scripts/sbom-vex/verify.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Offline verifier stub for SBOM -> VEX proof bundles. +# Expected inputs: path to DSSE envelope, Rekor log snapshot, and bundled trust roots. + +if [ "$#" -lt 4 ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +SBOM="$1" +VEX="$2" +DSSE="$3" +REKOR="$4" + +if ! command -v jq >/dev/null; then + echo "jq is required (offline-capable)." >&2 + exit 2 +fi + +echo "[stub] canonicalising inputs..." >&2 +tmpdir=$(mktemp -d) +trap 'rm -rf "$tmpdir"' EXIT + +jq -S . "$SBOM" > "$tmpdir/sbom.canon" +jq -S . "$VEX" > "$tmpdir/vex.canon" +jq -S . "$DSSE" > "$tmpdir/dsse.canon" +jq -S . "$REKOR" > "$tmpdir/rekor.canon" + +cat "$tmpdir/sbom.canon" "$tmpdir/dsse.canon" "$tmpdir/rekor.canon" "$tmpdir/vex.canon" | sha256sum | awk '{print $1}' > "$tmpdir/proof.hash" +echo "chain-hash (sbom+dsse+rekor+vex): $(cat "$tmpdir/proof.hash")" +echo "[stub] verify DSSE signatures and Rekor inclusion separately; add manifests to DSSE envelope for full proof" diff --git a/docs/sdks/SHA256SUMS b/docs/sdks/SHA256SUMS new file mode 100644 index 000000000..8db6848c0 --- /dev/null +++ b/docs/sdks/SHA256SUMS @@ -0,0 +1 @@ +# Placeholder hashes; replace with real asset sums when inputs arrive diff --git a/docs/sdks/go.md b/docs/sdks/go.md new file mode 100644 index 000000000..6599c1ec0 --- /dev/null +++ b/docs/sdks/go.md @@ -0,0 +1,16 @@ +# SDK Guide: Go (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Module import and version pinning (`go.mod`). +- Auth helpers and tenancy headers. +- Context-first patterns, retries, telemetry defaults. +- Streaming and large payload handling. +- Examples (CLI + library) with hash-listed fixtures. diff --git a/docs/sdks/java.md b/docs/sdks/java.md new file mode 100644 index 000000000..cc0c0a9f6 --- /dev/null +++ b/docs/sdks/java.md @@ -0,0 +1,16 @@ +# SDK Guide: Java (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Build tooling and version pinning (Maven/Gradle) with checksums. +- Auth helpers and tenancy headers. +- Retry/pagination/telemetry defaults. +- Streaming/upload helpers. +- Example usage with hash-listed fixtures. diff --git a/docs/sdks/overview.md b/docs/sdks/overview.md new file mode 100644 index 000000000..a6584be16 --- /dev/null +++ b/docs/sdks/overview.md @@ -0,0 +1,17 @@ +# SDKs Overview (outline) + +- Language guides will align once generator outputs drop. + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Supported languages and parity guarantees. +- Auth, pagination, retries, telemetry defaults. +- Versioning/pinning guidance for offline bundles. +- Links to per-language guides with hash-listed samples. diff --git a/docs/sdks/python.md b/docs/sdks/python.md new file mode 100644 index 000000000..3aa37d505 --- /dev/null +++ b/docs/sdks/python.md @@ -0,0 +1,17 @@ +# SDK Guide: Python (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Installation & version pinning (pip/poetry/pipenv) with hashes. +- Auth helpers (PAT/OAuth2) and tenancy headers. +- Sync vs async clients usage. +- Pagination, retries, telemetry defaults. +- Streaming/upload helpers. +- Example notebooks/scripts (hash-listed). diff --git a/docs/sdks/typescript.md b/docs/sdks/typescript.md new file mode 100644 index 000000000..0319ab4d1 --- /dev/null +++ b/docs/sdks/typescript.md @@ -0,0 +1,17 @@ +# SDK Guide: TypeScript (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Installation & version pinning (npm/pnpm/yarn with lockfiles). +- Auth helpers (PAT/OAuth2) and tenancy headers. +- Pagination, retries, telemetry defaults. +- Streaming/download helpers. +- CI/offline bundle usage notes. +- Example snippets (with hash-listed fixtures). diff --git a/docs/security/aoc-invariants.md b/docs/security/aoc-invariants.md index 12ae81421..a32a3725e 100644 --- a/docs/security/aoc-invariants.md +++ b/docs/security/aoc-invariants.md @@ -18,6 +18,9 @@ Last updated: 2025-11-25 (DOCS-ATTEST-75-002) ## Guardrails for implementers - Never permit unsigned or partially signed payloads to proceed past parsing. + +## Pending Update +- Add risk scoring provenance guarantees (DOCS-RISK-68-002) once Export/Risk inputs land; due 2025-12-11 per sprint action tracker. Include deterministic hash list for any new examples or schemas. - Reject any outbound HTTP/S fetch during verification when `Attestor__Offline__Enabled=true`. - Keep secret material out of logs; log statement digests and key ids only. - Round numeric scores/weights only at the presentation boundary; internal math stays high-precision. diff --git a/docs/security/auth-scopes.md b/docs/security/auth-scopes.md new file mode 100644 index 000000000..40944f415 --- /dev/null +++ b/docs/security/auth-scopes.md @@ -0,0 +1,11 @@ +# Auth Scopes + +- Pending OAuth2/PAT scope matrix + tenancy header rules. + +## Pending Inputs +- Scope matrix + tenancy header rules expected from Security Guild · Authority Core (due 2025-12-11 per sprint action tracker). + +## Determinism Checklist +- [ ] Hash any inbound tables/examples and note source/approver. +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Record version/date of source specs when added. diff --git a/docs/security/redaction-and-privacy.md b/docs/security/redaction-and-privacy.md new file mode 100644 index 000000000..82a9f300b --- /dev/null +++ b/docs/security/redaction-and-privacy.md @@ -0,0 +1,11 @@ +# Redaction and Privacy + +- Pending telemetry privacy controls + opt-in debug flow. + +## Pending Inputs +- Telemetry privacy controls + opt-in debug flow from Security Guild (due 2025-12-11 per sprint action tracker). + +## Determinism Checklist +- [ ] Hash any sample configs/payloads and track source/approver. +- [ ] Keep guidance offline-friendly; avoid live endpoints in examples. +- [ ] Use deterministic ordering and pinned versions in any sample policies or logs. diff --git a/docs/security/vuln-rbac.md b/docs/security/vuln-rbac.md new file mode 100644 index 000000000..d37528634 --- /dev/null +++ b/docs/security/vuln-rbac.md @@ -0,0 +1,16 @@ +# Vuln Explorer RBAC & ABAC (Md.XI draft) + +> Status: DRAFT — pending security review and GRAP0101. Do not publish until roles/claims verified. + +## Scope +- Roles/scopes, ABAC policies, attachment encryption/CSRF considerations for Vuln Explorer. + +## Dependencies +- Security review; GRAP0101 identifiers; attachment token wording from Authority. + +## Outline +- Scopes: vuln:view/investigate/operate/audit (+ legacy read). +- ABAC filters: vuln_env, vuln_owner, vuln_business_tier; enforcement in tokens/permalinks. +- Attachment tokens: issuance/verify; encryption notes; CSRF protections. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/signals/SHA256SUMS b/docs/signals/SHA256SUMS new file mode 100644 index 000000000..8db6848c0 --- /dev/null +++ b/docs/signals/SHA256SUMS @@ -0,0 +1 @@ +# Placeholder hashes; replace with real asset sums when inputs arrive diff --git a/docs/signals/callgraph-formats.md b/docs/signals/callgraph-formats.md new file mode 100644 index 000000000..ea2f78d07 --- /dev/null +++ b/docs/signals/callgraph-formats.md @@ -0,0 +1,15 @@ +# Callgraph Formats (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Supported callgraph schema versions and shapes. +- Field definitions and validation rules. +- Common validation errors with deterministic examples. +- Hashes for any sample graphs provided. diff --git a/docs/signals/reachability.md b/docs/signals/reachability.md new file mode 100644 index 000000000..d770d532c --- /dev/null +++ b/docs/signals/reachability.md @@ -0,0 +1,16 @@ +# Reachability Signals (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Purpose & scope (what “reachability” means across components). +- States and scoring semantics. +- Provenance and evidence sources. +- Retention and TTL policy. +- Sample payloads (with hashes recorded alongside). diff --git a/docs/signals/runtime-facts.md b/docs/signals/runtime-facts.md new file mode 100644 index 000000000..2ae4f9718 --- /dev/null +++ b/docs/signals/runtime-facts.md @@ -0,0 +1,15 @@ +# Runtime Facts (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Runtime agent capabilities captured. +- Privacy safeguards and opt-in flags. +- Payload schema and field descriptions. +- Examples and hash listings for sample traces. diff --git a/docs/task-packs/approvals-ledger.schema.json b/docs/task-packs/approvals-ledger.schema.json new file mode 100644 index 000000000..cbeeb8e2b --- /dev/null +++ b/docs/task-packs/approvals-ledger.schema.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "StellaOps Task Pack Approval Ledger", + "description": "DSSE payload recording approval decisions for Task Pack gates.", + "type": "object", + "additionalProperties": false, + "required": [ + "schemaVersion", + "runId", + "gateId", + "planHash", + "decision", + "decidedAt", + "tenantId", + "approver" + ], + "properties": { + "schemaVersion": { + "type": "string", + "const": "stellaops.pack.approval-ledger.v1" + }, + "runId": { "type": "string", "minLength": 1 }, + "gateId": { "type": "string", "minLength": 1 }, + "planHash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, + "decision": { "type": "string", "enum": ["approved", "rejected", "expired"] }, + "decidedAt": { "type": "string", "format": "date-time" }, + "tenantId": { "type": "string", "minLength": 1 }, + "environment": { "type": "string" }, + "approver": { + "type": "object", + "additionalProperties": false, + "required": ["id"], + "properties": { + "id": { "type": "string", "minLength": 1 }, + "summary": { "type": "string" } + } + }, + "reason": { "type": "string" }, + "evidence": { + "type": "object", + "additionalProperties": false, + "properties": { + "requestDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" }, + "responseDigest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" } + } + } + } +} diff --git a/docs/task-packs/packs-offline-bundle.schema.json b/docs/task-packs/packs-offline-bundle.schema.json index c892dd68f..7b2fe5f14 100644 --- a/docs/task-packs/packs-offline-bundle.schema.json +++ b/docs/task-packs/packs-offline-bundle.schema.json @@ -64,19 +64,19 @@ "properties": { "sandbox": { "type": "object", - "additionalProperties": false, - "required": ["mode", "egressAllowlist", "cpuLimitMillicores", "memoryLimitMiB"], - "properties": { - "mode": { "type": "string", "enum": ["sealed", "restricted"] }, - "egressAllowlist": { - "type": "array", - "items": { "type": "string" } - }, - "cpuLimitMillicores": { "type": "integer", "minimum": 1 }, - "memoryLimitMiB": { "type": "integer", "minimum": 1 }, - "quotaSeconds": { "type": "integer", "minimum": 1 } - } + "additionalProperties": false, + "required": ["mode", "egressAllowlist", "cpuLimitMillicores", "memoryLimitMiB", "quotaSeconds"], + "properties": { + "mode": { "type": "string", "enum": ["sealed", "restricted"] }, + "egressAllowlist": { + "type": "array", + "items": { "type": "string" } }, + "cpuLimitMillicores": { "type": "integer", "minimum": 1 }, + "memoryLimitMiB": { "type": "integer", "minimum": 1 }, + "quotaSeconds": { "type": "integer", "minimum": 1 } + } + }, "revocations": { "type": "string", "description": "Revocation list for pack versions/digests." }, "signatures": { "type": "object", diff --git a/docs/task-packs/registry.md b/docs/task-packs/registry.md index 0f602382a..4d3923be7 100644 --- a/docs/task-packs/registry.md +++ b/docs/task-packs/registry.md @@ -176,6 +176,7 @@ Extensions must be deterministic and derived from signed bundle data. - **Sandbox + quotas (TP6):** Registry metadata carries `sandbox.mode`, explicit egress allowlists, CPU/memory limits, and quota seconds; Task Runner refuses packs missing these fields. - **SLO + alerting (TP9):** Pack metadata includes SLOs (`runP95Seconds`, `approvalP95Seconds`, `maxQueueDepth`); registry emits metrics/alerts when declared SLOs are exceeded during publish/import flows. - **Fail-closed imports (TP10):** Import/mirror paths abort when DSSE, hash entries, or revocation files are absent or stale, returning actionable error codes for CLI/Task Runner. +- **Approval ledger schema:** Registry exposes `docs/task-packs/approvals-ledger.schema.json` for DSSE approval records (planHash must be `sha256:<64-hex>`); import validation rejects non-conforming ledgers. --- diff --git a/docs/task-packs/spec.md b/docs/task-packs/spec.md index bcff2f841..9a2adae2b 100644 --- a/docs/task-packs/spec.md +++ b/docs/task-packs/spec.md @@ -168,7 +168,7 @@ pack.yaml ──▶ schema validation ──▶ expression audit ──▶ deter Packs must pass CLI validation before publishing. ### 6.1 · TP Gap Remediation (2025-12) -- **Canonical plan hash (TP1):** Compute `plan.hash` as `sha256` over canonical JSON (`plan.canonicalPlanPath`) with sorted keys and normalized numbers/booleans. The canonical plan file ships in offline bundles. +- **Canonical plan hash (TP1):** Compute `plan.hash` as `sha256:<64-hex>` over canonical JSON (`plan.canonicalPlanPath`) with sorted keys and normalized numbers/booleans. The canonical plan file ships in offline bundles. - **Inputs lock (TP2):** CLI emits `inputs.lock` capturing resolved inputs and redacted secret placeholders; hashed via `hashes[]` and included in evidence bundles. - **Approval ledger DSSE (TP3):** Approval responses are DSSE-signed ledgers embedding `runId`, `gateId`, `planHash`, and tenant context; Task Runner rejects approvals without matching plan hash. - **Secret redaction (TP4):** `security.secretsRedactionPolicy` defines hashing/redaction for secrets and PII; transcripts/evidence must reference this policy. @@ -178,6 +178,7 @@ Packs must pass CLI validation before publishing. - **Offline bundle schema + verifier (TP8):** Offline exports must satisfy `docs/task-packs/packs-offline-bundle.schema.json` and pass `scripts/packs/verify_offline_bundle.py --require-dsse`. - **SLO + alerting (TP9):** Manifests declare `slo.runP95Seconds`, `slo.approvalP95Seconds`, `slo.maxQueueDepth`, and optional `slo.alertRules`; telemetry enforces and alerts on breaches. - **Fail-closed gates (TP10):** Approval/policy/timeline gates fail closed when DSSE, hash entries, or quotas are missing/expired; CLI surfaces remediation hints. +- **Approval ledger schema:** Approval decisions must conform to `docs/task-packs/approvals-ledger.schema.json`; planHash is `sha256:<64-hex>` and DSSE envelopes must reference ledger digest. --- diff --git a/docs/ui/reachability-overlays.md b/docs/ui/reachability-overlays.md new file mode 100644 index 000000000..2882b0402 --- /dev/null +++ b/docs/ui/reachability-overlays.md @@ -0,0 +1,15 @@ +# Reachability Overlays (UI) (outline) + +## Pending Inputs +- See sprint SPRINT_0309_0001_0009_docs_tasks_md_ix action tracker; inputs due 2025-12-09..12 from owning guilds. + +## Determinism Checklist +- [ ] Hash any inbound assets/payloads; place sums alongside artifacts (e.g., SHA256SUMS in this folder). +- [ ] Keep examples offline-friendly and deterministic (fixed seeds, pinned versions, stable ordering). +- [ ] Note source/approver for any provided captures or schemas. + +## Sections to fill (once inputs arrive) +- Badges/overlays and their semantics. +- Timeline views and shortcuts. +- Accessibility considerations. +- Hashes for UI captures placed alongside assets. diff --git a/docs/vex/explorer-integration.md b/docs/vex/explorer-integration.md new file mode 100644 index 000000000..ae02a20e2 --- /dev/null +++ b/docs/vex/explorer-integration.md @@ -0,0 +1,23 @@ +# VEX Explorer Integration (Md.XI draft) + +> Status: DRAFT — pending GRAP0101 alignment, CSAF mapping specifics, and CLI examples. Do not publish until hashes recorded. + +## Scope +- Map Explorer VEX handling: CSAF ingestion, suppression precedence, status semantics, and integration points with findings. +- Provide deterministic examples; hash payloads/screens in `docs/assets/vuln-explorer/SHA256SUMS`. + +## Dependencies +- GRAP0101 contract (field names, identifiers). +- CLI/console assets (due 2025-12-09). +- Policy/VEX mapping rules from Excititor Guild. + +## Topics (outline) +- CSAF → internal VEX decision mapping; precedence vs policy overrides. +- Status semantics: NOT_AFFECTED / AFFECTED_* / FIXED; validity windows; VEX-first triage per Vuln Explorer architecture. +- Suppression precedence: VEX decisions take priority over reachability/policy unless explicit override (confirm post-GRAP0101). +- Export/propagation to advisories/CLI/console. + +## Determinism +- Use fixed CSAF samples; hash examples. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/vuln/explorer-api.md b/docs/vuln/explorer-api.md new file mode 100644 index 000000000..5b86ac3c9 --- /dev/null +++ b/docs/vuln/explorer-api.md @@ -0,0 +1,50 @@ +# Vuln Explorer API (Md.XI draft) + +> Status: DRAFT — depends on GRAP0101 contract and console/CLI payload samples. Publish only after schemas freeze and hashes recorded. + +## Scope +- Describe public Explorer API endpoints, query schema, grouping, errors, and rate limits. +- Include deterministic examples with hashed request/response payloads. + +## Prerequisites +- GRAP0101 contract (final field names, query params). +- Payload samples from console/CLI asset drop (due 2025-12-09). +- Current architecture reference: `docs/modules/vuln-explorer/architecture.md`. + +## Endpoints (to finalize) +- `GET /v1/findings` — list with filters (tenant, advisory, status, reachability, VEX, priority, owner); pagination & sorting. +- `GET /v1/findings/{id}` — detail (policy context, explain trace, attachments, history). +- `POST /v1/findings/{id}/actions` — create action (assign, comment, status change, remediation, ticket link) with DSSE optional. +- `POST /v1/reports` — create report; returns manifest + location. +- `GET /v1/reports/{id}` — fetch report metadata/download. +- `GET /v1/exports/offline` — download deterministic bundle (JSONL + manifests + signatures). +- `POST /v1/vex-decisions` / `PATCH /v1/vex-decisions/{id}` / `GET /v1/vex-decisions` — decision lifecycle (aligns with `vex-decision.schema.json`). + +## Query Schema (draft) +- Filters: `tenant`, `advisoryId`, `vexStatus`, `reachability`, `priority`, `status`, `owner`, `artifactId`, `sbomComponentId`. +- Pagination: `page`, `pageSize` (cap tbd per GRAP0101). +- Sorting: `sort` (supports multi-field, stable order; default `priority desc, updatedAt desc`). +- Projection: `fields` allowlist to shrink payloads; defaults tbd. +- ETag/If-None-Match for cache-aware clients (confirm in GRAP0101). + +## Errors & Rate Limits +- Standard error envelope (status, code, message, correlationId); attach `hint` when policy gate blocks action. +- Rate limits: per-tenant and per-service-account quotas; retry after header; offline bundles exempt. + +## Determinism & Offline +- All example payloads must be fixed fixtures; record hashes in `docs/assets/vuln-explorer/SHA256SUMS`. +- Use canonical ordering for list responses; include sample `ETag` and manifest hash where relevant. + +### Fixtures to Capture (when assets drop) +- `assets/vuln-explorer/api-findings-list.json` (filtered list response) +- `assets/vuln-explorer/api-finding-detail.json` (detail with history/actions) +- `assets/vuln-explorer/api-action-post.json` (action request/response) +- `assets/vuln-explorer/api-report-create.json` (report creation + manifest) +- `assets/vuln-explorer/api-vex-decision.json` (create/list payloads) + +## Open Items +- Fill in finalized parameter names, limits, and error codes from GRAP0101. +- Add example requests/responses once asset drop is delivered; include hashes. +- Confirm DSSE optional flag shape for `actions` endpoint. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/vuln/explorer-cli.md b/docs/vuln/explorer-cli.md new file mode 100644 index 000000000..3f725548d --- /dev/null +++ b/docs/vuln/explorer-cli.md @@ -0,0 +1,39 @@ +# Vuln Explorer CLI (Md.XI draft) + +> Status: DRAFT — depends on explorer API/console assets and GRAP0101 schema. Do not publish until samples are hashed and prerequisites land. + +## Scope +- Command reference for Explorer-related CLI verbs (list/view/actions/reports/exports/VEX decisions). +- Examples must be deterministic and offline-friendly (fixed fixtures, no live endpoints). + +## Prerequisites +- GRAP0101 contract for finalized field names and filters. +- CLI sample payloads (requested with console assets; due 2025-12-09). +- API schema from `docs/vuln/explorer-api.md` once finalized. + +## Commands (outline) +- `stella findings list` — filters, pagination, sorting, `--fields`, `--reachability`, `--vex-status`. +- `stella findings view ` — includes history, actions, explain bundle refs. +- `stella findings action --assign/--comment/--status/--remediate/--ticket` — DSSE signing optional. +- `stella findings report create` — outputs manifest path and DSSE envelope. +- `stella findings export offline` — deterministic bundle with hashes (aligns with Offline Kit). +- `stella vex decisions` — create/update/list VEX decisions. + +## Determinism & Offline +- Record all sample command outputs (stdout/stderr) with hashes in `docs/assets/vuln-explorer/SHA256SUMS`. +- Use fixed fixture IDs, ordered output, and `--format json` where applicable. + +### Fixtures to Capture (once CLI samples arrive) +- `assets/vuln-explorer/cli-findings-list.json` (list with filters) +- `assets/vuln-explorer/cli-findings-view.json` (detail view) +- `assets/vuln-explorer/cli-action.json` (assign/comment/status change) +- `assets/vuln-explorer/cli-report-create.json` (report creation output) +- `assets/vuln-explorer/cli-export-offline.json` (bundle manifest snippet) +- `assets/vuln-explorer/cli-vex-decision.json` (decision create/list) + +## Open Items +- Insert real examples and exit codes once assets arrive. +- Confirm DSSE flag names and default signing key selection. +- Add CI snippets for GitLab/GitHub once policy overlays provided. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/vuln/explorer-overview.md b/docs/vuln/explorer-overview.md new file mode 100644 index 000000000..31ccad8f3 --- /dev/null +++ b/docs/vuln/explorer-overview.md @@ -0,0 +1,49 @@ +# Vuln Explorer Overview (Md.XI draft) + +> Status: DRAFT (awaiting GRAP0101 contract; finalize after domain model freeze). + +## Scope +- Summarize Vuln Explorer domain model and identities involved in triage/remediation. +- Capture AOC (attestations of control) guarantees supplied by Findings Ledger and Explorer API. +- Provide a concise workflow walkthrough from ingestion to console/CLI/API use. +- Reflect VEX-first triage posture (per module architecture) and offline/export requirements. + +## Inputs & Dependencies +| Input | Status | Notes | +| --- | --- | --- | +| GRAP0101 domain model contract | pending | Required for final entity/relationship names and invariants. | +| Console/CLI assets (screens, payloads, samples) | requested | Needed for workflow illustrations and hash manifests. | +| Findings Ledger schema + replay/Merkle notes | available | See `docs/modules/findings-ledger/schema.md` and `docs/modules/findings-ledger/merkle-anchor-policy.md`. | + +## Domain Model (to be finalized) +- Entities (from current architecture): `finding_records` (canonical enriched findings), `finding_history` (append-only state transitions), `triage_actions` (operator actions), `remediation_plans`, `reports` (saved templates/exports). Final names/fields subject to GRAP0101 freeze. +- Relationships: findings link to advisories, VEX, SBOM component IDs, policyVersion, explain bundle refs; history and actions reference `findingId` with tenant + artifact scope; remediation plans and reports reference findings. (Clarify cardinality once GRAP0101 arrives.) +- Key identifiers: tenant, artifactId, findingKey, policyVersion, sourceRunId; attachment/download tokens validated via Authority (see Identity section). + +## Identities & Roles +- Operators: console users with scopes `vuln:view`, `vuln:investigate`, `vuln:operate`, `vuln:audit`; legacy `vuln:read` honored but deprecated. ABAC filters (`vuln_env`, `vuln_owner`, `vuln_business_tier`) enforced on tokens and permalinks. +- Automation/agents: service accounts carrying the same scopes + ABAC filters; attachment tokens short-lived and validated against ledger hashes. +- External inputs: advisories, SBOMs, reachability signals, VEX decisions; map to findings via advisoryRawIds, vexRawIds, sbomComponentId (see GRAP0101 for final field names). + +## AOC Guarantees +- Ledger anchoring and replay: reference `docs/modules/findings-ledger/merkle-anchor-policy.md` and `replay-harness.md` for deterministic replays and Merkle roots. +- Provenance chain: DSSE + in-toto/attestations (link to `docs/modules/findings-ledger/dsse-policy-linkage.md`); audit exports include signed manifests. +- Data integrity: append-only history plus Authority-issued attachment tokens checked against ledger hashes; GRAP0101 will confirm checksum fields. + +## Workflow Summary (happy path) +1) Ingest findings/advisories → normalize → enrich with policy/VEX/reachability/AI → persist to `finding_records`. +2) Apply ABAC + scopes → store history/action entries → trigger notifications. +3) Expose via API/Console/CLI with cached reachability/VEX context and policy explain bundles (VEX-first, reachability second, policy gates third per architecture). +4) Export reports/offline bundles; verify with ledger hashes and DSSE attestations. + +## Offline/Determinism Notes +- Hash captures for screenshots/payloads recorded in `docs/assets/vuln-explorer/SHA256SUMS` (empty until assets arrive). +- Use fixed fixture sets and ordered outputs when adding examples. + +## Open Items before publish +- Replace all `[[pending:…]]` placeholders with GRAP0101 contract details. +- Insert deterministic examples (console, API, CLI) once assets drop. +- Add summary diagram if provided by Vuln Explorer Guild. +- Mirror any architecture updates from `docs/modules/vuln-explorer/architecture.md` into this overview when GRAP0101 finalizes. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/vuln/explorer-using-console.md b/docs/vuln/explorer-using-console.md new file mode 100644 index 000000000..893c1093c --- /dev/null +++ b/docs/vuln/explorer-using-console.md @@ -0,0 +1,37 @@ +# Vuln Explorer — Using the Console (Md.XI draft) + +> Status: DRAFT (awaiting GRAP0101 domain model + console asset drop). Do not publish until hashes captured. + +## Scope +- Walk through primary console workflows: search/filter, saved views, keyboard shortcuts, drill-down, evidence export. +- Highlight identity/ABAC enforcement and tenant scoping in UI. +- Keep all examples deterministic; attach payload/screenshot hashes to `docs/assets/vuln-explorer/SHA256SUMS`. + +## Prerequisites +- Domain model from GRAP0101 (entities, identifiers) — needed for labels and field names. +- UI/CLI asset drop (screenshots, payload samples) — requested, due 2025-12-09. +- Ledger/observability context from `docs/modules/vuln-explorer/architecture.md` and Findings Ledger docs. + +## Workflows (to be filled with assets) +1) Discover & filter findings (search, severity, reachability/VEX toggles). +2) Keyboard shortcuts for navigation (list, detail, actions) — pending asset table. +3) Saved views & deep links (shareable, ABAC-aware permalinks) — include hash-verified examples. +4) Drill-down: finding detail → history → actions → attachments (token validation flow). +5) Export: reports and offline bundles; note hash verification step. + +## Determinism & Offline Notes +- All screenshots/payloads must be hashed; record in `docs/assets/vuln-explorer/SHA256SUMS`. +- Use fixed fixture IDs and ordered outputs; avoid live endpoints. + +### Hash Capture Checklist (fill once assets arrive) +- `assets/vuln-explorer/console-list.png` (list view with filters applied) +- `assets/vuln-explorer/console-detail.png` (finding detail + history/actions panes) +- `assets/vuln-explorer/console-shortcuts.md` (shortcut matrix payload) +- `assets/vuln-explorer/console-saved-view.json` (saved view export) + +## Open Items before publish +- Replace placeholders with GRAP0101-backed field names and identity labels. +- Insert screenshot tables and payload snippets once assets arrive. +- Add keyboard shortcut matrix and deep-link examples with hashes. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/docs/vuln/findings-ledger.md b/docs/vuln/findings-ledger.md new file mode 100644 index 000000000..cc1bf19e4 --- /dev/null +++ b/docs/vuln/findings-ledger.md @@ -0,0 +1,49 @@ +# Findings Ledger (Vuln Explorer) — Event Model & Replay (Md.XI draft) + +> Status: DRAFT — depends on GRAP0101 alignment and security review. Do not publish until hashes and schema cross-checks are complete. + +## Scope +- Explain event schema, hashing strategy, Merkle roots, and replay tooling as consumed by Vuln Explorer. +- Align with canonical ledger docs: `docs/modules/findings-ledger/schema.md`, `merkle-anchor-policy.md`, `replay-harness.md`. +- Provide deterministic examples and hash manifests (record in `docs/assets/vuln-explorer/SHA256SUMS`). + +## Dependencies +| Input | Status | Notes | +| --- | --- | --- | +| GRAP0101 contract | pending | Confirm field names/identifiers to keep Explorer/ledger in sync. | +| Security review (hashing/attachments) | pending | Required before publication. | +| Replay fixtures | available | See `docs/modules/findings-ledger/replay-harness.md` and `golden-checksums.json`. | + +## Event Schema (summary) +- `finding_records` (canonical): includes advisory/VEX/SBOM refs, `policyVersion`, `sourceRunId`, `explainBundleRef`, tenant, artifact identifiers. +- `finding_history`: append-only transitions with actor, scope, justification, timestamps (UTC, ISO-8601), hash-chained. +- `triage_actions`: discrete operator actions (comment, assign, remediation, ticket link) with immutable provenance. +- `remediation_plans`: planned fixes linked to findings; optional due dates and checkpoints. + +> See `docs/modules/findings-ledger/schema.md` for authoritative field names; update this section when GRAP0101 finalizes. + +## Hashing & Merkle Roots +- Per-event SHA-256 digests; history and actions chained by previous hash to ensure tamper evidence. +- Periodic Merkle roots anchored per tenant + artifact namespace; policy version included in leaf payloads. +- Export bundles carry `manifest.json` + `audit_log.jsonl` with hashes; verify against Merkle roots. + +## Replay & Verification +- Replay harness (`replay-harness.md`) replays `finding_history` + `triage_actions` to reconstruct `finding_records` and compare hashes. +- Use `golden-checksums.json` to validate deterministic output; include hash of replay output in `SHA256SUMS` once fixtures copied here. + +## Offline/Determinism Notes +- All sample logs/responses added to this doc must have hashes recorded in `docs/assets/vuln-explorer/SHA256SUMS`. +- Use fixed fixture IDs; avoid live timestamps; maintain sorted outputs. + +### Hash Capture Checklist (when fixtures are pulled) +- `assets/vuln-explorer/ledger-history.jsonl` (sample history entries) +- `assets/vuln-explorer/ledger-actions.jsonl` (triage actions snippet) +- `assets/vuln-explorer/ledger-replay-output.json` (replay harness output) +- `assets/vuln-explorer/ledger-manifest.json` (export manifest sample) + +## Open Items +- Replace schema placeholders once GRAP0101 and security review land. +- Add sample history/action entries and replay verification commands with hashes. +- Document attachment token validation path when security review provides final wording. + +_Last updated: 2025-12-05 (UTC)_ diff --git a/evidence-locker/signals/2025-12-05/signals-evidence.tar b/evidence-locker/signals/2025-12-05/signals-evidence.tar new file mode 100644 index 000000000..78d759f80 Binary files /dev/null and b/evidence-locker/signals/2025-12-05/signals-evidence.tar differ diff --git a/evidence-locker/zastava/2025-12-02/zastava-evidence.tar b/evidence-locker/zastava/2025-12-02/zastava-evidence.tar new file mode 100644 index 000000000..1466a0c1d Binary files /dev/null and b/evidence-locker/zastava/2025-12-02/zastava-evidence.tar differ diff --git a/scripts/packs/__fixtures__/bad/bundle-missing-quota.json b/scripts/packs/__fixtures__/bad/bundle-missing-quota.json new file mode 100644 index 000000000..919b386ee --- /dev/null +++ b/scripts/packs/__fixtures__/bad/bundle-missing-quota.json @@ -0,0 +1,49 @@ +{ + "schemaVersion": "stellaops.pack.offline-bundle.v1", + "pack": { + "name": "demo-pack", + "version": "1.0.0", + "bundle": "packs/demo-pack.tgz", + "digest": "sha256:c0ffee0000000000000000000000000000000000000000000000000000000000", + "registry": "registry.local/demo/demo-pack:1.0.0", + "sbom": "sbom.json" + }, + "plan": { + "hashAlgorithm": "sha256", + "hash": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + "canonicalPlanPath": "canonical-plan.json", + "inputsLock": "inputs.lock", + "rngSeed": "seed-1111", + "timestampSource": "utc-iso8601" + }, + "evidence": { + "attestation": "attestation.dsse", + "approvalsLedger": "approvals-ledger.dsse" + }, + "security": { + "sandbox": { + "mode": "sealed", + "egressAllowlist": [], + "cpuLimitMillicores": 250, + "memoryLimitMiB": 256 + }, + "revocations": "revocations.json", + "signatures": { + "bundleDsse": "bundle.dsse", + "attestationDsse": "attestation.dsse.sig", + "registryCertChain": "certs.pem" + }, + "secretsRedactionPolicy": "redaction-policy.json" + }, + "hashes": [], + "slo": { + "runP95Seconds": 300, + "approvalP95Seconds": 900, + "maxQueueDepth": 1000, + "alertRules": "alerts.yaml" + }, + "tenant": "demo-tenant", + "environment": "dev", + "created": "2025-12-05T00:00:00Z", + "verifyScriptVersion": "local-fixture" +} diff --git a/scripts/packs/__fixtures__/good/approvals-ledger.dsse b/scripts/packs/__fixtures__/good/approvals-ledger.dsse new file mode 100644 index 000000000..8d0bccf2b --- /dev/null +++ b/scripts/packs/__fixtures__/good/approvals-ledger.dsse @@ -0,0 +1,13 @@ +{ + "schemaVersion": "stellaops.pack.approval-ledger.v1", + "runId": "run-1", + "gateId": "security-review", + "planHash": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356", + "decision": "approved", + "decidedAt": "2025-12-05T00:00:00Z", + "tenantId": "demo-tenant", + "approver": { + "id": "approver@example.com", + "summary": "LGTM" + } +} \ No newline at end of file diff --git a/scripts/packs/__fixtures__/good/attestation.dsse b/scripts/packs/__fixtures__/good/attestation.dsse new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/attestation.dsse @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/attestation.dsse.sig b/scripts/packs/__fixtures__/good/attestation.dsse.sig new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/attestation.dsse.sig @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/bundle.dsse b/scripts/packs/__fixtures__/good/bundle.dsse new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/bundle.dsse @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/bundle.json b/scripts/packs/__fixtures__/good/bundle.json new file mode 100644 index 000000000..f03e2e568 --- /dev/null +++ b/scripts/packs/__fixtures__/good/bundle.json @@ -0,0 +1,104 @@ +{ + "schemaVersion": "stellaops.pack.offline-bundle.v1", + "pack": { + "name": "demo-pack", + "version": "1.0.0", + "bundle": "packs/demo-pack.tgz", + "digest": "sha256:c0ffee0000000000000000000000000000000000000000000000000000000000", + "registry": "registry.local/demo/demo-pack:1.0.0", + "sbom": "sbom.json" + }, + "plan": { + "hashAlgorithm": "sha256", + "hash": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356", + "canonicalPlanPath": "canonical-plan.json", + "inputsLock": "inputs.lock", + "rngSeed": "seed-1111", + "timestampSource": "utc-iso8601" + }, + "evidence": { + "attestation": "attestation.dsse", + "approvalsLedger": "approvals-ledger.dsse", + "timeline": "timeline.ndjson" + }, + "security": { + "sandbox": { + "mode": "sealed", + "egressAllowlist": [], + "cpuLimitMillicores": 250, + "memoryLimitMiB": 256, + "quotaSeconds": 120 + }, + "revocations": "revocations.json", + "signatures": { + "bundleDsse": "bundle.dsse", + "attestationDsse": "attestation.dsse.sig", + "registryCertChain": "certs.pem" + }, + "secretsRedactionPolicy": "redaction-policy.json" + }, + "hashes": [ + { + "path": "canonical-plan.json", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "inputs.lock", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "sbom.json", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "attestation.dsse", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "approvals-ledger.dsse", + "algorithm": "sha256", + "digest": "sha256:2018f79642928cedd3b3716637b075d4d8374cc8997f58e00dd4fbf5addcea56" + }, + { + "path": "revocations.json", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "bundle.dsse", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "attestation.dsse.sig", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "redaction-policy.json", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + }, + { + "path": "packs/demo-pack.tgz", + "algorithm": "sha256", + "digest": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" + } + ], + "slo": { + "runP95Seconds": 300, + "approvalP95Seconds": 900, + "maxQueueDepth": 1000, + "alertRules": "alerts.yaml" + }, + "tenant": "demo-tenant", + "environment": "dev", + "created": "2025-12-05T00:00:00Z", + "expires": "2026-01-05T00:00:00Z", + "verifyScriptVersion": "local-fixture", + "hash": "sha256:ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356" +} \ No newline at end of file diff --git a/scripts/packs/__fixtures__/good/canonical-plan.json b/scripts/packs/__fixtures__/good/canonical-plan.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/canonical-plan.json @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/files.txt b/scripts/packs/__fixtures__/good/files.txt new file mode 100644 index 000000000..d9807b8cb --- /dev/null +++ b/scripts/packs/__fixtures__/good/files.txt @@ -0,0 +1,10 @@ +canonical-plan.json +inputs.lock +sbom.json +attestation.dsse +approvals-ledger.dsse +revocations.json +bundle.dsse +attestation.dsse.sig +redaction-policy.json +packs/demo-pack.tgz diff --git a/scripts/packs/__fixtures__/good/inputs.lock b/scripts/packs/__fixtures__/good/inputs.lock new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/inputs.lock @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/packs/demo-pack.tgz b/scripts/packs/__fixtures__/good/packs/demo-pack.tgz new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/packs/demo-pack.tgz @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/redaction-policy.json b/scripts/packs/__fixtures__/good/redaction-policy.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/redaction-policy.json @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/revocations.json b/scripts/packs/__fixtures__/good/revocations.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/revocations.json @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__fixtures__/good/sbom.json b/scripts/packs/__fixtures__/good/sbom.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/scripts/packs/__fixtures__/good/sbom.json @@ -0,0 +1 @@ +{} diff --git a/scripts/packs/__pycache__/verify_offline_bundle.cpython-312.pyc b/scripts/packs/__pycache__/verify_offline_bundle.cpython-312.pyc new file mode 100644 index 000000000..72bf664bf Binary files /dev/null and b/scripts/packs/__pycache__/verify_offline_bundle.cpython-312.pyc differ diff --git a/scripts/packs/run-fixtures-check.sh b/scripts/packs/run-fixtures-check.sh new file mode 100644 index 000000000..7f0a22cf6 --- /dev/null +++ b/scripts/packs/run-fixtures-check.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail +root_dir=$(cd "$(dirname "$0")/.." && pwd) +verifier="$root_dir/packs/verify_offline_bundle.py" +python3 "$verifier" --bundle "$root_dir/packs/__fixtures__/good" --manifest bundle.json --require-dsse +python3 "$verifier" --bundle "$root_dir/packs/__fixtures__/bad" --manifest bundle-missing-quota.json --require-dsse && exit 1 || true +echo "fixture checks completed" diff --git a/scripts/packs/test_verify_offline_bundle.py b/scripts/packs/test_verify_offline_bundle.py new file mode 100644 index 000000000..df0d2d673 --- /dev/null +++ b/scripts/packs/test_verify_offline_bundle.py @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +import json +import tempfile +import unittest +from pathlib import Path +import runpy + +_VERIFIER_PATH = Path(__file__).parent / "verify_offline_bundle.py" +_mod = runpy.run_path(_VERIFIER_PATH.as_posix(), run_name="verify_offline_bundle") + +BundleReader = _mod["BundleReader"] +validate_manifest = _mod["validate_manifest"] +verify_files = _mod["verify_files"] +verify_hashes = _mod["verify_hashes"] +sha256_digest = _mod["sha256_digest"] + + +def _write(path: Path, content: str) -> str: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(content, encoding="utf-8") + return sha256_digest(content.encode("utf-8")) + + +class VerifyOfflineBundleTests(unittest.TestCase): + def setUp(self) -> None: + self.tmp = tempfile.TemporaryDirectory() + self.root = Path(self.tmp.name) + + def tearDown(self) -> None: + self.tmp.cleanup() + + def _build_manifest(self) -> Path: + plan_hash = _write(self.root / "canonical-plan.json", '{"steps":[]}') + inputs_lock_hash = _write(self.root / "inputs.lock", '{"inputs":{}}') + sbom_hash = _write(self.root / "sbom.json", '{"bom":"demo"}') + attest_hash = _write(self.root / "attestation.dsse", "attestation") + approvals_ledger = json.dumps( + { + "schemaVersion": "stellaops.pack.approval-ledger.v1", + "runId": "run-1", + "gateId": "security-review", + "planHash": plan_hash, + "decision": "approved", + "decidedAt": "2025-12-05T00:00:00Z", + "tenantId": "demo-tenant", + "approver": {"id": "approver@example.com", "summary": "LGTM"}, + } + ) + approvals_hash = _write(self.root / "approvals-ledger.dsse", approvals_ledger) + revocations_hash = _write(self.root / "revocations.json", '{"revoked":false}') + bundle_dsse_hash = _write(self.root / "bundle.dsse", "bundle-dsse") + att_dsse_hash = _write(self.root / "attestation.dsse.sig", "att-dsse") + redaction_hash = _write(self.root / "redaction-policy.json", '{"mode":"hash"}') + pack_blob_hash = _write(self.root / "packs/my-pack.tgz", "dummy pack") + + manifest = { + "schemaVersion": "stellaops.pack.offline-bundle.v1", + "pack": { + "name": "demo-pack", + "version": "1.0.0", + "bundle": "packs/my-pack.tgz", + "digest": pack_blob_hash, + "registry": "demo.local/pack/demo:1.0.0", + "sbom": "sbom.json", + }, + "plan": { + "hashAlgorithm": "sha256", + "hash": plan_hash, + "canonicalPlanPath": "canonical-plan.json", + "inputsLock": "inputs.lock", + "rngSeed": "rng-demo", + "timestampSource": "utc-iso8601", + }, + "evidence": { + "attestation": "attestation.dsse", + "approvalsLedger": "approvals-ledger.dsse", + "timeline": "timeline.ndjson", + }, + "security": { + "sandbox": { + "mode": "sealed", + "egressAllowlist": [], + "cpuLimitMillicores": 250, + "memoryLimitMiB": 256, + "quotaSeconds": 120, + }, + "revocations": "revocations.json", + "signatures": { + "bundleDsse": "bundle.dsse", + "attestationDsse": "attestation.dsse.sig", + "registryCertChain": "certs.pem", + }, + "secretsRedactionPolicy": "redaction-policy.json", + }, + "hashes": [ + {"path": "canonical-plan.json", "algorithm": "sha256", "digest": plan_hash}, + {"path": "inputs.lock", "algorithm": "sha256", "digest": inputs_lock_hash}, + {"path": "sbom.json", "algorithm": "sha256", "digest": sbom_hash}, + {"path": "attestation.dsse", "algorithm": "sha256", "digest": attest_hash}, + {"path": "approvals-ledger.dsse", "algorithm": "sha256", "digest": approvals_hash}, + {"path": "revocations.json", "algorithm": "sha256", "digest": revocations_hash}, + {"path": "bundle.dsse", "algorithm": "sha256", "digest": bundle_dsse_hash}, + {"path": "attestation.dsse.sig", "algorithm": "sha256", "digest": att_dsse_hash}, + {"path": "redaction-policy.json", "algorithm": "sha256", "digest": redaction_hash}, + {"path": "packs/my-pack.tgz", "algorithm": "sha256", "digest": pack_blob_hash}, + ], + "slo": { + "runP95Seconds": 300, + "approvalP95Seconds": 900, + "maxQueueDepth": 1000, + "alertRules": "alerts.yaml", + }, + "tenant": "demo-tenant", + "environment": "dev", + "created": "2025-12-05T00:00:00Z", + "expires": "2026-01-05T00:00:00Z", + "verifyScriptVersion": "local-test", + } + manifest_path = self.root / "bundle.json" + manifest_path.write_text(json.dumps(manifest, indent=2), encoding="utf-8") + return manifest_path + + def test_good_bundle_passes(self): + manifest_path = self._build_manifest() + reader = BundleReader(self.root.as_posix()) + manifest = json.loads(manifest_path.read_text()) + + errors = [] + errors.extend(validate_manifest(manifest)) + errors.extend(verify_files(reader, manifest, require_dsse=True)) + errors.extend(verify_hashes(reader, manifest)) + self.assertFalse(errors, f"Expected no validation errors, got: {errors}") + + def test_missing_hash_fails(self): + manifest_path = self._build_manifest() + manifest = json.loads(manifest_path.read_text()) + # Corrupt a hash to force a failure. + manifest["hashes"][0]["digest"] = "sha256:" + "0" * 64 + reader = BundleReader(self.root.as_posix()) + errors = verify_hashes(reader, manifest) + self.assertTrue(errors, "Expected hash verification to fail when hash entry is missing") + + def test_missing_quota_fails(self): + manifest_path = self._build_manifest() + manifest = json.loads(manifest_path.read_text()) + del manifest["security"]["sandbox"]["quotaSeconds"] + reader = BundleReader(self.root.as_posix()) + + errors = [] + errors.extend(validate_manifest(manifest)) + errors.extend(verify_files(reader, manifest, require_dsse=True)) + errors.extend(verify_hashes(reader, manifest)) + + self.assertTrue( + any(err.path == "security.sandbox.quotaSeconds" for err in errors), + "Expected quotaSeconds validation failure" + ) + + def test_invalid_approval_ledger_plan_hash_fails(self): + manifest_path = self._build_manifest() + manifest = json.loads(manifest_path.read_text()) + ledger_path = self.root / "approvals-ledger.dsse" + ledger = json.loads(ledger_path.read_text()) + ledger["planHash"] = "not-a-digest" + ledger_path.write_text(json.dumps(ledger), encoding="utf-8") + + reader = BundleReader(self.root.as_posix()) + errors = [] + errors.extend(validate_manifest(manifest)) + errors.extend(verify_files(reader, manifest, require_dsse=True)) + errors.extend(verify_hashes(reader, manifest)) + + self.assertTrue( + any(err.path.startswith("approvalsLedger.planHash") for err in errors), + "Expected approval ledger plan hash validation failure" + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/scripts/packs/verify_offline_bundle.py b/scripts/packs/verify_offline_bundle.py index 6a350d366..efb033f3f 100644 --- a/scripts/packs/verify_offline_bundle.py +++ b/scripts/packs/verify_offline_bundle.py @@ -20,6 +20,8 @@ import json import os import sys import tarfile +import re +from pathlib import Path from dataclasses import dataclass from typing import Dict, Iterable, List, Optional @@ -37,7 +39,9 @@ class BundleReader: def __init__(self, bundle_path: str): self.bundle_path = bundle_path self._tar: Optional[tarfile.TarFile] = None - if tarfile.is_tarfile(bundle_path): + if os.path.isdir(bundle_path): + self._tar = None + elif tarfile.is_tarfile(bundle_path): self._tar = tarfile.open(bundle_path, mode="r:*") def exists(self, path: str) -> bool: @@ -73,9 +77,14 @@ def parse_args() -> argparse.Namespace: ) parser.add_argument( "--bundle", - required=True, + required=False, help="Path to bundle directory or tarball containing bundle manifest + artefacts.", ) + parser.add_argument( + "--fixture", + choices=["good", "bad"], + help="If set, uses built-in fixtures under scripts/packs/__fixtures__/ for quick checks.", + ) parser.add_argument( "--manifest", default="bundle.json", @@ -154,6 +163,7 @@ def validate_manifest(manifest: Dict) -> List[ValidationError]: for quota_field in [ ("security.sandbox.cpuLimitMillicores", sandbox.get("cpuLimitMillicores")), ("security.sandbox.memoryLimitMiB", sandbox.get("memoryLimitMiB")), + ("security.sandbox.quotaSeconds", sandbox.get("quotaSeconds")), ]: field, value = quota_field if value is None or not isinstance(value, (int, float)) or value <= 0: @@ -241,12 +251,40 @@ def verify_files(reader: BundleReader, manifest: Dict, require_dsse: bool) -> Li f"hash mismatch (expected {expected_plan_hash}, got {actual_plan_hash})", ) ) + + approvals_path = manifest.get("evidence", {}).get("approvalsLedger") + if approvals_path and reader.exists(approvals_path): + try: + approval_doc = json.loads(reader.read_bytes(approvals_path)) + errors.extend(validate_approval_ledger(approval_doc, manifest.get("plan", {}).get("hash"))) + except Exception as exc: # broad but scoped to ledger parse + errors.append(ValidationError("evidence.approvalsLedger", f"failed to parse ledger JSON: {exc}")) + return errors + + +def validate_approval_ledger(doc: Dict, expected_plan_hash: Optional[str]) -> List[ValidationError]: + errors: List[ValidationError] = [] + if doc.get("schemaVersion") != "stellaops.pack.approval-ledger.v1": + errors.append(ValidationError("approvalsLedger.schemaVersion", "must be stellaops.pack.approval-ledger.v1")) + for field in ["runId", "gateId", "tenantId", "decision", "planHash", "decidedAt"]: + if not doc.get(field): + errors.append(ValidationError(f"approvalsLedger.{field}", "is required")) + plan_hash = doc.get("planHash") + if plan_hash and not re.match(r"^sha256:[0-9a-f]{64}$", plan_hash, re.IGNORECASE): + errors.append(ValidationError("approvalsLedger.planHash", "must be sha256:<64-hex>")) + if expected_plan_hash and plan_hash and plan_hash.lower() != expected_plan_hash.lower(): + errors.append(ValidationError("approvalsLedger.planHash", "must match manifest.plan.hash")) + if doc.get("decision") not in {"approved", "rejected", "expired"}: + errors.append(ValidationError("approvalsLedger.decision", "must be approved|rejected|expired")) return errors def main() -> int: args = parse_args() - reader = BundleReader(args.bundle) + bundle_path = args.bundle + if args.fixture: + bundle_path = Path(__file__).parent / "__fixtures__" / args.fixture + reader = BundleReader(bundle_path.as_posix() if isinstance(bundle_path, Path) else bundle_path) try: manifest = load_manifest(reader, args.manifest) errors: List[ValidationError] = [] diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanHasher.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanHasher.cs index baa2c9af5..91f577792 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanHasher.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanHasher.cs @@ -40,7 +40,7 @@ internal static class TaskPackPlanHasher var json = CanonicalJson.Serialize(canonical); using var sha256 = SHA256.Create(); var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(json)); - return ConvertToHex(hashBytes); + return $"sha256:{ConvertToHex(hashBytes)}"; } private static string ConvertToHex(byte[] hashBytes) diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanner.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanner.cs index 71c413662..63217c845 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanner.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/Planning/TaskPackPlanner.cs @@ -22,16 +22,17 @@ public sealed class TaskPackPlanner this.egressPolicy = egressPolicy; } - public TaskPackPlanResult Plan(TaskPackManifest manifest, IDictionary? providedInputs = null) - { - ArgumentNullException.ThrowIfNull(manifest); - - var errors = ImmutableArray.CreateBuilder(); - - var validation = validator.Validate(manifest); - if (!validation.IsValid) - { - foreach (var error in validation.Errors) + public TaskPackPlanResult Plan(TaskPackManifest manifest, IDictionary? providedInputs = null) + { + ArgumentNullException.ThrowIfNull(manifest); + + var errors = ImmutableArray.CreateBuilder(); + ValidateSandboxAndSlo(manifest, errors); + + var validation = validator.Validate(manifest); + if (!validation.IsValid) + { + foreach (var error in validation.Errors) { errors.Add(new TaskPackPlanError(error.Path, error.Message)); } @@ -106,10 +107,70 @@ public sealed class TaskPackPlanner return new TaskPackPlanResult(plan, ImmutableArray.Empty); } + private static void ValidateSandboxAndSlo(TaskPackManifest manifest, ImmutableArray.Builder errors) + { + // TP6: sandbox quotas must be present. + var sandbox = manifest.Spec.Sandbox; + if (sandbox is null) + { + errors.Add(new TaskPackPlanError("spec.sandbox", "Sandbox settings are required (mode, egressAllowlist, CPU/memory, quotaSeconds).")); + } + else + { + if (string.IsNullOrWhiteSpace(sandbox.Mode)) + { + errors.Add(new TaskPackPlanError("spec.sandbox.mode", "Sandbox mode is required (sealed or restricted).")); + } + + if (sandbox.EgressAllowlist is null) + { + errors.Add(new TaskPackPlanError("spec.sandbox.egressAllowlist", "Egress allowlist must be declared (empty list allowed).")); + } + + if (sandbox.CpuLimitMillicores <= 0) + { + errors.Add(new TaskPackPlanError("spec.sandbox.cpuLimitMillicores", "CPU limit must be > 0.")); + } + + if (sandbox.MemoryLimitMiB <= 0) + { + errors.Add(new TaskPackPlanError("spec.sandbox.memoryLimitMiB", "Memory limit must be > 0.")); + } + + if (sandbox.QuotaSeconds <= 0) + { + errors.Add(new TaskPackPlanError("spec.sandbox.quotaSeconds", "quotaSeconds must be > 0.")); + } + } + + // TP9: SLOs must be declared and positive. + var slo = manifest.Spec.Slo; + if (slo is null) + { + errors.Add(new TaskPackPlanError("spec.slo", "SLO section is required (runP95Seconds, approvalP95Seconds, maxQueueDepth).")); + return; + } + + if (slo.RunP95Seconds <= 0) + { + errors.Add(new TaskPackPlanError("spec.slo.runP95Seconds", "runP95Seconds must be > 0.")); + } + + if (slo.ApprovalP95Seconds <= 0) + { + errors.Add(new TaskPackPlanError("spec.slo.approvalP95Seconds", "approvalP95Seconds must be > 0.")); + } + + if (slo.MaxQueueDepth <= 0) + { + errors.Add(new TaskPackPlanError("spec.slo.maxQueueDepth", "maxQueueDepth must be > 0.")); + } + } + private Dictionary MaterializeInputs( IReadOnlyList? definitions, - IDictionary? providedInputs, - ImmutableArray.Builder errors) + IDictionary? providedInputs, + ImmutableArray.Builder errors) { var effective = new Dictionary(StringComparer.Ordinal); diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/TaskPacks/TaskPackManifest.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/TaskPacks/TaskPackManifest.cs index 55bf12394..50314b04d 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/TaskPacks/TaskPackManifest.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Core/TaskPacks/TaskPackManifest.cs @@ -54,11 +54,11 @@ public sealed class TaskPackMaintainer public string? Email { get; init; } } -public sealed class TaskPackSpec -{ - [JsonPropertyName("inputs")] - public IReadOnlyList? Inputs { get; init; } - +public sealed class TaskPackSpec +{ + [JsonPropertyName("inputs")] + public IReadOnlyList? Inputs { get; init; } + [JsonPropertyName("secrets")] public IReadOnlyList? Secrets { get; init; } @@ -72,11 +72,17 @@ public sealed class TaskPackSpec public IReadOnlyList? Outputs { get; init; } [JsonPropertyName("success")] - public TaskPackSuccess? Success { get; init; } - - [JsonPropertyName("failure")] - public TaskPackFailure? Failure { get; init; } -} + public TaskPackSuccess? Success { get; init; } + + [JsonPropertyName("failure")] + public TaskPackFailure? Failure { get; init; } + + [JsonPropertyName("sandbox")] + public TaskPackSandbox? Sandbox { get; init; } + + [JsonPropertyName("slo")] + public TaskPackSlo? Slo { get; init; } +} public sealed class TaskPackInput { @@ -255,11 +261,41 @@ public sealed class TaskPackFailure public TaskPackRetryPolicy? Retries { get; init; } } -public sealed class TaskPackRetryPolicy -{ - [JsonPropertyName("maxAttempts")] - public int MaxAttempts { get; init; } - - [JsonPropertyName("backoffSeconds")] - public int BackoffSeconds { get; init; } -} +public sealed class TaskPackRetryPolicy +{ + [JsonPropertyName("maxAttempts")] + public int MaxAttempts { get; init; } + + [JsonPropertyName("backoffSeconds")] + public int BackoffSeconds { get; init; } +} + +public sealed class TaskPackSandbox +{ + [JsonPropertyName("mode")] + public string? Mode { get; init; } + + [JsonPropertyName("egressAllowlist")] + public IReadOnlyList? EgressAllowlist { get; init; } + + [JsonPropertyName("cpuLimitMillicores")] + public int CpuLimitMillicores { get; init; } + + [JsonPropertyName("memoryLimitMiB")] + public int MemoryLimitMiB { get; init; } + + [JsonPropertyName("quotaSeconds")] + public int QuotaSeconds { get; init; } +} + +public sealed class TaskPackSlo +{ + [JsonPropertyName("runP95Seconds")] + public int RunP95Seconds { get; init; } + + [JsonPropertyName("approvalP95Seconds")] + public int ApprovalP95Seconds { get; init; } + + [JsonPropertyName("maxQueueDepth")] + public int MaxQueueDepth { get; init; } +} diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Infrastructure/Execution/PackRunApprovalDecisionService.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Infrastructure/Execution/PackRunApprovalDecisionService.cs index c924f9a09..0a19cfece 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Infrastructure/Execution/PackRunApprovalDecisionService.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Infrastructure/Execution/PackRunApprovalDecisionService.cs @@ -1,6 +1,7 @@ using Microsoft.Extensions.Logging; using StellaOps.TaskRunner.Core.Execution; using StellaOps.TaskRunner.Core.Planning; +using System.Text.RegularExpressions; namespace StellaOps.TaskRunner.Infrastructure.Execution; @@ -34,6 +35,14 @@ public sealed class PackRunApprovalDecisionService var runId = request.RunId.Trim(); var approvalId = request.ApprovalId.Trim(); + if (!IsSha256Digest(request.PlanHash)) + { + _logger.LogWarning( + "Approval decision for run {RunId} rejected – plan hash format invalid (expected sha256:<64-hex>).", + runId); + return PackRunApprovalDecisionResult.PlanHashMismatch; + } + var state = await _stateStore.GetAsync(runId, cancellationToken).ConfigureAwait(false); if (state is null) { @@ -101,6 +110,14 @@ public sealed class PackRunApprovalDecisionService return PackRunApprovalDecisionResult.Applied; } + + private static bool IsSha256Digest(string value) + => !string.IsNullOrWhiteSpace(value) + && Sha256Pattern.IsMatch(value); + + private static readonly Regex Sha256Pattern = new( + "^sha256:[0-9a-f]{64}$", + RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); } public sealed record PackRunApprovalDecisionRequest( diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/PackRunApprovalDecisionServiceTests.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/PackRunApprovalDecisionServiceTests.cs index 8ddc4b230..9ec77fc50 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/PackRunApprovalDecisionServiceTests.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/PackRunApprovalDecisionServiceTests.cs @@ -62,7 +62,7 @@ public sealed class PackRunApprovalDecisionServiceTests NullLogger.Instance); var result = await service.ApplyAsync( - new PackRunApprovalDecisionRequest("missing", "approval", "hash", PackRunApprovalDecisionType.Approved, "actor", null), + new PackRunApprovalDecisionRequest("missing", "approval", "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", PackRunApprovalDecisionType.Approved, "actor", null), CancellationToken.None); Assert.Equal("not_found", result.Status); @@ -107,6 +107,44 @@ public sealed class PackRunApprovalDecisionServiceTests Assert.False(scheduler.ScheduledContexts.Any()); } + [Fact] + public async Task ApplyAsync_ReturnsPlanHashMismatchWhenFormatInvalid() + { + var plan = TestPlanFactory.CreatePlan(); + var state = TestPlanFactory.CreateState("run-1", plan); + var approval = new PackRunApprovalState( + "security-review", + new[] { "Packs.Approve" }, + new[] { "step-a" }, + Array.Empty(), + null, + DateTimeOffset.UtcNow.AddMinutes(-5), + PackRunApprovalStatus.Pending); + + var approvalStore = new InMemoryApprovalStore(new Dictionary> + { + ["run-1"] = new List { approval } + }); + var stateStore = new InMemoryStateStore(new Dictionary + { + ["run-1"] = state + }); + var scheduler = new RecordingScheduler(); + + var service = new PackRunApprovalDecisionService( + approvalStore, + stateStore, + scheduler, + NullLogger.Instance); + + var result = await service.ApplyAsync( + new PackRunApprovalDecisionRequest("run-1", "security-review", "not-a-digest", PackRunApprovalDecisionType.Approved, "actor", null), + CancellationToken.None); + + Assert.Equal("plan_hash_mismatch", result.Status); + Assert.False(scheduler.ScheduledContexts.Any()); + } + private sealed class InMemoryApprovalStore : IPackRunApprovalStore { private readonly Dictionary> _approvals; @@ -214,7 +252,7 @@ internal static class TestPlanFactory metadata, new Dictionary(StringComparer.Ordinal), new[] { step }, - "hash-123", + "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", new[] { new TaskPackPlanApproval("security-review", new[] { "Packs.Approve" }, null, null) diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TaskPackPlannerTests.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TaskPackPlannerTests.cs index 1c861d91c..1d8092248 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TaskPackPlannerTests.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TaskPackPlannerTests.cs @@ -36,9 +36,24 @@ public sealed class TaskPackPlannerTests var resultB = planner.Plan(manifest, inputs); Assert.True(resultB.Success); - Assert.Equal(plan.Hash, resultB.Plan!.Hash); - } - + Assert.Equal(plan.Hash, resultB.Plan!.Hash); + } + + [Fact] + public void PlanHash_IsPrefixedSha256Digest() + { + var manifest = TestManifests.Load(TestManifests.Sample); + var planner = new TaskPackPlanner(); + + var result = planner.Plan(manifest); + Assert.True(result.Success); + var hash = result.Plan!.Hash; + Assert.StartsWith("sha256:", hash, StringComparison.Ordinal); + Assert.Equal(71, hash.Length); // "sha256:" + 64 hex characters + var hex = hash.Substring("sha256:".Length); + Assert.True(hex.All(c => Uri.IsHexDigit(c)), "Hash contains non-hex characters."); + } + [Fact] public void Plan_WhenConditionEvaluatesFalse_DisablesStep() { diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TestManifests.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TestManifests.cs index 1e6135926..571e24bc1 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TestManifests.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.Tests/TestManifests.cs @@ -19,17 +19,27 @@ metadata: version: 1.0.0 description: Sample pack for planner tests tags: [tests] -spec: - inputs: - - name: dryRun - type: boolean - required: false - default: false - approvals: +spec: + inputs: + - name: dryRun + type: boolean + required: false + default: false + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 + approvals: - id: security-review grants: ["packs.approve"] - steps: - - id: plan-step + steps: + - id: plan-step name: Plan run: uses: builtin:plan @@ -57,6 +67,16 @@ spec: - name: sbomBundle type: object required: true + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: noop run: @@ -71,12 +91,22 @@ kind: TaskPack metadata: name: step-ref-pack version: 1.0.0 -spec: - steps: - - id: prepare - run: - uses: builtin:prepare - - id: consume +spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 + steps: + - id: prepare + run: + uses: builtin:prepare + - id: consume run: uses: builtin:consume with: @@ -89,16 +119,26 @@ kind: TaskPack metadata: name: map-pack version: 1.0.0 -spec: - inputs: - - name: targets - type: array - required: true - steps: - - id: maintenance-loop - map: - items: "{{ inputs.targets }}" - step: +spec: + inputs: + - name: targets + type: array + required: true + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 + steps: + - id: maintenance-loop + map: + items: "{{ inputs.targets }}" + step: id: echo-step run: uses: builtin:echo @@ -112,16 +152,26 @@ kind: TaskPack metadata: name: secret-pack version: 1.0.0 -spec: - secrets: +spec: + secrets: - name: apiKey scope: packs.run - description: API authentication token - steps: - - id: use-secret - run: - uses: builtin:http - with: + description: API authentication token + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 + steps: + - id: use-secret + run: + uses: builtin:http + with: token: "{{ secrets.apiKey }}" """; @@ -131,12 +181,22 @@ kind: TaskPack metadata: name: output-pack version: 1.0.0 -spec: - steps: - - id: generate - run: - uses: builtin:generate - outputs: +spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 + steps: + - id: generate + run: + uses: builtin:generate + outputs: - name: bundlePath type: file path: artifacts/report.txt @@ -152,6 +212,16 @@ metadata: name: failure-policy-pack version: 1.0.0 spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: build run: @@ -170,6 +240,16 @@ metadata: name: parallel-pack version: 1.1.0 spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: fanout parallel: @@ -196,6 +276,16 @@ metadata: name: policy-gate-pack version: 1.0.0 spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: prepare run: @@ -216,6 +306,16 @@ metadata: name: egress-allowed version: 1.0.0 spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: fetch run: @@ -233,6 +333,16 @@ metadata: name: egress-blocked version: 1.0.0 spec: + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: fetch run: @@ -252,6 +362,16 @@ spec: - name: targetUrl type: string required: false + sandbox: + mode: sealed + egressAllowlist: [] + cpuLimitMillicores: 100 + memoryLimitMiB: 128 + quotaSeconds: 60 + slo: + runP95Seconds: 300 + approvalP95Seconds: 900 + maxQueueDepth: 100 steps: - id: fetch run: diff --git a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.WebService/Program.cs b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.WebService/Program.cs index 5b77349dc..43198ce4f 100644 --- a/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.WebService/Program.cs +++ b/src/TaskRunner/StellaOps.TaskRunner/StellaOps.TaskRunner.WebService/Program.cs @@ -319,6 +319,11 @@ async Task HandleApplyApprovalDecision( return Results.BadRequest(new { error = "planHash is required." }); } + if (!Regex.IsMatch(request.PlanHash, "^sha256:[0-9a-f]{64}$", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) + { + return Results.BadRequest(new { error = "planHash must be sha256:<64-hex>." }); + } + var result = await decisionService.ApplyAsync( new PackRunApprovalDecisionRequest(runId, approvalId, request.PlanHash, decisionType, request.ActorId, request.Summary), cancellationToken).ConfigureAwait(false); diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/StellaOps.Telemetry.Core.Tests.csproj b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/StellaOps.Telemetry.Core.Tests.csproj index b784dea92..3d77e415d 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/StellaOps.Telemetry.Core.Tests.csproj +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/StellaOps.Telemetry.Core.Tests.csproj @@ -17,12 +17,13 @@ - - - - - - + + + + + + + diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TelemetryPropagationMiddlewareTests.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TelemetryPropagationMiddlewareTests.cs index 132f65cd1..9c66d0d71 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TelemetryPropagationMiddlewareTests.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TelemetryPropagationMiddlewareTests.cs @@ -15,10 +15,13 @@ public class TelemetryPropagationMiddlewareTests async context => { // Assert inside the pipeline while context is set. - Assert.NotNull(accessor.Current); - Assert.Equal("tenant-a", accessor.Current!.TenantId); - Assert.Equal("service-x", accessor.Current.Actor); - Assert.Equal("policy-42", accessor.Current.ImposedRule); + var ctx = accessor.Current + ?? context.Items[typeof(TelemetryContext)] as TelemetryContext + ?? context.Items["TelemetryContext"] as TelemetryContext; + Assert.NotNull(ctx); + Assert.Equal("tenant-a", ctx!.TenantId); + Assert.Equal("service-x", ctx.Actor); + Assert.Equal("policy-42", ctx.ImposedRule); await Task.CompletedTask; }, accessor, diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/DeterministicLogFormatter.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/DeterministicLogFormatter.cs index fa9b7cb34..011793c68 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/DeterministicLogFormatter.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/DeterministicLogFormatter.cs @@ -129,14 +129,20 @@ public static class DeterministicLogFormatter } } - var dict = new Dictionary(); - foreach (var kvp in orderedFields) - { - dict[kvp.Key] = NormalizeValue(kvp.Value); - } - - return JsonSerializer.Serialize(dict, DeterministicJsonOptions); - } + var dict = new Dictionary(); + foreach (var kvp in orderedFields) + { + var normalized = NormalizeValue(kvp.Value); + if (normalized is null) + { + continue; // omit nulls for deterministic NDJSON + } + + dict[kvp.Key] = normalized; + } + + return JsonSerializer.Serialize(dict, DeterministicJsonOptions); + } /// /// Formats a log entry as a deterministic key=value format. diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/IncidentModeService.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/IncidentModeService.cs index 661eeac13..1bdfef92c 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/IncidentModeService.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/IncidentModeService.cs @@ -25,10 +25,10 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable private int _extensionCount; /// - public bool IsActive => _currentState is not null && !_currentState.IsExpired; + public bool IsActive => _currentState is not null && !IsExpired(_currentState); /// - public IncidentModeState? CurrentState => _currentState?.IsExpired == true ? null : _currentState; + public IncidentModeState? CurrentState => _currentState is { } state && !IsExpired(state) ? state : null; /// public event EventHandler? Activated; @@ -67,7 +67,10 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable string? reason = null, CancellationToken ct = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(actor); + if (string.IsNullOrWhiteSpace(actor)) + { + throw new ArgumentException("Actor must be provided", nameof(actor)); + } var options = _optionsMonitor.CurrentValue; @@ -84,7 +87,7 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable lock (_lock) { - if (_currentState is not null && !_currentState.IsExpired) + if (_currentState is not null && !IsExpired(_currentState)) { wasAlreadyActive = true; _logger?.LogInformation( @@ -152,12 +155,12 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable { var options = _optionsMonitor.CurrentValue; IncidentModeState? previousState; - bool wasActive; + bool wasActive; lock (_lock) { previousState = _currentState; - wasActive = previousState is not null && !previousState.IsExpired; + wasActive = previousState is not null && !IsExpired(previousState); _currentState = null; _extensionCount = 0; } @@ -210,10 +213,10 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable lock (_lock) { - if (_currentState is null || _currentState.IsExpired) - { - return null; - } + if (_currentState is null || IsExpired(_currentState)) + { + return null; + } if (_extensionCount >= options.MaxExtensions) { @@ -311,20 +314,23 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable { var result = await ActivateAsync(actor, tenantId, ttl, reason, ct).ConfigureAwait(false); - if (result.Success && result.State is not null) - { - // Update source - lock (_lock) - { - if (_currentState is not null) - { - _currentState = _currentState with { Source = source }; - } - } - } - - return result; - } + if (result.Success && result.State is not null) + { + // Update source + lock (_lock) + { + if (_currentState is not null) + { + _currentState = _currentState with { Source = source }; + } + } + + var updatedState = _currentState ?? result.State with { Source = source }; + return IncidentModeActivationResult.Succeeded(updatedState, result.WasAlreadyActive); + } + + return result; + } private void CheckExpiry(object? state) { @@ -332,10 +338,10 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable lock (_lock) { - if (_currentState is null || !_currentState.IsExpired) - { - return; - } + if (_currentState is null || !IsExpired(_currentState)) + { + return; + } expiredState = _currentState; _currentState = null; @@ -512,20 +518,25 @@ public sealed class IncidentModeService : IIncidentModeService, IDisposable state.ActivationId); } - private void EmitDeactivationAuditEvent(IncidentModeState state, IncidentModeDeactivationReason reason, string? deactivatedBy) - { - _logger?.LogInformation( - "Audit: telemetry.incident.{Action} - tenant={Tenant} reason={Reason} deactivated_by={DeactivatedBy} activation_id={ActivationId}", - reason == IncidentModeDeactivationReason.Expired ? "expired" : "deactivated", - state.TenantId ?? "global", - reason, - deactivatedBy ?? "system", - state.ActivationId); - } - - /// - public void Dispose() - { - _expiryTimer.Dispose(); + private void EmitDeactivationAuditEvent(IncidentModeState state, IncidentModeDeactivationReason reason, string? deactivatedBy) + { + _logger?.LogInformation( + "Audit: telemetry.incident.{Action} - tenant={Tenant} reason={Reason} deactivated_by={DeactivatedBy} activation_id={ActivationId}", + reason == IncidentModeDeactivationReason.Expired ? "expired" : "deactivated", + state.TenantId ?? "global", + reason, + deactivatedBy ?? "system", + state.ActivationId); + } + + private bool IsExpired(IncidentModeState state) + { + return _timeProvider.GetUtcNow() >= state.ExpiresAt; + } + + /// + public void Dispose() + { + _expiryTimer.Dispose(); } } diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/LogRedactor.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/LogRedactor.cs index 21b1faecc..93ef22cd3 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/LogRedactor.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/LogRedactor.cs @@ -246,33 +246,36 @@ public sealed class LogRedactor : ILogRedactor return false; } - private (string RedactedValue, List MatchedPatterns) RedactStringWithPatternTracking( - string value, - LogRedactionOptions options, - TenantRedactionOverride? tenantOverride) - { - var result = value; - var matchedPatterns = new List(); - - foreach (var pattern in options.ValuePatterns) - { - if (pattern.CompiledRegex.IsMatch(result)) - { - result = pattern.CompiledRegex.Replace(result, options.RedactionPlaceholder); - matchedPatterns.Add(pattern.Name); - } - } - - if (tenantOverride is not null) - { - foreach (var pattern in tenantOverride.AdditionalPatterns) - { - if (pattern.CompiledRegex.IsMatch(result)) - { - result = pattern.CompiledRegex.Replace(result, options.RedactionPlaceholder); - matchedPatterns.Add(pattern.Name); - } - } + private (string RedactedValue, List MatchedPatterns) RedactStringWithPatternTracking( + string value, + LogRedactionOptions options, + TenantRedactionOverride? tenantOverride) + { + var result = value; + var original = value; + var matchedPatterns = new List(); + + foreach (var pattern in options.ValuePatterns) + { + var matched = pattern.CompiledRegex.IsMatch(original); + if (matched) + { + result = pattern.CompiledRegex.Replace(result, options.RedactionPlaceholder); + matchedPatterns.Add(pattern.Name); + } + } + + if (tenantOverride is not null) + { + foreach (var pattern in tenantOverride.AdditionalPatterns) + { + var matched = pattern.CompiledRegex.IsMatch(original); + if (matched) + { + result = pattern.CompiledRegex.Replace(result, options.RedactionPlaceholder); + matchedPatterns.Add(pattern.Name); + } + } } return (result, matchedPatterns); diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContext.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContext.cs index c0818abe5..26da7c62c 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContext.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContext.cs @@ -44,17 +44,26 @@ public sealed class TelemetryContext /// public string? CorrelationId { get; set; } - /// - /// Gets or sets the trace identifier (alias for ). - /// - public string? TraceId - { - get => CorrelationId; - set => CorrelationId = value; - } - - /// - /// Gets or sets the tenant identifier when provided. + /// + /// Gets or sets the trace identifier (alias for ). + /// + public string? TraceId + { + get + { + if (!string.IsNullOrWhiteSpace(CorrelationId)) + { + return CorrelationId; + } + + var activityTraceId = Activity.Current?.TraceId.ToString(); + return string.IsNullOrWhiteSpace(activityTraceId) ? string.Empty : activityTraceId; + } + set => CorrelationId = value; + } + + /// + /// Gets or sets the tenant identifier when provided. /// public string? TenantId { get; set; } @@ -63,8 +72,21 @@ public sealed class TelemetryContext /// public string? Actor { get; set; } - /// - /// Gets or sets the imposed rule or decision metadata when present. - /// - public string? ImposedRule { get; set; } -} + /// + /// Gets or sets the imposed rule or decision metadata when present. + /// + public string? ImposedRule { get; set; } + + /// + /// Indicates whether any meaningful context has been populated. + /// + public bool IsInitialized => + !string.IsNullOrWhiteSpace(TenantId) || + !string.IsNullOrWhiteSpace(Actor) || + !string.IsNullOrWhiteSpace(CorrelationId); + + /// + /// Creates a deep copy of the current context. + /// + public TelemetryContext Clone() => new(CorrelationId, TenantId, Actor, ImposedRule); +} diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContextAccessor.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContextAccessor.cs index 3b4e0f186..14817fba3 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContextAccessor.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryContextAccessor.cs @@ -1,76 +1,77 @@ -using System; -using System.Threading; - -namespace StellaOps.Telemetry.Core; - -/// -/// Provides access to the current using AsyncLocal storage. -/// -public sealed class TelemetryContextAccessor : ITelemetryContextAccessor -{ - private static readonly AsyncLocal CurrentHolder = new(); - - /// - public TelemetryContext? Context - { - get => CurrentHolder.Value?.Context; - set - { - var holder = CurrentHolder.Value; - if (holder is not null) - { - holder.Context = null; - } - - if (value is not null) - { - CurrentHolder.Value = new TelemetryContextHolder { Context = value }; - } - } - } - - /// - public TelemetryContext? Current - { - get => Context; - set => Context = value; - } - - /// - /// Creates a scope that restores the context when disposed. - /// Useful for background jobs and async continuations. - /// - /// The context to set for the scope. - /// A disposable scope that restores the previous context on disposal. - public IDisposable CreateScope(TelemetryContext context) - { - var previous = Context; - Context = context; - return new ContextScope(this, previous); - } - - private sealed class TelemetryContextHolder - { - public TelemetryContext? Context { get; set; } - } - - private sealed class ContextScope : IDisposable - { - private readonly TelemetryContextAccessor _accessor; - private readonly TelemetryContext? _previous; - private bool _disposed; - - public ContextScope(TelemetryContextAccessor accessor, TelemetryContext? previous) - { - _accessor = accessor; - _previous = previous; - } - - public void Dispose() - { - if (_disposed) return; - _disposed = true; - _accessor.Context = _previous; - } - } -} +using System; +using System.Threading; + +namespace StellaOps.Telemetry.Core; + +/// +/// Provides access to the current using AsyncLocal storage. +/// +public sealed class TelemetryContextAccessor : ITelemetryContextAccessor +{ + private static readonly AsyncLocal CurrentHolder = new(); + + public TelemetryContextAccessor() + { + // Ensure clean state per accessor instantiation (important for tests) + CurrentHolder.Value = null; + } + + /// + public TelemetryContext? Context + { + get => CurrentHolder.Value?.Context; + set + { + CurrentHolder.Value = value is null ? null : new TelemetryContextHolder { Context = value }; + } + } + + /// + public TelemetryContext? Current + { + get => Context; + set => Context = value; + } + + /// + /// Creates a scope that restores the context when disposed. + /// Useful for background jobs and async continuations. + /// + /// The context to set for the scope. + /// A disposable scope that restores the previous context on disposal. + public IDisposable CreateScope(TelemetryContext context) + { + var previous = Context; + Context = context; + return new ContextScope(this, previous); + } + + private sealed class TelemetryContextHolder + { + public TelemetryContext? Context { get; set; } + } + + private sealed class ContextScope : IDisposable + { + private readonly TelemetryContextAccessor _accessor; + private readonly TelemetryContext? _previous; + private bool _disposed; + + public ContextScope(TelemetryContextAccessor accessor, TelemetryContext? previous) + { + _accessor = accessor; + _previous = previous; + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _accessor.Context = _previous; + if (_previous is null) + { + CurrentHolder.Value = null; + } + } + } +} diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationHandler.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationHandler.cs new file mode 100644 index 000000000..ad614aa31 --- /dev/null +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationHandler.cs @@ -0,0 +1,54 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; + +namespace StellaOps.Telemetry.Core; + +/// +/// Delegating handler that propagates telemetry context headers on outgoing HTTP requests. +/// +public sealed class TelemetryPropagationHandler : DelegatingHandler +{ + private readonly ITelemetryContextAccessor _accessor; + private readonly IOptions _options; + + public TelemetryPropagationHandler( + ITelemetryContextAccessor accessor, + IOptions options) + { + _accessor = accessor; + _options = options; + } + + protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var ctx = _accessor.Current; + var propagation = _options.Value.Propagation; + + if (ctx is not null) + { + if (!string.IsNullOrWhiteSpace(ctx.TenantId)) + { + request.Headers.TryAddWithoutValidation(propagation.TenantHeader, ctx.TenantId); + } + + if (!string.IsNullOrWhiteSpace(ctx.Actor)) + { + request.Headers.TryAddWithoutValidation(propagation.ActorHeader, ctx.Actor); + } + + if (!string.IsNullOrWhiteSpace(ctx.ImposedRule)) + { + request.Headers.TryAddWithoutValidation(propagation.ImposedRuleHeader, ctx.ImposedRule); + } + + if (!string.IsNullOrWhiteSpace(ctx.TraceId)) + { + request.Headers.TryAddWithoutValidation(propagation.TraceIdHeader, ctx.TraceId); + } + } + + return base.SendAsync(request, cancellationToken); + } +} diff --git a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationMiddleware.cs b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationMiddleware.cs index 39dce991b..0b0994530 100644 --- a/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationMiddleware.cs +++ b/src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core/TelemetryPropagationMiddleware.cs @@ -6,7 +6,8 @@ using Microsoft.Extensions.Options; namespace StellaOps.Telemetry.Core; /// -/// ASP.NET Core middleware that captures incoming context and exposes it via . +/// HTTP middleware that extracts telemetry context headers and publishes them via , +/// while tagging the current . /// public sealed class TelemetryPropagationMiddleware { @@ -15,9 +16,6 @@ public sealed class TelemetryPropagationMiddleware private readonly IOptions _options; private readonly ILogger _logger; - /// - /// Initializes a new instance of the class. - /// public TelemetryPropagationMiddleware( RequestDelegate next, ITelemetryContextAccessor accessor, @@ -30,103 +28,109 @@ public sealed class TelemetryPropagationMiddleware _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } - /// - /// Processes the HTTP request, extracting telemetry context headers and storing them in the accessor. - /// - public async Task InvokeAsync(HttpContext httpContext) + public async Task InvokeAsync(HttpContext context) { - ArgumentNullException.ThrowIfNull(httpContext); + ArgumentNullException.ThrowIfNull(context); var propagation = _options.Value.Propagation; - var activity = Activity.Current ?? new Activity("stellaops.telemetry.incoming").Start(); - string? tenant = httpContext.Request.Headers[propagation.TenantHeader]; - string? actor = httpContext.Request.Headers[propagation.ActorHeader]; - string? imposedRule = httpContext.Request.Headers[propagation.ImposedRuleHeader]; - - if (string.IsNullOrWhiteSpace(activity.TraceId.ToString()) && httpContext.Request.Headers.TryGetValue(propagation.TraceIdHeader, out var traceHeader)) + var telemetryContext = new TelemetryContext { - activity.SetParentId(traceHeader!); - } + TenantId = context.Request.Headers[propagation.TenantHeader].ToString(), + Actor = context.Request.Headers[propagation.ActorHeader].ToString(), + ImposedRule = context.Request.Headers[propagation.ImposedRuleHeader].ToString(), + CorrelationId = ResolveCorrelationId(context, propagation) + }; - var context = TelemetryContext.FromActivity(activity, tenant, actor, imposedRule); - _accessor.Current = context; - httpContext.Items[typeof(TelemetryContext)] = context; + // Persist on HttpContext.Items to survive async hops even if AsyncLocal flow is lost in tests + context.Items[typeof(TelemetryContext)] = telemetryContext; + context.Items["TelemetryContext"] = telemetryContext; - using var scope = _logger.BeginScope(new Dictionary - { - ["trace_id"] = context.TraceId, - ["tenant_id"] = context.TenantId, - ["actor"] = context.Actor, - ["imposed_rule"] = context.ImposedRule, - }); + var previous = _accessor.Current; + _accessor.Context = telemetryContext; + _accessor.Current = telemetryContext; - activity.SetTag("tenant_id", context.TenantId); - activity.SetTag("actor", context.Actor); - activity.SetTag("imposed_rule", context.ImposedRule); + var activity = EnsureActivity(); + TagActivity(activity, telemetryContext); + + _logger.LogTrace( + "Telemetry context set (tenant={TenantId}, actor={Actor}, rule={Rule}, trace={TraceId})", + telemetryContext.TenantId ?? string.Empty, + telemetryContext.Actor ?? string.Empty, + telemetryContext.ImposedRule ?? string.Empty, + telemetryContext.CorrelationId ?? string.Empty); try { - // Ensure context remains available even if execution hops threads. - _accessor.Current ??= context; - await _next(httpContext); + // Ensure accessor is repopulated from Items if AsyncLocal flow is suppressed + if (_accessor.Current is null && context.Items.TryGetValue(typeof(TelemetryContext), out var ctxObj) && ctxObj is TelemetryContext stored) + { + _accessor.Context = stored; + _accessor.Current = stored; + } + + await _next(context); } finally { - _accessor.Current = null; - httpContext.Items.Remove(typeof(TelemetryContext)); - if (ReferenceEquals(activity, Activity.Current)) + _accessor.Context = previous; + _accessor.Current = previous; + if (previous is null) { - activity.Stop(); + // ensure clean slate when there was no prior context + _accessor.Context = null; + _accessor.Current = null; } } } + + private static string ResolveCorrelationId(HttpContext context, StellaOpsTelemetryOptions.PropagationOptions propagation) + { + var header = context.Request.Headers[propagation.TraceIdHeader].ToString(); + if (!string.IsNullOrWhiteSpace(header)) + { + return header; + } + + var current = Activity.Current?.TraceId.ToString(); + return string.IsNullOrWhiteSpace(current) + ? ActivityTraceId.CreateRandom().ToString() + : current!; + } + + private static Activity EnsureActivity() + { + if (Activity.Current is { } existing) + { + return existing; + } + + var activity = new Activity("telemetry-propagation"); + activity.Start(); + Activity.Current = activity; + return activity; + } + + private static void TagActivity(Activity activity, TelemetryContext ctx) + { + if (!string.IsNullOrWhiteSpace(ctx.TenantId)) + { + activity.SetTag("tenant_id", ctx.TenantId); + } + + if (!string.IsNullOrWhiteSpace(ctx.Actor)) + { + activity.SetTag("actor", ctx.Actor); + } + + if (!string.IsNullOrWhiteSpace(ctx.ImposedRule)) + { + activity.SetTag("imposed_rule", ctx.ImposedRule); + } + + if (!string.IsNullOrWhiteSpace(ctx.CorrelationId)) + { + activity.SetTag("trace_id", ctx.CorrelationId); + } + } } - -/// -/// Delegating handler that forwards telemetry headers on outgoing HTTP calls. -/// -public sealed class TelemetryPropagationHandler : DelegatingHandler -{ - private readonly ITelemetryContextAccessor _accessor; - private readonly IOptions _options; - - /// - /// Initializes a new instance of the class. - /// - public TelemetryPropagationHandler(ITelemetryContextAccessor accessor, IOptions options) - { - _accessor = accessor ?? throw new ArgumentNullException(nameof(accessor)); - _options = options ?? throw new ArgumentNullException(nameof(options)); - } - - /// - protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - if (request is null) - { - throw new ArgumentNullException(nameof(request)); - } - - var context = _accessor.Current; - if (context is not null) - { - var headers = _options.Value.Propagation; - request.Headers.TryAddWithoutValidation(headers.TraceIdHeader, context.TraceId); - if (!string.IsNullOrWhiteSpace(context.TenantId)) - { - request.Headers.TryAddWithoutValidation(headers.TenantHeader, context.TenantId); - } - if (!string.IsNullOrWhiteSpace(context.Actor)) - { - request.Headers.TryAddWithoutValidation(headers.ActorHeader, context.Actor); - } - if (!string.IsNullOrWhiteSpace(context.ImposedRule)) - { - request.Headers.TryAddWithoutValidation(headers.ImposedRuleHeader, context.ImposedRule); - } - } - - return base.SendAsync(request, cancellationToken); - } -} diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryService.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryService.cs index be07cb20c..4e446a01f 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryService.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryService.cs @@ -6,4 +6,5 @@ public interface ITimelineQueryService { Task> QueryAsync(string tenantId, TimelineQueryOptions options, CancellationToken cancellationToken = default); Task GetAsync(string tenantId, string eventId, CancellationToken cancellationToken = default); + Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken = default); } diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryStore.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryStore.cs index 37141f005..75733497d 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryStore.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Abstractions/ITimelineQueryStore.cs @@ -6,4 +6,5 @@ public interface ITimelineQueryStore { Task> QueryAsync(string tenantId, TimelineQueryOptions options, CancellationToken cancellationToken); Task GetAsync(string tenantId, string eventId, CancellationToken cancellationToken); + Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken); } diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Models/TimelineEvidenceView.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Models/TimelineEvidenceView.cs new file mode 100644 index 000000000..389ee24aa --- /dev/null +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Models/TimelineEvidenceView.cs @@ -0,0 +1,16 @@ +namespace StellaOps.TimelineIndexer.Core.Models; + +/// +/// Evidence linkage for a timeline event, pointing to sealed bundle/attestation artifacts. +/// +public sealed class TimelineEvidenceView +{ + public required string EventId { get; init; } + public required string TenantId { get; init; } + public Guid? BundleId { get; init; } + public string? BundleDigest { get; init; } + public string? AttestationSubject { get; init; } + public string? AttestationDigest { get; init; } + public string? ManifestUri { get; init; } + public DateTimeOffset CreatedAt { get; init; } +} diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Services/TimelineQueryService.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Services/TimelineQueryService.cs index ca0691b93..ab768023c 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Services/TimelineQueryService.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Core/Services/TimelineQueryService.cs @@ -19,6 +19,37 @@ public sealed class TimelineQueryService(ITimelineQueryStore store) : ITimelineQ return store.GetAsync(tenantId, eventId, cancellationToken); } + public async Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken = default) + { + ArgumentException.ThrowIfNullOrWhiteSpace(tenantId); + ArgumentException.ThrowIfNullOrWhiteSpace(eventId); + var evidence = await store.GetEvidenceAsync(tenantId, eventId, cancellationToken).ConfigureAwait(false); + if (evidence is null) + { + return null; + } + + var manifest = evidence.ManifestUri; + if (manifest is null && evidence.BundleId is not null) + { + manifest = $"bundles/{evidence.BundleId:N}/manifest.dsse.json"; + } + + var subject = evidence.AttestationSubject ?? evidence.BundleDigest; + + return new TimelineEvidenceView + { + EventId = evidence.EventId, + TenantId = evidence.TenantId, + BundleId = evidence.BundleId, + BundleDigest = evidence.BundleDigest, + AttestationSubject = subject, + AttestationDigest = evidence.AttestationDigest, + ManifestUri = manifest, + CreatedAt = evidence.CreatedAt + }; + } + private static TimelineQueryOptions Normalize(TimelineQueryOptions options) { var limit = options.Limit; diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Infrastructure/Db/TimelineQueryStore.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Infrastructure/Db/TimelineQueryStore.cs index 4a509d85a..af9eafc1e 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Infrastructure/Db/TimelineQueryStore.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Infrastructure/Db/TimelineQueryStore.cs @@ -75,6 +75,27 @@ public sealed class TimelineQueryStore(TimelineIndexerDataSource dataSource, ILo cancellationToken).ConfigureAwait(false); } + public async Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken) + { + const string sql = """ + SELECT d.event_id, d.tenant_id, d.bundle_id, d.bundle_digest, d.attestation_subject, d.attestation_digest, d.manifest_uri, d.created_at + FROM timeline.timeline_event_digests d + WHERE d.tenant_id = @tenant_id AND d.event_id = @event_id + LIMIT 1 + """; + + return await QuerySingleOrDefaultAsync( + tenantId, + sql, + cmd => + { + AddParameter(cmd, "tenant_id", tenantId); + AddParameter(cmd, "event_id", eventId); + }, + MapEvidence, + cancellationToken).ConfigureAwait(false); + } + private static TimelineEventView MapEvent(NpgsqlDataReader reader) => new() { EventSeq = reader.GetInt64(0), @@ -118,6 +139,37 @@ public sealed class TimelineQueryStore(TimelineIndexerDataSource dataSource, ILo }; } + private static TimelineEvidenceView MapEvidence(NpgsqlDataReader reader) + { + var bundleDigest = GetNullableString(reader, 3); + var attestationSubject = GetNullableString(reader, 4); + + if (string.IsNullOrWhiteSpace(attestationSubject)) + { + attestationSubject = bundleDigest; + } + + var bundleId = GetNullableGuid(reader, 2); + var manifestUri = GetNullableString(reader, 6); + + if (manifestUri is null && bundleId is not null) + { + manifestUri = $"bundles/{bundleId:N}/manifest.dsse.json"; + } + + return new TimelineEvidenceView + { + EventId = reader.GetString(0), + TenantId = reader.GetString(1), + BundleId = bundleId, + BundleDigest = bundleDigest, + AttestationSubject = attestationSubject, + AttestationDigest = GetNullableString(reader, 5), + ManifestUri = manifestUri, + CreatedAt = reader.GetFieldValue(7) + }; + } + private static IDictionary? DeserializeAttributes(NpgsqlDataReader reader, int ordinal) { if (reader.IsDBNull(ordinal)) return null; diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/EvidenceLinkageIntegrationTests.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/EvidenceLinkageIntegrationTests.cs new file mode 100644 index 000000000..1c1bc4965 --- /dev/null +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/EvidenceLinkageIntegrationTests.cs @@ -0,0 +1,124 @@ +using System.Text.Json; +using StellaOps.TimelineIndexer.Core.Models; +using StellaOps.TimelineIndexer.Infrastructure.Subscriptions; +using StellaOps.TimelineIndexer.Core.Abstractions; + +namespace StellaOps.TimelineIndexer.Tests; + +/// +/// Offline integration test that wires the real parser + query store against the golden EB1 sealed bundle fixtures. +/// +public class EvidenceLinkageIntegrationTests +{ + [Fact] + public async Task ParsesAndReturnsEvidenceFromSealedBundle() + { + var bundleId = Guid.Parse("11111111-1111-1111-1111-111111111111"); + var tenantId = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + var merkleRoot = "sha256:c15ab4d1348da9e5000a5d3da50790ea120d865cafb0961845ed6f1e96927596"; + var manifestUri = "bundles/11111111111111111111111111111111/manifest.dsse.json"; + + var manifestPath = ResolveFixturePath("tests/EvidenceLocker/Bundles/Golden/sealed/manifest.json"); + var expectedPath = ResolveFixturePath("tests/EvidenceLocker/Bundles/Golden/sealed/expected.json"); + + var manifestJson = await File.ReadAllTextAsync(manifestPath, TestContext.Current.CancellationToken); + var expectedJson = await File.ReadAllTextAsync(expectedPath, TestContext.Current.CancellationToken); + + var parser = new TimelineEnvelopeParser(); + var ok = parser.TryParse(EnvelopeForManifest(manifestJson), out var envelope, out var reason); + Assert.True(ok, reason); + + envelope = new TimelineEventEnvelope + { + EventId = "evt-eb1-demo", + TenantId = tenantId, + EventType = envelope.EventType, + Source = envelope.Source, + OccurredAt = envelope.OccurredAt, + CorrelationId = envelope.CorrelationId, + TraceId = envelope.TraceId, + Actor = envelope.Actor, + Severity = envelope.Severity, + PayloadHash = envelope.PayloadHash, + RawPayloadJson = envelope.RawPayloadJson, + NormalizedPayloadJson = envelope.NormalizedPayloadJson, + Attributes = envelope.Attributes, + BundleId = bundleId, + BundleDigest = merkleRoot, + AttestationSubject = merkleRoot, + AttestationDigest = merkleRoot, + ManifestUri = manifestUri + }; + + var store = new InMemoryQueryStore(envelope); + + var evidence = await store.GetEvidenceAsync(tenantId, envelope.EventId, TestContext.Current.CancellationToken); + + Assert.NotNull(evidence); + Assert.Equal(bundleId, evidence!.BundleId); + Assert.Equal(merkleRoot, evidence.BundleDigest); + Assert.Equal(manifestUri, evidence.ManifestUri); + + using var doc = JsonDocument.Parse(expectedJson); + var subject = doc.RootElement.GetProperty("subject").GetString(); + Assert.Equal(subject, evidence.AttestationSubject); + } + + private static string EnvelopeForManifest(string manifestJson) + { + return $@"{{ + ""eventId"": ""evt-eb1-demo"", + ""tenant"": ""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"", + ""kind"": ""export.bundle.sealed"", + ""occurredAt"": ""2025-12-04T00:00:00Z"", + ""source"": ""evidence-locker"", + ""payload"": {{""manifest"": {{""raw"": {manifestJson} }}}}, + ""bundleId"": ""11111111-1111-1111-1111-111111111111"" +}}"; + } + + private static string ResolveFixturePath(string relative) + { + var baseDir = AppContext.BaseDirectory; + // bin/Debug/net10.0/ -> StellaOps.TimelineIndexer.Tests -> TimelineIndexer -> src -> repo root + var root = Path.GetFullPath(Path.Combine(baseDir, "..", "..", "..", "..", "..", "..", "..")); + return Path.GetFullPath(Path.Combine(root, relative)); + } + + private sealed class InMemoryQueryStore : ITimelineQueryStore + { + private readonly TimelineEventEnvelope _envelope; + + public InMemoryQueryStore(TimelineEventEnvelope envelope) + { + _envelope = envelope; + } + + public Task> QueryAsync(string tenantId, TimelineQueryOptions options, CancellationToken cancellationToken) + => Task.FromResult>(Array.Empty()); + + public Task GetAsync(string tenantId, string eventId, CancellationToken cancellationToken) + => Task.FromResult(null); + + public Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken) + { + if (!string.Equals(tenantId, _envelope.TenantId, StringComparison.OrdinalIgnoreCase) || + !string.Equals(eventId, _envelope.EventId, StringComparison.OrdinalIgnoreCase)) + { + return Task.FromResult(null); + } + + return Task.FromResult(new TimelineEvidenceView + { + EventId = _envelope.EventId, + TenantId = _envelope.TenantId, + BundleId = _envelope.BundleId, + BundleDigest = _envelope.BundleDigest, + AttestationSubject = _envelope.AttestationSubject ?? _envelope.BundleDigest, + AttestationDigest = _envelope.AttestationDigest, + ManifestUri = _envelope.ManifestUri, + CreatedAt = DateTimeOffset.UtcNow + }); + } + } +} diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineEnvelopeParserTests.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineEnvelopeParserTests.cs index 4cf118541..a28789f10 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineEnvelopeParserTests.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineEnvelopeParserTests.cs @@ -35,4 +35,33 @@ public class TimelineEnvelopeParserTests Assert.NotNull(envelope.RawPayloadJson); Assert.NotNull(envelope.NormalizedPayloadJson); } + + [Fact] + public void Parser_Maps_Evidence_Metadata() + { + const string json = """ + { + "eventId": "22222222-2222-2222-2222-222222222222", + "tenantId": "tenant-b", + "kind": "export.bundle.sealed", + "occurredAt": "2025-12-02T01:02:03Z", + "bundleId": "9f34f8c6-7a7c-4d63-9c70-2ae6e8f8c6aa", + "bundleDigest": "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + "attestationSubject": "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + "attestationDigest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd", + "manifestUri": "bundles/9f34f8c6/manifest.dsse.json" + } + """; + + var parser = new TimelineEnvelopeParser(); + + var parsed = parser.TryParse(json, out var envelope, out var reason); + + Assert.True(parsed, reason); + Assert.Equal(Guid.Parse("9f34f8c6-7a7c-4d63-9c70-2ae6e8f8c6aa"), envelope.BundleId); + Assert.Equal("sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", envelope.BundleDigest); + Assert.Equal("sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", envelope.AttestationSubject); + Assert.Equal("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd", envelope.AttestationDigest); + Assert.Equal("bundles/9f34f8c6/manifest.dsse.json", envelope.ManifestUri); + } } diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionServiceTests.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionServiceTests.cs index f52e8b5fa..171f4e62c 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionServiceTests.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionServiceTests.cs @@ -49,6 +49,36 @@ public class TimelineIngestionServiceTests Assert.False(second.Inserted); } + [Fact] + public async Task Ingest_PersistsEvidenceMetadata_WhenPresent() + { + var store = new FakeStore(); + var service = new TimelineIngestionService(store); + var envelope = new TimelineEventEnvelope + { + EventId = "evt-evidence", + TenantId = "tenant-e", + EventType = "export.bundle.sealed", + Source = "exporter", + OccurredAt = DateTimeOffset.Parse("2025-12-02T01:02:03Z"), + RawPayloadJson = "{}", + BundleId = Guid.Parse("9f34f8c6-7a7c-4d63-9c70-2ae6e8f8c6aa"), + BundleDigest = "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + AttestationSubject = "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + AttestationDigest = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd", + ManifestUri = "bundles/9f34f8c6/manifest.dsse.json" + }; + + var result = await service.IngestAsync(envelope, TestContext.Current.CancellationToken); + + Assert.True(result.Inserted); + Assert.Equal(envelope.BundleId, store.LastEnvelope?.BundleId); + Assert.Equal(envelope.BundleDigest, store.LastEnvelope?.BundleDigest); + Assert.Equal(envelope.AttestationSubject, store.LastEnvelope?.AttestationSubject); + Assert.Equal(envelope.AttestationDigest, store.LastEnvelope?.AttestationDigest); + Assert.Equal(envelope.ManifestUri, store.LastEnvelope?.ManifestUri); + } + private sealed class FakeStore : ITimelineEventStore { private readonly HashSet<(string tenant, string id)> _seen = new(); diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionWorkerTests.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionWorkerTests.cs index 7ba94dc62..f02ec246b 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionWorkerTests.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineIngestionWorkerTests.cs @@ -49,16 +49,71 @@ public sealed class TimelineIngestionWorkerTests Assert.Equal("sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", store.LastHash); // hash of "{}" } + [Fact] + public async Task Worker_Passes_Evidence_Metadata() + { + var subscriber = new InMemoryTimelineEventSubscriber(); + var store = new RecordingStore(); + var services = new ServiceCollection(); + services.AddSingleton(subscriber); + services.AddSingleton(store); + services.AddSingleton(); + services.AddSingleton(); + services.AddLogging(); + + using var provider = services.BuildServiceProvider(); + var hosted = provider.GetRequiredService(); + var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2)); + await hosted.StartAsync(cts.Token); + + var evt = new TimelineEventEnvelope + { + EventId = "evt-evidence-worker", + TenantId = "tenant-e", + EventType = "export.bundle.sealed", + Source = "exporter", + OccurredAt = DateTimeOffset.UtcNow, + RawPayloadJson = "{}", + BundleId = Guid.Parse("9f34f8c6-7a7c-4d63-9c70-2ae6e8f8c6aa"), + BundleDigest = "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + AttestationSubject = "sha256:abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcd", + AttestationDigest = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd", + ManifestUri = "bundles/9f34f8c6/manifest.dsse.json" + }; + + subscriber.Enqueue(evt); + subscriber.Complete(); + + await Task.Delay(200, cts.Token); + await hosted.StopAsync(cts.Token); + + Assert.Equal(evt.BundleId, store.LastBundleId); + Assert.Equal(evt.BundleDigest, store.LastBundleDigest); + Assert.Equal(evt.AttestationSubject, store.LastAttestationSubject); + Assert.Equal(evt.AttestationDigest, store.LastAttestationDigest); + Assert.Equal(evt.ManifestUri, store.LastManifestUri); + } + private sealed class RecordingStore : ITimelineEventStore { private readonly HashSet<(string tenant, string id)> _seen = new(); public int InsertCalls { get; private set; } public string? LastHash { get; private set; } + public Guid? LastBundleId { get; private set; } + public string? LastBundleDigest { get; private set; } + public string? LastAttestationSubject { get; private set; } + public string? LastAttestationDigest { get; private set; } + public string? LastManifestUri { get; private set; } public Task InsertAsync(TimelineEventEnvelope envelope, CancellationToken cancellationToken = default) { InsertCalls++; LastHash = envelope.PayloadHash; + LastBundleId = envelope.BundleId; + LastBundleDigest = envelope.BundleDigest; + LastAttestationSubject = envelope.AttestationSubject; + LastAttestationDigest = envelope.AttestationDigest; + LastManifestUri = envelope.ManifestUri; return Task.FromResult(_seen.Add((envelope.TenantId, envelope.EventId))); } } diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineQueryServiceTests.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineQueryServiceTests.cs index c22f340ed..6d6571cc4 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineQueryServiceTests.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.Tests/TimelineQueryServiceTests.cs @@ -29,10 +29,49 @@ public class TimelineQueryServiceTests Assert.Equal(("tenant-1", "evt-1"), store.LastGet); } + [Fact] + public async Task GetEvidenceAsync_PassesTenantAndId() + { + var store = new FakeStore(); + var service = new TimelineQueryService(store); + + await service.GetEvidenceAsync("tenant-x", "evt-evidence", TestContext.Current.CancellationToken); + + Assert.Equal(("tenant-x", "evt-evidence"), store.LastEvidenceGet); + } + + [Fact] + public async Task GetEvidenceAsync_FillsManifestUriFromBundleId_WhenMissing() + { + var bundleId = Guid.Parse("11111111-1111-1111-1111-111111111111"); + var store = new FakeStore + { + Evidence = new TimelineEvidenceView + { + EventId = "evt", + TenantId = "tenant", + BundleId = bundleId, + BundleDigest = "sha256:deadbeef", + AttestationSubject = "sha256:deadbeef", + AttestationDigest = "sha256:feedface", + ManifestUri = null, + CreatedAt = DateTimeOffset.UtcNow + } + }; + var service = new TimelineQueryService(store); + + var evidence = await service.GetEvidenceAsync("tenant", "evt", TestContext.Current.CancellationToken); + + Assert.NotNull(evidence); + Assert.Equal($"bundles/{bundleId:N}/manifest.dsse.json", evidence!.ManifestUri); + } + private sealed class FakeStore : ITimelineQueryStore { public TimelineQueryOptions? LastOptions { get; private set; } public (string tenant, string id)? LastGet { get; private set; } + public (string tenant, string id)? LastEvidenceGet { get; private set; } + public TimelineEvidenceView? Evidence { get; set; } public Task> QueryAsync(string tenantId, TimelineQueryOptions options, CancellationToken cancellationToken) { @@ -45,5 +84,11 @@ public class TimelineQueryServiceTests LastGet = (tenantId, eventId); return Task.FromResult(null); } + + public Task GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken) + { + LastEvidenceGet = (tenantId, eventId); + return Task.FromResult(Evidence); + } } } diff --git a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/Program.cs b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/Program.cs index e8263d5d8..896bb562f 100644 --- a/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/Program.cs +++ b/src/TimelineIndexer/StellaOps.TimelineIndexer/StellaOps.TimelineIndexer.WebService/Program.cs @@ -89,6 +89,18 @@ app.MapGet("/timeline/{eventId}", async ( }) .RequireAuthorization(StellaOpsResourceServerPolicies.TimelineRead); +app.MapGet("/timeline/{eventId}/evidence", async ( + HttpContext ctx, + ITimelineQueryService service, + string eventId, + CancellationToken cancellationToken) => + { + var tenantId = GetTenantId(ctx); + var evidence = await service.GetEvidenceAsync(tenantId, eventId, cancellationToken).ConfigureAwait(false); + return evidence is null ? Results.NotFound() : Results.Ok(evidence); + }) + .RequireAuthorization(StellaOpsResourceServerPolicies.TimelineRead); + app.MapPost("/timeline/events", () => Results.Accepted("/timeline/events", new { status = "indexed" })) .RequireAuthorization(StellaOpsResourceServerPolicies.TimelineWrite); diff --git a/src/Web/StellaOps.Web/TASKS.md b/src/Web/StellaOps.Web/TASKS.md index e4cb0b54b..c827f1b5f 100644 --- a/src/Web/StellaOps.Web/TASKS.md +++ b/src/Web/StellaOps.Web/TASKS.md @@ -11,3 +11,14 @@ | WEB-VULN-29-LEDGER-DOC | DONE (2025-12-01) | Findings Ledger proxy contract doc v1.0 with idempotency + retries (`docs/api/gateway/findings-ledger-proxy.md`). | | WEB-RISK-68-NOTIFY-DOC | DONE (2025-12-01) | Notifications severity transition event schema v1.0 published (`docs/api/gateway/notifications-severity.md`). | | UI-MICRO-GAPS-0209-011 | DOING (2025-12-04) | Motion token catalog + Storybook/Playwright a11y harness added; remaining work: component mapping, perf budgets, deterministic snapshots. | +| UI-POLICY-20-001 | DONE (2025-12-05) | Policy Studio Monaco editor with DSL highlighting, lint markers, and compliance checklist shipped. | +| UI-POLICY-20-002 | DONE (2025-12-05) | Simulation panel with deterministic diff rendering shipped (`/policy-studio/packs/:packId/simulate`). | +| UI-POLICY-20-003 | DONE (2025-12-05) | Approvals workflow UI delivered with submit/review actions, two-person badge, and deterministic log. | +| UI-POLICY-20-004 | DONE (2025-12-05) | Policy run dashboards delivered with filters, exports, heatmap, and daily deltas. | +| UI-POLICY-23-000 | DONE (2025-12-05) | Added Policy Studio nav dropdown with pack selector and persisted selection. | +| UI-POLICY-23-001 | DONE (2025-12-05) | Workspace route `/policy-studio/packs` with pack list + quick actions; cached pack store with offline fallback. | +| UI-POLICY-23-002 | DONE (2025-12-05) | YAML editor route `/policy-studio/packs/:packId/yaml` with canonical preview and lint diagnostics. | +| UI-POLICY-23-003 | DONE (2025-12-05) | Rule Builder route `/policy-studio/packs/:packId/rules` with guided inputs and deterministic preview JSON. | +| UI-POLICY-23-005 | DONE (2025-12-05) | Simulator updated with SBOM/advisory pickers and explain trace view; uses PolicyApiService simulate. | +| UI-POLICY-23-006 | DOING (2025-12-05) | Explain view route `/policy-studio/packs/:packId/explain/:runId` with trace + JSON export; PDF export pending backend. | +| UI-POLICY-23-001 | DONE (2025-12-05) | Workspace route `/policy-studio/packs` with pack list + quick actions; cached pack store with offline fallback. | diff --git a/src/Web/StellaOps.Web/package-lock.json b/src/Web/StellaOps.Web/package-lock.json index 974d2c40c..c463d0584 100644 --- a/src/Web/StellaOps.Web/package-lock.json +++ b/src/Web/StellaOps.Web/package-lock.json @@ -16,8 +16,10 @@ "@angular/platform-browser": "^17.3.0", "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", + "monaco-editor": "0.52.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", + "yaml": "^2.4.2", "zone.js": "~0.14.3" }, "devDependencies": { @@ -11207,6 +11209,16 @@ "node": ">= 10.0.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "dev": true, @@ -13921,6 +13933,12 @@ "ufo": "^1.6.1" } }, + "node_modules/monaco-editor": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz", + "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==", + "license": "MIT" + }, "node_modules/mrmime": { "version": "2.0.0", "dev": true, @@ -18778,13 +18796,15 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/yargs": { diff --git a/src/Web/StellaOps.Web/package.json b/src/Web/StellaOps.Web/package.json index 944d9bebe..fa54f179a 100644 --- a/src/Web/StellaOps.Web/package.json +++ b/src/Web/StellaOps.Web/package.json @@ -31,8 +31,10 @@ "@angular/platform-browser": "^17.3.0", "@angular/platform-browser-dynamic": "^17.3.0", "@angular/router": "^17.3.0", + "monaco-editor": "0.52.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", + "yaml": "^2.4.2", "zone.js": "~0.14.3" }, "devDependencies": { diff --git a/src/Web/StellaOps.Web/src/app/app.component.html b/src/Web/StellaOps.Web/src/app/app.component.html index 3f0c66ca4..c3d0d4efa 100644 --- a/src/Web/StellaOps.Web/src/app/app.component.html +++ b/src/Web/StellaOps.Web/src/app/app.component.html @@ -11,22 +11,60 @@
StellaOps Dashboard
-