From 9202cd7da8231f7593cb698c0f10992a01531fce Mon Sep 17 00:00:00 2001 From: StellaOps Bot Date: Sun, 14 Dec 2025 19:58:38 +0200 Subject: [PATCH] themed the bulk of advisories --- ...ompetitive Analysis Technical Reference.md | 379 +++++++ ...and Reproducibility Technical Reference.md | 640 +++++++++++ ...eveloper Onboarding Technical Reference.md | 399 +++++++ ...Offline and Air-Gap Technical Reference.md | 379 +++++++ ...PostgreSQL Patterns Technical Reference.md | 503 +++++++++ ... and Evidence Chain Technical Reference.md | 971 +++++++++++++++++ ...achability Analysis Technical Reference.md | 992 ++++++++++++++++++ ...- Rekor Integration Technical Reference.md | 291 +++++ ...c-2025 - Smart-Diff Technical Reference.md | 255 +++++ ... Quality Guardrails Technical Reference.md | 455 ++++++++ ...Triage and Unknowns Technical Reference.md | 390 +++++++ ...nd Time-to-Evidence Technical Reference.md | 723 +++++++++++++ ...Benchmarks for a Testable Security Moat.md | 0 ...01-Dec-2025 - Common Developers guides.md | 0 ... - DSSE‑Signed Offline Scanner Updates.md | 0 ...eSQL Patterns for Each StellaOps Module.md | 0 ...2025 - Proof-Linked VEX User Interface.md | 0 ...racking UX Health with Time‑to‑Evidence.md | 0 ...urning SBOM Data Into Verifiable Proofs.md | 0 ...- Benchmarking a Testable Security Moat.md | 0 ... Converting SBOM Data into Proof Chains.md | 0 ...Designing Deterministic Reachability UX.md | 0 ...paring Proof‑Linked VEX UX Across Tools.md | 0 ...Scanner Differentiators and Evidence Moat.md | 0 ...eachability Benchmarks and Moat Metrics.md | 0 ...gning Traceable Evidence in Security UX.md | 0 ...Ranking Unknowns in Reachability Graphs.md | 0 ...Ranking Unknowns in Reachability Graphs.md | 0 ...nistic, Reachability‑First Architecture.md | 0 ...s on Smart‑Diff and Call‑Stack Analysis.md | 0 ...g Triage UX That Stays Quiet on Purpose.md | 0 ...ow to Build a Verifiable SBOM→VEX Chain.md | 0 ...bility Methods Worth Testing This Week.md} | 0 ...ning Deterministic Vulnerability Scores.md | 0 ...Reliable Air‑Gap Verification Workflows.md | 0 ...ning Stella Ops’ Proof‑Linked Advantage.md | 0 ...Designing UX for Signed Evidence Trails.md | 0 ...25 - Caching Reachability the Smart Way.md | 0 ...Smart‑Diff and Provenance‑Rich Binaries.md | 0 ...- Stella DevOps UX Implementation Guide.md | 0 ...erministic Vulnerability Scoring Matrix.md | 0 ...25 - Measure UX Efficiency Through TTFS.md | 0 ...025 - Replay Fidelity as a Proof Metric.md | 0 ...art‑Diff Detects Meaningful Risk Shifts.md | 0 ...5 - Define a north star metric for TTFS.md | 0 ...ning the Call‑Stack Reachability Engine.md | 0 ...‑Diff - Defining Meaningful Risk Change.md | 0 ... - Add a dedicated “first_signal” event.md | 0 ...25 - Create a small ground‑truth corpus.md | 0 ...- Dissect triage and evidence workflows.md | 0 ...ate PostgreSQL vs MongoDB for StellaOps.md | 0 ... - Acceptance Tests Pack and Guardrails.md | 0 ....0 Momentum in Vulnerability Management.md | 0 ... - SBOM to VEX Proof Pipeline Blueprint.md | 0 ...A Failure Catalogue for StellaOps Tests.md | 0 ... Mid-Level .NET Onboarding (Quick Start).md | 0 ...rative Evidence Patterns for Stella Ops.md | 0 ...system Reality Test Cases for StellaOps.md | 0 ...- Implementor Guidelines for Stella Ops.md | 0 ... Rekor Receipt Checklist for Stella Ops.md | 0 ...-Nov-2025 - Standup Sprint Kickstarters.md | 0 ...5 - UI Micro-Interactions for StellaOps.md | 0 ...25 - Unknowns Decay & Triage Heuristics.md | 0 63 files changed, 6377 insertions(+) create mode 100644 docs/product-advisories/14-Dec-2025 - CVSS and Competitive Analysis Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Determinism and Reproducibility Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Developer Onboarding Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - PostgreSQL Patterns Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Proof and Evidence Chain Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Reachability Analysis Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Rekor Integration Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Smart-Diff Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - Triage and Unknowns Technical Reference.md create mode 100644 docs/product-advisories/14-Dec-2025 - UX and Time-to-Evidence Technical Reference.md rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - Benchmarks for a Testable Security Moat.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - Common Developers guides.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - DSSE‑Signed Offline Scanner Updates.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - Proof-Linked VEX User Interface.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/02-Dec-2025 - Benchmarking a Testable Security Moat.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/02-Dec-2025 - Converting SBOM Data into Proof Chains.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/02-Dec-2025 - Designing Deterministic Reachability UX.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/03-Dec-2025 - Reachability Benchmarks and Moat Metrics.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/04-Dec-2025 - Designing Traceable Evidence in Security UX.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/04-Dec-2025 - Ranking Unknowns in Reachability Graphs.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/04-Dec-2025- Ranking Unknowns in Reachability Graphs.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain.md (100%) rename docs/product-advisories/{06-Dec-2025 - Reachability Methods Worth Testing This Week.m => archived/14-Dec-2025/06-Dec-2025 - Reachability Methods Worth Testing This Week.md} (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/07-Dec-2025 - Designing Deterministic Vulnerability Scores.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/07-Dec-2025 - Reliable Air‑Gap Verification Workflows.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/08-Dec-2025 - Defining Stella Ops’ Proof‑Linked Advantage.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/08-Dec-2025 - Designing UX for Signed Evidence Trails.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/09-Dec-2025 - Caching Reachability the Smart Way.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/11-Dec-2025 - Stella DevOps UX Implementation Guide.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/12-Dec-2025 - Measure UX Efficiency Through TTFS.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/12-Dec-2025 - Replay Fidelity as a Proof Metric.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/13-Dec-2025 - Define a north star metric for TTFS.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/13-Dec-2025 - Designing the Call‑Stack Reachability Engine.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/14-Dec-2025 - Add a dedicated “first_signal” event.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/14-Dec-2025 - Create a small ground‑truth corpus.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/14-Dec-2025 - Dissect triage and evidence workflows.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Implementor Guidelines for Stella Ops.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Standup Sprint Kickstarters.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - UI Micro-Interactions for StellaOps.md (100%) rename docs/product-advisories/{ => archived/14-Dec-2025}/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md (100%) diff --git a/docs/product-advisories/14-Dec-2025 - CVSS and Competitive Analysis Technical Reference.md b/docs/product-advisories/14-Dec-2025 - CVSS and Competitive Analysis Technical Reference.md new file mode 100644 index 000000000..44d33670f --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - CVSS and Competitive Analysis Technical Reference.md @@ -0,0 +1,379 @@ +# CVSS and Competitive Analysis Technical Reference + +**Source Advisories**: +- 29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management +- 30-Nov-2025 - Comparative Evidence Patterns for Stella Ops +- 03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat + +**Last Updated**: 2025-12-14 + +--- + +## 1. CVSS V4.0 INTEGRATION + +### 1.1 Requirements + +- Vendors (NVD, GitHub, Microsoft, Snyk) shipping CVSS v4 signals +- Awareness needed for receipt schemas, reporting, UI alignment + +### 1.2 Determinism & Offline + +- Keep CVSS vector parsing deterministic +- Pin scoring library versions in receipts +- Avoid live API dependency +- Rely on mirrored NVD feeds or frozen samples + +### 1.3 Schema Mapping + +- Map impacts to receipt schemas +- Identify UI/reporting deltas for transparency +- Note in sprint Decisions & Risks for CVSS receipts + +## 2. SCANNER DISCREPANCIES ANALYSIS + +### 2.1 Trivy vs Grype Comparative Study (927 images) + +**Findings**: +- Tools disagreed on total vulnerability counts and specific CVE IDs +- Grype: ~603,259 vulns; Trivy: ~473,661 vulns +- Exact match in only 9.2% of cases (80 out of 865 vulnerable images) +- Even with same counts, specific vulnerability IDs differed + +**Root Causes**: +- Divergent vulnerability databases +- Differing matching logic +- Incomplete visibility + +### 2.2 VEX Tools Consistency Study (2025) + +**Tools Tested**: +- Trivy +- Grype +- OWASP DepScan +- Docker Scout +- Snyk CLI +- OSV-Scanner +- Vexy + +**Results**: +- Low consistency/similarity across container scanners +- DepScan: 18,680 vulns; Vexy: 191 vulns (2 orders of magnitude difference) +- Pairwise Jaccard indices very low (near 0) +- 4 most consistent tools shared only ~18% common vulnerabilities + +### 2.3 Implications for StellaOps + +**Moats Needed**: +- Golden-fixture benchmarks (container images with known, audited vulnerabilities) +- Deterministic, replayable scans +- Cryptographic integrity +- VEX/SBOM proofs + +**Metrics**: +- **Closure rate**: Time from flagged to confirmed exploitable +- **Proof coverage**: % of dependencies with valid SBOM/VEX proofs +- **Differential-closure**: Impact of database updates or policy changes on prior scan results + +## 3. RUNTIME REACHABILITY APPROACHES + +### 3.1 Runtime-Aware Vulnerability Prioritization + +**Approach**: +- Monitor container workloads at runtime to determine which vulnerable components are actually used +- Use eBPF-based monitors, dynamic tracers, or built-in profiling +- Construct runtime call graph or dependency graph +- Map vulnerabilities to code entities (functions/modules) +- If execution trace covers entity, vulnerability is "reachable" + +**Findings**: ~85% of critical vulns in containers are in inactive code (Sysdig) + +### 3.2 Reachability Analysis Techniques + +**Static**: +- Call-graph analysis (Snyk reachability, CodeQL) +- All possible paths + +**Dynamic**: +- Runtime observation (loaded modules, invoked functions) +- Actual runtime paths + +**Granularity Levels**: +- Function-level (precise, limited languages: Java, .NET) +- Package/module-level (broader, coarse) + +**Hybrid Approach**: Combine static (all possible paths) + dynamic (actual runtime paths) + +## 4. CONTAINER PROVENANCE & SUPPLY CHAIN + +### 4.1 In-Toto/DSSE Framework (NDSS 2024) + +**Purpose**: +- Track chain of custody in software builds +- Signed metadata (attestations) for each step +- DSSE: Dead Simple Signing Envelope for standardized signing + +### 4.2 Scudo System + +**Features**: +- Combines in-toto with Uptane +- Verifies build process and final image +- Full verification on client inefficient; verify upstream and trust summary +- Client checks final signature + hash only + +### 4.3 Supply Chain Verification + +**Signers**: +- Developer key signs code commit +- CI key signs build attestation +- Scanner key signs vulnerability attestation +- Release key signs container image + +**Verification Optimization**: Repository verifies in-toto attestations; client verifies final metadata only + +## 5. VENDOR EVIDENCE PATTERNS + +### 5.1 Snyk + +**Evidence Handling**: +- Runtime insights integration (Nov 2025) +- Evolution from static-scan noise to prioritized workflow +- Deployment context awareness + +**VEX Support**: +- CycloneDX VEX format +- Reachability-aware suppression + +### 5.2 GitHub Advanced Security + +**Features**: +- CodeQL for static analysis +- Dependency graph +- Dependabot alerts +- Security advisories + +**Evidence**: +- SARIF output +- SBOM generation (SPDX) + +### 5.3 Aqua Security + +**Approach**: +- Runtime protection +- Image scanning +- Kubernetes security + +**Evidence**: +- Dynamic runtime traces +- Network policy violations + +### 5.4 Anchore/Grype + +**Features**: +- Open-source scanner +- Policy-based compliance +- SBOM generation + +**Evidence**: +- CycloneDX/SPDX SBOM +- Vulnerability reports (JSON) + +### 5.5 Prisma Cloud + +**Features**: +- Cloud-native security +- Runtime defense +- Compliance monitoring + +**Evidence**: +- Multi-cloud attestations +- Compliance reports + +## 6. STELLAOPS DIFFERENTIATORS + +### 6.1 Reachability-with-Evidence + +**Why it Matters**: +- Snyk Container integrating runtime insights as "signal" (Nov 2025) +- Evolution from static-scan noise to prioritized, actionable workflow +- Deployment context: what's running, what's reachable, what's exploitable + +**Implication**: Container security triage relies on runtime/context signals + +### 6.2 Proof-First Architecture + +**Advantages**: +- Every claim backed by DSSE-signed attestations +- Cryptographic integrity +- Audit trail +- Offline verification + +### 6.3 Deterministic Scanning + +**Advantages**: +- Reproducible results +- Bit-identical outputs given same inputs +- Replay manifests +- Golden fixture benchmarks + +### 6.4 VEX-First Decisioning + +**Advantages**: +- Exploitability modeled in OpenVEX +- Lattice logic for stable outcomes +- Evidence-linked justifications + +### 6.5 Offline/Air-Gap First + +**Advantages**: +- No hidden network dependencies +- Bundled feeds, keys, Rekor snapshots +- Verifiable without internet access + +## 7. COMPETITIVE POSITIONING + +### 7.1 Market Segments + +| Vendor | Strength | Weakness vs StellaOps | +|--------|----------|----------------------| +| Snyk | Developer experience | Less deterministic, SaaS-only | +| Aqua | Runtime protection | Less reachability precision | +| Anchore | Open-source, SBOM | Less proof infrastructure | +| Prisma Cloud | Cloud-native breadth | Less offline/air-gap support | +| GitHub | Integration with dev workflow | Less cryptographic proof chain | + +### 7.2 StellaOps Unique Value + +1. **Deterministic + Provable**: Bit-identical scans with cryptographic proofs +2. **Reachability + Runtime**: Hybrid static/dynamic analysis +3. **Offline/Sovereign**: Air-gap operation with regional crypto (FIPS/GOST/eIDAS/SM) +4. **VEX-First**: Evidence-backed decisioning, not just alerting +5. **AGPL-3.0**: Self-hostable, no vendor lock-in + +## 8. MOAT METRICS + +### 8.1 Proof Coverage + +``` +proof_coverage = findings_with_valid_receipts / total_findings +Target: ≥95% +``` + +### 8.2 Closure Rate + +``` +closure_rate = time_from_flagged_to_confirmed_exploitable +Target: P95 < 24 hours +``` + +### 8.3 Differential-Closure Impact + +``` +differential_impact = findings_changed_after_db_update / total_findings +Target: <5% (non-code changes) +``` + +### 8.4 False Positive Reduction + +``` +fp_reduction = (baseline_fp_rate - stella_fp_rate) / baseline_fp_rate +Target: ≥50% vs baseline scanner +``` + +### 8.5 Reachability Accuracy + +``` +reachability_accuracy = correct_r0_r1_r2_r3_classifications / total_classifications +Target: ≥90% +``` + +## 9. COMPETITIVE INTELLIGENCE TRACKING + +### 9.1 Feature Parity Matrix + +| Feature | Snyk | Aqua | Anchore | Prisma | StellaOps | +|---------|------|------|---------|--------|-----------| +| SBOM Generation | ✓ | ✓ | ✓ | ✓ | ✓ | +| VEX Support | ✓ | ✗ | Partial | ✗ | ✓ | +| Reachability Analysis | ✓ | ✗ | ✗ | ✗ | ✓ | +| Runtime Evidence | ✓ | ✓ | ✗ | ✓ | ✓ | +| Cryptographic Proofs | ✗ | ✗ | ✗ | ✗ | ✓ | +| Deterministic Scans | ✗ | ✗ | ✗ | ✗ | ✓ | +| Offline/Air-Gap | ✗ | Partial | ✗ | ✗ | ✓ | +| Regional Crypto | ✗ | ✗ | ✗ | ✗ | ✓ | + +### 9.2 Monitoring Strategy + +- Track vendor release notes +- Monitor GitHub repos for feature announcements +- Participate in security conferences +- Engage with customer feedback +- Update competitive matrix quarterly + +## 10. MESSAGING FRAMEWORK + +### 10.1 Core Message + +"StellaOps provides deterministic, proof-backed vulnerability management with reachability analysis for offline/air-gapped environments." + +### 10.2 Key Differentiators (Elevator Pitch) + +1. **Deterministic**: Same inputs → same outputs, every time +2. **Provable**: Cryptographic proof chains for every decision +3. **Reachable**: Static + runtime analysis, not just presence +4. **Sovereign**: Offline operation, regional crypto compliance +5. **Open**: AGPL-3.0, self-hostable, no lock-in + +### 10.3 Target Personas + +- **Security Engineers**: Need proof-backed decisions for audits +- **DevOps Teams**: Need deterministic scans in CI/CD +- **Compliance Officers**: Need offline/air-gap for regulated environments +- **Platform Engineers**: Need self-hostable, sovereign solution + +## 11. BENCHMARKING PROTOCOL + +### 11.1 Comparative Test Suite + +**Images**: +- 50 representative production images +- Known vulnerabilities labeled +- Reachability ground truth established + +**Metrics**: +- Precision (1 - FP rate) +- Recall (TP / (TP + FN)) +- F1 score +- Scan time (P50, P95) +- Determinism (identical outputs over 10 runs) + +### 11.2 Test Execution + +```bash +# Run StellaOps scan +stellaops scan --image test-image:v1 --output stella-results.json + +# Run competitor scans +trivy image --format json test-image:v1 > trivy-results.json +grype test-image:v1 -o json > grype-results.json +snyk container test test-image:v1 --json > snyk-results.json + +# Compare results +stellaops benchmark compare \ + --ground-truth ground-truth.json \ + --stella stella-results.json \ + --trivy trivy-results.json \ + --grype grype-results.json \ + --snyk snyk-results.json +``` + +### 11.3 Results Publication + +- Publish benchmarks quarterly +- Open-source test images and ground truth +- Invite community contributions +- Document methodology transparently + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Determinism and Reproducibility Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Determinism and Reproducibility Technical Reference.md new file mode 100644 index 000000000..91b3afa06 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Determinism and Reproducibility Technical Reference.md @@ -0,0 +1,640 @@ +# Determinism and Reproducibility Technical Reference + +**Source Advisories**: +- 07-Dec-2025 - Designing Deterministic Vulnerability Scores +- 12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix +- 12-Dec-2025 - Replay Fidelity as a Proof Metric +- 01-Dec-2025 - Benchmarks for a Testable Security Moat +- 02-Dec-2025 - Benchmarking a Testable Security Moat + +**Last Updated**: 2025-12-14 + +--- + +## 1. SCORE FORMULA (BASIS POINTS) + +**Total Score:** +``` +riskScore = (wB*B + wR*R + wE*E + wP*P) / 10000 +``` + +**Default Weights (basis points, sum = 10000):** +- `wB=1000` (10%) - Base Severity +- `wR=4500` (45%) - Reachability +- `wE=3000` (30%) - Evidence +- `wP=1500` (15%) - Provenance + +## 2. SUBSCORE DEFINITIONS (0-100 integers) + +### 2.1 BaseSeverity (B) + +``` +B = round(CVSS * 10) // CVSS 0.0-10.0 → 0-100 +``` + +### 2.2 Reachability (R) + +Hop Buckets: +``` +0-2 hops: 100 +3 hops: 85 +4 hops: 70 +5 hops: 55 +6 hops: 45 +7 hops: 35 +8+ hops: 20 +unreachable: 0 +``` + +Gate Multipliers (in basis points): +``` +behind feature flag: ×7000 +auth required: ×8000 +admin only: ×8500 +non-default config: ×7500 +``` + +Final R: +``` +R = bucketScore * gateMultiplier / 10000 +``` + +### 2.3 Evidence (E) + +Points: +``` +runtime trace: +60 +DAST/integration test: +30 +SAST precise sink: +20 +SCA presence only: +10 +``` + +Freshness Multiplier (basis points): +``` +≤ 7 days: ×10000 +≤ 30 days: ×9000 +≤ 90 days: ×7500 +≤ 180 days: ×6000 +≤ 365 days: ×4000 +> 365 days: ×2000 +``` + +Final E: +``` +E = min(100, sum(points)) * freshness / 10000 +``` + +### 2.4 Provenance (P) + +``` +unsigned/unknown: 0 +signed image: 30 +signed + SBOM hash-linked: 60 +signed + SBOM + DSSE attestations: 80 +above + reproducible build match: 100 +``` + +## 3. SCORE POLICY YAML SCHEMA + +```yaml +policyVersion: score.v1 +weightsBps: + baseSeverity: 1000 + reachability: 4500 + evidence: 3000 + provenance: 1500 + +reachability: + hopBuckets: + - { maxHops: 2, score: 100 } + - { maxHops: 3, score: 85 } + - { maxHops: 4, score: 70 } + - { maxHops: 5, score: 55 } + - { maxHops: 6, score: 45 } + - { maxHops: 7, score: 35 } + - { maxHops: 9999, score: 20 } + unreachableScore: 0 + gateMultipliersBps: + featureFlag: 7000 + authRequired: 8000 + adminOnly: 8500 + nonDefaultConfig: 7500 + +evidence: + points: + runtime: 60 + dast: 30 + sast: 20 + sca: 10 + freshnessBuckets: + - { maxAgeDays: 7, multiplierBps: 10000 } + - { maxAgeDays: 30, multiplierBps: 9000 } + - { maxAgeDays: 90, multiplierBps: 7500 } + - { maxAgeDays: 180, multiplierBps: 6000 } + - { maxAgeDays: 365, multiplierBps: 4000 } + - { maxAgeDays: 99999, multiplierBps: 2000 } + +provenance: + levels: + unsigned: 0 + signed: 30 + signedWithSbom: 60 + signedWithSbomAndAttestations: 80 + reproducible: 100 + +overrides: + - name: knownExploitedAndReachable + when: + flags: + knownExploited: true + minReachability: 70 + setScore: 95 + + - name: unreachableAndOnlySca + when: + maxReachability: 0 + maxEvidence: 10 + clampMaxScore: 25 +``` + +## 4. SCORE DATA CONTRACTS + +### 4.1 ScoreInput + +```json +{ + "asOf": "2025-12-14T10:20:30Z", + "policyVersion": "score.v1", + "reachabilityDigest": "sha256:...", + "evidenceDigest": "sha256:...", + "provenanceDigest": "sha256:...", + "baseSeverityDigest": "sha256:..." +} +``` + +### 4.2 ScoreResult + +```json +{ + "scoreId": "score_...", + "riskScore": 73, + "subscores": { + "baseSeverity": 75, + "reachability": 85, + "evidence": 60, + "provenance": 60 + }, + "cvss": { + "v": "3.1", + "base": 7.5, + "environmental": 5.3, + "vector": "CVSS:3.1/AV:N/AC:L/..." + }, + "inputsRef": ["evidence_sha256:...", "env_sha256:..."], + "policyVersion": "score.v1", + "policyDigest": "sha256:...", + "engineVersion": "stella-scorer@1.8.2", + "computedAt": "2025-12-09T10:20:30Z", + "resultDigest": "sha256:...", + "explain": [ + {"factor": "reachability", "value": 85, "reason": "3 hops from HTTP endpoint"}, + {"factor": "evidence", "value": 60, "reason": "Runtime trace (60pts), 20 days old (×90%)"} + ] +} +``` + +### 4.3 ReachabilityReport + +```json +{ + "artifactDigest": "sha256:...", + "graphDigest": "sha256:...", + "vulnId": "CVE-2024-1234", + "vulnerableSymbol": "org.example.VulnClass.vulnMethod", + "entrypoints": ["POST /api/upload"], + "shortestPath": { + "hops": 3, + "nodes": [ + {"symbol": "UploadController.handleUpload", "file": "Controller.cs", "line": 42}, + {"symbol": "ProcessorService.process", "file": "Service.cs", "line": 18}, + {"symbol": "org.example.VulnClass.vulnMethod", "file": null, "line": null} + ] + }, + "gates": [ + {"type": "authRequired", "detail": "Requires JWT token"}, + {"type": "featureFlag", "detail": "FEATURE_UPLOAD_V2=true"} + ], + "computedAt": "2025-12-14T10:15:30Z", + "toolVersion": "reachability-analyzer@2.1.0" +} +``` + +### 4.4 EvidenceBundle + +```json +{ + "evidenceId": "sha256:...", + "artifactDigest": "sha256:...", + "vulnId": "CVE-2024-1234", + "type": "RUNTIME", + "tool": "runtime-tracer@1.0.0", + "timestamp": "2025-12-10T14:30:00Z", + "confidence": 95, + "subject": "org.example.VulnClass.vulnMethod", + "payloadDigest": "sha256:..." +} +``` + +### 4.5 ProvenanceReport + +```json +{ + "artifactDigest": "sha256:...", + "signatureChecks": [ + {"signer": "CI-KEY-1", "algorithm": "ECDSA-P256", "result": "VALID"} + ], + "sbomDigest": "sha256:...", + "sbomType": "cyclonedx-1.6", + "attestations": ["sha256:...", "sha256:..."], + "transparencyLogRefs": ["rekor://..."], + "reproducibleMatch": true, + "computedAt": "2025-12-14T10:15:30Z", + "toolVersion": "provenance-verifier@1.0.0" +} +``` + +## 5. DETERMINISM CONSTRAINTS + +### 5.1 Fixed-Point Math + +- Use integer basis points (100% = 10,000 bps) +- No floating point in scoring math +- Round only at final display + +### 5.2 Canonical Serialization + +- RFC-style canonical JSON (JCS) +- Sort keys and arrays deterministically +- Stable ordering for explanation lists by `(factorId, contributingObjectDigest)` + +### 5.3 Time Handling + +- No implicit time +- `asOf` is explicit input +- Freshness = `asOf - evidence.timestamp` +- Use monotonic time internally + +## 6. FIDELITY METRICS + +### 6.1 Bitwise Fidelity (BF) + +``` +BF = identical_outputs / total_replays +Target: ≥ 0.98 +``` + +### 6.2 Semantic Fidelity (SF) + +- Normalized object comparison (same packages, versions, CVEs, severities, verdicts) +- Allows formatting differences + +### 6.3 Policy Fidelity (PF) + +- Final policy decision (pass/fail + reason codes) matches + +## 7. SCAN MANIFEST SCHEMA + +```json +{ + "manifest_version": "1.0", + "scan_id": "scan_123", + "created_at": "2025-12-12T10:15:30Z", + + "input": { + "type": "oci_image", + "image_ref": "registry/app@sha256:...", + "layers": ["sha256:...", "sha256:..."], + "source_provenance": {"repo_sha": "abc123", "build_id": "ci-999"} + }, + + "scanner": { + "engine": "stella", + "scanner_image_digest": "sha256:...", + "scanner_version": "2025.12.0", + "config_digest": "sha256:...", + "flags": ["--deep", "--vex"] + }, + + "feeds": { + "vuln_feed_bundle_digest": "sha256:...", + "license_db_digest": "sha256:..." + }, + + "policy": { + "policy_bundle_digest": "sha256:...", + "policy_set": "prod-default" + }, + + "environment": { + "arch": "amd64", + "os": "linux", + "tz": "UTC", + "locale": "C", + "network": "disabled", + "clock_mode": "frozen", + "clock_value": "2025-12-12T10:15:30Z" + }, + + "normalization": { + "canonicalizer_version": "1.2.0", + "sbom_schema": "cyclonedx-1.6", + "vex_schema": "cyclonedx-vex-1.0" + } +} +``` + +## 8. MISMATCH CLASSIFICATION TAXONOMY + +``` +- Feed drift +- Policy drift +- Runtime drift +- Scanner drift +- Nondeterminism (ordering, concurrency, RNG, time-based logic) +- External IO +``` + +## 9. POSTGRESQL SCHEMA + +```sql +CREATE TABLE scan_manifest ( + manifest_id UUID PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + + artifact_digest TEXT NOT NULL, + feeds_merkle_root TEXT NOT NULL, + engine_build_hash TEXT NOT NULL, + policy_lattice_hash TEXT NOT NULL, + + ruleset_hash TEXT NOT NULL, + config_flags JSONB NOT NULL, + + environment_fingerprint JSONB NOT NULL, + + raw_manifest JSONB NOT NULL, + raw_manifest_sha256 TEXT NOT NULL +); + +CREATE TABLE scan_execution ( + execution_id UUID PRIMARY KEY, + manifest_id UUID NOT NULL REFERENCES scan_manifest(manifest_id) ON DELETE CASCADE, + + started_at TIMESTAMPTZ NOT NULL, + finished_at TIMESTAMPTZ NOT NULL, + + t_ingest_ms INT NOT NULL, + t_analyze_ms INT NOT NULL, + t_reachability_ms INT NOT NULL, + t_vex_ms INT NOT NULL, + t_sign_ms INT NOT NULL, + t_publish_ms INT NOT NULL, + + proof_bundle_sha256 TEXT NOT NULL, + findings_sha256 TEXT NOT NULL, + vex_bundle_sha256 TEXT NOT NULL, + + replay_mode BOOLEAN NOT NULL DEFAULT FALSE +); + +CREATE TABLE classification_history ( + id BIGSERIAL PRIMARY KEY, + artifact_digest TEXT NOT NULL, + manifest_id UUID NOT NULL REFERENCES scan_manifest(manifest_id) ON DELETE CASCADE, + execution_id UUID NOT NULL REFERENCES scan_execution(execution_id) ON DELETE CASCADE, + + previous_status TEXT NOT NULL, + new_status TEXT NOT NULL, + cause TEXT NOT NULL, + + changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE VIEW scan_tte AS +SELECT + execution_id, + manifest_id, + (finished_at - started_at) AS tte_interval +FROM scan_execution; + +CREATE MATERIALIZED VIEW fn_drift_stats AS +SELECT + date_trunc('day', changed_at) AS day_bucket, + COUNT(*) FILTER (WHERE new_status = 'affected') AS affected_count, + COUNT(*) AS total_reclassified, + ROUND( + (COUNT(*) FILTER (WHERE new_status = 'affected')::numeric / + NULLIF(COUNT(*), 0)) * 100, 4 + ) AS drift_percent +FROM classification_history +GROUP BY 1; +``` + +## 10. C# CANONICAL DATA STRUCTURES + +```csharp +public sealed record CanonicalScanManifest +{ + public required string ArtifactDigest { get; init; } + public required string FeedsMerkleRoot { get; init; } + public required string EngineBuildHash { get; init; } + public required string PolicyLatticeHash { get; init; } + public required string RulesetHash { get; init; } + + public required IReadOnlyDictionary ConfigFlags { get; init; } + public required EnvironmentFingerprint Environment { get; init; } +} + +public sealed record EnvironmentFingerprint +{ + public required string CpuModel { get; init; } + public required string RuntimeVersion { get; init; } + public required string Os { get; init; } + public required IReadOnlyDictionary Extra { get; init; } +} + +public sealed record ScanExecutionMetrics +{ + public required int IngestMs { get; init; } + public required int AnalyzeMs { get; init; } + public required int ReachabilityMs { get; init; } + public required int VexMs { get; init; } + public required int SignMs { get; init; } + public required int PublishMs { get; init; } +} +``` + +## 11. CANONICALIZATION IMPLEMENTATION + +```csharp +internal static class CanonicalJson +{ + private static readonly JsonSerializerOptions Options = new() + { + WriteIndented = false, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + + public static string Serialize(object obj) + { + using var stream = new MemoryStream(); + using (var writer = new Utf8JsonWriter(stream, new JsonWriterOptions + { + Indented = false, + SkipValidation = false + })) + { + JsonSerializer.Serialize(writer, obj, obj.GetType(), Options); + } + + var bytes = stream.ToArray(); + var canonical = JsonCanonicalizer.Canonicalize(bytes); + + return canonical; + } +} +``` + +## 12. REPLAY RUNNER + +```csharp +public static class ReplayRunner +{ + public static ReplayResult Replay(Guid manifestId, IScannerEngine engine) + { + var manifest = ManifestRepository.Load(manifestId); + var canonical = CanonicalJson.Serialize(manifest.RawObject); + var canonicalHash = Sha256(canonical); + + if (canonicalHash != manifest.RawManifestSHA256) + throw new InvalidOperationException("Manifest integrity violation."); + + using var feeds = FeedSnapshotResolver.Open(manifest.FeedsMerkleRoot); + + var exec = engine.Scan(new ScanRequest + { + ArtifactDigest = manifest.ArtifactDigest, + Feeds = feeds, + LatticeHash = manifest.PolicyLatticeHash, + EngineBuildHash = manifest.EngineBuildHash, + CanonicalManifest = canonical + }); + + return new ReplayResult( + exec.FindingsHash == manifest.FindingsSHA256, + exec.VexBundleHash == manifest.VexBundleSHA256, + exec.ProofBundleHash == manifest.ProofBundleSHA256, + exec + ); + } +} +``` + +## 13. BENCHMARK METRICS + +### 13.1 Time-to-Evidence (TTE) + +**Definition:** +``` +TTE = t(proof_ready) – t(artifact_ingested) +``` + +**Targets:** +- P50 < 2m for typical containers (≤ 500 MB) +- P95 < 5m including cold-start/offline-bundle mode + +**Stage Breakdown:** +- t_ingest_ms +- t_analyze_ms +- t_reachability_ms +- t_vex_ms +- t_sign_ms +- t_publish_ms + +### 13.2 False-Negative Drift Rate (FN-DRIFT) + +**Definition (rolling 30d window):** +``` +FN-Drift = (# artifacts re-classified from {unaffected/unknown} → affected) / (total artifacts re-evaluated) +``` + +**Stratification:** +- feed delta +- rule delta +- lattice/policy delta +- reachability delta + +**Targets:** +- Engine-caused FN-Drift ≈ 0 +- Feed-caused FN-Drift: faster is better + +### 13.3 Deterministic Reproducibility + +**Proof Object:** +```json +{ + "artifact_digest": "sha256:...", + "scan_manifest_hash": "sha256:...", + "feeds_merkle_root": "sha256:...", + "engine_build_hash": "sha256:...", + "policy_lattice_hash": "sha256:...", + "findings_sha256": "sha256:...", + "vex_bundle_sha256": "sha256:...", + "proof_bundle_sha256": "sha256:..." +} +``` + +**Metric:** +``` +Repro rate = identical_outputs / total_replays +Target: 100% +``` + +### 13.4 Detection Metrics + +``` +true_positive_count (TP) +false_positive_count (FP) +false_negative_count (FN) + +precision = TP / (TP + FP) +recall = TP / (TP + FN) + +fp_reduction = (baseline_fp_rate - stella_fp_rate) / baseline_fp_rate +``` + +### 13.5 Proof Coverage + +``` +proof_coverage_all = findings_with_valid_receipts / total_findings + +proof_coverage_vex = vex_items_with_valid_receipts / total_vex_items + +proof_coverage_reachable = reachable_findings_with_proofs / total_reachable_findings +``` + +## 14. SLO THRESHOLDS + +**Fidelity:** +- BF ≥ 0.98 (general) +- BF ≥ 0.95 (regulated projects) +- PF ≈ 1.0 (unless policy changed intentionally) + +**Alerts:** +- BF drops ≥2% week-over-week → warn +- BF < 0.90 overall → page/block release +- Regulated BF < 0.95 → page/block release + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Developer Onboarding Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Developer Onboarding Technical Reference.md new file mode 100644 index 000000000..006e295f4 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Developer Onboarding Technical Reference.md @@ -0,0 +1,399 @@ +# Developer Onboarding Technical Reference + +**Source Advisories**: +- 01-Dec-2025 - Common Developers guides +- 29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start) +- 30-Nov-2025 - Implementor Guidelines for Stella Ops +- 30-Nov-2025 - Standup Sprint Kickstarters + +**Last Updated**: 2025-12-14 + +--- + +## 1. CORE ENGINEERING PRINCIPLES + +- **SOLID First**: Interface and dependency inversion required +- **100-line File Rule**: Files >100 lines must be split/refactored +- **Contracts vs Runtime**: Public DTOs/interfaces in `*.Contracts` projects +- **Single Composition Root**: DI wiring in `StellaOps.Web/Program.cs` and plugin `IoCConfigurator` +- **No Service Locator**: Constructor injection only +- **Fail-fast Startup**: Validate configuration before web host starts +- **Hot-load Compatibility**: Avoid static singletons that survive plugin unload + +## 2. REPOSITORY LAYOUT RULES + +- No "Module" folders or nested solution hierarchies +- Tests mirror `src/` structure 1:1 +- No test code in production projects +- Feature folder layout: `Scan/ScanService.cs`, `Scan/ScanController.cs` + +## 3. NAMING & STYLE CONVENTIONS + +### 3.1 Namespaces & Files + +- **Namespaces**: File-scoped, `StellaOps.*` +- **Classes/records**: PascalCase +- **Interfaces**: `I` prefix (`IScannerRunner`) +- **Private fields**: `camelCase` (no leading `_`) +- **Constants**: `SCREAMING_SNAKE_CASE` +- **Async methods**: End with `Async` + +### 3.2 Usings + +- Outside namespace +- Sorted +- No wildcards + +## 4. C# FEATURE USAGE + +- Nullable reference types enabled +- Use `record` for immutable DTOs +- Prefer pattern matching over long `switch` cascades +- `Span`/`Memory` only when measured as necessary +- Use `await foreach` instead of manual iterator loops + +## 5. DI POLICY + +### 5.1 Composition Root + +- **One composition root** per process +- Plugins contribute via `[ServiceBinding]` or `IoCConfigurator : IDependencyInjectionRoutine` +- Default lifetime: **scoped** +- Singletons only for stateless, thread-safe helpers +- Never use service locator or manually build nested service providers + +### 5.2 Service Binding Attributes + +```csharp +[ServiceBinding(typeof(IMyContract), ServiceLifetime.Scoped)] +public class MyService : IMyContract +{ + // Implementation +} +``` + +### 5.3 Advanced DI Configuration + +```csharp +public class MyPluginIoCConfigurator : IDependencyInjectionRoutine +{ + public void Configure(IServiceCollection services, IConfiguration config) + { + services.AddScoped(); + services.Configure(config.GetSection("MyPlugin")); + } +} +``` + +## 6. ASYNC & THREADING + +- All I/O is async; avoid `.Result` / `.Wait()` +- Library code uses `ConfigureAwait(false)` +- Control concurrency with channels or `Parallel.ForEachAsync` + +## 7. TEST LAYERS + +- **Unit**: xUnit +- **Property-based**: FsCheck +- **Integration**: API with Testcontainers, DB/merge with Mongo + Redis +- **Contracts**: gRPC breakage checks with Buf +- **Frontend**: Jest (unit), Playwright (e2e), Lighthouse (performance/a11y) +- **Non-functional**: k6 (load), Docker (chaos), dependency/license scanning, SBOM reproducibility + +## 8. QUALITY GATES + +- API unit test coverage ≥ ~85% +- API P95 latency ≤ ~120ms +- Δ-SBOM warm scan P95 ≤ ~5s +- Lighthouse perf ≥ ~90, a11y ≥ ~95 + +## 9. PLUGIN SYSTEM + +### 9.1 Plugin Templates + +```bash +dotnet new stellaops-plugin-schedule -n MyPlugin.Schedule +``` + +### 9.2 Plugin Publishing + +- Publish signed artifacts to `src/backend/Stella.Ops.Plugin.Binaries//` +- Backend verifies Cosign signature +- Enforces `[StellaPluginVersion]` compatibility +- Loads plugins in isolated `AssemblyLoadContext`s + +### 9.3 Plugin Signing + +```bash +dotnet publish -c Release -p:PublishSingleFile=true -o out +cosign sign --key $COSIGN_KEY out/MyPlugin.Schedule.dll +``` + +## 10. POLICY DSL (stella-dsl@1) + +### 10.1 Goals + +- Deterministic +- Declarative +- Explainable +- Offline-friendly +- Reachability-aware + +### 10.2 Structure + +- One `policy` block per `.stella` file +- Contains: `metadata`, `profile` blocks, `rule` blocks, optional `settings` + +### 10.3 Context Namespaces + +- `sbom` +- `advisory` +- `vex` +- `env` +- `telemetry` +- `secret` +- `profile.*` + +### 10.4 Helpers + +- `normalize_cvss` +- `risk_score` +- `vex.any` +- `vex.latest` +- `sbom.any_component` +- `exists` +- `coalesce` + +### 10.5 Rules + +- Always include clear `because` when changing `status` or `severity` +- Avoid catch-all suppressions (`when true` + `status := "suppressed"`) +- Use `stella policy lint/compile/simulate` in CI +- Test in sealed (offline) mode + +## 11. PR CHECKLIST + +1. Use **Conventional Commit** prefixes (`feat:`, `fix:`, `docs:`) +2. Run `dotnet format` and `dotnet test` (both must be green) +3. Keep files within 100-line guideline +4. Update XML-doc comments for new public API +5. Update docs and JSON schema for contract changes +6. Ensure analyzers and CI jobs pass + +## 12. ONBOARDING DETERMINISM REQUIREMENTS + +- Use fixed seeds and pinned toolchain versions +- Avoid live network calls; prefer cached feeds/mirrors +- Note mirror paths in examples + +## 13. SPRINT READINESS CHECKLIST + +- Scanner regressions verification +- Postgres slice validation +- DSSE/Rekor sweep complete +- Pin tool versions in scripts + +## 14. MODULE-SPECIFIC GUIDANCE + +### 14.1 Scanner Module + +- Reachability algorithms only in Scanner.WebService +- Cache lazy and keyed by deterministic inputs +- Output includes explicit evidence pointers +- UI endpoints expose reachability state in structured form + +### 14.2 Authority Module + +- Trust roots: pinned via out-of-band distribution +- Key rotation: maintain version history in trust store +- Revocation: maintain revoked_keys list in trust anchors + +### 14.3 Excititor (VEX) Module + +- VEX schema includes pointers to all upstream artifacts +- No duplication of SBOM/scan content inside VEX +- DSSE used as standard envelope type + +### 14.4 Policy Module + +- Facts and policies serialized separately +- Lattice code in allowed services only +- Merge strategies named and versioned +- Artifacts record which lattice algorithm used + +## 15. COMMON PITFALLS & SOLUTIONS + +### 15.1 Avoid + +- ❌ Service Locator pattern +- ❌ Static mutable state +- ❌ Async void (except event handlers) +- ❌ Blocking on async code (.Result, .Wait()) +- ❌ Non-deterministic ordering +- ❌ Hard-coded timestamps +- ❌ Environment variables in core algorithms + +### 15.2 Prefer + +- ✅ Constructor injection +- ✅ Immutable data structures +- ✅ async Task +- ✅ await or Task.Run for CPU-bound work +- ✅ Stable sorting with explicit comparers +- ✅ Explicit `asOf` parameters +- ✅ Configuration objects passed as parameters + +## 16. DEBUGGING WORKFLOW + +### 16.1 Local Development + +```bash +# Run all services +docker-compose up -d + +# Run specific service +dotnet run --project src/Scanner/StellaOps.Scanner.WebService + +# Attach debugger +# Use VS Code launch.json or Visual Studio F5 +``` + +### 16.2 Log Correlation + +```csharp +using var activity = Activity.Current; +activity?.SetTag("scan.id", scanId); +_logger.LogInformation("Processing scan {ScanId}", scanId); +``` + +### 16.3 OpenTelemetry + +```csharp +services.AddOpenTelemetry() + .WithTracing(builder => builder + .AddAspNetCoreInstrumentation() + .AddNpgsql() + .AddOtlpExporter()); +``` + +## 17. PERFORMANCE OPTIMIZATION + +### 17.1 Database + +- Use indexes for hot queries +- Batch inserts/updates +- Use `COPY` for bulk data +- Avoid N+1 queries + +### 17.2 Memory + +- Use `Span` for hot paths +- Pool large objects +- Dispose `IDisposable` promptly +- Profile with dotMemory + +### 17.3 Caching + +- Cache deterministically (keyed by input hashes) +- Use distributed cache (Valkey/Redis) for shared state +- TTL appropriate to data volatility + +## 18. SECURITY GUIDELINES + +### 18.1 Input Validation + +- Validate all user inputs +- Use allowlists, not denylists +- Sanitize for SQL, XSS, path traversal + +### 18.2 Authentication & Authorization + +- Never roll your own crypto +- Use standard protocols (OAuth2, OIDC) +- Implement principle of least privilege + +### 18.3 Secrets Management + +- Never commit secrets +- Use environment variables or KMS +- Rotate credentials regularly + +## 19. DOCUMENTATION STANDARDS + +### 19.1 XML Documentation + +```csharp +/// +/// Scans the specified artifact for vulnerabilities. +/// +/// The artifact identifier. +/// Cancellation token. +/// Scan results with reachability analysis. +/// If artifactId is null. +public Task ScanAsync(string artifactId, CancellationToken ct); +``` + +### 19.2 Architecture Decision Records (ADRs) + +```markdown +# ADR-XXX: Title + +## Status +Proposed | Accepted | Deprecated | Superseded + +## Context +What is the issue? + +## Decision +What did we decide? + +## Consequences +What are the implications? +``` + +## 20. CI/CD INTEGRATION + +### 20.1 Build Pipeline + +```yaml +stages: + - restore + - build + - test + - analyze + - package + - deploy +``` + +### 20.2 Required Checks + +- Unit tests pass +- Integration tests pass +- Code coverage ≥85% +- No high/critical vulnerabilities +- SBOM generated +- Determinism tests pass + +## 21. MIGRATION GUIDE + +### 21.1 From .NET 8 to .NET 10 + +- Update `net10.0` +- Review breaking changes +- Update NuGet packages +- Test thoroughly + +### 21.2 Database Migrations + +```bash +# Create migration +dotnet ef migrations add MigrationName -p src/Module -s src/WebService + +# Apply migration +dotnet ef database update -p src/Module -s src/WebService +``` + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md new file mode 100644 index 000000000..8cc58a060 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Offline and Air-Gap Technical Reference.md @@ -0,0 +1,379 @@ +# Offline and Air-Gap Technical Reference + +**Source Advisories**: +- 01-Dec-2025 - DSSE‑Signed Offline Scanner Updates +- 07-Dec-2025 - Reliable Air‑Gap Verification Workflows + +**Last Updated**: 2025-12-14 + +--- + +## 1. OFFLINE UPDATE BUNDLE STRUCTURE + +### 1.1 Directory Layout + +``` +/bundle-2025-12-14/ + manifest.json # version, created_at, entries[], sha256s + payload.tar.zst # actual DB/indices/feeds + payload.tar.zst.sha256 + statement.dsse.json # DSSE-wrapped statement over payload hash + rekor-receipt.json # Rekor v2 inclusion/verification material +``` + +### 1.2 Manifest Schema + +**manifest.json**: +```json +{ + "version": "string", + "created_at": "UTC ISO-8601", + "entries": [{"name": "string", "sha256": "string", "size": int}], + "payload_sha256": "string" +} +``` + +### 1.3 DSSE Predicate Schema + +**statement.dsse.json payload**: +```json +{ + "payloadType": "application/vnd.in-toto+json", + "payload": { + "subject": { + "name": "stella-ops-offline-kit-.tgz", + "digest": {"sha256": "string"} + }, + "predicateType": "https://stella-ops.org/attestations/offline-update/1", + "predicate": { + "offline_manifest_sha256": "string", + "feeds": [{"name": "string", "snapshot_date": "UTC ISO-8601", "archive_digest": "string"}], + "builder": "string", + "created_at": "UTC ISO-8601", + "oukit_channel": "edge|stable|fips-profile" + } + } +} +``` + +### 1.4 Rekor Receipt Schema + +**rekor-receipt.json**: +```json +{ + "uuid": "string", + "logIndex": int, + "rootHash": "string", + "hashes": ["string"], + "checkpoint": "string" +} +``` + +## 2. VERIFICATION SEQUENCE + +### 2.1 Offline Kit Import Steps + +``` +1. Validate Cosign signature of tarball +2. Validate offline-manifest.json with JWS signature +3. Verify file digests for all entries (including /attestations/*) +4. Verify DSSE: + - Call StellaOps.Attestor.Verify with: + - offline-update.dsse.json + - offline-update.rekor.json + - local Rekor log snapshot/segment + - Ensure payload digest matches kit tarball + manifest digests +5. Only after all checks pass: + - Swap Scanner's feed pointer to new snapshot + - Emit audit event (kit filename, tarball digest, DSSE digest, Rekor UUID + log index) +``` + +### 2.2 Activation Acceptance Rules + +- Trust root: pinned publisher public keys (out-of-band rotation) +- Monotonicity: only activate if `manifest.version > current.version` +- Atomic switch: unpack → validate → symlink flip (`db/staging/` → `db/active/`) +- Quarantine on failure: move to `updates/quarantine/` with reason code + +## 3. OFFLINE DIRECTORY LAYOUT + +``` +/evidence/ + keys/ + roots/ # root/intermediate certs, PGP pubkeys + identities/ # per-vendor public keys + tlog-root/ # hashed/pinned tlog root(s) + policy/ + verify-policy.yaml + lattice-rules.yaml + sboms/ # *.cdx.json, *.spdx.json + attestations/ # *.intoto.jsonl.dsig (DSSE) + tlog/ + checkpoint.sig # signed tree head + entries/ # *.jsonl (Merkle leaves) + proofs + tools/ + cosign- (sha256) + oras- (sha256) + jq- (sha256) + scanner- (sha256) +``` + +## 4. OFFLINE VERIFICATION POLICY SCHEMA + +```yaml +keys: + - ./evidence/keys/identities/vendor_A.pub + - ./evidence/keys/identities/your_authority.pub +tlog: + mode: "offline" + checkpoint: "./evidence/tlog/checkpoint.sig" + entry_pack: "./evidence/tlog/entries" +attestations: + required: + - type: slsa-provenance + - type: cyclonedx-sbom + optional: + - type: vex +constraints: + subjects: + alg: "sha256" + certs: + allowed_issuers: + - "https://fulcio.offline" + allow_expired_if_timepinned: true +``` + +## 5. DETERMINISTIC EVIDENCE RECONCILIATION ALGORITHM + +``` +1. Index artifacts by immutable digest +2. For each artifact digest: + - Collect SBOM nodes from canonical SBOM files + - Collect attestations (provenance, VEX, SLSA, signatures) + - Validate each attestation (sig + tlog inclusion proof) +3. Normalize all docs (stable sort, strip non-essential timestamps, lowercase URIs) +4. Apply lattice rules (precedence: vendor > maintainer > 3rd-party) +5. Emit `evidence-graph.json` (stable node/edge order) + `evidence-graph.sha256` + DSSE signature +``` + +## 6. OFFLINE FLOW OPERATIONAL STEPS + +``` +1. Import bundle (mount WORM media read-only) +2. Verify tools (hash + signature) before execution +3. Verify tlog checkpoint +4. Verify each inclusion proof +5. Verify attestations (keyring + policy) +6. Ingest SBOMs (canonicalize + hash) +7. Reconcile (apply lattice rules → evidence graph) +8. Record run: write `run.manifest` with input/policy/tool/output hashes; DSSE-sign with Authority key +``` + +## 7. SCANNER CONFIG SURFACE + +### 7.1 Offline Kit Configuration + +```yaml +scanner: + offlineKit: + requireDsse: true # fail import if DSSE/Rekor verification fails + rekorOfflineMode: true # use local snapshots only + attestationVerifier: https://attestor.internal + trustAnchors: + - anchorId: "UUID" + purlPattern: "pkg:npm/*" + allowedKeyids: ["key1", "key2"] +``` + +### 7.2 DSSE/Rekor Failure Handling + +**DSSE/Rekor fail, Cosign + manifest OK**: +- Keep old feeds active +- Mark import as failed; surface ProblemDetails error via API/UI +- Log structured fields: `rekorUuid`, `attestationDigest`, `offlineKitHash`, `failureReason` + +**Config flag to soften during rollout**: +- When `requireDsse=false`: treat DSSE/Rekor failure as warning; allow import with alerts + +## 8. SBOM INGESTION DETERMINISTIC FLOW + +```bash +# 1. Normalize SBOMs to canonical form +jq -S . sboms/app.cdx.json > sboms/_canon/app.cdx.json + +# 2. Validate schemas (vendored validators) + +# 3. Hash-pin canonical files and record in manifest.lock +sha256sum sboms/_canon/*.json > manifest.lock + +# 4. Import to DB with idempotent keys: (artifactDigest, sbomHash) +``` + +## 9. OFFLINE REKOR MIRROR VERIFICATION + +### 9.1 File-Ledger Pattern + +- Keep `tlog/checkpoint.sig` (signed tree head) + `tlog/entries/*.jsonl` (leaves + proofs) + +### 9.2 Verification Steps + +``` +1. Recompute Merkle root from entries +2. Check matches `checkpoint.sig` (after verifying signature with tlog root key) +3. For each attestation: + - Verify UUID/digest appears in entry pack + - Verify inclusion proof resolves +``` + +## 10. METRICS & OBSERVABILITY + +### 10.1 Offline Kit Metrics (Prometheus) + +``` +offlinekit_import_total{status="success|failed_dsse|failed_rekor|failed_cosign"} +offlinekit_attestation_verify_latency_seconds (histogram) +attestor_rekor_success_total +attestor_rekor_retry_total +rekor_inclusion_latency +``` + +### 10.2 Structured Logging Fields + +``` +rekorUuid +attestationDigest +offlineKitHash +failureReason +kitFilename +tarballDigest +dsseStatementDigest +rekorLogIndex +``` + +## 11. ERROR HANDLING + +### 11.1 Import Failure Modes + +| Failure Type | Action | Audit Event | +|--------------|--------|-------------| +| Cosign signature invalid | Reject, quarantine | `IMPORT_FAILED_COSIGN` | +| Manifest signature invalid | Reject, quarantine | `IMPORT_FAILED_MANIFEST` | +| DSSE verification failed | Reject (if requireDsse=true) | `IMPORT_FAILED_DSSE` | +| Rekor inclusion failed | Reject (if requireDsse=true) | `IMPORT_FAILED_REKOR` | +| Digest mismatch | Reject, quarantine | `IMPORT_FAILED_DIGEST` | +| Version not monotonic | Reject | `IMPORT_FAILED_VERSION` | + +### 11.2 Quarantine Structure + +``` +/updates/quarantine/-/ + bundle.tar.zst + manifest.json + verification.log + failure-reason.txt +``` + +## 12. CLI COMMANDS + +### 12.1 Offline Kit Import + +```bash +stellaops offline import \ + --bundle ./bundle-2025-12-14.tar.zst \ + --verify-dsse \ + --verify-rekor \ + --trust-root /evidence/keys/roots/stella-root.pub +``` + +### 12.2 Offline Kit Status + +```bash +stellaops offline status +# Output: +# Active kit: bundle-2025-12-14 +# Kit digest: sha256:abc123... +# Activated at: 2025-12-14T10:00:00Z +# DSSE verified: true +# Rekor verified: true +``` + +### 12.3 Offline Verification + +```bash +stellaops verify offline \ + --evidence-dir /evidence \ + --artifact sha256:def456... \ + --policy verify-policy.yaml +``` + +## 13. AUDIT TRAIL + +### 13.1 Audit Event Schema + +```json +{ + "eventId": "uuid", + "eventType": "OFFLINE_KIT_IMPORTED", + "timestamp": "2025-12-14T10:00:00Z", + "actor": "system", + "details": { + "kitFilename": "bundle-2025-12-14.tar.zst", + "tarballDigest": "sha256:...", + "dsseStatementDigest": "sha256:...", + "rekorUuid": "...", + "rekorLogIndex": 12345, + "previousKitVersion": "bundle-2025-12-07", + "newKitVersion": "bundle-2025-12-14" + }, + "result": "success" +} +``` + +### 13.2 Audit Log Storage + +```sql +CREATE TABLE offline_kit_audit ( + event_id UUID PRIMARY KEY, + event_type TEXT NOT NULL, + timestamp TIMESTAMPTZ NOT NULL, + actor TEXT NOT NULL, + details JSONB NOT NULL, + result TEXT NOT NULL +); + +CREATE INDEX idx_offline_kit_audit_ts ON offline_kit_audit(timestamp DESC); +CREATE INDEX idx_offline_kit_audit_type ON offline_kit_audit(event_type); +``` + +## 14. SECURITY CONSIDERATIONS + +### 14.1 Key Management + +- Trust roots: pinned via out-of-band distribution +- Key rotation: maintain version history in trust store +- Revocation: maintain revoked_keys list in trust anchors + +### 14.2 Integrity Guarantees + +- All bundles content-addressed +- Manifest integrity via signature +- DSSE envelope integrity via signature +- Rekor inclusion proof integrity via Merkle tree + +### 14.3 Air-Gap Boundaries + +**Allowed**: +- Local file system reads (read-only mount) +- Local tool execution (verified binaries) +- Local database writes (staged) + +**Forbidden**: +- Network egress +- DNS lookups +- NTP synchronization (use frozen clock) +- External API calls + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - PostgreSQL Patterns Technical Reference.md b/docs/product-advisories/14-Dec-2025 - PostgreSQL Patterns Technical Reference.md new file mode 100644 index 000000000..dcc212e61 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - PostgreSQL Patterns Technical Reference.md @@ -0,0 +1,503 @@ +# PostgreSQL Patterns Technical Reference + +**Source Advisories**: +- 01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module +- 14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps + +**Last Updated**: 2025-12-14 + +--- + +## 1. MODULE-SCHEMA MAPPING + +| Module | Schema | Primary Tables | +|--------|--------|----------------| +| Authority | `authority` | `user`, `role`, `grant`, `oauth_client`, `oauth_token`, `audit_log` | +| Routing | `routing` | `feature_flag`, `instance`, `rate_limit_config` | +| VEX | `vex` | `vuln_fact`, `package`, `vex_decision`, `mv_triage_queue` | +| Unknowns | `unknowns` | `unknown` (bitemporal) | +| Artifact | `artifact` | `artifact`, `signature`, `tag` | +| Core | `core` | `outbox` | + +## 2. CORE POSTGRESQL CONVENTIONS + +### 2.1 Required Columns (All Tables) + +```sql +id uuid primary key default gen_random_uuid() +tenant_id uuid not null +created_at timestamptz not null default now() +updated_at timestamptz not null default now() +``` + +### 2.2 Multi-Tenancy RLS Pattern + +```sql +alter table enable row level security; + +create policy p_
_tenant on
+ for all using (tenant_id = current_setting('app.tenant_id')::uuid); +``` + +### 2.3 Session Configuration (Set Per Request) + +```sql +select set_config('app.user_id', '', false); +select set_config('app.tenant_id', '', false); +select set_config('app.roles', 'role1,role2', false); +``` + +## 3. TABLE TAXONOMY AND PATTERNS + +### 3.1 Source-of-Truth (SOR) Tables + +```sql +create table . ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + external_id uuid, + content_hash bytea not null, + doc jsonb not null, + schema_version int not null, + created_at timestamptz not null default now(), + supersedes_id bigint null +); + +create unique index on (tenant_id, content_hash); +``` + +### 3.2 JSONB Facts + Relational Decisions + +**Facts (Immutable)**: +```sql +create table vex.vuln_fact ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + source text not null, + external_id text, + payload jsonb not null, + schema_version int not null, + received_at timestamptz not null default now() +); +``` + +**Decisions (Relational)**: +```sql +create table vex.vex_decision ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + package_id uuid not null, + vuln_id text not null, + status text check (status in ('not_affected','affected','fixed','under_investigation')), + rationale text, + proof_ref text, + decided_by uuid, + decided_at timestamptz not null default now(), + unique (tenant_id, package_id, vuln_id) +); +``` + +### 3.3 Queue Pattern (SKIP LOCKED) + +```sql +create table job_queue ( + id bigserial primary key, + tenant_id uuid, + kind text not null, + payload jsonb not null, + run_after timestamptz default now(), + attempts int default 0, + locked_at timestamptz, + locked_by text +); + +create index ix_job_ready + on job_queue(kind, run_after, id) + where locked_at is null; + +-- Claim job +with cte as ( + select id from job_queue + where kind = $1 + and run_after <= now() + and locked_at is null + order by id + for update skip locked + limit 1 +) +update job_queue j +set locked_at = now(), locked_by = $2 +from cte +where j.id = cte.id +returning j.*; +``` + +### 3.4 Temporal Pattern (Unknowns) + +```sql +create table unknowns.unknown ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + subject_hash text not null, + kind text not null, + context jsonb not null, + valid_from timestamptz not null default now(), + valid_to timestamptz, + sys_from timestamptz not null default now(), + sys_to timestamptz, + created_at timestamptz not null default now() +); + +create unique index unknown_one_open_per_subject + on unknowns.unknown (tenant_id, subject_hash, kind) + where valid_to is null; + +create view unknowns.current as + select * from unknowns.unknown + where valid_to is null; +``` + +### 3.5 Audit Log Pattern + +```sql +create table authority.audit_log ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + actor_id uuid, + action text not null, + entity_type text not null, + entity_id uuid, + at timestamptz not null default now(), + diff jsonb not null +); +``` + +### 3.6 Outbox Pattern (Exactly-Once Side Effects) + +```sql +create table core.outbox ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid, + aggregate_type text not null, + aggregate_id uuid, + topic text not null, + payload jsonb not null, + created_at timestamptz not null default now(), + dispatched_at timestamptz, + dispatch_attempts int not null default 0, + error text +); +``` + +## 4. JSONB WITH GENERATED COLUMNS + +```sql +create table sbom_document ( + id bigserial primary key, + tenant_id uuid not null, + artifact_purl text not null, + content_hash bytea not null, + doc jsonb not null, + created_at timestamptz not null default now(), + + -- hot keys as generated columns + bom_format text generated always as ((doc->>'bomFormat')) stored, + spec_version text generated always as ((doc->>'specVersion')) stored +); + +create unique index ux_sbom_doc_hash on sbom_document(tenant_id, content_hash); +create index ix_sbom_doc_tenant_artifact on sbom_document(tenant_id, artifact_purl, created_at desc); +create index ix_sbom_doc_json_gin on sbom_document using gin (doc jsonb_path_ops); +create index ix_sbom_doc_bomformat on sbom_document(tenant_id, bom_format); +``` + +## 5. MATERIALIZED VIEWS FOR HOT READS + +```sql +create materialized view mv_artifact_risk as +select tenant_id, artifact_purl, max(score) as risk_score +from open_findings +group by tenant_id, artifact_purl; + +create unique index ux_mv_artifact_risk + on mv_artifact_risk(tenant_id, artifact_purl); + +-- Refresh +refresh materialized view concurrently mv_artifact_risk; +``` + +## 6. PARTITIONING (TIME-BASED EVENTS) + +```sql +create table scan_run_event ( + tenant_id uuid not null, + scan_run_id bigint not null, + occurred_at timestamptz not null, + event_type text not null, + payload jsonb not null +) partition by range (occurred_at); + +create index brin_scan_events_time + on scan_run_event using brin (occurred_at); +``` + +## 7. INDEX PATTERNS + +| Use Case | Index Pattern | +|----------|---------------| +| Tenant-scoped queries | `INDEX(tenant_id, ...)` | +| Latest version lookup | `INDEX(tenant_id, artifact_purl, created_at DESC)` | +| Queue readiness | `INDEX(kind, run_after, id) WHERE locked_at IS NULL` | +| JSONB containment | `INDEX USING GIN (doc jsonb_path_ops)` | +| JSONB key lookup | `INDEX((doc->>'key'))` | +| Time-series scan | `INDEX USING BRIN (occurred_at)` | + +## 8. PERFORMANCE REQUIREMENTS + +### 8.1 Query Performance Standards + +**Required per PR**: +- Provide SQL query + intended parameters +- Provide `EXPLAIN (ANALYZE, BUFFERS)` from staging-sized dataset +- Identify serving index(es) +- Confirm row estimates not wildly wrong +- Confirm tenant-scoped and uses tenant-leading index + +### 8.2 Index Performance Standards + +| Pattern | Requirement | +|---------|-------------| +| Tenant queries | `INDEX(tenant_id, ...)` leading column | +| Sort ordering | Index must end with `ORDER BY` column + direction | +| Queue claims | Partial index `WHERE locked_at IS NULL` | +| Time-series | BRIN index on timestamp columns for partitioned tables | +| JSONB containment | GIN `jsonb_path_ops` for `@>` queries | + +### 8.3 General Performance Rules + +- Every hot query must have an index story +- Write path stays simple: prefer append-only versioning +- Multi-tenant explicit: all core tables include `tenant_id` +- Derived data modeled as projection tables or materialized views +- Idempotency enforced in DB: unique keys for imports/jobs/results + +## 9. FEATURE FLAG SCHEMA + +```sql +create table routing.feature_flag ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + key text not null, + rules jsonb not null, + version int not null default 1, + is_enabled boolean not null default true, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + unique (tenant_id, key) +); + +create table routing.feature_flag_history ( + id uuid primary key default gen_random_uuid(), + feature_flag_id uuid not null, + tenant_id uuid not null, + key text not null, + rules jsonb not null, + version int not null, + changed_at timestamptz not null default now(), + changed_by uuid +); +``` + +**Redis Cache Pattern**: +``` +SETEX flag:{key}:{version} +``` + +## 10. RATE LIMIT CONFIGURATION + +```sql +create table routing.rate_limit_config ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + key text not null, + limit_per_interval int not null, + interval_seconds int not null, + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + unique (tenant_id, key) +); +``` + +**Redis Counter Pattern**: +``` +INCR rl:{bucket}:{window} +``` + +## 11. INSTANCE REGISTRY + +```sql +create table routing.instance ( + id uuid primary key default gen_random_uuid(), + tenant_id uuid not null, + instance_key text not null, + domain text not null, + last_heartbeat timestamptz not null default now(), + status text not null check (status in ('active','draining','offline')), + created_at timestamptz not null default now(), + updated_at timestamptz not null default now(), + unique (tenant_id, instance_key), + unique (tenant_id, domain) +); +``` + +## 12. MIGRATION PATTERNS + +### 12.1 Schema Versioning + +```sql +create table core.schema_version ( + module text primary key, + version int not null, + applied_at timestamptz not null default now(), + migration_hash text not null +); +``` + +### 12.2 Migration Script Template + +```sql +-- Migration: _v_ +-- Dependencies: _v + +begin; + +-- Schema changes +create table if not exists .
(...); + +-- Data migrations (if needed) + +-- Update version +insert into core.schema_version (module, version, migration_hash) +values ('', , '') +on conflict (module) do update +set version = excluded.version, + applied_at = now(), + migration_hash = excluded.migration_hash; + +commit; +``` + +## 13. CONNECTION POOLING + +### 13.1 Recommended Settings + +```yaml +database: + host: postgres.local + port: 5432 + database: stellaops + username: stellaops_app + password: + pool: + min_size: 5 + max_size: 20 + connection_timeout: 5000 # ms + idle_timeout: 600000 # ms (10 min) + max_lifetime: 1800000 # ms (30 min) +``` + +### 13.2 .NET Configuration + +```csharp +services.AddNpgsqlDataSource(connectionString, builder => +{ + builder.MaxConnections = 20; + builder.MinConnections = 5; + builder.ConnectionIdleLifetime = TimeSpan.FromMinutes(10); + builder.ConnectionLifetime = TimeSpan.FromMinutes(30); +}); +``` + +## 14. MONITORING & OBSERVABILITY + +### 14.1 Essential Metrics + +``` +postgres_connections_active +postgres_connections_idle +postgres_transaction_duration_seconds +postgres_query_duration_seconds +postgres_cache_hit_ratio +postgres_table_size_bytes +postgres_index_size_bytes +postgres_slow_queries_total +``` + +### 14.2 Query Performance Monitoring + +```sql +-- Enable pg_stat_statements +create extension if not exists pg_stat_statements; + +-- Top 10 slowest queries +select + substring(query, 1, 100) as query_snippet, + calls, + total_exec_time / 1000 as total_time_sec, + mean_exec_time as mean_time_ms, + max_exec_time as max_time_ms +from pg_stat_statements +order by total_exec_time desc +limit 10; +``` + +## 15. BACKUP & RECOVERY + +### 15.1 Backup Strategy + +- **Point-in-time recovery (PITR)**: Enabled via WAL archiving +- **Daily full backups**: Automated via `pg_basebackup` +- **Retention**: 30 days for compliance +- **Testing**: Monthly restore drills + +### 15.2 Backup Commands + +```bash +# Full backup +pg_basebackup -h postgres.local -D /backup/$(date +%Y%m%d) -Ft -z -P + +# WAL archiving (postgresql.conf) +# archive_mode = on +# archive_command = 'cp %p /archive/%f' +``` + +## 16. SECURITY BEST PRACTICES + +### 16.1 Access Control + +- Use RLS for multi-tenancy isolation +- Grant minimal privileges per role +- Separate read-only and read-write users +- Use connection pooler with separate credentials + +### 16.2 Encryption + +- TLS for connections: `sslmode=require` +- Transparent data encryption (TDE) for data at rest +- Encrypted backups + +### 16.3 Audit Logging + +```sql +-- Enable audit logging +create extension if not exists pgaudit; + +-- Configure audit (postgresql.conf) +-- pgaudit.log = 'write, ddl' +-- pgaudit.log_catalog = off +``` + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Proof and Evidence Chain Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Proof and Evidence Chain Technical Reference.md new file mode 100644 index 000000000..ef00c754e --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Proof and Evidence Chain Technical Reference.md @@ -0,0 +1,971 @@ +# Proof and Evidence Chain Technical Reference + +**Source Advisories**: +- 29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint +- 01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs +- 01-Dec-2025 - Proof-Linked VEX User Interface +- 02-Dec-2025 - Converting SBOM Data into Proof Chains +- 06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain +- 08-Dec-2025 - Defining Stella Ops' Proof‑Linked Advantage +- 08-Dec-2025 - Designing UX for Signed Evidence Trails +- 03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools + +**Last Updated**: 2025-12-14 + +--- + +## 1. CORE IDENTIFIERS & DATA MODEL + +### 1.1 Canonical IDs + +``` +ArtifactID = sha256: +SBOMEntryID = :[@] +EvidenceID = hash(canonical_evidence_json) +ReasoningID = hash(canonical_reasoning_json) +VEXVerdictID = hash(canonical_vex_json) +ProofBundleID = merkle_root(SBOMEntryID, EvidenceID[], ReasoningID, VEXVerdictID) +TrustAnchorID = per-dependency anchor (public key + policy) +``` + +### 1.2 Component Identifiers (bom-ref) + +``` +Format: pkg:/@?sha256= + +Examples: + pkg:maven/org.apache.commons/commons-lang3@3.14.0?sha256= + pkg:apk/alpine/openssl@3.2.1-r0?sha256=2c0f...54e + pkg:oci/@sha256: + pkg:npm/lodash@4.17.21 + +Rules: + - Must be stable across regenerations for identical content + - Independent of local paths, build numbers + - Derived from canonical bytes + - Used as CycloneDX bom-ref +``` + +### 1.3 Subject Schema + +```csharp +public sealed record ProofSubject( + string Name, // PURL or canonical URI + IReadOnlyDictionary Digest // {"sha256": "...", "sha512": "..."} +); +``` + +### 1.4 SBOM Identity + +``` +sbomId = sha256(canonical_sbom_bytes) +``` + +## 2. DSSE ENVELOPE STRUCTURES + +### 2.1 Evidence Statement + +```json +{ + "payloadType": "application/vnd.in-toto+json", + "payload": { + "_type": "https://in-toto.io/Statement/v1", + "subject": [{"name": "", "digest": {"sha256": "..."}}], + "predicateType": "evidence.stella/v1", + "predicate": { + "source": "scanner/feed name", + "sourceVersion": "tool version", + "collectionTime": "2025-12-14T00:00:00Z", + "sbomEntryId": "", + "vulnerabilityId": "CVE-XXXX-YYYY", + "rawFinding": "", + "evidenceId": "" + } + }, + "signatures": [{"keyid": "", "sig": "BASE64(SIG)"}] +} +``` + +Signer: Scanner/Ingestor key + +### 2.2 Reasoning Statement + +```json +{ + "payloadType": "application/vnd.in-toto+json", + "payload": { + "_type": "https://in-toto.io/Statement/v1", + "subject": [{"name": "", "digest": {"sha256": "..."}}], + "predicateType": "reasoning.stella/v1", + "predicate": { + "sbomEntryId": "", + "evidenceIds": ["", ...], + "policyVersion": "v2.3.1", + "inputs": { + "currentEvaluationTime": "2025-12-14T00:00:00Z", + "severityThresholds": {...}, + "latticeRules": {...} + }, + "intermediateFindings": {}, + "reasoningId": "" + } + }, + "signatures": [{"keyid": "", "sig": "BASE64(SIG)"}] +} +``` + +Signer: Policy/Authority key + +### 2.3 VEX Verdict Statement + +```json +{ + "payloadType": "application/vnd.in-toto+json", + "payload": { + "_type": "https://in-toto.io/Statement/v1", + "subject": [{"name": "", "digest": {"sha256": "..."}}], + "predicateType": "cdx-vex.stella/v1", + "predicate": { + "sbomEntryId": "", + "vulnerabilityId": "CVE-XXXX-YYYY", + "status": "not_affected|affected|fixed|under_investigation", + "justification": "vulnerable_code_not_in_execute_path", + "policyVersion": "v2.3.1", + "reasoningId": "", + "vexVerdictId": "" + } + }, + "signatures": [{"keyid": "", "sig": "BASE64(SIG)"}] +} +``` + +Signer: VEXer key or vendor key + +### 2.4 Proof Spine Statement + +```json +{ + "payloadType": "application/vnd.in-toto+json", + "payload": { + "_type": "https://in-toto.io/Statement/v1", + "subject": [{"name": "", "digest": {"sha256": "..."}}], + "predicateType": "proofspine.stella/v1", + "predicate": { + "sbomEntryId": "", + "evidenceIds": ["", ""], + "reasoningId": "", + "vexVerdictId": "", + "policyVersion": "v2.3.1", + "proofBundleId": "" + } + }, + "signatures": [{"keyid": "", "sig": "BASE64(SIG)"}] +} +``` + +Signer: Authority key + +### 2.5 SBOM Linkage Statement + +```json +{ + "_type": "https://in-toto.io/Statement/v1", + "subject": [ + {"name": "pkg:npm/lodash@4.17.21", "digest": {"sha256": "...", "sha512": "..."}} + ], + "predicateType": "https://stella-ops.org/predicates/sbom-linkage/v1", + "predicate": { + "sbom": { + "id": "", + "format": "CycloneDX", + "specVersion": "1.6", + "mediaType": "application/vnd.cyclonedx+json", + "sha256": "", + "location": "oci://... or file://..." + }, + "generator": { + "name": "StellaOps.Sbomer", + "version": "x.y.z" + }, + "generatedAt": "2025-12-14T00:00:00Z", + "incompleteSubjects": [], + "tags": { + "tenantId": "...", + "projectId": "...", + "pipelineRunId": "..." + } + } +} +``` + +## 3. CYCLONEDX VEX STRUCTURE + +```json +{ + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "version": 1, + "vulnerabilities": [ + { + "id": "CVE-2024-12345", + "source": {"name": "NVD"}, + "analysis": { + "state": "not_affected", + "justification": "vulnerable_code_not_present", + "response": ["will_not_fix"], + "detail": "Linked OpenSSL feature set excludes the vulnerable cipher." + }, + "affects": [ + {"ref": "pkg:apk/alpine/openssl@3.2.1-r0?sha256=2c0f...54e"} + ], + "properties": [ + {"name": "evidence.sbomDigest", "value": "sha256:91f2...9a"}, + {"name": "evidence.rekorLogID", "value": "425c1d1e..."}, + {"name": "reachability.report", "value": "sha256:reacha..."}, + {"name": "policy.decision", "value": "TrustGate#R-17.2"} + ] + } + ] +} +``` + +### VEX Status Values + +``` +not_affected +affected +fixed +under_investigation +``` + +### VEX Justification Values + +``` +vulnerable_code_not_present +vulnerable_code_not_in_execute_path +vulnerable_code_not_configured +vulnerable_code_cannot_be_controlled_by_adversary +component_not_present +inline_mitigations_exist +``` + +## 4. STORAGE SCHEMA + +### 4.1 PostgreSQL Tables + +```sql +CREATE TABLE sbom_entries ( + entry_id UUID PRIMARY KEY, + bom_digest VARCHAR(64) NOT NULL, + purl TEXT NOT NULL, + version TEXT, + artifact_digest VARCHAR(64), + trust_anchor_id UUID, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE dsse_envelopes ( + env_id UUID PRIMARY KEY, + entry_id UUID REFERENCES sbom_entries(entry_id), + predicate_type TEXT NOT NULL, + signer_keyid TEXT NOT NULL, + body_hash VARCHAR(64) NOT NULL, + envelope_blob_ref TEXT NOT NULL, + signed_at TIMESTAMPTZ NOT NULL, + INDEX idx_entry_predicate (entry_id, predicate_type) +); + +CREATE TABLE spines ( + entry_id UUID PRIMARY KEY REFERENCES sbom_entries(entry_id), + bundle_id VARCHAR(64) NOT NULL, + evidence_ids TEXT[] NOT NULL, + reasoning_id VARCHAR(64) NOT NULL, + vex_id VARCHAR(64) NOT NULL, + anchor_id UUID, + policy_version TEXT NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE trust_anchors ( + anchor_id UUID PRIMARY KEY, + purl_pattern TEXT NOT NULL, + allowed_keyids TEXT[] NOT NULL, + policy_ref TEXT, + revoked_keys TEXT[], + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE TABLE rekor_entries ( + dsse_sha256 VARCHAR(64) PRIMARY KEY, + log_index BIGINT NOT NULL, + log_id TEXT NOT NULL, + integrated_time BIGINT NOT NULL, + inclusion_proof JSONB NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); +``` + +### 4.2 Proof Graph Nodes + +``` +Node Types: + - Artifact (container image, binary, Helm chart) + - SbomDocument (by sbomId) + - InTotoStatement (by statement hash) + - DsseEnvelope (by envelope hash) + - RekorEntry (by log index/UUID) + - VexStatement (by vex hash) + - Subject (component from SBOM) + +Edge Types: + - DESCRIBED_BY: Artifact → SbomDocument + - ATTESTED_BY: SbomDocument → InTotoStatement + - WRAPPED_BY: InTotoStatement → DsseEnvelope + - LOGGED_IN: DsseEnvelope → RekorEntry + - HAS_VEX: Artifact/Subject → VexStatement + - CONTAINS_SUBJECT: InTotoStatement → Subject + - PRODUCES: Build → SBOM + - AFFECTS: VEX → Component + - SIGNED_BY: Envelope → Key + - RECORDED_AT: Envelope → Rekor +``` + +## 5. API CONTRACTS + +### 5.1 Proof Spine API + +``` +POST /proofs/:entry/spine + Body: { + "evidenceIds": ["", ...], + "reasoningId": "", + "vexVerdictId": "", + "policyVersion": "v2.3.1" + } + Response: 201 Created, {"proofBundleId": "..."} + +GET /proofs/:entry/receipt + Response: { + "proofBundleId": "...", + "verifiedAt": "2025-12-14T00:00:00Z", + "verifierVersion": "1.0.0", + "anchorId": "...", + "result": "pass|fail", + "details": {...} + } + +GET /proofs/:entry/vex + Response: + +GET /anchors/:anchor + Response: { + "anchorId": "...", + "purlPattern": "pkg:npm/*", + "allowedKeyids": ["key1", "key2"], + "policyRef": "...", + "revokedKeys": [] + } +``` + +### 5.2 Verification API + +``` +POST /verify + Body: { + "artifactDigest": "sha256:...", + "sbom": , + "vex": , + "signatures": [...], + "logs": [...] + } + Response: { + "artifact": "pkg:oci/...", + "sbomVerified": true, + "vexVerified": true, + "components": [ + { + "bomRef": "pkg:...", + "vulnerabilities": [ + { + "id": "CVE-...", + "state": "not_affected", + "justification": "..." + } + ] + } + ] + } +``` + +## 6. CANONICALIZATION RULES + +### 6.1 JSON Canonicalization + +``` +1. UTF-8 encoding +2. Sorted keys (lexicographic) +3. No insignificant whitespace +4. No volatile fields beyond semantic need +5. Version schema: evidence.stella/v1, reasoning.stella/v1 +6. Deterministic array ordering where semantically unordered +``` + +### 6.2 SBOM Canonicalization + +```csharp +public interface ISbomCanonicalizer +{ + byte[] Canonicalize(ReadOnlySpan rawSbom, string mediaType); +} + +public interface IBlobHasher +{ + string ComputeSha256Hex(ReadOnlySpan data); +} +``` + +Rules: +- Remove insignificant whitespace +- Sort object keys lexicographically +- Sort arrays deterministically (by bom-ref or purl) +- Strip volatile fields: generation timestamps, tool build IDs, non-deterministic UUIDs +- Convert to internal JSON, then canonicalize + +### 6.3 Subject Extraction + +```csharp +IEnumerable ToSubjects(CycloneDxSbom sbom) +{ + foreach (var c in sbom.Metadata.Components) + { + if (c.Hashes == null || c.Hashes.Count == 0) continue; + var name = $"pkg:{c.Type}/{c.Name}@{c.Version}"; + var dig = c.Hashes + .OrderBy(h => h.Algorithm) + .ToDictionary( + h => h.Algorithm.ToLowerInvariant(), + h => h.Value.ToLowerInvariant() + ); + yield return new Subject(name, dig); + } +} +``` + +Digest requirements: +- Must have at least sha256 or sha512 +- Normalize algorithm keys to lowercase +- Sort subjects by: 1) Name ascending, 2) Algorithm:value pairs + +## 7. REKOR INTEGRATION + +### 7.1 Rekor Entry Structure + +```json +{ + "dsseSha256": "sha256:...", + "rekor": { + "uuid": "...", + "logIndex": 12345, + "logId": "...", + "integratedTime": 1733736000, + "inclusionProof": { + "rootHash": "...", + "hashes": ["...", "..."], + "checkpoint": "..." + } + } +} +``` + +### 7.2 Offline Update Bundle Structure + +``` +/bundle-2025-12-14/ + manifest.json # version, created_at, entries[], sha256s + payload.tar.zst # actual DB/indices/feeds + payload.tar.zst.sha256 + statement.dsse.json # DSSE-wrapped statement over payload hash + rekor-receipt.json # Rekor v2 inclusion/verification material +``` + +### 7.3 Offline Update DSSE Predicate + +```json +{ + "predicateType": "https://stella-ops.org/attestations/offline-update/1", + "predicate": { + "offline_manifest_sha256": "sha256:...", + "feeds": [ + { + "name": "nvd", + "snapshot_date": "2025-12-14", + "archive_digest": "sha256:..." + } + ], + "builder": "ci-workflow-id / git-commit / job-id", + "created_at": "2025-12-14T00:00:00Z", + "oukit_channel": "stable|edge|fips-profile" + } +} +``` + +### 7.4 Verification Sequence (Offline Kit) + +``` +1. Validate Cosign signature of tarball +2. Validate offline-manifest.json with JWS signature +3. Verify file digests for all entries (including /attestations/*) +4. Verify DSSE: + - Call StellaOps.Attestor.Verify with: + - offline-update.dsse.json + - offline-update.rekor.json + - local Rekor log snapshot/segment + - Ensure payload digest matches kit tarball + manifest digests +5. Only after all checks pass: + - Swap Scanner's feed pointer to new snapshot + - Emit audit event (kit filename, tarball digest, DSSE digest, Rekor UUID + log index) +``` + +## 8. CRYPTOGRAPHIC SPECIFICATIONS + +### 8.1 Signing Keys & Profiles + +``` +Default Profile: + Hash: SHA-256 + Signature: Ed25519 or ECDSA P-256 + +Future Profiles: + GOST R 34.10-2012 + eIDAS-compliant algorithms + FIPS 140-2/140-3 + SM2/SM3 (Chinese standards) + PQC: Dilithium/Falcon for long-term archives + +Key Storage: + KMS/HSM (production) + PKCS#11 for air-gap + Per-environment keysets: dev, staging, prod + Per-role keysets: Authority, VEXer, Evidence Ingestor +``` + +### 8.2 Key Rotation + +``` +Rotation Process: + 1. Add new allowed_keyids to TrustAnchor + 2. Never mutate old DSSE envelopes + 3. Publish key material via attestation feed or Rekor-mirror + 4. Record all changes in audit log + 5. Maintain key version history +``` + +### 8.3 Trust Anchor Structure + +```json +{ + "trustAnchorId": "UUID", + "purlPattern": "pkg:npm/*", + "allowedKeyids": ["keyid1", "keyid2"], + "allowedPredicateTypes": [ + "evidence.stella/v1", + "reasoning.stella/v1", + "cdx-vex.stella/v1" + ], + "policyVersion": "v2.3.1", + "revokedKeys": [] +} +``` + +## 9. VERIFICATION PIPELINE + +### 9.1 Verification Algorithm + +``` +Input: SBOMEntryID or ProofBundleID + +Steps: +1. Resolve SBOMEntryID → TrustAnchorID +2. Fetch spine and trust anchor +3. Verify spine DSSE signature against TrustAnchor.allowedKeyids +4. Verify VEX DSSE signature +5. Verify reasoning DSSE signature +6. Verify evidence DSSE signatures +7. Recompute EvidenceIDs from stored canonical evidence +8. Recompute ReasoningID from reasoning +9. Recompute VEXVerdictID from VEX body +10. Recompute ProofBundleID (merkle root) from above +11. Compare all computed IDs to stored IDs +12. If using Rekor: + - Verify log inclusion proof + - Verify payload hashes match local files +13. Emit Receipt + +Output: Receipt { + proofBundleId, + verifiedAt, + verifierVersion, + anchorId, + result: "pass|fail", + details: [...] +} +``` + +### 9.2 Receipt Structure + +```json +{ + "proofBundleId": "sha256:...", + "verifiedAt": "2025-12-14T00:00:00Z", + "verifierVersion": "1.0.0", + "anchorId": "UUID", + "result": "pass", + "checks": [ + { + "check": "spine_signature", + "status": "pass", + "keyid": "..." + }, + { + "check": "evidence_id_recompute", + "status": "pass", + "expected": "sha256:...", + "actual": "sha256:..." + }, + { + "check": "rekor_inclusion", + "status": "pass", + "logIndex": 12345 + } + ], + "toolDigests": { + "verifier": "sha256:...", + "canonicalizer": "sha256:..." + } +} +``` + +## 10. DETERMINISM CONSTRAINTS + +### 10.1 Non-Negotiable Invariants + +``` +1. Immutability of Signed Facts + - DSSE envelopes are append-only + - Never edit or delete content inside signed envelope + - Corrections via superseding (new statement pointing to old) + +2. Determinism + - Same {SBOMEntryID, Evidence set, policyVersion} ⇒ same {ReasoningID, VEXVerdictID, ProofBundleID} + - No non-deterministic inputs in ID computation + - No current time, random IDs in verdict logic + +3. Traceability + - Every VEX verdict → SBOM entry, evidence blobs, policy snapshot, trust anchor + +4. Least Trust/Least Privilege + - Trust always explicit via TrustAnchors + signature verification + - Never "because it's in our DB" + +5. Backwards Compatibility + - New code verifies old proofs + - New policies generate new spines, old spines intact +``` + +### 10.2 Temporal Handling + +``` +UTC ISO-8601 only +No local time +Timestamps only when semantically required +Derivation from content preferred over wall-clock time +Record evaluation time as explicit input if policy needs it +``` + +### 10.3 Ordering Requirements + +``` +Subjects: sorted by Name ascending, then digest keys +Evidence IDs: sorted lexicographically +Keys in JSON: sorted lexicographically +Array elements: stable sort by semantic key (bom-ref, purl) +``` + +## 11. IMPLEMENTATION INTERFACES + +### 11.1 .NET 10 Core Interfaces + +```csharp +// DSSE Signing +public interface IDsseSigner +{ + Task SignAsync( + ReadOnlyMemory payload, + string payloadType, + string keyProfile, + CancellationToken ct = default + ); +} + +// Verification +public record DsseEnvelope( + string PayloadType, + byte[] Payload, + Signature[] Signatures +); + +public record Signature( + string Keyid, + string Sig, + string? Cert +); + +// Subject Extraction +public sealed record ProofSubject( + string Name, + IReadOnlyDictionary Digest +); + +// Predicate Models +public record SbomLinkagePredicate( + SbomDescriptor Sbom, + GeneratorDescriptor Generator, + DateTimeOffset GeneratedAt, + IReadOnlyList? IncompleteSubjects, + IReadOnlyDictionary? Tags +); + +public record EvidencePredicate( + string Source, + string SourceVersion, + DateTimeOffset CollectionTime, + string SbomEntryId, + string? VulnerabilityId, + object RawFinding, + string EvidenceId +); + +public record ReasoningPredicate( + string SbomEntryId, + string[] EvidenceIds, + string PolicyVersion, + Dictionary Inputs, + Dictionary? IntermediateFindings, + string ReasoningId +); + +public record VexPredicate( + string SbomEntryId, + string VulnerabilityId, + string Status, + string Justification, + string PolicyVersion, + string ReasoningId, + string VexVerdictId +); + +public record ProofSpinePredicate( + string SbomEntryId, + string[] EvidenceIds, + string ReasoningId, + string VexVerdictId, + string PolicyVersion, + string ProofBundleId +); +``` + +### 11.2 Rekor Client Interface + +```csharp +public interface IRekorClient +{ + Task SubmitDsseAsync( + DsseEnvelope envelope, + CancellationToken ct = default + ); + + Task VerifyInclusionAsync( + RekorEntry entry, + byte[] payloadDigest, + byte[] rekorPublicKey, + CancellationToken ct = default + ); +} + +public record RekorEntry( + string Uuid, + long LogIndex, + string LogId, + long IntegratedTime, + InclusionProof Proof +); + +public record InclusionProof( + string RootHash, + string[] Hashes, + string Checkpoint +); +``` + +## 12. CONFIGURATION SCHEMA + +### 12.1 Scanner Offline Kit Config + +```yaml +scanner: + offlineKit: + requireDsse: true + rekorOfflineMode: true + attestationVerifier: https://attestor.internal + trustAnchors: + - anchorId: "UUID" + purlPattern: "pkg:npm/*" + allowedKeyids: ["key1", "key2"] +``` + +### 12.2 Signer Config + +```yaml +signer: + profiles: + default: + algorithm: "SHA256-ED25519" + keyStore: "kms://..." + fips: + algorithm: "SHA256-ECDSA-P256" + keyStore: "hsm://..." + pqc: + algorithm: "SHA256-DILITHIUM3" + keyStore: "kms://..." +``` + +### 12.3 Authority Config + +```yaml +authority: + trustRoots: + - id: "root-ca-1" + publicKey: "..." + validFrom: "2025-01-01T00:00:00Z" + validUntil: "2030-01-01T00:00:00Z" + keystores: + - type: "kms" + url: "aws-kms://..." + region: "us-east-1" +``` + +## 13. ERROR HANDLING + +### 13.1 Ingestion Failures + +``` +If SBOM invalid: + - Reject SBOM + - Record DSSE failure attestation: + { + "error": "schema_validation_failed", + "file": "sbom.json", + "system_version": "1.0.0" + } + - Maintain proof trail for "we tried and it failed" +``` + +### 13.2 Missing Digests + +``` +If component lacks sha256/sha512: + - Do NOT use as primary subject in proof chain + - Log in "incompleteSubjects" block in predicate + - Expose in UI as "unverifiable component" +``` + +### 13.3 Rekor Failures + +``` +If Rekor unavailable: + - Store DSSE envelope locally + - Queue for retry + - Mark proof chain as "rekorStatus: pending" + - Internal-only until Rekor sync succeeds + - Flag in verification results +``` + +## 14. METRICS & OBSERVABILITY + +### 14.1 Pipeline Metrics + +``` +sboms_ingested_total +sbom_ingest_errors_total{reason} +evidence_statements_created_total +reasoning_statements_created_total +vex_statements_created_total +proof_spines_created_total +proof_verifications_total{result} +*_duration_seconds (latency histograms per stage) + +offlinekit_import_total{status="success|failed_dsse|failed_rekor|failed_cosign"} +offlinekit_attestation_verify_latency_seconds +attestor_rekor_success_total +attestor_rekor_retry_total +rekor_inclusion_latency +``` + +### 14.2 Structured Logging Fields + +``` +sbomEntryId +proofBundleId +anchorId +policyVersion +requestId / traceId +rekorUuid +attestationDigest +offlineKitHash +failureReason +``` + +## 15. CI/CD INTEGRATION + +### 15.1 Pipeline Hooks + +``` +On SBOM ingest: + - Create/refresh SBOMEntry rows + - Attach TrustAnchor + +On scan completion: + - Produce Evidence Statements (DSSE) immediately + +On policy evaluation: + - Produce Reasoning + VEX + - Assemble Spine + +Release gates: + - Require: GET /proofs/:entry/receipt == PASS +``` + +### 15.2 CLI Exit Codes + +``` +0 = no policy violation +1 = policy violation +2 = scanner/system error (distinguish from "found vulns") +``` + +### 15.3 CLI Output Modes + +``` +Default: Human-readable summary (3-5 lines) +--output json: Machine-readable with: + - Web UI run page link + - Proof bundle ID + - Rekor/ledger reference + +-v / -vv: Verbose details +``` + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Reachability Analysis Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Reachability Analysis Technical Reference.md new file mode 100644 index 000000000..80170bdef --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Reachability Analysis Technical Reference.md @@ -0,0 +1,992 @@ +# Reachability Analysis Technical Reference + +**Source Advisories**: +- 05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture +- 13-Dec-2025 - Designing the Call‑Stack Reachability Engine +- 03-Dec-2025 - Reachability Benchmarks and Moat Metrics +- 09-Dec-2025 - Caching Reachability the Smart Way +- 04-Dec-2025 - Ranking Unknowns in Reachability Graphs +- 02-Dec-2025 - Designing Deterministic Reachability UX +- 05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis + +**Last Updated**: 2025-12-14 + +--- + +## 1. ARCHITECTURE PATTERNS + +### 1.1 Core System Architecture + +**Module Responsibilities** +- `StellaOps.Scanner.WebService`: Authoritative for reachability pipeline and lattice computation +- Language workers: Stateless compute producing `CallGraph.v1.json` +- Runtime collectors: Agent/sidecar emitting evidence events only +- Concelier/Excititor: Provide pruned sources; never compute reachability +- Authority: Manages replay manifests, crypto profiles +- Scheduler: Executes rescan/escalation policies + +**Architectural Rules** +- Scanner = origin of truth for reachability +- Concelier/Vexer = prune-preservers only +- Authority = replay manifest owner +- Scheduler = executor of policies +- Postgres = System of Record (SoR) +- Valkey = ephemeral only (dedupe, hot cache, rate limits) + +### 1.2 Evidence Graph Structure + +**Node Types** +- `Artifact`, `Component`, `Vulnerability`, `Attestation`, `Build`, `Deployment`, `RuntimeSignal` + +**Edge Types** +- `DESCRIBES`, `AFFECTS`, `NOT_AFFECTED_BY`, `FIXED_IN`, `DERIVED_FROM`, `DEPLOYS`, `OBSERVED_AT_RUNTIME` + +**Edge Signing** +- Sign edges, not just nodes (edge = claim) + +### 1.3 Determinism Requirements + +**Input Manifest Structure** +```jsonc +{ + "scannerVersion": "1.3.0", + "rulesetId": "stella-default-2025.11", + "feeds": { + "nvdDigest": "sha256:...", + "osvDigest": "sha256:..." + }, + "sbomDigest": "sha256:...", + "policyDigest": "sha256:..." +} +``` + +**Canonicalization Rules** +- Sort arrays by stable keys +- Normalize paths (POSIX style) +- Line endings (LF) +- Encodings (UTF-8) +- No environment variables in core algorithms +- No machine-local files +- No system clock inside algorithms + +## 2. DATA CONTRACTS + +### 2.1 CallGraph.v1.json Schema + +```json +{ + "schema": "stella.callgraph.v1", + "scanKey": "uuid", + "language": "dotnet|java|node|python|go|rust|binary", + "artifacts": [{ + "artifactKey": "…", + "kind": "assembly|jar|module|binary", + "sha256": "…" + }], + "nodes": [{ + "nodeId": "…", + "artifactKey": "…", + "symbolKey": "Namespace.Type::Method(…)", + "visibility": "public|internal|private|unknown", + "isEntrypointCandidate": false + }], + "edges": [{ + "from": "nodeId", + "to": "nodeId", + "kind": "static|heuristic", + "reason": "direct_call|virtual_call|reflection_string|di_binding|dynamic_import|unknown", + "weight": 1.0 + }], + "entrypoints": [{ + "nodeId": "…", + "kind": "http|grpc|cli|job|event|unknown", + "route": "/api/orders/{id}", + "framework": "aspnetcore|minimalapi|spring|express|unknown" + }] +} +``` + +### 2.2 RuntimeEvidence.v1.json Schema + +```json +{ + "schema": "stella.runtimeevidence.v1", + "scanKey": "uuid", + "collectedAt": "2025-12-14T10:00:00Z", + "environment": { + "os": "linux|windows", + "k8s": {"namespace": "…", "pod": "…", "container": "…"}, + "imageDigest": "sha256:…", + "buildId": "…" + }, + "samples": [{ + "timestamp": "…", + "pid": 1234, + "threadId": 77, + "frames": ["nodeId","nodeId","nodeId"], + "sampleWeight": 1.0 + }], + "loadedArtifacts": [{ + "artifactKey": "…", + "evidence": "loaded_module|mapped_file|jar_loaded" + }] +} +``` + +### 2.3 ReplayManifest.json Schema + +```json +{ + "schema": "stella.replaymanifest.v1", + "scanId": "uuid", + "inputs": { + "sbomDigest": "sha256:…", + "callGraphs": [{"language":"dotnet","digest":"sha256:…"}], + "runtimeEvidence": [{"digest":"sha256:…"}], + "concelierSnapshot": "sha256:…", + "excititorSnapshot": "sha256:…", + "policyDigest": "sha256:…" + } +} +``` + +### 2.4 ProofSpine Data Model + +```csharp +public sealed record ProofSpine( + string SpineId, + string ArtifactId, + string VulnerabilityId, + string PolicyProfileId, + IReadOnlyList Segments, + string Verdict, + string VerdictReason, + string RootHash, + string ScanRunId, + DateTimeOffset CreatedAt, + string? SupersededBySpineId +); + +public sealed record ProofSegment( + string SegmentId, + string SegmentType, + int Index, + string InputHash, + string ResultHash, + string? PrevSegmentHash, + DsseEnvelope Envelope, + string ToolId, + string ToolVersion, + string Status +); +``` + +**Segment Types** +- `SBOM_SLICE`: Component relevance +- `MATCH`: SBOM-to-vuln mapping +- `REACHABILITY`: Symbol reachability +- `GUARD_ANALYSIS`: Config/feature flag gates +- `RUNTIME_OBSERVATION`: Runtime evidence +- `POLICY_EVAL`: Lattice decision + +## 3. DATABASE SCHEMAS + +### 3.1 Core Reachability Tables (Postgres) + +```sql +-- Scan tracking +CREATE TABLE scan ( + scan_id uuid PRIMARY KEY, + created_at timestamptz, + repo_uri text, + commit_sha text, + sbom_digest text, + policy_digest text, + status text +); +CREATE INDEX idx_scan_cache ON scan(commit_sha, sbom_digest); + +-- Artifacts +CREATE TABLE artifact ( + artifact_id uuid PRIMARY KEY, + scan_id uuid REFERENCES scan, + artifact_key text, + kind text, + sha256 text, + build_id text, + purl text, + UNIQUE(scan_id, artifact_key) +); + +-- Call graph nodes +CREATE TABLE cg_node ( + scan_id uuid, + node_id text, + artifact_key text, + symbol_key text, + visibility text, + flags int, + PRIMARY KEY(scan_id, node_id) +); + +-- Call graph edges +CREATE TABLE cg_edge ( + scan_id uuid, + from_node_id text, + to_node_id text, + kind smallint, + reason smallint, + weight real, + PRIMARY KEY(scan_id, from_node_id, to_node_id, kind, reason) +); +CREATE INDEX idx_cg_edge_from ON cg_edge(scan_id, from_node_id); +CREATE INDEX idx_cg_edge_to ON cg_edge(scan_id, to_node_id); + +-- Entrypoints +CREATE TABLE entrypoint ( + scan_id uuid, + node_id text, + kind text, + framework text, + route text, + PRIMARY KEY(scan_id, node_id, kind, framework, route) +); + +-- Runtime samples +CREATE TABLE runtime_sample ( + scan_id uuid, + collected_at timestamptz, + env_hash text, + sample_id bigserial PRIMARY KEY, + timestamp timestamptz, + pid int, + thread_id int, + frames text[], + weight real +); + +-- Symbol-to-component mapping +CREATE TABLE symbol_component_map ( + scan_id uuid, + node_id text, + purl text, + mapping_kind text, + confidence real, + PRIMARY KEY(scan_id, node_id, purl) +); + +-- Reachability results +CREATE TABLE reachability_component ( + scan_id uuid, + purl text, + status smallint, + confidence real, + why jsonb, + evidence jsonb, + PRIMARY KEY(scan_id, purl) +); + +CREATE TABLE reachability_finding ( + scan_id uuid, + cve_id text, + purl text, + status smallint, + confidence real, + why jsonb, + evidence jsonb, + PRIMARY KEY(scan_id, cve_id, purl) +); +``` + +### 3.2 Unknowns Ranking Tables + +```sql +CREATE TABLE unknowns ( + unknown_id uuid PRIMARY KEY, + pkg_id text, + pkg_version text, + digest_anchor bytea, + unknown_flags jsonb, + popularity_p float, + potential_e float, + uncertainty_u float, + centrality_c float, + staleness_s float, + score float, + band text CHECK(band IN ('HOT','WARM','COLD')), + graph_slice_hash bytea, + evidence_set_hash bytea, + normalization_trace jsonb, + callgraph_attempt_hash bytea, + created_at timestamptz, + updated_at timestamptz +); + +CREATE TABLE deploy_refs ( + pkg_id text, + image_id text, + env text, + first_seen timestamptz, + last_seen timestamptz +); + +CREATE TABLE graph_metrics ( + pkg_id text PRIMARY KEY, + degree_c float, + betweenness_c float, + last_calc_at timestamptz +); +``` + +### 3.3 Proof Spine Tables + +```sql +CREATE TABLE proof_spines ( + spine_id uuid PRIMARY KEY, + artifact_id text, + vuln_id text, + policy_profile_id text, + verdict text, + verdict_reason text, + root_hash text, + scan_run_id uuid, + created_at timestamptz, + superseded_by_spine_id uuid, + segment_count int +); +CREATE INDEX idx_spine_lookup ON proof_spines(artifact_id, vuln_id, policy_profile_id); + +CREATE TABLE proof_segments ( + segment_id uuid PRIMARY KEY, + spine_id uuid REFERENCES proof_spines, + idx int, + segment_type text, + input_hash text, + result_hash text, + prev_segment_hash text, + envelope bytea, + tool_id text, + tool_version text, + status text, + created_at timestamptz +); +``` + +## 4. ALGORITHMS + +### 4.1 Reachability Status Classification + +**Status Values** +- `UNREACHABLE`: No path from entrypoints +- `POSSIBLY_REACHABLE`: Graph incomplete/dynamic behavior +- `REACHABLE_STATIC`: Static path exists +- `REACHABLE_PROVEN`: Runtime evidence confirms + +**Confidence Scoring (Deterministic)** + +Base scores: +``` +UNREACHABLE → 0.05 +POSSIBLY_REACHABLE → 0.35 +REACHABLE_STATIC → 0.70 +REACHABLE_PROVEN → 0.95 +``` + +Modifiers: +``` ++0.10 if path uses only static edges +-0.15 if path includes reflection_string|dynamic_import ++0.10 if runtime evidence hits affected component +-0.10 if NO_ENTRYPOINTS_DISCOVERED +Clamp to [0, 1] +``` + +### 4.2 Reachability Computation Algorithm + +``` +Inputs: +- Call graph nodes/edges + entrypoints +- Runtime evidence (optional) +- SBOM with purls +- Vulnerability facts (CVE ↔ purl/version) +- VEX statements + +Steps: +1. Build adjacency list for cg_edge.kind in (static, heuristic) +2. Optional: Compress SCCs (Tarjan/Kosaraju) +3. Seed from entrypoints; if empty → mark POSSIBLY_REACHABLE with NO_ENTRYPOINTS_DISCOVERED +4. Traverse reachable nodes; track: + - firstSeenFromEntrypoint[node] + - pathWitness[node] +5. Map reachable nodes to purls via symbol_component_map: + Priority order: + a. Exact binary symbol → package metadata + b. Assembly/jar/module to SBOM component (hash/purl) + c. Heuristics: namespace prefixes, import paths, jar manifest +6. Runtime evidence upgrade: + - Mark frame nodes as "executed" + - Mint runtime edges: consecutive frames → runtime_minted + - Upgrade to REACHABLE_PROVEN if executed node maps to affected purl +7. Compute confidence using deterministic formula +``` + +### 4.3 Unknowns Ranking Algorithm + +**Score Formula** +``` +Score = clamp01( + wP·P + # Popularity impact + wE·E + # Exploit consequence potential + wU·U + # Uncertainty density + wC·C + # Graph centrality + wS·S # Evidence staleness +) +``` + +**Default Weights** +``` +wP = 0.25 (deployment impact) +wE = 0.25 (potential consequence) +wU = 0.25 (uncertainty density) +wC = 0.15 (graph centrality) +wS = 0.10 (evidence staleness) +``` + +**Heuristics** +``` +P = min(1, log10(1 + deployments)/log10(1 + 100)) +U = sum of flags, capped at 1.0: + +0.30 if no provenance anchor + +0.25 if version_range + +0.20 if conflicting_feeds + +0.15 if missing_vector + +0.10 if unreachable source advisory +S = min(1, age_days / 14) +``` + +**Band Assignment** +``` +Score ≥ 0.70 → HOT (immediate rescan + VEX escalation) +0.40 ≤ Score < 0.70 → WARM (scheduled rescan 12-72h) +Score < 0.40 → COLD (weekly batch) +``` + +### 4.4 Node ID Computation (.NET) + +**Primary (IL-based)** +``` +nodeId = SHA256(MVID + ":" + metadataToken + ":" + arity + ":" + signatureShape) +``` + +**Fallback (source-only)** +``` +nodeId = SHA256(projectPath + ":" + file + ":" + span + ":" + symbolDisplayString) +``` + +**External nodes** +``` +nodeId = SHA256("ext:" + artifactKey + ":" + symbolKey) +``` + +### 4.5 Canonical Symbol Key Format + +``` +{Namespace}.{TypeName}[`Arity][+Nested]::{MethodName}[`Arity]({ParamType1},{ParamType2},...) +``` + +Rules: +- Use `System.*` full names for BCL types +- Use `+` for nested types (metadata style) +- Use backtick arity for generic type/method definitions +- Arrays: `System.String[]` +- Byref: `System.String&` + +### 4.6 Reachability Cache Algorithm + +```csharp +public readonly record struct ReachKey( + string AlgoSig, // e.g., "RTA@sha256:…" + string InputsHash, // SBOM slice + policy + versions + string CallPathHash // normalized query graph +); + +public sealed class ReachCache { + private readonly ConcurrentDictionary>> _memo = new(); + + public Task GetOrComputeAsync( + ReachKey key, + Func> compute, + CancellationToken ct) + { + var lazy = _memo.GetOrAdd(key, _ => new Lazy>( + () => compute(), LazyThreadSafetyMode.ExecutionAndPublication)); + + return lazy.Value.ContinueWith(t => { + if (t.IsCompletedSuccessfully) return t.Result; + _memo.TryRemove(key, out _); + throw t.Exception ?? new Exception("reachability failed"); + }, ct); + } +} +``` + +**Operational rules** +- Canonical everything: sort nodes/edges, normalize paths +- Cache scope: per-scan, per-workspace, or per-feed version +- TTL: 15-60 minutes or evict after pipeline completes +- Max-entries cap +- Concurrency: `Lazy>` coalesces duplicate in-flight calls + +### 4.7 Proof Spine Construction + +``` +1. Sbomer produces SBOM_SLICE segment, DSSE-signs it +2. Scanner produces MATCH segment +3. Reachability produces REACHABILITY segment +4. Guard Analyzer produces GUARD_ANALYSIS segment +5. Vexer evaluates lattice, produces POLICY_EVAL segment +6. ProofSpineBuilder: + - Sorts segments by predetermined order + - Chains PrevSegmentHash + - Computes RootHash = hash(concat of segment hashes) + - Stores ProofSpine with deterministic SpineId +``` + +## 5. API CONTRACTS + +### 5.1 Scanner Ingestion Endpoints + +``` +POST /api/scans + Returns: scanId + +POST /api/scans/{scanId}/callgraphs + Body: CallGraph.v1.json + Header: Content-Digest (for idempotency) + +POST /api/scans/{scanId}/runtimeevidence + Body: RuntimeEvidence.v1.json + +POST /api/scans/{scanId}/sbom + Body: CycloneDX/SPDX + +POST /api/scans/{scanId}/compute-reachability + Idempotent trigger +``` + +### 5.2 Query Endpoints + +``` +GET /api/scans/{scanId}/reachability/components?purl=... +GET /api/scans/{scanId}/reachability/findings?cve=... +GET /api/scans/{scanId}/reachability/explain?cve=...&purl=... + Returns: why[], path witness, sample refs +``` + +### 5.3 Export Endpoints + +``` +GET /api/scans/{scanId}/exports/sarif +GET /api/scans/{scanId}/exports/cdxr # CycloneDX reachability extension +GET /api/scans/{scanId}/exports/openvex +``` + +### 5.4 Proof Spine Endpoints + +``` +GET /graph/runtime/{podId}/lineage +GET /graph/image/{digest}/vex +GET /spines/{spineId} + Returns: ProofSpine with all segments +``` + +## 6. .NET IMPLEMENTATION PATTERNS + +### 6.1 .NET Worker (Roslyn + IL) Required Features + +**Call Graph Extraction** +- Direct invocation edges: `InvocationExpressionSyntax` +- Object creation edges: constructors +- Delegate invocation: record heuristic edge when target unresolved +- Virtual/interface dispatch: record `virtual_call` edge to declared method +- Async/await: connect logical caller → awaited method + +**Entrypoint Discovery** +- `Program.Main` (classic) +- ASP.NET Core: + - Controllers: `[ApiController]`, route attributes, action methods + - Minimal APIs: `MapGet/MapPost/MapMethods` patterns + - gRPC: `MapGrpcService()` and service methods + - Hosted services: `IHostedService`, `BackgroundService.ExecuteAsync` + +**Reflection and DI Heuristics** +- `Type.GetType("…")`, `Assembly.GetType`, `GetMethod("…")`, `Invoke` +- `services.AddTransient()` / `AddScoped` / `AddSingleton` +- `Activator.CreateInstance`, `ServiceProvider.GetService` +- Produce heuristic edges with `reason = di_binding` or `reflection_string` + +### 6.2 NuGet Dependencies + +```xml + + + + + + + + + + + + +``` + +### 6.3 Roslyn IL Opcodes for Call Detection + +``` +Recognize as "calls": +- call +- callvirt +- newobj +- jmp +- ldftn +- ldvirtftn +``` + +### 6.4 MSBuild Workspace Loading Pattern + +```csharp +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.MSBuild; + +var ws = MSBuildWorkspace.Create(); +var sln = await ws.OpenSolutionAsync(@"path\to.sln"); +foreach (var proj in sln.Projects) +foreach (var doc in proj.Documents) +{ + var model = await doc.GetSemanticModelAsync(); + var root = await doc.GetSyntaxRootAsync(); + foreach (var node in root.DescendantNodes() + .OfType()) + { + var sym = model.GetSymbolInfo(node).Symbol as IMethodSymbol; + if (sym != null) + { + // record edge: caller -> sym + } + } +} +``` + +## 7. CONFIGURATION PATTERNS + +### 7.1 Crypto Profiles + +```csharp +public interface ICryptoProfile +{ + string ProfileId { get; } + byte[] Sign(byte[] data, string keyId); + bool Verify(byte[] data, byte[] signature, string keyId); +} + +// Implementations: FipsProfile, GostProfile, EidasProfile, SmProfile, PqcProfile +``` + +**Profile Metadata** +- Algorithm +- Key ID +- Profile name + +**Key Rotation** +- Keys have validity intervals +- Spines keep KeyId in each DSSE signature +- Authority maintains trust table: which keys trusted for which SegmentType and time window + +### 7.2 Offline Bundle Format + +**Required Contents** +- SBOM + feeds + policy bundle + key material +- Manifest with hashes of all contents +- Replay manifest for deterministic rerun + +**Format** +- Zip/tar + manifest +- Each entry content-addressed + +### 7.3 Cache Configuration (appsettings) + +```json +{ + "Scanner": { + "Reach": { + "Cache": { + "MaxEntries": 10000, + "TtlMinutes": 60, + "EvictOnPipelineComplete": true + } + } + } +} +``` + +## 8. METRICS AND THRESHOLDS + +### 8.1 Performance SLOs (v1) + +``` +Medium service (100k LOC .NET) static graph: < 2 minutes +Reachability compute: < 30 seconds +Query GET finding: < 200ms p95 +``` + +### 8.2 Quality Metrics + +**Proof verification** +- % verified proofs +- Proof verification failures +- Proof age since last verification +- % entries with valid inclusion proof (Rekor) + +**Unknowns triage** +- Hot/Warm/Cold distribution +- Rescan success rate after N attempts +- Evidence staleness distribution + +**Drift detection** +- Runtime edges not in static graph (above threshold → emit COVERAGE_DRIFT warning) + +### 8.3 Benchmark Metrics (Moat) + +| Metric | Target | +|--------|--------| +| Time-to-evidence: SBOM → signed call-graph | < 5 minutes for 100k LOC service | +| SBOM-diff false positive rate under dependency churn | < 5% change in reachability status for non-code changes | +| Deterministic priority scoring under air-gap replay | Bit-identical results given same inputs | +| Proof verification time | < 200ms p95 | + +## 9. TESTING PATTERNS + +### 9.1 Golden Corpus Requirements + +**Mandatory Test Cases** +1. Minimal ASP.NET controller with reachable endpoint → vulnerable lib call +2. Vulnerable lib present but never called → unreachable +3. Reflection-based activation → "possible" unless runtime proves +4. BackgroundService job case +5. Version range ambiguity +6. Mismatched epoch/backport +7. Missing CVSS vector +8. Conflicting severity vendor/NVD +9. Unanchored filesystem library + +**Assertions per Test** +- Reachability status +- At least one `why[]` reason +- Deterministic confidence within ±0.01 +- Segments with expected status (verified/partial/invalid) + +### 9.2 Replay Manifest Tests + +Given manifest containing: +- feed hashes +- rules version +- normalization logic +- lattice rules + +Assert: ranking/reachability recomputes identically (byte-for-byte) + +### 9.3 Signature Tampering Tests + +- Flip byte in DSSE payload → UI must show `invalid` +- Mark key untrusted → segments show `untrusted-key` +- Entire spine marked as compromised + +## 10. SPECIFICATION COMPLIANCE + +### 10.1 SBOM Standards + +**CycloneDX** +- Version: 1.6 (ECMA-424) and 1.7 (current) +- Media type: include version parameter +- Ingest: validate against ECMA-424/1.7 schemas + +**SPDX** +- Version: 3.0.1 +- Validate against canonical spec + +**Ingestion Rules** +- Accept only `*.cdx.json` and `*.spdx.json` +- Hard fail others +- Store: raw bytes + parsed form + normalized canonical form + +### 10.2 VEX Standards + +**OpenVEX** +- Minimal, SBOM-agnostic +- Predicate type: `https://openvex.dev/ns/v0.2.0` + +**CSAF VEX** +- Alternative format for interoperability + +**Required VEX Fields** +- status: `not_affected|affected|fixed|under_investigation` +- justification +- timestamp +- author +- link to supporting evidence + +### 10.3 Attestation Standards + +**DSSE (Dead Simple Signing Envelope)** +- Use for all signed artifacts +- Payload: canonical JSON +- Envelope: signature + key metadata + profile + +**in-toto** +- Statement structure +- Predicate types: + - SBOM: `https://spdx.dev/Document` + - VEX: OpenVEX predicate URI + - Custom: reachability predicates + +**Cosign Integration** +```bash +cosign attest --yes --type https://spdx.dev/Document \ + --predicate sbom.spdx.json \ + --key cosign.key \ + "${IMAGE_DIGEST}" +``` + +### 10.4 Rekor Integration + +**CLI Verification** +```bash +rekor-cli verify --rekor_server https://rekor.sigstore.dev \ + --signature artifact.sig \ + --public-key cosign.pub \ + --artifact artifact.bin +``` + +**Persistence per Entry** +- Rekor UUID +- Log index +- Integrated time +- Inclusion proof data + +## 11. CLI COMMANDS + +### 11.1 Worker CLI + +```bash +# Artifacts-first scan +stella-worker-dotnet scan \ + --scanKey 00000000-0000-0000-0000-000000000000 \ + --assemblies ./artifacts/bin/Release \ + --out ./callgraph.json + +# Build-and-scan +stella-worker-dotnet scan \ + --scanKey ... \ + --sln ./src/MySolution.sln \ + --configuration Release \ + --tfm net10.0 \ + --buildMode build \ + --out ./callgraph.json + +# Upload to scanner.webservice +stella-worker-dotnet scan \ + --scanKey ... \ + --assemblies ./artifacts/bin/Release \ + --upload https://scanner/api/scans/{scanId}/callgraphs \ + --apiKey $STELLA_API_KEY +``` + +### 11.2 Replay CLI + +```bash +stellaops scan \ + --replay-manifest \ + --artifact \ + --vuln \ + --explain +``` + +### 11.3 Reachability Query CLI + +```bash +stella scan graph --lang dotnet --sln path.sln --out graph.scc.json +stella scan runtime --target pod/myservice --duration 30s --out stacks.json +stella reachability join \ + --graph graph.scc.json \ + --runtime stacks.json \ + --sbom bom.cdx.json \ + --out reach.cdxr.json +``` + +## 12. DEVELOPER CHECKLIST + +### 12.1 Per-Feature Definition of Done + +For any feature touching scans, VEX, or evidence: + +- [ ] Deterministic: input manifest defined, canonicalization applied, golden fixture(s) added +- [ ] Evidence: outputs DSSE-wrapped and linked +- [ ] Reachability/Lattice: runs only in allowed services, records algorithm IDs +- [ ] Crypto: calls through profile abstraction, tests for ≥2 profiles +- [ ] Graph: lineage edges added, node/edge IDs stable and queryable +- [ ] UX/API: API to retrieve structured evidence +- [ ] Tests: unit + golden + integration test with full SBOM → scan → VEX chain + +### 12.2 Determinism Checklist + +- [ ] Input manifest type defined and versioned +- [ ] Canonicalization applied before hashing/signing +- [ ] Output stored with `inputsDigest` and `algoDigest` +- [ ] At least one golden fixture proves determinism +- [ ] No environment variables in core algorithm +- [ ] No machine-local files +- [ ] No system clock inside algorithms + +### 12.3 Reachability Implementation Checklist + +- [ ] Reachability algorithms only in Scanner.WebService +- [ ] Cache lazy and keyed by deterministic inputs +- [ ] Output includes explicit evidence pointers +- [ ] UI endpoints expose reachability state in structured form +- [ ] All modifiers recorded in `why[]` + +### 12.4 Crypto-Sovereign Checklist + +- [ ] No direct crypto calls in feature code; only via profile layer +- [ ] All attestations carry algorithm + key id + profile +- [ ] Offline bundle type exists for this workflow +- [ ] Tests for at least 2 different crypto profiles + +### 12.5 Policy/Lattice Checklist + +- [ ] Facts and policies serialized separately +- [ ] Lattice code in allowed services only +- [ ] Merge strategies named and versioned +- [ ] Artifacts record which lattice algorithm used + +### 12.6 Proof-Linked VEX Checklist + +- [ ] VEX schema includes pointers to all upstream artifacts (sbomDigest, scanId, reachMapDigest, policyDigest, signerKeyId) +- [ ] No duplication of SBOM/scan content inside VEX +- [ ] DSSE used as standard envelope type + +### 12.7 Unknowns Triage Checklist + +- [ ] Persist all traces for deterministic replay +- [ ] Ranking depends only on manifest-declared parameters +- [ ] All uncertainty factors are explicit flags +- [ ] Scoring reproducible under identical inputs +- [ ] Scheduler decision table deterministic and tested +- [ ] API exposes full reasoning + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Rekor Integration Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Rekor Integration Technical Reference.md new file mode 100644 index 000000000..6524cc3f7 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Rekor Integration Technical Reference.md @@ -0,0 +1,291 @@ +# Rekor Integration Technical Reference + +**Source Advisories**: +- 30-Nov-2025 - Rekor Receipt Checklist for Stella Ops + +**Last Updated**: 2025-12-14 + +--- + +## 1. REQUIREMENTS + +- Rekor receipts must be deterministic, tenant-scoped, and verifiable offline +- For Authority/Sbomer/Vexer flows +- Field-level ownership map for receipts and bundles +- Offline verifier expectations +- Mirror snapshot rules +- DSSE/receipt schema pointers + +## 2. DETERMINISM & OFFLINE + +- Bundle TSA/time anchors with receipts +- Prefer mirror snapshots +- Avoid live log fetches in examples + +## 3. DELIVERABLES + +- Schema draft +- Offline verifier stub +- Module dossier updates + +## 4. REKOR ENTRY STRUCTURE + +```json +{ + "dsseSha256": "sha256:...", + "rekor": { + "uuid": "...", + "logIndex": 12345, + "logId": "...", + "integratedTime": 1733736000, + "inclusionProof": { + "rootHash": "...", + "hashes": ["...", "..."], + "checkpoint": "..." + } + } +} +``` + +## 5. REKOR CLIENT INTERFACE + +```csharp +public interface IRekorClient +{ + Task SubmitDsseAsync( + DsseEnvelope envelope, + CancellationToken ct = default + ); + + Task VerifyInclusionAsync( + RekorEntry entry, + byte[] payloadDigest, + byte[] rekorPublicKey, + CancellationToken ct = default + ); +} + +public record RekorEntry( + string Uuid, + long LogIndex, + string LogId, + long IntegratedTime, + InclusionProof Proof +); + +public record InclusionProof( + string RootHash, + string[] Hashes, + string Checkpoint +); +``` + +## 6. CLI VERIFICATION + +### 6.1 Rekor CLI Commands + +```bash +rekor-cli verify --rekor_server https://rekor.sigstore.dev \ + --signature artifact.sig \ + --public-key cosign.pub \ + --artifact artifact.bin +``` + +### 6.2 Persistence per Entry + +- Rekor UUID +- Log index +- Integrated time +- Inclusion proof data + +## 7. OFFLINE REKOR MIRROR + +### 7.1 Mirror Structure + +``` +/evidence/tlog/ + checkpoint.sig # signed tree head + entries/ # *.jsonl (Merkle leaves) + proofs +``` + +### 7.2 Verification Steps + +``` +1. Recompute Merkle root from entries +2. Check matches `checkpoint.sig` (after verifying signature with tlog root key) +3. For each attestation: + - Verify UUID/digest appears in entry pack + - Verify inclusion proof resolves +``` + +## 8. REKOR STORAGE SCHEMA + +```sql +CREATE TABLE rekor_entries ( + dsse_sha256 VARCHAR(64) PRIMARY KEY, + log_index BIGINT NOT NULL, + log_id TEXT NOT NULL, + integrated_time BIGINT NOT NULL, + inclusion_proof JSONB NOT NULL, + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX idx_rekor_log_index ON rekor_entries(log_index); +CREATE INDEX idx_rekor_integrated_time ON rekor_entries(integrated_time); +``` + +## 9. REKOR FAILURE HANDLING + +### 9.1 Rekor Unavailable + +``` +If Rekor unavailable: + - Store DSSE envelope locally + - Queue for retry + - Mark proof chain as "rekorStatus: pending" + - Internal-only until Rekor sync succeeds + - Flag in verification results +``` + +### 9.2 Rekor Verification Failed + +``` +If verification fails: + - Log error with structured fields (rekorUuid, dsseDigest, failureReason) + - Mark envelope as "rekor_verification_failed" + - Do not accept as valid proof + - Alert security team +``` + +## 10. INTEGRATION POINTS + +### 10.1 Authority Module + +- Submit signed attestations to Rekor +- Store receipts with DSSE envelopes +- Verify inclusion proofs on retrieval + +### 10.2 Sbomer Module + +- Submit SBOM attestations to Rekor +- Link Rekor UUID to SBOM entries + +### 10.3 Vexer Module + +- Submit VEX statements to Rekor +- Store receipts with VEX decisions + +## 11. METRICS & OBSERVABILITY + +``` +rekor_submit_total{status="success|failed"} +rekor_submit_latency_seconds +rekor_verify_total{result="pass|fail"} +rekor_verify_latency_seconds +rekor_queue_depth (pending submissions) +rekor_retry_attempts_total +``` + +## 12. CONFIGURATION + +```yaml +rekor: + server_url: https://rekor.sigstore.dev + public_key_path: /etc/stellaops/rekor-pub.pem + offline_mode: false + retry: + max_attempts: 3 + initial_delay_ms: 1000 + max_delay_ms: 10000 + timeout_seconds: 30 +``` + +## 13. OFFLINE BUNDLE INTEGRATION + +### 13.1 Rekor Receipt in Offline Kit + +**rekor-receipt.json**: +```json +{ + "uuid": "string", + "logIndex": int, + "rootHash": "string", + "hashes": ["string"], + "checkpoint": "string" +} +``` + +### 13.2 Offline Verification + +``` +1. Load Rekor public key from offline bundle +2. Verify checkpoint signature +3. Recompute Merkle root from inclusion proof +4. Verify root hash matches checkpoint +5. Verify DSSE envelope hash appears in proof +``` + +## 14. SECURITY CONSIDERATIONS + +### 14.1 Trust Model + +- Rekor provides transparency, not trust +- Trust derives from key verification +- Inclusion proof demonstrates timestamp +- Does not prove correctness of content + +### 14.2 Key Pinning + +- Pin Rekor public key via out-of-band distribution +- Verify checkpoint signatures before trusting +- Maintain key version history + +### 14.3 Replay Protection + +- Use integrated_time to detect backdated entries +- Compare with local clock (within reasonable skew) +- Alert on time anomalies + +## 15. TESTING REQUIREMENTS + +### 15.1 Integration Tests + +- Submit DSSE to Rekor (staging) +- Verify inclusion proof +- Offline verification with mirror +- Retry on failure +- Timeout handling + +### 15.2 Failure Scenarios + +- Rekor unavailable +- Network timeout +- Invalid inclusion proof +- Signature verification failure +- Malformed response + +## 16. OPERATIONAL PROCEDURES + +### 16.1 Rekor Mirror Sync + +```bash +# Download latest checkpoint +curl https://rekor.sigstore.dev/api/v1/log/checkpoint > checkpoint.sig + +# Verify checkpoint signature +rekor-cli verify --checkpoint checkpoint.sig --public-key rekor-pub.pem + +# Sync entries since last update +rekor-cli sync --since --output ./entries/ +``` + +### 16.2 Monitoring + +- Alert on Rekor submission failures >1% over 5 minutes +- Alert on verification failures >0.1% over 5 minutes +- Alert on queue depth >1000 for >10 minutes + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Smart-Diff Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Smart-Diff Technical Reference.md new file mode 100644 index 000000000..e002d715e --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Smart-Diff Technical Reference.md @@ -0,0 +1,255 @@ +# Smart-Diff Technical Reference + +**Source Advisories**: +- 09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries +- 12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts +- 13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change +- 05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis + +**Last Updated**: 2025-12-14 + +--- + +## 1. SMART-DIFF PREDICATE SCHEMA + +```json +{ + "predicateType": "stellaops.dev/predicates/smart-diff@v1", + "predicate": { + "baseImage": {"name":"...", "digest":"sha256:..."}, + "targetImage": {"name":"...", "digest":"sha256:..."}, + "diff": { + "filesAdded": [...], + "filesRemoved": [...], + "filesChanged": [{"path":"...", "hunks":[...]}], + "packagesChanged": [{"name":"openssl","from":"1.1.1u","to":"3.0.14"}] + }, + "context": { + "entrypoint":["/app/start"], + "env":{"FEATURE_X":"true"}, + "user":{"uid":1001,"caps":["NET_BIND_SERVICE"]} + }, + "reachabilityGate": {"reachable":true,"configActivated":true,"runningUser":false,"class":6}, + "scanner": {"name":"StellaOps.Scanner","version":"...","ruleset":"reachability-2025.12"} + } +} +``` + +## 2. REACHABILITY GATE (3-BIT SEVERITY) + +**Data Model:** +```csharp +public sealed record ReachabilityGate( + bool? Reachable, // true / false / null for unknown + bool? ConfigActivated, + bool? RunningUser, + int Class, // 0..7 derived from the bits when all known + string Rationale // short explanation, human-readable +); +``` + +**Class Computation:** 0-7 based on 3 binary gates (reachable, config-activated, running user) + +**Unknown Handling:** +- Never silently treat `null` as `false` or `true` +- If any bit is `null`, set `Class = -1` or compute from known bits only + +## 3. DELTA DATA STRUCTURES + +```csharp +// Delta.Packages +{ + added[], + removed[], + changed[{name, fromVer, toVer}] +} + +// Delta.Layers +{ + changed[{path, fromHash, toHash, licenseDelta}] +} + +// Delta.Functions +{ + added[], + removed[], + changed[{symbol, file, signatureHashFrom, signatureHashTo}] +} + +// PatchDelta +{ + addedSymbols[], + removedSymbols[], + changedSignatures[] +} +``` + +## 4. SMART-DIFF ALGORITHMS + +**Core Diff Computation:** +```pseudo +prev = load_snapshot(t-1) +curr = load_snapshot(t) + +Δ.pkg = diff_packages(prev.lock, curr.lock) +Δ.layers= diff_layers(prev.sbom, curr.sbom) +Δ.funcs = diff_cfg(prev.cfgIndex, curr.cfgIndex) + +scope = union( + impact_of(Δ.pkg.changed), + impact_of_files(Δ.layers.changed), + reachability_of(Δ.funcs.changed) +) + +for f in scope.functions: + rescore(f) + +for v in impacted_vulns(scope): + annotate(v, patch_delta(Δ)) + link_evidence(v, dsse_attestation(), proof_links()) + +for v in previously_flagged where vulnerable_apis_now_absent(v, curr): + emit_vex_candidate(v, status="not_affected", rationale="API not present", evidence=proof_links()) +``` + +## 5. MATERIAL RISK CHANGE DETECTION RULES + +**FindingKey:** +``` +FindingKey = (component_purl, component_version, cve_id) +``` + +**RiskState Fields:** +- `reachable: bool | unknown` +- `vex_status: enum` (AFFECTED | NOT_AFFECTED | FIXED | UNDER_INVESTIGATION | UNKNOWN) +- `in_affected_range: bool | unknown` +- `kev: bool` +- `epss_score: float | null` +- `policy_flags: set` +- `evidence_links: list` + +**Rule R1: Reachability Flip** +- `reachable` changes: `false → true` (risk ↑) or `true → false` (risk ↓) + +**Rule R2: VEX Status Flip** +- Meaningful changes: `AFFECTED ↔ NOT_AFFECTED`, `UNDER_INVESTIGATION → NOT_AFFECTED` + +**Rule R3: Affected Range Boundary** +- `in_affected_range` flips: `false → true` or `true → false` + +**Rule R4: Intelligence/Policy Flip** +- `kev` changes `false → true` +- `epss_score` crosses configured threshold +- `policy_flag` changes severity (warn → block) + +## 6. SUPPRESSION RULES + +**Suppression Conditions (ALL must apply):** +1. `reachable == false` +2. `vex_status == NOT_AFFECTED` +3. `kev == false` +4. No policy override + +**Patch Churn Suppression:** +- If version changes AND `in_affected_range` remains false in both AND no KEV/policy flip → suppress + +## 7. CALL-STACK ANALYSIS + +**C# Roslyn Skeleton:** +```csharp +public static class SmartDiff +{ + public static async Task> ReachableSinks(string solutionPath, string[] entrypoints, string[] sinks) + { + var workspace = MSBuild.MSBuildWorkspace.Create(); + var solution = await workspace.OpenSolutionAsync(solutionPath); + var index = new HashSet(); + + foreach (var proj in solution.Projects) + { + var comp = await proj.GetCompilationAsync(); + if (comp is null) continue; + + var epSymbols = comp.GlobalNamespace.GetMembers().SelectMany(Descend) + .OfType().Where(m => entrypoints.Contains(m.ToDisplayString())).ToList(); + var sinkSymbols = comp.GlobalNamespace.GetMembers().SelectMany(Descend) + .OfType().Where(m => sinks.Contains(m.ToDisplayString())).ToList(); + + foreach (var ep in epSymbols) + foreach (var sink in sinkSymbols) + { + var refs = await SymbolFinder.FindReferencesAsync(sink, solution); + if (refs.SelectMany(r => r.Locations).Any()) + index.Add($"{ep.ToDisplayString()} -> {sink.ToDisplayString()}"); + } + } + return index; + + static IEnumerable Descend(INamespaceOrTypeSymbol sym) + { + foreach (var m in sym.GetMembers()) + { + yield return m; + if (m is INamespaceOrTypeSymbol nt) + foreach (var x in Descend(nt)) yield return x; + } + } + } +} +``` + +**Go SSA Skeleton:** +```go +package main + +import ( + "fmt" + "golang.org/x/tools/go/callgraph/cha" + "golang.org/x/tools/go/packages" + "golang.org/x/tools/go/ssa" +) + +func main() { + cfg := &packages.Config{Mode: packages.LoadAllSyntax, Tests: false} + pkgs, _ := packages.Load(cfg, "./...") + prog, pkgsSSA := ssa.NewProgram(pkgs[0].Fset, ssa.BuilderMode(0)) + for _, p := range pkgsSSA { prog.CreatePackage(p, p.Syntax, p.TypesInfo, true) } + prog.Build() + + cg := cha.CallGraph(prog) + fmt.Println("nodes:", len(cg.Nodes)) +} +``` + +## 8. SINK TAXONOMY + +```yaml +sinks: + - CMD_EXEC + - UNSAFE_DESER + - SQL_RAW + - SSRF + - FILE_WRITE + - PATH_TRAVERSAL + - TEMPLATE_INJECTION + - CRYPTO_WEAK + - AUTHZ_BYPASS +``` + +## 9. POLICY SCORING FORMULA + +**Priority Score:** +``` +score = + + 1000 if new.kev + + 500 if new.reachable + + 200 if reason includes RANGE_FLIP to affected + + 150 if VEX_FLIP to AFFECTED + + 0..100 based on EPSS (epss * 100) + + policy weight: +300 if decision BLOCK, +100 if WARN +``` + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md new file mode 100644 index 000000000..3dc4b469d --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Testing and Quality Guardrails Technical Reference.md @@ -0,0 +1,455 @@ +# Testing and Quality Guardrails Technical Reference + +**Source Advisories**: +- 29-Nov-2025 - Acceptance Tests Pack and Guardrails +- 29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests +- 30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps +- 14-Dec-2025 - Create a small ground‑truth corpus + +**Last Updated**: 2025-12-14 + +--- + +## 1. ACCEPTANCE TEST PACK SCHEMA + +### 1.1 Required Artifacts (MVP for DONE) + +- Advisory summary under `docs/process/` +- Checklist stub referencing AT1–AT10 +- Fixture pack path: `tests/acceptance/packs/guardrails/` (no network) +- Links into sprint tracker (`SPRINT_0300_0001_0001_documentation_process.md`) + +### 1.2 Determinism & Offline + +- Freeze scanner/db versions; record in `inputs.lock` +- All fixtures reproducible from seeds +- Include DSSE envelopes for pack manifests + +## 2. SCA FAILURE CATALOGUE (FC1-FC10) + +### 2.1 Required Artifacts + +- Catalogue plus fixture pack root: `tests/fixtures/sca/catalogue/` +- Sprint Execution Log entry when published + +### 2.2 Fixture Requirements + +- Pin scanner versions and feeds +- Include `inputs.lock` and DSSE manifest per case +- Normalize results (ordering, casing) for stable comparisons + +## 3. ECOSYSTEM REALITY TEST CASES (ET1-ET10) + +**Fixture Path**: `tests/fixtures/sca/catalogue/` + +**Requirements**: +- Map each incident to acceptance tests and fixture paths +- Pin tool versions and feeds; no live network +- Populate fixtures and acceptance specs + +## 4. GROUND-TRUTH CORPUS SCHEMA + +### 4.1 Service Structure + +Each service under `/toys/svc-XX-/`: + +``` +app/ +infra/ # Dockerfile, compose, network policy +tests/ # positive + negative reachability tests +labels.yaml # ground truth +evidence/ # generated by tests (trace, tags, manifests) +fix/ # minimal patch proving remediation +``` + +### 4.2 labels.yaml Schema + +```yaml +service: svc-01-password-reset +vulns: + - id: V1 + cve: CVE-2022-XXXXX + type: dep_runtime|dep_build|code|config|os_pkg|supply_chain + package: string + version: string + reachable: true|false + reachability_level: R0|R1|R2|R3|R4 + entrypoint: string # route:/reset, topic:jobs, cli:command + preconditions: [string] # flags/env/auth + path_tags: [string] + proof: + artifacts: [string] + tags: [string] + fix: + type: upgrade|config|code + patch_path: string + expected_delta: string + negative_proof: string # if unreachable +``` + +### 4.3 Reachability Tiers + +- **R0 Present**: component exists in SBOM, not imported/loaded +- **R1 Loaded**: imported/linked/initialized, no executed path +- **R2 Executed**: vulnerable function executed (deterministic trace) +- **R3 Tainted execution**: execution with externally influenced input +- **R4 Exploitable**: controlled, non-harmful PoC (optional) + +### 4.4 Evidence Requirements per Tier + +- **R0**: SBOM + file hash/package metadata +- **R1**: runtime startup logs or module load trace tag +- **R2**: callsite tag + stack trace snippet +- **R3**: R2 + taint marker showing external data reached call +- **R4**: only if safe/necessary; non-weaponized, sandboxed + +### 4.5 Canonical Tag Format + +``` +TAG:route: +TAG:topic: +TAG:call: +TAG:taint: +TAG:flag:= +``` + +### 4.6 Evidence Artifact Schema + +**evidence/trace.json**: +```json +{ + "ts": "UTC ISO-8601", + "corr": "correlation-id", + "tags": ["TAG:route:POST /reset", "TAG:taint:http.body.email", "TAG:call:Crypto.MD5"] +} +``` + +### 4.7 Evidence Manifest + +**evidence/manifest.json**: +```json +{ + "git_sha": "string", + "image_digest": "string", + "tool_versions": {"scanner": "string", "db": "string"}, + "timestamps": {"started_at": "UTC ISO-8601", "completed_at": "UTC ISO-8601"}, + "evidence_hashes": {"trace.json": "sha256:...", "tags.log": "sha256:..."} +} +``` + +## 5. CORE TEST METRICS + +| Metric | Definition | +|--------|------------| +| Recall (by class) | % of labeled vulns detected (runtime deps, OS pkgs, code, config) | +| Precision | 1 - false positive rate | +| Reachability accuracy | % correct R0/R1/R2/R3 classifications | +| Overreach | Predicted reachable but labeled R0/R1 | +| Underreach | Labeled R2/R3 but predicted non-reachable | +| TTFS | Time-to-first-signal (first evidence-backed blocking issue) | +| Fix validation | % of applied fixes producing expected delta | + +## 6. TEST QUALITY GATES (CI ENFORCEMENT THRESHOLDS) + +```yaml +thresholds: + runtime_dependency_recall: >= 0.95 + unreachable_false_positives: <= 0.05 + reachability_underreport: <= 0.10 + ttfs_regression: <= +10% vs main + fix_validation_pass_rate: 100% +``` + +## 7. SERVICE DEFINITION OF DONE + +A service PR is DONE only if it includes: + +- [ ] `labels.yaml` validated by `schemas/labels.schema.json` +- [ ] Docker build reproducible (digest pinned, lockfiles committed) +- [ ] Positive tests generating evidence proving reachability tiers +- [ ] Negative tests proving "unreachable" claims +- [ ] `fix/` patch removing/mitigating weakness with measurable delta +- [ ] `evidence/manifest.json` capturing tool versions, git sha, image digest, timestamps, evidence hashes + +## 8. REVIEWER REJECTION CRITERIA + +Reject PR if any fail: + +- [ ] Labels complete, schema-valid, stable IDs preserved +- [ ] Proof artifacts deterministic and generated by tests +- [ ] Reachability tier justified and matches evidence +- [ ] Unreachable claims have negative proofs +- [ ] Docker build uses pinned digests + committed lockfiles +- [ ] `fix/` produces measurable delta without new unlabeled issues +- [ ] No network egress required; tests hermetic + +## 9. TEST HARNESS PATTERNS + +### 9.1 xUnit Test Template + +```csharp +public class ReachabilityAcceptanceTests : IClassFixture +{ + private readonly PostgresFixture _db; + + public ReachabilityAcceptanceTests(PostgresFixture db) + { + _db = db; + } + + [Theory] + [InlineData("svc-01-password-reset", "V1", ReachabilityLevel.R2)] + [InlineData("svc-02-file-upload", "V1", ReachabilityLevel.R0)] + public async Task VerifyReachabilityClassification( + string serviceId, + string vulnId, + ReachabilityLevel expectedLevel) + { + // Arrange + var labels = await LoadLabels($"toys/{serviceId}/labels.yaml"); + var expectedVuln = labels.Vulns.First(v => v.Id == vulnId); + + // Act + var result = await _scanner.ScanAsync(serviceId); + var actualVuln = result.Findings.First(f => f.VulnId == vulnId); + + // Assert + Assert.Equal(expectedLevel, actualVuln.ReachabilityLevel); + Assert.NotEmpty(actualVuln.Evidence); + } +} +``` + +### 9.2 Testcontainers Pattern + +```csharp +public class PostgresFixture : IAsyncLifetime +{ + private PostgreSqlContainer? _container; + public string ConnectionString { get; private set; } = null!; + + public async Task InitializeAsync() + { + _container = new PostgreSqlBuilder() + .WithImage("postgres:16-alpine") + .WithDatabase("stellaops_test") + .WithUsername("test") + .WithPassword("test") + .Build(); + + await _container.StartAsync(); + ConnectionString = _container.GetConnectionString(); + + // Run migrations + await RunMigrations(ConnectionString); + } + + public async Task DisposeAsync() + { + if (_container != null) + await _container.DisposeAsync(); + } +} +``` + +## 10. FIXTURE ORGANIZATION + +``` +tests/ + fixtures/ + sca/ + catalogue/ + FC001_openssl_version_range/ + inputs.lock + sbom.cdx.json + expected_findings.json + dsse_manifest.json + acceptance/ + packs/ + guardrails/ + AT001_reachability_present/ + AT002_reachability_loaded/ + AT003_reachability_executed/ + micro/ + motion/ + error/ + offline/ + toys/ + svc-01-password-reset/ + app/ + infra/ + tests/ + labels.yaml + evidence/ + fix/ +``` + +## 11. DETERMINISTIC TEST REQUIREMENTS + +### 11.1 Time Handling + +- Freeze timers to `2025-12-04T12:00:00Z` in stories/e2e +- Use `FakeTimeProvider` in .NET tests +- Playwright: `useFakeTimers` + +### 11.2 Random Number Generation + +- Seed RNG with `0x5EED2025` unless scenario-specific +- Never use `Random()` without explicit seed + +### 11.3 Network Isolation + +- No network calls in test execution +- Offline assets bundled +- Testcontainers for external dependencies +- Mock external APIs + +### 11.4 Snapshot Testing + +- All fixtures stored under `tests/fixtures/` +- Golden outputs checked into git +- Stable ordering for arrays/objects +- Strip volatile fields (timestamps, UUIDs) unless semantic + +## 12. COVERAGE REQUIREMENTS + +### 12.1 Unit Tests + +- **Target**: ≥85% line coverage for core modules +- **Critical paths**: 100% coverage required +- **Exceptions**: UI glue code, generated code + +### 12.2 Integration Tests + +- **Database operations**: All repositories tested with Testcontainers +- **API endpoints**: All endpoints tested with WebApplicationFactory +- **External integrations**: Mocked or stubbed + +### 12.3 End-to-End Tests + +- **Critical workflows**: User registration → scan → triage → decision +- **Happy paths**: All major features +- **Error paths**: Authentication failures, network errors, data validation + +## 13. PERFORMANCE TESTING + +### 13.1 Benchmark Tests + +```csharp +[MemoryDiagnoser] +public class ScannerBenchmarks +{ + [Benchmark] + public async Task ScanMediumImage() + { + // 100k LOC .NET service + await _scanner.ScanAsync("medium-service"); + } + + [Benchmark] + public async Task ComputeReachability() + { + await _reachability.ComputeAsync(_testGraph); + } +} +``` + +### 13.2 Performance Targets + +| Operation | Target | +|-----------|--------| +| Medium service scan | < 2 minutes | +| Reachability compute | < 30 seconds | +| Query GET finding | < 200ms p95 | +| SBOM ingestion | < 5 seconds | + +## 14. MUTATION TESTING + +### 14.1 Stryker Configuration + +```json +{ + "stryker-config": { + "mutate": [ + "src/**/*.cs", + "!src/**/*.Designer.cs", + "!src/**/Migrations/**" + ], + "test-runner": "dotnet", + "threshold-high": 90, + "threshold-low": 70, + "threshold-break": 60 + } +} +``` + +### 14.2 Mutation Score Targets + +- **Critical modules**: ≥90% +- **Standard modules**: ≥70% +- **Break build**: <60% + +## 15. SECURITY TESTING + +### 15.1 OWASP Top 10 Coverage + +- [ ] SQL Injection +- [ ] XSS (Cross-Site Scripting) +- [ ] CSRF (Cross-Site Request Forgery) +- [ ] Authentication bypasses +- [ ] Authorization bypasses +- [ ] Sensitive data exposure +- [ ] XML External Entities (XXE) +- [ ] Broken Access Control +- [ ] Security Misconfiguration +- [ ] Insecure Deserialization + +### 15.2 Dependency Scanning + +```bash +# SBOM generation +dotnet sbom-tool generate -b ./bin -bc ./src -pn StellaOps -pv 1.0.0 + +# Vulnerability scanning +dotnet list package --vulnerable --include-transitive +``` + +## 16. CI/CD INTEGRATION + +### 16.1 GitHub Actions Workflow + +```yaml +name: Test + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + - name: Restore dependencies + run: dotnet restore + - name: Build + run: dotnet build --no-restore + - name: Test + run: dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage" + - name: Upload coverage + uses: codecov/codecov-action@v4 +``` + +### 16.2 Quality Gates + +- All tests pass +- Coverage ≥85% +- No high/critical vulnerabilities +- Mutation score ≥70% +- Performance regressions <10% + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - Triage and Unknowns Technical Reference.md b/docs/product-advisories/14-Dec-2025 - Triage and Unknowns Technical Reference.md new file mode 100644 index 000000000..be0e390a2 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - Triage and Unknowns Technical Reference.md @@ -0,0 +1,390 @@ +# Triage and Unknowns Technical Reference + +**Source Advisories**: +- 30-Nov-2025 - Unknowns Decay & Triage Heuristics +- 14-Dec-2025 - Dissect triage and evidence workflows +- 04-Dec-2025 - Ranking Unknowns in Reachability Graphs + +**Last Updated**: 2025-12-14 + +--- + +## 1. EVIDENCE-FIRST PRINCIPLES + +1. **Evidence before detail**: Opening alert shows best available evidence immediately +2. **Fast first signal**: UI renders credible "first signal" quickly +3. **Determinism reduces hesitation**: Sorting, graphs, diffs stable across refreshes +4. **Offline by design**: If evidence exists locally, render without network +5. **Audit-ready by default**: Every decision reproducible, attributable, exportable + +## 2. MINIMAL EVIDENCE BUNDLE (PER FINDING) + +1. **Reachability proof**: Function-level path or package-level import chain +2. **Call-stack snippet**: 5–10 frames around sink/source with file:line anchors +3. **Provenance**: Attestation/DSSE + build ancestry (image → layer → artifact → commit) +4. **VEX/CSAF status**: affected/not-affected/under-investigation + reason +5. **Diff**: SBOM or VEX delta since last scan (smart-diff) + +## 3. KPIS + +### 3.1 TTFS (Time-to-First-Signal) + +**Definition**: p50/p95 from alert creation to first rendered evidence + +**Target**: p95 < 1.5s (with 100ms RTT, 1% loss) + +### 3.2 Clicks-to-Closure + +**Definition**: Median interactions per decision type + +**Target**: median < 6 clicks + +### 3.3 Evidence Completeness Score + +**Definition**: 0–4 (reachability, call-stack, provenance, VEX present) + +**Target**: ≥90% of decisions include all evidence + reason + replay token + +### 3.4 Offline Friendliness + +**Definition**: % evidence resolvable with no network + +**Target**: ≥95% with local bundle + +### 3.5 Audit Log Completeness + +**Requirement**: Every decision has evidence hash set, actor, policy context, replay token + +## 4. KEYBOARD SHORTCUTS + +- `J`: Jump to first incomplete evidence pane +- `Y`: Copy DSSE (attestation block or Rekor entry ref) +- `R`: Toggle reachability view (path list ↔ compact graph ↔ textual proof) +- `/`: Search within graph (node/func/package) +- `S`: Deterministic sort (reachability→severity→age→component) +- `A`, `N`, `U`: Quick VEX set (Affected / Not-affected / Under-investigation) +- `?`: Keyboard help overlay + +## 5. UX FLOW + +### 5.1 Alert Row + +- TTFS timer +- Reachability badge +- Decision state +- Diff-dot + +### 5.2 Open Alert → Evidence Tab (Not Details) + +**Top strip**: 3 proof pills (Reachability ✓ / Call-stack ✓ / Provenance ✓) + +Click to expand inline + +### 5.3 Decision Drawer (Pinned Right) + +- VEX/CSAF radio (A/N/U) +- Reason presets → "Record decision" +- Audit-ready summary (hashes, timestamps, policy) + +### 5.4 Diff Tab + +SBOM/VEX delta, grouped by "meaningful risk shift" + +### 5.5 Activity Tab + +Immutable audit log; export as signed bundle + +## 6. GRAPH PERFORMANCE (LARGE CALL GRAPHS) + +### 6.1 Minimal-Latency Snapshots + +- Pre-render static PNG/SVG thumbnails server-side + +### 6.2 Progressive Neighborhood Expansion + +- Load 1-hop first, expand on demand +- First TTFS < 500ms + +### 6.3 Stable Node Ordering + +- Deterministic layout with consistent anchors + +### 6.4 Chunked Graph Edges + +- Capped fan-out +- Collapse identical library paths into reachability macro-edge + +**Targets**: +- Preview < 300ms +- Interactive hydration < 2.0s for large graphs + +## 7. OFFLINE DESIGN + +### 7.1 Local Evidence Cache + +Store (SBOM slices, path proofs, DSSE attestations, compiled call-stacks) in signed bundle beside SARIF/VEX + +### 7.2 Deferred Enrichment + +Mark fields needing internet; queue background "enricher" when network returns + +### 7.3 Predictable Fallbacks + +Show embedded DSSE + "verification pending" if provenance server missing + +## 8. AUDIT & REPLAY + +### 8.1 Deterministic Replay Token + +``` +replay_token = hash(feed_manifests + rules + lattice_policy + inputs) +``` + +### 8.2 One-Click "Reproduce" + +CLI snippet pinned to exact versions and policies + +### 8.3 Evidence Hash-Set + +Content-address each proof artifact; audit entry stores hashes + signer + +## 9. TELEMETRY IMPLEMENTATION + +```typescript +ttfs.start → (alert creation) +ttfs.signal → (first evidence card paint) +close.clicks → (decision recorded) +``` + +Log evidence bitset (reach, stack, prov, vex) at decision time + +## 10. API REQUIREMENTS + +### 10.1 Endpoints + +``` +GET /alerts?filters… → list view +GET /alerts/{id}/evidence → evidence payload (reachability, call stack, provenance, hashes) +POST /alerts/{id}/decisions → record decision event (append-only) +GET /alerts/{id}/audit → audit timeline +GET /alerts/{id}/diff?baseline=… → SBOM/VEX diff +GET /bundles/{id}, POST /bundles/verify → offline bundle download/verify +``` + +### 10.2 Evidence Payload Schema + +```json +{ + "alert_id": "a123", + "reachability": { "status": "available|loading|unavailable|error", "hash": "sha256:…", "proof": {...} }, + "callstack": { "status": "...", "hash": "...", "frames": [...] }, + "provenance": { "status": "...", "hash": "...", "dsse": {...} }, + "vex": { "status": "...", "current": {...}, "history": [...] }, + "hashes": ["sha256:…", ...] +} +``` + +**Guidelines**: +- Deterministic ordering for arrays and nodes +- Explicit `status` per evidence section +- Include `hash` per artifact + +## 11. DECISION EVENT SCHEMA + +Store per decision: + +- `alert_id`, `artifact_id` (image digest/commit hash) +- `actor_id`, `timestamp` +- `decision_status` (Affected/Not affected/Under investigation) +- `reason_code` (preset) + `reason_text` +- `evidence_hashes[]` (content-addressed) +- `policy_context` (ruleset version, policy id) +- `replay_token` (hash of inputs) + +## 12. OFFLINE BUNDLE FORMAT + +Single file (`.stella.bundle.tgz`) containing: + +- Alert metadata snapshot +- Evidence artifacts (reachability proofs, call stacks, provenance attestations) +- SBOM slice(s) for diffs +- VEX decision history +- Manifest with content hashes +- **Must be signed and verifiable** + +## 13. PERFORMANCE BUDGETS + +- **TTFS**: <200ms skeleton, <500ms first evidence pill, <1.5s p95 full evidence +- **Graph**: Preview <300ms, interactive <2.0s +- **Interaction response**: ≤100ms +- **Animation frame budget**: 16ms avg / 50ms p95 +- **Keyboard coverage**: ≥90% of triage actions +- **Offline replay**: 100% of decisions re-render from bundle + +## 14. ERROR HANDLING + +Never show empty states without explanation. Distinguish: + +- "not computed yet" +- "not possible due to missing inputs" +- "blocked by permissions" +- "offline—enrichment pending" +- "verification failed" + +## 15. RBAC + +Gate: +- Viewing provenance attestations +- Recording decisions +- Exporting audit bundles + +All decision events immutable; corrections are new events (append-only) + +## 16. UNKNOWNS DECAY & TRIAGE HEURISTICS + +### 16.1 Problem + +Stale "unknown" findings create noise; need deterministic decay and triage rules + +### 16.2 Requirements + +- Confidence decay card +- Triage queue UI +- Export artifacts for planning + +### 16.3 Determinism + +- Decay windows and thresholds must be deterministic +- Exports reproducible without live dependencies + +### 16.4 Decay Logic + +**Decay Windows**: Define time-based decay windows + +**Thresholds**: Set confidence thresholds for promotion/demotion + +**UI/Export Snapshot Expectations**: Deterministic decay logic description + +## 17. UNKNOWNS RANKING ALGORITHM + +### 17.1 Score Formula + +``` +Score = clamp01( + wP·P + # Popularity impact + wE·E + # Exploit consequence potential + wU·U + # Uncertainty density + wC·C + # Graph centrality + wS·S # Evidence staleness +) +``` + +### 17.2 Default Weights + +``` +wP = 0.25 (deployment impact) +wE = 0.25 (potential consequence) +wU = 0.25 (uncertainty density) +wC = 0.15 (graph centrality) +wS = 0.10 (evidence staleness) +``` + +### 17.3 Heuristics + +``` +P = min(1, log10(1 + deployments)/log10(1 + 100)) +U = sum of flags, capped at 1.0: + +0.30 if no provenance anchor + +0.25 if version_range + +0.20 if conflicting_feeds + +0.15 if missing_vector + +0.10 if unreachable source advisory +S = min(1, age_days / 14) +``` + +### 17.4 Band Assignment + +``` +Score ≥ 0.70 → HOT (immediate rescan + VEX escalation) +0.40 ≤ Score < 0.70 → WARM (scheduled rescan 12-72h) +Score < 0.40 → COLD (weekly batch) +``` + +## 18. UNKNOWNS DATABASE SCHEMA + +```sql +CREATE TABLE unknowns ( + unknown_id uuid PRIMARY KEY, + pkg_id text, + pkg_version text, + digest_anchor bytea, + unknown_flags jsonb, + popularity_p float, + potential_e float, + uncertainty_u float, + centrality_c float, + staleness_s float, + score float, + band text CHECK(band IN ('HOT','WARM','COLD')), + graph_slice_hash bytea, + evidence_set_hash bytea, + normalization_trace jsonb, + callgraph_attempt_hash bytea, + created_at timestamptz, + updated_at timestamptz +); + +CREATE TABLE deploy_refs ( + pkg_id text, + image_id text, + env text, + first_seen timestamptz, + last_seen timestamptz +); + +CREATE TABLE graph_metrics ( + pkg_id text PRIMARY KEY, + degree_c float, + betweenness_c float, + last_calc_at timestamptz +); +``` + +## 19. TRIAGE QUEUE UI + +### 19.1 Queue Views + +- **HOT**: Red badge, sort by score desc +- **WARM**: Yellow badge, sort by score desc +- **COLD**: Gray badge, sort by age asc + +### 19.2 Bulk Actions + +- Mark as reviewed +- Escalate to HOT +- Suppress (with reason) +- Export selected + +### 19.3 Filters + +- By band +- By package +- By environment +- By date range + +## 20. DECISION WORKFLOW CHECKLIST + +For any triage decision: + +- [ ] Evidence reviewed (reachability, call-stack, provenance, VEX) +- [ ] Decision status selected (A/N/U) +- [ ] Reason provided (preset or custom) +- [ ] Replay token generated +- [ ] Evidence hashes captured +- [ ] Audit event recorded +- [ ] Decision immutable (append-only) + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/14-Dec-2025 - UX and Time-to-Evidence Technical Reference.md b/docs/product-advisories/14-Dec-2025 - UX and Time-to-Evidence Technical Reference.md new file mode 100644 index 000000000..6eb3057c1 --- /dev/null +++ b/docs/product-advisories/14-Dec-2025 - UX and Time-to-Evidence Technical Reference.md @@ -0,0 +1,723 @@ +# UX and Time-to-Evidence Technical Reference + +**Source Advisories**: +- 01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence +- 12-Dec-2025 - Measure UX Efficiency Through TTFS +- 13-Dec-2025 - Define a north star metric for TTFS +- 14-Dec-2025 - Add a dedicated "first_signal" event +- 04-Dec-2025 - Designing Traceable Evidence in Security UX +- 05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose +- 30-Nov-2025 - UI Micro-Interactions for StellaOps +- 11-Dec-2025 - Stella DevOps UX Implementation Guide + +**Last Updated**: 2025-12-14 + +--- + +## 1. PERFORMANCE TARGETS & SLOS + +### 1.1 Time-to-Evidence (TTE) + +**Definition**: `TTE = t_first_proof_rendered − t_open_finding` + +**Primary SLO**: P95 ≤ 15s (stretch: P99 ≤ 30s) + +**Guardrail**: P50 < 3s + +**By proof type**: +- Simple proof (SBOM row): P95 ≤ 5s +- Complex proof (reachability graph): P95 ≤ 15s + +**Backend budget**: 12s backend + 3s UI/render margin = 15s P95 + +**Query performance**: O(log n) on indexed columns + +### 1.2 Time-to-First-Signal (TTFS) + +**Definition**: Time from user action/CI start → first meaningful signal rendered/logged + +**Primary SLO**: P50 < 2s, P95 < 5s (all surfaces: UI, CLI, CI) + +**Warm path**: P50 < 700ms, P95 < 2500ms + +**Cold path**: P95 ≤ 4000ms + +**Component budgets**: +- Frontend: ≤150ms (skeleton + last known state) +- Edge/API: ≤250ms (signal frame fast path from cache) +- Core services: ≤500–1500ms (pre-indexed failures, warm summaries) +- Slow work: async (scan, lattice merge, provenance) + +### 1.3 General UX Performance + +- **Interaction response**: ≤100ms +- **Animation frame budget**: 16ms avg / 50ms P95 +- **LCP placeholder**: shown immediately +- **Layout shift**: <0.05 +- **Motion durations**: 80/140/200/260/320ms +- **Reduced-motion**: 0-80ms clamp + +### 1.4 Cache Performance + +- **Cache-hit response**: P95 ≤ 250ms +- **Cold response**: P95 ≤ 500ms +- **Endpoint error rate**: < 0.1% under expected concurrency + +## 2. METRICS DEFINITIONS & FORMULAS + +### 2.1 TTE Metrics + +```typescript +// Core TTE calculation +tte_ms = proof_rendered.timestamp - finding_open.timestamp + +// Dimensions +{ + tenant: string, + finding_id: string, + proof_kind: 'sbom' | 'reachability' | 'vex', + source: 'local' | 'remote' | 'cache', + page: string +} +``` + +**SQL Rollup (hourly)**: +```sql +SELECT + proof_kind, + percentile_cont(0.95) WITHIN GROUP (ORDER BY tte_ms) AS p95_ms +FROM tte_events +WHERE ts >= now() - interval '1 hour' +GROUP BY proof_kind; +``` + +### 2.2 TTFS Metrics + +```typescript +// Core TTFS calculation +ttfs_ms = signal_rendered.timestamp - start.timestamp + +// Dimensions +{ + surface: 'ui' | 'cli' | 'ci', + cache_hit: boolean, + signal_source: 'snapshot' | 'cold_start' | 'failure_index', + kind: string, + repo_size_bucket: string, + provider: string, + branch: string, + run_type: 'PR' | 'main', + network_state: string +} +``` + +### 2.3 Secondary Metrics + +- **Open→Action time**: Time from opening run to first user action +- **Bounce rate**: Close page within 10s without interaction +- **MTTR proxy**: Time from failure to first rerun or fix commit +- **Signal availability rate**: % of run views showing first signal within 3s +- **Signal accuracy score**: Engineer confirms "helpful vs not" (sampled) +- **Extractor failure rate**: Parsing errors / missing mappings / timeouts + +### 2.4 DORA Metrics + +- **Deployment Frequency**: Deploys per day/week +- **Lead Time for Changes**: Commit → deployment completion +- **Change Failure Rate**: Failed deployments / total deployments +- **Time to Restore**: Incident start → resolution + +### 2.5 Quality Metrics + +- **Error budget burn**: Minutes over target per day +- **Top regressions**: Last 7 days vs prior 7 +- **Extraction failure rate**: < 1% for sampled runs + +## 3. EVENT SCHEMAS + +### 3.1 TTE Events + +**finding_open**: +```typescript +{ + event: 'finding_open', + findingId: string, + tenantId: string, + userId: string, + userRole: 'admin' | 'dev' | 'triager', + entryPoint: 'list' | 'search' | 'notification' | 'deep_link', + uiVersion: string, + buildSha: string, + t: number // performance.now() +} +``` + +**proof_rendered**: +```typescript +{ + event: 'proof_rendered', + findingId: string, + proofKind: 'sbom' | 'reachability' | 'vex' | 'logs' | 'other', + source: 'local_cache' | 'backend_api' | '3rd_party', + proofHeight: number, // pixel offset from top + t: number // performance.now() +} +``` + +### 3.2 TTFS Events + +**ttfs_start**: +```typescript +{ + event: 'ttfs_start', + runId: string, + surface: 'ui' | 'cli' | 'ci', + provider: string, + repo: string, + branch: string, + runType: 'PR' | 'main', + device: string, + release: string, + networkState: string, + t: number +} +``` + +**ttfs_signal_rendered**: +```typescript +{ + event: 'ttfs_signal_rendered', + runId: string, + surface: 'ui' | 'cli' | 'ci', + cacheHit: boolean, + signalSource: 'snapshot' | 'cold_start' | 'failure_index', + kind: string, + t: number +} +``` + +### 3.3 FirstSignal Event Contract + +```typescript +interface FirstSignal { + version: '1.0', + signalId: string, + jobId: string, + timestamp: string, // ISO-8601 + kind: 'queued' | 'started' | 'phase' | 'blocked' | 'failed' | 'succeeded' | 'canceled' | 'unavailable', + phase: 'resolve' | 'fetch' | 'restore' | 'analyze' | 'policy' | 'report' | 'unknown', + scope: { + type: 'repo' | 'image' | 'artifact', + id: string + }, + summary: string, + etaSeconds?: number, + lastKnownOutcome?: { + signatureId: string, + errorCode: string, + token: string, + excerpt: string, + confidence: 'low' | 'medium' | 'high', + firstSeenAt: string, + hitCount: number + }, + nextActions?: Array<{ + type: 'open_logs' | 'open_job' | 'docs' | 'retry' | 'cli_command', + label: string, + target: string + }>, + diagnostics: { + cacheHit: boolean, + source: 'snapshot' | 'failure_index' | 'cold_start', + correlationId: string + } +} +``` + +### 3.4 UI Telemetry Schema + +**ui.micro.* events**: +```typescript +{ + version: string, + tenant: string, + surface: string, + component: string, + action: string, + latency_ms: number, + outcome: string, + reduced_motion: boolean, + offline_mode: boolean, + error_code?: string +} +``` +*Schema location*: `docs/modules/ui/telemetry/ui-micro.schema.json` + +## 4. API CONTRACTS + +### 4.1 First Signal Endpoint + +**GET** `/api/runs/{runId}/first-signal` + +**Headers**: +- `If-None-Match: W/"..."` (supported) + +**Response**: +```json +{ + "runId": "123", + "firstSignal": { + "type": "stage_failed", + "stage": "build", + "step": "dotnet restore", + "message": "401 Unauthorized: token expired", + "at": "2025-12-11T09:22:31Z", + "artifact": { + "kind": "log", + "range": { "start": 1880, "end": 1896 } + } + }, + "summaryEtag": "W/\"a1b2c3\"" +} +``` + +**Status codes**: +- `200`: Full first signal object +- `304`: Not modified +- `404`: Run not found +- `204`: Run exists but signal not available yet + +**Response headers**: +- `ETag` +- `Cache-Control` +- `X-Correlation-Id` +- `Cache-Status: hit|miss|bypass` + +### 4.2 Summary Endpoint + +**GET** `/api/runs/{runId}/summary` + +Returns: Status, first failing stage/job, timestamps, blocking policies, artifact counts + +### 4.3 SSE Events Endpoint + +**GET** `/api/runs/{runId}/events` (Server-Sent Events) + +**Event payloads**: +- `status` (kind+phase+message) +- `hint` (token+errorCode+confidence) +- `policy` (blocked + policyId) +- `complete` (terminal) + +## 5. FRONTEND PATTERNS & COMPONENT SPECIFICATIONS + +### 5.1 UI Contract (Evidence First) + +**Above the fold**: +- Always show compact **Proof panel** first (not hidden behind tabs) +- **Skeletons over spinners**: Reserve space; render partial proof as ready +- **Plain text copy affordance**: "Copy SBOM line / path" button next to proof +- **Defer non-proof widgets**: CVSS badges, remediation prose, charts load *after* proof +- **Empty-state truth**: "No proof available yet" + loader for *that* proof type only + +### 5.2 Progressive Rendering Pattern + +**Immediate render**: +1. Title, status badge, pipeline metadata (run id, commit, branch) +2. Skeleton for details area + +**First signal fetch**: +3. Render `FirstSignalCard` immediately when available +4. Fire telemetry event when card is in DOM and visible + +**Lazy-load**: +5. Stage graph +6. Full logs viewer +7. Artifacts list +8. Security findings +9. Trends, flaky tests, etc. + +### 5.3 Component Specifications + +#### FirstSignalCard Component +- Standalone, minimal dependencies +- Shows: summary + at least one next action button (Open job/logs) +- Updates in-place on deltas from SSE +- Falls back to polling when SSE fails + +#### EvidencePanel Component +```typescript +interface EvidencePanel { + tabs: ['SBOM', 'Reachability', 'VEX', 'Logs', 'Other'], + firstProofType: ProofKind, + copyEnabled: boolean, + emptyStateMessage?: string +} +``` + +#### ProofSpine Component +- Displays: hashes, Rekor link +- Verification status: `Verified` | `Unverified` | `Failed verification` | `Expired/Outdated` +- "Verify locally" copy button with exact commands + +### 5.4 Prefetch Strategy + +From runs list view: +- Use `IntersectionObserver` to prefetch summaries/first signals for items in viewport +- Store results in in-memory cache (`Map`) +- Respect ETag to avoid redundant payloads + +## 6. TELEMETRY REQUIREMENTS + +### 6.1 Client-Side Telemetry + +**Frontend events**: +```typescript +// On route enter +metrics.emit('finding_open', { findingId, t: performance.now() }); + +// When first proof node/line hits DOM +metrics.emit('proof_rendered', { findingId, proofKind, t: performance.now() }); +``` + +**Sampling**: +- **Staging**: 100% +- **Production**: ≥25% of sessions (ideal: 100%) + +**Clock handling**: +- Use `performance.now()` for TTE (monotonic within tab) +- Don't mix backend clocks into TTE calculation + +### 6.2 Backend Telemetry + +**Endpoint metrics**: +- `signal_endpoint_latency_ms` +- `signal_payload_bytes` +- `signal_error_rate` + +**Server-side timing logs** (debug-level): +- Cache read time +- DB read time +- Cold path time + +**Tracing**: +- Correlation ID propagated in: + - API response header + - Worker logs + - Events + +### 6.3 Dashboard Requirements + +**Core widgets**: +1. TTE distribution (P50/P90/P95/P99) per day, split by proof_kind +2. TTE by page/surface (list→detail, deep links, bookmarks) +3. TTE by user segment (new vs power users, roles) +4. Error budget: "Minutes over SLO per day" +5. Correlation: TTE vs session length, TTE vs "clicked ignore/snooze" + +**Operational panels**: +- Update granularity: Real-time or ≤15 min +- Retention: ≥90 days +- Breakdowns: backend_region, build_version + +**TTFS dashboards**: +- By surface (ui/cli/ci) +- Cache hit rate +- Endpoint latency percentiles +- Repo size bucket +- Kind/phase + +**Alerts**: +- Page when `p95(ttfs_ms) > 5000` for 5 mins +- Page when `signal_endpoint_error_rate > 1%` +- Alert when **P95 TTE > 15s** for 15 minutes + +## 7. DATABASE SCHEMAS + +### 7.1 TTE Events Table + +```sql +CREATE TABLE tte_events ( + id SERIAL PRIMARY KEY, + ts TIMESTAMPTZ NOT NULL DEFAULT now(), + tenant TEXT NOT NULL, + finding_id TEXT NOT NULL, + proof_kind TEXT NOT NULL, + source TEXT NOT NULL, + tte_ms INT NOT NULL, + page TEXT, + user_role TEXT +); + +CREATE INDEX ON tte_events (ts DESC); +CREATE INDEX ON tte_events (proof_kind, ts DESC); +``` + +### 7.2 First Signal Snapshots + +```sql +CREATE TABLE first_signal_snapshots ( + job_id TEXT PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + kind TEXT NOT NULL, + phase TEXT NOT NULL, + summary TEXT NOT NULL, + eta_seconds INT NULL, + payload_json JSONB NOT NULL +); + +CREATE INDEX ON first_signal_snapshots (updated_at DESC); +``` + +### 7.3 Failure Signatures + +```sql +CREATE TABLE failure_signatures ( + signature_id TEXT PRIMARY KEY, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + scope_type TEXT NOT NULL, + scope_id TEXT NOT NULL, + toolchain_hash TEXT NOT NULL, + error_code TEXT NULL, + token TEXT NOT NULL, + excerpt TEXT NULL, + confidence TEXT NOT NULL, + first_seen_at TIMESTAMPTZ NOT NULL, + last_seen_at TIMESTAMPTZ NOT NULL, + hit_count INT NOT NULL DEFAULT 1 +); + +CREATE INDEX ON failure_signatures (scope_type, scope_id, toolchain_hash); +CREATE INDEX ON failure_signatures (token); +``` + +## 8. MOTION & ANIMATION TOKENS + +### 8.1 Duration Tokens + +| Token | Value | Use Case | +|-------|-------|----------| +| `duration-xs` | 80ms | Quick hover, focus | +| `duration-sm` | 140ms | Button press, small transitions | +| `duration-md` | 200ms | Modal open/close, panel slide | +| `duration-lg` | 260ms | Page transitions | +| `duration-xl` | 320ms | Complex animations | + +**Reduced-motion override**: Clamp all to 0-80ms + +### 8.2 Easing Tokens + +- `standard`: Default transition +- `decel`: Element entering (start fast, slow down) +- `accel`: Element exiting (slow start, speed up) +- `emphasized`: Important state changes + +### 8.3 Distance Scales + +- `XS`: 4px +- `SM`: 8px +- `MD`: 16px +- `LG`: 24px +- `XL`: 32px + +**Location**: `src/Web/StellaOps.Web/src/styles/tokens/motion.{ts,scss}` + +## 9. ACCESSIBILITY REQUIREMENTS + +### 9.1 WCAG 2.1 AA Compliance + +- Focus order: logical and consistent +- Keyboard: all interactive elements accessible +- Contrast: + - Text: ≥ 4.5:1 + - UI elements: ≥ 3:1 +- Reduced motion: honored via `prefers-reduced-motion` +- Status messaging: `aria-live=polite` for updates + +### 9.2 Reduced-Motion Rules + +When `prefers-reduced-motion: reduce`: +- Durations clamp to 0-80ms +- Disable parallax/auto-animations +- Focus/hover states remain visible +- No animated GIF/Lottie autoplay + +### 9.3 Screen Reader Support + +- **Undo window**: 8s with keyboard focus and `aria-live=polite` +- **Loading states**: Announce state changes +- **Error messages**: Informative, not generic + +## 10. EVIDENCE & PROOF SPECIFICATIONS + +### 10.1 Evidence Bundle Minimum Requirements + +**Component presence**: +- SBOM fragment (SPDX/CycloneDX) with component identity and provenance +- Signed attestation for SBOM artifact + +**Vulnerability match**: +- Matching rule details (CPE/purl/range) + scanner identity/version +- Signed vulnerability report attestation + +**Reachable vulnerability**: +- Call path: entrypoint → frames → vulnerable symbol +- Hash/digest of call graph slice (tamper-evident) +- Tool info + limitations (reflection/dynamic dispatch uncertainty) + +**Not affected via VEX**: +- VEX statement (OpenVEX/CSAF) + signer +- Justification for `not_affected` +- Align to CISA minimum requirements + +**Gate decision**: +- Input digests (SBOM digest, scan attestation digests, VEX doc digests) +- Policy version + rule ID +- Deterministic **decision hash** over (policy + input digests) + +### 10.2 Evidence Object Structure + +```typescript +interface Evidence { + sbom_snippet_attestation: DSSEEnvelope, + reachability_proof: { + entrypoint: string, + frames: CallFrame[], + file_hashes: string[], + graph_digest: string + }, + attestation_chain: DSSESummary[], + transparency_receipt: { + logIndex: number, + uuid: string, + inclusionProof: string, + checkpoint: string + } +} +``` + +### 10.3 Proof Panel Requirements + +**Four artifacts**: +1. **SBOM snippet (signed)**: DSSE attestation, verify with cosign +2. **Call-stack slice**: Entrypoint → vulnerable symbol, status pill (`Reachable`, `Potentially reachable`, `Unreachable`) +3. **Attestation chain**: DSSE envelope summary, verification status, "Verify locally" command +4. **Transparency receipt**: Rekor inclusion proof, "Verify inclusion" command + +**One-click export**: +- "Export Evidence (.tar.gz)" bundling: SBOM slice, call-stack JSON, DSSE attestation, Rekor proof JSON + +## 11. CONFIGURATION & FEATURE FLAGS + +### 11.1 TTFS Feature Flags + +```yaml +ttfs: + first_signal_enabled: true # Default ON in staging + cache_enabled: true + failure_index_enabled: true + sse_enabled: true + policy_preeval_enabled: true +``` + +### 11.2 Cache Configuration + +```yaml +cache: + backend: valkey | postgres | none # TTFS_CACHE_BACKEND + ttl_seconds: 86400 # TTFS_CACHE_TTL_SECONDS + key_pattern: "signal:job:{jobId}" +``` + +### 11.3 Air-Gapped Profile + +- Skip Valkey; use Postgres-only +- Use `first_signal_snapshots` table +- NOTIFY/LISTEN for streaming updates + +## 12. TESTING REQUIREMENTS + +### 12.1 Acceptance Criteria (TTE) + +- [ ] First paint shows real proof snippet (not summary) +- [ ] "Copy proof" button works within 1 click +- [ ] TTE P95 in staging ≤ 10s; in prod ≤ 15s +- [ ] If proof missing, explicit empty-state + retry path +- [ ] Telemetry sampled ≥ 50% of sessions (or 100% for internal) + +### 12.2 Acceptance Tests (TTFS) + +- Run with early fail → first signal < 1s, shows exact command + exit code +- Run with policy gate fail → rule name + fix hint visible first +- Offline/slow network → cached summary still renders actionable hint + +### 12.3 Determinism Requirements + +- Freeze timers to `2025-12-04T12:00:00Z` in stories/e2e +- Seed RNG with `0x5EED2025` unless scenario-specific +- All fixtures stored under `tests/fixtures/micro/` +- No network calls; offline assets bundled +- Playwright runs with `--disable-animations` and reduced-motion emulation + +### 12.4 Load Tests + +`/jobs/{id}/signal`: +- Cache-hit P95 ≤ 250ms +- Cold path P95 ≤ 500ms +- Error rate < 0.1% under expected concurrency + +## 13. REDACTION & SECURITY + +### 13.1 Excerpt Redaction Rules + +- Strip: bearer tokens, API keys, access tokens, private URLs +- Cap excerpt length: 240 chars +- Normalize whitespace +- Never include excerpts in telemetry attributes + +### 13.2 Tenant Isolation + +Cache keys include tenant boundary: +``` +tenant:{tenantId}:signal:job:{jobId} +``` + +Failure signatures looked up within same tenant only. + +### 13.3 Secret Scanning + +Runtime guardrails: +- If excerpt contains forbidden patterns → replace with "[redacted]" +- Security review sign-off required for snapshot + signature + telemetry + +## 14. LOCALIZATION + +### 14.1 Micro-Copy Requirements + +- Keys and ICU messages for micro-interaction copy +- Defaults: EN +- Fallbacks present +- No hard-coded strings in components +- i18n extraction shows zero TODO keys + +### 14.2 Snapshot Verification + +Verify translated skeleton/error/undo copy in snapshots. + +## 15. DELIVERABLES MAP + +| Category | Location | Description | +|----------|----------|-------------| +| Motion tokens | `src/Web/StellaOps.Web/src/styles/tokens/motion.{ts,scss}` | Duration, easing, distance scales + reduced-motion overrides | +| Storybook stories | `apps/storybook/src/stories/micro/*` | Slow, error, offline, reduced-motion, undo flows | +| Playwright suite | `tests/e2e/micro-interactions.spec.ts` | MI2/MI3/MI4/MI8 coverage | +| Telemetry schema | `docs/modules/ui/telemetry/ui-micro.schema.json` | Event schema + validators | +| Component map | `docs/modules/ui/micro-interactions-map.md` | Components → interaction type → token usage | +| Fixtures | `tests/fixtures/micro/` | Deterministic test fixtures | + +--- + +**Document Version**: 1.0 +**Target Platform**: .NET 10, PostgreSQL ≥16, Angular v17 diff --git a/docs/product-advisories/01-Dec-2025 - Benchmarks for a Testable Security Moat.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Benchmarks for a Testable Security Moat.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - Benchmarks for a Testable Security Moat.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Benchmarks for a Testable Security Moat.md diff --git a/docs/product-advisories/01-Dec-2025 - Common Developers guides.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Common Developers guides.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - Common Developers guides.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Common Developers guides.md diff --git a/docs/product-advisories/01-Dec-2025 - DSSE‑Signed Offline Scanner Updates.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - DSSE‑Signed Offline Scanner Updates.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - DSSE‑Signed Offline Scanner Updates.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - DSSE‑Signed Offline Scanner Updates.md diff --git a/docs/product-advisories/01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - PostgreSQL Patterns for Each StellaOps Module.md diff --git a/docs/product-advisories/01-Dec-2025 - Proof-Linked VEX User Interface.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Proof-Linked VEX User Interface.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - Proof-Linked VEX User Interface.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Proof-Linked VEX User Interface.md diff --git a/docs/product-advisories/01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Tracking UX Health with Time‑to‑Evidence.md diff --git a/docs/product-advisories/01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs.md b/docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs.md similarity index 100% rename from docs/product-advisories/01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs.md rename to docs/product-advisories/archived/14-Dec-2025/01-Dec-2025 - Turning SBOM Data Into Verifiable Proofs.md diff --git a/docs/product-advisories/02-Dec-2025 - Benchmarking a Testable Security Moat.md b/docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Benchmarking a Testable Security Moat.md similarity index 100% rename from docs/product-advisories/02-Dec-2025 - Benchmarking a Testable Security Moat.md rename to docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Benchmarking a Testable Security Moat.md diff --git a/docs/product-advisories/02-Dec-2025 - Converting SBOM Data into Proof Chains.md b/docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Converting SBOM Data into Proof Chains.md similarity index 100% rename from docs/product-advisories/02-Dec-2025 - Converting SBOM Data into Proof Chains.md rename to docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Converting SBOM Data into Proof Chains.md diff --git a/docs/product-advisories/02-Dec-2025 - Designing Deterministic Reachability UX.md b/docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Designing Deterministic Reachability UX.md similarity index 100% rename from docs/product-advisories/02-Dec-2025 - Designing Deterministic Reachability UX.md rename to docs/product-advisories/archived/14-Dec-2025/02-Dec-2025 - Designing Deterministic Reachability UX.md diff --git a/docs/product-advisories/03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools.md b/docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools.md similarity index 100% rename from docs/product-advisories/03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools.md rename to docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Comparing Proof‑Linked VEX UX Across Tools.md diff --git a/docs/product-advisories/03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat.md b/docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat.md similarity index 100% rename from docs/product-advisories/03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat.md rename to docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Next‑Gen Scanner Differentiators and Evidence Moat.md diff --git a/docs/product-advisories/03-Dec-2025 - Reachability Benchmarks and Moat Metrics.md b/docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Reachability Benchmarks and Moat Metrics.md similarity index 100% rename from docs/product-advisories/03-Dec-2025 - Reachability Benchmarks and Moat Metrics.md rename to docs/product-advisories/archived/14-Dec-2025/03-Dec-2025 - Reachability Benchmarks and Moat Metrics.md diff --git a/docs/product-advisories/04-Dec-2025 - Designing Traceable Evidence in Security UX.md b/docs/product-advisories/archived/14-Dec-2025/04-Dec-2025 - Designing Traceable Evidence in Security UX.md similarity index 100% rename from docs/product-advisories/04-Dec-2025 - Designing Traceable Evidence in Security UX.md rename to docs/product-advisories/archived/14-Dec-2025/04-Dec-2025 - Designing Traceable Evidence in Security UX.md diff --git a/docs/product-advisories/04-Dec-2025 - Ranking Unknowns in Reachability Graphs.md b/docs/product-advisories/archived/14-Dec-2025/04-Dec-2025 - Ranking Unknowns in Reachability Graphs.md similarity index 100% rename from docs/product-advisories/04-Dec-2025 - Ranking Unknowns in Reachability Graphs.md rename to docs/product-advisories/archived/14-Dec-2025/04-Dec-2025 - Ranking Unknowns in Reachability Graphs.md diff --git a/docs/product-advisories/04-Dec-2025- Ranking Unknowns in Reachability Graphs.md b/docs/product-advisories/archived/14-Dec-2025/04-Dec-2025- Ranking Unknowns in Reachability Graphs.md similarity index 100% rename from docs/product-advisories/04-Dec-2025- Ranking Unknowns in Reachability Graphs.md rename to docs/product-advisories/archived/14-Dec-2025/04-Dec-2025- Ranking Unknowns in Reachability Graphs.md diff --git a/docs/product-advisories/05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture.md b/docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture.md similarity index 100% rename from docs/product-advisories/05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture.md rename to docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Building a Deterministic, Reachability‑First Architecture.md diff --git a/docs/product-advisories/05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis.md b/docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis.md similarity index 100% rename from docs/product-advisories/05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis.md rename to docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Design Notes on Smart‑Diff and Call‑Stack Analysis.md diff --git a/docs/product-advisories/05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose.md b/docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose.md similarity index 100% rename from docs/product-advisories/05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose.md rename to docs/product-advisories/archived/14-Dec-2025/05-Dec-2025 - Designing Triage UX That Stays Quiet on Purpose.md diff --git a/docs/product-advisories/06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain.md b/docs/product-advisories/archived/14-Dec-2025/06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain.md similarity index 100% rename from docs/product-advisories/06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain.md rename to docs/product-advisories/archived/14-Dec-2025/06-Dec-2025 - How to Build a Verifiable SBOM→VEX Chain.md diff --git a/docs/product-advisories/06-Dec-2025 - Reachability Methods Worth Testing This Week.m b/docs/product-advisories/archived/14-Dec-2025/06-Dec-2025 - Reachability Methods Worth Testing This Week.md similarity index 100% rename from docs/product-advisories/06-Dec-2025 - Reachability Methods Worth Testing This Week.m rename to docs/product-advisories/archived/14-Dec-2025/06-Dec-2025 - Reachability Methods Worth Testing This Week.md diff --git a/docs/product-advisories/07-Dec-2025 - Designing Deterministic Vulnerability Scores.md b/docs/product-advisories/archived/14-Dec-2025/07-Dec-2025 - Designing Deterministic Vulnerability Scores.md similarity index 100% rename from docs/product-advisories/07-Dec-2025 - Designing Deterministic Vulnerability Scores.md rename to docs/product-advisories/archived/14-Dec-2025/07-Dec-2025 - Designing Deterministic Vulnerability Scores.md diff --git a/docs/product-advisories/07-Dec-2025 - Reliable Air‑Gap Verification Workflows.md b/docs/product-advisories/archived/14-Dec-2025/07-Dec-2025 - Reliable Air‑Gap Verification Workflows.md similarity index 100% rename from docs/product-advisories/07-Dec-2025 - Reliable Air‑Gap Verification Workflows.md rename to docs/product-advisories/archived/14-Dec-2025/07-Dec-2025 - Reliable Air‑Gap Verification Workflows.md diff --git a/docs/product-advisories/08-Dec-2025 - Defining Stella Ops’ Proof‑Linked Advantage.md b/docs/product-advisories/archived/14-Dec-2025/08-Dec-2025 - Defining Stella Ops’ Proof‑Linked Advantage.md similarity index 100% rename from docs/product-advisories/08-Dec-2025 - Defining Stella Ops’ Proof‑Linked Advantage.md rename to docs/product-advisories/archived/14-Dec-2025/08-Dec-2025 - Defining Stella Ops’ Proof‑Linked Advantage.md diff --git a/docs/product-advisories/08-Dec-2025 - Designing UX for Signed Evidence Trails.md b/docs/product-advisories/archived/14-Dec-2025/08-Dec-2025 - Designing UX for Signed Evidence Trails.md similarity index 100% rename from docs/product-advisories/08-Dec-2025 - Designing UX for Signed Evidence Trails.md rename to docs/product-advisories/archived/14-Dec-2025/08-Dec-2025 - Designing UX for Signed Evidence Trails.md diff --git a/docs/product-advisories/09-Dec-2025 - Caching Reachability the Smart Way.md b/docs/product-advisories/archived/14-Dec-2025/09-Dec-2025 - Caching Reachability the Smart Way.md similarity index 100% rename from docs/product-advisories/09-Dec-2025 - Caching Reachability the Smart Way.md rename to docs/product-advisories/archived/14-Dec-2025/09-Dec-2025 - Caching Reachability the Smart Way.md diff --git a/docs/product-advisories/09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries.md b/docs/product-advisories/archived/14-Dec-2025/09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries.md similarity index 100% rename from docs/product-advisories/09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries.md rename to docs/product-advisories/archived/14-Dec-2025/09-Dec-2025 - Smart‑Diff and Provenance‑Rich Binaries.md diff --git a/docs/product-advisories/11-Dec-2025 - Stella DevOps UX Implementation Guide.md b/docs/product-advisories/archived/14-Dec-2025/11-Dec-2025 - Stella DevOps UX Implementation Guide.md similarity index 100% rename from docs/product-advisories/11-Dec-2025 - Stella DevOps UX Implementation Guide.md rename to docs/product-advisories/archived/14-Dec-2025/11-Dec-2025 - Stella DevOps UX Implementation Guide.md diff --git a/docs/product-advisories/12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix.md b/docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix.md similarity index 100% rename from docs/product-advisories/12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix.md rename to docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Designing a Deterministic Vulnerability Scoring Matrix.md diff --git a/docs/product-advisories/12-Dec-2025 - Measure UX Efficiency Through TTFS.md b/docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Measure UX Efficiency Through TTFS.md similarity index 100% rename from docs/product-advisories/12-Dec-2025 - Measure UX Efficiency Through TTFS.md rename to docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Measure UX Efficiency Through TTFS.md diff --git a/docs/product-advisories/12-Dec-2025 - Replay Fidelity as a Proof Metric.md b/docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Replay Fidelity as a Proof Metric.md similarity index 100% rename from docs/product-advisories/12-Dec-2025 - Replay Fidelity as a Proof Metric.md rename to docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Replay Fidelity as a Proof Metric.md diff --git a/docs/product-advisories/12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts.md b/docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts.md similarity index 100% rename from docs/product-advisories/12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts.md rename to docs/product-advisories/archived/14-Dec-2025/12-Dec-2025 - Smart‑Diff Detects Meaningful Risk Shifts.md diff --git a/docs/product-advisories/13-Dec-2025 - Define a north star metric for TTFS.md b/docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Define a north star metric for TTFS.md similarity index 100% rename from docs/product-advisories/13-Dec-2025 - Define a north star metric for TTFS.md rename to docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Define a north star metric for TTFS.md diff --git a/docs/product-advisories/13-Dec-2025 - Designing the Call‑Stack Reachability Engine.md b/docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Designing the Call‑Stack Reachability Engine.md similarity index 100% rename from docs/product-advisories/13-Dec-2025 - Designing the Call‑Stack Reachability Engine.md rename to docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Designing the Call‑Stack Reachability Engine.md diff --git a/docs/product-advisories/13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change.md b/docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change.md similarity index 100% rename from docs/product-advisories/13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change.md rename to docs/product-advisories/archived/14-Dec-2025/13-Dec-2025 - Smart‑Diff - Defining Meaningful Risk Change.md diff --git a/docs/product-advisories/14-Dec-2025 - Add a dedicated “first_signal” event.md b/docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Add a dedicated “first_signal” event.md similarity index 100% rename from docs/product-advisories/14-Dec-2025 - Add a dedicated “first_signal” event.md rename to docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Add a dedicated “first_signal” event.md diff --git a/docs/product-advisories/14-Dec-2025 - Create a small ground‑truth corpus.md b/docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Create a small ground‑truth corpus.md similarity index 100% rename from docs/product-advisories/14-Dec-2025 - Create a small ground‑truth corpus.md rename to docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Create a small ground‑truth corpus.md diff --git a/docs/product-advisories/14-Dec-2025 - Dissect triage and evidence workflows.md b/docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Dissect triage and evidence workflows.md similarity index 100% rename from docs/product-advisories/14-Dec-2025 - Dissect triage and evidence workflows.md rename to docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Dissect triage and evidence workflows.md diff --git a/docs/product-advisories/14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps.md b/docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps.md similarity index 100% rename from docs/product-advisories/14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps.md rename to docs/product-advisories/archived/14-Dec-2025/14-Dec-2025 - Evaluate PostgreSQL vs MongoDB for StellaOps.md diff --git a/docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md b/docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md similarity index 100% rename from docs/product-advisories/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md rename to docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - Acceptance Tests Pack and Guardrails.md diff --git a/docs/product-advisories/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md b/docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md similarity index 100% rename from docs/product-advisories/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md rename to docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - CVSS v4.0 Momentum in Vulnerability Management.md diff --git a/docs/product-advisories/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md b/docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md similarity index 100% rename from docs/product-advisories/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md rename to docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - SBOM to VEX Proof Pipeline Blueprint.md diff --git a/docs/product-advisories/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md b/docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md similarity index 100% rename from docs/product-advisories/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md rename to docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - SCA Failure Catalogue for StellaOps Tests.md diff --git a/docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md b/docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md similarity index 100% rename from docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md rename to docs/product-advisories/archived/14-Dec-2025/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md diff --git a/docs/product-advisories/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Comparative Evidence Patterns for Stella Ops.md diff --git a/docs/product-advisories/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Ecosystem Reality Test Cases for StellaOps.md diff --git a/docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Implementor Guidelines for Stella Ops.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Implementor Guidelines for Stella Ops.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Implementor Guidelines for Stella Ops.md diff --git a/docs/product-advisories/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Rekor Receipt Checklist for Stella Ops.md diff --git a/docs/product-advisories/30-Nov-2025 - Standup Sprint Kickstarters.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Standup Sprint Kickstarters.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Standup Sprint Kickstarters.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Standup Sprint Kickstarters.md diff --git a/docs/product-advisories/30-Nov-2025 - UI Micro-Interactions for StellaOps.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - UI Micro-Interactions for StellaOps.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - UI Micro-Interactions for StellaOps.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - UI Micro-Interactions for StellaOps.md diff --git a/docs/product-advisories/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md b/docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md similarity index 100% rename from docs/product-advisories/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md rename to docs/product-advisories/archived/14-Dec-2025/30-Nov-2025 - Unknowns Decay & Triage Heuristics.md