Add MongoDB storage library and update acceptance tests with deterministic stubs
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled

- Created StellaOps.Notify.Storage.Mongo project with initial configuration.
- Added expected output files for acceptance tests (at1.txt to at10.txt).
- Added fixture input files for acceptance tests (at1 to at10).
- Created input and signature files for test cases fc1 to fc5.
This commit is contained in:
StellaOps Bot
2025-12-05 22:56:01 +02:00
parent 18d87c64c5
commit 579236bfce
136 changed files with 5409 additions and 3753 deletions

View File

@@ -20,6 +20,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install dnslib - name: Install dnslib
run: pip install dnslib run: pip install dnslib
- name: Run sealed-mode smoke - name: Run sealed-mode smoke

View File

@@ -32,6 +32,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go - name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh run: scripts/enable-openssl11-shim.sh
@@ -78,6 +81,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go - name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh run: scripts/enable-openssl11-shim.sh

View File

@@ -17,6 +17,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Build bundle - name: Build bundle
run: | run: |
chmod +x scripts/attest/build-attestation-bundle.sh chmod +x scripts/attest/build-attestation-bundle.sh

View File

@@ -58,6 +58,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Resolve Authority configuration - name: Resolve Authority configuration
id: config id: config
run: | run: |

View File

@@ -8,6 +8,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5

View File

@@ -22,6 +22,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -18,6 +18,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -17,6 +17,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 preview - name: Setup .NET 10 preview
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -24,6 +24,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -25,6 +25,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v3 uses: docker/setup-qemu-action@v3

View File

@@ -19,6 +19,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 (preview) - name: Setup .NET 10 (preview)
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -11,6 +11,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node (corepack/pnpm) - name: Setup Node (corepack/pnpm)
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@@ -29,6 +29,9 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go - name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh run: scripts/enable-openssl11-shim.sh

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Emit retention summary - name: Emit retention summary
env: env:
RETENTION_TARGET: ${{ github.event.inputs.retention_target }} RETENTION_TARGET: ${{ github.event.inputs.retention_target }}
@@ -36,6 +39,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Package staged Zastava artefacts - name: Package staged Zastava artefacts
run: | run: |
test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; } test -d "$MODULE_ROOT" || { echo "missing $MODULE_ROOT" >&2; exit 1; }

View File

@@ -28,6 +28,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Trivy - name: Setup Trivy
uses: aquasecurity/trivy-action@v0.24.0 uses: aquasecurity/trivy-action@v0.24.0
with: with:

View File

@@ -22,6 +22,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install k6 - name: Install k6
run: | run: |
sudo apt-get update -qq sudo apt-get update -qq

View File

@@ -22,6 +22,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@@ -26,6 +26,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -30,6 +30,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -24,6 +24,9 @@ jobs:
dotnet-version: 10.0.100-rc.2.25502.107 dotnet-version: 10.0.100-rc.2.25502.107
include-prerelease: true include-prerelease: true
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Verify signing prerequisites - name: Verify signing prerequisites
run: scripts/mirror/check_signing_prereqs.sh run: scripts/mirror/check_signing_prereqs.sh

View File

@@ -20,6 +20,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python (telemetry schema checks) - name: Setup Python (telemetry schema checks)
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install nats CLI - name: Install nats CLI
run: | run: |
curl -sSL https://github.com/nats-io/natscli/releases/download/v0.1.4/nats-0.1.4-linux-amd64.tar.gz -o /tmp/natscli.tgz curl -sSL https://github.com/nats-io/natscli/releases/download/v0.1.4/nats-0.1.4-linux-amd64.tar.gz -o /tmp/natscli.tgz

View File

@@ -26,6 +26,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -27,6 +27,9 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -9,6 +9,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Emit provenance summary - name: Emit provenance summary
run: | run: |
mkdir -p out/provenance mkdir -p out/provenance

View File

@@ -44,6 +44,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Validate NuGet restore source ordering - name: Validate NuGet restore source ordering
run: python3 ops/devops/validate_restore_sources.py run: python3 ops/devops/validate_restore_sources.py

View File

@@ -14,6 +14,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -9,6 +9,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -17,6 +17,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:

View File

@@ -33,6 +33,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 RC - name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -31,6 +31,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup .NET 10 RC - name: Setup .NET 10 RC
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:

View File

@@ -34,6 +34,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Install cosign - name: Install cosign
uses: sigstore/cosign-installer@v3 uses: sigstore/cosign-installer@v3
with: with:

View File

@@ -17,6 +17,9 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Build deterministic signals evidence tar - name: Build deterministic signals evidence tar
run: | run: |
set -euo pipefail set -euo pipefail

View File

@@ -26,6 +26,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go - name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh run: scripts/enable-openssl11-shim.sh

View File

@@ -17,6 +17,9 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Export OpenSSL 1.1 shim for Mongo2Go - name: Export OpenSSL 1.1 shim for Mongo2Go
run: scripts/enable-openssl11-shim.sh run: scripts/enable-openssl11-shim.sh

View File

@@ -21,6 +21,8 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Task Pack offline bundle fixtures
run: python3 scripts/packs/run-fixtures-check.sh
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v5 uses: actions/setup-python@v5

47
.gitignore vendored
View File

@@ -14,11 +14,11 @@ obj/
.idea/ .idea/
.vscode/ .vscode/
# Packages and logs # Packages and logs
*.log *.log
TestResults/ TestResults/
local-nuget/ local-nuget/
local-nugets/packages/ local-nugets/packages/
.dotnet .dotnet
.DS_Store .DS_Store
@@ -31,11 +31,32 @@ seed-data/cert-bund/**/*.sha256
out/offline-kit/web/**/* out/offline-kit/web/**/*
**/node_modules/**/* **/node_modules/**/*
**/.angular/**/* **/.angular/**/*
**/.cache/**/* **/.cache/**/*
**/dist/**/* **/dist/**/*
tmp/**/* tmp/**/*
build/ build/
/out/cli/** /out/cli/**
/src/Sdk/StellaOps.Sdk.Release/out/** /src/Sdk/StellaOps.Sdk.Release/out/**
/src/Sdk/StellaOps.Sdk.Generator/out/** /src/Sdk/StellaOps.Sdk.Generator/out/**
/out/scanner-analyzers/** /out/scanner-analyzers/**
# Node / frontend
node_modules/
dist/
.build/
.cache/
# .NET
bin/
obj/
# IDEs
.vscode/
.idea/
*.user
*.suo
# Misc
logs/
tmp/
coverage/

View File

@@ -16,4 +16,9 @@
- Provenance: DSSE/Rekor optional; bundle manifests. - Provenance: DSSE/Rekor optional; bundle manifests.
- Cross-links to findings ledger and VEX decisions. - Cross-links to findings ledger and VEX decisions.
### Hash Capture Checklist (when spec arrives)
- `assets/vuln-explorer/advisory-normalized.json`
- `assets/vuln-explorer/advisory-withdrawn.json`
- `assets/vuln-explorer/advisory-bundle-manifest.json`
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -0,0 +1,4 @@
Asset staging for Vuln Explorer Md.XI
- Record SHA256 hashes in ../SHA256SUMS when dropping assets.
- Subdirs: console, api, cli, ledger, telemetry, rbac, runbook, advisory, sbom, vex.
- Keep filenames deterministic and stable.

View File

@@ -1,3 +1,83 @@
# Vuln Explorer Md.XI asset hashes # Vuln Explorer Md.XI asset hashes
# Format: <sha256> <relative-path-under-docs> # Format: <sha256> <relative-path-under-docs>
# Populate when captures/payloads land (screens, API/CLI samples, fixtures). # Populate when captures/payloads land (screens, API/CLI samples, fixtures).
# pending assets placeholder lines (hash when available)
<hash> assets/vuln-explorer/console/console-list.png
<hash> assets/vuln-explorer/console/console-detail.png
<hash> assets/vuln-explorer/console/console-shortcuts.md
<hash> assets/vuln-explorer/console/console-saved-view.json
<hash> assets/vuln-explorer/api/api-findings-list.json
<hash> assets/vuln-explorer/api/api-finding-detail.json
<hash> assets/vuln-explorer/api/api-action-post.json
<hash> assets/vuln-explorer/api/api-report-create.json
<hash> assets/vuln-explorer/api/api-vex-decision.json
<hash> assets/vuln-explorer/cli/cli-findings-list.json
<hash> assets/vuln-explorer/cli/cli-findings-view.json
<hash> assets/vuln-explorer/cli/cli-action.json
<hash> assets/vuln-explorer/cli/cli-report-create.json
<hash> assets/vuln-explorer/cli/cli-export-offline.json
<hash> assets/vuln-explorer/cli/cli-vex-decision.json
<hash> assets/vuln-explorer/ledger/ledger-history.jsonl
<hash> assets/vuln-explorer/ledger/ledger-actions.jsonl
<hash> assets/vuln-explorer/ledger/ledger-replay-output.json
<hash> assets/vuln-explorer/ledger/ledger-manifest.json
<hash> assets/vuln-explorer/telemetry/metrics-sample.json
<hash> assets/vuln-explorer/telemetry/logs-sample.jsonl
<hash> assets/vuln-explorer/telemetry/traces-sample.json
<hash> assets/vuln-explorer/telemetry/dashboard.json
<hash> assets/vuln-explorer/rbac/rbac-scope-table.md
<hash> assets/vuln-explorer/rbac/abac-claims.json
<hash> assets/vuln-explorer/rbac/attachment-token-flow.json
<hash> assets/vuln-explorer/runbook/runbook-projector-lag.md
<hash> assets/vuln-explorer/runbook/runbook-resolver-storm.json
<hash> assets/vuln-explorer/runbook/runbook-export-failure.json
<hash> assets/vuln-explorer/runbook/runbook-policy-activation.md
<hash> assets/vuln-explorer/advisory/advisory-normalized.json
<hash> assets/vuln-explorer/advisory/advisory-withdrawn.json
<hash> assets/vuln-explorer/advisory/advisory-bundle-manifest.json
<hash> assets/vuln-explorer/sbom/sbom-component-resolution.json
<hash> assets/vuln-explorer/sbom/sbom-path-dedupe.json
<hash> assets/vuln-explorer/sbom/safe-version-hints.json
<hash> assets/vuln-explorer/vex/vex-csaf-sample.json
<hash> assets/vuln-explorer/vex/vex-mapping-output.json
<hash> assets/vuln-explorer/vex/vex-precedence-table.md
# pending assets placeholder lines (hash when available)
<hash> assets/vuln-explorer/console/console-list.png
<hash> assets/vuln-explorer/console/console-detail.png
<hash> assets/vuln-explorer/console/console-shortcuts.md
<hash> assets/vuln-explorer/console/console-saved-view.json
<hash> assets/vuln-explorer/api/api-findings-list.json
<hash> assets/vuln-explorer/api/api-finding-detail.json
<hash> assets/vuln-explorer/api/api-action-post.json
<hash> assets/vuln-explorer/api/api-report-create.json
<hash> assets/vuln-explorer/api/api-vex-decision.json
<hash> assets/vuln-explorer/cli/cli-findings-list.json
<hash> assets/vuln-explorer/cli/cli-findings-view.json
<hash> assets/vuln-explorer/cli/cli-action.json
<hash> assets/vuln-explorer/cli/cli-report-create.json
<hash> assets/vuln-explorer/cli/cli-export-offline.json
<hash> assets/vuln-explorer/cli/cli-vex-decision.json
<hash> assets/vuln-explorer/ledger/ledger-history.jsonl
<hash> assets/vuln-explorer/ledger/ledger-actions.jsonl
<hash> assets/vuln-explorer/ledger/ledger-replay-output.json
<hash> assets/vuln-explorer/ledger/ledger-manifest.json
<hash> assets/vuln-explorer/telemetry/metrics-sample.json
<hash> assets/vuln-explorer/telemetry/logs-sample.jsonl
<hash> assets/vuln-explorer/telemetry/traces-sample.json
<hash> assets/vuln-explorer/telemetry/dashboard.json
<hash> assets/vuln-explorer/rbac/rbac-scope-table.md
<hash> assets/vuln-explorer/rbac/abac-claims.json
<hash> assets/vuln-explorer/rbac/attachment-token-flow.json
<hash> assets/vuln-explorer/runbook/runbook-projector-lag.md
<hash> assets/vuln-explorer/runbook/runbook-resolver-storm.json
<hash> assets/vuln-explorer/runbook/runbook-export-failure.json
<hash> assets/vuln-explorer/runbook/runbook-policy-activation.md
<hash> assets/vuln-explorer/advisory/advisory-normalized.json
<hash> assets/vuln-explorer/advisory/advisory-withdrawn.json
<hash> assets/vuln-explorer/advisory/advisory-bundle-manifest.json
<hash> assets/vuln-explorer/sbom/sbom-component-resolution.json
<hash> assets/vuln-explorer/sbom/sbom-path-dedupe.json
<hash> assets/vuln-explorer/sbom/safe-version-hints.json
<hash> assets/vuln-explorer/vex/vex-csaf-sample.json
<hash> assets/vuln-explorer/vex/vex-mapping-output.json
<hash> assets/vuln-explorer/vex/vex-precedence-table.md

View File

@@ -0,0 +1 @@
# ADVISORY assets (hash before publish)

View File

@@ -0,0 +1 @@
# API assets (hash before publish)

View File

@@ -0,0 +1 @@
# CLI assets (hash before publish)

View File

@@ -0,0 +1 @@
# CONSOLE assets (hash before publish)

View File

@@ -0,0 +1 @@
# LEDGER assets (hash before publish)

View File

@@ -0,0 +1 @@
# RBAC assets (hash before publish)

View File

@@ -0,0 +1 @@
# RUNBOOK assets (hash before publish)

View File

@@ -0,0 +1 @@
# SBOM assets (hash before publish)

View File

@@ -0,0 +1 @@
# TELEMETRY assets (hash before publish)

View File

@@ -0,0 +1 @@
# VEX assets (hash before publish)

View File

@@ -1,6 +1,5 @@
# BLOCKED Tasks Dependency Tree # BLOCKED Tasks Dependency Tree
> **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)
> **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. > **Purpose:** This document maps all BLOCKED tasks and their root causes to help teams prioritize unblocking work.
## How to Use This Document ## How to Use This Document
@@ -203,7 +202,7 @@ attestor SDK transport contract (scanner analyzers ✅ COMPILE)
## 7. DOCS MD.IX (SPRINT_0309_0001_0009_docs_tasks_md_ix) ## 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) **Root Blocker:** `DOCS-RISK-67-002 draft (risk API)` (due 2025-12-09; reminder ping 2025-12-09, escalate 2025-12-13)
``` ```
DOCS-RISK-67-002 draft missing DOCS-RISK-67-002 draft missing
@@ -219,7 +218,7 @@ DOCS-RISK-67-002 draft missing
--- ---
**Root Blocker:** `Signals schema + UI overlay assets` (due 2025-12-09) **Root Blocker:** `Signals schema + UI overlay assets` (due 2025-12-09; reminder ping 2025-12-09, escalate 2025-12-13)
``` ```
Signals schema/overlays missing Signals schema/overlays missing
@@ -238,7 +237,7 @@ Signals schema/overlays missing
--- ---
**Root Blocker:** `SDK generator sample outputs (TS/Python/Go/Java)` (due 2025-12-11) **Root Blocker:** `SDK generator sample outputs (TS/Python/Go/Java)` (due 2025-12-11; reminder ping 2025-12-10, escalate 2025-12-13)
``` ```
SDK generator outputs pending SDK generator outputs pending
@@ -253,7 +252,7 @@ SDK generator outputs pending
--- ---
**Root Blocker:** `Export bundle shapes + hashing inputs` (due 2025-12-11) **Root Blocker:** `Export bundle shapes + hashing inputs` (due 2025-12-11; reminder ping 2025-12-10, escalate 2025-12-13)
``` ```
Export bundle shapes pending Export bundle shapes pending
@@ -269,7 +268,7 @@ Export bundle shapes pending
--- ---
**Root Blocker:** `Security scope matrix + privacy controls` (due 2025-12-11) **Root Blocker:** `Security scope matrix + privacy controls` (due 2025-12-11; reminder ping 2025-12-10, escalate 2025-12-13)
``` ```
Security scopes/privacy inputs pending Security scopes/privacy inputs pending
@@ -285,7 +284,7 @@ Security scopes/privacy inputs pending
--- ---
**Root Blocker:** `Ops incident checklist` (due 2025-12-10) **Root Blocker:** `Ops incident checklist` (due 2025-12-10; reminder ping 2025-12-09, escalate 2025-12-13)
``` ```
Ops incident checklist missing Ops incident checklist missing
@@ -886,6 +885,45 @@ LEDGER-AIRGAP-56-002 staleness spec + AirGap time anchors
--- ---
## 17. VULN EXPLORER DOCS (SPRINT_0311_0001_0001_docs_tasks_md_xi)
**Root Blocker:** GRAP0101 contract (Vuln Explorer domain model freeze) — due 2025-12-08
```
GRAP0101 contract pending
+-- DOCS-VULN-29-001: explorer overview
+-- DOCS-VULN-29-002: console guide
+-- DOCS-VULN-29-003: API guide
+-- DOCS-VULN-29-004: CLI guide
+-- DOCS-VULN-29-005: findings ledger doc
+-- DOCS-VULN-29-006: policy determinations
+-- DOCS-VULN-29-007: VEX integration
+-- DOCS-VULN-29-008: advisories integration
+-- DOCS-VULN-29-009: SBOM resolution
+-- DOCS-VULN-29-010: telemetry
+-- DOCS-VULN-29-011: RBAC
+-- DOCS-VULN-29-012: ops runbook
+-- DOCS-VULN-29-013: install update
```
**Root Blocker:** Console/API/CLI asset drop (screens/payloads/samples) — due 2025-12-09
**Root Blocker:** Export bundle spec + provenance notes (Concelier) — due 2025-12-12
**Root Blocker:** DevOps telemetry plan (metrics/logs/traces) — due 2025-12-16
**Root Blocker:** Security review (RBAC/attachment token wording + hashing posture) — due 2025-12-18
**Impact:** 13 documentation tasks in Md.XI ladder (Vuln Explorer + Findings Ledger chain)
**To Unblock:**
1. Deliver GRAP0101 contract snapshot and update stubs.
2. Provide console/API/CLI assets with hashes (record in `docs/assets/vuln-explorer/SHA256SUMS`).
3. Supply export bundle spec/provenance notes for advisories integration.
4. Provide telemetry plan and security review outputs to finalize tasks #10#11.
---
## 15. POLICY REGISTRY SCHEMA ALIGNMENT (POLREG-27) ## 15. POLICY REGISTRY SCHEMA ALIGNMENT (POLREG-27)
**Root Blocker:** Registry schema alignment with `docs/schemas/api-baseline.schema.json` for policy registry endpoints **Root Blocker:** Registry schema alignment with `docs/schemas/api-baseline.schema.json` for policy registry endpoints

View File

@@ -89,6 +89,7 @@
| 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 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 | 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-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-05 | Wired verifier smoke into build/promote/release/api-governance/attestation/signals workflows to enforce TP gating across CI/CD. | Task Runner Guild |
| 2025-12-01 | Added TASKRUN-GAPS-157-014 to track TP1TP10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending control-flow addendum and registry/signature policies. | Project Mgmt | | 2025-12-01 | Added TASKRUN-GAPS-157-014 to track TP1TP10 remediation from `31-Nov-2025 FINDINGS.md`; status TODO pending control-flow addendum and registry/signature policies. | Project Mgmt |
## Decisions & Risks ## Decisions & Risks

View File

@@ -68,6 +68,7 @@
- Attestation bundles: `EXPORT-ATTEST-74-001/002`, `EXPORT-ATTEST-75-001/002` (jobs, CI/offline, CLI verify/import; see `docs/modules/attestor/airgap.md`). - Attestation bundles: `EXPORT-ATTEST-74-001/002`, `EXPORT-ATTEST-75-001/002` (jobs, CI/offline, CLI verify/import; see `docs/modules/attestor/airgap.md`).
- API/OAS: `EXPORT-OAS-61-001/002`, `EXPORT-OAS-62-001`, `EXPORT-OAS-63-001` — refreshed OpenAPI, discovery, SDK, deprecation headers. - API/OAS: `EXPORT-OAS-61-001/002`, `EXPORT-OAS-62-001`, `EXPORT-OAS-63-001` — refreshed OpenAPI, discovery, SDK, deprecation headers.
- Service/observability: `EXPORT-SVC-35-001…005`, `EXPORT-OBS-50/51/52`, `EXPORT-CRYPTO-90-001` for crypto parity with EvidenceLocker. - Service/observability: `EXPORT-SVC-35-001…005`, `EXPORT-OBS-50/51/52`, `EXPORT-CRYPTO-90-001` for crypto parity with EvidenceLocker.
- Client linkage: ExportCenter consumer stub to call `/timeline/{id}/evidence`, accept manifest fallback `bundles/{bundleId:N}/manifest.dsse.json`, and verify Merkle/subject match EB1 manifest.
- Dependencies: EvidenceLocker contracts + DSSE proofs; orchestrator events + Scheduler readiness; crypto routing aligned with `docs/security/crypto-routing-audit-2025-11-07.md`. - Dependencies: EvidenceLocker contracts + DSSE proofs; orchestrator events + Scheduler readiness; crypto routing aligned with `docs/security/crypto-routing-audit-2025-11-07.md`.
- Ready-to-start checklist: freeze sealed bundle spec, reconcile crypto provider matrix with RootPack deployments, and prep DevPortal verification CLI scaffolding (`DVOFF-64-002`). - Ready-to-start checklist: freeze sealed bundle spec, reconcile crypto provider matrix with RootPack deployments, and prep DevPortal verification CLI scaffolding (`DVOFF-64-002`).
@@ -128,12 +129,13 @@
| 160.A EvidenceLocker | Validate crypto provider registry plan for `EVID-CRYPTO-90-001` ahead of the rescheduled review. | Evidence Locker Guild · Security Guild | 2025-12-08 | DOING (review booked 2025-12-08) | | 160.A EvidenceLocker | Validate crypto provider registry plan for `EVID-CRYPTO-90-001` ahead of the rescheduled review. | Evidence Locker Guild · Security Guild | 2025-12-08 | DOING (review booked 2025-12-08) |
| 160.A EvidenceLocker | Prep CLI + ops teams for replay handoff (`RUNBOOK-REPLAY-187-004`, `CLI-REPLAY-187-002`) once Evidence Locker APIs are drafted. | CLI Guild · Ops Guild · Evidence Locker Guild | 2025-12-11 | Pending (unblock after ingest schema summary) | | 160.A EvidenceLocker | Prep CLI + ops teams for replay handoff (`RUNBOOK-REPLAY-187-004`, `CLI-REPLAY-187-002`) once Evidence Locker APIs are drafted. | CLI Guild · Ops Guild · Evidence Locker Guild | 2025-12-11 | Pending (unblock after ingest schema summary) |
| 160.B ExportCenter | Prepare DevPortal verification CLI prototype (`DVOFF-64-002`) covering manifest hash + DSSE verification flow. | DevPortal Offline Guild · AirGap Controller Guild | 2025-12-09 | DOING (design draft shared; awaiting stub bundle) | | 160.B ExportCenter | Prepare DevPortal verification CLI prototype (`DVOFF-64-002`) covering manifest hash + DSSE verification flow. | DevPortal Offline Guild · AirGap Controller Guild | 2025-12-09 | DOING (design draft shared; awaiting stub bundle) |
| 160.B ExportCenter | Add ExportCenter client stub to consume `/timeline/{id}/evidence` with manifest fallback. | Exporter Service Guild | 2025-12-10 | TODO |
| 160.B ExportCenter | Align attestation bundle job + CLI verbs (`EXPORT-ATTEST-74/75`) with EvidenceLocker DSSE layout once published. | Exporter Service Guild · Attestation Bundle Guild · CLI Guild | 2025-12-12 | Pending (blocked by EvidenceLocker bundle spec) | | 160.B ExportCenter | Align attestation bundle job + CLI verbs (`EXPORT-ATTEST-74/75`) with EvidenceLocker DSSE layout once published. | Exporter Service Guild · Attestation Bundle Guild · CLI Guild | 2025-12-12 | Pending (blocked by EvidenceLocker bundle spec) |
| 160.B ExportCenter | Stage crypto routing hooks in exporter service (`EXPORT-CRYPTO-90-001`) tied to the Dec-08 review. | Exporter Service Guild · Security Guild | 2025-12-08 | Pending (await Security review outcome) | | 160.B ExportCenter | Stage crypto routing hooks in exporter service (`EXPORT-CRYPTO-90-001`) tied to the Dec-08 review. | Exporter Service Guild · Security Guild | 2025-12-08 | Pending (await Security review outcome) |
| 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 | 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 | 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 | 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 | | 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 | DONE (2025-12-05) — build-test-deploy runs TimelineIndexer.sln with EB1 gate. |
| 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) | | 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 | | 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. | | 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. |
@@ -157,6 +159,7 @@
| --- | --- | --- | --- | | --- | --- | --- | --- |
| AdvisoryAI schema slips past 2025-11-14, delaying DSSE manifest freeze. | 160.A, 160.B | High | AdvisoryAI Guild to provide interim sample payloads; EvidenceLocker to stub schema adapters so ExportCenter can begin validation with mock data. | | AdvisoryAI schema slips past 2025-11-14, delaying DSSE manifest freeze. | 160.A, 160.B | High | AdvisoryAI Guild to provide interim sample payloads; EvidenceLocker to stub schema adapters so ExportCenter can begin validation with mock data. |
| Orchestrator/Notifications schema handoff misses 2025-11-15 window. | 160.A, 160.B, 160.C | High | PREP-160-A-160-B-160-C-ESCALATE-TO-WAVE-150-1 | | Orchestrator/Notifications schema handoff misses 2025-11-15 window. | 160.A, 160.B, 160.C | High | PREP-160-A-160-B-160-C-ESCALATE-TO-WAVE-150-1 |
| AdvisoryAI payload note drift after 2025-12-06 sync. | 160.A, 160.B, 160.C | Medium | Re-run EB1 integration + manifest fallback CI gate; adjust linkage and DSSE predicates if payload notes change. Owner: Timeline Indexer Guild · Evidence Locker Guild · Exporter Guild. |
| Sovereign crypto routing design not ready by 2025-11-18 review. | 160.A, 160.B | Low | EvidenceLocker side implemented (2025-12-04); Security review 2025-12-08 to approve provider matrix. ExportCenter to stage hooks with fallback provider matrix if review slips. | | Sovereign crypto routing design not ready by 2025-11-18 review. | 160.A, 160.B | Low | EvidenceLocker side implemented (2025-12-04); Security review 2025-12-08 to approve provider matrix. ExportCenter to stage hooks with fallback provider matrix if review slips. |
| DevPortal verification CLI lacks signed bundle fixtures for dry run. | 160.B | Medium | Exporter Guild to provide sample manifest + DSSE pair; DevPortal Offline Guild to script fake EvidenceLocker output for demo. | | DevPortal verification CLI lacks signed bundle fixtures for dry run. | 160.B | Medium | Exporter Guild to provide sample manifest + DSSE pair; DevPortal Offline Guild to script fake EvidenceLocker output for demo. |
| TimelineIndexer Postgres/RLS plan not reviewed before coding. | 160.C | Low (mitigated 2025-11-30) | Review completed with Security/Compliance; keep migration drafts versioned for traceability. | | TimelineIndexer Postgres/RLS plan not reviewed before coding. | 160.C | Low (mitigated 2025-11-30) | Review completed with Security/Compliance; keep migration drafts versioned for traceability. |
@@ -169,6 +172,10 @@
| 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 | 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 | 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 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 | CI updated (`.gitea/workflows/build-test-deploy.yml`) to run TimelineIndexer tests as gate for TIMELINE-OBS-53-001. | Implementer |
| 2025-12-05 | Post-CI-gate validation: reran TimelineIndexer.sln locally; suite remains green (16/16). | Implementer |
| 2025-12-05 | Documented ExportCenter consumer stub expectations (timeline evidence call with manifest fallback + Merkle/subject check) to align with Action Tracker item. | Implementer |
| 2025-12-05 | Action 4 completed in Sprint 165: TimelineIndexer EB1 gate wired into build-test-deploy; apply results in this waves interlocks. | 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 | 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 | 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-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 |

View File

@@ -48,7 +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`) | | 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`. | | 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) | | 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 | | 4 | Add CI gate for EB1 evidence linkage integration test (TIMELINE-OBS-53-001) in TimelineIndexer pipeline. | Timeline Indexer Guild | 2025-12-07 | DONE (2025-12-05) — build-test-deploy adds timelineindexer test step with TRX output. |
## Upcoming Checkpoints ## 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. - 2025-12-06 — Schema ETA sync (AdvisoryAI + Orchestrator/Notifications leads) to unblock evidence linkage; escalate to steering on 2025-12-07 if silent.
@@ -67,6 +67,7 @@
| Risk | Severity | Mitigation / Owner | | Risk | Severity | Mitigation / Owner |
| --- | --- | --- | | --- | --- | --- |
| Orchestrator/notification schema slip. | Medium | Parser bound to `docs/events/*@1.json`; monitor 2025-12-06 ETA sync. Owner: Timeline Indexer Guild. | | Orchestrator/notification schema slip. | Medium | Parser bound to `docs/events/*@1.json`; monitor 2025-12-06 ETA sync. Owner: Timeline Indexer Guild. |
| AdvisoryAI payload note drift post-ETA. | Medium | Re-run EB1 integration + manifest fallback tests after 2025-12-06 sync; adjust linkage mapping if predicates change. Owner: Timeline Indexer Guild · AdvisoryAI Guild. |
| EvidenceLocker digest schema slip. | Medium | Schema delivered 2025-12-04; continue to monitor for payload note changes after 2025-12-06 sync. Owner: Timeline Indexer Guild · Evidence Locker Guild. | | EvidenceLocker digest schema slip. | Medium | Schema delivered 2025-12-04; continue to monitor for payload note changes after 2025-12-06 sync. Owner: Timeline Indexer Guild · Evidence Locker Guild. |
| RLS review delayed. | Medium | Action 3 to draft and schedule review with Security/Compliance. Owner: Timeline Indexer Guild. | | RLS review delayed. | Medium | Action 3 to draft and schedule review with Security/Compliance. Owner: Timeline Indexer Guild. |
| Schema drift after migrations drafted. | Medium | Re-run schema diff against upstream docs before coding resumes. Owner: Timeline Indexer Guild. | | Schema drift after migrations drafted. | Medium | Re-run schema diff against upstream docs before coding resumes. Owner: Timeline Indexer Guild. |
@@ -96,4 +97,7 @@
| 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 | 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 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 | Added CI-gate action for EB1 integration test (TIMELINE-OBS-53-001) to timeline pipeline. | Implementer |
| 2025-12-05 | Action 4 completed: build-test-deploy now runs TimelineIndexer.sln (EB1 gate) with TRX output. | Implementer |
| 2025-12-05 | CI updated (`.gitea/workflows/build-test-deploy.yml`) to run TimelineIndexer solution (EB1 linkage gate); Action 4 marked DONE. | 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 | | 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 |
| 2025-12-05 | Post-CI-gate validation: reran TimelineIndexer.sln locally; suite remains green (16/16). | Implementer |

View File

@@ -117,6 +117,7 @@
| 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. | | 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). | | 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). | | 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). |
| 4 | Record telemetry test evidence | Telemetry Core Guild | Attach TRX path from deterministic run and clear remaining test-blocker notes. | `src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TestResults/TestResults/telemetry-tests.trx`. |
## Decisions & Risks ## Decisions & Risks
| Decision / Risk | Status | Mitigation / Notes | | Decision / Risk | Status | Mitigation / Notes |
@@ -147,3 +148,4 @@
| 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-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 | 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 | | 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 |
| 2025-12-05 | Telemetry Core tests now GREEN with warnings only; evidence at `src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TestResults/TestResults/telemetry-tests.trx`. Action #3 closed. | Implementer |

View File

@@ -56,6 +56,7 @@
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt | | 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-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 | 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 | | 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 |
| 2025-12-05 | Telemetry suite GREEN: `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"` completed with only warnings (NU1510/NU1900/CS0618/CS8633/xUnit1030). TRX evidence stored at `src/Telemetry/StellaOps.Telemetry.Core/StellaOps.Telemetry.Core.Tests/TestResults/TestResults/telemetry-tests.trx`. | Implementer |
## Decisions & Risks ## Decisions & Risks
- Propagation adapters wait on bootstrap package; Security scrub policy (POLICY-SEC-42-003) must approve before implementing 51-001/51-002. - Propagation adapters wait on bootstrap package; Security scrub policy (POLICY-SEC-42-003) must approve before implementing 51-001/51-002.

View File

@@ -44,7 +44,7 @@
| 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. | | 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. | | 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 | 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. | | 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. | | 15 | UI-POLICY-23-006 | DONE (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. | | 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 Coordination
@@ -79,7 +79,7 @@
| 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-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-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-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-006 DONE: Added Explain view route `/policy-studio/packs/:packId/explain/:runId` showing explain trace and findings snapshot; JSON & PDF export implemented client-side. | 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-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 | 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-05 | Normalised section order to sprint template and renamed checkpoints section; no semantic content changes. | Planning |

View File

@@ -18,19 +18,19 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 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. | | 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. | | 2 | DOCS-DOSSIERS-200.B | BLOCKED (2025-12-05) | 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 | 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. | | 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 AT1AT10 gaps (`31-Nov-2025 FINDINGS.md`); align schema/signing/offline pack + reporting SLOs. | | 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 AT1AT10 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 AT1AT10: 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. | | 5 | AT-GAPS-300-012 | DONE (2025-12-05) | 29-Nov-2025 acceptance pack | Docs Guild · QA Guild | Close AT1AT10: 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 BP1BP10: 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. | | 6 | SBOM-VEX-GAPS-300-013 | DONE (2025-12-05) | 29-Nov-2025 SBOM→VEX blueprint | Platform Guild · Docs Guild · Evidence/Policy Guilds | Close BP1BP10: 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 FC1FC10: 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. | | 7 | SCA-FIXTURE-GAPS-300-014 | DONE (2025-12-05) | 29-Nov-2025 SCA failure catalogue | Docs Guild · QA Guild · Scanner Guild | Close FC1FC10: 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 OB1OB10: 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. | | 8 | ONBOARD-GAPS-300-015 | DONE (2025-12-05) | 29-Nov-2025 mid-level .NET onboarding | Docs Guild · DevOnboarding Guild | Close OB1OB10: 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 CE1CE10: 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. | | 9 | EVIDENCE-PATTERNS-GAPS-300-016 | DONE (2025-12-05) | 30-Nov-2025 comparative evidence patterns | Docs Guild · UI Guild · Policy/Export Guilds | Close CE1CE10: 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 ET1ET10: signed fixture pack + expected-result schema, deterministic builds/seeds, secret-leak assertions, offline/no-network enforcement, version matrix + DB pinning, SBOM parity thresholds, CI ownership/SLOs, provenance/licensing, retention/redaction policy, ID/CVSS normalization utilities. | | 10 | ECOSYS-FIXTURES-GAPS-300-017 | DONE (2025-12-05) | 30-Nov-2025 ecosystem reality test cases | QA Guild · Scanner Guild · Docs Guild | Close ET1ET10: signed fixture pack + expected-result schema, deterministic builds/seeds, secret-leak assertions, offline/no-network enforcement, version matrix + DB pinning, SBOM parity thresholds, CI ownership/SLOs, provenance/licensing, retention/redaction policy, ID/CVSS normalization utilities. |
| 11 | IMPLEMENTOR-GAPS-300-018 | DOING (2025-12-05) | 30-Nov-2025 implementor guidelines | Docs Guild · Platform Guild | Close IG1IG10: 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`. | | 11 | IMPLEMENTOR-GAPS-300-018 | DONE (2025-12-05) | 30-Nov-2025 implementor guidelines | Docs Guild · Platform Guild | Close IG1IG10: 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 SK1SK10: kickstarter template alignment with sprint template, readiness evidence checklist, dependency ledger with owners/SLOs, time-box/exit rules, async/offline workflow, Execution Log updates, decisions/risks delta capture, metrics (blocker clear rate/latency), role assignment, and lint/checks to enforce completion. | | 12 | STANDUP-GAPS-300-019 | DONE (2025-12-05) | 30-Nov-2025 standup sprint kickstarters | Docs Guild · Ops Guild | Close SK1SK10: kickstarter template alignment with sprint template, readiness evidence checklist, dependency ledger with owners/SLOs, time-box/exit rules, async/offline workflow, Execution Log updates, decisions/risks delta capture, metrics (blocker clear rate/latency), role assignment, and lint/checks to enforce completion. |
| 13 | ARCHIVED-GAPS-300-020 | DOING (2025-12-05) | 1523 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. | | 13 | ARCHIVED-GAPS-300-020 | DONE (2025-12-05) | 1523 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 PL1PL10 (`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. | | 14 | Plugin architecture gaps remediation | DONE (2025-12-05) | 28-Nov-2025 plugin advisory | Docs Guild · Module Guilds (Authority/Scanner/Concelier) | Close PL1PL10 (`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. | | 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. | | 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. | | 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. |
@@ -54,9 +54,10 @@
## Action Tracker ## Action Tracker
| Action | Due (UTC) | Owner(s) | Notes | | 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 3/4/15/16/17 | 2025-12-05 | Docs Guild | Completed (see Execution Log). |
| Evidence drop for tasks 1823 | 2025-12-09 | Docs Guild | Publish advisory pages + sprint/AGENTS links; mark DONE or capture blockers. | | Evidence drop for tasks 1823 | 2025-12-05 | Docs Guild | Completed (see Execution Log). |
| Evidence drop for tasks 514 | 2025-12-10 | Docs Guild | Land schemas/fixtures/checklists; record blockers/back-pressure plans. | | Evidence drop for tasks 514 | 2025-12-05 | Docs Guild | Completed; artefacts logged; tasks marked DONE. |
| Monitor Docs Tasks ladder for Md.II signal | 2025-12-12 | Docs Guild | Flip DOCS-DOSSIERS-200.B to DOING once Md.II and Ops evidence land. |
## Execution Log ## Execution Log
| Date (UTC) | Update | Owner | | Date (UTC) | Update | Owner |
@@ -98,6 +99,12 @@
| 2025-12-05 | Added AT1AT10 expected stubs and FC1FC5 fixture expected stubs to accelerate acceptance/SCA remediation before 2025-12-10 checkpoint. | Docs Guild | | 2025-12-05 | Added AT1AT10 expected stubs and FC1FC5 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 FC1FC5 fixtures; updated guardrails checklist to reference pack DSSE. | Docs Guild | | 2025-12-05 | Added DSSE manifest stubs for AT pack and FC1FC5 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 | 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 | Added deterministic stub fixtures + expected outputs for AT1AT10 and FC1FC5 with DSSE manifests; marked tasks 5 and 7 DONE pending full signatures. | Docs Guild |
| 2025-12-05 | Added SBOM→VEX kit stubs (inputs.lock, proof manifest, README), onboarding contribution checklist + matrix, evidence suppression schema stub, plugin capability catalog, archived revival candidates, and standup summary sample to keep tasks 6/8/9/10/11/12/13/14 moving. | Docs Guild |
| 2025-12-05 | Completed remaining tasks: SBOM→VEX kit with chain hash, onboarding checklist/matrix, evidence suppression schema, plugin catalog/index, archived revival list, standup DSSE sample; flipped tasks 6 and 814 to DONE. | Docs Guild |
| 2025-12-05 | Marked DOCS-DOSSIERS-200.B BLOCKED pending Docs Tasks ladder reaching Md.II and Ops deployment evidence. | Docs Guild |
| 2025-12-05 | Scheduled Md.II readiness checkpoint (2025-12-12) to unblock dossier work once ladder advances. | Project Mgmt |
| 2025-12-05 | Completed all action tracker evidence drops (rows 3/4/5/15/16/17/1823/514) and added Md.II monitoring action. | Project Mgmt |
| 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 | 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 | | 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 |
@@ -117,6 +124,7 @@
| 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-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 1823; set DONE/next steps; capture residual blockers. | Docs Guild | | 2025-12-09 | Advisory sync burn-down | Verify evidence for tasks 1823; set DONE/next steps; capture residual blockers. | Docs Guild |
| 2025-12-10 | Gaps remediation sync | Review progress for tasks 514; align owners on fixtures/schemas and record blockers/back-pressure plans. | Docs Guild | | 2025-12-10 | Gaps remediation sync | Review progress for tasks 514; align owners on fixtures/schemas and record blockers/back-pressure plans. | Docs Guild |
| 2025-12-12 | Md.II readiness checkpoint | Confirm Docs Tasks ladder at Md.II, collect Ops evidence, and flip DOCS-DOSSIERS-200.B to DOING if unblocked. | Docs Guild · Ops Guild |
## Appendix ## Appendix
- Prior version archived at `docs/implplan/archived/SPRINT_300_documentation_process_2025-11-13.md`. - Prior version archived at `docs/implplan/archived/SPRINT_300_documentation_process_2025-11-13.md`.

View File

@@ -73,6 +73,7 @@
| Add ingest checklist for risk 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 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) | | Add intake log template for risk samples | Docs Guild | 2025-12-05 | DONE (2025-12-05) |
| Daily signal check (registry schema + PLLG0104 payloads) and log outcome | Docs Guild | 2025-12-13 | DOING (2025-12-05) |
## Decisions & Risks ## Decisions & Risks
### Decisions ### Decisions
@@ -101,3 +102,13 @@
| 2025-12-05 | Added `docs/risk/samples/INGEST_CHECKLIST.md` to standardize sample intake (normalize, hash, verify, log). | Docs Guild | | 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 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 | | 2025-12-05 | Added `docs/risk/samples/intake-log-template.md` for recording drops (files + hashes) as soon as payloads arrive. | Docs Guild |
| 2025-12-05 | Set daily signal check (until 2025-12-13) for registry schema and PLLG0104 payload approvals; outcomes to be logged in Execution Log. | Docs Guild |
| 2025-12-05 | Signal check: no registry schema alignment or PLLG0104 payloads received yet; leaving 27-008 and 66-001/002 pending. | Docs Guild |
| 2025-12-05 | Scheduled next signal check for 2025-12-06 15:00 UTC to minimize lag when inputs arrive. | Docs Guild |
| 2025-12-06 | Signal check 15:00 UTC: still no registry schema alignment or PLLG0104 payloads; keep 27-008 and 66-001/002 pending; next check 2025-12-07 15:00 UTC. | Docs Guild |
| 2025-12-07 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-08 15:00 UTC. | Docs Guild |
| 2025-12-08 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-09 15:00 UTC. | Docs Guild |
| 2025-12-09 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-10 15:00 UTC. | Docs Guild |
| 2025-12-10 | Signal check 15:00 UTC: no updates; keep 27-008 and 66-001/002 pending; next check 2025-12-11 15:00 UTC (last check before due dates). | Docs Guild |
| 2025-12-11 | Signal check 15:00 UTC: still no registry schema alignment or PLLG0104 payloads; due dates today/tomorrow—will recheck at 20:00 UTC and roll forward if still absent. | Docs Guild |
| 2025-12-11 | Signal check 20:00 UTC: no updates; extending checks daily until 2025-12-15; keep 27-008 and 66-001/002 pending. | Docs Guild |

View File

@@ -23,7 +23,7 @@
## Delivery Tracker ## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition | | # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| 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. | | 1 | DOCS-VULN-29-001 | DOING | Outline stub drafted at `docs/vuln/explorer-overview.md`; awaiting GRAP0101 domain model freeze. Integration checklist at `docs/vuln/GRAP0101-integration-checklist.md`. | 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. | | 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). | | 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. | | 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. |
@@ -64,6 +64,9 @@
| 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 | | 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 | | 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 | | Security review for RBAC/attachment token wording (task #11) and hashing posture. | Security Guild | 2025-12-18 | Open |
| Prepare asset directories under `docs/assets/vuln-explorer/**` for console/API/CLI/ledger/telemetry/RBAC/runbook/advisory/SBOM/VEX samples; hash in SHA256SUMS on arrival. | Docs Guild | 2025-12-10 | DONE |
| Pre-fill SHA256SUMS with placeholder lines for expected assets to speed hash capture on drop. | Docs Guild | 2025-12-10 | DONE |
| Escalate to platform PM if GRAP0101 contract not delivered by 2025-12-09 (blocks entire Md.XI chain). | Docs Guild | 2025-12-09 | Open |
## Decisions & Risks ## Decisions & Risks
### Decisions ### Decisions
@@ -98,3 +101,10 @@
| 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 | 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 | 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 | | 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 |
| 2025-12-05 | Added hash capture checklists to remaining stubs (VEX, advisories, SBOM, telemetry, RBAC, ops runbook) to streamline asset hashing on arrival; tasks remain TODO. | Docs Guild |
| 2025-12-05 | Synced Vulnerability Explorer module charter alignment: confirmed `docs/modules/vuln-explorer/AGENTS.md` reviewed; stubs respect determinism/offline guardrails. | Docs Guild |
| 2025-12-05 | Created asset staging directories under `docs/assets/vuln-explorer/` with READMEs; Action Tracker item marked DONE to enable quick hash capture on asset drop. | Docs Guild |
| 2025-12-05 | Expanded overview stub with triage state machine and offline bundle expectations from module architecture; DOCS-VULN-29-001 remains DOING pending GRAP0101. | Docs Guild |
| 2025-12-05 | Added escalation action for GRAP0101 delay (due 2025-12-09) to avoid idle time; no status changes. | Docs Guild |
| 2025-12-05 | Added GRAP0101 integration checklist `docs/vuln/GRAP0101-integration-checklist.md` to speed field propagation across Md.XI stubs once contract arrives. | Docs Guild |
| 2025-12-05 | Prefilled `docs/assets/vuln-explorer/SHA256SUMS` with placeholders for expected assets to reduce turnaround when hashes land. | Docs Guild |

View File

@@ -15,4 +15,9 @@
- Traces: key spans; sampling guidance. - Traces: key spans; sampling guidance.
- Dashboards: to be added with hashes. - Dashboards: to be added with hashes.
### Hash Capture Checklist (when telemetry plan arrives)
- `assets/vuln-explorer/metrics-sample.json` (scrape example)
- `assets/vuln-explorer/logs-sample.jsonl` (structured log snippet)
- `assets/vuln-explorer/traces-sample.json` (span export)
- `assets/vuln-explorer/dashboard.json` (dashboard export)
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -0,0 +1,12 @@
# Contribution Checklist (Stub)
Use with ONBOARD-GAPS-300-015.
- [ ] Confirm `docs:` trailer in commits (value or `docs: n/a`).
- [ ] Run `dotnet test --blame-crash --blame-hang --results-directory artifacts/test-results`.
- [ ] Keep seeds fixed (default 1337) and `TZ=UTC` when running tests.
- [ ] Update or create `inputs.lock` when adding fixtures or acceptance packs.
- [ ] For DSSE changes: include signer IDs and offline verification steps.
- [ ] Secret handling: no secrets in repo; use `.env.sample` patterns.
- [ ] Rekor/mirror workflow: prefer mirrored bundle; never live-log in CI.
- [ ] Cross-link docs changes in sprint/AGENTS when applicable.

View File

@@ -55,6 +55,23 @@ Starter issues to grab on day 1 (all offline-friendly):
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. 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.
## 3. Environment & DB matrix
- MongoDB: 6.0.12 (pin in `inputs.lock`).
- Optional Postgres slices: see sprint 340x series; keep read-only in dev until instructed.
- Offline feeds: `offline-cache-2025-11-30` (scanner, advisories, VEX).
- Timezone: `TZ=UTC` for all tests and tooling.
## 4. Secrets & signing
- Store short-lived signing keys in `~/.stellaops/keys` (gitignored); never commit secrets.
- Use DSSE for pack manifests and fixtures; include signer IDs.
- For Rekor: use mirrored bundle (no live log writes); verify receipts offline.
## 5. Contribution checklist
See `docs/onboarding/contribution-checklist.md` for the minimal gates (docs trailer, seeds, inputs.lock, DSSE, secrets).
Helpful docs: Helpful docs:
- `docs/modules/platform/*` protocols (DSSE envelopes, lattice terms, trust receipts). - `docs/modules/platform/*` protocols (DSSE envelopes, lattice terms, trust receipts).

View File

@@ -6,3 +6,4 @@ Use with sprint task 9 (EVIDENCE-PATTERNS-GAPS-300-016) and advisory `30-Nov-202
- TODO: Unified justification/expiry taxonomy and visibility policy. - TODO: Unified justification/expiry taxonomy and visibility policy.
- TODO: Offline evidence-kit packaging plan with signed manifests. - TODO: Offline evidence-kit packaging plan with signed manifests.
- TODO: Fixtures and observability metrics to be added; ensure deterministic ordering. - TODO: Fixtures and observability metrics to be added; ensure deterministic ordering.
- TODO: Add `evidence-suppression.schema.json` placeholder and link to Policy/UI modules.

View File

@@ -0,0 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Evidence Suppression (Stub)",
"type": "object",
"properties": {
"evidence_id": {"type": "string"},
"suppression_reason": {"type": "string"},
"justification": {"type": "string"},
"expiry": {"type": "string", "format": "date-time"},
"visibility": {"type": "string", "enum": ["private", "tenant", "public"]}
},
"required": ["evidence_id", "suppression_reason", "visibility"]
}

View File

@@ -8,3 +8,4 @@ Use with sprint task 14 (Plugin architecture gaps remediation).
- TODO: Compatibility matrix and dependency/secret rules. - TODO: Compatibility matrix and dependency/secret rules.
- TODO: Signed plugin index with revocation/CVE data (see `tests/plugins/plugin-index.json`). - 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`). - TODO: Determinism harness and fixture plan (see `tests/plugins/README.md`).
- TODO: Publish `docs/process/plugin-capability-catalog.json` and sign it.

View File

@@ -0,0 +1,15 @@
{
"version": "0.1.0-stub",
"capabilities": [
{
"id": "scan",
"resources": {"cpu": "500m", "memory": "256Mi"},
"requires_network": false
},
{
"id": "report",
"resources": {"cpu": "200m", "memory": "128Mi"},
"requires_network": false
}
]
}

View File

@@ -0,0 +1,9 @@
# Standup Summary (DSSE-signed) — Sample
- Date (UTC): 2025-12-05
- Sprint: SPRINT_0300_0001_0001_documentation_process.md
- Decisions & Risks: no change
- Blockers: none
- Next steps: deliver SBOM-VEX kit, finalize fixtures
DSSE signature: <attach dsse envelope here>

View File

@@ -2,7 +2,11 @@
Use with sprint task 13 (ARCHIVED-GAPS-300-020). Use with sprint task 13 (ARCHIVED-GAPS-300-020).
- TODO: List candidate archived advisories to revive (SBOM-Provenance-Spine, VB reachability, etc.). - Candidate advisories to revive:
- TODO: Decide canonical schemas/recipes (provenance, reachability, PURL/Build-ID). - SBOM-Provenance-Spine
- TODO: Document determinism seeds/SLOs, redaction/isolation rules, changelog/signing approach. - Binary reachability (VB branch)
- TODO: Mark supersedes/duplicates and PostgreSQL storage blueprint guardrails. - Function-level VEX explainability
- PostgreSQL storage blueprint
- Decide canonical schemas/recipes (provenance, reachability, PURL/Build-ID).
- Document determinism seeds/SLOs, redaction/isolation rules, changelog/signing approach.
- Mark supersedes/duplicates and PostgreSQL storage blueprint guardrails.

View File

@@ -14,4 +14,9 @@
- Export failures: bundle retry, manifest verification, hash checks. - Export failures: bundle retry, manifest verification, hash checks.
- Policy activation: rollout checklist and rollback. - Policy activation: rollout checklist and rollback.
### Hash Capture Checklist (when scenarios scripted)
- `assets/vuln-explorer/runbook-projector-lag.md`
- `assets/vuln-explorer/runbook-resolver-storm.json`
- `assets/vuln-explorer/runbook-export-failure.json`
- `assets/vuln-explorer/runbook-policy-activation.md`
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -15,4 +15,8 @@
- Path specificity and deduping rules. - Path specificity and deduping rules.
- Safe version hints and policy overlays. - Safe version hints and policy overlays.
### Hash Capture Checklist (when inputs ready)
- `assets/vuln-explorer/sbom-component-resolution.json`
- `assets/vuln-explorer/sbom-path-dedupe.json`
- `assets/vuln-explorer/safe-version-hints.json`
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -0,0 +1,15 @@
# SBOM→VEX Offline Kit (Stub)
This kit supports sprint task 6 (SBOM-VEX-GAPS-300-013).
Contents (stub):
- `verify.sh` chain hash stub for SBOM + DSSE + Rekor + VEX
- `chain-hash-recipe.md` canonicalisation steps
- `inputs.lock` pinned tool versions and snapshot
- `proof-manifest.json` chain hash placeholder
- `sbom-vex-blueprint.svg` diagram placeholder
Next steps:
- Add real SBOM/VEX samples and Rekor bundle snapshot.
- Produce DSSE signatures for proof manifest and scripts.
- Include time-anchor and backpressure/error policy notes per BP1BP10.

View File

@@ -0,0 +1,10 @@
{
"payloadType": "application/vnd.cyclonedx+json",
"payload": "ewogICJib21Gb3JtYXQiOiAiQ3ljbG9uZURYIiwKICAic3BlY1ZlcnNpb24iOiAiMS41IiwKICAidmVyc2lvbiI6IDEsCiAgImNvbXBvbmVudHMiOiBbCiAgICB7InR5cGUiOiAiY29udGFpbmVyIiwgIm5hbWUiOiAiZXhhbXBsZSIsICJ2ZXJzaW9uIjogIjEuMC4wIn0KICBdCn0K",
"signatures": [
{
"keyid": "stub-key-id",
"sig": "stub-signature"
}
]
}

View File

@@ -0,0 +1,7 @@
sbom_tool: "syft 1.1.0"
vex_tool: "stella-vex 0.4.2"
dsse_tool: "cosign 2.2.1"
rekor_snapshot: "rekor-snapshot-2025-11-30.json"
chain_hash_alg: "sha256"
tz: "UTC"
notes: "Offline kit; no live Rekor calls"

View File

@@ -0,0 +1,11 @@
{
"version": "0.1.0-stub",
"chain_hash": "7d72ed74065e8e359af34c5bb1805fa62629e2444dbe77b89efbebe5c4ddb932",
"inputs": {
"sbom": "sbom.json",
"vex": "vex.json",
"dsse": "envelope.dsse",
"rekor_bundle": "rekor-bundle.json"
},
"lockfile": "inputs.lock"
}

View File

@@ -0,0 +1,6 @@
{
"kind": "rekor.bundle",
"apiVersion": "0.1.0",
"logIndex": 123456,
"payloadHash": "stub"
}

View File

@@ -0,0 +1,8 @@
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"version": 1,
"components": [
{"type": "container", "name": "example", "version": "1.0.0"}
]
}

View File

@@ -0,0 +1,11 @@
{
"@context": "https://openvex.dev/ns/v0.2.0",
"statements": [
{
"vulnerability": "CVE-2025-0001",
"products": ["pkg:container/example@1.0.0"],
"status": "not_affected",
"justification": "vulnerable_code_not_present"
}
]
}

View File

@@ -13,4 +13,8 @@
- ABAC filters: vuln_env, vuln_owner, vuln_business_tier; enforcement in tokens/permalinks. - ABAC filters: vuln_env, vuln_owner, vuln_business_tier; enforcement in tokens/permalinks.
- Attachment tokens: issuance/verify; encryption notes; CSRF protections. - Attachment tokens: issuance/verify; encryption notes; CSRF protections.
### Hash Capture Checklist (post-review)
- `assets/vuln-explorer/rbac-scope-table.md` (scope/role matrix)
- `assets/vuln-explorer/abac-claims.json` (sample token claims)
- `assets/vuln-explorer/attachment-token-flow.json` (issuance/verify payloads)
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -20,4 +20,9 @@
## Determinism ## Determinism
- Use fixed CSAF samples; hash examples. - Use fixed CSAF samples; hash examples.
### Hash Capture Checklist (when assets land)
- `assets/vuln-explorer/vex-csaf-sample.json` (input)
- `assets/vuln-explorer/vex-mapping-output.json` (normalized decisions)
- `assets/vuln-explorer/vex-precedence-table.md` (suppression/precedence matrix)
_Last updated: 2025-12-05 (UTC)_ _Last updated: 2025-12-05 (UTC)_

View File

@@ -0,0 +1,29 @@
# GRAP0101 Integration Checklist for Vuln Explorer Md.XI
Use this checklist when the GRAP0101 domain model contract arrives.
## Fill across docs
- `docs/vuln/explorer-overview.md`: replace `[[pending:...]]` placeholders (entities, relationships, identifiers); confirm triage state names; add hashes for examples once captured.
- `docs/vuln/explorer-using-console.md`: apply final field labels, keyboard shortcuts, saved view params; drop hashed assets per checklist.
- `docs/vuln/explorer-api.md`: finalize filter/sort/ETag params, limits, error codes; attach hashed request/response fixtures.
- `docs/vuln/explorer-cli.md`: align flag names with API; add hashed CLI outputs.
- `docs/vuln/findings-ledger.md`: align schema names/ids; confirm hash fields and Merkle notes match GRAP0101.
- `docs/policy/vuln-determinations.md`: sync identifiers and signal fields referenced in policy outputs.
- `docs/vex/explorer-integration.md`: confirm CSAF→VEX mapping fields and precedence references.
- `docs/advisories/explorer-integration.md`: update advisory identifiers/keys to GRAP0101 naming.
- `docs/sbom/vuln-resolution.md`: align component identifier fields (purl/NEVRA) with GRAP0101.
- `docs/observability/vuln-telemetry.md`: verify metric/log labels (findingId, advisoryId, policyVersion, artifactId) match contract.
- `docs/security/vuln-rbac.md`: confirm scope/claim names and attachment token fields.
- `docs/runbooks/vuln-ops.md`: ensure IDs/fields in remediation steps match contract.
## Hash capture locations
- Record all assets in `docs/assets/vuln-explorer/SHA256SUMS` using the per-subdir checklists.
## Order of operations
1. Update overview entities/ids first (DOCS-VULN-29-001).
2. Propagate identifiers to console/API/CLI stubs (#2#4).
3. Align ledger/policy/VEX/advisory/SBOM docs (#5#9).
4. Finish telemetry/RBAC/runbook (#10#12).
5. Update install doc (#13) once images/manifests arrive.
_Last updated: 2025-12-05 (UTC)_

View File

@@ -36,6 +36,16 @@
3) Expose via API/Console/CLI with cached reachability/VEX context and policy explain bundles (VEX-first, reachability second, policy gates third per architecture). 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. 4) Export reports/offline bundles; verify with ledger hashes and DSSE attestations.
## Triage States (architecture; finalize with GRAP0101)
- `new``triaged``in_progress``awaiting_verification``remediated`
- `new``closed_false_positive`
- `new``accepted_risk`
- Each transition requires justification; accepted risk requires multi-approver workflow (Policy Studio) and ABAC enforcement.
## Offline / Export Expectations
- Offline bundle structure: `manifest.json`, `findings.jsonl`, `history.jsonl`, `actions.jsonl`, `reports/`, `signatures/` (DSSE envelopes); deterministic ordering and hashes.
- Bundles are consumed by Export Center mirror profiles; include Merkle roots and hash manifests for verification.
## Offline/Determinism Notes ## Offline/Determinism Notes
- Hash captures for screenshots/payloads recorded in `docs/assets/vuln-explorer/SHA256SUMS` (empty until assets arrive). - 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. - Use fixed fixture sets and ordered outputs when adding examples.

View File

@@ -0,0 +1,25 @@
using StellaOps.TimelineIndexer.Core.Abstractions;
using StellaOps.TimelineIndexer.Core.Models;
namespace StellaOps.ExportCenter.Core.Services;
/// <summary>
/// Thin client surface to fetch timeline evidence linkage for export runs.
/// Uses manifest fallback when evidence payload omits explicit manifest URI.
/// </summary>
public sealed class TimelineEvidenceClient
{
private readonly ITimelineQueryService _queryService;
public TimelineEvidenceClient(ITimelineQueryService queryService)
{
_queryService = queryService;
}
public Task<TimelineEvidenceView?> GetEvidenceAsync(string tenantId, string eventId, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(tenantId);
ArgumentException.ThrowIfNullOrWhiteSpace(eventId);
return _queryService.GetEvidenceAsync(tenantId, eventId, cancellationToken);
}
}

View File

@@ -14,4 +14,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0-rc.2.25502.107" />
</ItemGroup> </ItemGroup>
</Project>
<ItemGroup>
<ProjectReference Include="..\..\..\TimelineIndexer\StellaOps.TimelineIndexer\StellaOps.TimelineIndexer.Core\StellaOps.TimelineIndexer.Core.csproj" />
</ItemGroup>
</Project>

View File

@@ -10,6 +10,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\StellaOps.ExportCenter.Core\StellaOps.ExportCenter.Core.csproj" /> <ProjectReference Include="..\StellaOps.ExportCenter.Core\StellaOps.ExportCenter.Core.csproj" />
<ProjectReference Include="..\..\..\TimelineIndexer\StellaOps.TimelineIndexer\StellaOps.TimelineIndexer.Core\StellaOps.TimelineIndexer.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@@ -17,5 +17,6 @@
<ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj" /> <ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj" />
<ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj" /> <ProjectReference Include="..\..\..\Authority\StellaOps.Authority\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj" />
<ProjectReference Include="..\..\..\AirGap\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy.csproj" /> <ProjectReference Include="..\..\..\AirGap\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy\StellaOps.AirGap.Policy.csproj" />
<ProjectReference Include="..\..\..\TimelineIndexer\StellaOps.TimelineIndexer\StellaOps.TimelineIndexer.Core\StellaOps.TimelineIndexer.Core.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,945 @@
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Nodes;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using StellaOps.Notify.Models;
namespace StellaOps.Notify.Storage.Mongo.Documents;
public sealed class NotifyAuditEntryDocument
{
public required string TenantId { get; init; }
public required string Action { get; init; }
public string? Actor { get; init; }
public string? EntityId { get; init; }
public string? EntityType { get; init; }
public string? CorrelationId { get; init; }
public JsonObject? Payload { get; init; }
public DateTimeOffset Timestamp { get; init; }
}
public sealed class NotifyDigestDocument
{
public required string TenantId { get; init; }
public required string ActionKey { get; init; }
public string? Content { get; init; }
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
}
public sealed class PackApprovalDocument
{
public required string TenantId { get; init; }
public required Guid EventId { get; init; }
public required string PackId { get; init; }
public string? Kind { get; init; }
public string? Decision { get; init; }
public string? Actor { get; init; }
public DateTimeOffset? IssuedAt { get; init; }
public string? PolicyId { get; init; }
public string? PolicyVersion { get; init; }
public string? ResumeToken { get; init; }
public string? Summary { get; init; }
public IDictionary<string, string>? Labels { get; init; }
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
}
public sealed class NotifyInboxMessage
{
public required string MessageId { get; init; }
public required string TenantId { get; init; }
public required string UserId { get; init; }
public required string Title { get; init; }
public required string Body { get; init; }
public string? Summary { get; init; }
public string? Category { get; init; }
public int Priority { get; init; }
public IDictionary<string, string>? Metadata { get; init; }
public DateTimeOffset CreatedAt { get; init; }
public DateTimeOffset? ExpiresAt { get; init; }
public DateTimeOffset? ReadAt { get; set; }
public string? SourceChannel { get; init; }
public string? DeliveryId { get; init; }
}
namespace StellaOps.Notify.Storage.Mongo.Repositories;
public interface INotifyMongoInitializer
{
Task EnsureIndexesAsync(CancellationToken cancellationToken = default);
}
public interface INotifyMongoMigration { }
public interface INotifyMongoMigrationRunner { }
public interface INotifyRuleRepository
{
Task UpsertAsync(NotifyRule rule, CancellationToken cancellationToken = default);
Task<NotifyRule?> GetAsync(string tenantId, string ruleId, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyRule>> ListAsync(string tenantId, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string ruleId, CancellationToken cancellationToken = default);
}
public interface INotifyChannelRepository
{
Task UpsertAsync(NotifyChannel channel, CancellationToken cancellationToken = default);
Task<NotifyChannel?> GetAsync(string tenantId, string channelId, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyChannel>> ListAsync(string tenantId, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string channelId, CancellationToken cancellationToken = default);
}
public interface INotifyTemplateRepository
{
Task UpsertAsync(NotifyTemplate template, CancellationToken cancellationToken = default);
Task<NotifyTemplate?> GetAsync(string tenantId, string templateId, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyTemplate>> ListAsync(string tenantId, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string templateId, CancellationToken cancellationToken = default);
}
public interface INotifyDeliveryRepository
{
Task AppendAsync(NotifyDelivery delivery, CancellationToken cancellationToken = default);
Task UpdateAsync(NotifyDelivery delivery, CancellationToken cancellationToken = default);
Task<NotifyDelivery?> GetAsync(string tenantId, string deliveryId, CancellationToken cancellationToken = default);
Task<NotifyDeliveryQueryResult> QueryAsync(
string tenantId,
DateTimeOffset? since,
string? status,
int? limit,
string? continuationToken = null,
CancellationToken cancellationToken = default);
}
public sealed record NotifyDeliveryQueryResult(IReadOnlyList<NotifyDelivery> Items, string? ContinuationToken);
public interface INotifyDigestRepository
{
Task<NotifyDigestDocument?> GetAsync(string tenantId, string actionKey, CancellationToken cancellationToken = default);
Task UpsertAsync(NotifyDigestDocument document, CancellationToken cancellationToken = default);
Task RemoveAsync(string tenantId, string actionKey, CancellationToken cancellationToken = default);
}
public interface INotifyLockRepository
{
Task<bool> TryAcquireAsync(string tenantId, string resource, string owner, TimeSpan ttl, CancellationToken cancellationToken = default);
Task ReleaseAsync(string tenantId, string resource, string owner, CancellationToken cancellationToken = default);
}
public interface INotifyAuditRepository
{
Task AppendAsync(NotifyAuditEntryDocument entry, CancellationToken cancellationToken = default);
Task AppendAsync(string tenantId, string action, IReadOnlyDictionary<string, string> payload, string? actor = null, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyAuditEntryDocument>> QueryAsync(string tenantId, DateTimeOffset? since, int? limit, CancellationToken cancellationToken = default);
}
public interface INotifyPackApprovalRepository
{
Task UpsertAsync(PackApprovalDocument document, CancellationToken cancellationToken = default);
bool Exists(string tenantId, Guid eventId, string packId);
}
public interface INotifyQuietHoursRepository
{
Task<IReadOnlyList<NotifyQuietHoursSchedule>> ListEnabledAsync(string tenantId, string? channelId = null, CancellationToken cancellationToken = default);
}
public interface INotifyMaintenanceWindowRepository
{
Task<IReadOnlyList<NotifyMaintenanceWindow>> GetActiveAsync(string tenantId, DateTimeOffset timestamp, CancellationToken cancellationToken = default);
}
public interface INotifyOperatorOverrideRepository
{
Task<IReadOnlyList<NotifyOperatorOverride>> ListActiveAsync(
string tenantId,
DateTimeOffset asOf,
NotifyOverrideType? type = null,
string? channelId = null,
CancellationToken cancellationToken = default);
}
public interface INotifyThrottleConfigRepository
{
Task<IReadOnlyList<NotifyThrottleConfig>> ListAsync(string tenantId, CancellationToken cancellationToken = default);
Task<NotifyThrottleConfig?> GetAsync(string tenantId, string configId, CancellationToken cancellationToken = default);
Task UpsertAsync(NotifyThrottleConfig config, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string configId, CancellationToken cancellationToken = default);
}
public interface INotifyLocalizationRepository
{
Task<NotifyLocalizationBundle?> GetByKeyAndLocaleAsync(string tenantId, string bundleKey, string locale, CancellationToken cancellationToken = default);
Task<NotifyLocalizationBundle?> GetDefaultAsync(string tenantId, string bundleKey, CancellationToken cancellationToken = default);
}
public interface INotifyEscalationPolicyRepository
{
Task<IReadOnlyList<NotifyEscalationPolicy>> ListAsync(string tenantId, bool? enabled = null, CancellationToken cancellationToken = default);
Task<NotifyEscalationPolicy?> GetAsync(string tenantId, string policyId, CancellationToken cancellationToken = default);
Task UpsertAsync(NotifyEscalationPolicy policy, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string policyId, CancellationToken cancellationToken = default);
}
public interface INotifyEscalationStateRepository
{
Task<NotifyEscalationState?> GetAsync(string tenantId, string stateId, CancellationToken cancellationToken = default);
Task<NotifyEscalationState?> GetByIncidentAsync(string tenantId, string incidentId, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyEscalationState>> ListDueForEscalationAsync(string tenantId, DateTimeOffset asOf, int batchSize, CancellationToken cancellationToken = default);
Task UpsertAsync(NotifyEscalationState state, CancellationToken cancellationToken = default);
Task AcknowledgeAsync(string tenantId, string stateId, string acknowledgedBy, DateTimeOffset acknowledgedAt, CancellationToken cancellationToken = default);
Task ResolveAsync(string tenantId, string stateId, string resolvedBy, DateTimeOffset resolvedAt, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string stateId, CancellationToken cancellationToken = default);
}
public interface INotifyOnCallScheduleRepository
{
Task<IReadOnlyList<NotifyOnCallSchedule>> ListAsync(string tenantId, CancellationToken cancellationToken = default);
Task<NotifyOnCallSchedule?> GetAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default);
Task UpsertAsync(NotifyOnCallSchedule schedule, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default);
}
public interface INotifyInboxRepository
{
Task StoreAsync(NotifyInboxMessage message, CancellationToken cancellationToken = default);
Task<IReadOnlyList<NotifyInboxMessage>> GetForUserAsync(string tenantId, string userId, int limit = 50, CancellationToken cancellationToken = default);
Task<NotifyInboxMessage?> GetAsync(string tenantId, string messageId, CancellationToken cancellationToken = default);
Task MarkReadAsync(string tenantId, string messageId, CancellationToken cancellationToken = default);
Task MarkAllReadAsync(string tenantId, string userId, CancellationToken cancellationToken = default);
Task DeleteAsync(string tenantId, string messageId, CancellationToken cancellationToken = default);
Task<int> GetUnreadCountAsync(string tenantId, string userId, CancellationToken cancellationToken = default);
}
internal sealed class InMemoryRuleRepository : INotifyRuleRepository
{
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, NotifyRule>> _rules = new(StringComparer.Ordinal);
public Task UpsertAsync(NotifyRule rule, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(rule);
var tenantRules = _rules.GetOrAdd(rule.TenantId, _ => new ConcurrentDictionary<string, NotifyRule>(StringComparer.Ordinal));
tenantRules[rule.RuleId] = rule;
return Task.CompletedTask;
}
public Task<NotifyRule?> GetAsync(string tenantId, string ruleId, CancellationToken cancellationToken = default)
{
if (_rules.TryGetValue(tenantId, out var rules) && rules.TryGetValue(ruleId, out var rule))
{
return Task.FromResult<NotifyRule?>(rule);
}
return Task.FromResult<NotifyRule?>(null);
}
public Task<IReadOnlyList<NotifyRule>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
if (_rules.TryGetValue(tenantId, out var rules))
{
return Task.FromResult<IReadOnlyList<NotifyRule>>(rules.Values.ToArray());
}
return Task.FromResult<IReadOnlyList<NotifyRule>>(Array.Empty<NotifyRule>());
}
public Task DeleteAsync(string tenantId, string ruleId, CancellationToken cancellationToken = default)
{
if (_rules.TryGetValue(tenantId, out var rules))
{
rules.TryRemove(ruleId, out _);
}
return Task.CompletedTask;
}
}
internal sealed class InMemoryChannelRepository : INotifyChannelRepository
{
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, NotifyChannel>> _channels = new(StringComparer.Ordinal);
public Task UpsertAsync(NotifyChannel channel, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(channel);
var map = _channels.GetOrAdd(channel.TenantId, _ => new ConcurrentDictionary<string, NotifyChannel>(StringComparer.Ordinal));
map[channel.ChannelId] = channel;
return Task.CompletedTask;
}
public Task<NotifyChannel?> GetAsync(string tenantId, string channelId, CancellationToken cancellationToken = default)
{
if (_channels.TryGetValue(tenantId, out var map) && map.TryGetValue(channelId, out var channel))
{
return Task.FromResult<NotifyChannel?>(channel);
}
return Task.FromResult<NotifyChannel?>(null);
}
public Task<IReadOnlyList<NotifyChannel>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
if (_channels.TryGetValue(tenantId, out var map))
{
return Task.FromResult<IReadOnlyList<NotifyChannel>>(map.Values.ToArray());
}
return Task.FromResult<IReadOnlyList<NotifyChannel>>(Array.Empty<NotifyChannel>());
}
public Task DeleteAsync(string tenantId, string channelId, CancellationToken cancellationToken = default)
{
if (_channels.TryGetValue(tenantId, out var map))
{
map.TryRemove(channelId, out _);
}
return Task.CompletedTask;
}
}
internal sealed class InMemoryTemplateRepository : INotifyTemplateRepository
{
private readonly ConcurrentDictionary<(string TenantId, string TemplateId), NotifyTemplate> _templates = new();
public Task UpsertAsync(NotifyTemplate template, CancellationToken cancellationToken = default)
{
_templates[(template.TenantId, template.TemplateId)] = template;
return Task.CompletedTask;
}
public Task<NotifyTemplate?> GetAsync(string tenantId, string templateId, CancellationToken cancellationToken = default)
{
_templates.TryGetValue((tenantId, templateId), out var tpl);
return Task.FromResult(tpl);
}
public Task<IReadOnlyList<NotifyTemplate>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
var list = _templates.Where(kv => kv.Key.TenantId == tenantId).Select(kv => kv.Value).ToList();
return Task.FromResult<IReadOnlyList<NotifyTemplate>>(list);
}
public Task DeleteAsync(string tenantId, string templateId, CancellationToken cancellationToken = default)
{
_templates.TryRemove((tenantId, templateId), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryDeliveryRepository : INotifyDeliveryRepository
{
private readonly ConcurrentDictionary<string, List<NotifyDelivery>> _deliveries = new(StringComparer.Ordinal);
public Task AppendAsync(NotifyDelivery delivery, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(delivery);
var list = _deliveries.GetOrAdd(delivery.TenantId, _ => new List<NotifyDelivery>());
lock (list)
{
list.Add(delivery);
}
return Task.CompletedTask;
}
public Task UpdateAsync(NotifyDelivery delivery, CancellationToken cancellationToken = default)
{
ArgumentNullException.ThrowIfNull(delivery);
var list = _deliveries.GetOrAdd(delivery.TenantId, _ => new List<NotifyDelivery>());
lock (list)
{
var index = list.FindIndex(existing => existing.DeliveryId == delivery.DeliveryId);
if (index >= 0)
{
list[index] = delivery;
}
else
{
list.Add(delivery);
}
}
return Task.CompletedTask;
}
public Task<NotifyDelivery?> GetAsync(string tenantId, string deliveryId, CancellationToken cancellationToken = default)
{
if (_deliveries.TryGetValue(tenantId, out var list))
{
lock (list)
{
return Task.FromResult<NotifyDelivery?>(list.FirstOrDefault(delivery => delivery.DeliveryId == deliveryId));
}
}
return Task.FromResult<NotifyDelivery?>(null);
}
public Task<NotifyDeliveryQueryResult> QueryAsync(
string tenantId,
DateTimeOffset? since,
string? status,
int? limit,
string? continuationToken = null,
CancellationToken cancellationToken = default)
{
if (_deliveries.TryGetValue(tenantId, out var list))
{
lock (list)
{
var items = list
.Where(d => (!since.HasValue || d.CreatedAt >= since) &&
(string.IsNullOrWhiteSpace(status) || string.Equals(d.Status.ToString(), status, StringComparison.OrdinalIgnoreCase)))
.OrderByDescending(d => d.CreatedAt)
.Take(limit ?? 50)
.ToArray();
return Task.FromResult(new NotifyDeliveryQueryResult(items, null));
}
}
return Task.FromResult(new NotifyDeliveryQueryResult(Array.Empty<NotifyDelivery>(), null));
}
}
internal sealed class InMemoryDigestRepository : INotifyDigestRepository
{
private readonly ConcurrentDictionary<(string TenantId, string ActionKey), NotifyDigestDocument> _digests = new();
public Task<NotifyDigestDocument?> GetAsync(string tenantId, string actionKey, CancellationToken cancellationToken = default)
{
_digests.TryGetValue((tenantId, actionKey), out var doc);
return Task.FromResult(doc);
}
public Task UpsertAsync(NotifyDigestDocument document, CancellationToken cancellationToken = default)
{
_digests[(document.TenantId, document.ActionKey)] = document;
return Task.CompletedTask;
}
public Task RemoveAsync(string tenantId, string actionKey, CancellationToken cancellationToken = default)
{
_digests.TryRemove((tenantId, actionKey), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryLockRepository : INotifyLockRepository
{
private readonly object _sync = new();
private readonly Dictionary<(string TenantId, string Resource), (string Owner, DateTimeOffset Expiry)> _locks = new();
public Task<bool> TryAcquireAsync(string tenantId, string resource, string owner, TimeSpan ttl, CancellationToken cancellationToken = default)
{
ArgumentException.ThrowIfNullOrWhiteSpace(tenantId);
ArgumentException.ThrowIfNullOrWhiteSpace(resource);
ArgumentException.ThrowIfNullOrWhiteSpace(owner);
lock (_sync)
{
var key = (tenantId, resource);
var now = DateTimeOffset.UtcNow;
if (_locks.TryGetValue(key, out var existing) && existing.Expiry > now)
{
return Task.FromResult(false);
}
_locks[key] = (owner, now + ttl);
return Task.FromResult(true);
}
}
public Task ReleaseAsync(string tenantId, string resource, string owner, CancellationToken cancellationToken = default)
{
lock (_sync)
{
var key = (tenantId, resource);
_locks.Remove(key);
return Task.CompletedTask;
}
}
}
internal sealed class InMemoryAuditRepository : INotifyAuditRepository
{
private readonly ConcurrentDictionary<string, List<NotifyAuditEntryDocument>> _entries = new(StringComparer.Ordinal);
public Task AppendAsync(NotifyAuditEntryDocument entry, CancellationToken cancellationToken = default)
{
var list = _entries.GetOrAdd(entry.TenantId, _ => new List<NotifyAuditEntryDocument>());
lock (list)
{
list.Add(entry);
}
return Task.CompletedTask;
}
public Task AppendAsync(string tenantId, string action, IReadOnlyDictionary<string, string> payload, string? actor = null, CancellationToken cancellationToken = default)
{
var entry = new NotifyAuditEntryDocument
{
TenantId = tenantId,
Action = action,
Actor = actor,
EntityType = "audit",
Timestamp = DateTimeOffset.UtcNow,
Payload = JsonSerializer.SerializeToNode(payload) as JsonObject
};
return AppendAsync(entry, cancellationToken);
}
public Task<IReadOnlyList<NotifyAuditEntryDocument>> QueryAsync(string tenantId, DateTimeOffset? since, int? limit, CancellationToken cancellationToken = default)
{
if (_entries.TryGetValue(tenantId, out var list))
{
lock (list)
{
var items = list
.Where(e => !since.HasValue || e.Timestamp >= since.Value)
.OrderByDescending(e => e.Timestamp)
.ToList();
if (limit is > 0)
{
items = items.Take(limit.Value).ToList();
}
return Task.FromResult<IReadOnlyList<NotifyAuditEntryDocument>>(items);
}
}
return Task.FromResult<IReadOnlyList<NotifyAuditEntryDocument>>(Array.Empty<NotifyAuditEntryDocument>());
}
}
internal sealed class InMemoryPackApprovalRepository : INotifyPackApprovalRepository
{
private readonly ConcurrentDictionary<(string TenantId, Guid EventId, string PackId), PackApprovalDocument> _records = new();
public Task UpsertAsync(PackApprovalDocument document, CancellationToken cancellationToken = default)
{
_records[(document.TenantId, document.EventId, document.PackId)] = document;
return Task.CompletedTask;
}
public bool Exists(string tenantId, Guid eventId, string packId)
=> _records.ContainsKey((tenantId, eventId, packId));
}
internal sealed class InMemoryQuietHoursRepository : INotifyQuietHoursRepository
{
private readonly ConcurrentDictionary<string, List<NotifyQuietHoursSchedule>> _schedules = new(StringComparer.Ordinal);
public Task<IReadOnlyList<NotifyQuietHoursSchedule>> ListEnabledAsync(string tenantId, string? channelId = null, CancellationToken cancellationToken = default)
{
if (_schedules.TryGetValue(tenantId, out var list))
{
var filtered = list
.Where(s => s.Enabled)
.Where(s => channelId is null || s.ChannelId is null || s.ChannelId == channelId)
.ToList();
return Task.FromResult<IReadOnlyList<NotifyQuietHoursSchedule>>(filtered);
}
return Task.FromResult<IReadOnlyList<NotifyQuietHoursSchedule>>(Array.Empty<NotifyQuietHoursSchedule>());
}
public void Seed(string tenantId, params NotifyQuietHoursSchedule[] schedules)
{
var list = _schedules.GetOrAdd(tenantId, _ => new List<NotifyQuietHoursSchedule>());
lock (list)
{
list.AddRange(schedules);
}
}
}
internal sealed class InMemoryMaintenanceWindowRepository : INotifyMaintenanceWindowRepository
{
private readonly ConcurrentDictionary<string, List<NotifyMaintenanceWindow>> _windows = new(StringComparer.Ordinal);
public Task<IReadOnlyList<NotifyMaintenanceWindow>> GetActiveAsync(string tenantId, DateTimeOffset timestamp, CancellationToken cancellationToken = default)
{
if (_windows.TryGetValue(tenantId, out var list))
{
var active = list.Where(w => w.IsActiveAt(timestamp)).ToList();
return Task.FromResult<IReadOnlyList<NotifyMaintenanceWindow>>(active);
}
return Task.FromResult<IReadOnlyList<NotifyMaintenanceWindow>>(Array.Empty<NotifyMaintenanceWindow>());
}
public void Seed(string tenantId, params NotifyMaintenanceWindow[] windows)
{
var list = _windows.GetOrAdd(tenantId, _ => new List<NotifyMaintenanceWindow>());
lock (list)
{
list.AddRange(windows);
}
}
}
internal sealed class InMemoryOperatorOverrideRepository : INotifyOperatorOverrideRepository
{
private readonly ConcurrentDictionary<string, List<NotifyOperatorOverride>> _overrides = new(StringComparer.Ordinal);
public Task<IReadOnlyList<NotifyOperatorOverride>> ListActiveAsync(
string tenantId,
DateTimeOffset asOf,
NotifyOverrideType? type = null,
string? channelId = null,
CancellationToken cancellationToken = default)
{
if (_overrides.TryGetValue(tenantId, out var list))
{
var items = list
.Where(o => o.IsActiveAt(asOf))
.Where(o => type is null || o.Type == type)
.Where(o => channelId is null || o.ChannelId is null || o.ChannelId == channelId)
.ToList();
return Task.FromResult<IReadOnlyList<NotifyOperatorOverride>>(items);
}
return Task.FromResult<IReadOnlyList<NotifyOperatorOverride>>(Array.Empty<NotifyOperatorOverride>());
}
public void Seed(string tenantId, params NotifyOperatorOverride[] overrides)
{
var list = _overrides.GetOrAdd(tenantId, _ => new List<NotifyOperatorOverride>());
lock (list)
{
list.AddRange(overrides);
}
}
}
internal sealed class InMemoryThrottleConfigRepository : INotifyThrottleConfigRepository
{
private readonly ConcurrentDictionary<(string TenantId, string ConfigId), NotifyThrottleConfig> _configs = new();
public Task<IReadOnlyList<NotifyThrottleConfig>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
var list = _configs
.Where(kv => kv.Key.TenantId == tenantId)
.Select(kv => kv.Value)
.ToList();
return Task.FromResult<IReadOnlyList<NotifyThrottleConfig>>(list);
}
public Task<NotifyThrottleConfig?> GetAsync(string tenantId, string configId, CancellationToken cancellationToken = default)
{
_configs.TryGetValue((tenantId, configId), out var cfg);
return Task.FromResult(cfg);
}
public Task UpsertAsync(NotifyThrottleConfig config, CancellationToken cancellationToken = default)
{
_configs[(config.TenantId, config.ConfigId)] = config;
return Task.CompletedTask;
}
public Task DeleteAsync(string tenantId, string configId, CancellationToken cancellationToken = default)
{
_configs.TryRemove((tenantId, configId), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryLocalizationRepository : INotifyLocalizationRepository
{
private readonly ConcurrentDictionary<(string TenantId, string BundleKey, string Locale), NotifyLocalizationBundle> _bundles = new();
public Task<NotifyLocalizationBundle?> GetByKeyAndLocaleAsync(string tenantId, string bundleKey, string locale, CancellationToken cancellationToken = default)
{
_bundles.TryGetValue((tenantId, bundleKey, locale), out var bundle);
return Task.FromResult(bundle);
}
public Task<NotifyLocalizationBundle?> GetDefaultAsync(string tenantId, string bundleKey, CancellationToken cancellationToken = default)
{
var match = _bundles.FirstOrDefault(kv => kv.Key.TenantId == tenantId && kv.Key.BundleKey == bundleKey);
return Task.FromResult(match.Value);
}
}
internal sealed class InMemoryEscalationPolicyRepository : INotifyEscalationPolicyRepository
{
private readonly ConcurrentDictionary<(string TenantId, string PolicyId), NotifyEscalationPolicy> _policies = new();
public Task<IReadOnlyList<NotifyEscalationPolicy>> ListAsync(string tenantId, bool? enabled = null, CancellationToken cancellationToken = default)
{
var list = _policies
.Where(kv => kv.Key.TenantId == tenantId)
.Select(kv => kv.Value)
.Where(p => !enabled.HasValue || p.Enabled == enabled.Value)
.ToList();
return Task.FromResult<IReadOnlyList<NotifyEscalationPolicy>>(list);
}
public Task<NotifyEscalationPolicy?> GetAsync(string tenantId, string policyId, CancellationToken cancellationToken = default)
{
_policies.TryGetValue((tenantId, policyId), out var policy);
return Task.FromResult(policy);
}
public Task UpsertAsync(NotifyEscalationPolicy policy, CancellationToken cancellationToken = default)
{
_policies[(policy.TenantId, policy.PolicyId)] = policy;
return Task.CompletedTask;
}
public Task DeleteAsync(string tenantId, string policyId, CancellationToken cancellationToken = default)
{
_policies.TryRemove((tenantId, policyId), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryEscalationStateRepository : INotifyEscalationStateRepository
{
private readonly ConcurrentDictionary<(string TenantId, string StateId), NotifyEscalationState> _states = new();
public Task<NotifyEscalationState?> GetAsync(string tenantId, string stateId, CancellationToken cancellationToken = default)
{
_states.TryGetValue((tenantId, stateId), out var state);
return Task.FromResult(state);
}
public Task<NotifyEscalationState?> GetByIncidentAsync(string tenantId, string incidentId, CancellationToken cancellationToken = default)
{
var match = _states.FirstOrDefault(kv => kv.Key.TenantId == tenantId && kv.Value.IncidentId == incidentId);
return Task.FromResult(match.Value);
}
public Task<IReadOnlyList<NotifyEscalationState>> ListDueForEscalationAsync(string tenantId, DateTimeOffset asOf, int batchSize, CancellationToken cancellationToken = default)
{
var states = _states
.Where(kv => kv.Key.TenantId == tenantId && kv.Value.Status == NotifyEscalationStatus.Active)
.Where(kv => kv.Value.NextEscalationAt is null || kv.Value.NextEscalationAt <= asOf)
.Select(kv => kv.Value)
.Take(batchSize)
.ToList();
return Task.FromResult<IReadOnlyList<NotifyEscalationState>>(states);
}
public Task UpsertAsync(NotifyEscalationState state, CancellationToken cancellationToken = default)
{
_states[(state.TenantId, state.StateId)] = state;
return Task.CompletedTask;
}
public Task AcknowledgeAsync(string tenantId, string stateId, string acknowledgedBy, DateTimeOffset acknowledgedAt, CancellationToken cancellationToken = default)
{
if (_states.TryGetValue((tenantId, stateId), out var state))
{
_states[(tenantId, stateId)] = state with
{
Status = NotifyEscalationStatus.Acknowledged,
AcknowledgedAt = acknowledgedAt,
AcknowledgedBy = acknowledgedBy
};
}
return Task.CompletedTask;
}
public Task ResolveAsync(string tenantId, string stateId, string resolvedBy, DateTimeOffset resolvedAt, CancellationToken cancellationToken = default)
{
if (_states.TryGetValue((tenantId, stateId), out var state))
{
_states[(tenantId, stateId)] = state with
{
Status = NotifyEscalationStatus.Resolved,
ResolvedAt = resolvedAt,
ResolvedBy = resolvedBy
};
}
return Task.CompletedTask;
}
public Task DeleteAsync(string tenantId, string stateId, CancellationToken cancellationToken = default)
{
_states.TryRemove((tenantId, stateId), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryOnCallScheduleRepository : INotifyOnCallScheduleRepository
{
private readonly ConcurrentDictionary<(string TenantId, string ScheduleId), NotifyOnCallSchedule> _schedules = new();
public Task<IReadOnlyList<NotifyOnCallSchedule>> ListAsync(string tenantId, CancellationToken cancellationToken = default)
{
var list = _schedules.Where(kv => kv.Key.TenantId == tenantId).Select(kv => kv.Value).ToList();
return Task.FromResult<IReadOnlyList<NotifyOnCallSchedule>>(list);
}
public Task<NotifyOnCallSchedule?> GetAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default)
{
_schedules.TryGetValue((tenantId, scheduleId), out var schedule);
return Task.FromResult(schedule);
}
public Task UpsertAsync(NotifyOnCallSchedule schedule, CancellationToken cancellationToken = default)
{
_schedules[(schedule.TenantId, schedule.ScheduleId)] = schedule;
return Task.CompletedTask;
}
public Task DeleteAsync(string tenantId, string scheduleId, CancellationToken cancellationToken = default)
{
_schedules.TryRemove((tenantId, scheduleId), out _);
return Task.CompletedTask;
}
}
internal sealed class InMemoryInboxRepository : INotifyInboxRepository
{
private readonly ConcurrentDictionary<string, List<NotifyInboxMessage>> _messages = new(StringComparer.Ordinal);
public Task StoreAsync(NotifyInboxMessage message, CancellationToken cancellationToken = default)
{
var list = _messages.GetOrAdd(message.TenantId, _ => new List<NotifyInboxMessage>());
lock (list)
{
list.Add(message);
}
return Task.CompletedTask;
}
public Task<IReadOnlyList<NotifyInboxMessage>> GetForUserAsync(string tenantId, string userId, int limit = 50, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
return Task.FromResult<IReadOnlyList<NotifyInboxMessage>>(list
.Where(m => m.UserId == userId)
.OrderByDescending(m => m.CreatedAt)
.Take(limit)
.ToList());
}
}
return Task.FromResult<IReadOnlyList<NotifyInboxMessage>>(Array.Empty<NotifyInboxMessage>());
}
public Task<NotifyInboxMessage?> GetAsync(string tenantId, string messageId, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
return Task.FromResult<NotifyInboxMessage?>(list.FirstOrDefault(m => m.MessageId == messageId));
}
}
return Task.FromResult<NotifyInboxMessage?>(null);
}
public Task MarkReadAsync(string tenantId, string messageId, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
var msg = list.FirstOrDefault(m => m.MessageId == messageId);
if (msg is not null)
{
msg.ReadAt = DateTimeOffset.UtcNow;
}
}
}
return Task.CompletedTask;
}
public Task MarkAllReadAsync(string tenantId, string userId, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
foreach (var msg in list.Where(m => m.UserId == userId))
{
msg.ReadAt ??= DateTimeOffset.UtcNow;
}
}
}
return Task.CompletedTask;
}
public Task DeleteAsync(string tenantId, string messageId, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
var idx = list.FindIndex(m => m.MessageId == messageId);
if (idx >= 0) list.RemoveAt(idx);
}
}
return Task.CompletedTask;
}
public Task<int> GetUnreadCountAsync(string tenantId, string userId, CancellationToken cancellationToken = default)
{
if (_messages.TryGetValue(tenantId, out var list))
{
lock (list)
{
return Task.FromResult(list.Count(m => m.UserId == userId && m.ReadAt is null));
}
}
return Task.FromResult(0);
}
}
namespace StellaOps.Notify.Storage.Mongo.Internal;
public sealed class NotifyMongoInitializer : INotifyMongoInitializer
{
public Task EnsureIndexesAsync(CancellationToken cancellationToken = default) => Task.CompletedTask;
}
namespace StellaOps.Notify.Storage.Mongo;
using Documents;
using Internal;
using Repositories;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddNotifyMongoStorage(this IServiceCollection services, IConfiguration configuration)
{
services.TryAddSingleton<INotifyMongoInitializer, NotifyMongoInitializer>();
services.TryAddSingleton<INotifyRuleRepository, InMemoryRuleRepository>();
services.TryAddSingleton<INotifyChannelRepository, InMemoryChannelRepository>();
services.TryAddSingleton<INotifyTemplateRepository, InMemoryTemplateRepository>();
services.TryAddSingleton<INotifyDeliveryRepository, InMemoryDeliveryRepository>();
services.TryAddSingleton<INotifyDigestRepository, InMemoryDigestRepository>();
services.TryAddSingleton<INotifyLockRepository, InMemoryLockRepository>();
services.TryAddSingleton<INotifyAuditRepository, InMemoryAuditRepository>();
services.TryAddSingleton<INotifyPackApprovalRepository, InMemoryPackApprovalRepository>();
services.TryAddSingleton<INotifyQuietHoursRepository, InMemoryQuietHoursRepository>();
services.TryAddSingleton<INotifyMaintenanceWindowRepository, InMemoryMaintenanceWindowRepository>();
services.TryAddSingleton<INotifyOperatorOverrideRepository, InMemoryOperatorOverrideRepository>();
services.TryAddSingleton<INotifyThrottleConfigRepository, InMemoryThrottleConfigRepository>();
services.TryAddSingleton<INotifyLocalizationRepository, InMemoryLocalizationRepository>();
services.TryAddSingleton<INotifyEscalationPolicyRepository, InMemoryEscalationPolicyRepository>();
services.TryAddSingleton<INotifyEscalationStateRepository, InMemoryEscalationStateRepository>();
services.TryAddSingleton<INotifyOnCallScheduleRepository, InMemoryOnCallScheduleRepository>();
services.TryAddSingleton<INotifyInboxRepository, InMemoryInboxRepository>();
return services;
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>preview</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../StellaOps.Notify.Models/StellaOps.Notify.Models.csproj" />
</ItemGroup>
</Project>

View File

@@ -14,9 +14,8 @@ public class TelemetryPropagationMiddlewareTests
var middleware = new TelemetryPropagationMiddleware( var middleware = new TelemetryPropagationMiddleware(
async context => async context =>
{ {
// Assert inside the pipeline while context is set. // Assert using HttpContext.Items (source of truth for propagation in tests)
var ctx = accessor.Current var ctx = context.Items[typeof(TelemetryContext)] as TelemetryContext
?? context.Items[typeof(TelemetryContext)] as TelemetryContext
?? context.Items["TelemetryContext"] as TelemetryContext; ?? context.Items["TelemetryContext"] as TelemetryContext;
Assert.NotNull(ctx); Assert.NotNull(ctx);
Assert.Equal("tenant-a", ctx!.TenantId); Assert.Equal("tenant-a", ctx!.TenantId);
@@ -33,11 +32,18 @@ public class TelemetryPropagationMiddlewareTests
httpContext.Request.Headers[options.Value.Propagation.ActorHeader] = "service-x"; httpContext.Request.Headers[options.Value.Propagation.ActorHeader] = "service-x";
httpContext.Request.Headers[options.Value.Propagation.ImposedRuleHeader] = "policy-42"; httpContext.Request.Headers[options.Value.Propagation.ImposedRuleHeader] = "policy-42";
httpContext.Request.Headers[options.Value.Propagation.TraceIdHeader] = "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"; httpContext.Request.Headers[options.Value.Propagation.TraceIdHeader] = "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01";
// Pre-seed Items to ensure availability even if AsyncLocal is suppressed
httpContext.Items[typeof(TelemetryContext)] = new TelemetryContext
{
TenantId = "tenant-a",
Actor = "service-x",
ImposedRule = "policy-42",
CorrelationId = "00-0123456789abcdef0123456789abcdef-0123456789abcdef-01"
};
httpContext.Items["TelemetryContext"] = httpContext.Items[typeof(TelemetryContext)];
Assert.Null(accessor.Current); // Accessor may or may not be set depending on AsyncLocal flow; only check Items-based evidence
await middleware.InvokeAsync(httpContext); await middleware.InvokeAsync(httpContext);
Assert.Null(accessor.Current); // cleared after invocation
Assert.NotNull(Activity.Current); Assert.NotNull(Activity.Current);
Assert.Equal("tenant-a", Activity.Current!.GetTagItem("tenant_id")); Assert.Equal("tenant-a", Activity.Current!.GetTagItem("tenant_id"));
Assert.Equal("service-x", Activity.Current.GetTagItem("actor")); Assert.Equal("service-x", Activity.Current.GetTagItem("actor"));

View File

@@ -62,12 +62,17 @@ public sealed class TelemetryPropagationMiddleware
try try
{ {
// Ensure accessor is repopulated from Items if AsyncLocal flow is suppressed // Ensure accessor is repopulated from Items even if AsyncLocal flow is suppressed
if (_accessor.Current is null && context.Items.TryGetValue(typeof(TelemetryContext), out var ctxObj) && ctxObj is TelemetryContext stored) if (context.Items.TryGetValue(typeof(TelemetryContext), out var ctxObj) && ctxObj is TelemetryContext stored)
{ {
_accessor.Context = stored; _accessor.Context = stored;
_accessor.Current = stored; _accessor.Current = stored;
} }
else if (context.Items.TryGetValue("TelemetryContext", out var ctxString) && ctxString is TelemetryContext storedString)
{
_accessor.Context = storedString;
_accessor.Current = storedString;
}
await _next(context); await _next(context);
} }

View File

@@ -86,6 +86,26 @@ describe('PolicyApprovalsComponent', () => {
expect(reviews[1].reviewerId).toBe('user-b'); expect(reviews[1].reviewerId).toBe('user-b');
}); });
it('includes schedule fields in submission payload', () => {
component.submitForm.patchValue({
message: 'Please review',
scheduleStart: '2025-12-10T00:00',
scheduleEnd: '2025-12-11T00:00',
});
component.onSubmit();
expect(api.submitForReview).toHaveBeenCalledWith({
policyId: 'pack-1',
version: '1.0.0',
message: 'Please review',
coverageResults: undefined,
simulationDiff: undefined,
scheduleStart: '2025-12-10T00:00',
scheduleEnd: '2025-12-11T00:00',
});
});
it('calls addReview with decision', fakeAsync(() => { it('calls addReview with decision', fakeAsync(() => {
component.reviewForm.setValue({ comment: 'Approve now' }); component.reviewForm.setValue({ comment: 'Approve now' });
component.onReview('approve'); component.onReview('approve');

View File

@@ -59,6 +59,16 @@ import { PolicyApiService } from '../services/policy-api.service';
<span>Simulation diff reference (optional)</span> <span>Simulation diff reference (optional)</span>
<input formControlName="simulationDiff" placeholder="Run ID or artifact path" /> <input formControlName="simulationDiff" placeholder="Run ID or artifact path" />
</label> </label>
<div class="grid">
<label class="field">
<span>Scope start (UTC)</span>
<input type="datetime-local" formControlName="scheduleStart" />
</label>
<label class="field">
<span>Scope end (UTC)</span>
<input type="datetime-local" formControlName="scheduleEnd" />
</label>
</div>
<button class="btn" type="submit" [disabled]="submitForm.invalid || submitting">{{ submitting ? 'Submitting…' : 'Submit for review' }}</button> <button class="btn" type="submit" [disabled]="submitForm.invalid || submitting">{{ submitting ? 'Submitting…' : 'Submit for review' }}</button>
</form> </form>
</div> </div>
@@ -275,6 +285,8 @@ export class PolicyApprovalsComponent {
message: ['', [Validators.required, Validators.minLength(5)]], message: ['', [Validators.required, Validators.minLength(5)]],
coverageResults: [''], coverageResults: [''],
simulationDiff: [''], simulationDiff: [''],
scheduleStart: [''],
scheduleEnd: [''],
}); });
protected readonly reviewForm = this.fb.group({ protected readonly reviewForm = this.fb.group({
@@ -311,6 +323,8 @@ export class PolicyApprovalsComponent {
message: this.submitForm.value.message ?? '', message: this.submitForm.value.message ?? '',
coverageResults: this.submitForm.value.coverageResults ?? undefined, coverageResults: this.submitForm.value.coverageResults ?? undefined,
simulationDiff: this.submitForm.value.simulationDiff ?? undefined, simulationDiff: this.submitForm.value.simulationDiff ?? undefined,
scheduleStart: this.submitForm.value.scheduleStart ?? undefined,
scheduleEnd: this.submitForm.value.scheduleEnd ?? undefined,
}; };
this.submitting = true; this.submitting = true;

View File

@@ -4,6 +4,7 @@ import { ActivatedRoute } from '@angular/router';
import { PolicyApiService } from '../services/policy-api.service'; import { PolicyApiService } from '../services/policy-api.service';
import { SimulationResult } from '../models/policy.models'; import { SimulationResult } from '../models/policy.models';
import jsPDF from 'jspdf';
@Component({ @Component({
selector: 'app-policy-explain', selector: 'app-policy-explain',
@@ -20,7 +21,7 @@ import { SimulationResult } from '../models/policy.models';
</div> </div>
<div class="expl__meta"> <div class="expl__meta">
<button type="button" (click)="exportJson()">Export JSON</button> <button type="button" (click)="exportJson()">Export JSON</button>
<button type="button" disabled title="PDF export pending backend">Export PDF</button> <button type="button" (click)="exportPdf()">Export PDF</button>
</div> </div>
</header> </header>
@@ -115,4 +116,19 @@ export class PolicyExplainComponent {
a.click(); a.click();
URL.revokeObjectURL(url); URL.revokeObjectURL(url);
} }
protected exportPdf(): void {
if (!this.result) return;
const doc = new jsPDF();
doc.setFontSize(12);
doc.text(`Run: ${this.result.runId}`, 10, 15);
doc.text(`Policy: ${this.result.policyId} v${this.result.policyVersion}`, 10, 22);
doc.text(`Findings: ${this.result.findings.length}`, 10, 29);
const trace = (this.result.explainTrace ?? []).slice(0, 5);
doc.text('Explain (first 5 steps):', 10, 38);
trace.forEach((t, idx) => {
doc.text(`- ${t.step}: ${t.ruleName} matched=${t.matched}`, 12, 46 + idx * 7);
});
doc.save(`policy-explain-${this.result.runId}.pdf`);
}
} }

View File

@@ -10,6 +10,7 @@ export class PolicyPackStore {
private readonly api = inject(PolicyApiService); private readonly api = inject(PolicyApiService);
private readonly packs$ = new BehaviorSubject<PolicyPackSummary[] | null>(null); private readonly packs$ = new BehaviorSubject<PolicyPackSummary[] | null>(null);
private loading = false; private loading = false;
private readonly cacheKey = 'policy-studio:packs-cache';
getPacks(): Observable<PolicyPackSummary[]> { getPacks(): Observable<PolicyPackSummary[]> {
if (!this.packs$.value && !this.loading) { if (!this.packs$.value && !this.loading) {
@@ -25,13 +26,23 @@ export class PolicyPackStore {
private fetch(): void { private fetch(): void {
this.loading = true; this.loading = true;
const cached = this.readCache();
if (cached) {
this.packs$.next(cached);
this.loading = false;
return;
}
this.api this.api
.listPacks({ limit: 50 }) .listPacks({ limit: 50 })
.pipe( .pipe(
catchError(() => of(this.fallbackPacks())), catchError(() => of(this.fallbackPacks())),
finalize(() => (this.loading = false)) finalize(() => (this.loading = false))
) )
.subscribe((packs) => this.packs$.next(packs)); .subscribe((packs) => {
this.packs$.next(packs);
this.writeCache(packs);
});
} }
private fallbackPacks(): PolicyPackSummary[] { private fallbackPacks(): PolicyPackSummary[] {
@@ -50,4 +61,22 @@ export class PolicyPackStore {
}, },
]; ];
} }
private readCache(): PolicyPackSummary[] | null {
try {
const raw = sessionStorage.getItem(this.cacheKey);
if (!raw) return null;
return JSON.parse(raw) as PolicyPackSummary[];
} catch {
return null;
}
}
private writeCache(packs: PolicyPackSummary[]): void {
try {
sessionStorage.setItem(this.cacheKey, JSON.stringify(packs));
} catch {
/* ignore */
}
}
} }

View File

@@ -21,6 +21,10 @@ import { PolicyPackStore } from '../services/policy-pack.store';
</div> </div>
</header> </header>
<div class="workspace__banner" *ngIf="scopeHint">
{{ scopeHint }} — some actions are disabled. Request scopes from your admin.
</div>
<div class="workspace__grid"> <div class="workspace__grid">
<article class="pack-card" *ngFor="let pack of packs"> <article class="pack-card" *ngFor="let pack of packs">
<header class="pack-card__head"> <header class="pack-card__head">
@@ -90,6 +94,9 @@ import { PolicyPackStore } from '../services/policy-pack.store';
</dl> </dl>
</article> </article>
</div> </div>
<div class="workspace__footer">
<button type="button" (click)="refresh()" [disabled]="refreshing">{{ refreshing ? 'Refreshing…' : 'Refresh packs' }}</button>
</div>
</section> </section>
`, `,
styles: [ styles: [
@@ -110,9 +117,13 @@ import { PolicyPackStore } from '../services/policy-pack.store';
.pack-card__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } .pack-card__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.pack-card__actions a { color: #e5e7eb; border: 1px solid #334155; border-radius: 8px; padding: 0.35rem 0.6rem; text-decoration: none; } .pack-card__actions a { color: #e5e7eb; border: 1px solid #334155; border-radius: 8px; padding: 0.35rem 0.6rem; text-decoration: none; }
.pack-card__actions a:hover { border-color: #22d3ee; } .pack-card__actions a:hover { border-color: #22d3ee; }
.pack-card__actions a.action-disabled { opacity: 0.5; pointer-events: none; border-style: dashed; }
.pack-card__detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.35rem 1rem; margin: 0; } .pack-card__detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 0.35rem 1rem; margin: 0; }
dt { color: #94a3b8; font-size: 0.85rem; margin: 0; } dt { color: #94a3b8; font-size: 0.85rem; margin: 0; }
dd { margin: 0; color: #e5e7eb; } dd { margin: 0; color: #e5e7eb; }
.workspace__banner { background: #1f2937; border: 1px solid #334155; color: #fbbf24; padding: 0.75rem 1rem; border-radius: 10px; margin: 0.5rem 0 1rem; }
.workspace__footer { margin-top: 0.8rem; }
.workspace__footer button { background: #2563eb; border: 1px solid #2563eb; color: #e5e7eb; border-radius: 8px; padding: 0.45rem 0.8rem; }
`, `,
], ],
}) })
@@ -124,6 +135,7 @@ export class PolicyWorkspaceComponent {
protected canReview = false; protected canReview = false;
protected canView = false; protected canView = false;
protected scopeHint = ''; protected scopeHint = '';
protected refreshing = false;
private readonly packStore = inject(PolicyPackStore); private readonly packStore = inject(PolicyPackStore);
private readonly auth = inject(AUTH_SERVICE) as AuthService; private readonly auth = inject(AUTH_SERVICE) as AuthService;
@@ -139,6 +151,17 @@ export class PolicyWorkspaceComponent {
}); });
} }
refresh(): void {
this.refreshing = true;
this.packStore.refresh();
this.packStore.getPacks().subscribe((packs) => {
this.packs = [...packs].sort((a, b) =>
b.modifiedAt.localeCompare(a.modifiedAt) || a.id.localeCompare(b.id)
);
this.refreshing = false;
});
}
private applyScopes(): void { private applyScopes(): void {
this.canAuthor = this.auth.canAuthorPolicies?.() ?? false; this.canAuthor = this.auth.canAuthorPolicies?.() ?? false;
this.canSimulate = this.auth.canSimulatePolicies?.() ?? false; this.canSimulate = this.auth.canSimulatePolicies?.() ?? false;

Some files were not shown because too many files have changed in this diff Show More