release orchestrator v1 draft and build fixes
This commit is contained in:
256
docs-archived/sprints/evid-001/EVID-001_COMPLETED.md
Normal file
256
docs-archived/sprints/evid-001/EVID-001_COMPLETED.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# EVID-001: Reachability Evidence Pipeline - COMPLETED
|
||||
|
||||
**Status**: ARCHIVED - All Sprints Complete
|
||||
**Completion Date**: January 2025
|
||||
**Total Duration**: 5 Sprints
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Successfully implemented a comprehensive reachability evidence pipeline that:
|
||||
- Performs 3-layer reachability analysis (Static, Binary, Runtime)
|
||||
- Generates VEX (Vulnerability Exploitability eXchange) statements
|
||||
- Integrates with existing Ghidra/eBPF infrastructure
|
||||
- Provides full API endpoints for evidence operations
|
||||
|
||||
---
|
||||
|
||||
## Sprint 0: Validation (COMPLETED)
|
||||
|
||||
**Objective**: Validate existing infrastructure compatibility
|
||||
|
||||
**Findings**:
|
||||
- 70-80% of proposed infrastructure already exists
|
||||
- Existing components: `ReachabilityAnalyzer`, `ReachabilityStackEvaluator`, `GhidraDecompilerAdapter`
|
||||
- eBPF infrastructure available via `IRuntimeSignalCollector`
|
||||
- DSSE signing infrastructure ready
|
||||
|
||||
---
|
||||
|
||||
## Sprint 1: CVE-Symbol Mapping & Job Executor (COMPLETED)
|
||||
|
||||
**Files Created**:
|
||||
- `Services/ICveSymbolMappingService.cs` - Interface for CVE-to-sink mappings
|
||||
- `Services/PostgresCveSymbolMappingRepository.cs` - PostgreSQL implementation
|
||||
- `Jobs/ReachabilityEvidenceJob.cs` - Job model with options
|
||||
- `Jobs/IReachabilityEvidenceJobExecutor.cs` - Executor interface
|
||||
- `Jobs/ReachabilityEvidenceJobExecutor.cs` - Full L1/L2/L3 orchestration
|
||||
|
||||
**Key Features**:
|
||||
- CVE-to-symbol mapping CRUD operations
|
||||
- Deterministic job ID generation
|
||||
- Layer 1 (static call graph) integration with existing `ReachabilityAnalyzer`
|
||||
|
||||
---
|
||||
|
||||
## Sprint 2: VEX Integration (COMPLETED)
|
||||
|
||||
**Files Created**:
|
||||
- `Vex/IVexStatusDeterminer.cs` - Interface with VEX models
|
||||
- `Vex/VexStatusDeterminer.cs` - CycloneDX/OpenVEX compliant implementation
|
||||
|
||||
**Verdict-to-VEX Mapping**:
|
||||
| ReachabilityVerdict | VexStatus |
|
||||
|---------------------|-----------|
|
||||
| Exploitable | Affected |
|
||||
| LikelyExploitable | Affected |
|
||||
| PossiblyExploitable | UnderInvestigation |
|
||||
| Unreachable | NotAffected |
|
||||
| Unknown | UnderInvestigation |
|
||||
|
||||
**Justification Categories**:
|
||||
- VulnerableCodeNotReachable (for Unreachable verdict)
|
||||
- RequiresDependency (for Exploitable)
|
||||
- RequiresConfiguration (for partial analysis)
|
||||
|
||||
---
|
||||
|
||||
## Sprint 3: Runtime Observation (COMPLETED)
|
||||
|
||||
**Files Created**:
|
||||
- `Runtime/IRuntimeReachabilityCollector.cs` - Interface with models
|
||||
- `Runtime/EbpfRuntimeReachabilityCollector.cs` - eBPF bridge implementation
|
||||
|
||||
**Key Features**:
|
||||
- Historical observation data lookup
|
||||
- Live eBPF signal collection integration
|
||||
- Symbol observation tracking
|
||||
- Layer 3 (runtime gating) evidence building
|
||||
|
||||
---
|
||||
|
||||
## Sprint 4: Binary Patch Verification (COMPLETED)
|
||||
|
||||
**Files Created**:
|
||||
- `Binary/IBinaryPatchVerifier.cs` - Interface with models
|
||||
- `Binary/BinaryPatchVerifier.cs` - Ghidra-based implementation
|
||||
|
||||
**Key Features**:
|
||||
- P-Code hash comparison for fast identity check
|
||||
- AST-based semantic comparison fallback
|
||||
- Patch status determination: Patched, Vulnerable, PartiallyPatched, Unknown
|
||||
- Layer 2 evidence building from verification results
|
||||
|
||||
---
|
||||
|
||||
## Sprint 5: Testing, Migrations & Integration (COMPLETED)
|
||||
|
||||
### Unit Tests Created
|
||||
|
||||
**Files**:
|
||||
- `Tests/Evidence/VexStatusDeterminerTests.cs` - 12 test cases
|
||||
- `Tests/Evidence/BinaryPatchVerifierTests.cs` - 10 test cases
|
||||
- `Tests/Evidence/RuntimeReachabilityCollectorTests.cs` - 8 test cases
|
||||
- `Tests/Evidence/CveSymbolMappingServiceTests.cs` - 6 test cases
|
||||
|
||||
### Database Migration
|
||||
|
||||
**File**: `022_reachability_evidence.sql`
|
||||
|
||||
**Tables Created**:
|
||||
- `cve_symbol_mappings` - CVE to vulnerable symbol mappings
|
||||
- `reachability_evidence_jobs` - Job tracking
|
||||
- `reachability_stacks` - 3-layer analysis results
|
||||
- `vex_statements` - Generated VEX statements
|
||||
- `runtime_observations` - eBPF observation data
|
||||
- `binary_patch_verifications` - Patch verification results
|
||||
- `evidence_bundles` - DSSE-signed evidence bundles
|
||||
|
||||
### Worker Integration
|
||||
|
||||
**File**: `ReachabilityEvidenceStageExecutor.cs`
|
||||
|
||||
**Features**:
|
||||
- Integrated into scan pipeline as `IScanStageExecutor`
|
||||
- Extracts CVE findings from analyzer results
|
||||
- Generates reachability evidence for eligible CVEs
|
||||
- Produces VEX statements automatically
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints
|
||||
|
||||
**File**: `ReachabilityEvidenceEndpoints.cs`
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/api/reachability/analyze` | Analyze CVE reachability |
|
||||
| GET | `/api/reachability/result/{jobId}` | Get job result |
|
||||
| GET | `/api/reachability/mapping/{cveId}` | Get CVE-to-symbol mappings |
|
||||
| POST | `/api/reachability/vex` | Generate VEX from analysis |
|
||||
|
||||
---
|
||||
|
||||
## DI Registration
|
||||
|
||||
**File**: `ServiceCollectionExtensions.cs`
|
||||
|
||||
```csharp
|
||||
services.AddReachabilityEvidence(connectionString);
|
||||
// Registers:
|
||||
// - ICveSymbolMappingService -> PostgresCveSymbolMappingRepository
|
||||
// - IReachabilityStackEvaluator -> ReachabilityStackEvaluator
|
||||
// - IVexStatusDeterminer -> VexStatusDeterminer
|
||||
// - IReachabilityEvidenceJobExecutor -> ReachabilityEvidenceJobExecutor
|
||||
// - IRuntimeReachabilityCollector -> EbpfRuntimeReachabilityCollector
|
||||
// - IBinaryPatchVerifier -> BinaryPatchVerifier
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ API Endpoints │
|
||||
│ /api/reachability/* │
|
||||
└─────────────────┬────────────────────────┘
|
||||
│
|
||||
┌─────────────────▼────────────────────────┐
|
||||
│ ReachabilityEvidenceJobExecutor │
|
||||
│ ┌──────────┬──────────┬──────────┐ │
|
||||
│ │ L1 │ L2 │ L3 │ │
|
||||
│ │ Static │ Binary │ Runtime │ │
|
||||
│ │ BFS │ Ghidra │ eBPF │ │
|
||||
│ └────┬─────┴────┬─────┴────┬─────┘ │
|
||||
└───────┼──────────┼──────────┼───────────┘
|
||||
│ │ │
|
||||
┌──────────────────▼──────────▼──────────▼───────────┐
|
||||
│ ReachabilityStackEvaluator │
|
||||
│ (Truth Table → Verdict Calculation) │
|
||||
└────────────────────────┬────────────────────────────┘
|
||||
│
|
||||
┌────────────────────────▼────────────────────────────┐
|
||||
│ VexStatusDeterminer │
|
||||
│ (Verdict → VEX Statement Generation) │
|
||||
└────────────────────────┬────────────────────────────┘
|
||||
│
|
||||
┌────────────────────────▼────────────────────────────┐
|
||||
│ Evidence Storage (PostgreSQL) │
|
||||
│ reachability_stacks | vex_statements | bundles │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Files Summary
|
||||
|
||||
### New Files Created (18 total)
|
||||
|
||||
**Core Library** (`Scanner/__Libraries/StellaOps.Scanner.Reachability/`):
|
||||
1. `Services/ICveSymbolMappingService.cs`
|
||||
2. `Services/PostgresCveSymbolMappingRepository.cs`
|
||||
3. `Jobs/ReachabilityEvidenceJob.cs`
|
||||
4. `Jobs/IReachabilityEvidenceJobExecutor.cs`
|
||||
5. `Jobs/ReachabilityEvidenceJobExecutor.cs`
|
||||
6. `Vex/IVexStatusDeterminer.cs`
|
||||
7. `Vex/VexStatusDeterminer.cs`
|
||||
8. `Runtime/IRuntimeReachabilityCollector.cs`
|
||||
9. `Runtime/EbpfRuntimeReachabilityCollector.cs`
|
||||
10. `Binary/IBinaryPatchVerifier.cs`
|
||||
11. `Binary/BinaryPatchVerifier.cs`
|
||||
12. `ServiceCollectionExtensions.cs`
|
||||
|
||||
**WebService** (`Scanner/StellaOps.Scanner.WebService/`):
|
||||
13. `Endpoints/ReachabilityEvidenceEndpoints.cs`
|
||||
|
||||
**Worker** (`Scanner/StellaOps.Scanner.Worker/`):
|
||||
14. `Processing/Reachability/ReachabilityEvidenceStageExecutor.cs`
|
||||
|
||||
**Tests** (`Scanner/__Tests/StellaOps.Scanner.Reachability.Tests/`):
|
||||
15. `Evidence/VexStatusDeterminerTests.cs`
|
||||
16. `Evidence/BinaryPatchVerifierTests.cs`
|
||||
17. `Evidence/RuntimeReachabilityCollectorTests.cs`
|
||||
18. `Evidence/CveSymbolMappingServiceTests.cs`
|
||||
|
||||
**Database**:
|
||||
19. `Storage/Postgres/Migrations/022_reachability_evidence.sql`
|
||||
|
||||
### Modified Files (4 total)
|
||||
|
||||
1. `Program.cs` - Added DI registration and stage executor
|
||||
2. `MigrationIds.cs` - Added new migration ID
|
||||
3. `StellaOps.Scanner.Reachability.Tests.csproj` - Added project references
|
||||
|
||||
---
|
||||
|
||||
## Next Steps (Future Sprints)
|
||||
|
||||
1. **Sprint 6**: DSSE attestation signing for evidence bundles
|
||||
2. **Sprint 7**: CVE-symbol mapping ingestion from NVD/OSV
|
||||
3. **Sprint 8**: Real-time runtime observation dashboard
|
||||
4. **Sprint 9**: VEX document export (CycloneDX, OpenVEX formats)
|
||||
5. **Sprint 10**: Integration tests with real binaries
|
||||
|
||||
---
|
||||
|
||||
## Metrics & Success Criteria
|
||||
|
||||
| Metric | Target | Status |
|
||||
|--------|--------|--------|
|
||||
| Unit test coverage | >80% | Achieved |
|
||||
| API endpoint availability | 4 endpoints | Achieved |
|
||||
| Database tables | 7 tables | Achieved |
|
||||
| Worker integration | Stage executor | Achieved |
|
||||
| VEX generation | CycloneDX compliant | Achieved |
|
||||
@@ -0,0 +1,487 @@
|
||||
# Evidence Pipeline Consolidation - Sprint Plan
|
||||
|
||||
**Created**: 2026-01-11
|
||||
**Status**: Planning
|
||||
**Owner**: Stella Ops Engineering
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This document consolidates the product advisory for "reachability + runtime + patch-diff" evidence into actionable sprints. **Critical finding: 70-80% of the proposed infrastructure already exists in Stella Ops.** The work is primarily about:
|
||||
|
||||
1. **Connecting** existing components
|
||||
2. **Implementing** missing adapters (runtime capture, binary diff)
|
||||
3. **Orchestrating** CVE-to-verdict flow
|
||||
4. **Enhancing** evidence-to-VEX integration
|
||||
|
||||
---
|
||||
|
||||
## Existing Infrastructure Analysis
|
||||
|
||||
### Already Implemented (No New Development Needed)
|
||||
|
||||
| Component | Location | Status |
|
||||
|-----------|----------|--------|
|
||||
| **ReachabilityAnalyzer** | `Scanner.CallGraph/Analysis/` | Complete - BFS traversal, deterministic paths |
|
||||
| **ReachabilityLattice** | `Scanner.Emit/Reachability/` | Complete - Score-based verdict merge |
|
||||
| **ReachabilityStackEvaluator** | `Scanner.Reachability/Stack/` | Complete - 3-layer evaluation |
|
||||
| **ReachabilityWitnessDsseBuilder** | `Scanner.Reachability/Attestation/` | Complete - in-toto statements |
|
||||
| **ReachabilityEvidence** | `Evidence.Bundle/` | Complete - FunctionPath, ImportChain |
|
||||
| **ReachabilityResult** | `Scanner.Reachability/Witnesses/` | Complete - PathWitness/SuppressionWitness |
|
||||
| **EvidenceBundle** | `Evidence.Bundle/` | Complete - Multi-type evidence container |
|
||||
| **EvidenceDbContext** | `Evidence.Persistence/` | Complete - Postgres persistence |
|
||||
| **RuntimeEvidence models** | `Scanner.Analyzers.Native/RuntimeCapture/` | Complete - Session, LoadEvent, Edge |
|
||||
| **DotNetCallGraphExtractor** | `Scanner.CallGraph/Extraction/DotNet/` | Complete - .NET call graphs |
|
||||
| **DotNetReachabilityLifter** | `Scanner.Reachability/Lifters/` | Complete - Lift to union model |
|
||||
| **CVE-Symbol mapping schema** | `devops/database/migrations/` | Complete - Tables and indexes |
|
||||
| **DSSE signing** | `Scanner.Worker/Processing/Surface/` | Complete - IDsseEnvelopeSigner |
|
||||
| **Multi-language analyzers** | `Scanner.Analyzers.Lang.*` | Complete - 10 languages |
|
||||
|
||||
### Needs Implementation
|
||||
|
||||
| Component | Gap | Priority |
|
||||
|-----------|-----|----------|
|
||||
| **Runtime Capture Adapters** | Models exist, no Tetragon/ETW/dtrace adapters | P0 |
|
||||
| **CVE-to-Sink Orchestrator** | Schema exists, no service to trigger analysis | P0 |
|
||||
| **VEX Verdict Emitter** | Reachability results don't flow to VEX | P0 |
|
||||
| **Binary Patch Diff** | No B2R2-based patch verification | P1 |
|
||||
| **Evidence Job Queue** | Manual triggering, no automated pipeline | P1 |
|
||||
|
||||
### Architecture Truth Table
|
||||
|
||||
```
|
||||
Verdict Decision (ReachabilityStackEvaluator):
|
||||
|
||||
| L1 (Static) | L2 (Binary) | L3 (Runtime) | Verdict |
|
||||
|-------------|-------------|--------------|---------------------|
|
||||
| Reachable | Resolved | Not Gated | Exploitable |
|
||||
| Reachable | Resolved | Unknown | LikelyExploitable |
|
||||
| Reachable | Resolved | Gated | Unreachable |
|
||||
| Reachable | Unknown | Unknown | PossiblyExploitable |
|
||||
| Reachable | Not Resolved| * | Unreachable |
|
||||
| Not Reach | * | * | Unreachable |
|
||||
| Unknown | * | * | Unknown |
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sprint Plan
|
||||
|
||||
### Phase 0: Foundation Validation (1 Sprint - 2 weeks)
|
||||
|
||||
**Goal**: Validate existing components work end-to-end with manual triggering.
|
||||
|
||||
#### Sprint S0.1: Smoke Test Existing Pipeline
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S0.1.1 | Write integration test: DotNetCallGraphExtractor -> ReachabilityAnalyzer -> ReachabilityResult | Backend | 2d |
|
||||
| S0.1.2 | Write integration test: ReachabilityStackEvaluator with mock L1/L2/L3 | Backend | 1d |
|
||||
| S0.1.3 | Write integration test: ReachabilityWitnessDsseBuilder -> signed envelope | Backend | 1d |
|
||||
| S0.1.4 | Validate CVE-symbol mapping schema with real CVE data (Log4Shell, Spring4Shell) | Backend | 1d |
|
||||
| S0.1.5 | Document gaps found during validation | Tech Lead | 1d |
|
||||
|
||||
**Exit Criteria**:
|
||||
- All integration tests pass
|
||||
- Gap analysis document produced
|
||||
- Existing components confirmed working
|
||||
|
||||
---
|
||||
|
||||
### Phase 1: CVE-to-Verdict Orchestration (2 Sprints - 4 weeks)
|
||||
|
||||
**Goal**: Enable "given CVE + image, produce reachability verdict" flow.
|
||||
|
||||
#### Sprint S1.1: CVE-Symbol Mapping Service
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S1.1.1 | Create `ICveSymbolMappingService` interface | Backend | 0.5d |
|
||||
| S1.1.2 | Implement `PostgresCveSymbolMappingRepository` using existing schema | Backend | 2d |
|
||||
| S1.1.3 | Create `CveSymbolMappingLoader` - import from OSV/NVD advisories | Backend | 3d |
|
||||
| S1.1.4 | Create `PatchAnalysisExtractor` - parse git diffs for symbols | Backend | 2d |
|
||||
| S1.1.5 | Wire to Concelier - enrich CVE data with sink mappings | Backend | 2d |
|
||||
|
||||
**Schema** (exists in `reachability.cve_symbol_mappings`):
|
||||
```sql
|
||||
-- Already implemented, no changes needed
|
||||
```
|
||||
|
||||
**Interface**:
|
||||
```csharp
|
||||
public interface ICveSymbolMappingService
|
||||
{
|
||||
Task<IReadOnlyList<VulnerableSymbol>> GetSinksForCveAsync(
|
||||
string cveId,
|
||||
string purl,
|
||||
CancellationToken ct);
|
||||
|
||||
Task<bool> HasMappingAsync(string cveId, CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
#### Sprint S1.2: Reachability Evidence Job
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S1.2.1 | Create `ReachabilityEvidenceJob` record for queue | Backend | 1d |
|
||||
| S1.2.2 | Create `ReachabilityEvidenceJobExecutor` in Scanner.Worker | Backend | 3d |
|
||||
| S1.2.3 | Wire to existing `CallGraphSnapshot` -> `ReachabilityAnalyzer` | Backend | 2d |
|
||||
| S1.2.4 | Emit `ReachabilityStack` with L1 analysis | Backend | 1d |
|
||||
| S1.2.5 | Store result in `EvidenceDbContext` | Backend | 1d |
|
||||
| S1.2.6 | Add WebService endpoint: `POST /api/reachability/analyze` | Backend | 1d |
|
||||
|
||||
**Job Flow**:
|
||||
```
|
||||
Request: { imageDigest, cveId, purl }
|
||||
-> Lookup sinks from CveSymbolMappingService
|
||||
-> Get CallGraphSnapshot from cache/compute
|
||||
-> Run ReachabilityAnalyzer with sinks
|
||||
-> Build ReachabilityStack (L1 only initially)
|
||||
-> Store EvidenceBundle
|
||||
-> Return ReachabilityResult
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: VEX Integration (2 Sprints - 4 weeks)
|
||||
|
||||
**Goal**: Reachability results automatically influence VEX status.
|
||||
|
||||
#### Sprint S2.1: Verdict-to-VEX Bridge
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S2.1.1 | Create `IVexStatusDeterminer` interface | Backend | 0.5d |
|
||||
| S2.1.2 | Implement verdict -> VEX status mapping | Backend | 2d |
|
||||
| S2.1.3 | Create `ReachabilityVexJustificationBuilder` | Backend | 2d |
|
||||
| S2.1.4 | Wire to VexHub - emit VEX with evidence references | Backend | 3d |
|
||||
| S2.1.5 | Add evidence URI to VEX justification | Backend | 1d |
|
||||
|
||||
**Mapping Logic**:
|
||||
```csharp
|
||||
public VexStatus MapVerdictToVexStatus(ReachabilityVerdict verdict) => verdict switch
|
||||
{
|
||||
ReachabilityVerdict.Exploitable => VexStatus.Affected,
|
||||
ReachabilityVerdict.LikelyExploitable => VexStatus.Affected,
|
||||
ReachabilityVerdict.PossiblyExploitable => VexStatus.UnderInvestigation,
|
||||
ReachabilityVerdict.Unreachable => VexStatus.NotAffected,
|
||||
ReachabilityVerdict.Unknown => VexStatus.UnderInvestigation,
|
||||
_ => VexStatus.UnderInvestigation
|
||||
};
|
||||
```
|
||||
|
||||
#### Sprint S2.2: Automated VEX Refresh
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S2.2.1 | Create `VexRefreshTrigger` - on new CVE or new scan | Backend | 2d |
|
||||
| S2.2.2 | Implement incremental VEX update (don't regenerate all) | Backend | 3d |
|
||||
| S2.2.3 | Add `vex_evidence_links` table for evidence->VEX tracking | Backend | 1d |
|
||||
| S2.2.4 | Create VexLens query: "show VEX decisions with evidence" | Backend | 2d |
|
||||
| S2.2.5 | Add UI endpoint for evidence drill-down | Frontend | 2d |
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Runtime Observation (2 Sprints - 4 weeks)
|
||||
|
||||
**Goal**: Implement Layer 3 (Runtime Gating) with actual runtime data.
|
||||
|
||||
#### Sprint S3.1: Runtime Capture Infrastructure
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S3.1.1 | Create `IRuntimeCaptureAdapter` interface | Backend | 1d |
|
||||
| S3.1.2 | Implement `TetragonAdapter` for Linux/Kubernetes | Backend | 5d |
|
||||
| S3.1.3 | Implement `EtwAdapter` for Windows | Backend | 3d |
|
||||
| S3.1.4 | Create `RuntimeEvidenceCollector` service | Backend | 2d |
|
||||
| S3.1.5 | Wire to existing `RuntimeEvidence` models | Backend | 1d |
|
||||
|
||||
**Interface** (leverages existing models):
|
||||
```csharp
|
||||
public interface IRuntimeCaptureAdapter
|
||||
{
|
||||
Task<RuntimeCaptureSession> StartSessionAsync(
|
||||
RuntimeCaptureOptions options,
|
||||
CancellationToken ct);
|
||||
|
||||
Task StopSessionAsync(string sessionId, CancellationToken ct);
|
||||
|
||||
IAsyncEnumerable<RuntimeLoadEvent> StreamEventsAsync(
|
||||
string sessionId,
|
||||
CancellationToken ct);
|
||||
}
|
||||
|
||||
// Uses existing: RuntimeCaptureSession, RuntimeLoadEvent, RuntimeEvidence
|
||||
// from StellaOps.Scanner.Analyzers.Native.RuntimeCapture
|
||||
```
|
||||
|
||||
#### Sprint S3.2: Runtime-to-Stack Integration
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S3.2.1 | Create `RuntimeEvidenceCorrelator` - map events to symbols | Backend | 3d |
|
||||
| S3.2.2 | Implement Layer 3 population from runtime evidence | Backend | 2d |
|
||||
| S3.2.3 | Update `ReachabilityStackEvaluator` to use real L3 data | Backend | 2d |
|
||||
| S3.2.4 | Add runtime evidence to DSSE attestation | Backend | 1d |
|
||||
| S3.2.5 | Create `RuntimeObservationEvidence` bundle type | Backend | 1d |
|
||||
|
||||
**Tetragon Policy** (example for container runtime):
|
||||
```yaml
|
||||
apiVersion: cilium.io/v1alpha1
|
||||
kind: TracingPolicy
|
||||
metadata:
|
||||
name: stella-vuln-tracing
|
||||
spec:
|
||||
kprobes:
|
||||
- call: "security_file_open"
|
||||
selectors:
|
||||
- matchActions:
|
||||
- action: Sigkill # or just observe
|
||||
args:
|
||||
- index: 0
|
||||
type: "file"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Binary Patch Verification (2 Sprints - 4 weeks)
|
||||
|
||||
**Goal**: Implement patch verification for "distro says fixed" cases.
|
||||
|
||||
#### Sprint S4.1: B2R2 Patch Diff Engine
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S4.1.1 | Create `IBinaryDiffService` interface | Backend | 1d |
|
||||
| S4.1.2 | Implement `B2R2BinaryDiffService` using existing B2R2 deps | Backend | 5d |
|
||||
| S4.1.3 | Create function similarity matching (basic) | Backend | 3d |
|
||||
| S4.1.4 | Create `PatchDiffEvidence` model | Backend | 1d |
|
||||
| S4.1.5 | Add to evidence bundle | Backend | 1d |
|
||||
|
||||
**Note**: B2R2 is already in dependencies for binary lifting. No Ghidra needed.
|
||||
|
||||
```csharp
|
||||
public interface IBinaryDiffService
|
||||
{
|
||||
Task<PatchDiffResult> DiffAsync(
|
||||
Stream vulnerableBinary,
|
||||
Stream patchedBinary,
|
||||
IReadOnlyList<string> targetSymbols,
|
||||
CancellationToken ct);
|
||||
}
|
||||
|
||||
public record PatchDiffResult(
|
||||
bool IsPatched,
|
||||
IReadOnlyList<FunctionDiff> ChangedFunctions,
|
||||
double SimilarityScore,
|
||||
string DiffSummary);
|
||||
```
|
||||
|
||||
#### Sprint S4.2: Patch Verification Pipeline
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S4.2.1 | Create `PatchVerificationJob` for queue | Backend | 1d |
|
||||
| S4.2.2 | Implement binary fetching from registry/distro | Backend | 3d |
|
||||
| S4.2.3 | Wire to Layer 2 (Binary Resolution) | Backend | 2d |
|
||||
| S4.2.4 | Add patch verification to verdict logic | Backend | 2d |
|
||||
| S4.2.5 | Create "backport detected" VEX justification | Backend | 1d |
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: DSSE Attestation & Policy Gate (1 Sprint - 2 weeks)
|
||||
|
||||
**Goal**: All evidence signed, policy gates enforce requirements.
|
||||
|
||||
#### Sprint S5.1: Attestation Pipeline
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S5.1.1 | Create `ReachabilityAttestationPublisher` | Backend | 2d |
|
||||
| S5.1.2 | Wire to Authority for real signing (replace deterministic fallback) | Backend | 2d |
|
||||
| S5.1.3 | Create `PolicyGateEvaluator` using attestations | Backend | 3d |
|
||||
| S5.1.4 | Add Rekor-compatible logging (optional) | Backend | 2d |
|
||||
| S5.1.5 | Create attestation verification endpoint | Backend | 1d |
|
||||
|
||||
**Policy Example**:
|
||||
```yaml
|
||||
# Release gate policy
|
||||
gates:
|
||||
- name: reachability-evidence
|
||||
require:
|
||||
- predicateType: "https://stella.ops/reachabilityWitness/v1"
|
||||
conditions:
|
||||
- verdict: ["Unreachable", "Unknown"] # Block Exploitable
|
||||
- signed: true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: UI & Observability (1 Sprint - 2 weeks)
|
||||
|
||||
**Goal**: Make evidence visible and actionable.
|
||||
|
||||
#### Sprint S6.1: Evidence UI
|
||||
|
||||
| Task ID | Task | Owner | Effort |
|
||||
|---------|------|-------|--------|
|
||||
| S6.1.1 | Add "Evidence" tab to finding detail view | Frontend | 3d |
|
||||
| S6.1.2 | Visualize call path (entry -> sink) | Frontend | 2d |
|
||||
| S6.1.3 | Show runtime observation timeline | Frontend | 2d |
|
||||
| S6.1.4 | Display patch diff summary | Frontend | 1d |
|
||||
| S6.1.5 | Add DSSE signature verification badge | Frontend | 1d |
|
||||
|
||||
---
|
||||
|
||||
## Database Migrations Required
|
||||
|
||||
### New Tables
|
||||
|
||||
```sql
|
||||
-- Runtime observation storage (extends existing RuntimeEvidence model)
|
||||
CREATE TABLE IF NOT EXISTS reachability.runtime_observations (
|
||||
observation_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
scan_id UUID NOT NULL,
|
||||
image_digest TEXT NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
|
||||
-- Observation data
|
||||
symbol_name TEXT,
|
||||
observed_at TIMESTAMPTZ NOT NULL,
|
||||
load_type TEXT,
|
||||
process_id INTEGER,
|
||||
|
||||
-- Correlation
|
||||
correlated_cve_id TEXT,
|
||||
correlated_finding_id UUID,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_runtime_obs_image ON reachability.runtime_observations(image_digest);
|
||||
CREATE INDEX idx_runtime_obs_symbol ON reachability.runtime_observations(symbol_name);
|
||||
|
||||
-- VEX-Evidence linkage
|
||||
CREATE TABLE IF NOT EXISTS reachability.vex_evidence_links (
|
||||
link_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
vex_document_id UUID NOT NULL,
|
||||
evidence_bundle_id UUID NOT NULL,
|
||||
evidence_type TEXT NOT NULL,
|
||||
linked_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX idx_vex_evidence_vex ON reachability.vex_evidence_links(vex_document_id);
|
||||
CREATE INDEX idx_vex_evidence_bundle ON reachability.vex_evidence_links(evidence_bundle_id);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Interfaces Summary
|
||||
|
||||
### Core Services to Implement
|
||||
|
||||
```csharp
|
||||
// CVE-to-Sink mapping
|
||||
public interface ICveSymbolMappingService
|
||||
{
|
||||
Task<IReadOnlyList<VulnerableSymbol>> GetSinksForCveAsync(string cveId, string purl, CancellationToken ct);
|
||||
}
|
||||
|
||||
// Runtime capture
|
||||
public interface IRuntimeCaptureAdapter
|
||||
{
|
||||
Task<RuntimeCaptureSession> StartSessionAsync(RuntimeCaptureOptions options, CancellationToken ct);
|
||||
IAsyncEnumerable<RuntimeLoadEvent> StreamEventsAsync(string sessionId, CancellationToken ct);
|
||||
}
|
||||
|
||||
// Binary diff
|
||||
public interface IBinaryDiffService
|
||||
{
|
||||
Task<PatchDiffResult> DiffAsync(Stream vulnerable, Stream patched, IReadOnlyList<string> symbols, CancellationToken ct);
|
||||
}
|
||||
|
||||
// VEX integration
|
||||
public interface IVexStatusDeterminer
|
||||
{
|
||||
VexStatus DetermineStatus(ReachabilityVerdict verdict);
|
||||
VexJustification BuildJustification(ReachabilityStack stack, IReadOnlyList<string> evidenceUris);
|
||||
}
|
||||
|
||||
// Evidence job
|
||||
public interface IReachabilityEvidenceJobExecutor
|
||||
{
|
||||
Task<ReachabilityStack> ExecuteAsync(ReachabilityEvidenceJob job, CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
| Risk | Mitigation | Owner |
|
||||
|------|------------|-------|
|
||||
| Tetragon requires privileged container | Provide fallback to log-based observation | Platform |
|
||||
| Binary diff performance on large binaries | Queue-based processing with timeouts | Backend |
|
||||
| CVE-symbol mapping accuracy | Confidence scores, manual curation workflow | Security |
|
||||
| Runtime observation overhead | Sampling, targeted policies | Platform |
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
| Metric | Target | Measurement |
|
||||
|--------|--------|-------------|
|
||||
| Reachability evidence coverage | 80% of high/critical CVEs | Evidence bundle count |
|
||||
| Verdict accuracy (vs manual triage) | 90% | Audit sample |
|
||||
| VEX auto-population rate | 60% of findings | VEX with evidence links |
|
||||
| Runtime observation latency | < 5s to verdict | P95 latency |
|
||||
|
||||
---
|
||||
|
||||
## Timeline Summary
|
||||
|
||||
| Phase | Sprints | Duration | Focus |
|
||||
|-------|---------|----------|-------|
|
||||
| Phase 0 | 1 | 2 weeks | Validation |
|
||||
| Phase 1 | 2 | 4 weeks | CVE-to-Verdict |
|
||||
| Phase 2 | 2 | 4 weeks | VEX Integration |
|
||||
| Phase 3 | 2 | 4 weeks | Runtime |
|
||||
| Phase 4 | 2 | 4 weeks | Binary Diff |
|
||||
| Phase 5 | 1 | 2 weeks | Attestation |
|
||||
| Phase 6 | 1 | 2 weeks | UI |
|
||||
| **Total** | **11** | **22 weeks** | |
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Existing Code References
|
||||
|
||||
### Reachability Stack (3-Layer Model)
|
||||
- `Scanner.Reachability/Stack/ReachabilityStack.cs` - Stack model
|
||||
- `Scanner.Reachability/Stack/ReachabilityStackEvaluator.cs` - Verdict logic
|
||||
- `Scanner.Reachability/Stack/ReachabilityLayer1.cs` - Static analysis layer
|
||||
- `Scanner.Reachability/Stack/ReachabilityLayer2.cs` - Binary resolution layer
|
||||
- `Scanner.Reachability/Stack/ReachabilityLayer3.cs` - Runtime gating layer
|
||||
|
||||
### Evidence Models
|
||||
- `Evidence.Bundle/ReachabilityEvidence.cs` - Reachability proof
|
||||
- `Evidence.Bundle/EvidenceBundle.cs` - Container
|
||||
- `Evidence.Bundle/CallStackEvidence.cs` - Call stack trace
|
||||
- `Evidence.Bundle/DiffEvidence.cs` - Diff proof
|
||||
|
||||
### Attestation
|
||||
- `Scanner.Reachability/Attestation/ReachabilityWitnessDsseBuilder.cs` - DSSE builder
|
||||
- `Scanner.Reachability/Attestation/ReachabilityWitnessStatement.cs` - Statement model
|
||||
- `Scanner.Reachability/Attestation/ReachabilityWitnessPublisher.cs` - Publisher
|
||||
|
||||
### Call Graph
|
||||
- `Scanner.CallGraph/Analysis/ReachabilityAnalyzer.cs` - BFS analysis
|
||||
- `Scanner.CallGraph/Extraction/DotNet/DotNetCallGraphExtractor.cs` - .NET extraction
|
||||
|
||||
### Runtime (Models Only)
|
||||
- `Scanner.Analyzers.Native/RuntimeCapture/RuntimeEvidence.cs` - Models
|
||||
- `Scanner.Analyzers.Native/RuntimeCapture/RuntimeCaptureOptions.cs` - Options
|
||||
|
||||
### Lattice
|
||||
- `Scanner.Emit/Reachability/ReachabilityLattice.cs` - Score-based merge
|
||||
37
docs-archived/sprints/evid-001/README.md
Normal file
37
docs-archived/sprints/evid-001/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# EVID-001: Reachability Evidence Pipeline - ARCHIVED
|
||||
|
||||
**Sprint Status**: COMPLETED
|
||||
**Archive Date**: January 2026
|
||||
**Duration**: 5 Sprints (Sprint 0-5)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This sprint implemented a comprehensive reachability evidence pipeline for vulnerability analysis:
|
||||
- 3-layer reachability model (Static, Binary, Runtime)
|
||||
- VEX (Vulnerability Exploitability eXchange) statement generation
|
||||
- Ghidra/eBPF infrastructure integration
|
||||
- Full API endpoints and worker integration
|
||||
|
||||
## Archived Files
|
||||
|
||||
| File | Description |
|
||||
|------|-------------|
|
||||
| `EVID-001_COMPLETED.md` | Sprint completion archive with all implementation details |
|
||||
| `EVIDENCE_PIPELINE_CONSOLIDATION.md` | Initial planning document and sprint roadmap |
|
||||
| `TASKS_DETAILED.md` | JIRA-compatible task breakdown with acceptance criteria |
|
||||
|
||||
## Active Reference
|
||||
|
||||
The architecture documentation remains active at:
|
||||
- `docs/architecture/EVIDENCE_PIPELINE_ARCHITECTURE.md` - Component integration guide
|
||||
|
||||
## Implementation Location
|
||||
|
||||
Code implemented during this sprint:
|
||||
- `Scanner/__Libraries/StellaOps.Scanner.Reachability/` - Core library
|
||||
- `Scanner/StellaOps.Scanner.Worker/Processing/Reachability/` - Worker integration
|
||||
- `Scanner/StellaOps.Scanner.WebService/Endpoints/` - API endpoints
|
||||
- `Scanner/__Tests/StellaOps.Scanner.Reachability.Tests/` - Unit tests
|
||||
- `Storage/Postgres/Migrations/022_reachability_evidence.sql` - Database schema
|
||||
876
docs-archived/sprints/evid-001/TASKS_DETAILED.md
Normal file
876
docs-archived/sprints/evid-001/TASKS_DETAILED.md
Normal file
@@ -0,0 +1,876 @@
|
||||
# Evidence Pipeline - Detailed Task Breakdown
|
||||
|
||||
**Format**: JIRA-compatible task definitions with acceptance criteria.
|
||||
|
||||
---
|
||||
|
||||
## Epic: EVID-001 - Evidence Pipeline Consolidation
|
||||
|
||||
### User Story: EVID-001-001 - CVE-to-Sink Mapping Service
|
||||
|
||||
**As a** scanner
|
||||
**I want to** look up vulnerable symbols (sinks) for a given CVE
|
||||
**So that** I can run targeted reachability analysis
|
||||
|
||||
#### Tasks
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-001-001**: Create ICveSymbolMappingService interface
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 0.5 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Define the interface for CVE-to-symbol mapping lookup.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a CVE ID and PURL
|
||||
When I call GetSinksForCveAsync
|
||||
Then I receive a list of VulnerableSymbol records
|
||||
And each symbol has name, canonical_id, file_path, and confidence
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
// Location: Scanner/__Libraries/StellaOps.Scanner.Reachability/Services/ICveSymbolMappingService.cs
|
||||
public interface ICveSymbolMappingService
|
||||
{
|
||||
Task<IReadOnlyList<VulnerableSymbol>> GetSinksForCveAsync(
|
||||
string cveId,
|
||||
string purl,
|
||||
CancellationToken ct);
|
||||
|
||||
Task<bool> HasMappingAsync(string cveId, CancellationToken ct);
|
||||
|
||||
Task<int> GetMappingCountAsync(CancellationToken ct);
|
||||
}
|
||||
|
||||
public record VulnerableSymbol(
|
||||
string SymbolName,
|
||||
string? CanonicalId,
|
||||
string? FilePath,
|
||||
int? StartLine,
|
||||
VulnerabilityType VulnType,
|
||||
decimal Confidence);
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-001-002**: Implement PostgresCveSymbolMappingRepository
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Implement the repository using existing `reachability.cve_symbol_mappings` schema.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given CVE-2021-44228 exists in the database
|
||||
When I query for sinks with purl "pkg:maven/org.apache.logging.log4j/log4j-core"
|
||||
Then I receive JndiLookup.lookup and JndiManager.lookup symbols
|
||||
And confidence scores are included
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
// Uses existing schema from V20260110__reachability_cve_mapping_schema.sql
|
||||
// EF Core entity mapping to reachability.cve_symbol_mappings table
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-001-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-001-003**: Create CveSymbolMappingLoader
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Concelier
|
||||
- **Effort**: 3 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Import CVE-to-symbol mappings from OSV, NVD, and patch analysis.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given an OSV advisory with affected symbols
|
||||
When the loader processes the advisory
|
||||
Then symbols are inserted into cve_symbol_mappings
|
||||
And source is set to 'osv_advisory'
|
||||
|
||||
Given a git patch URL
|
||||
When the loader analyzes the diff
|
||||
Then changed functions are extracted
|
||||
And inserted with source 'patch_analysis'
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
- Parse OSV `affected[].ranges[].events` for version info
|
||||
- Parse `affected[].ecosystem_specific.vulnerable_functions` for symbols
|
||||
- For patch analysis, use existing diff parsing from Concelier.Analyzers
|
||||
|
||||
**Dependencies**: EVID-001-001-002
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-001-004**: Create PatchAnalysisExtractor
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Parse git diffs to extract changed function symbols.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a git diff URL for a security patch
|
||||
When I run the extractor
|
||||
Then I receive a list of changed function names
|
||||
And file paths and line numbers are included
|
||||
And language is detected
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public interface IPatchAnalysisExtractor
|
||||
{
|
||||
Task<PatchAnalysisResult> ExtractAsync(string commitUrl, CancellationToken ct);
|
||||
}
|
||||
|
||||
public record PatchAnalysisResult(
|
||||
string CommitUrl,
|
||||
string? Language,
|
||||
IReadOnlyList<ExtractedSymbol> Symbols,
|
||||
string? Error);
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-001-005**: Wire to Concelier CVE enrichment
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Concelier
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Enrich CVE data with sink mappings during ingestion.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a new CVE is ingested from NVD
|
||||
When Concelier processes it
|
||||
Then it checks for OSV symbol data
|
||||
And creates cve_symbol_mappings entries if found
|
||||
And marks CVE as "has_reachability_data" = true
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-001-003
|
||||
|
||||
---
|
||||
|
||||
### User Story: EVID-001-002 - Reachability Evidence Job
|
||||
|
||||
**As a** scanner
|
||||
**I want to** queue reachability analysis for a specific CVE+image
|
||||
**So that** I get an evidence-backed verdict
|
||||
|
||||
#### Tasks
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-001**: Create ReachabilityEvidenceJob model
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Queue
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Define the job model for queued reachability analysis.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a reachability job request
|
||||
When serialized and deserialized
|
||||
Then all fields are preserved
|
||||
And job ID is deterministic from inputs hash
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public record ReachabilityEvidenceJob(
|
||||
string JobId,
|
||||
string ImageDigest,
|
||||
string CveId,
|
||||
string Purl,
|
||||
string? SourceCommit,
|
||||
ReachabilityJobOptions Options,
|
||||
DateTimeOffset QueuedAt);
|
||||
|
||||
public record ReachabilityJobOptions(
|
||||
bool IncludeL2 = false, // Binary resolution
|
||||
bool IncludeL3 = false, // Runtime (if available)
|
||||
int MaxPaths = 5,
|
||||
int MaxDepth = 256);
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-002**: Create ReachabilityEvidenceJobExecutor
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Worker
|
||||
- **Effort**: 3 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Implement the job executor that orchestrates L1 analysis.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a queued reachability job
|
||||
When the executor processes it
|
||||
Then it retrieves or computes CallGraphSnapshot
|
||||
And runs ReachabilityAnalyzer with CVE sinks
|
||||
And produces ReachabilityStack with L1 populated
|
||||
And stores EvidenceBundle in database
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public sealed class ReachabilityEvidenceJobExecutor : IJobExecutor<ReachabilityEvidenceJob>
|
||||
{
|
||||
// Inject: ICveSymbolMappingService, ICallGraphCache, ReachabilityAnalyzer,
|
||||
// ReachabilityStackEvaluator, IEvidenceStore
|
||||
|
||||
public async Task<ReachabilityStack> ExecuteAsync(
|
||||
ReachabilityEvidenceJob job,
|
||||
CancellationToken ct)
|
||||
{
|
||||
// 1. Get sinks from CVE mapping service
|
||||
var sinks = await _cveSymbolService.GetSinksForCveAsync(job.CveId, job.Purl, ct);
|
||||
|
||||
// 2. Get or compute call graph
|
||||
var graph = await _callGraphCache.GetOrComputeAsync(job.ImageDigest, ct);
|
||||
|
||||
// 3. Run reachability analysis
|
||||
var analysisResult = _analyzer.Analyze(graph, new ReachabilityAnalysisOptions
|
||||
{
|
||||
ExplicitSinks = sinks.Select(s => s.CanonicalId ?? s.SymbolName).ToImmutableArray(),
|
||||
MaxTotalPaths = job.Options.MaxPaths,
|
||||
MaxDepth = job.Options.MaxDepth
|
||||
});
|
||||
|
||||
// 4. Build Layer 1
|
||||
var layer1 = BuildLayer1(analysisResult);
|
||||
|
||||
// 5. Evaluate stack (L2, L3 as Unknown initially)
|
||||
var stack = _stackEvaluator.Evaluate(
|
||||
findingId: $"{job.CveId}:{job.Purl}",
|
||||
symbol: sinks.FirstOrDefault() ?? VulnerableSymbol.Unknown,
|
||||
layer1: layer1,
|
||||
layer2: ReachabilityLayer2.Unknown(),
|
||||
layer3: ReachabilityLayer3.Unknown());
|
||||
|
||||
// 6. Store evidence
|
||||
await _evidenceStore.StoreAsync(stack.ToEvidenceBundle(), ct);
|
||||
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-001-001, EVID-001-002-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-003**: Wire CallGraphSnapshot retrieval
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Worker
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Integrate with existing call graph cache/computation.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given an image digest with existing call graph
|
||||
When the job requests it
|
||||
Then the cached graph is returned
|
||||
|
||||
Given an image digest without cached call graph
|
||||
When the job requests it
|
||||
Then the graph is computed
|
||||
And cached for future requests
|
||||
```
|
||||
|
||||
**Dependencies**: None (uses existing CallGraph infrastructure)
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-004**: Emit ReachabilityStack with L1 analysis
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Convert ReachabilityAnalysisResult to ReachabilityLayer1.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a ReachabilityAnalysisResult with paths
|
||||
When converted to Layer1
|
||||
Then IsReachable is true
|
||||
And Paths contains the converted paths
|
||||
And ReachingEntrypoints lists unique entrypoints
|
||||
And Confidence is High
|
||||
|
||||
Given a ReachabilityAnalysisResult with no paths
|
||||
When converted to Layer1
|
||||
Then IsReachable is false
|
||||
And Confidence is Medium
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-002-002
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-005**: Store result in EvidenceDbContext
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Evidence.Persistence
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Persist the ReachabilityStack as an EvidenceBundle.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a ReachabilityStack
|
||||
When stored
|
||||
Then an EvidenceBundle is created
|
||||
And ReachabilityEvidence is included
|
||||
And the bundle ID is returned
|
||||
And it can be retrieved by ID
|
||||
```
|
||||
|
||||
**Dependencies**: None (uses existing EvidenceDbContext)
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-002-006**: Add WebService endpoint
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.WebService
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Expose reachability analysis via REST API.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a POST to /api/reachability/analyze
|
||||
With body { imageDigest, cveId, purl }
|
||||
When the request is processed
|
||||
Then a job is queued
|
||||
And the job ID is returned
|
||||
|
||||
Given a GET to /api/reachability/result/{jobId}
|
||||
When the job is complete
|
||||
Then the ReachabilityStack is returned
|
||||
And evidence bundle URI is included
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
// Location: Scanner.WebService/Endpoints/ReachabilityEvidenceEndpoints.cs
|
||||
public static class ReachabilityEvidenceEndpoints
|
||||
{
|
||||
public static void MapReachabilityEvidenceEndpoints(this IEndpointRouteBuilder routes)
|
||||
{
|
||||
routes.MapPost("/api/reachability/analyze", AnalyzeAsync);
|
||||
routes.MapGet("/api/reachability/result/{jobId}", GetResultAsync);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-002-002
|
||||
|
||||
---
|
||||
|
||||
### User Story: EVID-001-003 - VEX Integration
|
||||
|
||||
**As a** security team
|
||||
**I want** reachability verdicts to automatically update VEX status
|
||||
**So that** I don't manually triage unreachable vulnerabilities
|
||||
|
||||
#### Tasks
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-003-001**: Create IVexStatusDeterminer interface
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: VexHub
|
||||
- **Effort**: 0.5 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Define interface for verdict-to-VEX mapping.
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public interface IVexStatusDeterminer
|
||||
{
|
||||
VexStatus DetermineStatus(ReachabilityVerdict verdict);
|
||||
VexJustification BuildJustification(
|
||||
ReachabilityStack stack,
|
||||
IReadOnlyList<string> evidenceUris);
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-003-002**: Implement verdict to VEX status mapping
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: VexHub
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Map ReachabilityVerdict to CycloneDX VEX status.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given verdict Exploitable
|
||||
When mapped to VEX
|
||||
Then status is "affected"
|
||||
And impact_statement includes path summary
|
||||
|
||||
Given verdict Unreachable
|
||||
When mapped to VEX
|
||||
Then status is "not_affected"
|
||||
And justification includes "code_not_reachable"
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public VexStatus DetermineStatus(ReachabilityVerdict verdict) => verdict switch
|
||||
{
|
||||
ReachabilityVerdict.Exploitable => VexStatus.Affected,
|
||||
ReachabilityVerdict.LikelyExploitable => VexStatus.Affected,
|
||||
ReachabilityVerdict.PossiblyExploitable => VexStatus.UnderInvestigation,
|
||||
ReachabilityVerdict.Unreachable => VexStatus.NotAffected,
|
||||
ReachabilityVerdict.Unknown => VexStatus.UnderInvestigation,
|
||||
_ => VexStatus.UnderInvestigation
|
||||
};
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-003-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-003-003**: Create ReachabilityVexJustificationBuilder
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: VexHub
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Build VEX justification from reachability evidence.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a ReachabilityStack with Unreachable verdict
|
||||
When justification is built
|
||||
Then detail includes "No call path from entrypoints to vulnerable symbol"
|
||||
And layer summaries are included
|
||||
And evidence URIs are referenced
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-003-002
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-003-004**: Wire to VexHub emission
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: VexHub
|
||||
- **Effort**: 3 days
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Automatically emit VEX documents when reachability evidence is produced.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a new ReachabilityStack is stored
|
||||
When the VEX bridge processes it
|
||||
Then a VEX statement is created for the CVE+component
|
||||
And it references the evidence bundle
|
||||
And it's stored in VexHub
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-003-003
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-003-005**: Add evidence URI to VEX justification
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: VexHub
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Include evidence bundle URI in VEX document.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a VEX document with reachability evidence
|
||||
When serialized to CycloneDX
|
||||
Then analysis.detail includes evidence URI
|
||||
And URI follows stella:// scheme
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-003-004
|
||||
|
||||
---
|
||||
|
||||
### User Story: EVID-001-004 - Runtime Observation
|
||||
|
||||
**As a** security team
|
||||
**I want** runtime execution data to refine reachability verdicts
|
||||
**So that** I know if vulnerable code is actually running
|
||||
|
||||
#### Tasks
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-004-001**: Create IRuntimeCaptureAdapter interface
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Analyzers.Native
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P0
|
||||
|
||||
**Description**:
|
||||
Define the interface for runtime capture backends.
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
// Location: Scanner.Analyzers.Native/RuntimeCapture/IRuntimeCaptureAdapter.cs
|
||||
public interface IRuntimeCaptureAdapter
|
||||
{
|
||||
string Platform { get; } // "linux", "windows", "macos"
|
||||
string Method { get; } // "ebpf", "etw", "dyld-interpose"
|
||||
|
||||
Task<RuntimeCaptureSession> StartSessionAsync(
|
||||
RuntimeCaptureOptions options,
|
||||
CancellationToken ct);
|
||||
|
||||
Task StopSessionAsync(string sessionId, CancellationToken ct);
|
||||
|
||||
IAsyncEnumerable<RuntimeLoadEvent> StreamEventsAsync(
|
||||
string sessionId,
|
||||
CancellationToken ct);
|
||||
|
||||
Task<RuntimeEvidence> GetEvidenceAsync(
|
||||
string sessionId,
|
||||
CancellationToken ct);
|
||||
}
|
||||
```
|
||||
|
||||
**Dependencies**: None (uses existing RuntimeEvidence models)
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-004-002**: Implement TetragonAdapter
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Analyzers.Native
|
||||
- **Effort**: 5 days
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Implement runtime capture using Cilium Tetragon.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given Tetragon is running in the cluster
|
||||
When a capture session is started
|
||||
Then tracing policies are applied
|
||||
And library load events are captured
|
||||
And events are correlated to container digest
|
||||
|
||||
Given a session is stopped
|
||||
When evidence is requested
|
||||
Then all captured events are returned
|
||||
And unique libraries are summarized
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
- Use Tetragon gRPC API for event streaming
|
||||
- Apply TracingPolicy for library loads
|
||||
- Correlate events via cgroup/container ID
|
||||
|
||||
**Dependencies**: EVID-001-004-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-004-003**: Implement EtwAdapter (Windows)
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Analyzers.Native
|
||||
- **Effort**: 3 days
|
||||
- **Priority**: P2
|
||||
|
||||
**Description**:
|
||||
Implement runtime capture using Windows ETW.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given ETW providers are available
|
||||
When a capture session is started
|
||||
Then DLL load events are captured
|
||||
And events include process and timestamp
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-004-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-004-004**: Create RuntimeEvidenceCollector service
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Worker
|
||||
- **Effort**: 2 days
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Orchestrate runtime evidence collection for a target.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a container image running in the cluster
|
||||
When the collector is invoked
|
||||
Then it selects the appropriate adapter
|
||||
And starts a session for the configured duration
|
||||
And stores the runtime evidence
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-004-002
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-004-005**: Wire to existing RuntimeEvidence models
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Analyzers.Native
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Ensure adapters produce existing RuntimeEvidence types.
|
||||
|
||||
**Dependencies**: EVID-001-004-004
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### User Story: EVID-001-005 - Binary Patch Verification
|
||||
|
||||
**As a** security team
|
||||
**I want** to verify if a binary is actually patched
|
||||
**So that** I trust distro backport claims
|
||||
|
||||
#### Tasks
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-005-001**: Create IBinaryDiffService interface
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Define interface for binary comparison.
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
public interface IBinaryDiffService
|
||||
{
|
||||
Task<PatchDiffResult> DiffAsync(
|
||||
Stream vulnerableBinary,
|
||||
Stream patchedBinary,
|
||||
IReadOnlyList<string> targetSymbols,
|
||||
CancellationToken ct);
|
||||
}
|
||||
|
||||
public record PatchDiffResult(
|
||||
bool IsPatched,
|
||||
IReadOnlyList<FunctionDiff> ChangedFunctions,
|
||||
double SimilarityScore,
|
||||
string DiffSummary,
|
||||
byte[]? DiffArtifact);
|
||||
|
||||
public record FunctionDiff(
|
||||
string FunctionName,
|
||||
ulong OriginalAddress,
|
||||
ulong PatchedAddress,
|
||||
int InstructionChanges,
|
||||
double Similarity);
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-005-002**: Implement B2R2BinaryDiffService
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 5 days
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Implement binary diff using B2R2 (already in dependencies).
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given two versions of a binary (vulnerable and patched)
|
||||
When diffed for a target symbol
|
||||
Then changed basic blocks are identified
|
||||
And similarity score is computed
|
||||
And IsPatched is true if significant changes detected
|
||||
```
|
||||
|
||||
**Technical Notes**:
|
||||
- Use B2R2.FrontEnd for disassembly
|
||||
- Use B2R2.MiddleEnd for IR comparison
|
||||
- Compare function CFGs for similarity
|
||||
|
||||
**Dependencies**: EVID-001-005-001
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-005-003**: Create function similarity matching
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Scanner.Reachability
|
||||
- **Effort**: 3 days
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Match functions between binaries even with different addresses.
|
||||
|
||||
**Acceptance Criteria**:
|
||||
```gherkin
|
||||
Given a function name from CVE mapping
|
||||
When searching in patched binary
|
||||
Then the function is located by name
|
||||
Or by signature similarity if renamed
|
||||
And match confidence is returned
|
||||
```
|
||||
|
||||
**Dependencies**: EVID-001-005-002
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-005-004**: Create PatchDiffEvidence model
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Evidence.Bundle
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Add patch diff evidence to the bundle types.
|
||||
|
||||
**Technical Notes**:
|
||||
```csharp
|
||||
// Location: Evidence.Bundle/PatchDiffEvidence.cs
|
||||
public sealed class PatchDiffEvidence
|
||||
{
|
||||
public required EvidenceStatus Status { get; init; }
|
||||
public string? Hash { get; init; }
|
||||
public bool IsPatched { get; init; }
|
||||
public double SimilarityScore { get; init; }
|
||||
public IReadOnlyList<ChangedFunctionSummary>? ChangedFunctions { get; init; }
|
||||
public string? DiffSummary { get; init; }
|
||||
public string? ArtifactUri { get; init; }
|
||||
}
|
||||
|
||||
public record ChangedFunctionSummary(
|
||||
string FunctionName,
|
||||
int InstructionChanges,
|
||||
double Similarity);
|
||||
```
|
||||
|
||||
**Dependencies**: None
|
||||
|
||||
---
|
||||
|
||||
**EVID-001-005-005**: Add to evidence bundle
|
||||
|
||||
- **Type**: Task
|
||||
- **Component**: Evidence.Bundle
|
||||
- **Effort**: 1 day
|
||||
- **Priority**: P1
|
||||
|
||||
**Description**:
|
||||
Include PatchDiffEvidence in EvidenceBundle.
|
||||
|
||||
**Dependencies**: EVID-001-005-004
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Summary Statistics
|
||||
|
||||
| Category | Count |
|
||||
|----------|-------|
|
||||
| Epics | 1 |
|
||||
| User Stories | 5 |
|
||||
| Tasks | 25 |
|
||||
| Total Effort | ~50 days |
|
||||
|
||||
## Sprint Assignment Suggestion
|
||||
|
||||
| Sprint | Stories | Effort |
|
||||
|--------|---------|--------|
|
||||
| S1 | EVID-001-001 (CVE Mapping) | 10 days |
|
||||
| S2 | EVID-001-002 (Evidence Job) | 9 days |
|
||||
| S3 | EVID-001-003 (VEX Integration) | 8.5 days |
|
||||
| S4 | EVID-001-004 (Runtime - part 1) | 9 days |
|
||||
| S5 | EVID-001-004 (Runtime - part 2) + EVID-001-005 (Binary Diff) | 13 days |
|
||||
Reference in New Issue
Block a user