release orchestrator v1 draft and build fixes
This commit is contained in:
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