196 lines
5.9 KiB
Markdown
196 lines
5.9 KiB
Markdown
# VexLens Testing Strategy
|
|
|
|
## Overview
|
|
|
|
This document describes the testing strategy for VexLens module, covering determinism verification, regression testing, and golden corpus validation.
|
|
|
|
## Test Categories
|
|
|
|
### 1. Unit Tests (`Category=Unit`)
|
|
|
|
Standard unit tests for individual components:
|
|
|
|
- **Location:** `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/`
|
|
- **Coverage:** Models, builders, serializers, individual consensus components
|
|
- **Run frequency:** Every PR, every commit
|
|
|
|
### 2. Determinism Tests (`Category=Determinism`)
|
|
|
|
Tests that verify VexLens produces identical outputs for identical inputs:
|
|
|
|
- **Location:** `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/Determinism/`
|
|
- **Key tests:**
|
|
- `VexProofShuffleDeterminismTests` - Verifies statement order doesn't affect consensus
|
|
- `VexLensPipelineDeterminismTests` - E2E pipeline structural determinism
|
|
- **Run frequency:** Nightly regression suite
|
|
- **Requirements:** Fixed `TimeProvider` injection for reproducible timestamps
|
|
|
|
#### Known Limitations
|
|
|
|
The `VexProofBuilder.GenerateProofId()` method currently uses `Guid.NewGuid()` which introduces non-determinism in the ProofId (and consequently the Digest). This is tracked as risk R-003 and violates AGENTS.md Rule 8.2 (Inject TimeProvider / ID generators). Until `IGuidGenerator` injection is added, determinism tests validate structural determinism rather than byte-identical outputs.
|
|
|
|
### 3. Regression Tests (`Category=Regression`)
|
|
|
|
Tests that validate known scenarios produce expected verdicts:
|
|
|
|
- **Location:** `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/Regression/`
|
|
- **Key tests:**
|
|
- Fixed package verdict validation
|
|
- Not_affected with justification
|
|
- Conflict resolution via lattice precedence
|
|
- Backport scenario handling
|
|
- Under_investigation status preservation
|
|
- Signature verification confidence bonus
|
|
- Same-issuer temporal precedence
|
|
- **Run frequency:** Nightly regression suite
|
|
|
|
### 4. Golden Corpus Tests (`Category=Golden`)
|
|
|
|
Tests using curated real-world backport scenarios:
|
|
|
|
- **Location:** `src/VexLens/StellaOps.VexLens/__Tests/StellaOps.VexLens.Tests/GoldenCorpus/`
|
|
- **Data location:** `src/__Tests/__Datasets/GoldenBackports/`
|
|
- **Coverage:** 20 backport cases across 8 distributions (Debian, Ubuntu, RHEL, SUSE, CentOS, Alpine, Fedora, Rocky/Alma, Amazon Linux, Oracle Linux)
|
|
- **Run frequency:** Nightly regression suite
|
|
|
|
## Test Infrastructure
|
|
|
|
### Golden Corpus Structure
|
|
|
|
```
|
|
src/__Tests/__Datasets/GoldenBackports/
|
|
├── index.json # Corpus index with case metadata
|
|
├── CVE-YYYY-XXXXX-distro-package/
|
|
│ └── case.json # Individual test case
|
|
└── ...
|
|
```
|
|
|
|
### Case Schema
|
|
|
|
```json
|
|
{
|
|
"id": "case identifier",
|
|
"cve": "CVE-YYYY-XXXXX",
|
|
"distro": {
|
|
"name": "debian|rhel|...",
|
|
"version": "7|8|...",
|
|
"family": "debian|rpm|..."
|
|
},
|
|
"package": {
|
|
"name": "package-name",
|
|
"binary": "binary-name",
|
|
"vulnerableEvr": "vulnerable EVR",
|
|
"patchedEvr": "patched EVR"
|
|
},
|
|
"upstream": {
|
|
"vulnerableRange": "SemVer constraint",
|
|
"fixedVersion": "upstream fix version"
|
|
},
|
|
"expectedVerdict": {
|
|
"status": "fixed|not_affected|affected",
|
|
"reason": "backport_detected|...",
|
|
"upstreamWouldSay": "affected|..."
|
|
},
|
|
"evidence": {
|
|
"advisoryUrl": "URL to advisory",
|
|
"patchCommit": "optional commit hash",
|
|
"notes": "explanation"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Test Runner Components
|
|
|
|
1. **GoldenCorpusLoader** - Loads and filters corpus cases
|
|
2. **GoldenCorpusTestRunner** - Executes evaluator against corpus
|
|
3. **GoldenCorpusTests** - xUnit test class for corpus validation
|
|
|
|
## CI Integration
|
|
|
|
### Nightly Regression (`.gitea/workflows/nightly-regression.yml`)
|
|
|
|
Test categories run nightly:
|
|
- Unit
|
|
- Architecture
|
|
- Contract
|
|
- Integration
|
|
- Security
|
|
- Golden
|
|
- **Determinism**
|
|
- **Regression**
|
|
|
|
### PR Gating
|
|
|
|
Quick tests run on every PR:
|
|
- Unit tests only
|
|
- Build determinism check
|
|
|
|
## Test Best Practices
|
|
|
|
### 1. Use FakeTimeProvider
|
|
|
|
Always inject `Microsoft.Extensions.Time.Testing.FakeTimeProvider` to ensure deterministic timestamps:
|
|
|
|
```csharp
|
|
private readonly FakeTimeProvider _timeProvider;
|
|
private readonly DateTimeOffset _fixedTime = new(2026, 1, 3, 12, 0, 0, TimeSpan.Zero);
|
|
|
|
public MyTests()
|
|
{
|
|
_timeProvider = new FakeTimeProvider(_fixedTime);
|
|
}
|
|
```
|
|
|
|
### 2. Set Confidence Explicitly
|
|
|
|
The `VexProofBuilder` calculates confidence from explicit weight values. For predictable test assertions, set all confidence-affecting properties:
|
|
|
|
```csharp
|
|
builder
|
|
.WithWeightSpread(0.95m)
|
|
.WithConditionCoverage(1.0m)
|
|
.WithSignatureBonus(0.10m)
|
|
.WithFreshnessBonus(0.05m);
|
|
```
|
|
|
|
### 3. Set Justification with Status
|
|
|
|
When testing `not_affected` status, pass justification to `WithFinalStatus`:
|
|
|
|
```csharp
|
|
.WithFinalStatus(VexStatus.NotAffected, VexJustification.VulnerableCodeNotPresent)
|
|
```
|
|
|
|
### 4. Use Correct Types
|
|
|
|
The `AddStatement` method requires proper types:
|
|
- `VexProofIssuer` - Not a string
|
|
- `VexProofWeight` with `VexProofWeightFactors` - Not a decimal
|
|
|
|
```csharp
|
|
builder.AddStatement(
|
|
id: "stmt-001",
|
|
source: "vendor-csaf",
|
|
issuer: new VexProofIssuer("Vendor", IssuerCategory.Vendor, TrustTier.Authoritative),
|
|
status: VexStatus.Fixed,
|
|
justification: null,
|
|
weight: new VexProofWeight(0.95m, new VexProofWeightFactors(0.95m, 1.0m, 0.9m, 1.0m, 0.8m)),
|
|
timestamp: _fixedTime,
|
|
signatureVerified: true);
|
|
```
|
|
|
|
### 5. IssuerCategory and TrustTier Values
|
|
|
|
Valid `IssuerCategory` values:
|
|
- `Unknown`, `Vendor`, `Distributor`, `Community`, `Internal`, `Aggregator`
|
|
|
|
Valid `TrustTier` values:
|
|
- `Authoritative`, `Trusted`, `Untrusted`, `Unknown`
|
|
|
|
## Future Improvements
|
|
|
|
1. **Inject IGuidGenerator** - Enable full digest determinism (R-003)
|
|
2. **Expand golden corpus** - Add more edge cases and distributions
|
|
3. **Property-based testing** - Use FsCheck for fuzzing VEX inputs
|
|
4. **Mutation testing** - Use Stryker.NET to validate test coverage quality
|