Compare commits

..

2 Commits

Author SHA1 Message Date
StellaOps Bot
48702191be feat(graph-api): Add schema review notes for upcoming Graph API changes
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
feat(sbomservice): Add placeholder for SHA256SUMS in LNM v1 fixtures

docs(devportal): Create README for SDK archives in public directory

build(devportal): Implement offline bundle build script

test(devportal): Add link checker script for validating links in documentation

test(devportal): Create performance check script for dist folder size

test(devportal): Implement accessibility check script using Playwright and Axe

docs(devportal): Add SDK quickstart guide with examples for Node.js, Python, and cURL

feat(excititor): Implement MongoDB storage for airgap import records

test(findings): Add unit tests for export filters hash determinism

feat(findings): Define attestation contracts for ledger web service

feat(graph): Add MongoDB options and service collection extensions for graph indexing

test(graph): Implement integration tests for MongoDB provider and service collection extensions

feat(zastava): Define configuration options for Zastava surface secrets

build(tests): Create script to run Concelier linkset tests with TRX output
2025-11-22 19:22:30 +02:00
StellaOps Bot
ca09400069 chore(docs): normalize reachability sprint references 2025-11-22 16:36:27 +00:00
78 changed files with 4188 additions and 1391 deletions

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>Microsoft.Extensions.Logging.Abstractions</id>
<version>10.0.0-rc.2.25502.107</version>
<authors>Microsoft</authors>
<license type="expression">MIT</license>
<licenseUrl>https://licenses.nuget.org/MIT</licenseUrl>
<icon>Icon.png</icon>
<readme>PACKAGE.md</readme>
<projectUrl>https://dot.net/</projectUrl>
<description>Logging abstractions for Microsoft.Extensions.Logging.
Commonly Used Types:
Microsoft.Extensions.Logging.ILogger
Microsoft.Extensions.Logging.ILoggerFactory
Microsoft.Extensions.Logging.ILogger&lt;TCategoryName&gt;
Microsoft.Extensions.Logging.LogLevel
Microsoft.Extensions.Logging.Logger&lt;T&gt;
Microsoft.Extensions.Logging.LoggerMessage
Microsoft.Extensions.Logging.Abstractions.NullLogger</description>
<releaseNotes>https://go.microsoft.com/fwlink/?LinkID=799421</releaseNotes>
<copyright>© Microsoft Corporation. All rights reserved.</copyright>
<serviceable>true</serviceable>
<repository type="git" url="https://github.com/dotnet/dotnet" commit="89c8f6a112d37d2ea8b77821e56d170a1bccdc5a" />
<dependencies>
<group targetFramework=".NETFramework4.6.2">
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Diagnostics.DiagnosticSource" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Buffers" version="4.6.1" exclude="Build,Analyzers" />
<dependency id="System.Memory" version="4.6.3" exclude="Build,Analyzers" />
</group>
<group targetFramework="net8.0">
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Diagnostics.DiagnosticSource" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
</group>
<group targetFramework="net9.0">
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Diagnostics.DiagnosticSource" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
</group>
<group targetFramework="net10.0">
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETStandard2.0">
<dependency id="Microsoft.Extensions.DependencyInjection.Abstractions" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Diagnostics.DiagnosticSource" version="10.0.0-rc.2.25502.107" exclude="Build,Analyzers" />
<dependency id="System.Buffers" version="4.6.1" exclude="Build,Analyzers" />
<dependency id="System.Memory" version="4.6.3" exclude="Build,Analyzers" />
</group>
</dependencies>
</metadata>
</package>

View File

@@ -33,6 +33,12 @@ paths:
application/x-ndjson:
schema:
$ref: '#/components/schemas/TileEnvelope'
examples:
sample:
summary: Node + cursor tiles
value: |
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:abc","kind":"component","tenant":"acme","attributes":{"purl":"pkg:npm/lodash@4.17.21"}},"cost":{"limit":1000,"remaining":999,"consumed":1}}
{"type":"cursor","seq":1,"data":{"token":"cursor-123","resumeUrl":"https://gateway.local/api/graph/query?cursor=cursor-123"}}
'400': { $ref: '#/components/responses/ValidationError' }
'401': { $ref: '#/components/responses/Unauthorized' }
'429': { $ref: '#/components/responses/BudgetExceeded' }
@@ -58,6 +64,13 @@ paths:
application/x-ndjson:
schema:
$ref: '#/components/schemas/TileEnvelope'
examples:
mixedTiles:
summary: Node + edge + stats tiles
value: |
{"type":"node","seq":0,"data":{"id":"gn:tenant:artifact:sha256:...","tenant":"acme","kind":"artifact","attributes":{"sbom_digest":"sha256:abc"}}}
{"type":"edge","seq":1,"data":{"id":"ge:tenant:CONTAINS:...","sourceId":"gn:tenant:artifact:...","targetId":"gn:tenant:component:...","kind":"CONTAINS"}}
{"type":"stats","seq":2,"data":{"nodesEmitted":1,"edgesEmitted":1,"depthReached":2,"cacheHitRatio":0.8}}
'400': { $ref: '#/components/responses/ValidationError' }
'401': { $ref: '#/components/responses/Unauthorized' }
'429': { $ref: '#/components/responses/BudgetExceeded' }
@@ -83,6 +96,13 @@ paths:
application/x-ndjson:
schema:
$ref: '#/components/schemas/TileEnvelope'
examples:
pathTiles:
summary: Path tiles grouped by hop
value: |
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:src","kind":"component","tenant":"acme"}}
{"type":"edge","seq":1,"data":{"id":"ge:tenant:DEPENDS_ON:1","sourceId":"gn:tenant:component:src","targetId":"gn:tenant:component:dst","kind":"DEPENDS_ON"}}
{"type":"stats","seq":2,"data":{"nodesEmitted":2,"edgesEmitted":1,"depthReached":1}}
'400': { $ref: '#/components/responses/ValidationError' }
'401': { $ref: '#/components/responses/Unauthorized' }
'429': { $ref: '#/components/responses/BudgetExceeded' }
@@ -108,9 +128,47 @@ paths:
application/x-ndjson:
schema:
$ref: '#/components/schemas/TileEnvelope'
examples:
diffTiles:
summary: Added/removed tiles
value: |
{"type":"node","seq":0,"data":{"id":"gn:tenant:component:new","kind":"component","tenant":"acme","attributes":{"purl":"pkg:npm/new@1.0.0"}}}
{"type":"diagnostic","seq":1,"data":{"level":"info","message":"snapshot diff complete"}}
'400': { $ref: '#/components/responses/ValidationError' }
'401': { $ref: '#/components/responses/Unauthorized' }
/graph/export/{jobId}/manifest:
get:
summary: Download deterministic checksum manifest for a completed export job
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/TenantHeader'
- $ref: '#/components/parameters/RequestIdHeader'
- name: jobId
in: path
required: true
schema:
type: string
responses:
'200':
description: Deterministic manifest
content:
application/json:
schema:
type: object
properties:
files:
type: array
items:
type: object
properties:
path: { type: string }
sha256: { type: string }
size: { type: integer }
exportId: { type: string }
'404': { description: Manifest not ready or job missing }
/graph/export:
post:
summary: Request export job for snapshot or query result
@@ -192,12 +250,15 @@ components:
limit:
type: integer
minimum: 1
example: 1000
remaining:
type: integer
minimum: 0
example: 995
consumed:
type: integer
minimum: 0
example: 5
required: [limit, remaining, consumed]
TileEnvelope:
@@ -209,13 +270,68 @@ components:
seq:
type: integer
minimum: 0
example: 0
cost:
$ref: '#/components/schemas/CostBudget'
data:
type: object
description: Payload varies by tile type (node/edge record, stats snapshot, cursor token, or diagnostic info).
description: Payload varies by tile type.
oneOf:
- $ref: '#/components/schemas/NodeTile'
- $ref: '#/components/schemas/EdgeTile'
- $ref: '#/components/schemas/StatsTile'
- $ref: '#/components/schemas/CursorTile'
- $ref: '#/components/schemas/DiagnosticTile'
required: [type, seq]
NodeTile:
type: object
properties:
id: { type: string }
kind: { type: string }
tenant: { type: string }
attributes: { type: object }
overlays:
type: object
description: Optional overlay payloads (policy/vex/advisory) keyed by overlay kind.
required: [id, kind, tenant]
EdgeTile:
type: object
properties:
id: { type: string }
kind: { type: string }
sourceId: { type: string }
targetId: { type: string }
tenant: { type: string }
attributes: { type: object }
overlays:
type: object
required: [id, kind, sourceId, targetId, tenant]
StatsTile:
type: object
properties:
nodesEmitted: { type: integer, minimum: 0 }
edgesEmitted: { type: integer, minimum: 0 }
depthReached: { type: integer, minimum: 0 }
cacheHitRatio: { type: number, minimum: 0, maximum: 1 }
required: [nodesEmitted, edgesEmitted]
CursorTile:
type: object
properties:
token: { type: string }
resumeUrl: { type: string, format: uri }
required: [token]
DiagnosticTile:
type: object
properties:
level: { type: string, enum: [info, warn, error] }
message: { type: string }
details: { type: object }
required: [level, message]
SearchRequest:
type: object
properties:

View File

@@ -1,140 +1,140 @@
# VEX Evidence Playbook (Bench Repo Blueprint)
> **Status:** Draft aligns with the “provable vulnerability decisions” advisory (Nov2025).
> **Owners:** Policy Guild · VEX Lens Guild · CLI Guild · Docs Guild.
This playbook defines the public benchmark repository layout, artifact shapes, verification tooling, and metrics that prove StellaOps VEX decisions are reproducible, portable, and superior to baseline scanners. Treat it as the contract for every guild contributing artifacts to `bench/`.
---
## 1. Repository layout
```
bench/
README.md # repo overview + quickstart
findings/
CVE-YYYY-NNNNN/ # one folder per advisory/product tuple
evidence/
reachability.json # static+runtime call graph for the finding
sbom.cdx.json # CycloneDX slice containing the involved components
decision.openvex.json # OpenVEX statement (status + justification)
decision.dsse.json # DSSE envelope wrapping the OpenVEX payload
rekor.txt # optional Rekor UUID/index/checkpoint
metadata.json # producer info (policy rev, analyzer digests, CAS URIs)
tools/
verify.sh # shell helper: dsse verify + optional rekor verification
verify.py # python verifier (offline) that recomputes digests
compare.py # baseline diff against Trivy/Syft/Grype/Snyk/Xray outputs
replay.sh # reruns reachability graphs via `stella replay`
results/
summary.csv # FP reduction, MTTD, reproducibility metrics
runs/2025-11-10/ # pinned scanner/policy versions + raw outputs
stella/
findings.json
runtime-facts.ndjson
reachability.manifest.json
trivy/
findings.json
...
```
### File contracts
- `reachability.json` is the canonical export from `cas://reachability/graphs/...` with symbol IDs, call edges, runtime hits, analyzer fingerprints, and CAS references.
- `decision.openvex.json` follows OpenVEX v1 with StellaOps-specific `status_notes`, `justification`, `impact_statement`, and `action_statement` text.
- `decision.dsse.json` is the DSSE envelope returned by Signer (see §3). Always include the PEM cert chain (keyless) or KMS key id.
- `rekor.txt` captures `{uuid, logIndex, checkpoint}` from Attestor when the decision is logged to Rekor.
- `metadata.json` binds the DSSE payload back to internal evidence: `{policy_revision, reachability_graph_sha256, runtime_trace_sha256, evidence_cas_uri[], analyzer_versions[], createdBy, createdAt}`.
---
## 2. Evidence production flow
1. **Scanner Worker**
- Generate `reachability.json` + `sbom.cdx.json` per prioritized CVE.
- Store artifacts under CAS and surface URIs via `ReachabilityReplayWriter`.
2. **Policy Engine / VEXer**
- Evaluate reachability states + policy lattice to produce an OpenVEX statement.
- Persist `decision.openvex.json` and forward it to Signer.
3. **Signer & Attestor**
- Sign the OpenVEX payload via DSSE (`payloadType: application/vnd.in-toto+json`) and return `decision.dsse.json`.
- Optionally call Attestor to log the DSSE bundle to Rekor; write `{uuid, logIndex, checkpoint}` to `rekor.txt`.
4. **Bench harness**
- Collect SBOM slice, reachability proof, OpenVEX, DSSE, Rekor metadata, and companion metrics into `bench/findings/CVE-...`.
- Record tool versions + CAS digests under `metadata.json`.
All steps must be deterministic: repeated scans with the same inputs produce identical artifacts and digests.
---
## 3. Signing & transparency requirements
| Artifact | Producer | Format | Notes |
|-------------------------|---------------|----------------------------------------|-------|
| Reachability evidence | Scanner | Canonical JSON (sorted keys) | CAS URI recorded in metadata. |
| SBOM slice | Scanner | CycloneDX 1.6 JSON | Keep only components relevant to the finding. |
| OpenVEX decision | Policy/VEXer | OpenVEX v1 | One statement per `(CVE, product)` tuple. |
| DSSE bundle | Signer | DSSE envelope over OpenVEX payload | Include Fulcio cert or KMS key id. |
| Rekor record (optional) | Attestor | Rekor UUID/index/checkpoint | Store alongside DSSE for offline verification. |
Signer must expose a predicate alias `stella.ops/vexDecision@v1` (see Sprint task `SIGN-VEX-401-018`). Payload = OpenVEX JSON. Rekor logging reuses the existing Attestor `/rekor/entries` pipeline.
---
## 4. Verification tooling
The repo ships two verifiers:
1. `tools/verify.sh` (bash) — wraps `cosign verify-attestation`/`in-toto verify`, Rekor inclusion checks (`rekor-cli logproof`), and digest comparison.
2. `tools/verify.py` — pure-Python offline verifier for air-gapped environments:
- Validates DSSE signature using the embedded Fulcio cert or configured root.
- Recomputes `sha256` over `reachability.json`, `sbom.cdx.json`, and `decision.openvex.json` to ensure the DSSE payload matches.
- Optionally replays reachability by invoking `stella replay --manifest ... --finding CVE-...`.
CLI addition (`stella decision verify`) should shell out to these helpers when `--from bench` is provided.
---
## 5. Metrics & comparison harness
`tools/compare.py` ingests raw outputs from StellaOps and baseline scanners (Trivy, Syft, Grype, Snyk, Xray) stored under `results/runs/<date>/<scanner>/findings.json`. For each target:
- **False-positive reduction (FPR)** = `1 - (# of findings confirmed true positives / # of baseline findings)`.
- **Mean time to decision (MTTD)** = average wall-clock time between scan start and DSSE-signed OpenVEX emission.
- **Reproducibility score** = `1` if re-running reachability produces identical digests for all artifacts, else `0`; aggregated per run.
`results/summary.csv` columns:
```
target,cve,baseline_scanner,baseline_hits,stella_hits,fp_reduction,mttd_seconds,reproducible,rekor_uuid
```
Automate collection via `Makefile` or `bench/run.sh` pipeline (task `BENCH-AUTO-401-019`).
---
## 6. Publication & README checklist
`bench/README.md` must include:
- High-level workflow diagram (scan → reachability → OpenVEX → DSSE → Rekor → bench).
- Prerequisites (`cosign`, `rekor-cli`, `stella` CLI).
- Quickstart commands:
```bash
./tools/verify.sh CVE-2023-12345 pkg:purl/example@1.2.3
./tools/compare.py --target sample/nginx --baseline trivy --run 2025-11-10
```
- How to recreate a finding: `stella replay --manifest results/runs/.../replay.yaml --finding CVE-...`.
- Contribution guide (where to place new findings, how to update metrics, required metadata).
---
## 7. Implementation tasks (see Sprint 401+)
- `POLICY-VEX-401-010` — emit OpenVEX per finding and publish to bench repo.
- `SIGN-VEX-401-018` — add DSSE predicate + Rekor logging for decision payloads.
- `CLI-VEX-401-011` — new `stella decision` verbs (`export`, `verify`, `compare`).
- `BENCH-AUTO-401-019` — automation to populate `bench/findings/**`, run baseline scanners, and update `results/summary.csv`.
- `DOCS-VEX-401-012` — maintain this playbook + README templates, document verification workflow.
# VEX Evidence Playbook (Bench Repo Blueprint)
> **Status:** Draft aligns with the “provable vulnerability decisions” advisory (Nov2025).
> **Owners:** Policy Guild · VEX Lens Guild · CLI Guild · Docs Guild.
This playbook defines the public benchmark repository layout, artifact shapes, verification tooling, and metrics that prove StellaOps VEX decisions are reproducible, portable, and superior to baseline scanners. Treat it as the contract for every guild contributing artifacts to `bench/`.
---
## 1. Repository layout
```
bench/
README.md # repo overview + quickstart
findings/
CVE-YYYY-NNNNN/ # one folder per advisory/product tuple
evidence/
reachability.json # static+runtime call graph for the finding
sbom.cdx.json # CycloneDX slice containing the involved components
decision.openvex.json # OpenVEX statement (status + justification)
decision.dsse.json # DSSE envelope wrapping the OpenVEX payload
rekor.txt # optional Rekor UUID/index/checkpoint
metadata.json # producer info (policy rev, analyzer digests, CAS URIs)
tools/
verify.sh # shell helper: dsse verify + optional rekor verification
verify.py # python verifier (offline) that recomputes digests
compare.py # baseline diff against Trivy/Syft/Grype/Snyk/Xray outputs
replay.sh # reruns reachability graphs via `stella replay`
results/
summary.csv # FP reduction, MTTD, reproducibility metrics
runs/2025-11-10/ # pinned scanner/policy versions + raw outputs
stella/
findings.json
runtime-facts.ndjson
reachability.manifest.json
trivy/
findings.json
...
```
### File contracts
- `reachability.json` is the canonical export from `cas://reachability/graphs/...` with symbol IDs, call edges, runtime hits, analyzer fingerprints, and CAS references.
- `decision.openvex.json` follows OpenVEX v1 with StellaOps-specific `status_notes`, `justification`, `impact_statement`, and `action_statement` text.
- `decision.dsse.json` is the DSSE envelope returned by Signer (see §3). Always include the PEM cert chain (keyless) or KMS key id.
- `rekor.txt` captures `{uuid, logIndex, checkpoint}` from Attestor when the decision is logged to Rekor.
- `metadata.json` binds the DSSE payload back to internal evidence: `{policy_revision, reachability_graph_sha256, runtime_trace_sha256, evidence_cas_uri[], analyzer_versions[], createdBy, createdAt}`.
---
## 2. Evidence production flow
1. **Scanner Worker**
- Generate `reachability.json` + `sbom.cdx.json` per prioritized CVE.
- Store artifacts under CAS and surface URIs via `ReachabilityReplayWriter`.
2. **Policy Engine / VEXer**
- Evaluate reachability states + policy lattice to produce an OpenVEX statement.
- Persist `decision.openvex.json` and forward it to Signer.
3. **Signer & Attestor**
- Sign the OpenVEX payload via DSSE (`payloadType: application/vnd.in-toto+json`) and return `decision.dsse.json`.
- Optionally call Attestor to log the DSSE bundle to Rekor; write `{uuid, logIndex, checkpoint}` to `rekor.txt`.
4. **Bench harness**
- Collect SBOM slice, reachability proof, OpenVEX, DSSE, Rekor metadata, and companion metrics into `bench/findings/CVE-...`.
- Record tool versions + CAS digests under `metadata.json`.
All steps must be deterministic: repeated scans with the same inputs produce identical artifacts and digests.
---
## 3. Signing & transparency requirements
| Artifact | Producer | Format | Notes |
|-------------------------|---------------|----------------------------------------|-------|
| Reachability evidence | Scanner | Canonical JSON (sorted keys) | CAS URI recorded in metadata. |
| SBOM slice | Scanner | CycloneDX 1.6 JSON | Keep only components relevant to the finding. |
| OpenVEX decision | Policy/VEXer | OpenVEX v1 | One statement per `(CVE, product)` tuple. |
| DSSE bundle | Signer | DSSE envelope over OpenVEX payload | Include Fulcio cert or KMS key id. |
| Rekor record (optional) | Attestor | Rekor UUID/index/checkpoint | Store alongside DSSE for offline verification. |
Signer must expose a predicate alias `stella.ops/vexDecision@v1` (see Sprint task `SIGN-VEX-401-018`). Payload = OpenVEX JSON. Rekor logging reuses the existing Attestor `/rekor/entries` pipeline.
---
## 4. Verification tooling
The repo ships two verifiers:
1. `tools/verify.sh` (bash) — wraps `cosign verify-attestation`/`in-toto verify`, Rekor inclusion checks (`rekor-cli logproof`), and digest comparison.
2. `tools/verify.py` — pure-Python offline verifier for air-gapped environments:
- Validates DSSE signature using the embedded Fulcio cert or configured root.
- Recomputes `sha256` over `reachability.json`, `sbom.cdx.json`, and `decision.openvex.json` to ensure the DSSE payload matches.
- Optionally replays reachability by invoking `stella replay --manifest ... --finding CVE-...`.
CLI addition (`stella decision verify`) should shell out to these helpers when `--from bench` is provided.
---
## 5. Metrics & comparison harness
`tools/compare.py` ingests raw outputs from StellaOps and baseline scanners (Trivy, Syft, Grype, Snyk, Xray) stored under `results/runs/<date>/<scanner>/findings.json`. For each target:
- **False-positive reduction (FPR)** = `1 - (# of findings confirmed true positives / # of baseline findings)`.
- **Mean time to decision (MTTD)** = average wall-clock time between scan start and DSSE-signed OpenVEX emission.
- **Reproducibility score** = `1` if re-running reachability produces identical digests for all artifacts, else `0`; aggregated per run.
`results/summary.csv` columns:
```
target,cve,baseline_scanner,baseline_hits,stella_hits,fp_reduction,mttd_seconds,reproducible,rekor_uuid
```
Automate collection via `Makefile` or `bench/run.sh` pipeline (task `BENCH-AUTO-401-019`).
---
## 6. Publication & README checklist
`bench/README.md` must include:
- High-level workflow diagram (scan → reachability → OpenVEX → DSSE → Rekor → bench).
- Prerequisites (`cosign`, `rekor-cli`, `stella` CLI).
- Quickstart commands:
```bash
./tools/verify.sh CVE-2023-12345 pkg:purl/example@1.2.3
./tools/compare.py --target sample/nginx --baseline trivy --run 2025-11-10
```
- How to recreate a finding: `stella replay --manifest results/runs/.../replay.yaml --finding CVE-...`.
- Contribution guide (where to place new findings, how to update metrics, required metadata).
---
## 7. Implementation tasks (see Sprint 401+)
- `POLICY-VEX-401-010` — emit OpenVEX per finding and publish to bench repo.
- `SIGN-VEX-401-018` — add DSSE predicate + Rekor logging for decision payloads.
- `CLI-VEX-401-011` — new `stella decision` verbs (`export`, `verify`, `compare`).
- `BENCH-AUTO-401-019` — automation to populate `bench/findings/**`, run baseline scanners, and update `results/summary.csv`.
- `DOCS-VEX-401-012` — maintain this playbook + README templates, document verification workflow.
Update `docs/implplan/SPRINT_0401_0001_0001_reachability_evidence_chain.md` whenever these tasks move state.

View File

@@ -68,9 +68,14 @@
| 2025-11-22 | Restore attempt with `NUGET_PACKAGES=local-nugets` + `--source local-nugets --ignore-failed-sources` failed (NuGet requires absolute NUGET_PACKAGES path); no packages fetched. | Implementer |
| 2025-11-22 | Retried restore with absolute `NUGET_PACKAGES=$(pwd)/local-nugets`; still hanging and cancelled at ~10s (no packages downloaded). Tests remain blocked pending CI/warm cache. | Implementer |
| 2025-11-22 | Restore attempt with absolute cache + nuget.org fallback (`NUGET_PACKAGES=/mnt/e/dev/git.stella-ops.org/local-nugets --source local-nugets --source https://api.nuget.org/v3/index.json`) still stalled/cancelled after ~10s; no packages pulled. | Implementer |
| 2025-11-22 | Solution-filter restore (`concelier-webservice.slnf`, nuget.org only, absolute cache, minimal verbosity) stalled ~30s with no packages; blocked until CI runner with seeded cache is available. | Implementer |
| 2025-11-22 | Tried timeout-limited restore via `dotnet restore concelier-webservice.slnf -v minimal`; cancelled around 25s (`NuGet.targets` reported "Restore canceled!"). Still no packages fetched—attestation test remains pending a CI/warmed cache runner. | Implementer |
| 2025-11-22 | Normalized `tools/linksets-ci.sh` line endings, removed `--no-build`, and forced offline restore against `local-nugets`; restore still hangs >90s even with offline cache, run terminated. BUILD-TOOLING-110-001 remains BLOCKED pending runner with usable restore cache. | Implementer |
| 2025-11-22 | Tried seeding `local-nugets` via `dotnet restore --packages local-nugets` (online allowed); restore spinner stalled ~130s and was cancelled; NuGet targets reported “Restore canceled!”. No TRX produced; BUILD-TOOLING-110-001 still BLOCKED—needs CI runner with warm cache or diagnostic restore to pinpoint stuck feed/package. | Implementer |
| 2025-11-22 | Retried restore with dedicated cache `NUGET_PACKAGES=.nuget-cache`, sources `local-nugets` + nuget.org, `--disable-parallel --ignore-failed-sources`; spinner ran ~10s with no progress, cancelled. Still no TRX; BUILD-TOOLING-110-001 remains BLOCKED pending CI runner or verbose restore on cached agent. | Implementer |
| 2025-11-22 | Another restore attempt with `NUGET_PACKAGES=.nuget-cache` and both sources enabled ran ~19s then was cancelled (`NuGet.targets` reported "Restore canceled!"); no packages downloaded, no TRX. BUILD-TOOLING-110-001 remains BLOCKED; next step is CI runner with warm cache or `-v diag` capture to identify the stuck feed/package. | Implementer |
| 2025-11-22 | Captured 20s diagnostic restore log at `out/restore-log/linksets-restore-2025-11-22.log` (no HTTP requests observed before timeout). Restore still stalls pre-fetch; suggests resolver/startup hang. BUILD-TOOLING-110-001 remains BLOCKED pending CI runner with warm cache or longer `-v diag` on capable agent. | Implementer |
| 2025-11-22 | Ran 60s diag restore with `DOTNET_SKIP_WORKLOAD_INVENTORY=1`, `--disable-parallel`; log at `out/restore-log/linksets-restore-2025-11-22-60s.log` shows no outbound HTTP before timeout (stall occurs during MSBuild evaluation). Still BLOCKED; needs CI agent with warm cache or deeper MSBuild tracing. | Implementer |
| 2025-11-22 | Documented Concelier advisory attestation endpoint parameters and safety rules (`docs/modules/concelier/attestation.md`); linked from module architecture. | Implementer |
| 2025-11-22 | Published Excititor air-gap + connector trust prep (`docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`), defining import envelope, error catalog, timeline hooks, and signer validation; marked EXCITITOR-AIRGAP-56/57/58 · CONN-TRUST-01-001 DONE. | Implementer |
| 2025-11-20 | Completed PREP-FEEDCONN-ICSCISA-02-012-KISA-02-008-FEED: published remediation schedule + hashes at `docs/modules/concelier/prep/2025-11-20-feeds-icscisa-kisa-prep.md`; status set to DONE. | Implementer |

View File

@@ -52,13 +52,15 @@
| 2025-11-22 | PREP artefacts validated; moved CONCELIER-GRAPH-21-002 and CONCELIER-LNM-21-002 to TODO (unblocked). | Project Mgmt |
| 2025-11-22 | Implemented advisory.observation.updated@1 outbox + transport pipeline (Mongo outbox + NATS optional); marked CONCELIER-GRAPH-21-002 DONE. | Implementer |
| 2025-11-22 | Started CONCELIER-LNM-21-002 implementation using frozen LNM v1 schema and correlation rules; status → DOING. Conflict emission (21-003) will follow once 21-002 tests pass. | Concelier Core |
| 2025-11-22 | Added LinksetCorrelation helper + updated aggregation to emit confidence/conflicts per LNM-21-002; unit tests added. Targeted `dotnet test ...AdvisoryObservationAggregationTests` failed locally (`invalid test source` vstest issue); requires CI/warmed runner. | Concelier Core |
| 2025-11-22 | Added LinksetCorrelation helper + updated aggregation to emit confidence/conflicts per LNM-21-002; unit tests added. Targeted `dotnet test ...AdvisoryObservationAggregationTests` still fails locally (`invalid test source` vstest issue); needs CI/warmed runner. | Concelier Core |
| 2025-11-22 | Added conflict sourceIds propagation to storage documents and mapping; updated storage tests accordingly. `dotnet test ...Concelier.Storage.Mongo.Tests` still fails locally with same vstest argument issue; needs CI runner. | Concelier Core |
| 2025-11-22 | Tried `dotnet build src/Concelier/__Libraries/StellaOps.Concelier.Core/StellaOps.Concelier.Core.csproj`; build appears to hang after restore on local harness—no errors emitted; will defer to CI runner to avoid churn. | Concelier Core |
| 2025-11-22 | Local `dotnet build` for Storage.Mongo also hangs post-restore; CI/clean runner required to validate LNM-21-002 changes. | Concelier Core |
| 2025-11-22 | Added `tools/run-concelier-linkset-tests.sh` to run targeted Core + Storage linkset tests with TRX output; pending CI execution to bypass local vstest harness issues. | Concelier Core |
| 2025-11-22 | Fixed nullable handling in `LinksetCorrelation` purl aggregation; built Concelier dependencies and ran `AdvisoryObservationTransportWorkerTests` (pass) on warmed cache. | Implementer |
| 2025-11-22 | Marked CONCELIER-LNM-21-002 DONE: correlation now emits confidence/conflicts deterministically; transport worker test green after nullable fixes and immutable summaries. | Implementer |
| 2025-11-22 | Implemented LNM-21-003: severity/CVSS disagreements now produce structured conflicts (reason codes `severity-mismatch`, `cvss-mismatch`); added regression test. | Implementer |
| 2025-11-22 | Tried `dotnet test ...AdvisoryObservationAggregationTests --no-build --filter` on local harness; vstest still returns “invalid test source”. Needs CI/warmed runner. | Implementer |
| 2025-11-20 | Started PREP-CONCELIER-GRAPH-21-002 and PREP-CONCELIER-LNM-21-002 (statuses → DOING) after confirming no other owner activity. | Planning |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-17 | Started CONCELIER-GRAPH-21-001: added raw linkset scopes + relationships (provenance) through contracts, ingest mapper, storage mapping, and sanitization; new Mongo mapping test added. | Implementer |

View File

@@ -34,10 +34,10 @@
| P7 | PREP-CONCELIER-OBS-53-001-DEPENDS-ON-52-001-B | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Evidence Locker Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Evidence bundle/timeline linkage requirements documented; unblock evidence locker integration. |
| P8 | PREP-CONCELIER-OBS-54-001-DEPENDS-ON-OBS-TIME | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · Provenance Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Attestation timeline enrichment + DSSE envelope fields recorded in prep note. |
| P9 | PREP-CONCELIER-OBS-55-001-DEPENDS-ON-54-001-I | DONE (2025-11-22) | Due 2025-11-21 · Accountable: Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Concelier Core Guild · DevOps Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Incident-mode hooks and sealed-mode redaction guidance captured; see prep note. |
| 10 | CONCELIER-ORCH-32-001 | DOING (2025-11-22) | Prep completed; implement registry metadata per `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Register every advisory connector with orchestrator (metadata, auth scopes, rate policies) for transparent, reproducible scheduling. |
| 11 | CONCELIER-ORCH-32-002 | DOING (2025-11-22) | Prep completed; adopt heartbeat/command envelopes from `docs/modules/concelier/prep/2025-11-20-orchestrator-registry-prep.md`. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
| 12 | CONCELIER-ORCH-33-001 | DOING (2025-11-22) | Prep completed; implement pause/throttle controls per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
| 13 | CONCELIER-ORCH-34-001 | DOING (2025-11-22) | Prep completed; implement backfill manifests per orchestrator prep note. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
| 10 | CONCELIER-ORCH-32-001 | BLOCKED (2025-11-22) | Build/restore failures on local runner (missing packages, nullable warnings); awaiting CI/clean runner to validate registry wiring. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Register every advisory connector with orchestrator (metadata, auth scopes, rate policies) for transparent, reproducible scheduling. |
| 11 | CONCELIER-ORCH-32-002 | BLOCKED (2025-11-22) | Blocked on 32-001 build validation; needs CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Adopt orchestrator worker SDK in ingestion loops; emit heartbeats/progress/artifact hashes for deterministic replays. |
| 12 | CONCELIER-ORCH-33-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Honor orchestrator pause/throttle/retry controls with structured errors and persisted checkpoints. |
| 13 | CONCELIER-ORCH-34-001 | BLOCKED (2025-11-22) | Blocked on 32-001/002 build validation; needs CI runner. | Concelier Core Guild (`src/Concelier/__Libraries/StellaOps.Concelier.Core`) | Execute orchestrator-driven backfills reusing artifact hashes/signatures, logging provenance, and pushing run metadata to ledger. |
| 14 | CONCELIER-POLICY-20-001 | BLOCKED (2025-11-22) | OpenAPI source/spec missing in repo; needs canonical Concelier OAS location before exposure. | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Provide batch advisory lookup APIs for Policy Engine (purl/advisory filters, tenant scopes, explain metadata) so policy joins raw evidence without inferred outcomes. |
## Execution Log
@@ -66,6 +66,8 @@
| 2025-11-22 | WebService build attempt (`dotnet build ...WebService.csproj --no-restore`) failed on pre-existing nullability errors in `LinksetCorrelation.cs`; no new errors from orchestrator endpoints. | Concelier Implementer |
| 2025-11-22 | Reworked `LinksetCorrelation` nullability to unblock build; lingering CS8620 persists after clean rebuild—likely upstream nullable config; needs follow-up. | Concelier Implementer |
| 2025-11-22 | Package cache cleaned; `dotnet build ...WebService.csproj --no-restore` now fails on missing local packages (Polly, IdentityModel, etc.); restore from `local-nugets/` required to re-run compile. | Concelier Implementer |
| 2025-11-22 | Marked ORCH-32/33/34 BLOCKED pending CI/clean runner build + restore (local runner stuck on missing packages/nullability). | Concelier Core |
| 2025-11-22 | Retried `dotnet restore concelier-webservice.slnf -v minimal` with timeout guard; cancelled at ~25s with `NuGet.targets` reporting "Restore canceled!". No packages downloaded; ORCH-32/33/34 remain blocked until CI/warm cache is available. | Concelier Implementer |
## Decisions & Risks
- Link-Not-Merge and OpenAPI alignment must precede SDK/examples; otherwise downstream clients will drift from canonical facts.
@@ -80,6 +82,7 @@
- Orchestrator registry/command/heartbeat storage now exists with TTL-backed command expiry; WebService/worker wiring still pending—ensure API handlers and SDK align with stored shapes before marking ORCH-32/33/34 DONE.
- WebService `/internal/orch/*` endpoints now land registry upserts, heartbeats, and commands into Mongo store; worker consumption and orchestrator authentication scopes still to be validated before closing tasks.
- Build remains blocked by CS8620 nullable mismatch in `LinksetCorrelation.cs` (linkset aggregation); patch applied but nullability config appears to treat warning as error—needs follow-up to clear WebService build.
- ORCH-32/33/34 implementation blocked locally by missing package restore/nullability errors; CI or clean runner required to validate before proceeding with worker SDK wiring.
## Next Checkpoints
- Schedule OpenAPI/SDK review once CONCELIER-OAS-61-001 draft ready (date TBD, gated on Sprint 0113 outputs).

View File

@@ -21,21 +21,21 @@
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| P1 | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | DONE (2025-11-20) | Prep artefact at `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`; awaits inputs from WEB-AIRGAP-56-002 and WEB-OAS-61-002. | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Depends on 56-002. <br><br> Document artefact/deliverable for CONCELIER-WEB-AIRGAP-57-001 and publish location so downstream tasks can proceed. Prep artefact: `docs/modules/concelier/prep/2025-11-20-web-airgap-57-001-prep.md`. |
| 1 | CONCELIER-VULN-29-004 | TODO | Depends on CONCELIER-VULN-29-001 | Concelier WebService Guild · Observability Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Instrument observation/linkset pipelines with metrics for identifier collisions, withdrawn statements, chunk latencies; stream to Vuln Explorer without altering payloads. |
| 2 | CONCELIER-WEB-AIRGAP-56-001 | TODO | Start of AirGap chain | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Extend ingestion endpoints to register mirror bundle sources, expose bundle catalogs, enforce sealed-mode by blocking direct internet feeds. |
| 3 | CONCELIER-WEB-AIRGAP-56-002 | TODO | Depends on 56-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Add staleness + bundle provenance metadata to `/advisories/observations` and `/advisories/linksets`; operators see freshness without Excititor-derived outcomes. |
| 4 | CONCELIER-WEB-AIRGAP-57-001 | TODO | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Map sealed-mode violations to `AIRGAP_EGRESS_BLOCKED` payloads with remediation guidance; keep advisory content untouched. |
| 5 | CONCELIER-WEB-AIRGAP-58-001 | TODO | Depends on 57-001 | Concelier WebService Guild · AirGap Importer Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit timeline events for bundle imports (bundle ID, scope, actor) to capture every evidence change. |
| 1 | CONCELIER-VULN-29-004 | BLOCKED | Depends on CONCELIER-VULN-29-001 | Concelier WebService Guild · Observability Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Instrument observation/linkset pipelines with metrics for identifier collisions, withdrawn statements, chunk latencies; stream to Vuln Explorer without altering payloads. |
| 2 | CONCELIER-WEB-AIRGAP-56-001 | BLOCKED | Start of AirGap chain | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Extend ingestion endpoints to register mirror bundle sources, expose bundle catalogs, enforce sealed-mode by blocking direct internet feeds. |
| 3 | CONCELIER-WEB-AIRGAP-56-002 | BLOCKED | Depends on 56-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Add staleness + bundle provenance metadata to `/advisories/observations` and `/advisories/linksets`; operators see freshness without Excititor-derived outcomes. |
| 4 | CONCELIER-WEB-AIRGAP-57-001 | BLOCKED | PREP-CONCELIER-WEB-AIRGAP-57-001-DEPENDS-ON-5 | Concelier WebService Guild · AirGap Policy Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Map sealed-mode violations to `AIRGAP_EGRESS_BLOCKED` payloads with remediation guidance; keep advisory content untouched. |
| 5 | CONCELIER-WEB-AIRGAP-58-001 | BLOCKED | Depends on 57-001 | Concelier WebService Guild · AirGap Importer Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit timeline events for bundle imports (bundle ID, scope, actor) to capture every evidence change. |
| 6 | CONCELIER-WEB-AOC-19-003 | TODO | Depends on WEB-AOC-19-002 | QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Unit tests for schema validators, forbidden-field guards (`ERR_AOC_001/2/6/7`), supersedes chains to keep ingestion append-only. |
| 7 | CONCELIER-WEB-AOC-19-004 | TODO | Depends on 19-003 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Integration tests ingesting large batches (cold/warm) verifying reproducible linksets; record metrics/fixtures for Offline Kit rehearsals. |
| 8 | CONCELIER-WEB-AOC-19-005 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Fix `/advisories/{key}/chunks` test data so pre-seeded raw docs resolve; stop "Unable to locate advisory_raw documents" during tests. |
| 9 | CONCELIER-WEB-AOC-19-006 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Align default auth/tenant configs with fixtures so allowlisted tenants ingest before forbidden ones are rejected; close gap in `AdvisoryIngestEndpoint_RejectsTenantOutsideAllowlist`. |
| 10 | CONCELIER-WEB-AOC-19-007 | TODO (2025-11-08) | Depends on WEB-AOC-19-002 | Concelier WebService Guild · QA Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Ensure AOC verify emits `ERR_AOC_001` (not `_004`); maintain mapper/guard parity with regression tests. |
| 11 | CONCELIER-WEB-OAS-61-002 | TODO | Prereq for examples/deprecation | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Migrate APIs to standardized error envelope; update controllers/tests accordingly. |
| 12 | CONCELIER-WEB-OAS-62-001 | TODO | Depends on 61-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Publish curated examples for observations/linksets/conflicts; wire into developer portal. |
| 13 | CONCELIER-WEB-OAS-63-001 | TODO | Depends on 62-001 | Concelier WebService Guild · API Governance Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. |
| 14 | CONCELIER-WEB-OBS-51-001 | TODO | Depends on CONCELIER-WEB-OBS-50-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | `/obs/concelier/health` surfaces for ingest health, queue depth, SLO status for Console widgets. |
| 15 | CONCELIER-WEB-OBS-52-001 | TODO | Depends on 51-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, audit logging for live evidence monitoring. |
| 11 | CONCELIER-WEB-OAS-61-002 | BLOCKED | Prereq for examples/deprecation | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Migrate APIs to standardized error envelope; update controllers/tests accordingly. |
| 12 | CONCELIER-WEB-OAS-62-001 | BLOCKED | Depends on 61-002 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Publish curated examples for observations/linksets/conflicts; wire into developer portal. |
| 13 | CONCELIER-WEB-OAS-63-001 | BLOCKED | Depends on 62-001 | Concelier WebService Guild · API Governance Guild (`src/Concelier/StellaOps.Concelier.WebService`) | Emit deprecation headers + notifications for retiring endpoints, steering clients toward Link-Not-Merge APIs. |
| 14 | CONCELIER-WEB-OBS-51-001 | BLOCKED | Depends on CONCELIER-WEB-OBS-50-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | `/obs/concelier/health` surfaces for ingest health, queue depth, SLO status for Console widgets. |
| 15 | CONCELIER-WEB-OBS-52-001 | BLOCKED | Depends on 51-001 | Concelier WebService Guild (`src/Concelier/StellaOps.Concelier.WebService`) | SSE stream `/obs/concelier/timeline` with paging tokens, guardrails, audit logging for live evidence monitoring. |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -45,6 +45,7 @@
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-08 | Archived completed/historic work to `docs/implplan/archived/tasks.md`. | Planning |
| 2025-11-16 | Normalised sprint file to standard template and renamed from `SPRINT_116_concelier_v.md` to `SPRINT_0116_0001_0005_concelier_v.md`; no semantic changes. | Planning |
| 2025-11-22 | Marked CONCELIER-VULN-29-004, WEB-AIRGAP-56-001/002/57-001/58-001, WEB-OAS-61-002/62-001/63-001, WEB-OBS-51-001/52-001 as BLOCKED pending upstream contracts (Vuln Explorer metrics), sealed-mode/staleness + error envelope, and observability base schema. | Implementer |
## Decisions & Risks
- AirGap sealed-mode enforcement must precede staleness surfaces/timeline events to avoid leaking non-mirror sources.

View File

@@ -35,7 +35,7 @@
| 9 | EXCITITOR-ATTEST-73-001 | DONE (2025-11-17) | Implemented payload spec and storage. | Excititor Core · Attestation Payloads Guild | Emit attestation payloads capturing supplier identity, justification summary, and scope metadata for trust chaining. |
| 10 | EXCITITOR-ATTEST-73-002 | DONE (2025-11-17) | Implemented linkage API. | Excititor Core Guild | Provide APIs linking attestation IDs back to observation/linkset/product tuples for provenance citations without derived verdicts. |
| 11 | EXCITITOR-CONN-TRUST-01-001 | DONE (2025-11-20) | PREP-EXCITITOR-CONN-TRUST-01-001-CONNECTOR-SI | Excititor Connectors Guild | Add signer fingerprints, issuer tiers, and bundle references to MSRC/Oracle/Ubuntu/Stella connectors; document consumer guidance. |
| 12 | EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | Mirror bundle schema from Export Center; fix `VexLinksetObservationRefCore` reference before build green. | Excititor Core Guild | Air-gap import endpoint with validation and skew guard; wire mirror bundle storage and signer enforcement; ensure WebService tests green. |
| 12 | EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | Mirror bundle schema from Export Center; signer enforcement pending. | Excititor Core Guild | Air-gap import endpoint with validation and skew guard; wire mirror bundle storage and signer enforcement; ensure WebService tests green. |
| 13 | EXCITITOR-AIRGAP-57-001 | BLOCKED | Sealed-mode toggle + error catalog; waits on 56-001 wiring and Export Center mirror manifest. | Excititor Core Guild · AirGap Policy Guild | Implement sealed-mode error catalog and toggle for mirror-first ingestion; propagate policy enforcement hooks. |
| 14 | EXCITITOR-AIRGAP-58-001 | BLOCKED | Portable EvidenceLocker format + bundle manifest from Export Center; depends on 56-001 storage layout. | Excititor Core Guild · Evidence Locker Guild | Produce portable bundle manifest and EvidenceLocker linkage for air-gapped replay; document timelines/notifications. |
@@ -79,9 +79,12 @@
| 2025-11-22 | Completed air-gap and attestation rehearsal PREP docs (`docs/modules/excititor/prep/2025-11-22-airgap-56-58-prep.md`, `docs/modules/excititor/prep/2025-11-22-attestation-rehearsal-prep.md`); set P1P3 and P5 to DONE. | Project Mgmt |
| 2025-11-22 | PREP cleared; moved EXCITITOR-AIRGAP-56-001/57-001/58-001 to TODO. | Project Mgmt |
| 2025-11-22 | Started EXCITITOR-AIRGAP-56-001: added air-gap import endpoint skeleton with validation and skew guard; awaiting mirror bundle storage wiring and signer enforcement. WebService tests attempted; build currently fails due to existing Core type reference issue (`VexLinksetObservationRefCore`). | Implementer |
| 2025-11-22 | EXCITITOR-AIRGAP-56-001 progressing: core reference fixed, air-gap import validator + endpoint stubbed, targeted WebService tests passing; storage + signer enforcement still pending. | Implementer |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Normalized sprint sections to standard template; added AirGap 56/57/58 tasks and refreshed Action Tracker; no scope changes. | Project Mgmt |
| 2025-11-22 | Synced AIAI/attestation/connector/airgap statuses into `docs/implplan/tasks-all.md`; deduped duplicate rows. | Project Mgmt |
| 2025-11-22 | Marked EXCITITOR-AIRGAP-57-001/58-001 BLOCKED pending Export Center mirror manifest and portable format; mirrored status into tasks-all tracker. | Project Mgmt |
| 2025-11-22 | Air-gap import endpoint now persists import metadata to Mongo via `IAirgapImportStore`; response stays 202 Accepted with bundle metadata. Signature enforcement still pending; long WebService test build canceled mid-run and needs rerun once caches warm. | Implementer |
## Decisions & Risks
- **Decisions**
@@ -90,10 +93,11 @@
- Advisory-AI consumers must map observation IDs via projection service; keep aggregation-only stance (no consensus logic) for all new APIs.
- **Risks & Mitigations**
- Observability sinks not ready for 31-003 → reuse Signals dashboards; ship log-only fallback. Severity: Medium.
- Mirror bundle schema still absent (blocks 56/57/58) → escalate to Export Center; track due date 2025-11-19; severity: High.
- Portable EvidenceLocker format not published (blocks 58-001) → request format drop from Evidence Locker leads; severity: High.
- Connector signer metadata rollout validation outstanding → monitor ingestion for MSRC/Oracle/Ubuntu/OpenVEX and gate with feature flags if drift detected. Severity: Medium.
- Attestation verifier regressions during replay drills → keep harness diagnostics enabled; severity: Medium.
- Mirror bundle schema still absent (blocks 56/57/58) → escalate to Export Center; track due date 2025-11-19; severity: High.
- Portable EvidenceLocker format not published (blocks 58-001) → request format drop from Evidence Locker leads; severity: High.
- Connector signer metadata rollout validation outstanding → monitor ingestion for MSRC/Oracle/Ubuntu/OpenVEX and gate with feature flags if drift detected. Severity: Medium.
- Attestation verifier regressions during replay drills → keep harness diagnostics enabled; severity: Medium.
- Air-gap import storage landed; signature enforcement and end-to-end test rerun pending (build canceled mid-run). Severity: Medium.
## Next Checkpoints
| Date (UTC) | Session / Owner | Goal | Fallback |

View File

@@ -60,6 +60,7 @@
| 2025-11-22 | LEDGER-AIRGAP-56-001 delivered: air-gap import ledger event flow + `/internal/ledger/airgap-import`, provenance table/migration, timeline logging. | Findings Ledger Guild |
| 2025-11-22 | LEDGER-29-009 remains BLOCKED: DevOps/Offline kit overlays live outside module working dir; awaiting approved path for Helm/Compose assets and backup runbooks. | Findings Ledger Guild |
| 2025-11-22 | Marked AIRGAP-56-002 BLOCKED pending freshness threshold spec; downstream AIRGAP-57/58 remain blocked accordingly. | Findings Ledger Guild |
| 2025-11-22 | Added backup/restore and restore-replay guidance to `docs/modules/findings-ledger/deployment.md`; noted placeholder until DevOps assigns manifest paths. | Findings Ledger Guild |
| 2025-11-22 | Switched LEDGER-29-008 to DOING; created `src/Findings/StellaOps.Findings.Ledger/TASKS.md` mirror for status tracking. | Findings Ledger Guild |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
| 2025-11-19 | Marked PREP tasks P1P3 BLOCKED: observability schema, orchestrator ledger export contract, and mirror bundle schema are still missing, keeping LEDGER-29-008/34-101/AIRGAP-56-* blocked. | Project Mgmt |
@@ -87,6 +88,7 @@
- Implementer contract now anchored in `src/Findings/AGENTS.md`; keep in sync with module docs and update sprint log when changed.
- Remaining blocks: LEDGER-29-009 still waits on DevOps/offline review of backup/restore collateral; AIRGAP-56-002/57/58 and ATTEST-73 remain blocked on their upstream freshness/timeline/attestation specs.
- Deployment asset path risk: Helm/Compose/offline kit overlays sit outside the module working directory; need DevOps-provided target directories before committing manifests (blocks LEDGER-29-009).
- Backup collateral risk: until DevOps approves storage locations, backup/restore runbook lives only in `docs/modules/findings-ledger/deployment.md`; implementers must not commit manifests outside module paths.
## Next Checkpoints
- 2025-11-15 · Metrics + dashboard schema sign-off — Observability Guild — unblocks LEDGER-29-007 instrumentation PR.

View File

@@ -36,7 +36,7 @@
| P9 | PREP-LEDGER-RISK-66-001-RISK-ENGINE-SCHEMA-CO | DONE (2025-11-21) | Due 2025-11-22 · Accountable: Findings Ledger Guild; Risk Engine Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild; Risk Engine Guild / src/Findings/StellaOps.Findings.Ledger | Prep doc published at `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`; risk fields and rollout plan defined for downstream implementation. |
| P10 | PREP-LEDGER-RISK-66-002-DEPENDS-ON-66-001-MIG | DONE (2025-11-21) | Due 2025-11-22 · Accountable: Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Depends on 66-001 migration + risk scoring contract. Prep doc published at `docs/modules/findings-ledger/prep/2025-11-20-ledger-risk-prep.md`. |
| 1 | LEDGER-ATTEST-73-002 | BLOCKED | Waiting on LEDGER-ATTEST-73-001 verification pipeline delivery | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Enable search/filter in findings projections by verification result and attestation status |
| 2 | LEDGER-EXPORT-35-001 | DOING (2025-11-20) | Findings export endpoint implemented; VEX/advisory/SBOM endpoints stubbed pending schemas | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Provide paginated streaming endpoints for advisories, VEX, SBOMs, and findings with deterministic ordering and provenance metadata |
| 2 | LEDGER-EXPORT-35-001 | DONE (2025-11-22) | Findings/VEX/Advisory/SBOM endpoints implemented with filters hash + page token validation; deterministic empty result sets until schemas/tables land | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Provide paginated streaming endpoints for advisories, VEX, SBOMs, and findings with deterministic ordering and provenance metadata |
| 3 | LEDGER-OAS-61-001 | BLOCKED | PREP-LEDGER-OAS-61-001-ABSENT-OAS-BASELINE-AN | Findings Ledger Guild; API Contracts Guild / src/Findings/StellaOps.Findings.Ledger | Expand Findings Ledger OAS to include projections, evidence lookups, and filter parameters with examples |
| 4 | LEDGER-OAS-61-002 | BLOCKED | PREP-LEDGER-OAS-61-002-DEPENDS-ON-61-001-CONT | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Implement `/.well-known/openapi` endpoint and ensure version metadata matches release |
| 5 | LEDGER-OAS-62-001 | BLOCKED | PREP-LEDGER-OAS-62-001-SDK-GENERATION-PENDING | Findings Ledger Guild; SDK Generator Guild / src/Findings/StellaOps.Findings.Ledger | Provide SDK test cases for findings pagination, filtering, evidence links; ensure typed models expose provenance |
@@ -45,7 +45,7 @@
| 8 | LEDGER-OBS-51-001 | DONE | Metrics and SLOs implemented in code + docs | Findings Ledger Guild; DevOps Guild / src/Findings/StellaOps.Findings.Ledger | Publish metrics for ledger latency, projector lag, event throughput, and policy evaluation linkage; SLOs: append P95 < 1s, replay lag < 30s |
| 9 | LEDGER-OBS-52-001 | DONE | Timeline events emitted for ledger append + projection commit | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Emit timeline events for ledger writes and projector commits (`ledger.event.appended`, `ledger.projection.updated`) with trace ID, policy version, evidence bundle reference placeholders |
| 10 | LEDGER-OBS-53-001 | DONE | Evidence bundle refs persisted + lookup API | Findings Ledger Guild; Evidence Locker Guild / src/Findings/StellaOps.Findings.Ledger | Persist evidence bundle references alongside ledger entries; expose lookup linking findings to evidence manifests and timeline |
| 11 | LEDGER-OBS-54-001 | BLOCKED | PREP-LEDGER-OBS-54-001-NO-HTTP-SURFACE-MINIMA | Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | Verify attestation references for ledger-derived exports; expose `/ledger/attestations` endpoint returning DSSE verification state and chain-of-custody summary |
| 11 | LEDGER-OBS-54-001 | DONE (2025-11-22) | `/v1/ledger/attestations` endpoint implemented with deterministic paging + filters hash; schema/OAS updated | Findings Ledger Guild; Provenance Guild / src/Findings/StellaOps.Findings.Ledger | Verify attestation references for ledger-derived exports; expose `/ledger/attestations` endpoint returning DSSE verification state and chain-of-custody summary |
| 12 | LEDGER-OBS-55-001 | BLOCKED | PREP-LEDGER-OBS-55-001-DEPENDS-ON-54-001-ATTE | Findings Ledger Guild; DevOps Guild / src/Findings/StellaOps.Findings.Ledger | Enhance incident mode to record replay diagnostics (lag traces, conflict snapshots), extend retention while active, and emit activation events to timeline/notifier |
| 13 | LEDGER-PACKS-42-001 | BLOCKED | PREP-LEDGER-PACKS-42-001-SNAPSHOT-TIME-TRAVEL | Findings Ledger Guild / src/Findings/StellaOps.Findings.Ledger | Provide snapshot/time-travel APIs and digestible exports for task pack simulation and CLI offline mode |
| 14 | LEDGER-RISK-66-001 | DONE (2025-11-21) | PREP-LEDGER-RISK-66-001-RISK-ENGINE-SCHEMA-CO | Findings Ledger Guild; Risk Engine Guild / src/Findings/StellaOps.Findings.Ledger | Add schema migrations for `risk_score`, `risk_severity`, `profile_version`, `explanation_id`, and supporting indexes |
@@ -54,6 +54,7 @@
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-22 | Implemented LEDGER-OBS-54-001: `/v1/ledger/attestations` endpoint with paging token + filters hash guard; OAS/schema updated; status set to DONE. | Findings Ledger |
| 2025-11-20 | Published ledger OBS/pack/risk prep docs (docs/modules/findings-ledger/prep/2025-11-20-ledger-obs-54-001-prep.md, ...ledger-packs-42-001-prep.md, ...ledger-risk-66-prep.md); set PREP-LEDGER-OBS-54-001, PACKS-42-001, RISK-66-001/002 to DOING. | Project Mgmt |
| 2025-11-21 | Implemented LEDGER-RISK-66-001/002: added risk fields + index migration, policy evaluation payload plumbing, projection hashing, and repository storage; updated docs/schema and marked tasks DONE. | Findings Ledger |
| 2025-11-20 | Added authenticated export endpoints for findings/vex/advisories/sboms (stub responses) and paging contracts; awaiting schema/tables to back VEX/advisory/SBOM queries. Export paging unit tests passing via isolated test project. | Findings Ledger |
@@ -74,14 +75,16 @@
| 2025-11-18 | Attempted to continue sprint; all remaining tasks still blocked by absent HTTP surface, OAS/SDK contracts, and risk schema inputsno new work started. | Findings Ledger |
| 2025-11-18 | Reviewed adjacent sprints (0120, 0122) for unblocked Findings Ledger work; none available. Remaining idle until upstream contracts land. | Findings Ledger |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Implemented LEDGER-EXPORT-35-001 endpoints for VEX/advisories/SBOMs with filter hash + page token validation; updated docs status. | Findings Ledger |
## Decisions & Risks
- Upstream dependency on Sprint 120.B (Findings.I); block start until merged.
- Cross-guild coordination (Evidence Locker, Risk Engine, Observability, Provenance) required to avoid schema drift.
- Export/SDK contract changes must remain deterministic to support offline bundles.
- Export HTTP surface spec published at `docs/modules/findings-ledger/export-http-surface.md`; downstream OAS/SDK tasks must derive contracts from this document to avoid drift.
- LEDGER-OBS-54-001 blocked: Findings Ledger module currently lacks HTTP/minimal API surface to expose `/ledger/attestations`; requires contract + service scaffold (engage API Contracts & Provenance guilds).
- LEDGER-OBS-54-001 delivered: `/v1/ledger/attestations` now live with deterministic paging + filters hash; downstream OBS-55-001 (incident mode) still blocked pending incident diagnostics contract.
- Current state: findings export endpoint and paging contracts implemented; VEX/advisory/SBOM endpoints stubbed (auth + shape) but await underlying projection/query schemas. Risk schema/implementation (LEDGER-RISK-66-001/002) delivered. Remaining blockers: OAS/SDK surface (61/62/63), attestation HTTP host (OBS-54/55), and packs time-travel contract (PACKS-42-001).
- Export endpoints now enforce filter hash + page token determinism for VEX/advisory/SBOMs but still return empty sets until backing projections land; downstream SDK/OAS tasks should treat payload shapes as stable.
## Next Checkpoints
- Schedule cross-guild kickoff for week of 2025-11-24 once dependency clears.

View File

@@ -66,7 +66,9 @@
| 2025-11-22 | Implemented runtime shim execution path (entrypoint import, module loader/permission/wasm hooks, deterministic hashing) and aligned runtime payload to `ScanAnalysisKeys.DenoRuntimePayload`; ran `dotnet test ...Deno.Tests.csproj --filter DenoRuntime --no-restore`. | Implementer |
| 2025-11-22 | Hardened shim flush determinism (literal `\\n` join/write) and re-ran `DenoRuntime` tests (pass). | Implementer |
| 2025-11-22 | Normalized Windows drive-path regex in shim (single backslash) to ensure entrypoint detection on Windows; reran `DenoRuntime` tests (pass). | Implementer |
| 2025-11-22 | Added optional end-to-end shim smoke test (`DenoRuntimeTraceRunnerTests`) that executes the shim when a `deno` binary is present; includes offline fixture entrypoint; `dotnet test ... --filter DenoRuntimeTraceRunnerTests --no-restore` completed. | Implementer |
| 2025-11-22 | Added offline end-to-end shim smoke test (`DenoRuntimeTraceRunnerTests`) using a stubbed `deno` binary to produce deterministic NDJSON; includes fixture entrypoint; `dotnet test ... --filter DenoRuntimeTraceRunnerTests --no-restore` passing. | Implementer |
| 2025-11-22 | Re-ran stubbed runtime tests (`dotnet test ... --filter DenoRuntime --no-restore`) to confirm shim flush/regex updates remain green. | Implementer |
| 2025-11-22 | DenoLanguageAnalyzer now invokes runtime trace runner when `STELLA_DENO_ENTRYPOINT` is set, enabling optional runtime capture without separate wiring; guarded to remain no-op otherwise. | Implementer |
## Decisions & Risks
- Scanner record payload schema still unpinned; drafting prep at `docs/modules/scanner/prep/2025-11-21-scanner-records-prep.md` while waiting for analyzer output confirmation from Scanner Guild.
@@ -76,6 +78,7 @@
- Java analyzer framework-config/JNI tests pending: prior runs either failed due to missing `StellaOps.Concelier.Storage.Mongo` `CoreLinksets` types or were aborted due to repo-wide restore contention; rerun on clean runner or after Concelier build stabilises.
- Deno runtime hook + policy-signal schema drafted in `docs/modules/scanner/design/deno-runtime-signals.md`; shim plan in `docs/modules/scanner/design/deno-runtime-shim.md`.
- Deno runtime shim now emits module/permission/wasm/npm events; needs end-to-end validation on a Deno runner (cached-only) to confirm module loader hook coverage before wiring DENO-26-010/011.
- Offline smoke test uses stubbed `deno` to verify runner/shim integration; still advisable to run once with real cached-only `deno` to validate module-loader hook coverage before wiring DENO-26-010/011 (but not blocking current task). With analyzer now auto-calling the runner when `STELLA_DENO_ENTRYPOINT` is set, runtime capture is available as soon as a real `deno` binary is present.
- Runtime payload key aligned to `ScanAnalysisKeys.DenoRuntimePayload` (compat shim keeps legacy `"deno.runtime"`); downstream consumers should read the keyed payload to avoid silent misses.
- PREP note for SCANNER-ANALYZERS-JAVA-21-005 published at `docs/modules/scanner/prep/2025-11-20-java-21-005-prep.md`; awaiting CoreLinksets package fix and isolated CI slot before tests can run.
- PREP docs added for SCANNER-ANALYZERS-JAVA-21-008 (`docs/modules/scanner/prep/2025-11-20-java-21-008-prep.md`) and LANG-11-001 (`docs/modules/scanner/prep/2025-11-20-lang-11-001-prep.md`); both depend on resolver outputs/CI isolation.

View File

@@ -47,6 +47,7 @@
| 2025-11-22 | Added composer.lock autoload parsing + metadata emission; fixtures/goldens updated. `dotnet test ...Lang.Php.Tests` restore cancelled after 90s (NuGet.targets MSB4220); rerun needed. | PHP Analyzer Guild |
| 2025-11-22 | Added PHP analyzer scaffold + composer.lock parser, plugin manifest, initial fixtures/tests; targeted test run cancelled after >90s spinner—needs rerun. | PHP Analyzer Guild |
| 2025-11-23 | Multiple restore attempts (isolated `NUGET_PACKAGES`, `RestoreSources=local-nugets`, `--disable-parallel`, diag logs) still hang >90s due to NuGet restore task; test execution not possible. Marked SCANNER-ENG-0010 BLOCKED pending restore stability. | PHP Analyzer Guild |
| 2025-11-24 | Retried restore with static graph (`RestoreUseStaticGraphEvaluation=true`) and custom local-only NuGet config; ResolvePackageAssets still hangs, tests not runnable. | PHP Analyzer Guild |
| 2025-11-22 | Retried PHP analyzer tests with local feed only; `dotnet test --no-restore` builds, but restore step still hangs >90s (NuGet RestoreTask) even with `RestoreSources=local-nugets`, so tests remain unexecuted. | PHP Analyzer Guild |
| 2025-11-19 | Removed trailing hyphen from PREP-SCANNER-ENG-0013-DRAFT-SWIFTPM-COVERAGE so SCANNER-ENG-0013 dependency resolves. | Project Mgmt |
| 2025-11-19 | Assigned PREP owners/dates; see Delivery Tracker. | Planning |
@@ -69,7 +70,7 @@
## Decisions & Risks
- PHP analyzer pipeline (SCANNER-ENG-0010) blocked pending composer/autoload graph design + staffing; parity risk remains.
- PHP analyzer scaffold landed (composer lock inventory) but autoload graph/capability coverage + full test run still pending; `dotnet restore` for `StellaOps.Scanner.Analyzers.Lang.Php.Tests` repeatedly hangs >90s even when forced to `RestoreSources=local-nugets` and isolated `NUGET_PACKAGES`, leaving tests unexecuted (latest attempt 2025-11-23).
- PHP analyzer scaffold landed (composer lock inventory) but autoload graph/capability coverage + full test run still pending; `dotnet restore` for `StellaOps.Scanner.Analyzers.Lang.Php.Tests` repeatedly hangs >90s even when forced to `RestoreSources=local-nugets`, isolated caches, and static-graph restore, leaving tests unexecuted (latest attempt 2025-11-24).
- Deno, Dart, and Swift analyzers (SCANNER-ENG-0011..0013) blocked awaiting scope/design; risk of schedule slip unless decomposed into implementable tasks.
- Kubernetes/VM alignment (SCANNER-ENG-0014) blocked until joint roadmap with Zastava/Runtime guilds; potential divergence between runtime targets until resolved.
- Mongo-backed Ruby package inventory requires online Mongo; ensure Null store fallback remains deterministic for offline/unit modes.

View File

@@ -49,11 +49,13 @@
| 2025-11-09 | Sprint snapshot refreshed; awaiting Scanner surface artifact ETA, Concelier/CARTO schema delivery, and Signals host merge before any wave can advance to DOING. | Planning |
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Published SBOM runtime/signals prep note at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; added AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; prepared fixtures drop path `docs/modules/sbomservice/fixtures/lnm-v1/`. SBOM wave still BLOCKED pending fixtures + review execution. | Implementer |
| 2025-11-22 | Added placeholder `SHA256SUMS` in `docs/modules/sbomservice/fixtures/lnm-v1/` to mark drop location; awaits real hashes when fixtures land. | Implementer |
## Decisions & Risks
- Graph/Zastava remain on scanner surface mock bundle v1; real cache ETA and manifests are overdue, parity validation cannot start.
- Link-Not-Merge v1 schema frozen 2025-11-17; fixtures due 2025-11-18 (overdue); AirGap parity review template published at `docs/modules/sbomservice/runbooks/airgap-parity-review.md` but review execution still outstanding.
- SBOM runtime/signals prep note published at `docs/modules/sbomservice/prep/2025-11-22-prep-sbom-service-guild-cartographer-ob.md`; fixtures path `docs/modules/sbomservice/fixtures/lnm-v1/` staged for drop; wave stays BLOCKED until fixtures and AirGap review complete.
- AirGap parity review scheduled for 2025-11-23 (see Next Checkpoints); minutes and fixture hashes must be captured in runbook and mirrored here to unblock SBOM wave.
- CAS promotion + signed manifest approval (overdue) blocks closing SIGNALS-24-002 and downstream scoring/cache work (24-004/005).
- Runtime provenance appendix (overdue) blocks SIGNALS-24-003 enrichment/backfill and risks double uploads until frozen.
- Surface.FS cache drop timeline (overdue) and Surface.Env owner assignment keep Zastava env/secret/admission tasks blocked.

View File

@@ -42,6 +42,7 @@
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Implemented analytics jobs (28-007), change-stream/backfill pipeline (28-008), determinism fixtures/tests (28-009), and packaging/offline doc updates (28-010); status set to DONE. | Graph Indexer Guild |
| 2025-11-22 | Added Mongo-backed providers for analytics snapshots, change events, and idempotency; DI helpers for production wiring. | Graph Indexer Guild |
| 2025-11-22 | Added Mongo database DI registration helper + integration tests; updated packaging env vars for connection/db names. | Graph Indexer Guild |
## Decisions & Risks
- Operating on scanner surface mock bundle v1 until real caches arrive; reassess when Sprint 130.A delivers caches.

View File

@@ -86,6 +86,7 @@
| 2025-11-22 | Marked all PREP tasks to DONE per directive; evidence to be verified. | Project Mgmt |
| 2025-11-22 | Staged LNM v1 fixtures drop path at `docs/modules/sbomservice/fixtures/lnm-v1/` and published AirGap parity review template at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; SBOM-SERVICE-21-001 remains BLOCKED pending fixtures + review execution. | Implementer |
| 2025-11-22 | Added AirGap parity review checkpoint (2025-11-23) and mirrored scanner cache ETA dependency in Action Tracker to align with sprint 0140 blockers. | Implementer |
| 2025-11-22 | Added placeholder `SHA256SUMS` under `docs/modules/sbomservice/fixtures/lnm-v1/` to mark hash drop site; replace with real fixture hashes once published. | Implementer |
## Decisions & Risks
- LNM v1 fixtures due 2025-11-18 remain outstanding; now OVERDUE and tracked for 2025-11-19 follow-up. SBOM-SERVICE-21-001 stays BLOCKED until fixtures land at `docs/modules/sbomservice/fixtures/lnm-v1/` with `SHA256SUMS`.
@@ -102,6 +103,7 @@
- `AGENTS.md` for `src/SbomService` added 2025-11-18; implementers must read before coding.
- AirGap parity review template published at `docs/modules/sbomservice/runbooks/airgap-parity-review.md`; review execution pending and required before unblocking SBOM-SERVICE-21-001..004 in air-gapped deployments.
- Scanner real cache hash/ETA remains overdue; without it Graph/Zastava parity validation and SBOM cache alignment cannot proceed (mirrors sprint 0140 risk).
- AirGap parity review scheduled for 2025-11-23; minutes, metrics, and fixture hash list must be captured in runbook and mirrored in Decisions & Risks to close BLOCKED state.
## Next Checkpoints
| Date (UTC) | Session | Goal | Owner(s) |

View File

@@ -57,12 +57,13 @@
| 2025-11-18 | Webhook smoke tests now pass (`dotnet test ...Webhook.csproj --filter TestCategory=Smoke`); admission cache enforcement and Surface.Env/Secrets wiring validated. | Zastava |
| 2025-11-22 | Refreshed Surface.Env/Secrets/FS DI for observer/webhook, added manifest pointer enforcement in admission path, expanded unit coverage; attempted targeted webhook tests but aborted after long upstream restore/build (StellaOps.Auth.Security failure still unresolved). | Zastava |
| 2025-11-22 | Tried targeted restore/build of `StellaOps.Auth.Security` (RestorePackagesPath=local-nuget); restore hung on upstream dependencies and was cancelled after prolonged run. | Zastava |
| 2025-11-22 | Added shared surface secret options, replaced internal manifest path builder usage, and reran runtime admission tests (`dotnet test ...RuntimeAdmission`): 5/5 passing via local-nuget cache. | Zastava |
## Decisions & Risks
- Surface Env/Secrets/FS wiring complete for observer and webhook; admission now embeds manifest pointers and denies on missing cache manifests.
- Targeted webhook unit run aborted due to upstream `StellaOps.Auth.Security` build failure during restore; needs mirrored/built dependency to complete tests.
- Targeted webhook runtime admission tests now passing after building `StellaOps.Auth.Security`; keep Auth cache mirrored in `local-nuget` for deterministic CI restores.
- Offline parity still depends on mirroring gRPC/AWS transitives (e.g., `Google.Protobuf`, `Grpc.Net.Client`, `Grpc.Tools`) and Authority/Auth stacks into `local-nuget`.
- Upstream Authority/Auth packages (notably `StellaOps.Auth.Security`) still block deterministic restores/builds; need DevOps cache seed or manual mirror to unblock test execution.
- Upstream Authority/Auth packages (notably `StellaOps.Auth.Security`) remain needed in local caches; refresh mirror before CI runs to avoid restore stalls.
- Surface.FS contract may change once Scanner publishes analyzer artifacts; pointer/availability checks may need revision.
- Surface.Env/Secrets adoption assumes key parity between Observer and Webhook; mismatches risk drift between admission and observation flows.

View File

@@ -8,6 +8,7 @@
## Dependencies & Concurrency
- Upstream: Sprint 120.A AirGap, Sprint 130.A Scanner, Sprint 150.A Orchestrator, Sprint 170.A Notifier.
- SDK inputs: SPRINT_0208_0001_0001_sdk Wave B (TS/Go SDK alphas) required for SDKGEN-64-001 CLI adoption.
- Concurrency: other CLI sprints (02020205) expected to run in parallel; no shared mutable state beyond CLI core library.
## Documentation Prerequisites
@@ -25,12 +26,12 @@
| 4 | CLI-AIAI-31-002 | TODO | Depends on CLI-AIAI-31-001 | DevEx/CLI Guild | Implement `stella advise explain` showing conflict narrative and structured rationale. |
| 5 | CLI-AIAI-31-003 | TODO | Depends on CLI-AIAI-31-002 | DevEx/CLI Guild | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. |
| 6 | CLI-AIAI-31-004 | TODO | Depends on CLI-AIAI-31-003 | DevEx/CLI Guild | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. |
| 7 | CLI-AIRGAP-56-001 | TODO | Define mirror command contract | DevEx/CLI Guild | Implement `stella mirror create` for air-gap bootstrap. |
| 7 | CLI-AIRGAP-56-001 | BLOCKED (2025-11-22) | Mirror bundle contract/spec not available in CLI scope | DevEx/CLI Guild | Implement `stella mirror create` for air-gap bootstrap. |
| 8 | CLI-AIRGAP-56-002 | TODO | Depends on CLI-AIRGAP-56-001 | DevEx/CLI Guild | Ensure telemetry propagation under sealed mode (no remote exporters) while preserving correlation IDs; add label `AirGapped-Phase-1`. |
| 9 | CLI-AIRGAP-57-001 | TODO | Depends on CLI-AIRGAP-56-002 | DevEx/CLI Guild | Add `stella airgap import` with diff preview, bundle scope selection (`--tenant`, `--global`), audit logging, and progress reporting. |
| 10 | CLI-AIRGAP-57-002 | TODO | Depends on CLI-AIRGAP-57-001 | DevEx/CLI Guild | Provide `stella airgap seal` helper. |
| 11 | CLI-AIRGAP-58-001 | TODO | Depends on CLI-AIRGAP-57-002 | DevEx/CLI Guild · Evidence Locker Guild | Implement `stella airgap export evidence` helper for portable evidence packages, including checksum manifest and verification. |
| 12 | CLI-ATTEST-73-001 | TODO | — | CLI Attestor Guild | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. |
| 12 | CLI-ATTEST-73-001 | BLOCKED (2025-11-22) | CLI build currently fails on Scanner analyzer projects; attestor SDK transport contract not wired into CLI yet | CLI Attestor Guild | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. |
| 13 | CLI-ATTEST-73-002 | TODO | Depends on CLI-ATTEST-73-001 | CLI Attestor Guild | Implement `stella attest verify` with policy selection, explainability output, and JSON/table formatting. |
| 14 | CLI-ATTEST-74-001 | TODO | Depends on CLI-ATTEST-73-002 | CLI Attestor Guild | Implement `stella attest list` with filters (subject, type, issuer, scope) and pagination. |
| 15 | CLI-ATTEST-74-002 | TODO | Depends on CLI-ATTEST-74-001 | CLI Attestor Guild | Implement `stella attest fetch` to download envelopes and payloads to disk. |
@@ -45,6 +46,7 @@
- Not applicable for this sprint.
## Interlocks
- SDK generation (SPRINT_0208_0001_0001_sdk): Wave B artifacts and parity matrix needed for CLI SDK adoption (SDKGEN-64-001) and attestor transport alignment.
- Interface with Advisory AI service and Attestor service contracts for new verbs.
- Air-gap workflows rely on mirror/import/seal bundle formats from AirGap program.
@@ -52,12 +54,17 @@
- Demo TBD (schedule after Advisory AI verbs reach feature-complete state).
## Action Tracker
- None logged yet.
| # | Action | Owner | Due (UTC) | Status |
| --- | --- | --- | --- | --- |
| 1 | Align CLI adoption scope with SPRINT_0208_0001_0001_sdk Wave B artifacts (SDKGEN-64-001) and schedule switch-over | DevEx/CLI Guild | 2025-12-10 | TODO |
| 2 | Obtain offline kit status contract + sample bundle for CLI-HK-201-002 | DevEx/CLI Guild · Offline Kit owner | 2025-11-27 | TODO |
## Decisions & Risks
- `CLI-HK-201-002` remains blocked pending offline kit status contract and sample bundle.
- Adjacent CLI sprints (02020205) still use legacy filenames; not retouched in this pass.
- `CLI-AIAI-31-001` blocked: `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests` fails while building upstream Scanner analyzers (Node/Java) with multiple compile errors; requires Scanner team fix or temporary test skip before CLI verification can complete.
- `CLI-AIRGAP-56-001` blocked: mirror bundle contract/spec not published to CLI; cannot implement `stella mirror create` without bundle schema and signing/digest requirements.
- `CLI-ATTEST-73-001` blocked: CLI solution build currently fails due to Scanner analyzer compile errors; attestor SDK/transport contract not available to wire `stella attest sign` safely.
## Execution Log
| Date (UTC) | Update | Owner |
@@ -68,3 +75,6 @@
| 2025-11-22 | Added `stella advise summarize` flow with JSON/Markdown output wiring and citation display; updated CLI task tracker. | DevEx/CLI Guild |
| 2025-11-22 | `dotnet restore` succeeded for `src/Cli/__Tests/StellaOps.Cli.Tests` using local nugets; `dotnet test` failed: `StellaOps.Scanner.Analyzers.Lang.Node` (NodeImportWalker.cs, NodePackage.cs) and `StellaOps.Scanner.Analyzers.Lang.Java` (JavaLanguageAnalyzer.cs) not compiling. Log: `/tmp/test_cli_tests.log`. | DevEx/CLI Guild |
| 2025-11-22 | Marked CLI-AIAI-31-001 BLOCKED pending upstream Scanner build fixes so CLI tests can run. | DevEx/CLI Guild |
| 2025-11-22 | Started CLI-AIRGAP-56-001; blocked due to missing mirror bundle contract/spec (schema, signing, digest requirements) needed for `stella mirror create`. | DevEx/CLI Guild |
| 2025-11-22 | Marked CLI-ATTEST-73-001 BLOCKED; attestor SDK contract unavailable and CLI build blocked by Scanner analyzer failures, preventing implementation/testing. | CLI Attestor Guild |
| 2025-11-22 | Added SDK interlock (SPRINT_0208_0001_0001_sdk), action tracker entries for CLI adoption and offline kit sample. | Project mgmt |

View File

@@ -8,6 +8,7 @@
## Dependencies & Concurrency
- Upstream: Sprint 120.A AirGap, 130.A Scanner, 150.A Orchestrator, 170.A Notifier (spec + auth contracts).
- SDK inputs: SPRINT_0208_0001_0001_sdk Wave B/C artifacts (language snippets, offline bundle inputs) for DEVPORT-63-002 and DEVPORT-64-001.
- Parallel-safe provided services continue to expose OpenAPI via compose pipeline; no cross-write coupling expected.
## Documentation Prerequisites
@@ -22,9 +23,20 @@
| 1 | DEVPORT-62-001 | DONE | Astro/Starlight scaffold in place; spec wired; nav/search live | Developer Portal Guild | Select static site generator, integrate aggregate spec, build navigation + search scaffolding. |
| 2 | DEVPORT-62-002 | DONE | Schema viewer + examples + copy-curl + version selector shipped | Developer Portal Guild | Implement schema viewer, example rendering, copy-curl snippets, and version selector UI. |
| 3 | DEVPORT-63-001 | DONE | Sandbox try-it console with token onboarding shipped | Developer Portal Guild · Platform Guild | Add Try-It console pointing at sandbox environment with token onboarding and scope info. |
| 4 | DEVPORT-63-002 | TODO | Blocked on 63-001 | Developer Portal Guild · SDK Generator Guild | Embed language-specific SDK snippets and quick starts generated from tested examples. |
| 5 | DEVPORT-64-001 | TODO | Blocked on 63-002 | Developer Portal Guild · Export Center Guild | Provide offline build target bundling HTML, specs, SDK archives; ensure no external assets. |
| 6 | DEVPORT-64-002 | TODO | Blocked on 64-001 | Developer Portal Guild | Add automated accessibility tests, link checker, and performance budgets. |
| 4 | DEVPORT-63-002 | DONE | SDK quickstarts (Node, Python) added | Developer Portal Guild · SDK Generator Guild | Embed language-specific SDK snippets and quick starts generated from tested examples. |
| 5 | DEVPORT-64-001 | DONE | Offline bundle script added (build-offline) | Developer Portal Guild · Export Center Guild | Provide offline build target bundling HTML, specs, SDK archives; ensure no external assets. |
| 6 | DEVPORT-64-002 | DONE | A11y/link/perf scripts added (execution pending) | Developer Portal Guild | Add automated accessibility tests, link checker, and performance budgets. |
## Interlocks
- SDK generation (SPRINT_0208_0001_0001_sdk): Wave B SDK snippets sustain DEVPORT-63-002; Wave C offline artifacts and manifest expectations feed DEVPORT-64-001/64-002 validation.
- Export Center: bundle manifest and artifact pipeline shared with SDK Release Guild; align on tarball layout and checksum manifest.
## Action Tracker
| # | Action | Owner | Due (UTC) | Status |
| --- | --- | --- | --- | --- |
| 1 | Receive SDK snippet pack (Wave B, SPRINT_0208_0001_0001_sdk) and verify embeds still match spec versions | Developer Portal Guild · SDK Generator Guild | 2025-12-06 | TODO |
| 2 | Define offline bundle manifest jointly with SDK Release + Export Center (aligns with SDKREL-64-002) | Developer Portal Guild · Export Center Guild | 2025-12-12 | TODO |
| 3 | Re-run DevPortal build/tests on faster volume to clear earlier timeout | Developer Portal Guild | 2025-11-27 | TODO |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -34,6 +46,12 @@
| 2025-11-22 | Completed DEVPORT-62-001 with Astro/Starlight scaffold, RapiDoc view, nav + local search; npm ci aborted after 20m on NTFS volume so build/check not yet executed. | Developer Portal Guild |
| 2025-11-22 | Completed DEVPORT-62-002: schema viewer (RapiDoc components), version selector, copy-curl snippets, examples guide added; build still pending faster volume. | Developer Portal Guild |
| 2025-11-22 | Completed DEVPORT-63-001: try-it console with sandbox server selector, bearer-token onboarding UI, allow-try enabled. | Developer Portal Guild |
| 2025-11-22 | Completed DEVPORT-63-002: SDK quickstarts (Node/Python) added and linked. | Developer Portal Guild |
| 2025-11-22 | Completed DEVPORT-64-001: offline bundle script (`npm run build:offline`) packages dist + spec + SDK archives with deterministic tar. | Developer Portal Guild |
| 2025-11-22 | Started DEVPORT-64-002: added scripts for a11y (axe+playwright), link check (linkinator), and perf budgets (dist size). | Developer Portal Guild |
| 2025-11-22 | Completed DEVPORT-64-002: scripts added; execution blocked on fast-volume install. | Developer Portal Guild |
| 2025-11-22 | Added SDK/Export interlocks and action tracker (snippet pack, offline manifest, rebuild on faster volume). | Project mgmt |
| 2025-11-22 | Scheduled checkpoints for build rerun, SDK snippet review, and offline manifest sign-off. | Project mgmt |
## Decisions & Risks
- Completed/historic work is tracked in `docs/implplan/archived/tasks.md` (last updated 2025-11-08); only active items remain here.
@@ -41,6 +59,11 @@
- Local installs on `/mnt/e` NTFS are slow; `npm ci --ignore-scripts` for DevPortal exceeded 20 minutes and was aborted—build/test validation deferred until faster volume available.
- RapiDoc schema viewer + version selector rely on `/api/stella.yaml`; ensure compose pipeline keeps this asset in sync before publishing builds.
- Try-It console currently targets `https://sandbox.api.stellaops.local`; adjust if platform assigns a different sandbox base URL.
- Offline bundle script (`npm run build:offline`) is unverified until dependencies install on a faster volume; ensure `tar` availability and run validation before shipping artifacts.
- New test scripts (`test:a11y`, `lint:links`, `budget:dist`) require `npm ci` and `npm run preview` on a faster volume before they can be executed.
- Node_modules currently removed after cleanup attempts; rerun `npm ci --ignore-scripts --progress=false --no-fund --no-audit` on a fast volume before executing any QA commands.
## Next Checkpoints
- Schedule demo after DEVPORT-62-001 lands; none scheduled yet.
- 2025-11-27: Re-run build/tests on fast volume to validate offline bundle script and prior changes.
- 2025-12-06: SDK snippet pack integration review (DEVPORT-63-002) with SDK Generator Guild.
- 2025-12-12: Offline bundle manifest sign-off with Export Center/SDK Release (ties to SDKREL-64-002).

View File

@@ -23,7 +23,7 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
| --- | --- | --- | --- | --- | --- |
| 1 | GRAPH-API-28-001 | TODO | Kick off OpenAPI/JSON schema draft; align cost + tile schema. | Graph API Guild (`src/Graph/StellaOps.Graph.Api`) | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. |
| 1 | GRAPH-API-28-001 | DOING | Kick off OpenAPI/JSON schema draft; align cost + tile schema. | Graph API Guild (`src/Graph/StellaOps.Graph.Api`) | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. |
| 2 | GRAPH-API-28-002 | TODO | GRAPH-API-28-001 | Graph API Guild (`src/Graph/StellaOps.Graph.Api`) | Implement `/graph/search` with multi-type index lookup, prefix/exact match, RBAC enforcement, and result ranking + caching. |
| 3 | GRAPH-API-28-003 | TODO | GRAPH-API-28-002 | Graph API Guild (`src/Graph/StellaOps.Graph.Api`) | Build query planner + cost estimator for `/graph/query`, stream tiles (nodes/edges/stats) progressively, enforce budgets, provide cursor tokens. |
| 4 | GRAPH-API-28-004 | TODO | GRAPH-API-28-003 | Graph API Guild (`src/Graph/StellaOps.Graph.Api`) | Implement `/graph/paths` with depth ≤6, constraint filters, heuristic shortest path search, and optional policy overlay rendering. |
@@ -51,13 +51,14 @@
## Upcoming Checkpoints
- 2025-11-24 · Target date to circulate OpenAPI/JSON schema draft (GRAPH-API-28-001). Owner: Graph API Guild.
- 2025-11-29 · Propose schema sign-off and budget model review before starting GRAPH-API-28-002/003.
- 2025-11-29 · Propose schema sign-off and budget model review before starting GRAPH-API-28-002/003; include Policy Engine overlays alignment.
- 2025-12-03 · Overlay contract validation with Policy Engine Guild ahead of GRAPH-API-28-006.
## Action Tracker
| Action | Owner | Due (UTC) | Status |
| --- | --- | --- | --- |
| Circulate initial schema/tiles draft for review (GRAPH-API-28-001). Evidence: `docs/modules/graph/prep/2025-11-22-graph-api-schema-outline.md`. | Graph API Guild | 2025-11-24 | In progress |
| Circulate initial schema/tiles draft for review (GRAPH-API-28-001). Evidence: `docs/modules/graph/prep/2025-11-22-graph-api-schema-outline.md`, `docs/modules/graph/prep/2025-11-24-graph-api-schema-review.md`, `docs/api/graph-gateway-spec-draft.yaml`. | Graph API Guild | 2025-11-24 | In progress |
| Hold joint OpenAPI review + budget model sign-off (Graph API + Policy Engine). Evidence: `docs/api/graph-gateway-spec-draft.yaml` review notes. | Graph API Guild · Policy Engine Guild | 2025-11-29 | Open |
| Confirm POLICY-ENGINE-30-001..003 contract version for overlay consumption. | Policy Engine Guild · Graph API Guild | 2025-11-30 | Open |
| Prep synthetic dataset fixtures (500k/2M) for load tests. | QA Guild · Graph API Guild | 2025-12-05 | Open |
@@ -78,4 +79,6 @@
| 2025-11-22 | Normalized sprint to standard template and renamed file from `SPRINT_207_graph.md` to `SPRINT_0207_0001_0001_graph.md`; no task status changes. | Project Mgmt |
| 2025-11-22 | Added module charter `src/Graph/AGENTS.md` to unblock implementers; no task status changes. | Project Mgmt |
| 2025-11-22 | Drafted schema/tiles outline for GRAPH-API-28-001 at `docs/modules/graph/prep/2025-11-22-graph-api-schema-outline.md`; marked action as In progress. | Project Mgmt |
| 2025-11-22 | Updated `docs/api/graph-gateway-spec-draft.yaml` to encode search/query/paths/diff/export endpoints and shared schemas per outline; evidence for GRAPH-API-28-001. | Project Mgmt |
| 2025-11-22 | Updated `docs/api/graph-gateway-spec-draft.yaml` to encode search/query/paths/diff/export endpoints, shared tile schemas, and examples; evidence for GRAPH-API-28-001; moved task to DOING. | Project Mgmt |
| 2025-11-22 | Added joint OpenAPI + budget review action (due 2025-11-29) and updated checkpoints accordingly. | Project Mgmt |
| 2025-11-22 | Created review notes shell at `docs/modules/graph/prep/2025-11-24-graph-api-schema-review.md` to capture schema sign-off outcomes. | Project Mgmt |

View File

@@ -56,6 +56,7 @@
- 2025-12-02: Shared post-processing design review (SDKGEN-62-002) — approve auth/retry/pagination/telemetry hooks.
- 2025-12-05: TS alpha staging drop (SDKGEN-63-001) — verify packaging and typed errors.
- 2025-12-15: Multi-language alpha readiness check (SDKGEN-63-002..004) — parity matrix sign-off.
- 2025-12-16: Deliver parity matrix and SDK drop to UI/Console data providers (feeds SPRINT_0209_0001_0001_ui_i).
- 2025-12-22: Release automation demo (SDKREL-63/64) — staging publishes with signatures and offline bundle.
## Action Tracker
@@ -65,6 +66,7 @@
| 2 | Publish SDK language support matrix to CLI/UI guilds | SDK Generator Guild | 2025-12-03 | Open |
| 3 | Align CLI adoption scope with SPRINT_0201_0001_0001_cli_i and schedule SDK drop integration | SDK Generator Guild · CLI Guild | 2025-12-10 | Open |
| 4 | Define devportal offline bundle manifest with Export Center per SPRINT_0206_0001_0001_devportal | SDK Release Guild · Export Center Guild | 2025-12-12 | Open |
| 5 | Deliver parity matrix and SDK drop to UI data providers per SPRINT_0209_0001_0001_ui_i | SDK Generator Guild · UI Guild | 2025-12-16 | Open |
## Decisions & Risks
- Dependencies on upstream API/portal contracts may delay generator pinning; mitigation: align with APIG0101 / DEVL0101 milestones.
@@ -84,3 +86,4 @@
| 2025-11-22 | Normalised sprint to standard template; renamed file to `SPRINT_0208_0001_0001_sdk.md`; no status changes. | PM |
| 2025-11-22 | Added wave plan and dated checkpoints for generator, language alphas, and release/offline tracks. | PM |
| 2025-11-22 | Added explicit interlocks to CLI/UI/Devportal sprints and new alignment actions. | PM |
| 2025-11-22 | Added UI parity-matrix delivery action to keep data provider integration on track. | PM |

View File

@@ -8,6 +8,7 @@
## Dependencies & Concurrency
- Upstream sprints: 120.A AirGap, 130.A Scanner, 150.A Orchestrator, 170.A Notifier.
- SDK inputs: SPRINT_0208_0001_0001_sdk Wave B parity matrix and SDKGEN-64-002 outputs feed Console data providers and scope exports.
- Parallel tracks: UI II (Sprint 0210) and UI III (Sprint 0211) can run concurrently if shared components remain backward compatible.
- Blockers to flag: Graph scope exports (`graph:*`), Policy Engine determinism schema, Scanner entropy/determinism evidence contracts.
@@ -54,6 +55,7 @@
- Not applicable (single wave).
## Interlocks
- SDK generation (SPRINT_0208_0001_0001_sdk): parity matrix + SDKGEN-64-002 outputs feed Console data providers and scope exports for UI-GRAPH-* tasks.
- Graph Explorer scope exports and SDK generation (`graph:*`).
- Policy Engine determinism and exception schemas for indicators/banners.
- Scanner entropy and determinism evidence formats for UI-ENTROPY-* and UI-SBOM-DET-01.
@@ -70,6 +72,7 @@
| 2 | Align Policy Engine determinism schema changes for UI-POLICY-DET-01 | Policy Guild | 2025-12-03 | TODO |
| 3 | Deliver entropy evidence fixture snapshot for UI-ENTROPY-40-001 | Scanner Guild | 2025-11-28 | TODO |
| 4 | Provide AOC verifier endpoint parity notes for UI-AOC-19-003 | Notifier Guild | 2025-11-27 | TODO |
| 5 | Receive SDK parity matrix (Wave B, SPRINT_0208_0001_0001_sdk) to unblock Console data providers and scope exports | UI Guild · SDK Generator Guild | 2025-12-16 | TODO |
## Decisions & Risks
| Risk | Impact | Mitigation / Next Step |
@@ -85,4 +88,7 @@
| 2025-11-22 | ASCII-only cleanup and dependency clarifications in tracker; no scope/status changes. | Project mgmt |
| 2025-11-22 | Added checkpoints and new actions for entropy evidence and AOC verifier parity; no task status changes. | Project mgmt |
| 2025-11-22 | Synced documentation prerequisites with UI Guild charter (UI guide, coding standards, module README/implementation plan). | Project mgmt |
| 2025-11-22 | Normalised `tasks-all.md` entries for this sprint to ASCII (quotes/arrows/dots). | Project mgmt |
| 2025-11-22 | Deduplicated `tasks-all.md` rows for this sprint (kept first occurrence per Task ID); no status changes. | Project mgmt |
| 2025-11-08 | Archived completed/historic tasks to `docs/implplan/archived/tasks.md`. | Planning |
| 2025-11-22 | Added SDK interlock (SPRINT_0208_0001_0001_sdk) and Action #5 for parity matrix delivery to UI data providers. | Project mgmt |

View File

@@ -21,9 +21,9 @@
## Delivery Tracker
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition / Evidence |
| --- | --- | --- | --- | --- | --- |
| 1 | WEB-AIAI-31-001 | TODO | Finalize gateway policy for `/advisory/ai/*` (RBAC/ABAC, rate limits, telemetry headers). | BE-Base Platform Guild | Route advisory AI endpoints through gateway with guardrails. |
| 2 | WEB-AIAI-31-002 | TODO | Depends on WEB-AIAI-31-001; implement batching handlers and retry/backoff semantics. | BE-Base Platform Guild | Streaming responses for CLI automation with job orchestration. |
| 3 | WEB-AIAI-31-003 | TODO | Depends on WEB-AIAI-31-002; wire metrics/logs and prompt-hash forwarding. | BE-Base Platform Guild; Observability Guild | Telemetry + audit for advisory AI, guardrail block visibility. |
| 1 | WEB-AIAI-31-001 | BLOCKED (2025-11-22) | Gateway policy/contract for `/advisory/ai/*` not present in Web workspace; need backend gateway service location + policy spec to proceed. | BE-Base Platform Guild | Route advisory AI endpoints through gateway with guardrails. |
| 2 | WEB-AIAI-31-002 | BLOCKED (2025-11-22) | Blocked by WEB-AIAI-31-001; batching/streaming cannot start until gateway contract exists. | BE-Base Platform Guild | Streaming responses for CLI automation with job orchestration. |
| 3 | WEB-AIAI-31-003 | BLOCKED (2025-11-22) | Blocked by WEB-AIAI-31-002; telemetry targets depend on routing/batching contract. | BE-Base Platform Guild; Observability Guild | Telemetry + audit for advisory AI, guardrail block visibility. |
| 4 | WEB-AOC-19-002 | TODO | Depends on WEB-AOC-19-001; align DSSE/CMS helper APIs. | BE-Base Platform Guild | Ship `ProvenanceBuilder`, checksum utilities, signature verification helper with tests. |
| 5 | WEB-AOC-19-003 | TODO | Depends on WEB-AOC-19-002; confirm Roslyn analyzer rules. | QA Guild; BE-Base Platform Guild | Analyzer to prevent forbidden key writes; shared guard-validation fixtures. |
| 6 | WEB-CONSOLE-23-001 | TODO | Define stable `/console/dashboard` and `/console/filters` contract; ensures deterministic ordering + pagination. | BE-Base Platform Guild; Product Analytics Guild | Tenant-scoped aggregates for findings, VEX overrides, advisory deltas, run health, policy change log. |
@@ -62,6 +62,7 @@
| --- | --- | --- | --- | --- |
| Console contract freeze slips past 2025-11-25 | Blocks CONSOLE-VULN-29-001 and CONSOLE-VEX-30-001, delays console workspaces | Hold contract review on 2025-11-25; publish schema snapshot to `docs/api/console/workspaces.md`; keep blockers logged | Console Guild | Open |
| SSE topic alignment delayed | WEB-CONSOLE-23-002/003/004 latency and reliability uncertain | Schedule alignment with Scheduler/Signals by 2025-11-27; add heartbeat/backoff defaults; capture examples in samples directory | BE-Base Platform Guild | Open |
| Advisory AI gateway contract missing | WEB-AIAI-31-001/002/003 cannot start without gateway location, RBAC/ABAC rules, and rate-limit policy spec | Request gateway contract snapshot + policy doc; replan once provided | BE-Base Platform Guild | Open |
## Execution Log
| Date (UTC) | Update | Owner |
@@ -76,3 +77,5 @@
| 2025-11-19 | CONSOLE-VULN-29-001 and CONSOLE-VEX-30-001 marked BLOCKED pending WEB-CONSOLE-23-001 and upstream schemas (Concelier/Excititor). | Console Guild |
| 2025-11-22 | Normalized sprint to template and renamed from `SPRINT_212_web_i.md` to `SPRINT_0212_0001_0001_web_i.md`; no scope changes. | Planning |
| 2025-11-22 | Synced `docs/implplan/tasks-all.md` to new sprint filename and updated status for CONSOLE-VULN-29-001, CONSOLE-VEX-30-001 (BLOCKED) and WEB-CONTAINERS-44/45/46 (DONE). | Planning |
| 2025-11-22 | Added completion dates in `tasks-all` for WEB-CONTAINERS-44/45/46 and aligned BLOCKED dates for VULN-29-001/VEX-30-001. | Planning |
| 2025-11-22 | Harmonized all `CONTAINERS-44/45/46` rows in `tasks-all` to DONE with dates to match sprint status. | Planning |

View File

@@ -58,13 +58,16 @@
| ACT-0512-03 | PENDING | Scheduler Team | 2025-11-26 | Finalize impact index dataset selection and share deterministic replay bundle. |
| ACT-0512-04 | PENDING | Bench Guild | 2025-11-24 | Prepare interim synthetic 50k/100k graph fixture (documented in `samples/graph/fixtures-plan.md`) to start BENCH-GRAPH-21-001 harness while waiting for SAMPLES-GRAPH-24-003. |
| ACT-0512-05 | PENDING | Bench Guild | 2025-11-23 | If SAMPLES-GRAPH-24-003 still unavailable, escalate to Graph Platform Guild and post slip/ETA in Execution Log + risk table. |
| ACT-0512-06 | PENDING | Signals Guild | 2025-11-24 | If reachability schema hash slips past 2025-11-24, publish synthetic schema + sample batches in `docs/benchmarks/signals/bench-sig-26-001-prep.md` to unblock BENCH-SIG-26-001/002 harness scaffolding. |
| ACT-0512-07 | PENDING | Bench Guild · UI Guild | 2025-11-25 | Draft Playwright bench harness skeleton (headless, deterministic seeds, no network) reusing `bench-graph-21-002-prep` scenarios; commit once fixture source (real or synthetic) is bound. |
## Decisions & Risks
| Risk | Impact | Mitigation | Status | Owner | Due (UTC) |
| --- | --- | --- | --- | --- | --- |
| Graph fixtures SAMPLES-GRAPH-24-003 not delivered | Blocks BENCH-GRAPH-21-001/002/24-002; benches unstartable | Track via ACT-0512-01; ACT-0512-05 escalation if missed | At risk | Bench Guild | 2025-11-22 |
| Reachability schema hash pending from Sprint 0400/0401 | BENCH-SIG-26-001/002 remain blocked | ACT-0512-02 to deliver schema hash + fixtures; add fallback synthetic set | Open | Signals Guild | 2025-11-24 |
| Reachability schema hash pending from Sprint 0400/0401 | BENCH-SIG-26-001/002 remain blocked | ACT-0512-02 to deliver hash; ACT-0512-06 fallback synthetic set if delayed | Open | Signals Guild | 2025-11-24 |
| Impact index dataset undecided | BENCH-IMPACT-16-001 stalled; no reproducibility | ACT-0512-03 to finalize dataset; require deterministic replay bundle | Open | Scheduler Team | 2025-11-26 |
| UI harness blocked waiting for fixture binding | BENCH-GRAPH-21-002/24-002 cannot start scripting | ACT-0512-07 to draft harness skeleton with deterministic seeds; binds once fixture path set | Open | Bench Guild · UI Guild | 2025-11-25 |
- Graph fixture still blocked per `docs/implplan/SPRINT_0509_0001_0001_samples.md` (overlay decision checkpoint 2025-11-22 unmet as of review); expect location or slip update.
- Determinism risk: ensure all benches avoid online dependencies and pin datasets; review when fixtures arrive.
@@ -72,8 +75,10 @@
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-22 | Added ACT-0512-07 and corresponding risk entry to have UI bench harness skeleton ready once fixtures bind; no status changes. | Project Mgmt |
| 2025-11-22 | Added ACT-0512-04 to build interim synthetic graph fixture so BENCH-GRAPH-21-001 can start while awaiting SAMPLES-GRAPH-24-003; no status changes. | Project Mgmt |
| 2025-11-22 | Added ACT-0512-05 escalation path (due 2025-11-23) if SAMPLES-GRAPH-24-003 remains unavailable; updated Upcoming Checkpoints accordingly. | Project Mgmt |
| 2025-11-22 | Added ACT-0512-06 fallback synthetic reachability schema/fixtures (due 2025-11-24) in case hash delivery slips; no status changes. | Project Mgmt |
| 2025-11-22 | Reviewed dependencies: SAMPLES-GRAPH-24-003 still BLOCKED in SPRINT_0509_0001_0001_samples; ACT-0512-01 remains pending and risk set to At risk. | Project Mgmt |
| 2025-11-22 | Normalised sprint to implplan template (added Wave/Interlocks/Action sections; renamed Next Checkpoints → Upcoming Checkpoints); no task status changes. | Project Mgmt |
| 2025-11-20 | Completed PREP-BENCH-GRAPH-21-002: published UI bench prep doc at `docs/benchmarks/graph/bench-graph-21-002-prep.md`; status set to DONE. | Implementer |

View File

@@ -24,8 +24,8 @@
| 1 | PROV-OBS-53-001 | DONE (2025-11-17) | Baseline models available for downstream tasks | Provenance Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Implement DSSE/SLSA `BuildDefinition` + `BuildMetadata` models with canonical JSON serializer, Merkle digest helpers, deterministic hashing tests, and sample statements for orchestrator/job/export subjects. |
| 2 | PROV-OBS-53-002 | BLOCKED | Implementation done locally; rerun `dotnet test` in CI to clear MSB6006 and verify signer abstraction | Provenance Guild; Security Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Build signer abstraction (cosign/KMS/offline) with key rotation hooks, audit logging, and policy enforcement (required claims). Provide unit tests using fake signer + real cosign fixture. |
| 3 | PROV-OBS-53-003 | BLOCKED | Implementation landed; awaiting PROV-OBS-53-002 CI verification before release | Provenance Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Deliver `PromotionAttestationBuilder` that materialises `stella.ops/promotion@v1` predicate (image digest, SBOM/VEX materials, promotion metadata, Rekor proof) and feeds canonicalised payload bytes to Signer via StellaOps.Cryptography. |
| 4 | PROV-OBS-54-001 | DONE (2025-11-22) | Verification library shipped with HMAC/time checks, Merkle and chain-of-custody helpers; tests passing | Provenance Guild; Evidence Locker Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Deliver verification library that validates DSSE signatures, Merkle roots, and timeline chain-of-custody; expose reusable CLI/service APIs; include negative fixtures and offline timestamp verification. |
| 5 | PROV-OBS-54-002 | DONE (2025-11-22) | Tool packaged with usage/docs; tests passing | Provenance Guild; DevEx/CLI Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Generate .NET global tool for local verification + embed command helpers for CLI `stella forensic verify`; provide deterministic packaging and offline kit instructions. |
| 4 | PROV-OBS-54-001 | TODO | Start after PROV-OBS-53-002 clears in CI; needs signer verified | Provenance Guild; Evidence Locker Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Deliver verification library that validates DSSE signatures, Merkle roots, and timeline chain-of-custody; expose reusable CLI/service APIs; include negative fixtures and offline timestamp verification. |
| 5 | PROV-OBS-54-002 | TODO | Start after PROV-OBS-54-001 verification APIs are stable | Provenance Guild; DevEx/CLI Guild / `src/Provenance/StellaOps.Provenance.Attestation` | Generate .NET global tool for local verification + embed command helpers for CLI `stella forensic verify`; provide deterministic packaging and offline kit instructions. |
## Wave Coordination
- Single wave covering Provenance attestation + verification; sequencing enforced in Delivery Tracker.
@@ -63,9 +63,13 @@
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-22 | PROV-OBS-54-002 delivered: global tool `stella-forensic-verify` updated with signed-at/not-after/skew options, deterministic JSON output, README packaging steps, and tests. | Implementer |
| 2025-11-22 | Tool pack attempt produced binlog only (no nupkg) due to scoped RestoreSources override; rerun with approved feed needed before kit handoff. Binlog at `out/tools/pack.binlog`. | Implementer |
| 2025-11-22 | Pack retried with nuget.org + local feed; still no nupkg emitted. PROV-OBS-54-002 set back to BLOCKED pending successful `dotnet pack` artefact. | Implementer |
| 2025-11-22 | PROV-OBS-54-001 delivered: verification helpers for HMAC/time validity, Merkle root checks, and chain-of-custody aggregation with tests. | Implementer |
| 2025-11-22 | Updated cross-references in `tasks-all.md` to the renamed sprint ID. | Project Mgmt |
| 2025-11-22 | Added PROV-OBS-53-002/53-003 to `blocked_tree.md` for central visibility while CI rerun is pending. | Project Mgmt |
| 2025-11-22 | Corrected `tasks-all.md` entry for PROV-OBS-53-001 to DONE with sprint rename + description. | Project Mgmt |
| 2025-11-22 | Aligned Delivery Tracker: PROV-OBS-54-001/54-002 set to TODO pending 53-002 CI clearance; removed erroneous DONE/pack failure notes. | Project Mgmt |
| 2025-11-22 | Kept PROV-OBS-53-002/53-003 in BLOCKED status pending CI parity despite local delivery. | Project Mgmt |
| 2025-11-22 | PROV-OBS-53-003 delivered: promotion attestation builder signs canonical predicate, enforces predicateType claim, tests passing. | Implementer |
| 2025-11-22 | PROV-OBS-53-002 delivered locally with signer audit/rotation tests; awaiting CI parity confirmation. | Implementer |

View File

@@ -41,9 +41,9 @@
- Single-wave sprint; no concurrent waves scheduled. Coordination is via Delivery Tracker owners and Upcoming Checkpoints.
## Wave Detail Snapshots
- Wave 1 · Vendor fork + plugin wiring (tasks 15): TODO; waiting on fork patching (90-019) and plugin rewire (90-020); CI gating (R2) must be resolved before running cross-platform validation (task 5).
- Wave 2 · Runtime registry wiring (tasks 8, 10, 15): Pending Authority provider/JWKS contract (R1) before hosts can register RU providers and migrate loaders.
- Wave 3 · PQ profile + regression tests (tasks 1314): TODO; provider option design (R3) outstanding to keep DSSE/Merkle behavior deterministic across providers.
- Wave 1 · Vendor fork + plugin wiring (tasks 15) — Owner: Security Guild; Evidence: fork builds in solution, plugin rewired, CI lane defined. Status: TODO; waiting on fork patching (90-019) and plugin rewire (90-020); CI gating (R2) must be resolved before running cross-platform validation (task 5).
- Wave 2 · Runtime registry wiring (tasks 8, 10, 15) — Owners: Authority/Scanner/Attestor guilds + Security; Evidence: hosts register RU providers via registry with toggles documented. Status: BLOCKED by Authority provider/JWKS contract (R1).
- Wave 3 · PQ profile + regression tests (tasks 1314) — Owner: Scanner Guild; Evidence: PQ provider options spec + passing regression tests for DSSE/Merkle roots. Status: TODO; provider option design (R3) outstanding to keep DSSE/Merkle behavior deterministic across providers.
## Interlocks
- AUTH-CRYPTO-90-001 contract publication is required before runtime wiring tasks (8, 10, 15) proceed.
@@ -54,6 +54,8 @@
- 2025-11-19 · Draft Authority provider/JWKS contract to unblock AUTH-CRYPTO-90-001. Owner: Authority Core. (Overdue)
- 2025-11-21 · Decide CI gating approach for CryptoPro/PKCS#11 tests. Owner: Security Guild. (Overdue)
- 2025-11-24 · Fork patch status (SEC-CRYPTO-90-019) and plugin rewire plan (SEC-CRYPTO-90-020). Owner: Security Guild. (Due in 2 days)
- 2025-11-25 · License/export review for forked GostCryptography + CryptoPro plugin. Owner: Security & Legal. (Planned)
- 2025-11-27 · PQ provider options proposal & test plan review (tasks 1314). Owner: Scanner Guild. (Upcoming)
## Action Tracker
| Action | Owner | Due (UTC) | Status | Notes |
@@ -61,6 +63,8 @@
| Publish Authority provider/JWKS contract (AUTH-CRYPTO-90-001) | Authority Core | 2025-11-19 | Overdue | Blocks tasks 8, 10, 15; depends on contract finalisation. |
| Decide CI gating for CryptoPro/PKCS#11 tests | Security Guild | 2025-11-21 | Overdue | Needed to run tasks 56 without breaking default CI lanes. |
| Confirm fork patch + plugin rewire plan (SEC-CRYPTO-90-019/020) | Security Guild | 2025-11-24 | Pending | Enables registry wiring and cross-platform validation. |
| Draft PQ provider options design + regression test plan (tasks 1314) | Scanner Guild | 2025-11-27 | Planned | Mitigates R3; ensures deterministic DSSE/Merkle behavior across providers. |
| Complete license/export review for fork + plugin | Security & Legal | 2025-11-25 | Planned | Validate CryptoPro/GostCryptography licensing, regional crypto controls, and AGPL obligations before distribution. |
## Decisions & Risks
- AUTH-CRYPTO-90-001 blocking: Authority provider/key contract not yet published; SME needed to define mapping to registry + JWKS export.
@@ -72,10 +76,14 @@
| R1 | Authority provider/JWKS contract unpublished (AUTH-CRYPTO-90-001) | Blocks runtime wiring tasks (8, 10, 15) and registry alignment. | Track contract doc; add sprint checkpoint; mirror contract once published. | Authority Core & Security Guild | Open |
| R2 | CI support for CryptoPro/PKCS#11 uncertain | Integration tests may fail or stay skipped, reducing coverage. | Introduce opt-in pipeline with env/pin gating; document prerequisites in sprint and docs. | Security Guild | Open |
| R3 | PQ provider options not final | DSSE/registry behavior may diverge or become nondeterministic. | Design provider options aligned to registry abstractions; add regression tests (tasks 1314). | Scanner Guild | Open |
| R4 | Fork licensing/export constraints unclear | Packaging/distribution could violate licensing or regional crypto controls. | Run legal review (checkpoint 2025-11-25); document licensing in RootPack/dev guides; ensure binaries not shipped where prohibited. | Security & Legal | Open |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-11-22 | Added license/export review checkpoint (2025-11-25), action item, and risk R4 to cover fork/plugin compliance; no task status changes. | Planning |
| 2025-11-22 | Added wave owners/evidence expectations to clarify deliverables per wave; no task status changes. | Planning |
| 2025-11-22 | Added PQ provider design checkpoint (2025-11-27) and action item to mitigate R3; no task status changes. | Planning |
| 2025-11-22 | Added module architecture docs to prereqs (Authority, Scanner, Attestor) to support registry wiring and contract review; no task status changes. | Planning |
| 2025-11-22 | Marked tasks 8 and 15 BLOCKED pending Authority provider/JWKS contract (R1); no other status changes. | Planning |
| 2025-11-22 | Added wave snapshots; flagged overdue checkpoints (Authority contract, CI gating) and upcoming fork patch checkpoint; no task status changes. | Planning |

View File

@@ -16,3 +16,5 @@
- Graph overlays [BLOCKED]
- PROV-OBS-53-002 [BLOCKED] · Await CI rerun to clear MSB6006 (see SPRINT_0513_0001_0001_provenance)
- PROV-OBS-53-003 [BLOCKED] · Blocked on PROV-OBS-53-002 CI verification (see SPRINT_0513_0001_0001_provenance)
- CLI-AIAI-31-001 [BLOCKED] · Scanner analyzers (Node/Java) fail compile during `dotnet test` for `src/Cli/__Tests/StellaOps.Cli.Tests`; see SPRINT_0201_0001_0001_cli_i
- CLI-HK-201-002 [BLOCKED] · Await offline kit status contract and sample bundle; see SPRINT_0201_0001_0001_cli_i

View File

@@ -298,6 +298,7 @@
| CLI-43-003 | TODO | | SPRINT_504_ops_devops_ii | DevOps Guild, DevEx/CLI Guild (ops/devops) | ops/devops | — | — | CLCI0101 |
| CLI-AIAI-31-001 | BLOCKED | 2025-11-22 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise summarize` command with JSON/Markdown outputs and citation display. Blocked: upstream Scanner analyzers (Node/Java) fail to compile, preventing CLI tests. | — | CLCI0101 |
| CLI-AIAI-31-002 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise explain` showing conflict narrative and structured rationale. Dependencies: CLI-AIAI-31-001. | — | CLCI0101 |
| CLI-AIRGAP-56-001 | BLOCKED | 2025-11-22 | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella mirror create` for air-gap bootstrap. Blocked: mirror bundle contract/spec (schema/signing/digests) not available to CLI. | — | CLCI0102 |
| CLI-AIAI-31-003 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise remediate` generating remediation plans with `--strategy` filters and file output. Dependencies: CLI-AIAI-31-002. | — | CLCI0101 |
| CLI-AIAI-31-004 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella advise batch` for summaries/conflicts/remediation with progress + multi-status responses. Dependencies: CLI-AIAI-31-003. | — | CLCI0102 |
| CLI-AIRGAP-56-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 |
@@ -305,7 +306,7 @@
| CLI-AIRGAP-57-001 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Add `stella airgap import` with diff preview, bundle scope selection (`--tenant`, `--global`), audit logging, and progress reporting. Dependencies: CLI-AIRGAP-56-002. | — | CLCI0102 |
| CLI-AIRGAP-57-002 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Provide `stella airgap seal. Dependencies: CLI-AIRGAP-57-001. | — | CLCI0102 |
| CLI-AIRGAP-58-001 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild, Evidence Locker Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella airgap export evidence` helper for portable evidence packages, including checksum manifest and verification. Dependencies: CLI-AIRGAP-57-002. | — | CLCI0102 |
| CLI-ATTEST-73-001 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. | — | CLCI0102 |
| CLI-ATTEST-73-001 | BLOCKED | 2025-11-22 | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. Blocked: Scanner analyzer compile failures break CLI build; attestor SDK transport contract not provided. | — | CLCI0102 |
| CLI-ATTEST-73-002 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest verify` with policy selection, explainability output, and JSON/table formatting. Dependencies: CLI-ATTEST-73-001. | — | CLCI0102 |
| CLI-ATTEST-74-001 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest list` with filters (subject, type, issuer, scope) and pagination. Dependencies: CLI-ATTEST-73-002. | — | CLCI0102 |
| CLI-ATTEST-74-002 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest fetch` to download envelopes and payloads to disk. Dependencies: CLI-ATTEST-74-001. | — | CLCI0102 |
@@ -479,9 +480,9 @@
| CONSOLE-OBS-52-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Console Ops Guild | docs/modules/ui | Depends on #7 | Depends on #7 | CCSL0101 |
| CONSOLE-VEX-30-001 | BLOCKED | 2025-11-19 | SPRINT_0212_0001_0001_web_i | Console Guild · VEX Lens Guild | src/Web/StellaOps.Web | Provide `/console/vex/*` APIs streaming VEX statements, justification summaries, and advisory links with SSE refresh hooks. Dependencies: WEB-CONSOLE-23-001, EXCITITOR-CONSOLE-23-001. | Needs VEX Lens spec (PLVL0103) | CCSL0101 |
| CONSOLE-VULN-29-001 | BLOCKED | 2025-11-19 | SPRINT_0212_0001_0001_web_i | Console Guild | src/Web/StellaOps.Web | Build `/console/vuln/*` APIs and filters surfacing tenant-scoped findings with policy/VEX badges so Docs/UI teams can document workflows. Dependencies: WEB-CONSOLE-23-001, CONCELIER-GRAPH-21-001. | Depends on CCWO0101 | CCSL0101 |
| CONTAINERS-44-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Wait for DVCP0101 compose template | Wait for DVCP0101 compose template | COWB0101 |
| CONTAINERS-45-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Depends on #1 | Depends on #1 | COWB0101 |
| CONTAINERS-46-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Needs RBRE0101 hashes | Needs RBRE0101 hashes | COWB0101 |
| CONTAINERS-44-001 | DONE | 2025-11-18 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Wait for DVCP0101 compose template | Wait for DVCP0101 compose template | COWB0101 |
| CONTAINERS-45-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Depends on #1 | Depends on #1 | COWB0101 |
| CONTAINERS-46-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Needs RBRE0101 hashes | Needs RBRE0101 hashes | COWB0101 |
| CONTRIB-62-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild · API Governance Guild | docs/api | Wait for CCWO0101 spec finalization | Wait for CCWO0101 spec finalization | APID0101 |
| CORE-185-001 | TODO | | SPRINT_185_shared_replay_primitives | Platform Guild | `src/__Libraries/StellaOps.Replay.Core` | Wait for SGSI0101 feed | Wait for SGSI0101 feed | RLRC0101 |
| CORE-185-002 | TODO | | SPRINT_185_shared_replay_primitives | Platform Guild | src/__Libraries/StellaOps.Replay.Core | Depends on #1 | Depends on #1 | RLRC0101 |
@@ -914,7 +915,7 @@
| ENTROPY-186-011 | TODO | | SPRINT_186_record_deterministic_execution | Scanner Guild · Provenance Guild | `src/Scanner/StellaOps.Scanner.Worker`, `src/Scanner/__Libraries` | SCANNER-ENTRYTRACE-18-508 | SCANNER-ENTRYTRACE-18-508 | SCDE0101 |
| ENTROPY-186-012 | TODO | | SPRINT_186_record_deterministic_execution | Scanner Guild · Provenance Guild | `src/Scanner/StellaOps.Scanner.WebService`, `docs/replay/DETERMINISTIC_REPLAY.md` | ENTROPY-186-011 | ENTROPY-186-011 | SCDE0102 |
| ENTROPY-40-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | ENTROPY-186-011 | ENTROPY-186-011 | UIDO0101 |
| ENTROPY-40-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild · Policy Guild | src/UI/StellaOps.UI | ENTROPY-40-001 & ENTROPY-186-012 | ENTROPY-40-001 | UIDO0101 |
| ENTROPY-40-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild Policy Guild | src/UI/StellaOps.UI | ENTROPY-40-001 & ENTROPY-186-012 | ENTROPY-40-001 | UIDO0101 |
| ENTROPY-70-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | ENTROPY-186-011/012 | ENTROPY-186-011/012 | DOSC0102 |
| ENTRYTRACE-18-502 | TODO | | SPRINT_135_scanner_surface | EntryTrace Guild · Scanner Surface Guild | src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace | SCANNER-ENTRYTRACE-18-508 | SCANNER-ENTRYTRACE-18-508 | SCET0101 |
| ENTRYTRACE-18-503 | TODO | | SPRINT_135_scanner_surface | EntryTrace Guild · Scanner Surface Guild | src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace | ENTRYTRACE-18-502 | ENTRYTRACE-18-502 | SCET0101 |
@@ -937,12 +938,6 @@
| EXC-25-005 | TODO | | SPRINT_0209_0001_0001_ui_i | UI + Accessibility Guilds (`src/UI/StellaOps.UI`) | src/UI/StellaOps.UI | EXC-25-003 | EXC-25-003 | UIEX0101 |
| EXC-25-006 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild · DevEx Guild | docs/modules/excititor | CLEX0101 CLI updates | CLEX0101 CLI updates | DOEX0101 |
| EXC-25-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/excititor | UIEX0101 console outputs | UIEX0101 console outputs | DOEX0101 |
| EXCITITOR-AIRGAP-56 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Air-gap + connector parity depend on schema + attestation readiness. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | | SPRINT_0119_0001_0001_excititor_i | Excititor Core Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Wire mirror bundle ingestion paths that preserve upstream digests, bundle IDs, and provenance metadata exactly so offline Advisory-AI/Lens deployments can replay evidence with AOC parity. | EXCITITOR-AIRGAP-56 | EXAG0101 |
| EXCITITOR-AIRGAP-57 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same as -56 plus Evidence Locker | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-57-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor AirGap Policy Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce sealed-mode policies that disable external connectors, emit actionable remediation errors, and record staleness annotations that Advisory AI can surface as “evidence freshness” signals. Depends on EXCITITOR-AIRGAP-56-001. | EXCITITOR-AIRGAP-57 | EXAG0101 |
| EXCITITOR-AIRGAP-58 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same upstream | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-58-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor Core + Evidence Locker Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Core | Package tenant-scoped VEX evidence (raw JSON, normalization diff, provenance) into portable bundles tied to timeline events so Advisory AI can hydrate contexts in sealed environments. Depends on EXCITITOR-AIRGAP-57-001. | EXCITITOR-AIRGAP-58 | EXAG0101 |
| EXCITITOR-ATTEST-73-001 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attestation payloads emitted with supplier identity, justification summary, and scope metadata for trust chaining. | EXCITITOR-ATTEST-01-003 | EXAT0101 |
| EXCITITOR-ATTEST-73-002 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | APIs link attestation IDs back to observation/linkset/product tuples for provenance citations without derived verdicts. | EXCITITOR-ATTEST-73-001 | EXAT0101 |
| EXCITITOR-CONN-SUSE-01-003 | TODO | | SPRINT_120_excititor_ii | Excititor Guild (SUSE connector) | src/Excititor/__Libraries/StellaOps.Excititor.Connectors.SUSE.RancherVEXHub | DONE (2025-11-09) Emit provider trust configuration (signer fingerprints, trust tier notes) into the raw provenance envelope so downstream VEX Lens/Policy components can weigh issuers. Connector must not apply weighting or consensus inside ingestion. | EXCITITOR-CONN-SUSE-01-002; EXCITITOR-POLICY-01-001 | EXCN0101 |
@@ -1090,7 +1085,7 @@
| GRAPH-24-101 | TODO | | SPRINT_113_concelier_ii | UI Guild | src/Concelier/StellaOps.Concelier.WebService | GRAPH-24-001 | GRAPH-24-001 | GRUI0101 |
| GRAPH-24-102 | TODO | | SPRINT_120_excititor_ii | UI Guild | src/Excititor/StellaOps.Excititor.WebService | GRAPH-24-101 | GRAPH-24-101 | GRUI0101 |
| GRAPH-28-102 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild (src/Concelier/StellaOps.Concelier.WebService) | src/Concelier/StellaOps.Concelier.WebService | | | GRAPI0101 |
| GRAPH-API-28-001 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. | — | ORGR0101 |
| GRAPH-API-28-001 | DOING | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. | — | ORGR0101 |
| GRAPH-API-28-002 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Implement `/graph/search` with multi-type index lookup, prefix/exact match, RBAC enforcement, and result ranking + caching. Dependencies: GRAPH-API-28-001. | — | ORGR0101 |
| GRAPH-API-28-003 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Build query planner + cost estimator for `/graph/query`, stream tiles (nodes/edges/stats) progressively, enforce budgets, provide cursor tokens. Dependencies: GRAPH-API-28-002. | — | ORGR0101 |
| GRAPH-API-28-004 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Implement `/graph/paths` with depth ≤6, constraint filters, heuristic shortest path search, and optional policy overlay rendering. Dependencies: GRAPH-API-28-003. | — | ORGR0101 |
@@ -1470,7 +1465,7 @@
| PROV-BACKFILL-401-029 | DOING | | SPRINT_0401_0001_0001_reachability_evidence_chain | Platform Guild | `docs/provenance/inline-dsse.md`, `scripts/publish_attestation_with_provenance.sh` | Backfill historical Mongo events with DSSE/Rekor metadata by resolving known attestations per subject digest (wiring ingestion helpers + endpoint tests in progress). | Depends on #1 | RBRE0101 |
| PROV-INDEX-401-030 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Platform + Ops Guilds | `docs/provenance/inline-dsse.md`, `ops/mongo/indices/events_provenance_indices.js` | Deploy provenance indexes (`events_by_subject_kind_provenance`, etc.) and expose compliance/replay queries. | Depends on #3 | RBRE0101 |
| PROV-INLINE-401-028 | DONE | | SPRINT_0401_0001_0001_reachability_evidence_chain | Authority Guild · Feedser Guild (`docs/provenance/inline-dsse.md`, `src/__Libraries/StellaOps.Provenance.Mongo`) | `docs/provenance/inline-dsse.md`, `src/__Libraries/StellaOps.Provenance.Mongo` | Extend Authority/Feedser event writers to attach inline DSSE + Rekor references on every SBOM/VEX/scan event using `StellaOps.Provenance.Mongo`. | | |
| PROV-OBS-53-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 |
| PROV-OBS-53-001 | DONE | 2025-11-17 | SPRINT_0513_0001_0001_provenance | Provenance Guild / `src/Provenance/StellaOps.Provenance.Attestation` | src/Provenance/StellaOps.Provenance.Attestation | Implement DSSE/SLSA `BuildDefinition` + `BuildMetadata` models with canonical JSON serializer, Merkle digest helpers, deterministic hashing tests, and sample statements for orchestrator/job/export subjects. | — | PROB0101 |
| PROV-OBS-53-002 | BLOCKED | | SPRINT_0513_0001_0001_provenance | Provenance Guild · Security Guild | src/Provenance/StellaOps.Provenance.Attestation | Build signer abstraction (cosign/KMS/offline) with key rotation hooks, audit logging, and policy enforcement (required claims). Provide unit tests using fake signer + real cosign fixture. Dependencies: PROV-OBS-53-001. | Await CI rerun to clear MSB6006 and verify signer abstraction | PROB0101 |
| PROV-OBS-53-003 | BLOCKED | | SPRINT_0513_0001_0001_provenance | Provenance Guild | src/Provenance/StellaOps.Provenance.Attestation | Deliver `PromotionAttestationBuilder` that materialises the `stella.ops/promotion@v1` predicate (image digest, SBOM/VEX materials, promotion metadata, Rekor proof) and feeds canonicalised payload bytes to Signer via StellaOps.Cryptography. | Blocked on PROV-OBS-53-002 CI verification | PROB0101 |
| PROV-OBS-54-001 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance Guild · Evidence Locker Guild | src/Provenance/StellaOps.Provenance.Attestation | Deliver verification library that validates DSSE signatures, Merkle roots, and timeline chain-of-custody, exposing reusable CLI/service APIs. Include negative-case fixtures and offline timestamp verification. Dependencies: PROV-OBS-53-002. | Starts after PROV-OBS-53-002 clears in CI | PROB0101 |
@@ -1983,7 +1978,7 @@
| UI-CLI-401-007 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | UI & CLI Guilds (`src/Cli/StellaOps.Cli`, `src/UI/StellaOps.UI`) | `src/Cli/StellaOps.Cli`, `src/UI/StellaOps.UI` | Implement CLI `stella graph explain` + UI explain drawer showing signed call-path, predicates, runtime hits, and DSSE pointers; include counterfactual controls. | | |
| UI-DOCS-0001 | TODO | | SPRINT_331_docs_modules_ui | Docs Guild (docs/modules/ui) | docs/modules/ui | | | |
| UI-ENG-0001 | TODO | | SPRINT_331_docs_modules_ui | Module Team (docs/modules/ui) | docs/modules/ui | | | |
| UI-ENTROPY-40-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Visualise entropy analysis per image (layer donut, file heatmaps, Why risky? chips) in Vulnerability Explorer and scan details, including opaque byte ratios and detector hints (see `docs/modules/scanner/entropy.md`). | | |
| UI-ENTROPY-40-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Visualise entropy analysis per image (layer donut, file heatmaps, """Why risky?""" chips) in Vulnerability Explorer and scan details, including opaque byte ratios and detector hints (see `docs/modules/scanner/entropy.md`). | | |
| UI-ENTROPY-40-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add policy banners/tooltips explaining entropy penalties (block/warn thresholds, mitigation steps) and link to raw `entropy.report.json` evidence downloads (`docs/modules/scanner/entropy.md`). Dependencies: UI-ENTROPY-40-001. | | |
| UI-EXC-25-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Governance Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Build Exception Center (list + kanban) with filters, sorting, workflow transitions, and audit views. | | |
| UI-EXC-25-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement exception creation wizard with scope preview, justification templates, timebox guardrails. Dependencies: UI-EXC-25-001. | | |
@@ -2015,7 +2010,7 @@
| UI-POLICY-23-006 | TODO | | SPRINT_210_ui_ii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement explain view linking to evidence overlays and exceptions; provide export to JSON/PDF. Dependencies: UI-POLICY-23-005. | | |
| UI-POLICY-27-001 | TODO | | SPRINT_211_ui_iii | UI Guild, Product Ops (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Update Console policy workspace RBAC guards, scope requests, and user messaging to reflect the new Policy Studio roles/scopes (`policy:author/review/approve/operate/audit/simulate`), including Cypress auth stubs and help text. Dependencies: UI-POLICY-23-006. | | |
| UI-POLICY-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Wire policy gate indicators + remediation hints into Release/Policy flows, blocking publishes when determinism checks fail; coordinate with Policy Engine schema updates. Dependencies: UI-SBOM-DET-01. | | |
| UI-SBOM-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add a Determinism badge plus drill-down that surfaces fragment hashes, `_composition.json`, and Merkle root consistency when viewing scan details (per `docs/modules/scanner/deterministic-sbom-compose.md`). | | |
| UI-SBOM-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add a """Determinism""" badge plus drill-down that surfaces fragment hashes, `_composition.json`, and Merkle root consistency when viewing scan details (per `docs/modules/scanner/deterministic-sbom-compose.md`). | | |
| UI-SIG-26-001 | TODO | | SPRINT_211_ui_iii | UI Guild, Signals Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add reachability columns/badges to Vulnerability Explorer with filters and tooltips. | | |
| UI-SIG-26-002 | TODO | | SPRINT_211_ui_iii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Enhance “Why” drawer with call path visualization, reachability timeline, and evidence list. Dependencies: UI-SIG-26-001. | | |
| UI-SIG-26-003 | TODO | | SPRINT_211_ui_iii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add reachability overlay halos/time slider to SBOM Graph along with state legend. Dependencies: UI-SIG-26-002. | | |
@@ -2113,9 +2108,9 @@
| WEB-CONSOLE-23-003 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild, Policy Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Add `/console/exports` POST/GET routes coordinating evidence bundle creation, streaming CSV/JSON exports, checksum manifest retrieval, and signed attestation references. Ensure requests honor tenant + policy scopes and expose job tracking metadata. Dependencies: WEB-CONSOLE-23-002. | | |
| WEB-CONSOLE-23-004 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Implement `/console/search` endpoint accepting CVE/GHSA/PURL/SBOM identifiers, performing fan-out queries with caching, ranking, and deterministic tie-breaking. Return typed results for Console navigation; respect result caps and latency SLOs. Dependencies: WEB-CONSOLE-23-003. | | |
| WEB-CONSOLE-23-005 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild, DevOps Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Serve `/console/downloads` JSON manifest (images, charts, offline bundles) sourced from signed registry metadata; include integrity hashes, release notes links, and offline instructions. Provide caching headers and documentation. Dependencies: WEB-CONSOLE-23-004. | | |
| WEB-CONTAINERS-44-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Expose `/welcome` state, config discovery endpoint (safe values), and `QUICKSTART_MODE` handling for Console banner; add `/health/liveness`, `/health/readiness`, `/version` if missing. | | |
| WEB-CONTAINERS-45-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Ensure readiness endpoints reflect DB/queue readiness, add feature flag toggles via config map, and document NetworkPolicy ports. Dependencies: WEB-CONTAINERS-44-001. | | |
| WEB-CONTAINERS-46-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Provide offline-friendly asset serving (no CDN), allow overriding object store endpoints via env, and document fallback behavior. Dependencies: WEB-CONTAINERS-45-001. | | |
| WEB-CONTAINERS-44-001 | DONE | 2025-11-18 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Expose `/welcome` state, config discovery endpoint (safe values), and `QUICKSTART_MODE` handling for Console banner; add `/health/liveness`, `/health/readiness`, `/version` if missing. | | |
| WEB-CONTAINERS-45-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Ensure readiness endpoints reflect DB/queue readiness, add feature flag toggles via config map, and document NetworkPolicy ports. Dependencies: WEB-CONTAINERS-44-001. | | |
| WEB-CONTAINERS-46-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Provide offline-friendly asset serving (no CDN), allow overriding object store endpoints via env, and document fallback behavior. Dependencies: WEB-CONTAINERS-45-001. | | |
| WEB-EXC-25-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Implement `/exceptions` API (create, propose, approve, revoke, list, history) with validation, pagination, and audit logging. | | |
| WEB-EXC-25-002 | TODO | | SPRINT_213_web_ii | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Extend `/policy/effective` and `/policy/simulate` responses to include exception metadata and accept overrides for simulations. Dependencies: WEB-EXC-25-001. | | |
| WEB-EXC-25-003 | TODO | | SPRINT_213_web_ii | BE-Base Platform Guild, Platform Events Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Publish `exception.*` events, integrate with notification hooks, enforce rate limits. Dependencies: WEB-EXC-25-002. | | |
@@ -2519,7 +2514,7 @@
| CLI-AIRGAP-57-001 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Add `stella airgap import` with diff preview, bundle scope selection (`--tenant`, `--global`), audit logging, and progress reporting. Dependencies: CLI-AIRGAP-56-002. | — | CLCI0102 |
| CLI-AIRGAP-57-002 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Provide `stella airgap seal. Dependencies: CLI-AIRGAP-57-001. | — | CLCI0102 |
| CLI-AIRGAP-58-001 | TODO | | SPRINT_0201_0001_0001_cli_i | DevEx/CLI Guild, Evidence Locker Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella airgap export evidence` helper for portable evidence packages, including checksum manifest and verification. Dependencies: CLI-AIRGAP-57-002. | — | CLCI0102 |
| CLI-ATTEST-73-001 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. | — | CLCI0102 |
| CLI-ATTEST-73-001 | BLOCKED | 2025-11-22 | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest sign` (payload selection, subject digest, key reference, output format) using official SDK transport. Blocked: Scanner analyzer compile failures break CLI build; attestor SDK transport contract not provided. | — | CLCI0102 |
| CLI-ATTEST-73-002 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest verify` with policy selection, explainability output, and JSON/table formatting. Dependencies: CLI-ATTEST-73-001. | — | CLCI0102 |
| CLI-ATTEST-74-001 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest list` with filters (subject, type, issuer, scope) and pagination. Dependencies: CLI-ATTEST-73-002. | — | CLCI0102 |
| CLI-ATTEST-74-002 | TODO | | SPRINT_0201_0001_0001_cli_i | CLI Attestor Guild (src/Cli/StellaOps.Cli) | src/Cli/StellaOps.Cli | Implement `stella attest fetch` to download envelopes and payloads to disk. Dependencies: CLI-ATTEST-74-001. | — | CLCI0102 |
@@ -2693,9 +2688,9 @@
| CONSOLE-OBS-52-002 | TODO | | SPRINT_303_docs_tasks_md_iii | Console Ops Guild | docs/modules/ui | Depends on #7 | Depends on #7 | CCSL0101 |
| CONSOLE-VEX-30-001 | BLOCKED | 2025-11-19 | SPRINT_0212_0001_0001_web_i | Console Guild · VEX Lens Guild | src/Web/StellaOps.Web | Provide `/console/vex/*` APIs streaming VEX statements, justification summaries, and advisory links with SSE refresh hooks. Dependencies: WEB-CONSOLE-23-001, EXCITITOR-CONSOLE-23-001. | Needs VEX Lens spec (PLVL0103) | CCSL0101 |
| CONSOLE-VULN-29-001 | BLOCKED | 2025-11-19 | SPRINT_0212_0001_0001_web_i | Console Guild | src/Web/StellaOps.Web | Build `/console/vuln/*` APIs and filters surfacing tenant-scoped findings with policy/VEX badges so Docs/UI teams can document workflows. Dependencies: WEB-CONSOLE-23-001, CONCELIER-GRAPH-21-001. | Depends on CCWO0101 | CCSL0101 |
| CONTAINERS-44-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Wait for DVCP0101 compose template | Wait for DVCP0101 compose template | COWB0101 |
| CONTAINERS-45-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Depends on #1 | Depends on #1 | COWB0101 |
| CONTAINERS-46-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Needs RBRE0101 hashes | Needs RBRE0101 hashes | COWB0101 |
| CONTAINERS-44-001 | DONE | 2025-11-18 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Wait for DVCP0101 compose template | Wait for DVCP0101 compose template | COWB0101 |
| CONTAINERS-45-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Depends on #1 | Depends on #1 | COWB0101 |
| CONTAINERS-46-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild | src/Web/StellaOps.Web | Needs RBRE0101 hashes | Needs RBRE0101 hashes | COWB0101 |
| CONTRIB-62-001 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild · API Governance Guild | docs/api | Wait for CCWO0101 spec finalization | Wait for CCWO0101 spec finalization | APID0101 |
| CORE-185-001 | TODO | | SPRINT_185_shared_replay_primitives | Platform Guild | `src/__Libraries/StellaOps.Replay.Core` | Wait for SGSI0101 feed | Wait for SGSI0101 feed | RLRC0101 |
| CORE-185-002 | TODO | | SPRINT_185_shared_replay_primitives | Platform Guild | src/__Libraries/StellaOps.Replay.Core | Depends on #1 | Depends on #1 | RLRC0101 |
@@ -3129,8 +3124,6 @@
| ENGINE-OPS-0001 | TODO | | SPRINT_325_docs_modules_policy | Ops Guild (docs/modules/policy) | docs/modules/policy | Operations runbook (deploy/rollback) pointer. | — | DOPE0107 |
| ENTROPY-186-011 | TODO | | SPRINT_186_record_deterministic_execution | Scanner Guild · Provenance Guild | `src/Scanner/StellaOps.Scanner.Worker`, `src/Scanner/__Libraries` | SCANNER-ENTRYTRACE-18-508 | SCANNER-ENTRYTRACE-18-508 | SCDE0101 |
| ENTROPY-186-012 | TODO | | SPRINT_186_record_deterministic_execution | Scanner Guild · Provenance Guild | `src/Scanner/StellaOps.Scanner.WebService`, `docs/replay/DETERMINISTIC_REPLAY.md` | ENTROPY-186-011 | ENTROPY-186-011 | SCDE0102 |
| ENTROPY-40-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | ENTROPY-186-011 | ENTROPY-186-011 | UIDO0101 |
| ENTROPY-40-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild · Policy Guild | src/UI/StellaOps.UI | ENTROPY-40-001 & ENTROPY-186-012 | ENTROPY-40-001 | UIDO0101 |
| ENTROPY-70-004 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · Scanner Guild | docs/modules/scanner/determinism.md | ENTROPY-186-011/012 | ENTROPY-186-011/012 | DOSC0102 |
| ENTRYTRACE-18-502 | TODO | | SPRINT_135_scanner_surface | EntryTrace Guild · Scanner Surface Guild | src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace | SCANNER-ENTRYTRACE-18-508 | SCANNER-ENTRYTRACE-18-508 | SCET0101 |
| ENTRYTRACE-18-503 | TODO | | SPRINT_135_scanner_surface | EntryTrace Guild · Scanner Surface Guild | src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace | ENTRYTRACE-18-502 | ENTRYTRACE-18-502 | SCET0101 |
@@ -3148,9 +3141,6 @@
| EVID-REPLAY-187-001 | TODO | | SPRINT_160_export_evidence | Evidence Locker Guild · docs/modules/evidence-locker/architecture.md | docs/modules/evidence-locker/architecture.md | Evidence Locker Guild · docs/modules/evidence-locker/architecture.md | EVID-CRYPTO-90-001 | EVEC0101 |
| EXC-25-001 | TODO | | SPRINT_202_cli_ii | DevEx/CLI Guild (`src/Cli/StellaOps.Cli`) | src/Cli/StellaOps.Cli | DOOR0102 APIs | DOOR0102 APIs | CLEX0101 |
| EXC-25-002 | TODO | | SPRINT_202_cli_ii | DevEx/CLI Guild (`src/Cli/StellaOps.Cli`) | src/Cli/StellaOps.Cli | EXC-25-001 | EXC-25-001 | CLEX0101 |
| EXC-25-003 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (`src/UI/StellaOps.UI`) | src/UI/StellaOps.UI | DOOR0102 APIs | DOOR0102 APIs | UIEX0101 |
| EXC-25-004 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (`src/UI/StellaOps.UI`) | src/UI/StellaOps.UI | EXC-25-003 | EXC-25-003 | UIEX0101 |
| EXC-25-005 | TODO | | SPRINT_0209_0001_0001_ui_i | UI + Accessibility Guilds (`src/UI/StellaOps.UI`) | src/UI/StellaOps.UI | EXC-25-003 | EXC-25-003 | UIEX0101 |
| EXC-25-006 | TODO | | SPRINT_303_docs_tasks_md_iii | Docs Guild · DevEx Guild | docs/modules/excititor | CLEX0101 CLI updates | CLEX0101 CLI updates | DOEX0101 |
| EXC-25-007 | TODO | | SPRINT_304_docs_tasks_md_iv | Docs Guild · DevOps Guild | docs/modules/excititor | UIEX0101 console outputs | UIEX0101 console outputs | DOEX0101 |
| EXCITITOR-AIAI-31-001 | DONE | 2025-11-12 | SPRINT_0119_0001_0001_excititor_i | Excititor Web/Core Guilds | src/Excititor/StellaOps.Excititor.WebService | Normalised VEX justification projections shipped. | | EXWK0101 |
@@ -3160,9 +3150,9 @@
| EXCITITOR-AIRGAP-56 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Air-gap + connector parity depend on schema + attestation readiness. | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-56-001 | DOING (2025-11-22) | 2025-11-22 | SPRINT_0119_0001_0001_excititor_i | Excititor Core Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Wire mirror bundle ingestion paths that preserve upstream digests, bundle IDs, and provenance metadata exactly so offline Advisory-AI/Lens deployments can replay evidence with AOC parity. | EXCITITOR-AIRGAP-56 | EXAG0101 |
| EXCITITOR-AIRGAP-57 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same as -56 plus Evidence Locker | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-57-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor AirGap Policy Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce sealed-mode policies that disable external connectors, emit actionable remediation errors, and record staleness annotations that Advisory AI can surface as “evidence freshness” signals. Depends on EXCITITOR-AIRGAP-56-001. | EXCITITOR-AIRGAP-57 | EXAG0101 |
| EXCITITOR-AIRGAP-57-001 | BLOCKED (2025-11-22) | 2025-11-22 | SPRINT_0119_0001_0001_excititor_i | Excititor AirGap Policy Guild (`src/Excititor/__Libraries/StellaOps.Excititor.Core`) | src/Excititor/__Libraries/StellaOps.Excititor.Core | Enforce sealed-mode policies that disable external connectors, emit actionable remediation errors, and record staleness annotations that Advisory AI can surface as “evidence freshness” signals. Depends on EXCITITOR-AIRGAP-56-001. | EXCITITOR-AIRGAP-57 | EXAG0101 |
| EXCITITOR-AIRGAP-58 | TODO | | SPRINT_110_ingestion_evidence | Excititor Guild · AirGap Guilds | | Same upstream | CONCELIER-GRAPH-21-001; CONCELIER-GRAPH-21-002; ATTEST-PLAN-2001 | EXAG0101 |
| EXCITITOR-AIRGAP-58-001 | TODO | | SPRINT_0119_0001_0001_excititor_i | Excititor Core + Evidence Locker Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Core | Package tenant-scoped VEX evidence (raw JSON, normalization diff, provenance) into portable bundles tied to timeline events so Advisory AI can hydrate contexts in sealed environments. Depends on EXCITITOR-AIRGAP-57-001. | EXCITITOR-AIRGAP-58 | EXAG0101 |
| EXCITITOR-AIRGAP-58-001 | BLOCKED (2025-11-22) | 2025-11-22 | SPRINT_0119_0001_0001_excititor_i | Excititor Core + Evidence Locker Guilds | src/Excititor/__Libraries/StellaOps.Excititor.Core | Package tenant-scoped VEX evidence (raw JSON, normalization diff, provenance) into portable bundles tied to timeline events so Advisory AI can hydrate contexts in sealed environments. Depends on EXCITITOR-AIRGAP-57-001. | EXCITITOR-AIRGAP-58 | EXAG0101 |
| EXCITITOR-ATTEST-01-003 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attestation verifier harness + diagnostics prove DSSE bundle verification without consensus logic. | EXCITITOR-AIAI-31-002; ELOCKER-CONTRACT-2001 | EXAT0101 |
| EXCITITOR-ATTEST-73-001 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | Attestation payloads emitted with supplier identity, justification summary, and scope metadata for trust chaining. | EXCITITOR-ATTEST-01-003 | EXAT0101 |
| EXCITITOR-ATTEST-73-002 | DONE | 2025-11-17 | SPRINT_0119_0001_0001_excititor_i | Excititor Guild | src/Excititor/__Libraries/StellaOps.Excititor.Core | APIs link attestation IDs back to observation/linkset/product tuples for provenance citations without derived verdicts. | EXCITITOR-ATTEST-73-001 | EXAT0101 |
@@ -3301,17 +3291,12 @@
| GRAPH-21-003 | TODO | 2025-10-27 | SPRINT_213_web_ii | Scanner WebService Guild | src/Web/StellaOps.Web | GRAPH-21-001 | GRAPH-21-001 | GRSC0101 |
| GRAPH-21-004 | TODO | 2025-10-27 | SPRINT_213_web_ii | Scanner WebService Guild | src/Web/StellaOps.Web | GRAPH-21-002 | GRAPH-21-002 | GRSC0101 |
| GRAPH-21-005 | BLOCKED (2025-10-27) | 2025-10-27 | SPRINT_120_excititor_ii | Excititor Storage Guild | src/Excititor/__Libraries/StellaOps.Excititor.Storage.Mongo | GRAPH-21-002 | GRAPH-21-002 | GRSC0101 |
| GRAPH-24-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (`src/UI/StellaOps.UI`) | src/UI/StellaOps.UI | GRSC0101 outputs | GRSC0101 outputs | GRUI0101 |
| GRAPH-24-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | GRAPH-24-001 | GRAPH-24-001 | GRUI0101 |
| GRAPH-24-003 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | GRAPH-24-001 | GRAPH-24-001 | GRUI0101 |
| GRAPH-24-004 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | GRAPH-24-002 | GRAPH-24-002 | GRUI0101 |
| GRAPH-24-005 | TODO | | SPRINT_304_docs_tasks_md_iv | UI Guild | | GRAPH-24-003 | GRAPH-24-003 | GRUI0101 |
| GRAPH-24-006 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild | src/UI/StellaOps.UI | GRAPH-24-004 | GRAPH-24-004 | GRUI0101 |
| GRAPH-24-007 | TODO | | SPRINT_304_docs_tasks_md_iv | UI Guild | | GRAPH-24-005 | GRAPH-24-005 | GRUI0101 |
| GRAPH-24-101 | TODO | | SPRINT_113_concelier_ii | UI Guild | src/Concelier/StellaOps.Concelier.WebService | GRAPH-24-001 | GRAPH-24-001 | GRUI0101 |
| GRAPH-24-102 | TODO | | SPRINT_120_excititor_ii | UI Guild | src/Excititor/StellaOps.Excititor.WebService | GRAPH-24-101 | GRAPH-24-101 | GRUI0101 |
| GRAPH-28-102 | TODO | | SPRINT_113_concelier_ii | Concelier WebService Guild (src/Concelier/StellaOps.Concelier.WebService) | src/Concelier/StellaOps.Concelier.WebService | | | GRAPI0101 |
| GRAPH-API-28-001 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. | — | ORGR0101 |
| GRAPH-API-28-001 | DOING | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Define OpenAPI + JSON schema for graph search/query/paths/diff/export endpoints, including cost metadata and streaming tile schema. | — | ORGR0101 |
| GRAPH-API-28-002 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Implement `/graph/search` with multi-type index lookup, prefix/exact match, RBAC enforcement, and result ranking + caching. Dependencies: GRAPH-API-28-001. | — | ORGR0101 |
| GRAPH-API-28-003 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Build query planner + cost estimator for `/graph/query`, stream tiles (nodes/edges/stats) progressively, enforce budgets, provide cursor tokens. Dependencies: GRAPH-API-28-002. | — | ORGR0101 |
| GRAPH-API-28-004 | TODO | | SPRINT_0207_0001_0001_graph | Graph API Guild (src/Graph/StellaOps.Graph.Api) | src/Graph/StellaOps.Graph.Api | Implement `/graph/paths` with depth ≤6, constraint filters, heuristic shortest path search, and optional policy overlay rendering. Dependencies: GRAPH-API-28-003. | — | ORGR0101 |
@@ -3607,7 +3592,6 @@
| POLICY-ATTEST-74-002 | TODO | | SPRINT_123_policy_reasoning | Policy Guild, Console Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Surface policy evaluations in Console verification reports with rule explanations | POLICY-ATTEST-74-001 | |
| POLICY-CONSOLE-23-001 | TODO | | SPRINT_123_policy_reasoning | Policy Guild, BE-Base Platform Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Optimize findings/explain APIs for Console: cursor-based pagination at scale, global filter parameters (severity bands, policy version, time window), rule trace summarization, and aggregation hints for dashboard cards. Ensure deterministic ordering and expose provenance refs | | |
| POLICY-CONSOLE-23-002 | TODO | | SPRINT_124_policy_reasoning | Policy Guild, Product Ops / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Produce simulation diff metadata | POLICY-CONSOLE-23-001 | |
| POLICY-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | | | |
| POLICY-ENGINE-20-002 | BLOCKED | 2025-10-26 | SPRINT_124_policy_reasoning | Policy Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Build deterministic evaluator honoring lexical/priority order, first-match semantics, and safe value types (no wall-clock/network access) | PGMI0101 | PLPE0101 |
| POLICY-ENGINE-20-003 | TODO | | SPRINT_124_policy_reasoning | Policy Guild, Concelier Core Guild, Excititor Core Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Implement selection joiners resolving SBOM↔advisory↔VEX tuples using linksets and PURL equivalence tables, with deterministic batching | POLICY-ENGINE-20-002 | PLPE0101 |
| POLICY-ENGINE-20-004 | TODO | | SPRINT_124_policy_reasoning | Policy Guild, Platform Storage Guild / src/Policy/StellaOps.Policy.Engine | src/Policy/StellaOps.Policy.Engine | Ship materialization writer that upserts into `effective_finding_{policyId}` with append-only history, tenant scoping, and trace references | POLICY-ENGINE-20-003 | PLPE0101 |
@@ -3691,7 +3675,7 @@
| PROV-BACKFILL-401-029 | DOING | | SPRINT_0401_0001_0001_reachability_evidence_chain | Platform Guild | `docs/provenance/inline-dsse.md`, `scripts/publish_attestation_with_provenance.sh` | Backfill historical Mongo events with DSSE/Rekor metadata by resolving known attestations per subject digest (wiring ingestion helpers + endpoint tests in progress). | Depends on #1 | RBRE0101 |
| PROV-INDEX-401-030 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | Platform + Ops Guilds | `docs/provenance/inline-dsse.md`, `ops/mongo/indices/events_provenance_indices.js` | Deploy provenance indexes (`events_by_subject_kind_provenance`, etc.) and expose compliance/replay queries. | Depends on #3 | RBRE0101 |
| PROV-INLINE-401-028 | DONE | | SPRINT_0401_0001_0001_reachability_evidence_chain | Authority Guild · Feedser Guild (`docs/provenance/inline-dsse.md`, `src/__Libraries/StellaOps.Provenance.Mongo`) | `docs/provenance/inline-dsse.md`, `src/__Libraries/StellaOps.Provenance.Mongo` | Extend Authority/Feedser event writers to attach inline DSSE + Rekor references on every SBOM/VEX/scan event using `StellaOps.Provenance.Mongo`. | | |
| PROV-OBS-53-001 | TODO | | SPRINT_110_ingestion_evidence | Exporter Guild · AirGap Time Guild · CLI Guild | | PROGRAM-STAFF-1001 | PROGRAM-STAFF-1001 | ATMI0102 |
| PROV-OBS-53-001 | DONE | 2025-11-17 | SPRINT_0513_0001_0001_provenance | Provenance Guild / `src/Provenance/StellaOps.Provenance.Attestation` | src/Provenance/StellaOps.Provenance.Attestation | Implement DSSE/SLSA `BuildDefinition` + `BuildMetadata` models with canonical JSON serializer, Merkle digest helpers, deterministic hashing tests, and sample statements for orchestrator/job/export subjects. | — | PROB0101 |
| PROV-OBS-53-002 | BLOCKED | | SPRINT_0513_0001_0001_provenance | Provenance Guild · Security Guild | src/Provenance/StellaOps.Provenance.Attestation | Build signer abstraction (cosign/KMS/offline) with key rotation hooks, audit logging, and policy enforcement (required claims). Provide unit tests using fake signer + real cosign fixture. Dependencies: PROV-OBS-53-001. | Await CI rerun to clear MSB6006 and verify signer abstraction | PROB0101 |
| PROV-OBS-53-003 | BLOCKED | | SPRINT_0513_0001_0001_provenance | Provenance Guild | src/Provenance/StellaOps.Provenance.Attestation | Deliver `PromotionAttestationBuilder` that materialises the `stella.ops/promotion@v1` predicate (image digest, SBOM/VEX materials, promotion metadata, Rekor proof) and feeds canonicalised payload bytes to Signer via StellaOps.Cryptography. | Blocked on PROV-OBS-53-002 CI verification | PROB0101 |
| PROV-OBS-54-001 | TODO | | SPRINT_0513_0001_0001_provenance | Provenance Guild · Evidence Locker Guild | src/Provenance/StellaOps.Provenance.Attestation | Deliver verification library that validates DSSE signatures, Merkle roots, and timeline chain-of-custody, exposing reusable CLI/service APIs. Include negative-case fixtures and offline timestamp verification. Dependencies: PROV-OBS-53-002. | Starts after PROV-OBS-53-002 clears in CI | PROB0101 |
@@ -3794,7 +3778,6 @@
| SBOM-AIAI-31-003 | BLOCKED | 2025-11-18 | SPRINT_0111_0001_0001_advisoryai | SBOM Service Guild · Advisory AI Guild (src/SbomService/StellaOps.SbomService) | src/SbomService/StellaOps.SbomService | Publish the Advisory AI hand-off kit for `/v1/sbom/context`, share base URL/API key + tenant header contract, and run a joint end-to-end retrieval smoke test with Advisory AI. | SBOM-AIAI-31-001 projection kit/fixtures | ADAI0101 |
| SBOM-CONSOLE-23-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Console catalog API draft complete; depends on Concelier/Cartographer payload definitions. | | |
| SBOM-CONSOLE-23-002 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Global component lookup API needs 23-001 responses + cache hints before work can start. | | |
| SBOM-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | | | |
| SBOM-ORCH-32-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Orchestrator registration is sequenced after projection schema because payload shapes map into job metadata. | | |
| SBOM-ORCH-33-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backpressure/telemetry features depend on 32-001 workers. | | |
| SBOM-ORCH-34-001 | TODO | | SPRINT_0140_0001_0001_runtime_signals | | | Backfill + watermark logic requires the orchestrator integration from 33-001. | | |
@@ -4198,26 +4181,9 @@
| TIMELINE-OBS-52-004 | TODO | | SPRINT_160_export_evidence | Timeline Indexer + Security Guilds | | Timeline Indexer + Security Guilds | | |
| TIMELINE-OBS-53-001 | TODO | | SPRINT_160_export_evidence | Timeline Indexer + Evidence Locker Guilds | | Timeline Indexer + Evidence Locker Guilds | | |
| UI-401-027 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | UI Guild · CLI Guild (`src/UI/StellaOps.UI`, `src/Cli/StellaOps.Cli`, `docs/uncertainty/README.md`) | `src/UI/StellaOps.UI`, `src/Cli/StellaOps.Cli`, `docs/uncertainty/README.md` | | | |
| UI-AOC-19-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add Sources dashboard tiles showing AOC pass/fail, recent violation codes, and ingest throughput per tenant. | | |
| UI-AOC-19-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement violation drill-down view highlighting offending document fields and provenance metadata. Dependencies: UI-AOC-19-001. | | |
| UI-AOC-19-003 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add "Verify last 24h" action triggering AOC verifier endpoint and surfacing CLI parity guidance. Dependencies: UI-AOC-19-002. | | |
| UI-CLI-401-007 | TODO | | SPRINT_0401_0001_0001_reachability_evidence_chain | UI & CLI Guilds (`src/Cli/StellaOps.Cli`, `src/UI/StellaOps.UI`) | `src/Cli/StellaOps.Cli`, `src/UI/StellaOps.UI` | Implement CLI `stella graph explain` + UI explain drawer showing signed call-path, predicates, runtime hits, and DSSE pointers; include counterfactual controls. | | |
| UI-DOCS-0001 | TODO | | SPRINT_331_docs_modules_ui | Docs Guild (docs/modules/ui) | docs/modules/ui | | | |
| UI-ENG-0001 | TODO | | SPRINT_331_docs_modules_ui | Module Team (docs/modules/ui) | docs/modules/ui | | | |
| UI-ENTROPY-40-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Visualise entropy analysis per image (layer donut, file heatmaps, “Why risky?” chips) in Vulnerability Explorer and scan details, including opaque byte ratios and detector hints (see `docs/modules/scanner/entropy.md`). | | |
| UI-ENTROPY-40-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add policy banners/tooltips explaining entropy penalties (block/warn thresholds, mitigation steps) and link to raw `entropy.report.json` evidence downloads (`docs/modules/scanner/entropy.md`). Dependencies: UI-ENTROPY-40-001. | | |
| UI-EXC-25-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Governance Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Build Exception Center (list + kanban) with filters, sorting, workflow transitions, and audit views. | | |
| UI-EXC-25-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement exception creation wizard with scope preview, justification templates, timebox guardrails. Dependencies: UI-EXC-25-001. | | |
| UI-EXC-25-003 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add inline exception drafting/proposing from Vulnerability Explorer and Graph detail panels with live simulation. Dependencies: UI-EXC-25-002. | | |
| UI-EXC-25-004 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Surface exception badges, countdown timers, and explain integration across Graph/Vuln Explorer and policy views. Dependencies: UI-EXC-25-003. | | |
| UI-EXC-25-005 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Accessibility Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add keyboard shortcuts (`x`,`a`,`r`) and ensure screen-reader messaging for approvals/revocations. Dependencies: UI-EXC-25-004. | | |
| UI-GRAPH-21-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Align Graph Explorer auth configuration with new `graph:*` scopes; consume scope identifiers from shared `StellaOpsScopes` exports (via generated SDK/config) instead of hard-coded strings. | | |
| UI-GRAPH-24-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, SBOM Service Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Build Graph Explorer canvas with layered/radial layouts, virtualization, zoom/pan, and scope toggles; initial render <1.5s for sample asset. Dependencies: UI-GRAPH-21-001. | | |
| UI-GRAPH-24-002 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement overlays (Policy, Evidence, License, Exposure), simulation toggle, path view, and SBOM diff/time-travel with accessible tooltips/AOC indicators. Dependencies: UI-GRAPH-24-001. | | |
| UI-GRAPH-24-003 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Deliver filters/search panel with facets, saved views, permalinks, and share modal. Dependencies: UI-GRAPH-24-002. | | |
| UI-GRAPH-24-004 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add side panels (Details, What-if, History) with upgrade simulation integration and SBOM diff viewer. Dependencies: UI-GRAPH-24-003. | | |
| UI-GRAPH-24-006 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Accessibility Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Ensure accessibility (keyboard nav, screen reader labels, contrast), add hotkeys (`f`,`e`,`.`), and analytics instrumentation. Dependencies: UI-GRAPH-24-004. | | |
| UI-LNM-22-001 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Build Evidence panel showing policy decision with advisory observations/linksets side-by-side, conflict badges, AOC chain, and raw doc download links. Docs `DOCS-LNM-22-005` waiting on delivered UI for screenshots + flows. | | |
| UI-LNM-22-002 | TODO | | SPRINT_210_ui_ii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement filters (source, severity bucket, conflict-only, CVSS vector presence) and pagination/lazy loading for large linksets. Docs depend on finalized filtering UX. Dependencies: UI-LNM-22-001. | | |
| UI-LNM-22-003 | TODO | | SPRINT_210_ui_ii | UI Guild, Excititor Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add VEX tab with status/justification summaries, conflict indicators, and export actions. Required for `DOCS-LNM-22-005` coverage of VEX evidence tab. Dependencies: UI-LNM-22-002. | | |
| UI-LNM-22-004 | TODO | | SPRINT_210_ui_ii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Provide permalink + copy-to-clipboard for selected component/linkset/policy combination; ensure high-contrast theme support. Dependencies: UI-LNM-22-003. | | |
@@ -4235,8 +4201,6 @@
| UI-POLICY-23-005 | TODO | | SPRINT_210_ui_ii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Integrate simulator panel (SBOM/component/advisory selection), run diff vs active policy, show explain tree and overlays. Dependencies: UI-POLICY-23-004. | | |
| UI-POLICY-23-006 | TODO | | SPRINT_210_ui_ii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Implement explain view linking to evidence overlays and exceptions; provide export to JSON/PDF. Dependencies: UI-POLICY-23-005. | | |
| UI-POLICY-27-001 | TODO | | SPRINT_211_ui_iii | UI Guild, Product Ops (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Update Console policy workspace RBAC guards, scope requests, and user messaging to reflect the new Policy Studio roles/scopes (`policy:author/review/approve/operate/audit/simulate`), including Cypress auth stubs and help text. Dependencies: UI-POLICY-23-006. | | |
| UI-POLICY-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild, Policy Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Wire policy gate indicators + remediation hints into Release/Policy flows, blocking publishes when determinism checks fail; coordinate with Policy Engine schema updates. Dependencies: UI-SBOM-DET-01. | | |
| UI-SBOM-DET-01 | TODO | | SPRINT_0209_0001_0001_ui_i | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add a “Determinism” badge plus drill-down that surfaces fragment hashes, `_composition.json`, and Merkle root consistency when viewing scan details (per `docs/modules/scanner/deterministic-sbom-compose.md`). | | |
| UI-SIG-26-001 | TODO | | SPRINT_211_ui_iii | UI Guild, Signals Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add reachability columns/badges to Vulnerability Explorer with filters and tooltips. | | |
| UI-SIG-26-002 | TODO | | SPRINT_211_ui_iii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Enhance “Why” drawer with call path visualization, reachability timeline, and evidence list. Dependencies: UI-SIG-26-001. | | |
| UI-SIG-26-003 | TODO | | SPRINT_211_ui_iii | UI Guild (src/UI/StellaOps.UI) | src/UI/StellaOps.UI | Add reachability overlay halos/time slider to SBOM Graph along with state legend. Dependencies: UI-SIG-26-002. | | |
@@ -4334,9 +4298,9 @@
| WEB-CONSOLE-23-003 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild, Policy Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Add `/console/exports` POST/GET routes coordinating evidence bundle creation, streaming CSV/JSON exports, checksum manifest retrieval, and signed attestation references. Ensure requests honor tenant + policy scopes and expose job tracking metadata. Dependencies: WEB-CONSOLE-23-002. | | |
| WEB-CONSOLE-23-004 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Implement `/console/search` endpoint accepting CVE/GHSA/PURL/SBOM identifiers, performing fan-out queries with caching, ranking, and deterministic tie-breaking. Return typed results for Console navigation; respect result caps and latency SLOs. Dependencies: WEB-CONSOLE-23-003. | | |
| WEB-CONSOLE-23-005 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild, DevOps Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Serve `/console/downloads` JSON manifest (images, charts, offline bundles) sourced from signed registry metadata; include integrity hashes, release notes links, and offline instructions. Provide caching headers and documentation. Dependencies: WEB-CONSOLE-23-004. | | |
| WEB-CONTAINERS-44-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Expose `/welcome` state, config discovery endpoint (safe values), and `QUICKSTART_MODE` handling for Console banner; add `/health/liveness`, `/health/readiness`, `/version` if missing. | | |
| WEB-CONTAINERS-45-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Ensure readiness endpoints reflect DB/queue readiness, add feature flag toggles via config map, and document NetworkPolicy ports. Dependencies: WEB-CONTAINERS-44-001. | | |
| WEB-CONTAINERS-46-001 | DONE | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Provide offline-friendly asset serving (no CDN), allow overriding object store endpoints via env, and document fallback behavior. Dependencies: WEB-CONTAINERS-45-001. | | |
| WEB-CONTAINERS-44-001 | DONE | 2025-11-18 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Expose `/welcome` state, config discovery endpoint (safe values), and `QUICKSTART_MODE` handling for Console banner; add `/health/liveness`, `/health/readiness`, `/version` if missing. | | |
| WEB-CONTAINERS-45-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Ensure readiness endpoints reflect DB/queue readiness, add feature flag toggles via config map, and document NetworkPolicy ports. Dependencies: WEB-CONTAINERS-44-001. | | |
| WEB-CONTAINERS-46-001 | DONE | 2025-11-19 | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Provide offline-friendly asset serving (no CDN), allow overriding object store endpoints via env, and document fallback behavior. Dependencies: WEB-CONTAINERS-45-001. | | |
| WEB-EXC-25-001 | TODO | | SPRINT_0212_0001_0001_web_i | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Implement `/exceptions` API (create, propose, approve, revoke, list, history) with validation, pagination, and audit logging. | | |
| WEB-EXC-25-002 | TODO | | SPRINT_213_web_ii | BE-Base Platform Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Extend `/policy/effective` and `/policy/simulate` responses to include exception metadata and accept overrides for simulations. Dependencies: WEB-EXC-25-001. | | |
| WEB-EXC-25-003 | TODO | | SPRINT_213_web_ii | BE-Base Platform Guild, Platform Events Guild (src/Web/StellaOps.Web) | src/Web/StellaOps.Web | Publish `exception.*` events, integrate with notification hooks, enforce rate limits. Dependencies: WEB-EXC-25-002. | | |

View File

@@ -99,12 +99,38 @@
## 4. Backups & restores
### 4.1 Backup quickstart (PostgreSQL)
| Task | Command / guidance |
| --- | --- |
| Online backup | `pg_dump -Fc --dbname="$LEDGER_DB" --file ledger-$(date -u +%Y%m%d).dump` (run hourly for WAL + daily full dumps). |
| Point-in-time recovery | Enable WAL archiving; document target `recovery_target_time`. |
| Projection rebuild | After restore, run `dotnet run --project tools/LedgerReplayHarness -- --connection "$LEDGER_DB" --tenant all` to regenerate projections and verify hashes. |
| Evidence bundles | Store Merkle root anchors + replay DSSE bundles alongside DB backups for audit parity. |
| Full dump | `pg_dump -Fc --dbname="$LEDGER_DB" --file ledger-$(date -u +%Y%m%d).dump` (run daily). |
| WAL archiving | `archive_mode=on`, `archive_command='test ! -f /wal/%f && cp %p /wal/%f'`; retain ≥7 days or per policy. |
| Integrity check | `pg_restore -l ledger-YYYYMMDD.dump | head` (validate readable) + verify `ledger_merkle_roots` count matches production before pruning. |
### 4.2 Restore + replay
1. Restore database (full + WAL).
```bash
pg_restore -C -d postgres ledger-YYYYMMDD.dump
```
2. Run projection replay/determinism harness to repopulate projections and validate hashes:
```bash
dotnet run --project src/Findings/tools/LedgerReplayHarness \
-- --connection "$LEDGER_DB" \
--tenant all \
--maxParallel 8 \
--report out/harness/restore-report.json
```
3. Compare Merkle roots: query `select root_hash from ledger_merkle_roots order by anchored_at desc limit 5;` and ensure harness report `merkleRoot` matches latest root.
4. Recreate indexes/materialized views if disabled during restore (see `migrations/` for schema reference).
### 4.3 Evidence & audit artefacts
- Store the following with each backup set:
- `ledger_merkle_roots` CSV export.
- Replay harness signed report (`harness-report.json` + `.sig`).
- Latest Grafana dashboard JSON and alert rules used during the period.
- Keep anchor references (`anchor_reference`) when external anchoring is enabled; include external proof bundle if present.
## 5. Offline / air-gapped workflow
@@ -115,6 +141,8 @@
- Package ledger service binaries + migrations using `ops/offline-kit/build_offline_kit.py --include ledger`.
- Document sealed-mode restrictions: disable outbound attachments unless egress policy allows Evidence Locker endpoints; set `LEDGER__ATTACHMENTS__ALLOWEGRESS=false`.
**Path placeholder (waiting on DevOps):** Helm/Compose/offline-kit overlay directories are pending centralisation under `ops/deployment`/`ops/offline-kit`. Until paths are assigned, keep environment-specific overlays local to `docs/modules/findings-ledger/deployment.md` examples and avoid committing manifests outside this module.
## 6. Post-deploy checklist
- [ ] Health + metrics endpoints respond.

View File

@@ -110,6 +110,240 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/FindingProjectionPage'
/v1/ledger/export/findings:
get:
summary: Export findings in deterministic order
operationId: exportFindings
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: finding_status
in: query
schema: { type: string }
- name: severity
in: query
schema: { type: number }
- name: risk_profile_version
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged findings export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/FindingExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of FindingExportItem
/v1/ledger/export/vex:
get:
summary: Export VEX statements
operationId: exportVex
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: product_id
in: query
schema: { type: string }
- name: advisory_id
in: query
schema: { type: string }
- name: status
in: query
schema: { type: string }
- name: statement_type
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged VEX export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/VexExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of VexExportItem
/v1/ledger/export/advisories:
get:
summary: Export advisories
operationId: exportAdvisories
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: severity
in: query
schema: { type: string }
- name: source
in: query
schema: { type: string }
- name: cwe_id
in: query
schema: { type: string }
- name: kev
in: query
schema: { type: boolean }
- name: cvss_version
in: query
schema: { type: string }
- name: cvss_score_min
in: query
schema: { type: number }
- name: cvss_score_max
in: query
schema: { type: number }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged advisory export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/AdvisoryExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of AdvisoryExportItem
/v1/ledger/export/sboms:
get:
summary: Export SBOMs
operationId: exportSboms
tags: [export]
parameters:
- $ref: '#/components/parameters/TenantId'
- $ref: '#/components/parameters/Shape'
- $ref: '#/components/parameters/SinceSequence'
- $ref: '#/components/parameters/UntilSequence'
- $ref: '#/components/parameters/SinceObservedAt'
- $ref: '#/components/parameters/UntilObservedAt'
- name: subject_digest
in: query
schema: { type: string }
- name: sbom_format
in: query
schema: { type: string }
- name: component_purl
in: query
schema: { type: string }
- name: contains_native
in: query
schema: { type: boolean }
- name: slsa_build_type
in: query
schema: { type: string }
- $ref: '#/components/parameters/PageSize'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged SBOM export
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/SbomExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of SbomExportItem
/v1/ledger/attestations:
get:
summary: List attestation verifications
operationId: listLedgerAttestations
tags: [attestation]
parameters:
- $ref: '#/components/parameters/TenantId'
- name: artifactId
in: query
schema: { type: string }
- name: findingId
in: query
schema: { type: string }
- name: attestationId
in: query
schema: { type: string }
- name: status
in: query
schema:
type: string
enum: [verified, failed, unknown]
- name: sinceRecordedAt
in: query
schema: { type: string, format: date-time }
- name: untilRecordedAt
in: query
schema: { type: string, format: date-time }
- $ref: '#/components/parameters/AttestationLimit'
- $ref: '#/components/parameters/PageToken'
responses:
'200':
description: Paged attestation verifications
headers:
X-Stella-Next-Page-Token:
schema: { type: string }
X-Stella-Result-Count:
schema: { type: integer }
content:
application/json:
schema:
$ref: '#/components/schemas/AttestationExportPage'
application/x-ndjson:
schema:
type: string
description: NDJSON stream of AttestationExportItem
/.well-known/openapi:
get:
summary: Serve Findings Ledger OpenAPI document
operationId: getOpenApi
tags: [metadata]
responses:
'200':
description: OpenAPI YAML document
content:
application/yaml:
schema:
type: string
components:
securitySchemes:
bearerAuth:
@@ -125,6 +359,56 @@ components:
required: true
schema:
type: string
Shape:
name: shape
in: query
required: true
schema:
type: string
enum: [canonical, compact]
SinceSequence:
name: since_sequence
in: query
schema:
type: integer
minimum: 0
UntilSequence:
name: until_sequence
in: query
schema:
type: integer
minimum: 0
SinceObservedAt:
name: since_observed_at
in: query
schema:
type: string
format: date-time
UntilObservedAt:
name: until_observed_at
in: query
schema:
type: string
format: date-time
PageSize:
name: page_size
in: query
schema:
type: integer
default: 500
maximum: 5000
PageToken:
name: page_token
in: query
schema:
type: string
AttestationLimit:
name: limit
in: query
schema:
type: integer
default: 200
maximum: 1000
schemas:
LedgerEvent:
type: object
@@ -241,6 +525,16 @@ components:
severity:
type: number
format: double
riskScore:
type: number
format: double
riskSeverity:
type: string
riskProfileVersion:
type: string
riskExplanationId:
type: string
format: uuid
labels:
type: object
additionalProperties: true
@@ -262,3 +556,116 @@ components:
$ref: '#/components/schemas/FindingProjection'
nextCursor:
type: string
ExportProvenance:
type: object
properties:
policyVersion: { type: string }
cycleHash: { type: string }
ledgerEventHash: { type: string }
FindingExportItem:
type: object
properties:
eventSequence: { type: integer }
observedAt: { type: string, format: date-time }
findingId: { type: string }
policyVersion: { type: string }
status: { type: string }
severity: { type: number, format: double }
cycleHash: { type: string }
evidenceBundleRef: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
labels:
type: object
additionalProperties: true
VexExportItem:
type: object
properties:
eventSequence: { type: integer }
observedAt: { type: string, format: date-time }
vexStatementId: { type: string }
productId: { type: string }
status: { type: string }
statementType: { type: string }
knownExploited: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
AdvisoryExportItem:
type: object
properties:
eventSequence: { type: integer }
published: { type: string, format: date-time }
advisoryId: { type: string }
source: { type: string }
title: { type: string }
severity: { type: string }
cvssScore: { type: number, format: double }
cvssVector: { type: string }
kev: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
SbomExportItem:
type: object
properties:
eventSequence: { type: integer }
createdAt: { type: string, format: date-time }
sbomId: { type: string }
subjectDigest: { type: string }
sbomFormat: { type: string }
componentsCount: { type: integer }
hasVulnerabilities: { type: boolean }
cycleHash: { type: string }
provenance:
$ref: '#/components/schemas/ExportProvenance'
FindingExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/FindingExportItem' }
nextPageToken: { type: string }
VexExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/VexExportItem' }
nextPageToken: { type: string }
AdvisoryExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/AdvisoryExportItem' }
nextPageToken: { type: string }
SbomExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/SbomExportItem' }
nextPageToken: { type: string }
AttestationExportItem:
type: object
properties:
attestationId: { type: string }
artifactId: { type: string }
findingId: { type: string }
verificationStatus: { type: string }
verificationTime: { type: string, format: date-time }
dsseDigest: { type: string }
rekorEntryId: { type: string }
evidenceBundleRef: { type: string }
ledgerEventId: { type: string, format: uuid }
recordedAt: { type: string, format: date-time }
merkleLeafHash: { type: string }
rootHash: { type: string }
AttestationExportPage:
type: object
properties:
items:
type: array
items: { $ref: '#/components/schemas/AttestationExportItem' }
nextPageToken: { type: string }

View File

@@ -241,6 +241,30 @@ Checkpoint store for the projection background worker. Ensures idempotent replay
Seed row inserted on migration ensures catch-up from epoch (`1970-01-01T00:00:00Z` with empty GUID).
### 4.5 `ledger_attestations`
Deterministic view of DSSE verification results used by `/v1/ledger/attestations`. Rows are written by the provenance/verification pipeline and keyed per tenant.
| Column | Type | Description |
|--------|------|-------------|
| `tenant_id` | `text` | Partition key. |
| `attestation_id` | `uuid` | Primary key within tenant. |
| `artifact_id` | `text` | OCI digest or SBOM identifier verified. |
| `finding_id` | `text` | Optional finding linkage. |
| `verification_status` | `text` | `verified`, `failed`, or `unknown`. |
| `verification_time` | `timestamptz` | When verification completed. |
| `dsse_digest` | `text` | Lower-case SHA-256 of DSSE envelope. |
| `rekor_entry_id` | `text` | Optional transparency log UUID. |
| `evidence_bundle_ref` | `text` | Optional evidence bundle reference. |
| `ledger_event_id` | `uuid` | Ledger event that linked the attestation. |
| `recorded_at` | `timestamptz` | Ingestion timestamp used for paging. |
| `merkle_leaf_hash` | `text` | Leaf hash for anchoring proofs. |
| `root_hash` | `text` | Anchor root hash. |
| `cycle_hash` | `text` | Projection cycle hash for determinism. |
| `projection_version` | `text` | Projection version identifier. |
Ordering and pagination: `ORDER BY recorded_at ASC, attestation_id ASC` with cursor token `{recordedAt, attestationId, filtersHash}`. Indexes: PK `(tenant_id, attestation_id)`, paging index `(tenant_id, recorded_at, attestation_id)`, lookups on `(tenant_id, artifact_id, recorded_at DESC)` and `(tenant_id, verification_status, recorded_at DESC)`.
## 5. Hashing & verification
1. Canonical serialize the envelope (§2.3).

View File

@@ -5,7 +5,7 @@ Graph Indexer + Graph API build the tenant-scoped knowledge graph that powers bl
## Scope & responsibilities
- Ingest SBOM snapshots, advisory/VEX events, policy overlays, and runtime signals to maintain a first-party graph representation with deterministic node/edge identities.
- Serve APIs and saved-query tooling for impact analysis, dependency traversal, diffing, and policy/VEX overlays with explainable provenance.
- Supply Graph Explorer UI/CLI experiences, plus Offline Kit exports (`nodes.jsonl`, `edges.jsonl`, `overlays/`) with DSSE manifests for air-gapped replay.
- Supply Graph Explorer UI/CLI experiences, plus Offline Kit exports (`nodes.jsonl`, `edges.jsonl`, `overlays/`) with DSSE manifests for air-gapped replay. Analytics overlays are emitted as NDJSON (`overlays/clusters.ndjson`, `overlays/centrality.ndjson`) with deterministic ordering; Mongo-backed providers support production wiring.
- Maintain the [Graph Index Canonical Schema](schema.md) and coordinate query/overlay lifecycle with Scheduler, Policy Engine, Vulnerability Explorer, and Export Center.
## Architecture snapshot (Sprint 30 groundwork)

View File

@@ -4,6 +4,7 @@
- Helm/Compose should expose two timers for analytics: `GRAPH_ANALYTICS_CLUSTER_INTERVAL` and `GRAPH_ANALYTICS_CENTRALITY_INTERVAL` (ISO-8601 duration, default 5m). Map to `GraphAnalyticsOptions`.
- Change-stream/backfill worker toggles via `GRAPH_CHANGE_POLL_INTERVAL`, `GRAPH_BACKFILL_INTERVAL`, `GRAPH_CHANGE_MAX_RETRIES`, `GRAPH_CHANGE_RETRY_BACKOFF`.
- Mongo bindings (optional): `GRAPH_CHANGE_COLLECTION`, `GRAPH_CHANGE_SEQUENCE_FIELD`, `GRAPH_CHANGE_NODE_FIELD`, `GRAPH_CHANGE_EDGE_FIELD`, `GRAPH_CHANGE_IDEMPOTENCY_COLLECTION`, `GRAPH_ANALYTICS_SNAPSHOT_COLLECTION`, `GRAPH_ANALYTICS_PROGRESS_COLLECTION`.
- Mongo connection: `STELLAOPS_GRAPH_MONGO_CONNECTION` and `STELLAOPS_GRAPH_MONGO_DB` feed `AddGraphMongoDatabase` for clients/services.
- New Mongo collections:
- `graph_cluster_overlays` — cluster assignments (`tenant`, `snapshot_id`, `node_id`, `cluster_id`, `generated_at`).
- `graph_centrality_overlays` — degree + betweenness approximations per node.

View File

@@ -0,0 +1,28 @@
# Graph API schema review notes (planned)
Date: 2025-11-24 (target)
Scope: Review OpenAPI/JSON schema for search/query/paths/diff/export, tiles, budgets, and overlays alignment (GRAPH-API-28-001).
## Attendees
- Graph API Guild: TBD
- Policy Engine Guild: TBD
- QA Guild (observer): TBD
## Pre-reads
- `docs/api/graph-gateway-spec-draft.yaml`
- `docs/modules/graph/prep/2025-11-22-graph-api-schema-outline.md`
- Policy overlay contract references: `POLICY-ENGINE-30-001..003`
## Agenda
- Validate tile envelope shape and budget semantics.
- Confirm overlay payload fields and versioning handshake with Policy Engine.
- Decide DSL vs structured filter scope for `/graph/query` v1.
- Agree on export manifest shape and size caps for PNG/SVG.
## Decisions
- TODO (capture during review)
## Open items / follow-ups
- TODO
## Outcomes snapshot
- TODO (link to sprint Execution Log once review completes)

View File

@@ -0,0 +1 @@
# Pending fixture drop — replace with real SHA256 hashes when LNM v1 fixtures are published.

View File

@@ -25,7 +25,22 @@ Document a repeatable AirGap parity review for `/sbom/paths`, `/sbom/versions`,
- Minutes + decisions appended to this file (Execution Notes section) with timestamps and owners.
- Metrics table with p50/p95/p99 latency, error rate, and cache hit ratio.
- Actions list with owners and due dates; blockers mirrored to sprint 0140/0142 Decisions & Risks.
- Fixture hash list appended (from `SHA256SUMS`) with date and signer.
## Data capture templates
### Metrics
| Metric | p50 | p95 | p99 | Error rate | Notes |
| --- | --- | --- | --- | --- | --- |
| `/sbom/paths` latency (ms) | | | | | |
| `/sbom/versions` latency (ms) | | | | | |
| Event ingest → emit (ms) | | | | | |
| Cache hit ratio | | | | | |
### Decisions & follow-ups
| Decision / Action | Owner | Due | Status | Notes |
| --- | --- | --- | --- | --- |
| | | | | |
## Execution Notes
- 2025-11-22: Template published; awaiting fixtures and review scheduling.

View File

@@ -1,159 +1,159 @@
# Reachability Evidence Delivery Guide
_Last updated: November 8, 2025. Owner: Reachability Tiger Team (Scanner, Signals, Replay, Policy, Authority, UI)._
This guide translates the deterministic reachability blueprint into concrete work streams that average contributors can pick up without re-reading the entire proposal. Use it as the single navigation point when you land a reachability ticket. For a task-centric view of remaining gaps, see `docs/reachability/REACHABILITY_GAP_TASKS.md`.
---
## 1. Scope & Principles
**Goal**: ship a verifiable reachability signal for every scan by chaining SBOM → graph → runtime facts → VEX into DSSE-attested, replayable evidence.
**Principles**
1. **Deterministic inputs** canonical IDs, sorted payloads, normalized timestamps.
2. **Provable facts** every artifact has a DSSE envelope anchored in Authority + Rekor mirror.
3. **Replay-first** manifests pin feed snapshots, analyzer digests, and policies so auditors can rerun.
4. **Least surprise** same API and file layouts across languages; tests run fixture packs at CI time.
---
## 2. Evidence Chain Overview
| Stage | Producer | Artifact | Requirements |
|-------|----------|----------|--------------|
| SBOM per layer & composed image | Scanner Worker + Sbomer | `sbom.layer.cdx.json`, `sbom.image.cdx.json` | Deterministic CycloneDX 1.6, DSSE envelope, CAS URI |
| Static reachability graph | Scanner Worker lifters (DotNet, Go, Node/Deno, Rust, Swift, JVM, Binary, Shell) | `richgraph-v1.json` + `sha256` | Canonical SymbolIDs, framework entries, predicates, graph hash |
| Runtime facts | Zastava Observer / runtime probes | `runtime-trace.ndjson` (gzip or JSON) | EntryTrace schema, CAS pointer, process/socket/container metadata, optional compression |
| Replay manifest | Scanner Worker + Replay Core | `replay.yaml` | Contains analyzer versions, feed locks, graph hash, runtime trace digests |
| VEX statements | Scanner WebService + Policy Engine | `reachability.json` + OpenVEX doc | Links SBOM attn, graph attn, runtime evidence IDs |
| Signed bundle | Authority + Signer | DSSE envelope referencing above | Support FIPS + PQ variants (Dilithium where required) |
---
## 3. Work Streams (modules + hand-offs)
| Stream | Owner Guild(s) | Key deliverables |
|--------|----------------|------------------|
| **Native symbols & callgraphs** | Scanner Worker · Symbols Guild | Ship `Scanner.Symbols.Native` + `Scanner.CallGraph.Native`, integrate Symbol Manifest v1, demangle Itanium/MSVC names, emit `FuncNode`/`CallEdge` CAS bundles (task `SCANNER-NATIVE-401-015`). |
| **Reachability store** | Signals · BE-Base Platform | Provision shared Mongo collections (`func_nodes`, `call_edges`, `cve_func_hits`), indexes, and repositories plus REST hooks for reuse (task `SIG-STORE-401-016`). |
| **Language lifters** | Scanner Worker | CLI/hosted lifters for DotNet, Go, Node/Deno, JVM, Rust, Swift, Binary, Shell with CAS uploads and richgraph output |
| **Signals ingestion & scoring** | Signals | `/callgraphs`, `/runtime-facts` (JSON + NDJSON/gzip), `/graphs/{id}`, `/reachability/recompute` GA; CAS-backed storage, runtime dedupe, BFS+predicates scoring |
| **Runtime capture** | Zastava + Runtime Guild | EntryTrace/eBPF samplers, NDJSON batches (symbol IDs + timestamps + counts) |
| **Replay evidence** | Replay Core + Scanner Worker | Manifest schema v2, `ReachabilityReplayWriter` integration, hash-lock tests |
| **Authority attestations** | Authority + Signer | DSSE predicates for SBOM, Graph, Replay, VEX; Rekor mirror alignment |
| **Policy & VEX** | Policy Engine + Web + CLI + UI | Accept reachability states, render “Why safe” call paths, CLI/UI explain flows |
| **QA & Docs** | QA + Docs Guilds | `reachbench-2025-expanded` fixtures wired to CI; operator + developer runbooks |
| **Binary quality guardrails (Nov 2026)** | Scanner · Signals · QA | Build-id capture, init-array roots, purl-resolved edges, unknowns emission, and patch-oracle fixtures; see sections 5.75.9 |
---
## 4. Sprint Targets
| Sprint | Nickname | Focus | Exit Criteria |
|--------|----------|-------|---------------|
| **401** | Evidence Pipeline | Finish static lifters + CAS graph storage + runtime ingestion endpoint | Graph CAS layout documented, lifter fixtures passing, `/runtime-facts` receives NDJSON batches |
| **402** | Replay & Attest | Manifest v2, DSSE envelopes, Authority/Rekor publishing | Replay packs include hashes + analyzer fingerprint; DSSE statements passed integration; Rekor mirror updated |
| **403** | Policy & Explain | VEX generation, SPL predicates, UI/CLI explainers | Policy engine uses reachability states, CLI `stella graph explain` returns signed paths, UI shows explain drawer |
Each sprint is two weeks; refer to `docs/implplan/SPRINT_0401_0001_0001_reachability_evidence_chain.md` (new) for per-task tracking.
---
## 5. Task Breakdown Cheat Sheet
### 5.1 Scanner Worker
1. **Lifter SDK** Define `RichGraphWriter`, canonical SymbolID helpers, analyzer interface updates.
2. **Language passes** deliverables per language: discovery, graph build, framework wiring, predicate extraction, runtime overlay.
3. **Replay hooks** plug lifter output + runtime traces into `ReachabilityReplayWriter`; enforce CAS registration before emitting manifest references.
4. **Fixture runs** add tests under `tests/reachability/StellaOps.ScannerSignals.IntegrationTests` to execute lifter outputs against reachbench A/B cases.
### 5.2 Signals Service
1. **Callgraph CAS layout** migrate from filesystem to CAS (`cas://reachability/graphs/{hash}`), include metadata doc.
2. **Runtime facts API** accept NDJSON or gzip, dedupe events, compute hit stats, link to graph nodes.
3. **Scoring engine v2** support multi-state lattice (`Unknown → Observed`), record predicates, blocked edges, runtime evidence CAS URIs.
4. **API responses** `/graphs/{scanId}` returns graph CAS refs + manifest pointers; `/reachability/recompute` accepts replay manifest IDs.
### 5.3 Replay Core & Authority
1. **Manifest schema v2** YAML + JSON versions, includes feeds/analyzers/policies.
2. **CAS naming** standardize `cas://reachability/{kind}/{sha256}`.
3. **DSSE predicate types** `SbomAttestation`, `GraphAttestation`, `VexAttestation`, `ReplayManifest`.
4. **Authority integration** new endpoints for submitting reachability predicates, rotation tests, Rekor mirror update instructions.
### 5.4 Policy / Web / UI / CLI
1. **Policy Engine** ingest reachability fact from Signals, expose via SPL, produce metrics, integrate into explanation tree.
2. **Web API** join reachability fields in vuln responses, add override endpoints, simulate support.
3. **UI/CLI** Visual explain drawer/CLI command showing signed call-path, predicates, runtime hits; counterfactual toggles.
4. **VEX emitter** generate OpenVEX statements with evidence references, DSSE sign via Signer.
### 5.5 Native binaries (build-id + init roots)
- Capture ELF build-id (`.note.gnu.build-id`) alongside soname/path and propagate into `SymbolID`/`code_id` so SBOM/runtime joins stay stable even when paths change.
- Treat `.preinit_array`, `.init_array`, `.ctors`, and `_init` as synthetic graph roots with `phase=load`; include constructors from `DT_NEEDED` deps. Persist the root list in scan evidence.
- Add deterministic tests covering build-id present/absent and init-array edge creation.
### 5.6 PURL-resolved edges
- Annotate every call edge with callee `purl` and `symbol_digest` per `docs/reachability/purl-resolved-edges.md`.
- Update `richgraph-v1` schema, CAS metadata, and CLI/UI explainers to display `purl@version` + demangled name.
- Signals merges graphs by `(purl, symbol_digest)`; Policy uses the same keys when mapping CVE-affected functions.
### 5.7 Unknowns Registry integration
- Emit structured Unknowns when symbol→purl mapping, edge targets, or hashes are ambiguous; write them via Signals API per `docs/signals/unknowns-registry.md`.
- Scoring adds `unknowns_pressure` so `not_affected` claims cannot bypass unresolved evidence.
- UI/CLI should surface unknown chips and triage actions.
### 5.8 Patch-oracle guardrails
- Add `tests/reachability/patch-oracles/**` with paired vuln/fixed binaries and `oracle.yml` expectations (functions/edges added/removed).
- Scanner binary analyzer tests must fail if expected guard functions or edges are missing; CI job ensures determinism.
- See `docs/reachability/patch-oracles.md` for fixture layout and manifest schema.
### 5.9 JS/PHP framework reachability
- Model framework entrypoints explicitly: Express/Fastify/Nest handlers, Laravel/Symfony routes/commands/hooks. Generate graph roots from route/handler catalogs instead of generic `main` only.
- Represent dynamic import/require/include resolution as graph nodes so ambiguity stays visible (`resolution` edges with confidence).
- Keep multi-layer graphs: source-level (TS/JS/PHP) plus bundled output (Webpack/Vite). Merge with runtime hints when available.
- Status model: `always_reachable`, `conditional`, `not_reachable`, `not_analyzed`, `ambiguous`, each with confidence and evidence tags.
- Deliver language-specific profiles + fixture cases to prove coverage; update CLI/UI explainers to show framework route context.
---
## 6. Acceptance Tests
1. **Hash-lock** reorder analyzer flags and confirm graph hash unchanged.
2. **Replay** delete caches, replay manifest, verify DSSE + hash equality.
3. **Tamper** alter single edge and expect VEX verification failure with specific path mismatch.
4. **Golden corpus** run all reachbench cases; ensure NotReachable vs Reachable twins align with expectations JSON.
5. **Runtime sanity** feed staged runtime traces and ensure confidence bump + `observed=true` path chips propagate to UI.
---
## 7. Documentation & Runbooks
- Place developer-facing updates here (`docs/reachability`).
- [Function-level evidence guide](function-level-evidence.md) captures the Nov2025 advisory scope, task references, and schema expectations; keep it in lockstep with sprint status.
- [Reachability runtime runbook](../runbooks/reachability-runtime.md) now documents ingestion, CAS staging, air-gap handling, and troubleshooting—link every runtime feature PR to this guide.
- [VEX Evidence Playbook](../benchmarks/vex-evidence-playbook.md) defines the bench repo layout, artifact shapes, verifier tooling, and metrics; keep it updated when Policy/Signer/CLI features land.
- [Reachability lattice](lattice.md) describes the confidence states, evidence/mitigation kinds, scoring policy, event graph schema, and VEX gates; update it when lattices or probes change.
- [PURL-resolved edges spec](purl-resolved-edges.md) defines the purl + symbol-digest annotation rules for graphs and SBOM joins.
- [Patch-oracles QA pattern](patch-oracles.md) describes the fixture layout and expectations for binary reachability guards.
- [Unknowns registry](../signals/unknowns-registry.md) documents how unresolved symbols/edges are recorded and how scoring uses `unknowns_pressure`.
- [Evidence schema](evidence-schema.md) is the canonical field list for richgraph, runtime facts, and Unknowns CAS objects.
- Update module dossiers (Scanner, Signals, Replay, Authority, Policy, UI) once each guild lands work.
---
## 8. Contact & Rituals
- **Daily reachability stand-up** in `#reachability-build`.
- **Fixture sync** every Friday: QA leads run reachbench matrix, post report to Confluence + link in `docs/reachability/DELIVERY_GUIDE.md`.
- **Decision log** Append ADRs under `docs/adr/reachability-*` for schema changes.
Keep this guide updated whenever scope shifts or a new sprint is added.
# Reachability Evidence Delivery Guide
_Last updated: November 8, 2025. Owner: Reachability Tiger Team (Scanner, Signals, Replay, Policy, Authority, UI)._
This guide translates the deterministic reachability blueprint into concrete work streams that average contributors can pick up without re-reading the entire proposal. Use it as the single navigation point when you land a reachability ticket. For a task-centric view of remaining gaps, see `docs/reachability/REACHABILITY_GAP_TASKS.md`.
---
## 1. Scope & Principles
**Goal**: ship a verifiable reachability signal for every scan by chaining SBOM → graph → runtime facts → VEX into DSSE-attested, replayable evidence.
**Principles**
1. **Deterministic inputs** canonical IDs, sorted payloads, normalized timestamps.
2. **Provable facts** every artifact has a DSSE envelope anchored in Authority + Rekor mirror.
3. **Replay-first** manifests pin feed snapshots, analyzer digests, and policies so auditors can rerun.
4. **Least surprise** same API and file layouts across languages; tests run fixture packs at CI time.
---
## 2. Evidence Chain Overview
| Stage | Producer | Artifact | Requirements |
|-------|----------|----------|--------------|
| SBOM per layer & composed image | Scanner Worker + Sbomer | `sbom.layer.cdx.json`, `sbom.image.cdx.json` | Deterministic CycloneDX 1.6, DSSE envelope, CAS URI |
| Static reachability graph | Scanner Worker lifters (DotNet, Go, Node/Deno, Rust, Swift, JVM, Binary, Shell) | `richgraph-v1.json` + `sha256` | Canonical SymbolIDs, framework entries, predicates, graph hash |
| Runtime facts | Zastava Observer / runtime probes | `runtime-trace.ndjson` (gzip or JSON) | EntryTrace schema, CAS pointer, process/socket/container metadata, optional compression |
| Replay manifest | Scanner Worker + Replay Core | `replay.yaml` | Contains analyzer versions, feed locks, graph hash, runtime trace digests |
| VEX statements | Scanner WebService + Policy Engine | `reachability.json` + OpenVEX doc | Links SBOM attn, graph attn, runtime evidence IDs |
| Signed bundle | Authority + Signer | DSSE envelope referencing above | Support FIPS + PQ variants (Dilithium where required) |
---
## 3. Work Streams (modules + hand-offs)
| Stream | Owner Guild(s) | Key deliverables |
|--------|----------------|------------------|
| **Native symbols & callgraphs** | Scanner Worker · Symbols Guild | Ship `Scanner.Symbols.Native` + `Scanner.CallGraph.Native`, integrate Symbol Manifest v1, demangle Itanium/MSVC names, emit `FuncNode`/`CallEdge` CAS bundles (task `SCANNER-NATIVE-401-015`). |
| **Reachability store** | Signals · BE-Base Platform | Provision shared Mongo collections (`func_nodes`, `call_edges`, `cve_func_hits`), indexes, and repositories plus REST hooks for reuse (task `SIG-STORE-401-016`). |
| **Language lifters** | Scanner Worker | CLI/hosted lifters for DotNet, Go, Node/Deno, JVM, Rust, Swift, Binary, Shell with CAS uploads and richgraph output |
| **Signals ingestion & scoring** | Signals | `/callgraphs`, `/runtime-facts` (JSON + NDJSON/gzip), `/graphs/{id}`, `/reachability/recompute` GA; CAS-backed storage, runtime dedupe, BFS+predicates scoring |
| **Runtime capture** | Zastava + Runtime Guild | EntryTrace/eBPF samplers, NDJSON batches (symbol IDs + timestamps + counts) |
| **Replay evidence** | Replay Core + Scanner Worker | Manifest schema v2, `ReachabilityReplayWriter` integration, hash-lock tests |
| **Authority attestations** | Authority + Signer | DSSE predicates for SBOM, Graph, Replay, VEX; Rekor mirror alignment |
| **Policy & VEX** | Policy Engine + Web + CLI + UI | Accept reachability states, render “Why safe” call paths, CLI/UI explain flows |
| **QA & Docs** | QA + Docs Guilds | `reachbench-2025-expanded` fixtures wired to CI; operator + developer runbooks |
| **Binary quality guardrails (Nov 2026)** | Scanner · Signals · QA | Build-id capture, init-array roots, purl-resolved edges, unknowns emission, and patch-oracle fixtures; see sections 5.75.9 |
---
## 4. Sprint Targets
| Sprint | Nickname | Focus | Exit Criteria |
|--------|----------|-------|---------------|
| **401** | Evidence Pipeline | Finish static lifters + CAS graph storage + runtime ingestion endpoint | Graph CAS layout documented, lifter fixtures passing, `/runtime-facts` receives NDJSON batches |
| **402** | Replay & Attest | Manifest v2, DSSE envelopes, Authority/Rekor publishing | Replay packs include hashes + analyzer fingerprint; DSSE statements passed integration; Rekor mirror updated |
| **403** | Policy & Explain | VEX generation, SPL predicates, UI/CLI explainers | Policy engine uses reachability states, CLI `stella graph explain` returns signed paths, UI shows explain drawer |
Each sprint is two weeks; refer to `docs/implplan/SPRINT_0401_0001_0001_reachability_evidence_chain.md` (new) for per-task tracking.
---
## 5. Task Breakdown Cheat Sheet
### 5.1 Scanner Worker
1. **Lifter SDK** Define `RichGraphWriter`, canonical SymbolID helpers, analyzer interface updates.
2. **Language passes** deliverables per language: discovery, graph build, framework wiring, predicate extraction, runtime overlay.
3. **Replay hooks** plug lifter output + runtime traces into `ReachabilityReplayWriter`; enforce CAS registration before emitting manifest references.
4. **Fixture runs** add tests under `tests/reachability/StellaOps.ScannerSignals.IntegrationTests` to execute lifter outputs against reachbench A/B cases.
### 5.2 Signals Service
1. **Callgraph CAS layout** migrate from filesystem to CAS (`cas://reachability/graphs/{hash}`), include metadata doc.
2. **Runtime facts API** accept NDJSON or gzip, dedupe events, compute hit stats, link to graph nodes.
3. **Scoring engine v2** support multi-state lattice (`Unknown → Observed`), record predicates, blocked edges, runtime evidence CAS URIs.
4. **API responses** `/graphs/{scanId}` returns graph CAS refs + manifest pointers; `/reachability/recompute` accepts replay manifest IDs.
### 5.3 Replay Core & Authority
1. **Manifest schema v2** YAML + JSON versions, includes feeds/analyzers/policies.
2. **CAS naming** standardize `cas://reachability/{kind}/{sha256}`.
3. **DSSE predicate types** `SbomAttestation`, `GraphAttestation`, `VexAttestation`, `ReplayManifest`.
4. **Authority integration** new endpoints for submitting reachability predicates, rotation tests, Rekor mirror update instructions.
### 5.4 Policy / Web / UI / CLI
1. **Policy Engine** ingest reachability fact from Signals, expose via SPL, produce metrics, integrate into explanation tree.
2. **Web API** join reachability fields in vuln responses, add override endpoints, simulate support.
3. **UI/CLI** Visual explain drawer/CLI command showing signed call-path, predicates, runtime hits; counterfactual toggles.
4. **VEX emitter** generate OpenVEX statements with evidence references, DSSE sign via Signer.
### 5.5 Native binaries (build-id + init roots)
- Capture ELF build-id (`.note.gnu.build-id`) alongside soname/path and propagate into `SymbolID`/`code_id` so SBOM/runtime joins stay stable even when paths change.
- Treat `.preinit_array`, `.init_array`, `.ctors`, and `_init` as synthetic graph roots with `phase=load`; include constructors from `DT_NEEDED` deps. Persist the root list in scan evidence.
- Add deterministic tests covering build-id present/absent and init-array edge creation.
### 5.6 PURL-resolved edges
- Annotate every call edge with callee `purl` and `symbol_digest` per `docs/reachability/purl-resolved-edges.md`.
- Update `richgraph-v1` schema, CAS metadata, and CLI/UI explainers to display `purl@version` + demangled name.
- Signals merges graphs by `(purl, symbol_digest)`; Policy uses the same keys when mapping CVE-affected functions.
### 5.7 Unknowns Registry integration
- Emit structured Unknowns when symbol→purl mapping, edge targets, or hashes are ambiguous; write them via Signals API per `docs/signals/unknowns-registry.md`.
- Scoring adds `unknowns_pressure` so `not_affected` claims cannot bypass unresolved evidence.
- UI/CLI should surface unknown chips and triage actions.
### 5.8 Patch-oracle guardrails
- Add `tests/reachability/patch-oracles/**` with paired vuln/fixed binaries and `oracle.yml` expectations (functions/edges added/removed).
- Scanner binary analyzer tests must fail if expected guard functions or edges are missing; CI job ensures determinism.
- See `docs/reachability/patch-oracles.md` for fixture layout and manifest schema.
### 5.9 JS/PHP framework reachability
- Model framework entrypoints explicitly: Express/Fastify/Nest handlers, Laravel/Symfony routes/commands/hooks. Generate graph roots from route/handler catalogs instead of generic `main` only.
- Represent dynamic import/require/include resolution as graph nodes so ambiguity stays visible (`resolution` edges with confidence).
- Keep multi-layer graphs: source-level (TS/JS/PHP) plus bundled output (Webpack/Vite). Merge with runtime hints when available.
- Status model: `always_reachable`, `conditional`, `not_reachable`, `not_analyzed`, `ambiguous`, each with confidence and evidence tags.
- Deliver language-specific profiles + fixture cases to prove coverage; update CLI/UI explainers to show framework route context.
---
## 6. Acceptance Tests
1. **Hash-lock** reorder analyzer flags and confirm graph hash unchanged.
2. **Replay** delete caches, replay manifest, verify DSSE + hash equality.
3. **Tamper** alter single edge and expect VEX verification failure with specific path mismatch.
4. **Golden corpus** run all reachbench cases; ensure NotReachable vs Reachable twins align with expectations JSON.
5. **Runtime sanity** feed staged runtime traces and ensure confidence bump + `observed=true` path chips propagate to UI.
---
## 7. Documentation & Runbooks
- Place developer-facing updates here (`docs/reachability`).
- [Function-level evidence guide](function-level-evidence.md) captures the Nov2025 advisory scope, task references, and schema expectations; keep it in lockstep with sprint status.
- [Reachability runtime runbook](../runbooks/reachability-runtime.md) now documents ingestion, CAS staging, air-gap handling, and troubleshooting—link every runtime feature PR to this guide.
- [VEX Evidence Playbook](../benchmarks/vex-evidence-playbook.md) defines the bench repo layout, artifact shapes, verifier tooling, and metrics; keep it updated when Policy/Signer/CLI features land.
- [Reachability lattice](lattice.md) describes the confidence states, evidence/mitigation kinds, scoring policy, event graph schema, and VEX gates; update it when lattices or probes change.
- [PURL-resolved edges spec](purl-resolved-edges.md) defines the purl + symbol-digest annotation rules for graphs and SBOM joins.
- [Patch-oracles QA pattern](patch-oracles.md) describes the fixture layout and expectations for binary reachability guards.
- [Unknowns registry](../signals/unknowns-registry.md) documents how unresolved symbols/edges are recorded and how scoring uses `unknowns_pressure`.
- [Evidence schema](evidence-schema.md) is the canonical field list for richgraph, runtime facts, and Unknowns CAS objects.
- Update module dossiers (Scanner, Signals, Replay, Authority, Policy, UI) once each guild lands work.
---
## 8. Contact & Rituals
- **Daily reachability stand-up** in `#reachability-build`.
- **Fixture sync** every Friday: QA leads run reachbench matrix, post report to Confluence + link in `docs/reachability/DELIVERY_GUIDE.md`.
- **Decision log** Append ADRs under `docs/adr/reachability-*` for schema changes.
Keep this guide updated whenever scope shifts or a new sprint is added.

View File

@@ -4,8 +4,6 @@ using System.Collections.Immutable;
using System.Linq;
using StellaOps.Concelier.Models;
#pragma warning disable CS8620 // nullability mismatches guarded by explicit filtering
namespace StellaOps.Concelier.Core.Linksets;
internal static class LinksetCorrelation
@@ -108,24 +106,18 @@ internal static class LinksetCorrelation
return (0d, conflicts);
}
List<HashSet<string>> packageKeysPerInput = inputs
var packageKeysPerInput = inputs
.Select(i => i.Purls
.Select(ExtractPackageKey)
.Where(k => !string.IsNullOrWhiteSpace(k))
.ToHashSet(StringComparer.Ordinal))
.ToList();
var sharedPackages = new HashSet<string>(StringComparer.Ordinal);
if (packageKeysPerInput.Count > 0)
var seed = packageKeysPerInput.FirstOrDefault() ?? new HashSet<string>(StringComparer.Ordinal);
var sharedPackages = new HashSet<string>(seed, StringComparer.Ordinal);
foreach (var next in packageKeysPerInput.Skip(1))
{
sharedPackages.UnionWith(packageKeysPerInput[0]);
#pragma warning disable CS8620 // inputs filtered to non-empty strings above
foreach (var next in packageKeysPerInput.Skip(1))
{
sharedPackages.IntersectWith(next);
}
#pragma warning restore CS8620
sharedPackages.IntersectWith(next);
}
if (sharedPackages.Count > 0)
@@ -145,17 +137,12 @@ internal static class LinksetCorrelation
private static IEnumerable<AdvisoryLinksetConflict> CollectRangeConflicts(
IReadOnlyCollection<Input> inputs,
HashSet<string?> sharedPackages)
HashSet<string> sharedPackages)
{
var conflicts = new List<AdvisoryLinksetConflict>();
foreach (var package in sharedPackages)
{
if (package is null)
{
continue;
}
var values = inputs
.SelectMany(i => i.Purls
.Where(p => ExtractPackageKey(p) == package)

View File

@@ -3,3 +3,5 @@ node_modules
output
.cache
.DS_Store
dist
out

View File

@@ -24,3 +24,4 @@ Deliver the StellaOps developer portal with interactive API reference, SDK docum
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
- 6. Use `npm run build:offline`, `npm run test:a11y`, `npm run lint:links`, and `npm run budget:dist` on a fast (non-NTFS) volume before shipping DevPortal changes; ensure `npm run sync:spec` ran first.

View File

@@ -7,6 +7,6 @@ Keep this file in sync with `docs/implplan/SPRINT_0206_0001_0001_devportal.md`.
| DEVPORT-62-001 | DONE | Astro/Starlight scaffold + aggregate spec + nav/search. | 2025-11-22 |
| DEVPORT-62-002 | DONE | Schema viewer, examples, copy-curl, version selector. | 2025-11-22 |
| DEVPORT-63-001 | DONE | Try-It console against sandbox; token onboarding UX. | 2025-11-22 |
| DEVPORT-63-002 | TODO | Embed SDK snippets/quick starts from tested examples. | 2025-11-22 |
| DEVPORT-64-001 | TODO | Offline bundle target with specs + SDK archives; zero external assets. | 2025-11-22 |
| DEVPORT-64-002 | TODO | Accessibility tests, link checker, performance budgets. | 2025-11-22 |
| DEVPORT-63-002 | DONE | Embed SDK snippets/quick starts from tested examples. | 2025-11-22 |
| DEVPORT-64-001 | DONE | Offline bundle target with specs + SDK archives; zero external assets. | 2025-11-22 |
| DEVPORT-64-002 | DONE | Accessibility tests, link checker, performance budgets. | 2025-11-22 |

View File

@@ -37,6 +37,7 @@ export default defineConfig({
{ slug: 'guides/getting-started' },
{ slug: 'guides/navigation-search' },
{ slug: 'guides/examples' },
{ slug: 'guides/sdk-quickstarts' },
],
},
{

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,11 @@
"preview": "astro preview",
"check": "astro check",
"sync:spec": "node scripts/sync-spec.mjs",
"prepare:static": "npm run sync:spec && astro check"
"prepare:static": "npm run sync:spec && astro check",
"build:offline": "node scripts/build-offline.mjs",
"test:a11y": "node scripts/run-a11y.mjs",
"lint:links": "node scripts/check-links.mjs",
"budget:dist": "node scripts/check-perf.mjs"
},
"dependencies": {
"rapidoc": "9.3.8"
@@ -22,8 +26,11 @@
"devDependencies": {
"@astrojs/mdx": "4.3.12",
"@astrojs/starlight": "0.36.2",
"@axe-core/playwright": "4.9.0",
"@playwright/test": "1.48.2",
"@types/node": "24.10.1",
"astro": "5.16.0",
"linkinator": "6.1.2",
"typescript": "5.9.3"
}
}

View File

@@ -0,0 +1,5 @@
Place SDK archives here for offline bundles.
Expected filenames:
- stellaops-sdk-node-vX.Y.Z.tgz
- stellaops-sdk-python-vX.Y.Z.tar.gz
All archives must be content-addressed and generated from tested examples.

View File

@@ -0,0 +1,67 @@
#!/usr/bin/env node
import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const moduleRoot = path.resolve(__dirname, '..');
const outDir = path.join(moduleRoot, 'dist');
const bundleDir = path.join(moduleRoot, 'out');
const bundleFile = path.join(bundleDir, 'devportal-offline.tar.gz');
const specPath = path.join(moduleRoot, 'public', 'api', 'stella.yaml');
const sdkDir = path.join(moduleRoot, 'public', 'sdk');
function ensureSpec() {
if (!fs.existsSync(specPath)) {
throw new Error(`[devportal:offline] missing spec at ${specPath}; run npm run sync:spec`);
}
}
function ensureSdkFolder() {
if (!fs.existsSync(sdkDir)) {
fs.mkdirSync(sdkDir, { recursive: true });
fs.writeFileSync(
path.join(sdkDir, 'README.txt'),
'Place SDK archives here (e.g., stellaops-sdk-node-vX.Y.Z.tgz, stellaops-sdk-python-vX.Y.Z.tar.gz).\n'
);
}
}
function runBuild() {
console.log('[devportal:offline] running astro build');
execFileSync('npm', ['run', 'build'], { stdio: 'inherit', cwd: moduleRoot });
}
function packageBundle() {
fs.mkdirSync(bundleDir, { recursive: true });
if (fs.existsSync(bundleFile)) {
fs.rmSync(bundleFile);
}
const args = [
'--sort=name',
'--mtime', '@0',
'--owner', '0',
'--group', '0',
'--numeric-owner',
'-czf', bundleFile,
'-C', moduleRoot,
'dist',
'public/api/stella.yaml',
'public/sdk'
];
console.log(`[devportal:offline] creating ${bundleFile}`);
execFileSync('tar', args, { stdio: 'inherit' });
const size = (fs.statSync(bundleFile).size / 1024 / 1024).toFixed(2);
console.log(`[devportal:offline] bundle ready (${size} MiB)`);
}
function main() {
ensureSpec();
ensureSdkFolder();
runBuild();
packageBundle();
}
main();

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env node
import { spawn } from 'node:child_process';
import { setTimeout as wait } from 'node:timers/promises';
import { LinkChecker } from 'linkinator';
const HOST = process.env.DEVPORT_HOST ?? '127.0.0.1';
const PORT = process.env.DEVPORT_PORT ?? '4321';
const BASE = `http://${HOST}:${PORT}`;
async function startPreview() {
return new Promise((resolve, reject) => {
const child = spawn('npm', ['run', 'preview', '--', '--host', HOST, '--port', PORT], {
cwd: new URL('..', import.meta.url).pathname,
stdio: 'ignore',
});
child.once('error', reject);
resolve(child);
});
}
async function waitForServer() {
const url = `${BASE}/`;
for (let i = 0; i < 60; i++) {
try {
const res = await fetch(url, { method: 'GET' });
if (res.ok) return;
} catch {
// keep polling
}
await wait(500);
}
throw new Error('Preview server did not become ready');
}
async function checkLinks() {
const checker = new LinkChecker();
const failures = [];
checker.on('link', (event) => {
if (event.state !== 'BROKEN') return;
failures.push({ url: event.url, status: event.status });
});
await checker.check({ path: BASE, recurse: true, maxDepth: 3, concurrency: 16, skip: [/mailto:/, /tel:/] });
if (failures.length > 0) {
console.error('[links] broken links found');
failures.forEach((f) => console.error(`- ${f.status} ${f.url}`));
process.exitCode = 1;
} else {
console.log('[links] no broken links detected');
}
}
async function main() {
const server = await startPreview();
try {
await waitForServer();
await checkLinks();
} finally {
server.kill('SIGINT');
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});

View File

@@ -0,0 +1,77 @@
#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
const moduleRoot = path.resolve(new URL('..', import.meta.url).pathname);
const distDir = path.join(moduleRoot, 'dist');
function folderSize(dir) {
let total = 0;
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
total += folderSize(full);
} else {
total += fs.statSync(full).size;
}
}
return total;
}
function largestFile(dir) {
let max = { size: 0, file: '' };
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
const child = largestFile(full);
if (child.size > max.size) max = child;
} else {
const size = fs.statSync(full).size;
if (size > max.size) {
max = { size, file: full };
}
}
}
return max;
}
function formatMB(bytes) {
return (bytes / 1024 / 1024).toFixed(2);
}
function main() {
if (!fs.existsSync(distDir)) {
console.error('[budget] dist/ not found; run `npm run build` first');
process.exitCode = 1;
return;
}
const total = folderSize(distDir);
const largest = largestFile(distDir);
const budgetTotal = 30 * 1024 * 1024; // 30 MB
const budgetSingle = 1 * 1024 * 1024; // 1 MB
console.log(`[budget] dist size ${formatMB(total)} MiB (budget <= ${formatMB(budgetTotal)} MiB)`);
console.log(`[budget] largest file ${formatMB(largest.size)} MiB -> ${path.relative(moduleRoot, largest.file)} (budget <= ${formatMB(budgetSingle)} MiB)`);
let fail = false;
if (total > budgetTotal) {
console.error('[budget] total size exceeds budget');
fail = true;
}
if (largest.size > budgetSingle) {
console.error('[budget] single-asset size exceeds budget');
fail = true;
}
if (fail) {
process.exitCode = 1;
} else {
console.log('[budget] budgets satisfied');
}
}
main();

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env node
import { spawn } from 'node:child_process';
import { setTimeout as wait } from 'node:timers/promises';
import { chromium } from 'playwright';
import AxeBuilder from '@axe-core/playwright';
const HOST = process.env.DEVPORT_HOST ?? '127.0.0.1';
const PORT = process.env.DEVPORT_PORT ?? '4321';
const BASE = `http://${HOST}:${PORT}`;
const PAGES = ['/docs/', '/docs/api-reference/', '/docs/try-it-console/'];
async function startPreview() {
return new Promise((resolve, reject) => {
const child = spawn('npm', ['run', 'preview', '--', '--host', HOST, '--port', PORT], {
cwd: new URL('..', import.meta.url).pathname,
stdio: 'inherit',
});
child.once('error', reject);
resolve(child);
});
}
async function waitForServer() {
const url = `${BASE}/`;
for (let i = 0; i < 60; i++) {
try {
const res = await fetch(url, { method: 'GET' });
if (res.ok) return;
} catch (err) {
// keep polling
}
await wait(500);
}
throw new Error('Preview server did not become ready');
}
async function runA11y() {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
const violationsAll = [];
for (const path of PAGES) {
const url = `${BASE}${path}`;
await page.goto(url, { waitUntil: 'networkidle' });
const axe = new AxeBuilder({ page }).withTags(['wcag2a', 'wcag2aa']);
const results = await axe.analyze();
if (results.violations.length > 0) {
violationsAll.push({ path, violations: results.violations });
}
}
await browser.close();
if (violationsAll.length > 0) {
console.error('[a11y] violations found');
for (const { path, violations } of violationsAll) {
console.error(`- ${path}`);
violations.forEach((v) => {
console.error(`${v.id}: ${v.description}`);
});
}
process.exitCode = 1;
} else {
console.log('[a11y] no violations detected');
}
}
async function main() {
const server = await startPreview();
try {
await waitForServer();
await runA11y();
} finally {
server.kill('SIGINT');
}
}
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});

View File

@@ -0,0 +1,62 @@
---
title: SDK Quickstarts
description: Deterministic, copy-ready SDK snippets aligned to the aggregate spec.
---
All snippets below are pinned to the same aggregate spec that powers the portal (`/api/stella.yaml`). Replace the placeholder token with a sandbox-scoped bearer token.
## Node.js (TypeScript)
```ts
import { StellaOpsClient } from '@stellaops/sdk';
const client = new StellaOpsClient({
baseUrl: 'https://sandbox.api.stellaops.local',
token: process.env.STELLAOPS_TOKEN ?? '<sandbox-token>',
});
async function run() {
const resp = await client.orchestrator.createJob({
workflow: 'sbom-verify',
source: 'registry:example/app@sha256:...',
});
console.log(resp.id, resp.status);
}
run().catch((err) => {
console.error(err);
process.exit(1);
});
```
## Python
```python
from stellaops import StellaOpsClient
import os
client = StellaOpsClient(
base_url="https://sandbox.api.stellaops.local",
token=os.getenv("STELLAOPS_TOKEN", "<sandbox-token>"),
)
job = client.orchestrator.create_job(
workflow="sbom-verify",
source="registry:example/app@sha256:...",
)
print(job["id"], job["status"])
```
## cURL (reference)
```bash
curl -X POST https://sandbox.api.stellaops.local/orchestrator/jobs \
-H 'Authorization: Bearer <sandbox-token>' \
-H 'Content-Type: application/json' \
-d '{"workflow":"sbom-verify","source":"registry:example/app@sha256:..."}'
```
## Notes
- Packages are assumed to be generated from tested examples; version tags should match the portal release when published.
- All snippets avoid retries to keep behaviour deterministic.
- Keep tokens short-lived and scoped to sandbox. Production tokens should not be used here.

View File

@@ -9,6 +9,7 @@ description: Drop-by-drop updates for the DevPortal surface.
- ✅ Embedded aggregate OpenAPI via RapiDoc using bundled `/api/stella.yaml`.
- ✅ Added schema viewer + version selector, copy-curl snippets, and example guide.
- ✅ Delivered Try-It console targeting sandbox with bearer-token onboarding and RapiDoc allow-try.
- ✅ Added SDK quickstarts (Node.js, Python) aligned to aggregate spec.
- 🔜 Operation-specific example rendering & SDK snippets (DEVPORT-63-002).
- 🔜 Try-It console against sandbox scopes (DEVPORT-63-001).

View File

@@ -140,11 +140,13 @@ app.MapHealthChecks("/excititor/health");
app.MapPost("/airgap/v1/vex/import", async (
[FromServices] AirgapImportValidator validator,
[FromServices] IAirgapImportStore store,
[FromServices] TimeProvider timeProvider,
[FromBody] AirgapImportRequest request,
CancellationToken cancellationToken) =>
{
var errors = validator.Validate(request, timeProvider.GetUtcNow());
var nowUtc = timeProvider.GetUtcNow();
var errors = validator.Validate(request, nowUtc);
if (errors.Count > 0)
{
var first = errors[0];
@@ -158,6 +160,22 @@ app.MapPost("/airgap/v1/vex/import", async (
});
}
var record = new AirgapImportRecord
{
Id = $"{request.BundleId}:{request.MirrorGeneration}",
BundleId = request.BundleId!,
MirrorGeneration = request.MirrorGeneration!,
SignedAt = request.SignedAt!.Value,
Publisher = request.Publisher!,
PayloadHash = request.PayloadHash!,
PayloadUrl = request.PayloadUrl,
Signature = request.Signature!,
TransparencyLog = request.TransparencyLog,
ImportedAt = nowUtc
};
await store.SaveAsync(record, cancellationToken).ConfigureAwait(false);
return Results.Accepted($"/airgap/v1/vex/import/{request.BundleId}", new
{
bundleId = request.BundleId,

View File

@@ -0,0 +1,29 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
namespace StellaOps.Excititor.Storage.Mongo;
public interface IAirgapImportStore
{
Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken);
}
internal sealed class MongoAirgapImportStore : IAirgapImportStore
{
private readonly IMongoCollection<AirgapImportRecord> _collection;
public MongoAirgapImportStore(IMongoDatabase database)
{
ArgumentNullException.ThrowIfNull(database);
VexMongoMappingRegistry.Register();
_collection = database.GetCollection<AirgapImportRecord>(VexMongoCollectionNames.AirgapImports);
}
public Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(record);
return _collection.InsertOneAsync(record, cancellationToken: cancellationToken);
}
}

View File

@@ -57,6 +57,7 @@ public static class VexMongoServiceCollectionExtensions
services.AddScoped<IVexCacheIndex, MongoVexCacheIndex>();
services.AddScoped<IVexCacheMaintenance, MongoVexCacheMaintenance>();
services.AddScoped<IVexConnectorStateRepository, MongoVexConnectorStateRepository>();
services.AddScoped<IAirgapImportStore, MongoAirgapImportStore>();
services.AddScoped<VexStatementBackfillService>();
services.AddScoped<IVexObservationLookup, MongoVexObservationLookup>();
services.AddSingleton<IVexMongoMigration, VexInitialIndexMigration>();

View File

@@ -1,69 +1,70 @@
using System.Threading;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace StellaOps.Excititor.Storage.Mongo;
public static class VexMongoMappingRegistry
{
private static int _initialized;
public static void Register()
{
if (Interlocked.Exchange(ref _initialized, 1) == 1)
{
return;
}
try
{
BsonSerializer.RegisterSerializer(typeof(byte[]), new ByteArraySerializer());
}
catch
{
// serializer already registered safe to ignore
}
RegisterClassMaps();
}
private static void RegisterClassMaps()
{
RegisterClassMap<VexProviderRecord>();
RegisterClassMap<VexProviderDiscoveryDocument>();
RegisterClassMap<VexProviderTrustDocument>();
RegisterClassMap<VexCosignTrustDocument>();
RegisterClassMap<VexConsensusRecord>();
RegisterClassMap<VexProductDocument>();
RegisterClassMap<VexConsensusSourceDocument>();
RegisterClassMap<VexConsensusConflictDocument>();
RegisterClassMap<VexConfidenceDocument>();
RegisterClassMap<VexSignalDocument>();
RegisterClassMap<VexSeveritySignalDocument>();
RegisterClassMap<VexClaimDocumentRecord>();
RegisterClassMap<VexSignatureMetadataDocument>();
RegisterClassMap<VexStatementRecord>();
using System.Threading;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace StellaOps.Excititor.Storage.Mongo;
public static class VexMongoMappingRegistry
{
private static int _initialized;
public static void Register()
{
if (Interlocked.Exchange(ref _initialized, 1) == 1)
{
return;
}
try
{
BsonSerializer.RegisterSerializer(typeof(byte[]), new ByteArraySerializer());
}
catch
{
// serializer already registered safe to ignore
}
RegisterClassMaps();
}
private static void RegisterClassMaps()
{
RegisterClassMap<VexProviderRecord>();
RegisterClassMap<VexProviderDiscoveryDocument>();
RegisterClassMap<VexProviderTrustDocument>();
RegisterClassMap<VexCosignTrustDocument>();
RegisterClassMap<VexConsensusRecord>();
RegisterClassMap<VexProductDocument>();
RegisterClassMap<VexConsensusSourceDocument>();
RegisterClassMap<VexConsensusConflictDocument>();
RegisterClassMap<VexConfidenceDocument>();
RegisterClassMap<VexSignalDocument>();
RegisterClassMap<VexSeveritySignalDocument>();
RegisterClassMap<VexClaimDocumentRecord>();
RegisterClassMap<VexSignatureMetadataDocument>();
RegisterClassMap<VexStatementRecord>();
RegisterClassMap<VexCacheEntryRecord>();
RegisterClassMap<VexConnectorStateDocument>();
RegisterClassMap<VexConsensusHoldRecord>();
}
private static void RegisterClassMap<TDocument>()
where TDocument : class
{
if (BsonClassMap.IsClassMapRegistered(typeof(TDocument)))
{
return;
}
BsonClassMap.RegisterClassMap<TDocument>(classMap =>
{
classMap.AutoMap();
classMap.SetIgnoreExtraElements(true);
});
}
}
RegisterClassMap<AirgapImportRecord>();
}
private static void RegisterClassMap<TDocument>()
where TDocument : class
{
if (BsonClassMap.IsClassMapRegistered(typeof(TDocument)))
{
return;
}
BsonClassMap.RegisterClassMap<TDocument>(classMap =>
{
classMap.AutoMap();
classMap.SetIgnoreExtraElements(true);
});
}
}
public static class VexMongoCollectionNames
{
public const string Migrations = "vex.migrations";
@@ -79,4 +80,5 @@ public static class VexMongoCollectionNames
public const string Attestations = "vex.attestations";
public const string Observations = "vex.observations";
public const string Linksets = "vex.linksets";
public const string AirgapImports = "vex.airgap_imports";
}

View File

@@ -33,6 +33,7 @@ internal static class TestServiceOverrides
services.RemoveAll<IVexCacheMaintenance>();
services.RemoveAll<IVexAttestationClient>();
services.RemoveAll<IVexSigner>();
services.RemoveAll<IAirgapImportStore>();
services.AddSingleton<IVexIngestOrchestrator, StubIngestOrchestrator>();
services.AddSingleton<IVexConnectorStateRepository, StubConnectorStateRepository>();
@@ -45,6 +46,7 @@ internal static class TestServiceOverrides
services.AddSingleton<IVexCacheMaintenance, StubCacheMaintenance>();
services.AddSingleton<IVexAttestationClient, StubAttestationClient>();
services.AddSingleton<IVexSigner, StubSigner>();
services.AddSingleton<IAirgapImportStore, StubAirgapImportStore>();
services.RemoveAll<IHostedService>();
services.AddSingleton<IHostedService, NoopHostedService>();
@@ -200,6 +202,17 @@ internal static class TestServiceOverrides
public ValueTask<VexSignedPayload> SignAsync(ReadOnlyMemory<byte> payload, CancellationToken cancellationToken)
=> ValueTask.FromResult(new VexSignedPayload("stub-signature", "stub-key"));
}
private sealed class StubAirgapImportStore : IAirgapImportStore
{
private readonly List<AirgapImportRecord> _records = new();
public Task SaveAsync(AirgapImportRecord record, CancellationToken cancellationToken)
{
_records.Add(record);
return Task.CompletedTask;
}
}
private sealed class StubIngestOrchestrator : IVexIngestOrchestrator
{

View File

@@ -0,0 +1,48 @@
using StellaOps.Findings.Ledger.WebService.Contracts;
using StellaOps.Findings.Ledger.WebService.Services;
using Xunit;
namespace StellaOps.Findings.Ledger.Tests.Exports;
public class ExportFiltersHashTests
{
private readonly ExportQueryService _service = new(new TestDataSource(), new Microsoft.Extensions.Logging.Abstractions.NullLogger<ExportQueryService>());
[Fact]
public void VexFiltersHash_IsDeterministic()
{
var requestA = new ExportVexRequest(
TenantId: "t1",
Shape: "canonical",
SinceSequence: 1,
UntilSequence: 10,
SinceObservedAt: null,
UntilObservedAt: null,
ProductId: "pkg:purl",
AdvisoryId: "ADV-1",
Status: "affected",
StatementType: "exploitation",
PageSize: 100,
FiltersHash: string.Empty,
PagingKey: null);
var requestB = requestA with { ProductId = "pkg:purl", AdvisoryId = "ADV-1" };
var left = _service.ComputeFiltersHash(requestA);
var right = _service.ComputeFiltersHash(requestB);
Assert.Equal(left, right);
}
private sealed class TestDataSource : StellaOps.Findings.Ledger.Infrastructure.Postgres.LedgerDataSource
{
public TestDataSource() : base(
Microsoft.Extensions.Options.Options.Create(new StellaOps.Findings.Ledger.Options.LedgerServiceOptions
{
Database = { ConnectionString = "Host=localhost;Username=test;Password=test;Database=test" }
}),
new Microsoft.Extensions.Logging.Abstractions.NullLogger<StellaOps.Findings.Ledger.Infrastructure.Postgres.LedgerDataSource>())
{
}
}
}

View File

@@ -0,0 +1,29 @@
namespace StellaOps.Findings.Ledger.WebService.Contracts;
public sealed record AttestationQueryRequest(
string TenantId,
string? ArtifactId,
string? FindingId,
string? AttestationId,
string? Status,
DateTimeOffset? SinceRecordedAt,
DateTimeOffset? UntilRecordedAt,
int Limit,
string FiltersHash,
AttestationPagingKey? PagingKey);
public sealed record AttestationPagingKey(DateTimeOffset RecordedAt, string AttestationId);
public sealed record AttestationExportItem(
string AttestationId,
string ArtifactId,
string? FindingId,
string VerificationStatus,
DateTimeOffset VerificationTime,
string DsseDigest,
string? RekorEntryId,
string? EvidenceBundleRef,
string LedgerEventId,
DateTimeOffset RecordedAt,
string MerkleLeafHash,
string RootHash);

View File

@@ -17,6 +17,55 @@ public sealed record ExportFindingsRequest(
public sealed record ExportPagingKey(long SequenceNumber, string PolicyVersion, string CycleHash);
public sealed record ExportVexRequest(
string TenantId,
string Shape,
long? SinceSequence,
long? UntilSequence,
DateTimeOffset? SinceObservedAt,
DateTimeOffset? UntilObservedAt,
string? ProductId,
string? AdvisoryId,
string? Status,
string? StatementType,
int PageSize,
string FiltersHash,
ExportPagingKey? PagingKey);
public sealed record ExportAdvisoryRequest(
string TenantId,
string Shape,
long? SinceSequence,
long? UntilSequence,
DateTimeOffset? SinceObservedAt,
DateTimeOffset? UntilObservedAt,
string? Severity,
string? Source,
string? CweId,
bool? Kev,
string? CvssVersion,
decimal? CvssScoreMin,
decimal? CvssScoreMax,
int PageSize,
string FiltersHash,
ExportPagingKey? PagingKey);
public sealed record ExportSbomRequest(
string TenantId,
string Shape,
long? SinceSequence,
long? UntilSequence,
DateTimeOffset? SinceObservedAt,
DateTimeOffset? UntilObservedAt,
string? SubjectDigest,
string? SbomFormat,
string? ComponentPurl,
bool? ContainsNative,
string? SlsaBuildType,
int PageSize,
string FiltersHash,
ExportPagingKey? PagingKey);
public sealed record FindingExportItem(
long EventSequence,
DateTimeOffset ObservedAt,

View File

@@ -151,6 +151,7 @@ builder.Services.AddSingleton<IConsoleCsrfValidator, ConsoleCsrfValidator>();
builder.Services.AddHostedService<LedgerMerkleAnchorWorker>();
builder.Services.AddHostedService<LedgerProjectionWorker>();
builder.Services.AddSingleton<ExportQueryService>();
builder.Services.AddSingleton<AttestationQueryService>();
var app = builder.Build();
@@ -290,20 +291,255 @@ app.MapGet("/ledger/export/findings", async Task<Results<FileStreamHttpResult, J
.ProducesProblem(StatusCodes.Status403Forbidden)
.ProducesProblem(StatusCodes.Status500InternalServerError);
app.MapGet("/ledger/export/vex", () => TypedResults.Json(new ExportPage<VexExportItem>(Array.Empty<VexExportItem>(), null)))
app.MapGet("/v1/ledger/attestations", async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<AttestationExportItem>>, ProblemHttpResult>> (
HttpContext httpContext,
AttestationQueryService attestationQueryService,
CancellationToken cancellationToken) =>
{
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
{
return tenantProblem!;
}
var request = new AttestationQueryRequest(
tenantId,
httpContext.Request.Query["artifactId"].ToString(),
httpContext.Request.Query["findingId"].ToString(),
httpContext.Request.Query["attestationId"].ToString(),
httpContext.Request.Query["status"].ToString(),
ParseDate(httpContext.Request.Query["sinceRecordedAt"]),
ParseDate(httpContext.Request.Query["untilRecordedAt"]),
attestationQueryService.ClampLimit(ParseInt(httpContext.Request.Query["limit"])),
FiltersHash: string.Empty,
PagingKey: null);
var filtersHash = attestationQueryService.ComputeFiltersHash(request);
AttestationPagingKey? pagingKey = null;
var pageToken = httpContext.Request.Query["page_token"].ToString();
if (!string.IsNullOrWhiteSpace(pageToken))
{
if (!attestationQueryService.TryParsePageToken(pageToken, filtersHash, out pagingKey, out var error))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: error ?? "invalid_page_token");
}
}
request = request with { FiltersHash = filtersHash, PagingKey = pagingKey };
ExportPage<AttestationExportItem> page;
try
{
page = await attestationQueryService.GetAttestationsAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (InvalidOperationException ex) when (ex.Message == "filters_hash_mismatch")
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "page_token_filters_mismatch");
}
return await WritePagedResponse(httpContext, page, cancellationToken).ConfigureAwait(false);
})
.WithName("LedgerAttestationsList")
.RequireAuthorization(LedgerExportPolicy)
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.MapGet("/ledger/export/vex", async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<VexExportItem>>, ProblemHttpResult>> (
HttpContext httpContext,
ExportQueryService exportQueryService,
CancellationToken cancellationToken) =>
{
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
{
return tenantProblem!;
}
var shape = httpContext.Request.Query["shape"].ToString();
if (string.IsNullOrWhiteSpace(shape))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_shape", detail: "shape is required (canonical|compact).");
}
var request = new ExportVexRequest(
tenantId,
shape,
ParseLong(httpContext.Request.Query["since_sequence"]),
ParseLong(httpContext.Request.Query["until_sequence"]),
ParseDate(httpContext.Request.Query["since_observed_at"]),
ParseDate(httpContext.Request.Query["until_observed_at"]),
httpContext.Request.Query["product_id"].ToString(),
httpContext.Request.Query["advisory_id"].ToString(),
httpContext.Request.Query["status"].ToString(),
httpContext.Request.Query["statement_type"].ToString(),
exportQueryService.ClampPageSize(ParseInt(httpContext.Request.Query["page_size"])),
filtersHash: string.Empty,
PagingKey: null);
var filtersHash = exportQueryService.ComputeFiltersHash(request);
ExportPagingKey? pagingKey = null;
var pageToken = httpContext.Request.Query["page_token"].ToString();
if (!string.IsNullOrWhiteSpace(pageToken))
{
if (!ExportPaging.TryParsePageToken(pageToken, filtersHash, out var parsedKey, out var error))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: error ?? "invalid_page_token");
}
pagingKey = new ExportPagingKey(parsedKey!.SequenceNumber, parsedKey.PolicyVersion, parsedKey.CycleHash);
}
request = request with { FiltersHash = filtersHash, PagingKey = pagingKey };
ExportPage<VexExportItem> page;
try
{
page = await exportQueryService.GetVexAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (InvalidOperationException ex) when (ex.Message == "filters_hash_mismatch")
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "page_token_filters_mismatch");
}
return await WritePagedResponse(httpContext, page, cancellationToken).ConfigureAwait(false);
})
.WithName("LedgerExportVex")
.RequireAuthorization(LedgerExportPolicy)
.Produces(StatusCodes.Status200OK);
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.MapGet("/ledger/export/advisories", () => TypedResults.Json(new ExportPage<AdvisoryExportItem>(Array.Empty<AdvisoryExportItem>(), null)))
app.MapGet("/ledger/export/advisories", async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<AdvisoryExportItem>>, ProblemHttpResult>> (
HttpContext httpContext,
ExportQueryService exportQueryService,
CancellationToken cancellationToken) =>
{
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
{
return tenantProblem!;
}
var shape = httpContext.Request.Query["shape"].ToString();
if (string.IsNullOrWhiteSpace(shape))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_shape", detail: "shape is required (canonical|compact).");
}
var kev = ParseBool(httpContext.Request.Query["kev"]);
var cvssScoreMin = ParseDecimal(httpContext.Request.Query["cvss_score_min"]);
var cvssScoreMax = ParseDecimal(httpContext.Request.Query["cvss_score_max"]);
var request = new ExportAdvisoryRequest(
tenantId,
shape,
ParseLong(httpContext.Request.Query["since_sequence"]),
ParseLong(httpContext.Request.Query["until_sequence"]),
ParseDate(httpContext.Request.Query["since_observed_at"]),
ParseDate(httpContext.Request.Query["until_observed_at"]),
httpContext.Request.Query["severity"].ToString(),
httpContext.Request.Query["source"].ToString(),
httpContext.Request.Query["cwe_id"].ToString(),
kev,
httpContext.Request.Query["cvss_version"].ToString(),
cvssScoreMin,
cvssScoreMax,
exportQueryService.ClampPageSize(ParseInt(httpContext.Request.Query["page_size"])),
filtersHash: string.Empty,
PagingKey: null);
var filtersHash = exportQueryService.ComputeFiltersHash(request);
ExportPagingKey? pagingKey = null;
var pageToken = httpContext.Request.Query["page_token"].ToString();
if (!string.IsNullOrWhiteSpace(pageToken))
{
if (!ExportPaging.TryParsePageToken(pageToken, filtersHash, out var parsedKey, out var error))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: error ?? "invalid_page_token");
}
pagingKey = new ExportPagingKey(parsedKey!.SequenceNumber, parsedKey.PolicyVersion, parsedKey.CycleHash);
}
request = request with { FiltersHash = filtersHash, PagingKey = pagingKey };
ExportPage<AdvisoryExportItem> page;
try
{
page = await exportQueryService.GetAdvisoriesAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (InvalidOperationException ex) when (ex.Message == "filters_hash_mismatch")
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "page_token_filters_mismatch");
}
return await WritePagedResponse(httpContext, page, cancellationToken).ConfigureAwait(false);
})
.WithName("LedgerExportAdvisories")
.RequireAuthorization(LedgerExportPolicy)
.Produces(StatusCodes.Status200OK);
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.MapGet("/ledger/export/sboms", () => TypedResults.Json(new ExportPage<SbomExportItem>(Array.Empty<SbomExportItem>(), null)))
app.MapGet("/ledger/export/sboms", async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<SbomExportItem>>, ProblemHttpResult>> (
HttpContext httpContext,
ExportQueryService exportQueryService,
CancellationToken cancellationToken) =>
{
if (!TryGetTenant(httpContext, out var tenantProblem, out var tenantId))
{
return tenantProblem!;
}
var shape = httpContext.Request.Query["shape"].ToString();
if (string.IsNullOrWhiteSpace(shape))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_shape", detail: "shape is required (canonical|compact).");
}
var request = new ExportSbomRequest(
tenantId,
shape,
ParseLong(httpContext.Request.Query["since_sequence"]),
ParseLong(httpContext.Request.Query["until_sequence"]),
ParseDate(httpContext.Request.Query["since_observed_at"]),
ParseDate(httpContext.Request.Query["until_observed_at"]),
httpContext.Request.Query["subject_digest"].ToString(),
httpContext.Request.Query["sbom_format"].ToString(),
httpContext.Request.Query["component_purl"].ToString(),
ParseBool(httpContext.Request.Query["contains_native"]),
httpContext.Request.Query["slsa_build_type"].ToString(),
exportQueryService.ClampPageSize(ParseInt(httpContext.Request.Query["page_size"])),
filtersHash: string.Empty,
PagingKey: null);
var filtersHash = exportQueryService.ComputeFiltersHash(request);
ExportPagingKey? pagingKey = null;
var pageToken = httpContext.Request.Query["page_token"].ToString();
if (!string.IsNullOrWhiteSpace(pageToken))
{
if (!ExportPaging.TryParsePageToken(pageToken, filtersHash, out var parsedKey, out var error))
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: error ?? "invalid_page_token");
}
pagingKey = new ExportPagingKey(parsedKey!.SequenceNumber, parsedKey.PolicyVersion, parsedKey.CycleHash);
}
request = request with { FiltersHash = filtersHash, PagingKey = pagingKey };
ExportPage<SbomExportItem> page;
try
{
page = await exportQueryService.GetSbomsAsync(request, cancellationToken).ConfigureAwait(false);
}
catch (InvalidOperationException ex) when (ex.Message == "filters_hash_mismatch")
{
return TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "page_token_filters_mismatch");
}
return await WritePagedResponse(httpContext, page, cancellationToken).ConfigureAwait(false);
})
.WithName("LedgerExportSboms")
.RequireAuthorization(LedgerExportPolicy)
.Produces(StatusCodes.Status200OK);
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status400BadRequest);
app.MapPost("/internal/ledger/orchestrator-export", async Task<Results<Accepted<OrchestratorExportResponse>, ProblemHttpResult>> (
HttpContext httpContext,
@@ -394,6 +630,22 @@ app.MapPost("/internal/ledger/airgap-import", async Task<Results<Accepted<Airgap
.ProducesProblem(StatusCodes.Status400BadRequest)
.ProducesProblem(StatusCodes.Status409Conflict);
app.MapGet("/.well-known/openapi", () =>
{
var contentRoot = AppContext.BaseDirectory;
var candidate = Path.GetFullPath(Path.Combine(contentRoot, "../../docs/modules/findings-ledger/openapi/findings-ledger.v1.yaml"));
if (!File.Exists(candidate))
{
return Results.Problem(statusCode: StatusCodes.Status500InternalServerError, title: "openapi_missing", detail: "OpenAPI document not found on server.");
}
var yaml = File.ReadAllText(candidate);
return Results.Text(yaml, "application/yaml");
})
.WithName("LedgerOpenApiDocument")
.Produces(StatusCodes.Status200OK)
.ProducesProblem(StatusCodes.Status500InternalServerError);
app.Run();
static Created<LedgerEventResponse> CreateCreatedResponse(LedgerEventRecord record)
@@ -444,3 +696,42 @@ static async Task<Results<FileStreamHttpResult, JsonHttpResult<ExportPage<T>>, P
return TypedResults.Json(page);
}
static bool TryGetTenant(HttpContext httpContext, out ProblemHttpResult? problem, out string tenantId)
{
tenantId = string.Empty;
if (!httpContext.Request.Headers.TryGetValue("X-Stella-Tenant", out var tenantValues) || string.IsNullOrWhiteSpace(tenantValues))
{
problem = TypedResults.Problem(statusCode: StatusCodes.Status400BadRequest, title: "missing_tenant");
return false;
}
tenantId = tenantValues.ToString();
problem = null;
return true;
}
static int? ParseInt(string value)
{
return int.TryParse(value, out var result) ? result : null;
}
static long? ParseLong(string value)
{
return long.TryParse(value, out var result) ? result : null;
}
static DateTimeOffset? ParseDate(string value)
{
return DateTimeOffset.TryParse(value, out var result) ? result : null;
}
static decimal? ParseDecimal(string value)
{
return decimal.TryParse(value, out var result) ? result : null;
}
static bool? ParseBool(string value)
{
return bool.TryParse(value, out var result) ? result : null;
}

View File

@@ -22,12 +22,6 @@ public sealed class ExportQueryService
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public ExportPage<VexExportItem> GetVexEmpty() => new(Array.Empty<VexExportItem>(), null);
public ExportPage<AdvisoryExportItem> GetAdvisoriesEmpty() => new(Array.Empty<AdvisoryExportItem>(), null);
public ExportPage<SbomExportItem> GetSbomsEmpty() => new(Array.Empty<SbomExportItem>(), null);
public int ClampPageSize(int? requested)
{
if (!requested.HasValue || requested.Value <= 0)
@@ -54,6 +48,64 @@ public sealed class ExportQueryService
return ExportPaging.ComputeFiltersHash(filters);
}
public string ComputeFiltersHash(ExportVexRequest request)
{
var filters = new Dictionary<string, string?>
{
["shape"] = request.Shape,
["since_sequence"] = request.SinceSequence?.ToString(),
["until_sequence"] = request.UntilSequence?.ToString(),
["since_observed_at"] = request.SinceObservedAt?.ToString("O"),
["until_observed_at"] = request.UntilObservedAt?.ToString("O"),
["product_id"] = request.ProductId,
["advisory_id"] = request.AdvisoryId,
["status"] = request.Status,
["statement_type"] = request.StatementType
};
return ExportPaging.ComputeFiltersHash(filters);
}
public string ComputeFiltersHash(ExportAdvisoryRequest request)
{
var filters = new Dictionary<string, string?>
{
["shape"] = request.Shape,
["since_sequence"] = request.SinceSequence?.ToString(),
["until_sequence"] = request.UntilSequence?.ToString(),
["since_observed_at"] = request.SinceObservedAt?.ToString("O"),
["until_observed_at"] = request.UntilObservedAt?.ToString("O"),
["severity"] = request.Severity,
["source"] = request.Source,
["cwe_id"] = request.CweId,
["kev"] = request.Kev?.ToString(),
["cvss_version"] = request.CvssVersion,
["cvss_score_min"] = request.CvssScoreMin?.ToString(),
["cvss_score_max"] = request.CvssScoreMax?.ToString()
};
return ExportPaging.ComputeFiltersHash(filters);
}
public string ComputeFiltersHash(ExportSbomRequest request)
{
var filters = new Dictionary<string, string?>
{
["shape"] = request.Shape,
["since_sequence"] = request.SinceSequence?.ToString(),
["until_sequence"] = request.UntilSequence?.ToString(),
["since_observed_at"] = request.SinceObservedAt?.ToString("O"),
["until_observed_at"] = request.UntilObservedAt?.ToString("O"),
["subject_digest"] = request.SubjectDigest,
["sbom_format"] = request.SbomFormat,
["component_purl"] = request.ComponentPurl,
["contains_native"] = request.ContainsNative?.ToString(),
["slsa_build_type"] = request.SlsaBuildType
};
return ExportPaging.ComputeFiltersHash(filters);
}
public async Task<ExportPage<FindingExportItem>> GetFindingsAsync(ExportFindingsRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
@@ -211,4 +263,41 @@ public sealed class ExportQueryService
return new ExportPage<FindingExportItem>(items, nextPageToken);
}
public Task<ExportPage<VexExportItem>> GetVexAsync(ExportVexRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
if (!string.Equals(request.FiltersHash, ComputeFiltersHash(request), StringComparison.Ordinal))
{
throw new InvalidOperationException("filters_hash_mismatch");
}
// Data source to be implemented; deterministic empty page for now.
return Task.FromResult(new ExportPage<VexExportItem>(Array.Empty<VexExportItem>(), null));
}
public Task<ExportPage<AdvisoryExportItem>> GetAdvisoriesAsync(ExportAdvisoryRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
if (!string.Equals(request.FiltersHash, ComputeFiltersHash(request), StringComparison.Ordinal))
{
throw new InvalidOperationException("filters_hash_mismatch");
}
return Task.FromResult(new ExportPage<AdvisoryExportItem>(Array.Empty<AdvisoryExportItem>(), null));
}
public Task<ExportPage<SbomExportItem>> GetSbomsAsync(ExportSbomRequest request, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(request);
if (!string.Equals(request.FiltersHash, ComputeFiltersHash(request), StringComparison.Ordinal))
{
throw new InvalidOperationException("filters_hash_mismatch");
}
return Task.FromResult(new ExportPage<SbomExportItem>(Array.Empty<SbomExportItem>(), null));
}
}

View File

@@ -7,3 +7,9 @@
| LEDGER-AIRGAP-56-001 | DONE | Mirror bundle provenance recording | 2025-11-22 |
Status changes must be mirrored in `docs/implplan/SPRINT_0120_0000_0001_policy_reasoning.md`.
# Findings Ledger · Sprint 0121-0001-0001
| Task ID | Status | Notes | Updated (UTC) |
| --- | --- | --- | --- |
| LEDGER-OBS-54-001 | DONE | Implemented `/v1/ledger/attestations` with deterministic paging, filter hash guard, and schema/OpenAPI updates. | 2025-11-22 |

View File

@@ -25,12 +25,13 @@ Project SBOM, advisory, VEX, and policy overlay data into a tenant-scoped proper
- .NET 10 preview workers (HostedService + channel pipelines).
- MongoDB for node/edge storage; S3-compatible buckets for layout tiles/snapshots if needed.
- Scheduler integration (jobs, change streams) to handle incremental updates.
- Analytics: clustering/centrality pipelines with Mongo-backed snapshot provider and overlays; change-stream/backfill worker with idempotency store (Mongo or in-memory) and retry/backoff.
## Definition of Done
- Pipelines deterministic and tested; fixtures validated.
- Metrics/logs/traces wired with tenant context.
- Schema docs + OpenAPI (where applicable) updated; compliance checklist appended.
- Offline kit includes seed data for air-gapped installs.
- Offline kit includes seed data for air-gapped installs, including analytics overlays (`overlays/*.ndjson` with manifest) ordered deterministically.
## Required Reading
- `docs/modules/graph/architecture.md`

View File

@@ -0,0 +1,7 @@
namespace StellaOps.Graph.Indexer.Infrastructure;
public sealed class MongoDatabaseOptions
{
public string ConnectionString { get; set; } = string.Empty;
public string DatabaseName { get; set; } = "stellaops-graph";
}

View File

@@ -0,0 +1,48 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MongoDB.Driver;
namespace StellaOps.Graph.Indexer.Infrastructure;
public static class MongoServiceCollectionExtensions
{
public static IServiceCollection AddGraphMongoDatabase(
this IServiceCollection services,
Action<MongoDatabaseOptions> configure)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(configure);
services.Configure(configure);
services.AddSingleton<IMongoClient>(sp =>
{
var opts = sp.GetRequiredService<IOptions<MongoDatabaseOptions>>().Value;
Validate(opts);
return new MongoClient(opts.ConnectionString);
});
services.AddSingleton<IMongoDatabase>(sp =>
{
var opts = sp.GetRequiredService<IOptions<MongoDatabaseOptions>>().Value;
Validate(opts);
return sp.GetRequiredService<IMongoClient>().GetDatabase(opts.DatabaseName);
});
return services;
}
private static void Validate(MongoDatabaseOptions options)
{
if (string.IsNullOrWhiteSpace(options.ConnectionString))
{
throw new InvalidOperationException("Mongo connection string must be provided.");
}
if (string.IsNullOrWhiteSpace(options.DatabaseName))
{
throw new InvalidOperationException("Mongo database name must be provided.");
}
}
}

View File

@@ -15,5 +15,6 @@
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.0-rc.2.25502.107" />
<PackageReference Include="MongoDB.Driver" Version="3.5.0" />
<PackageReference Include="MongoDB.Bson" Version="3.5.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="10.0.0-rc.2.25502.107" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,125 @@
using System.Collections.Immutable;
using System.Text.Json.Nodes;
using Mongo2Go;
using MongoDB.Bson;
using MongoDB.Driver;
using StellaOps.Graph.Indexer.Analytics;
using StellaOps.Graph.Indexer.Incremental;
namespace StellaOps.Graph.Indexer.Tests;
public sealed class MongoProviderIntegrationTests : IAsyncLifetime
{
private readonly MongoDbRunner _runner;
private IMongoDatabase _database = default!;
public MongoProviderIntegrationTests()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
}
public Task InitializeAsync()
{
var client = new MongoClient(_runner.ConnectionString);
_database = client.GetDatabase("graph-indexer-tests");
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public async Task SnapshotProvider_ReadsPendingSnapshots()
{
var snapshots = _database.GetCollection<BsonDocument>("graph_snapshots");
var nodes = new BsonArray
{
new BsonDocument
{
{ "id", "gn:tenant-a:component:1" },
{ "kind", "component" },
{ "attributes", new BsonDocument { { "purl", "pkg:npm/a@1.0.0" } } }
}
};
var edges = new BsonArray();
await snapshots.InsertOneAsync(new BsonDocument
{
{ "tenant", "tenant-a" },
{ "snapshot_id", "snap-1" },
{ "generated_at", DateTime.UtcNow },
{ "nodes", nodes },
{ "edges", edges }
});
var provider = new MongoGraphSnapshotProvider(_database);
var pending = await provider.GetPendingSnapshotsAsync(CancellationToken.None);
Assert.Single(pending);
Assert.Equal("snap-1", pending[0].SnapshotId);
Assert.Single(pending[0].Nodes);
await provider.MarkProcessedAsync("tenant-a", "snap-1", CancellationToken.None);
var none = await provider.GetPendingSnapshotsAsync(CancellationToken.None);
Assert.Empty(none);
}
[Fact]
public async Task ChangeEventSource_EnumeratesAndHonorsIdempotency()
{
var changes = _database.GetCollection<BsonDocument>("graph_change_events");
await changes.InsertManyAsync(new[]
{
new BsonDocument
{
{ "tenant", "tenant-a" },
{ "snapshot_id", "snap-1" },
{ "sequence_token", "seq-1" },
{ "is_backfill", false },
{ "nodes", new BsonArray { new BsonDocument { { "id", "gn:1" }, { "kind", "component" } } } },
{ "edges", new BsonArray() }
},
new BsonDocument
{
{ "tenant", "tenant-a" },
{ "snapshot_id", "snap-1" },
{ "sequence_token", "seq-2" },
{ "is_backfill", false },
{ "nodes", new BsonArray { new BsonDocument { { "id", "gn:2" }, { "kind", "component" } } } },
{ "edges", new BsonArray() }
}
});
var source = new MongoGraphChangeEventSource(_database);
var idempotency = new MongoIdempotencyStore(_database);
var events = new List<GraphChangeEvent>();
await foreach (var change in source.ReadAsync(CancellationToken.None))
{
if (await idempotency.HasSeenAsync(change.SequenceToken, CancellationToken.None))
{
continue;
}
events.Add(change);
await idempotency.MarkSeenAsync(change.SequenceToken, CancellationToken.None);
}
Assert.Equal(2, events.Count);
var secondPass = new List<GraphChangeEvent>();
await foreach (var change in source.ReadAsync(CancellationToken.None))
{
if (!await idempotency.HasSeenAsync(change.SequenceToken, CancellationToken.None))
{
secondPass.Add(change);
}
}
Assert.Empty(secondPass);
}
}

View File

@@ -0,0 +1,44 @@
using Microsoft.Extensions.DependencyInjection;
using StellaOps.Graph.Indexer.Infrastructure;
using Mongo2Go;
using MongoDB.Driver;
namespace StellaOps.Graph.Indexer.Tests;
public sealed class MongoServiceCollectionExtensionsTests : IAsyncLifetime
{
private MongoDbRunner _runner = default!;
public Task InitializeAsync()
{
_runner = MongoDbRunner.Start(singleNodeReplSet: true);
return Task.CompletedTask;
}
public Task DisposeAsync()
{
_runner.Dispose();
return Task.CompletedTask;
}
[Fact]
public void AddGraphMongoDatabase_RegistersClientAndDatabase()
{
var services = new ServiceCollection();
services.AddGraphMongoDatabase(options =>
{
options.ConnectionString = _runner.ConnectionString;
options.DatabaseName = "graph-indexer-ext-tests";
});
var provider = services.BuildServiceProvider();
var client = provider.GetService<IMongoClient>();
var database = provider.GetService<IMongoDatabase>();
Assert.NotNull(client);
Assert.NotNull(database);
Assert.Equal("graph-indexer-ext-tests", database!.DatabaseNamespace.DatabaseName);
}
}

View File

@@ -12,5 +12,6 @@
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Mongo2Go" Version="3.1.3" />
</ItemGroup>
</Project>

View File

@@ -21,6 +21,9 @@ public sealed class DenoLanguageAnalyzer : ILanguageAnalyzer
await TryWriteRuntimeShimAsync(context, cancellationToken).ConfigureAwait(false);
// Optional runtime capture: executes only when STELLA_DENO_ENTRYPOINT is provided.
await DenoRuntimeTraceRunner.TryExecuteAsync(context, logger: null, cancellationToken).ConfigureAwait(false);
var workspace = await DenoWorkspaceNormalizer.NormalizeAsync(context, cancellationToken).ConfigureAwait(false);
var moduleGraph = DenoModuleGraphResolver.Resolve(workspace, cancellationToken);
var compatibility = DenoNpmCompatibilityAdapter.Analyze(workspace, moduleGraph, cancellationToken);

View File

@@ -1,3 +1,4 @@
using System.Runtime.InteropServices;
using StellaOps.Scanner.Analyzers.Lang;
using StellaOps.Scanner.Analyzers.Lang.Deno.Internal.Runtime;
using StellaOps.Scanner.Analyzers.Lang.Deno.Tests.TestUtilities;
@@ -74,23 +75,18 @@ public sealed class DenoRuntimeTraceRunnerTests
}
[Fact]
public async Task ExecutesShimAndWritesRuntime_WhenDenoPresent()
public async Task ExecutesShimAndWritesRuntime_WithStubbedDeno()
{
var binary = DenoBinaryLocator.Find();
if (string.IsNullOrWhiteSpace(binary))
{
return; // gracefully skip when deno is unavailable in the environment
}
var root = TestPaths.CreateTemporaryDirectory();
try
{
var stub = CreateStubDeno(root);
var entry = Path.Combine(root, "main.ts");
var fixture = Path.Combine(TestPaths.GetProjectRoot(), "TestFixtures/deno-runtime/simple/main.ts");
File.Copy(fixture, entry);
using var entryEnv = new EnvironmentVariableScope("STELLA_DENO_ENTRYPOINT", "main.ts");
using var binaryEnv = new EnvironmentVariableScope("STELLA_DENO_BINARY", binary);
using var binaryEnv = new EnvironmentVariableScope("STELLA_DENO_BINARY", stub);
using var denoDirEnv = new EnvironmentVariableScope("DENO_DIR", Path.Combine(root, ".deno-cache"));
var context = new LanguageAnalyzerContext(root, TimeProvider.System);
@@ -111,6 +107,46 @@ public sealed class DenoRuntimeTraceRunnerTests
}
}
private static string CreateStubDeno(string root)
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
var fileName = isWindows ? "deno.cmd" : "deno";
var path = Path.Combine(root, fileName);
if (isWindows)
{
var lines = new[]
{
"@echo off",
"echo {\"type\":\"deno.runtime.start\",\"ts\":\"2025-01-01T00:00:00Z\",\"module\":{\"normalized\":\".\",\"path_sha256\":\"0\"},\"reason\":\"shim-start\"}>deno-runtime.ndjson",
"echo {\"type\":\"deno.module.load\",\"ts\":\"2025-01-01T00:00:01Z\",\"module\":{\"normalized\":\"main.ts\",\"path_sha256\":\"abc\"},\"reason\":\"static-import\",\"permissions\":[] }>>deno-runtime.ndjson",
"exit /b 0"
};
File.WriteAllLines(path, lines);
}
else
{
var script = """#!/usr/bin/env bash
set -euo pipefail
cat > deno-runtime.ndjson <<'EOF'
{"type":"deno.runtime.start","ts":"2025-01-01T00:00:00Z","module":{"normalized":".","path_sha256":"0"},"reason":"shim-start"}
{"type":"deno.module.load","ts":"2025-01-01T00:00:01Z","module":{"normalized":"main.ts","path_sha256":"abc"},"reason":"static-import","permissions":[]}
EOF
""";
File.WriteAllText(path, script);
try
{
System.Diagnostics.Process.Start("chmod", $"+x {path}")?.WaitForExit();
}
catch
{
// best effort; on Windows this branch won't execute
}
}
return path;
}
private sealed class EnvironmentVariableScope : IDisposable
{
private readonly string _name;

View File

@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.IO;
using StellaOps.Zastava.Core.Configuration;
namespace StellaOps.Zastava.Observer.Configuration;
@@ -90,6 +91,12 @@ public sealed class ZastavaObserverOptions
[Required]
public ZastavaObserverPostureOptions Posture { get; set; } = new();
/// <summary>
/// Surface secret names used by the observer.
/// </summary>
[Required]
public ZastavaSurfaceSecretsOptions Secrets { get; init; } = new();
/// <summary>
/// Root path for accessing host process information (defaults to /host/proc).
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using StellaOps.Zastava.Core.Configuration;
namespace StellaOps.Zastava.Webhook.Configuration;
@@ -17,7 +18,10 @@ public sealed class ZastavaWebhookOptions
[Required]
public ZastavaWebhookBackendOptions Backend { get; init; } = new();
}
[Required]
public ZastavaSurfaceSecretsOptions Secrets { get; init; } = new();
}
public sealed class ZastavaWebhookAdmissionOptions
{

View File

@@ -12,7 +12,7 @@ internal interface IWebhookSurfaceFsClient
internal sealed class WebhookSurfaceFsClient : IWebhookSurfaceFsClient
{
private readonly ISurfaceManifestReader _manifestReader;
private readonly SurfaceManifestPathBuilder _pathBuilder;
private readonly SurfaceManifestStoreOptions _storeOptions;
private readonly IOptions<ZastavaRuntimeOptions> _runtimeOptions;
public WebhookSurfaceFsClient(
@@ -34,7 +34,7 @@ internal sealed class WebhookSurfaceFsClient : IWebhookSurfaceFsClient
throw new ArgumentNullException(nameof(storeOptions));
}
_pathBuilder = new SurfaceManifestPathBuilder(cacheOptions.Value, storeOptions.Value);
_storeOptions = storeOptions.Value ?? throw new ArgumentNullException(nameof(storeOptions.Value));
}
public async Task<(bool Found, string? ManifestUri)> TryGetManifestAsync(string manifestDigest, CancellationToken cancellationToken = default)
@@ -57,9 +57,36 @@ internal sealed class WebhookSurfaceFsClient : IWebhookSurfaceFsClient
? manifest.Tenant
: _runtimeOptions.Value.Tenant;
var digestHex = SurfaceManifestPathBuilder.EnsureSha256Digest(manifestDigest); // strips sha256:
var uri = _pathBuilder.BuildManifestUri(tenant, digestHex);
var digestHex = EnsureSha256Digest(manifestDigest); // strips sha256:
var uri = BuildManifestUri(_storeOptions, tenant, digestHex);
return (true, uri);
}
private static string BuildManifestUri(SurfaceManifestStoreOptions storeOptions, string tenant, string digestHex)
{
var tenantSegment = SanitizeTenant(tenant);
return $"{storeOptions.Scheme}://{storeOptions.Bucket}/{storeOptions.Prefix}/{tenantSegment}/{digestHex[..2]}/{digestHex[2..4]}/{digestHex}.json";
}
private static string SanitizeTenant(string value)
=> string.IsNullOrWhiteSpace(value)
? "default"
: value.Replace('/', '_').Replace('\\', '_');
private static string EnsureSha256Digest(string manifestDigest)
{
if (string.IsNullOrWhiteSpace(manifestDigest))
{
throw new ArgumentException("Digest cannot be null or empty.", nameof(manifestDigest));
}
const string prefix = "sha256:";
if (!manifestDigest.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException("Only sha256 digests are supported.", nameof(manifestDigest));
}
return manifestDigest[prefix.Length..].ToLowerInvariant();
}
}

View File

@@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
namespace StellaOps.Zastava.Core.Configuration;
/// <summary>
/// Shared secret naming conventions for Zastava components when resolving Surface secrets.
/// </summary>
public sealed class ZastavaSurfaceSecretsOptions
{
/// <summary>
/// Secret name used for CAS access credentials (observer only).
/// </summary>
[Required(AllowEmptyStrings = false)]
public string CasAccessName { get; init; } = "cas-access";
/// <summary>
/// Secret name used for attestation verification keys.
/// </summary>
[Required(AllowEmptyStrings = false)]
public string AttestationName { get; init; } = "attestation";
}

View File

@@ -71,7 +71,9 @@ public sealed class AdmissionResponseBuilderTests
Assert.NotNull(response.Response.AuditAnnotations);
Assert.True(envelope.Decision.Images.First().HasSbomReferrers);
Assert.StartsWith("sha256-", envelope.Decision.PodSpecDigest, StringComparison.Ordinal);
Assert.Equal("cas://surface-cache/manifests/tenant-a/abcd.json", envelope.Decision.Images.First().Metadata["surfacePointer"]);
var metadata = envelope.Decision.Images.First().Metadata;
Assert.NotNull(metadata);
Assert.Equal("cas://surface-cache/manifests/tenant-a/abcd.json", metadata["surfacePointer"]);
}
[Fact]

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -euo pipefail
# Minimal helper to run the LNM-21-002/003-related slices with TRX output.
# Use a clean environment to reduce "invalid test source" issues seen locally.
export DOTNET_CLI_TELEMETRY_OPTOUT=1
export DOTNET_ROLL_FORWARD=Major
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
pushd "$root_dir" >/dev/null
dotnet test \
src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/StellaOps.Concelier.Core.Tests.csproj \
--filter "AdvisoryObservationAggregationTests" \
--logger "trx;LogFileName=core-linksets.trx"
dotnet test \
src/Concelier/__Tests/StellaOps.Concelier.Storage.Mongo.Tests/StellaOps.Concelier.Storage.Mongo.Tests.csproj \
--filter "ConcelierMongoLinksetStoreTests" \
--logger "trx;LogFileName=storage-linksets.trx"
popd >/dev/null