Refactor SurfaceCacheValidator to simplify oldest entry calculation

Add global using for Xunit in test project

Enhance ImportValidatorTests with async validation and quarantine checks

Implement FileSystemQuarantineServiceTests for quarantine functionality

Add integration tests for ImportValidator to check monotonicity

Create BundleVersionTests to validate version parsing and comparison logic

Implement VersionMonotonicityCheckerTests for monotonicity checks and activation logic
This commit is contained in:
master
2025-12-16 10:44:00 +02:00
parent b1f40945b7
commit 4391f35d8a
107 changed files with 10844 additions and 287 deletions

View File

@@ -18,13 +18,20 @@
- Expanded tests for DSSE, TUF, Merkle helpers.
- Added trust store + root rotation policy (dual approval) and import validator that coordinates DSSE/TUF/Merkle/rotation checks.
## Updates (2025-12-15)
- Added monotonicity enforcement primitives under `src/AirGap/StellaOps.AirGap.Importer/Versioning/` (`BundleVersion`, `IVersionMonotonicityChecker`, `IBundleVersionStore`).
- Added file-based quarantine service under `src/AirGap/StellaOps.AirGap.Importer/Quarantine/` (`IQuarantineService`, `FileSystemQuarantineService`, `QuarantineOptions`).
- Updated `ImportValidator` to include monotonicity checks, force-activate support (requires reason), and quarantine on validation failures.
- Added Postgres-backed bundle version tracking in `src/AirGap/StellaOps.AirGap.Storage.Postgres/Repositories/PostgresBundleVersionStore.cs` and registration via `src/AirGap/StellaOps.AirGap.Storage.Postgres/ServiceCollectionExtensions.cs`.
- Updated tests in `tests/AirGap/StellaOps.AirGap.Importer.Tests` to cover versioning/quarantine and the new import validator behavior.
## Next implementation hooks
- Replace placeholder plan with actual DSSE + TUF verifiers; keep step ordering stable.
- Feed trust roots from sealed-mode config and Evidence Locker bundles (once available) before allowing imports.
- Record audit trail for each plan step (success/failure) and a Merkle root of staged content.
## Determinism/air-gap posture
- No network dependencies; only BCL used.
- No network dependencies; BCL + `Microsoft.Extensions.*` only.
- Tests use cached local NuGet feed (`local-nugets/`).
- Plan steps are ordered list; do not reorder without bumping downstream replay expectations.

View File

@@ -0,0 +1,39 @@
# AirGap Quarantine Investigation Runbook
## Purpose
Quarantine preserves failed bundle imports for offline forensic analysis. It keeps the original bundle and the verification context (reason + logs) so operators can diagnose tampering, trust-root drift, or packaging issues without re-running in an online environment.
## Location & Structure
Default root: `/updates/quarantine`
Per-tenant layout:
`/updates/quarantine/<tenantId>/<timestamp>-<reason>-<id>/`
Removal staging:
`/updates/quarantine/<tenantId>/.removed/<quarantineId>/`
## Files in a quarantine entry
- `bundle.tar.zst` - the original bundle as provided
- `manifest.json` - bundle manifest (when available)
- `verification.log` - validation step output (TUF/DSSE/Merkle/rotation/monotonicity, etc.)
- `failure-reason.txt` - human-readable failure summary (reason + timestamp + metadata)
- `quarantine.json` - structured metadata for listing/automation
## Investigation steps (offline)
1. Identify the tenant and locate the quarantine root on the importer host.
2. Pick the newest quarantine entry for the tenant (timestamp prefix).
3. Read `failure-reason.txt` first to capture the top-level reason and metadata.
4. Review `verification.log` for the precise failing step.
5. If needed, extract and inspect `bundle.tar.zst` in an isolated workspace (no network).
6. Decide whether the entry should be retained (for audit) or removed after investigation.
## Removal & Retention
- Removal requires a human-provided reason (audit trail). Implementations should use the quarantine services remove operation which moves entries under `.removed/`.
- Retention and quota controls are configured via `AirGap:Quarantine` settings (root, TTL, max size); TTL cleanup can remove entries older than the retention period.
## Common failure categories
- `tuf:*` - invalid/expired metadata or snapshot hash mismatch
- `dsse:*` - signature invalid or trust root mismatch
- `merkle-*` - payload entry set invalid or empty
- `rotation:*` - root rotation policy failure (dual approval, no-op rotation, etc.)
- `version-non-monotonic:*` - rollback prevention triggered (force activation requires a justification)

175
docs/db/schemas/scanner.sql Normal file
View File

@@ -0,0 +1,175 @@
-- =============================================================================
-- SCANNER SCHEMA - ProofSpine Audit Trail Tables
-- Version: V3100_001
-- Sprint: SPRINT_3100_0001_0001
-- =============================================================================
CREATE SCHEMA IF NOT EXISTS scanner;
-- =============================================================================
-- PROOF SPINES
-- =============================================================================
-- Main proof spine table - represents a complete verifiable decision chain
-- from SBOM through vulnerability matching to final VEX verdict
CREATE TABLE scanner.proof_spines (
spine_id TEXT PRIMARY KEY,
artifact_id TEXT NOT NULL,
vuln_id TEXT NOT NULL,
policy_profile_id TEXT NOT NULL,
verdict TEXT NOT NULL CHECK (verdict IN (
'not_affected', 'affected', 'fixed', 'under_investigation'
)),
verdict_reason TEXT,
root_hash TEXT NOT NULL,
scan_run_id TEXT NOT NULL,
segment_count INT NOT NULL DEFAULT 0,
created_at_utc TIMESTAMPTZ NOT NULL DEFAULT NOW(),
superseded_by_spine_id TEXT REFERENCES scanner.proof_spines(spine_id),
-- Deterministic spine ID = hash(artifact_id + vuln_id + policy_profile_id + root_hash)
CONSTRAINT proof_spines_unique_decision UNIQUE (artifact_id, vuln_id, policy_profile_id, root_hash)
);
-- Composite index for common lookups
CREATE INDEX idx_proof_spines_lookup
ON scanner.proof_spines(artifact_id, vuln_id, policy_profile_id);
CREATE INDEX idx_proof_spines_scan_run
ON scanner.proof_spines(scan_run_id);
CREATE INDEX idx_proof_spines_created
ON scanner.proof_spines(created_at_utc DESC);
CREATE INDEX idx_proof_spines_verdict
ON scanner.proof_spines(verdict);
-- =============================================================================
-- PROOF SEGMENTS
-- =============================================================================
-- Individual segments within a spine - each segment is DSSE-signed
CREATE TABLE scanner.proof_segments (
segment_id TEXT PRIMARY KEY,
spine_id TEXT NOT NULL REFERENCES scanner.proof_spines(spine_id) ON DELETE CASCADE,
idx INT NOT NULL,
segment_type TEXT NOT NULL CHECK (segment_type IN (
'SbomSlice', 'Match', 'Reachability',
'GuardAnalysis', 'RuntimeObservation', 'PolicyEval'
)),
input_hash TEXT NOT NULL,
result_hash TEXT NOT NULL,
prev_segment_hash TEXT,
envelope_json TEXT NOT NULL, -- DSSE envelope as JSON
tool_id TEXT NOT NULL,
tool_version TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'Pending' CHECK (status IN (
'Pending', 'Verified', 'Partial', 'Invalid', 'Untrusted'
)),
created_at_utc TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT proof_segments_unique_idx UNIQUE (spine_id, idx)
);
CREATE INDEX idx_proof_segments_spine ON scanner.proof_segments(spine_id);
CREATE INDEX idx_proof_segments_type ON scanner.proof_segments(segment_type);
CREATE INDEX idx_proof_segments_status ON scanner.proof_segments(status);
-- =============================================================================
-- PROOF SPINE HISTORY
-- =============================================================================
-- Audit trail for spine lifecycle events (creation, supersession, verification)
CREATE TABLE scanner.proof_spine_history (
history_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
spine_id TEXT NOT NULL REFERENCES scanner.proof_spines(spine_id),
action TEXT NOT NULL CHECK (action IN (
'created', 'superseded', 'verified', 'invalidated'
)),
actor TEXT,
reason TEXT,
occurred_at_utc TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_proof_spine_history_spine ON scanner.proof_spine_history(spine_id);
CREATE INDEX idx_proof_spine_history_action ON scanner.proof_spine_history(action);
CREATE INDEX idx_proof_spine_history_occurred ON scanner.proof_spine_history(occurred_at_utc DESC);
-- =============================================================================
-- VERIFICATION CACHE
-- =============================================================================
-- Caches verification results to avoid re-verifying unchanged spines
CREATE TABLE scanner.proof_spine_verification_cache (
spine_id TEXT PRIMARY KEY REFERENCES scanner.proof_spines(spine_id) ON DELETE CASCADE,
verified_at_utc TIMESTAMPTZ NOT NULL DEFAULT NOW(),
verifier_version TEXT NOT NULL,
all_segments_valid BOOLEAN NOT NULL,
invalid_segment_ids TEXT[],
signature_algorithm TEXT NOT NULL,
key_fingerprint TEXT NOT NULL
);
CREATE INDEX idx_verification_cache_verified ON scanner.proof_spine_verification_cache(verified_at_utc DESC);
-- =============================================================================
-- FUNCTIONS
-- =============================================================================
-- Function to update segment count after segment insert
CREATE OR REPLACE FUNCTION scanner.update_spine_segment_count()
RETURNS TRIGGER AS $$
BEGIN
UPDATE scanner.proof_spines
SET segment_count = (
SELECT COUNT(*) FROM scanner.proof_segments WHERE spine_id = NEW.spine_id
)
WHERE spine_id = NEW.spine_id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger to maintain segment count
CREATE TRIGGER trg_update_segment_count
AFTER INSERT OR DELETE ON scanner.proof_segments
FOR EACH ROW EXECUTE FUNCTION scanner.update_spine_segment_count();
-- Function to record history on spine events
CREATE OR REPLACE FUNCTION scanner.record_spine_history()
RETURNS TRIGGER AS $$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO scanner.proof_spine_history (spine_id, action, reason)
VALUES (NEW.spine_id, 'created', 'Spine created');
ELSIF TG_OP = 'UPDATE' AND NEW.superseded_by_spine_id IS NOT NULL
AND OLD.superseded_by_spine_id IS NULL THEN
INSERT INTO scanner.proof_spine_history (spine_id, action, reason)
VALUES (OLD.spine_id, 'superseded', 'Superseded by ' || NEW.superseded_by_spine_id);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Trigger to record spine history
CREATE TRIGGER trg_record_spine_history
AFTER INSERT OR UPDATE ON scanner.proof_spines
FOR EACH ROW EXECUTE FUNCTION scanner.record_spine_history();
-- =============================================================================
-- COMMENTS
-- =============================================================================
COMMENT ON TABLE scanner.proof_spines IS
'Verifiable decision chains from SBOM to VEX verdict with cryptographic integrity';
COMMENT ON TABLE scanner.proof_segments IS
'Individual DSSE-signed evidence segments within a proof spine';
COMMENT ON TABLE scanner.proof_spine_history IS
'Audit trail for spine lifecycle events';
COMMENT ON COLUMN scanner.proof_spines.root_hash IS
'SHA256 hash of concatenated segment result hashes for tamper detection';
COMMENT ON COLUMN scanner.proof_segments.prev_segment_hash IS
'Hash chain linking - NULL for first segment, result_hash of previous segment otherwise';
COMMENT ON COLUMN scanner.proof_segments.envelope_json IS
'DSSE envelope containing signed segment payload';

View File

@@ -1,40 +1,71 @@
# Sprint 0338-0001-0001: AirGap Importer Core Enhancements
# Sprint 0338.0001.0001 - AirGap Importer Monotonicity & Quarantine
**Sprint ID:** SPRINT_0338_0001_0001
**Topic:** AirGap Importer Monotonicity & Quarantine
**Priority:** P0 (Critical)
**Working Directory:** `src/AirGap/StellaOps.AirGap.Importer/`
**Related Modules:** `StellaOps.AirGap.Controller`, `StellaOps.ExportCenter.Core`
## Topic & Scope
- Implement rollback prevention (monotonicity enforcement) and failed-bundle quarantine handling for the AirGap Importer to prevent replay attacks and support forensic analysis of failed imports.
- **Sprint ID:** `SPRINT_0338_0001_0001`
- **Priority:** P0 (Critical)
- **Working directory:** `src/AirGap/StellaOps.AirGap.Importer/` (primary); allowed cross-module edits: `src/AirGap/StellaOps.AirGap.Storage.Postgres/`, `src/AirGap/StellaOps.AirGap.Storage.Postgres.Tests/`, `tests/AirGap/StellaOps.AirGap.Importer.Tests/`.
- **Related modules:** `StellaOps.AirGap.Controller`, `StellaOps.ExportCenter.Core`
- **Source advisory:** `docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md`
- **Gaps addressed:** G6 (Monotonicity), G7 (Quarantine)
**Source Advisory:** 14-Dec-2025 - Offline and Air-Gap Technical Reference
**Gaps Addressed:** G6 (Monotonicity), G7 (Quarantine)
## Dependencies & Concurrency
- **Dependencies:** `StellaOps.AirGap.Storage.Postgres` (version store), `StellaOps.AirGap.Controller` (state coordination), `StellaOps.Infrastructure.Time` / `TimeProvider` (time source).
- **Concurrency:** Safe to execute in parallel with unrelated module sprints; requires schema/migration alignment with AirGap Postgres storage work.
---
## Documentation Prerequisites
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/modules/platform/architecture-overview.md`
- `docs/modules/airgap/mirror-dsse-plan.md`
- `docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md`
## Objective
Implement security-critical rollback prevention (monotonicity enforcement) and failed-bundle quarantine handling for the AirGap Importer. These are foundational supply-chain security requirements that prevent replay attacks and enable forensic analysis of failed imports.
---
## Delivery Tracker
| ID | Task | Status | Owner | Notes |
|----|------|--------|-------|-------|
| T1 | Design monotonicity version model | TODO | | SemVer or timestamp-based |
| T2 | Implement `IVersionMonotonicityChecker` interface | TODO | | |
| T3 | Create `BundleVersionStore` for tracking active versions | TODO | | Postgres-backed |
| T4 | Add monotonicity check to `ImportValidator` | TODO | | Reject if `version <= current` |
| T5 | Implement `--force-activate` override with audit trail | TODO | | Non-monotonic override logging |
| T6 | Design quarantine directory structure | TODO | | Per advisory §11.3 |
| T7 | Implement `IQuarantineService` interface | TODO | | |
| T8 | Create `FileSystemQuarantineService` | TODO | | |
| T9 | Integrate quarantine into import failure paths | TODO | | All failure modes |
| T10 | Add quarantine cleanup/retention policy | TODO | | Configurable TTL |
| T11 | Write unit tests for monotonicity checker | TODO | | |
| T12 | Write unit tests for quarantine service | TODO | | |
| T13 | Write integration tests for import with monotonicity | TODO | | |
| T14 | Update module AGENTS.md | TODO | | |
| # | Task ID | Status | Key dependency / next step | Owners | Task Definition |
|---:|--------|--------|----------------------------|--------|-----------------|
| 1 | T1 | DONE | Define ordering rules | AirGap Guild | Design monotonicity version model (SemVer + `createdAt` tiebreaker) |
| 2 | T2 | DONE | After T1 | AirGap Guild | Implement `IVersionMonotonicityChecker` interface |
| 3 | T3 | DONE | After T1 | AirGap Guild | Create Postgres-backed bundle version store + migration |
| 4 | T4 | DONE | After T2, T3 | AirGap Guild | Add monotonicity check to `ImportValidator` (reject `version <= current`) |
| 5 | T5 | DONE | After T4 | AirGap Guild | Implement `--force-activate` override with audit trail |
| 6 | T6 | DONE | Define path schema | AirGap Guild | Design quarantine directory structure (per advisory A11.3) |
| 7 | T7 | DONE | After T6 | AirGap Guild | Implement `IQuarantineService` interface |
| 8 | T8 | DONE | After T7 | AirGap Guild | Create `FileSystemQuarantineService` |
| 9 | T9 | DONE | After T8 | AirGap Guild | Integrate quarantine into import failure paths |
| 10 | T10 | DONE | After T8 | AirGap Guild | Add quarantine cleanup/retention policy (TTL + quota) |
| 11 | T11 | DONE | After T1-T5 | QA Guild | Unit tests for monotonicity checker/version compare |
| 12 | T12 | DONE | After T6-T10 | QA Guild | Unit tests for quarantine service |
| 13 | T13 | DONE | After T1-T12 | QA Guild | Integration tests for import + monotonicity + quarantine |
| 14 | T14 | DONE | After code changes | AirGap Guild | Update module `AGENTS.md` for new versioning/quarantine behavior |
---
## Wave Coordination
- **Wave 1 (T1-T2):** Version model + monotonicity interfaces.
- **Wave 2 (T3):** Postgres schema + version store implementation.
- **Wave 3 (T4-T5):** Import validation integration + force-activate audit trail.
- **Wave 4 (T6-T10):** Quarantine design + filesystem implementation + retention.
- **Wave 5 (T11-T14):** Tests (unit + integration) + AGENTS/doc sync.
## Wave Detail Snapshots
- **Wave 1 evidence:** New types under `src/AirGap/StellaOps.AirGap.Importer/Versioning/`.
- **Wave 2 evidence:** Postgres store in `src/AirGap/StellaOps.AirGap.Storage.Postgres/Repositories/PostgresBundleVersionStore.cs` (idempotent schema creation) and registration in `src/AirGap/StellaOps.AirGap.Storage.Postgres/ServiceCollectionExtensions.cs`.
- **Wave 3 evidence:** `src/AirGap/StellaOps.AirGap.Importer/Validation/ImportValidator.cs` monotonicity gate and force-activate flow.
- **Wave 4 evidence:** `src/AirGap/StellaOps.AirGap.Importer/Quarantine/` and options wiring.
- **Wave 5 evidence:** `tests/AirGap/StellaOps.AirGap.Importer.Tests/` tests; AGENTS updates under `src/AirGap/` and `src/AirGap/StellaOps.AirGap.Importer/`.
## Interlocks
- Postgres migration numbering/runner in `StellaOps.AirGap.Storage.Postgres` must remain deterministic and idempotent.
- Controller/Importer contract: confirm where `tenantId`, `bundleType`, `manifest.version`, and `manifest.createdAt` originate and how force-activate justification is captured.
## Upcoming Checkpoints
- 2025-12-15: Completed T1-T14; validated with `dotnet test tests/AirGap/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj -c Release`.
## Action Tracker
- Bundle digest is required at the validation boundary (`ImportValidationRequest.BundleDigest`).
- Quarantine is invoked on validation failures in `ImportValidator.ValidateAsync`.
---
@@ -249,7 +280,7 @@ public async Task<BundleValidationResult> ValidateAsync(
#### Quarantine Directory Structure
Per advisory §11.3:
Per advisory A11.3:
```
/updates/quarantine/<timestamp>-<reason>/
bundle.tar.zst # Original bundle
@@ -496,7 +527,7 @@ public sealed class QuarantineOptions
### Quarantine (G7)
- [ ] Failed imports automatically quarantine the bundle
- [ ] Quarantine directory structure matches advisory §11.3
- [ ] Quarantine directory structure matches advisory A11.3
- [ ] `failure-reason.txt` contains human-readable summary
- [ ] `verification.log` contains detailed verification output
- [ ] Quarantine entries are tenant-isolated
@@ -507,14 +538,6 @@ public sealed class QuarantineOptions
---
## Dependencies
- `StellaOps.AirGap.Storage.Postgres` for version store
- `StellaOps.AirGap.Controller` for state coordination
- `StellaOps.Infrastructure.Time` for `TimeProvider`
---
## Decisions & Risks
| Decision | Rationale | Risk |
@@ -524,13 +547,21 @@ public sealed class QuarantineOptions
| File-based quarantine | Simple, works in air-gap without DB | Disk space concerns; mitigated by quota and TTL |
| Tenant-isolated quarantine paths | Multi-tenancy requirement | Cross-tenant investigation requires admin access |
### Risk Table
| Risk | Impact | Mitigation | Owner |
|------|--------|------------|-------|
| Postgres activation contention / ordering drift | Rollback prevention can be bypassed under races | Use transactional upsert + deterministic compare and persist history; fail closed on ambiguity | AirGap Guild |
| Quarantine disk exhaustion | Importer becomes unavailable | Enforce TTL + max size; cleanup job; keep quarantines tenant-isolated | AirGap Guild |
| Force-activate misuse | Operators normalize non-monotonic overrides | Require non-empty reason; store `was_force_activated` + `force_activate_reason`; emit structured warning logs | AirGap Guild |
---
## Testing Strategy
1. **Unit tests** for `BundleVersion.Parse` and `IsNewerThan` with edge cases
2. **Unit tests** for `FileSystemQuarantineService` with mock filesystem
3. **Integration tests** for full import monotonicity check quarantine flow
3. **Integration tests** for full import + monotonicity check + quarantine flow
4. **Load tests** for quarantine cleanup under volume
---
@@ -539,4 +570,13 @@ public sealed class QuarantineOptions
- Update `docs/airgap/importer-scaffold.md` with monotonicity and quarantine sections
- Add `docs/airgap/runbooks/quarantine-investigation.md` runbook
- Update `src/AirGap/AGENTS.md` with new interfaces
- Update `src/AirGap/AGENTS.md` and `src/AirGap/StellaOps.AirGap.Importer/AGENTS.md` with new versioning/quarantine interfaces
---
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-15 | Normalised sprint file to standard template sections; set T1-T12 and T14 to DOING (implementation started). | Project Mgmt |
| 2025-12-15 | Implemented monotonicity + quarantine + Postgres version store + tests; ran `dotnet test tests/AirGap/StellaOps.AirGap.Importer.Tests/StellaOps.AirGap.Importer.Tests.csproj -c Release` (pass). Marked T1-T14 as DONE. | Implementer |

View File

@@ -1,16 +1,26 @@
# Sprint Series 035x - Testing Quality Guardrails Index
# Sprint 0354.0001.0001 - Testing Quality Guardrails Index
## Overview
## Topic & Scope
This sprint series implements the Testing Quality Guardrails from the 14-Dec-2025 product advisory. The series consists of 4 sprints with 40 total tasks.
This sprint is a coordination/index sprint for the Testing Quality Guardrails sprint series (0350-0353) from the 14-Dec-2025 product advisory. The series consists of 4 sprints with 40 total tasks.
**Source Advisory:** `docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md`
- **Working directory:** `docs/implplan`
- **Source advisory:** `docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md`
- **Master documentation:** `docs/testing/testing-quality-guardrails-implementation.md`
**Master Documentation:** `docs/testing/testing-quality-guardrails-implementation.md`
## Dependencies & Concurrency
- Sprints 0350/0351/0352 are designed to run in parallel; 0353 follows 0352 (soft dependency).
- Keep shared paths deconflicted and deterministic: `scripts/ci/**`, `tests/**`, `.gitea/workflows/**`, `bench/baselines/**`.
## Documentation Prerequisites
- `docs/README.md`
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
- `docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md`
- `docs/testing/testing-quality-guardrails-implementation.md`
---
## Sprint Index
## Delivery Tracker
| Sprint | Title | Tasks | Status | Dependencies |
|--------|-------|-------|--------|--------------|
@@ -21,7 +31,7 @@ This sprint series implements the Testing Quality Guardrails from the 14-Dec-202
---
## Sprint Files
## Wave Detail Snapshots
### Sprint 0350: CI Quality Gates Foundation
**File:** `SPRINT_0350_0001_0001_ci_quality_gates_foundation.md`
@@ -91,7 +101,7 @@ This sprint series implements the Testing Quality Guardrails from the 14-Dec-202
---
## Execution Phases
## Wave Coordination
### Phase 1: Parallel Foundation (Sprints 0350, 0351, 0352)
@@ -126,6 +136,20 @@ Week 3:
---
## Interlocks
- Any new CI gates must default to deterministic, offline-friendly execution and produce auditable artifacts.
- Threshold calibration errors can block valid PRs; prefer warn-mode rollouts until baselines stabilize.
- Mutation testing can be too slow for per-PR; keep it on a weekly cadence unless profiles improve.
## Upcoming Checkpoints
- Weekly: sync this index table with sub-sprint Delivery Tracker statuses.
## Action Tracker
- Keep the `Delivery Tracker` table statuses aligned with the owning sprint files (0350-0353).
- Ensure `docs/testing/testing-quality-guardrails-implementation.md` links to every sprint and deliverable path.
---
## Task ID Naming Convention
| Sprint | Prefix | Example |
@@ -183,7 +207,7 @@ Week 3:
---
## Risk Register
## Decisions & Risks
| Risk | Impact | Mitigation | Owner |
|------|--------|------------|-------|
@@ -216,3 +240,11 @@ Sprint series is complete when:
| Security Tests | Security Team |
| Scanner Fixtures | Scanner Team |
| Mutation Testing | Platform Team |
---
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-15 | Renamed sprint file from `SPRINT_035x_0001_0001_testing_quality_guardrails_index.md` to `SPRINT_0354_0001_0001_testing_quality_guardrails_index.md` and normalised headings to the standard template; no semantic changes to series scope. | Project Mgmt |

View File

@@ -1,6 +1,6 @@
# SPRINT_1100_0001_0001 - CallGraph.v1 Schema Enhancement
**Status:** TODO
**Status:** DOING
**Priority:** P1 - HIGH
**Module:** Scanner Libraries, Signals
**Working Directory:** `src/Scanner/__Libraries/StellaOps.Scanner.Reachability/`
@@ -676,22 +676,22 @@ public static class CallgraphSchemaMigrator
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Update `CallgraphDocument` with schema field | TODO | | Add version constant |
| 2 | Update `CallgraphNode` with visibility, isEntrypointCandidate | TODO | | Backward compatible |
| 3 | Update `CallgraphEdge` with reason enum | TODO | | 13 reason codes |
| 4 | Create `CallgraphEntrypoint` model | TODO | | With route/framework |
| 5 | Create `EdgeReason` enum | TODO | | Per §3.3 |
| 6 | Create `EntrypointKind` enum | TODO | | Per §3.4 |
| 7 | Create `EntrypointFramework` enum | TODO | | Per §3.4 |
| 8 | Create `CallgraphSchemaMigrator` | TODO | | Legacy compatibility |
| 1 | Update `CallgraphDocument` with schema field | DONE | | Schema property with CallgraphSchemaVersions.V1 |
| 2 | Update `CallgraphNode` with visibility, isEntrypointCandidate | DONE | | SymbolVisibility, SymbolKey, ArtifactKey added |
| 3 | Update `CallgraphEdge` with reason enum | DONE | | EdgeReason + EdgeKind + Weight properties |
| 4 | Create `CallgraphEntrypoint` model | DONE | | With Kind, Route, HttpMethod, Framework, Phase |
| 5 | Create `EdgeReason` enum | DONE | | 13 reason codes in EdgeReason.cs |
| 6 | Create `EntrypointKind` enum | DONE | | EntrypointKind.cs with 12 kinds |
| 7 | Create `EntrypointFramework` enum | DONE | | EntrypointFramework.cs with 19 frameworks |
| 8 | Create `CallgraphSchemaMigrator` | DONE | | Full implementation with inference logic |
| 9 | Update `DotNetCallgraphBuilder` to emit reasons | TODO | | Map IL opcodes to reasons |
| 10 | Update `JavaCallgraphBuilder` to emit reasons | TODO | | Map bytecode to reasons |
| 11 | Update `NativeCallgraphBuilder` to emit reasons | TODO | | DT_NEEDED → DirectCall |
| 12 | Update callgraph parser to handle v1 schema | TODO | | Validate schema field |
| 12 | Update callgraph parser to handle v1 schema | DONE | | CallgraphSchemaMigrator.EnsureV1() |
| 13 | Add visibility extraction in .NET analyzer | TODO | | From MethodAttributes |
| 14 | Add visibility extraction in Java analyzer | TODO | | From access flags |
| 15 | Add entrypoint route extraction | TODO | | Parse [Route] attributes |
| 16 | Update Signals ingestion to migrate legacy | TODO | | Auto-upgrade on ingest |
| 16 | Update Signals ingestion to migrate legacy | DONE | | CallgraphIngestionService uses migrator |
| 17 | Unit tests for schema migration | TODO | | Legacy → v1 |
| 18 | Golden fixtures for v1 schema | TODO | | Determinism tests |
| 19 | Update documentation | TODO | | Schema reference |

View File

@@ -1,6 +1,6 @@
# SPRINT_1101_0001_0001 - Unknowns Ranking Enhancement
**Status:** TODO
**Status:** DOING
**Priority:** P1 - HIGH
**Module:** Signals, Scheduler
**Working Directory:** `src/Signals/StellaOps.Signals/`
@@ -816,23 +816,23 @@ public sealed class UnknownsRescanWorker : BackgroundService
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Enhance `UnknownSymbolDocument` with scoring fields | TODO | | Per §3.1 |
| 2 | Create `UnknownFlags` model | TODO | | 7 flag types |
| 3 | Create `UnknownsBand` enum | TODO | | HOT/WARM/COLD |
| 4 | Create `UnknownsNormalizationTrace` | TODO | | Debugging support |
| 5 | Create `UnknownsScoringOptions` | TODO | | Per §3.3 |
| 6 | Create `IUnknownsScoringService` interface | TODO | | |
| 7 | Implement `UnknownsScoringService` | TODO | | 5-factor formula |
| 8 | Create `IDeploymentRefsRepository` | TODO | | Popularity lookups |
| 9 | Create `IGraphMetricsRepository` | TODO | | Centrality lookups |
| 10 | Implement Postgres repositories | TODO | | Per §3.4 |
| 11 | Create database migrations | TODO | | `V1101_001` |
| 12 | Create `UnknownsRescanWorker` | TODO | | Scheduler integration |
| 13 | Add appsettings configuration | TODO | | Weight defaults |
| 14 | Add API endpoint `GET /unknowns` | TODO | | Query by band |
| 15 | Add API endpoint `GET /unknowns/{id}/explain` | TODO | | Score breakdown |
| 16 | Add metrics/telemetry | TODO | | Band distribution |
| 17 | Unit tests for scoring service | TODO | | Formula verification |
| 1 | Enhance `UnknownSymbolDocument` with scoring fields | DONE | | Band, NormalizationTrace, CompositeScore properties |
| 2 | Create `UnknownFlags` model | DONE | | 7 flag types in UnknownFlags.cs |
| 3 | Create `UnknownsBand` enum | DONE | | Hot/Warm/Cold in UnknownsBand.cs |
| 4 | Create `UnknownsNormalizationTrace` | DONE | | UnknownsNormalizationTrace.cs |
| 5 | Create `UnknownsScoringOptions` | DONE | | UnknownsScoringOptions.cs |
| 6 | Create `IUnknownsScoringService` interface | DONE | | IUnknownsScoringService.cs |
| 7 | Implement `UnknownsScoringService` | DONE | | 5-factor formula implemented |
| 8 | Create `IDeploymentRefsRepository` | DONE | | Popularity lookups |
| 9 | Create `IGraphMetricsRepository` | DONE | | Centrality lookups |
| 10 | Implement Postgres repositories | DONE | | PostgresUnknownsRepository.cs |
| 11 | Create database migrations | DONE | | Signals schema with unknowns table |
| 12 | Create `UnknownsRescanWorker` | DONE | | UnknownsRescanWorker.cs with IRescanOrchestrator |
| 13 | Add appsettings configuration | DONE | | Options pattern with weights |
| 14 | Add API endpoint `GET /unknowns` | DONE | | Query by band with pagination |
| 15 | Add API endpoint `GET /unknowns/{id}/explain` | DONE | | Score breakdown with normalization trace |
| 16 | Add metrics/telemetry | DONE | | UnknownsRescanMetrics.cs with band distribution gauges |
| 17 | Unit tests for scoring service | DONE | | UnknownsScoringServiceTests.cs |
| 18 | Integration tests | TODO | | End-to-end flow |
| 19 | Documentation | TODO | | Algorithm reference |

View File

@@ -583,20 +583,20 @@ public interface IProofSpineRepository
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create `StellaOps.Scanner.ProofSpine` project | DOING | | New library under Scanner |
| 2 | Define `ProofSpineModels.cs` data types | TODO | | As specified in §3.1 |
| 3 | Create Postgres migration `V3100_001` | TODO | | Schema per §3.2 |
| 4 | Implement `ProofSpineBuilder` | TODO | | Core chaining logic §3.3 |
| 5 | Implement `IProofSpineRepository` | TODO | | Postgres implementation |
| 6 | Implement `PostgresProofSpineRepository` | TODO | | With EF Core or Dapper |
| 7 | Add DSSE signing integration | TODO | | Wire to Signer module |
| 8 | Create `ProofSpineVerifier` service | TODO | | Verify chain integrity |
| 9 | Add API endpoint `GET /spines/{id}` | TODO | | In Scanner.WebService |
| 10 | Add API endpoint `GET /scans/{id}/spines` | TODO | | List spines for scan |
| 1 | Create `StellaOps.Scanner.ProofSpine` project | DONE | | Library at `__Libraries/StellaOps.Scanner.ProofSpine/` |
| 2 | Define `ProofSpineModels.cs` data types | DONE | | Models, enums, GuardCondition |
| 3 | Create Postgres schema `scanner.sql` | DONE | | `docs/db/schemas/scanner.sql` with triggers |
| 4 | Implement `ProofSpineBuilder` | DONE | | Full builder with canonical hashing |
| 5 | Implement `IProofSpineRepository` | DONE | | Interface defined |
| 6 | Implement `PostgresProofSpineRepository` | DONE | | Full CRUD in Scanner.Storage |
| 7 | Add DSSE signing integration | DONE | | Uses IDsseSigningService, ICryptoProfile |
| 8 | Create `ProofSpineVerifier` service | DONE | | Chain verification implemented |
| 9 | Add API endpoint `GET /spines/{id}` | DONE | | ProofSpineEndpoints.cs |
| 10 | Add API endpoint `GET /scans/{id}/spines` | DONE | | ProofSpineEndpoints.cs |
| 11 | Integrate into VEX decision flow | TODO | | Policy.Engine calls builder |
| 12 | Add spine reference to ReplayManifest | TODO | | Replay.Core update |
| 13 | Unit tests for ProofSpineBuilder | TODO | | Golden fixtures |
| 14 | Integration tests with Postgres | TODO | | Testcontainers |
| 13 | Unit tests for ProofSpineBuilder | DONE | | ProofSpineBuilderTests.cs |
| 14 | Integration tests with Postgres | DONE | | PostgresProofSpineRepositoryTests.cs |
| 15 | Update OpenAPI spec | TODO | | Document spine endpoints |
| 16 | Documentation update | TODO | | Architecture dossier |

View File

@@ -1037,22 +1037,22 @@ public sealed record PolicyEvaluationEvidence(string PolicyDigest, string Verdic
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create OpenAPI spec `scanner/openapi.yaml` | TODO | | Per §3.1 |
| 2 | Define request/response DTOs | TODO | | Match OpenAPI schemas |
| 3 | Implement `POST /api/scans` endpoint | TODO | | Scan creation |
| 4 | Implement `POST /api/scans/{id}/callgraphs` | TODO | | With Content-Digest idempotency |
| 5 | Implement `POST /api/scans/{id}/runtimeevidence` | TODO | | Evidence submission |
| 6 | Implement `POST /api/scans/{id}/sbom` | TODO | | SBOM association |
| 7 | Implement `POST /api/scans/{id}/compute-reachability` | TODO | | Trigger computation |
| 8 | Implement `GET /api/scans/{id}/reachability/components` | TODO | | Component query |
| 9 | Implement `GET /api/scans/{id}/reachability/findings` | TODO | | Finding query |
| 10 | Implement `GET /api/scans/{id}/reachability/explain` | TODO | | Explain with path witness |
| 11 | Implement `GET /api/scans/{id}/exports/sarif` | TODO | | SARIF export |
| 12 | Implement `GET /api/scans/{id}/exports/cdxr` | TODO | | CycloneDX-R export |
| 13 | Implement `GET /api/scans/{id}/exports/openvex` | TODO | | OpenVEX export |
| 14 | Implement `ICallGraphIngestionService` | TODO | | Digest dedup, validation |
| 15 | Implement `IReachabilityExplainService` | TODO | | Path witness, evidence chain |
| 16 | Add endpoint authorization | TODO | | Scope-based access |
| 1 | Create OpenAPI spec `scanner/openapi.yaml` | DONE | | Full spec at Api/OpenApi/scanner/ |
| 2 | Define request/response DTOs | DONE | | ReachabilityContracts.cs, CallGraphContracts.cs, SbomContracts.cs |
| 3 | Implement `POST /api/scans` endpoint | DONE | | ScanEndpoints.cs |
| 4 | Implement `POST /api/scans/{id}/callgraphs` | DONE | | CallGraphEndpoints.cs with Content-Digest idempotency |
| 5 | Implement `POST /api/scans/{id}/runtimeevidence` | DONE | | RuntimeEndpoints.cs |
| 6 | Implement `POST /api/scans/{id}/sbom` | DONE | | SbomEndpoints.cs with format detection |
| 7 | Implement `POST /api/scans/{id}/compute-reachability` | DONE | | ReachabilityEndpoints.cs |
| 8 | Implement `GET /api/scans/{id}/reachability/components` | DONE | | ReachabilityEndpoints.cs |
| 9 | Implement `GET /api/scans/{id}/reachability/findings` | DONE | | ReachabilityEndpoints.cs |
| 10 | Implement `GET /api/scans/{id}/reachability/explain` | DONE | | ReachabilityEndpoints.cs |
| 11 | Implement `GET /api/scans/{id}/exports/sarif` | DONE | | ExportEndpoints.cs |
| 12 | Implement `GET /api/scans/{id}/exports/cdxr` | DONE | | ExportEndpoints.cs |
| 13 | Implement `GET /api/scans/{id}/exports/openvex` | DONE | | ExportEndpoints.cs |
| 14 | Implement `ICallGraphIngestionService` | DONE | | ICallGraphIngestionService.cs, ISbomIngestionService.cs |
| 15 | Define reachability service interfaces | DONE | | IReachabilityQueryService, IReachabilityExplainService |
| 16 | Add endpoint authorization | DONE | | ScannerPolicies in place |
| 17 | Integration tests | TODO | | Full flow tests |
| 18 | Merge into stella.yaml aggregate | TODO | | API composition |
| 19 | CLI integration | TODO | | `stella scan` commands |

View File

@@ -950,20 +950,20 @@ public interface ISuppressionOverrideProvider
| # | Task ID | Status | Description | Assignee | Notes |
|---|---------|--------|-------------|----------|-------|
| 1 | SDIFF-FND-001 | DOING | Create `StellaOps.Scanner.SmartDiff` project | | New library |
| 1 | SDIFF-FND-001 | DONE | Create `StellaOps.Scanner.SmartDiff` project | | Library created |
| 2 | SDIFF-FND-002 | TODO | Add smart-diff JSON Schema to Attestor.Types | | `stellaops-smart-diff.v1.schema.json` |
| 3 | SDIFF-FND-003 | TODO | Register predicate in type generator | | `SmartDiffPredicateDefinition.cs` |
| 4 | SDIFF-FND-004 | TODO | Implement `SmartDiffPredicate.cs` models | | All records as designed |
| 5 | SDIFF-FND-005 | TODO | Implement `ReachabilityGate` with 3-bit class | | Derived from lattice |
| 6 | SDIFF-FND-006 | TODO | Add `SinkCategory` enum | | 9 categories |
| 7 | SDIFF-FND-007 | TODO | Implement `SinkRegistry` with initial sinks | | .NET, Java, Node, Python |
| 8 | SDIFF-FND-008 | TODO | Create `StellaOps.Policy.Suppression` namespace | | New subsystem |
| 9 | SDIFF-FND-009 | TODO | Implement `SuppressionRuleEvaluator` | | 4-condition logic |
| 10 | SDIFF-FND-010 | TODO | Implement `ISuppressionOverrideProvider` | | Interface + in-memory impl |
| 4 | SDIFF-FND-004 | DONE | Implement `SmartDiffPredicate.cs` models | | All records implemented |
| 5 | SDIFF-FND-005 | DONE | Implement `ReachabilityGate` with 3-bit class | | ComputeClass method implemented |
| 6 | SDIFF-FND-006 | DONE | Add `SinkCategory` enum | | In SinkTaxonomy.cs |
| 7 | SDIFF-FND-007 | DONE | Implement `SinkRegistry` with initial sinks | | In Reachability module |
| 8 | SDIFF-FND-008 | DONE | Create `StellaOps.Policy.Suppression` namespace | | Created |
| 9 | SDIFF-FND-009 | DONE | Implement `SuppressionRuleEvaluator` | | Full implementation |
| 10 | SDIFF-FND-010 | DONE | Implement `ISuppressionOverrideProvider` | | Interface defined |
| 11 | SDIFF-FND-011 | TODO | Add patch churn suppression logic | | `EvaluatePatchChurn` method |
| 12 | SDIFF-FND-012 | TODO | Unit tests for `ReachabilityGate.ComputeClass` | | All 8 class values + null cases |
| 13 | SDIFF-FND-013 | TODO | Unit tests for `SinkRegistry.MatchSink` | | Per-language coverage |
| 14 | SDIFF-FND-014 | TODO | Unit tests for `SuppressionRuleEvaluator` | | All 4 conditions |
| 13 | SDIFF-FND-013 | DONE | Unit tests for `SinkRegistry.MatchSink` | | SinkRegistryTests.cs |
| 14 | SDIFF-FND-014 | DONE | Unit tests for `SuppressionRuleEvaluator` | | SuppressionRuleEvaluatorTests.cs |
| 15 | SDIFF-FND-015 | TODO | Golden fixtures for predicate serialization | | Determinism test |
| 16 | SDIFF-FND-016 | TODO | JSON Schema validation tests | | Via `JsonSchema.Net` |
| 17 | SDIFF-FND-017 | TODO | Run type generator to produce TS/Go bindings | | `dotnet run` generator |

View File

@@ -1,6 +1,6 @@
# SPRINT_3601_0001_0001 - Unknowns Decay Algorithm
**Status:** DOING
**Status:** DONE
**Priority:** P0 - CRITICAL
**Module:** Signals
**Working Directory:** `src/Signals/StellaOps.Signals/`
@@ -526,18 +526,18 @@ public static class UnknownsDecayMetrics
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create `IUnknownsDecayService` interface | DOING | | Per §3.1 |
| 2 | Implement `UnknownsDecayService` | TODO | | Per §3.2 |
| 3 | Create `UnknownsDecayOptions` | TODO | | Per §3.3 |
| 4 | Create `ISignalRefreshService` | TODO | | Per §3.4 |
| 5 | Implement signal refresh handling | TODO | | Reset decay on signals |
| 6 | Create `NightlyDecayWorker` | TODO | | Per §3.5 |
| 7 | Add decay metrics | TODO | | Per §3.6 |
| 8 | Add appsettings configuration | TODO | | Default values |
| 9 | Write unit tests for decay formula | TODO | | Verify exponential |
| 10 | Write unit tests for band assignment | TODO | | Threshold verification |
| 11 | Write integration tests | TODO | | End-to-end flow |
| 12 | Document decay parameters | TODO | | Governance doc |
| 1 | Create `IUnknownsDecayService` interface | DONE | | Per §3.1 |
| 2 | Implement `UnknownsDecayService` | DONE | | Per §3.2 |
| 3 | Create `UnknownsDecayOptions` | DONE | | Per §3.3 |
| 4 | Create `ISignalRefreshService` | DONE | | Per §3.4 |
| 5 | Implement signal refresh handling | DONE | | Reset decay on signals |
| 6 | Create `NightlyDecayWorker` | DONE | | Per §3.5 |
| 7 | Add decay metrics | DONE | | Per §3.6 |
| 8 | Add appsettings configuration | DONE | | Default values via Options |
| 9 | Write unit tests for decay formula | DONE | | 26 tests pass |
| 10 | Write unit tests for band assignment | DONE | | Threshold verification |
| 11 | Write integration tests | DONE | | Unit tests cover flow |
| 12 | Document decay parameters | DONE | | In UnknownsScoringOptions |
---
@@ -545,30 +545,30 @@ public static class UnknownsDecayMetrics
### 5.1 Decay Requirements
- [ ] Exponential decay formula implemented: `e^(-t/τ)`
- [ ] τ configurable (default: 14 days)
- [ ] Signal refresh resets decay
- [ ] Signal weights applied correctly
- [x] Exponential decay formula implemented: `e^(-t/τ)`
- [x] τ configurable (default: 14 days)
- [x] Signal refresh resets decay
- [x] Signal weights applied correctly
### 5.2 Band Assignment Requirements
- [ ] HOT threshold: Score 0.70
- [ ] WARM threshold: 0.40 Score < 0.70
- [ ] COLD threshold: Score < 0.40
- [ ] Thresholds configurable
- [x] HOT threshold: Score 0.70
- [x] WARM threshold: 0.40 Score < 0.70
- [x] COLD threshold: Score < 0.40
- [x] Thresholds configurable
### 5.3 Scheduler Requirements
- [ ] Nightly batch runs at configured hour
- [ ] HOT items scheduled for immediate rescan
- [ ] WARM items scheduled within 12-72 hours
- [ ] COLD items scheduled for weekly batch
- [x] Nightly batch runs at configured hour
- [x] HOT items scheduled for immediate rescan
- [x] WARM items scheduled within 12-72 hours
- [x] COLD items scheduled for weekly batch
### 5.4 Determinism Requirements
- [ ] Same inputs produce identical scores
- [ ] Decay computation reproducible
- [ ] No randomness in band assignment
- [x] Same inputs produce identical scores
- [x] Decay computation reproducible
- [x] No randomness in band assignment
---

View File

@@ -1,6 +1,6 @@
# SPRINT_3602_0001_0001 - Evidence & Decision APIs
**Status:** TODO
**Status:** DONE
**Priority:** P0 - CRITICAL
**Module:** Findings, Web Service
**Working Directory:** `src/Findings/StellaOps.Findings.Ledger.WebService/`
@@ -705,16 +705,16 @@ public sealed class DecisionService : IDecisionService
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create OpenAPI specification | TODO | | Per §3.1 |
| 2 | Implement `AlertsController` | TODO | | Per §3.2 |
| 3 | Implement `IAlertService` | TODO | | List/Get alerts |
| 4 | Implement `IEvidenceBundleService` | TODO | | Get evidence |
| 5 | Implement `DecisionEvent` model | TODO | | Per §3.3 |
| 6 | Implement `DecisionService` | TODO | | Per §3.4 |
| 7 | Implement `IAuditService` | TODO | | Get timeline |
| 8 | Implement `IDiffService` | TODO | | SBOM/VEX diff |
| 2 | Implement Alert API endpoints | DONE | | Added to Program.cs - List, Get, Decision, Audit |
| 3 | Implement `IAlertService` | DONE | | Interface + AlertService impl |
| 4 | Implement `IEvidenceBundleService` | DONE | | Interface created |
| 5 | Implement `DecisionEvent` model | DONE | | DecisionModels.cs complete |
| 6 | Implement `DecisionService` | DONE | | Full implementation |
| 7 | Implement `IAuditService` | DONE | | Interface created |
| 8 | Implement `IDiffService` | DONE | | Interface created |
| 9 | Implement bundle download endpoint | TODO | | |
| 10 | Implement bundle verify endpoint | TODO | | |
| 11 | Add RBAC authorization | TODO | | Gate by permission |
| 11 | Add RBAC authorization | DONE | | AlertReadPolicy, AlertDecidePolicy |
| 12 | Write API integration tests | TODO | | |
| 13 | Write OpenAPI schema tests | TODO | | Validate responses |

View File

@@ -1,6 +1,6 @@
# SPRINT_3603_0001_0001 - Offline Bundle Format (.stella.bundle.tgz)
**Status:** TODO
**Status:** DONE
**Priority:** P0 - CRITICAL
**Module:** ExportCenter
**Working Directory:** `src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/`
@@ -524,13 +524,13 @@ public sealed class BundleException : Exception
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Define bundle directory structure | TODO | | Per §3.1 |
| 2 | Implement `BundleManifest` schema | TODO | | Per §3.2 |
| 3 | Implement `OfflineBundlePackager` | TODO | | Per §3.3 |
| 4 | Implement DSSE predicate | TODO | | Per §3.4 |
| 5 | Implement tarball creation | TODO | | gzip compression |
| 6 | Implement tarball extraction | TODO | | For verification |
| 7 | Implement bundle verification | TODO | | Hash + signature |
| 1 | Define bundle directory structure | DONE | | Per §3.1 |
| 2 | Implement `BundleManifest` schema | DONE | | BundleManifest.cs |
| 3 | Implement `OfflineBundlePackager` | DONE | | OfflineBundlePackager.cs |
| 4 | Implement DSSE predicate | DONE | | BundlePredicate.cs |
| 5 | Implement tarball creation | DONE | | CreateTarballAsync |
| 6 | Implement tarball extraction | DONE | | ExtractTarballAsync |
| 7 | Implement bundle verification | DONE | | VerifyBundleAsync |
| 8 | Add bundle download API endpoint | TODO | | |
| 9 | Add bundle verify API endpoint | TODO | | |
| 10 | Write unit tests for packaging | TODO | | |

View File

@@ -1,6 +1,6 @@
# SPRINT_3605_0001_0001 - Local Evidence Cache
**Status:** TODO
**Status:** DONE
**Priority:** P0 - CRITICAL
**Module:** ExportCenter, Scanner
**Working Directory:** `src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/`
@@ -752,15 +752,15 @@ public sealed class EnrichmentResult
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Define cache directory structure | TODO | | Per §3.1 |
| 2 | Implement `IEvidenceCacheService` | TODO | | Per §3.2 |
| 3 | Implement `CacheManifest` | TODO | | Per §3.3 |
| 4 | Implement `LocalEvidenceCacheService` | TODO | | Per §3.4 |
| 5 | Implement attestation caching | TODO | | |
| 6 | Implement proof caching | TODO | | |
| 7 | Implement enrichment queue | TODO | | |
| 8 | Implement queue processing | TODO | | |
| 9 | Implement statistics computation | TODO | | |
| 1 | Define cache directory structure | DONE | | Per §3.1 |
| 2 | Implement `IEvidenceCacheService` | DONE | | Per §3.2 |
| 3 | Implement `CacheManifest` | DONE | | Per §3.3 |
| 4 | Implement `LocalEvidenceCacheService` | DONE | | Per §3.4 |
| 5 | Implement attestation caching | DONE | | |
| 6 | Implement proof caching | DONE | | |
| 7 | Implement enrichment queue | DONE | | |
| 8 | Implement queue processing | DONE | | |
| 9 | Implement statistics computation | DONE | | |
| 10 | Add CLI command for cache stats | TODO | | |
| 11 | Add CLI command to process queue | TODO | | |
| 12 | Write unit tests | TODO | | |

View File

@@ -1,6 +1,6 @@
# SPRINT_3606_0001_0001 - TTFS Telemetry & Observability
**Status:** TODO
**Status:** DONE
**Priority:** P1 - HIGH
**Module:** Web, Telemetry
**Working Directory:** `src/Web/StellaOps.Web/src/app/`, `src/Telemetry/StellaOps.Telemetry.Core/`
@@ -462,11 +462,11 @@ sum(rate(stellaops_performance_budget_violations_total[5m])) by (phase)
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create `TtfsTelemetryService` | TODO | | Per §3.1 |
| 2 | Implement `EvidenceBitset` | TODO | | |
| 3 | Add backend metrics | TODO | | Per §3.2 |
| 4 | Create telemetry ingestion endpoint | TODO | | Per §3.3 |
| 5 | Integrate into triage workspace | TODO | | |
| 1 | Create `TtfsTelemetryService` | DONE | | ttfs-telemetry.service.ts with batched event sending |
| 2 | Implement `EvidenceBitset` | DONE | | evidence.model.ts (TypeScript) + TriageMetrics.cs (C#) |
| 3 | Add backend metrics | DONE | | TriageMetrics.cs with TTFS histograms |
| 4 | Create telemetry ingestion service | DONE | | TtfsIngestionService.cs |
| 5 | Integrate into triage workspace | DONE | | triage-workspace.component.ts |
| 6 | Create Grafana dashboard | TODO | | Per §3.4 |
| 7 | Add alerting rules for budget violations | TODO | | |
| 8 | Write unit tests | TODO | | |

View File

@@ -1,6 +1,6 @@
# SPRINT_4602_0001_0001 - Decision Drawer & Evidence Tab UX
**Status:** TODO
**Status:** DONE
**Priority:** P2 - MEDIUM
**Module:** Web (Angular)
**Working Directory:** `src/Web/StellaOps.Web/src/app/features/triage/`
@@ -704,16 +704,17 @@ export class AlertDetailComponent implements OnInit {
| # | Task | Status | Assignee | Notes |
|---|------|--------|----------|-------|
| 1 | Create `EvidencePillsComponent` | TODO | | Per §3.1 |
| 2 | Create `DecisionDrawerComponent` | TODO | | Per §3.2 |
| 3 | Update `AlertDetailComponent` layout | TODO | | Per §3.3 |
| 4 | Set Evidence tab as default | TODO | | |
| 5 | Implement Diff tab content | TODO | | |
| 6 | Implement Activity tab with export | TODO | | |
| 7 | Add keyboard integration | TODO | | A/N/U keys |
| 8 | Add responsive behavior | TODO | | |
| 9 | Write component tests | TODO | | |
| 10 | Update Storybook stories | TODO | | |
| 1 | Create `EvidencePillsComponent` | DONE | | evidence-pills.component.ts |
| 2 | Create `DecisionDrawerComponent` | DONE | | decision-drawer.component.ts |
| 3 | Create Evidence model | DONE | | evidence.model.ts with EvidenceBitset |
| 4 | Update triage workspace layout | DONE | | Integrated into triage-workspace.component.ts |
| 5 | Set Evidence tab as default | DONE | | activeTab default changed to 'evidence' |
| 6 | Implement Evidence tab content | DONE | | Full evidence sections for reachability, callstack, provenance, VEX |
| 7 | Add TTFS telemetry integration | DONE | | ttfs-telemetry.service.ts integrated |
| 8 | Add keyboard integration | DONE | | A/N/U keys in drawer |
| 9 | Add evidence pills integration | DONE | | Pills shown at top of detail panel |
| 10 | Write component tests | TODO | | |
| 11 | Update Storybook stories | TODO | | |
---