house keeping work

This commit is contained in:
StellaOps Bot
2025-12-19 22:19:08 +02:00
parent 91f3610b9d
commit 5b57b04484
64 changed files with 4702 additions and 4 deletions

View File

@@ -97,3 +97,168 @@
| 2025-12-12 | Schema freeze sync | Confirm ATLN/provenance freeze; unblock tasks 2-7. | Excititor Core |
| 2025-12-12 | Orchestrator SDK alignment | Pick SDK version and start task 8. | Excititor Worker |
| 2025-12-13 | Sprint handoff | Move blocked tasks 6-10 to next sprint once schema freeze and SDK decisions land. | Project Mgmt |
---
## Unblocking Plan: Orchestrator SDK Integration
### Blocker Analysis
**Root Cause:** Task 8 (EXCITITOR-ORCH-32/33) is blocked on selecting and confirming the orchestrator SDK version for Excititor worker adoption.
**Blocked Tasks (1 total):**
- EXCITITOR-ORCH-32/33: Adopt orchestrator worker SDK; honor pause/throttle/retry with deterministic checkpoints
**What's Already Done:**
- ✅ Storage backend decision: Postgres append-only store selected
- ✅ Schema freeze: Overlay contract v1.0.0 frozen
- ✅ Tasks 1-6 and 9-10 completed
- ✅ Evidence/attestation endpoints re-enabled
### Context
The Excititor worker needs to adopt the platform's orchestrator SDK to support:
- **Pause/Resume:** Graceful handling of worker pause signals
- **Throttle:** Rate limiting based on system load
- **Retry:** Automatic retry with exponential backoff
- **Checkpointing:** Deterministic progress tracking on Postgres store
### SDK Options
#### Option A: StellaOps.Scheduler.Worker SDK
**Status:** Exists in codebase
**Location:** `src/Scheduler/__Libraries/StellaOps.Scheduler.Worker/`
**Features:**
- Job scheduling with cron expressions
- State machine for job lifecycle
- PostgreSQL-backed checkpoints
- Retry policies
**Integration:**
```csharp
// Register in Excititor.Worker DI
services.AddSchedulerWorker(options =>
{
options.WorkerId = "excititor-worker";
options.CheckpointStore = "postgres";
});
// Implement IScheduledJob
public class VexIngestionJob : IScheduledJob
{
public string CronExpression => "*/5 * * * *"; // Every 5 minutes
public async Task ExecuteAsync(CancellationToken cancellationToken)
{
// Ingest VEX documents
}
}
```
#### Option B: Generic Orchestrator SDK (New)
**Status:** Proposed
**Location:** Would be `src/__Libraries/StellaOps.Orchestrator.Sdk/`
**Features:**
- Event-driven worker pattern
- Distributed checkpointing
- Pause/throttle/retry primitives
- Tenant-aware work distribution
**Considerations:**
- Requires new SDK development
- More flexible than Scheduler.Worker
- Higher initial investment
#### Option C: Minimal Custom Implementation
**Status:** Can implement directly
**Location:** `src/Excititor/StellaOps.Excititor.Worker/`
**Features:**
- Simple polling loop with checkpoint
- Manual retry logic
- Direct Postgres checkpoint storage
**Trade-offs:**
- Fastest to implement
- Less reusable
- May duplicate patterns from other workers
### Unblocking Recommendation
**Recommended: Option A (StellaOps.Scheduler.Worker SDK)**
**Rationale:**
1. SDK already exists in codebase
2. PostgreSQL checkpointing is proven
3. Consistent with other module workers
4. Retry/backoff policies are implemented
5. Lower risk than new SDK development
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-0120-001 | Review Scheduler.Worker SDK compatibility with Excititor | Excititor Worker Guild | 0.5 day |
| UNBLOCK-0120-002 | Document SDK adoption decision in ADR | Architecture Guild | After review |
| UNBLOCK-0120-003 | Add Scheduler.Worker reference to Excititor.Worker | Excititor Worker Guild | After ADR |
| UNBLOCK-0120-004 | Implement IScheduledJob for VEX ingestion | Excititor Worker Guild | 1-2 days |
| UNBLOCK-0120-005 | Configure Postgres checkpointing | Excititor Worker Guild | 0.5 day |
| UNBLOCK-0120-006 | Add pause/throttle signal handlers | Excititor Worker Guild | 1 day |
| UNBLOCK-0120-007 | Integration testing with checkpoint recovery | QA Guild | 1 day |
### Implementation Sketch
```csharp
// File: src/Excititor/StellaOps.Excititor.Worker/Jobs/VexIngestionJob.cs
public class VexIngestionJob : IScheduledJob
{
private readonly IVexConnectorRegistry _connectorRegistry;
private readonly IAppendOnlyLinksetStore _linksetStore;
private readonly ICheckpointStore _checkpointStore;
private readonly ILogger<VexIngestionJob> _logger;
public string CronExpression => "*/5 * * * *";
public async Task ExecuteAsync(CancellationToken ct)
{
foreach (var connector in _connectorRegistry.GetActiveConnectors())
{
var checkpoint = await _checkpointStore.GetAsync($"vex-ingest:{connector.Id}", ct);
try
{
var documents = await connector.FetchSinceAsync(checkpoint?.LastProcessed, ct);
foreach (var doc in documents)
{
await _linksetStore.AppendAsync(doc.ToLinkset(), ct);
}
await _checkpointStore.SetAsync($"vex-ingest:{connector.Id}",
new Checkpoint { LastProcessed = DateTimeOffset.UtcNow }, ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to ingest from connector {ConnectorId}", connector.Id);
// Retry handled by Scheduler.Worker
throw;
}
}
}
}
```
### Decision Required
**Action:** Excititor Worker Guild to confirm SDK choice and begin implementation.
**Options:**
- [ ] A: Adopt Scheduler.Worker SDK (Recommended)
- [ ] B: Develop new Orchestrator SDK
- [ ] C: Custom minimal implementation
**Contact:** @excititor-worker-guild, @scheduler-guild
**Deadline:** End of current sprint or defer to SPRINT_0120_0001_0003

View File

@@ -89,11 +89,12 @@
| 35 | PG-T7.5.2 | DONE | postgres-init scripts added | DevOps Guild | Update kit scripts for PostgreSQL setup |
| 36 | PG-T7.5.3 | DONE | 01-extensions.sql creates schemas | DevOps Guild | Include schema migrations in kit |
| 37 | PG-T7.5.4 | DONE | docs/24_OFFLINE_KIT.md updated | DevOps Guild | Update kit documentation |
| 38 | PG-T7.5.5 | TODO | Awaiting air-gap environment test | DevOps Guild | Test kit installation in air-gapped environment |
| 38 | PG-T7.5.5 | BLOCKED | Awaiting physical air-gap test environment | DevOps Guild | Test kit installation in air-gapped environment |
## Execution Log
| Date (UTC) | Update | Owner |
| --- | --- | --- |
| 2025-12-19 | Sprint status review: 37/38 tasks DONE (97%). Only PG-T7.5.5 (air-gap environment test) remains TODO - marked BLOCKED awaiting physical air-gap test environment. Sprint not archived; will close once validation occurs. | StellaOps Agent |
| 2025-12-10 | Completed Waves C, D, E: created comprehensive `docs/operations/postgresql-guide.md` (performance, monitoring, backup/restore, scaling), updated HIGH_LEVEL_ARCHITECTURE.md to PostgreSQL-primary, updated CLAUDE.md technology stack, added PostgreSQL 17 with pg_stat_statements to docker-compose.airgap.yaml, created postgres-init scripts for both local-postgres and airgap compose, updated offline kit docs. Only PG-T7.5.5 (air-gap environment test) remains TODO. Wave B dropped (no data to migrate - ground zero). | Infrastructure Guild |
| 2025-12-07 | Unblocked PG-T7.1.2T7.1.6 with plan at `docs/db/reports/mongo-removal-plan-20251207.md`; statuses set to TODO. | Project Mgmt |
| 2025-12-03 | Added Wave Coordination (A code removal, B archive, C performance, D docs, E air-gap kit; sequential). No status changes. | StellaOps Agent |

View File

@@ -665,3 +665,102 @@ WHERE schemaname = 'scheduler'
| 4 | BRIN vs B-tree for time column | DECIDED | Use BRIN (smaller, faster for range scans) |
| 5 | Monthly vs. quarterly partitions | DECIDED | Monthly for runs/logs, quarterly for low-volume tables |
| 6 | Category C migrations blocked | BLOCKED | Data migrations require production maintenance window coordination with ops team |
---
## Unblocking Plan: Category C Migrations
### Blocker Analysis
**Root Cause:** Data migrations for 4 tables (scheduler.audit, vuln.merge_events, vex.timeline_events, notify.deliveries) require production downtime to safely migrate data to partitioned tables and swap table names.
**Blocked Tasks (14 total):**
- Phase 2 (scheduler.audit): 2.3, 2.4, 2.5, 2.8, 2.9
- Phase 3 (vuln.merge_events): 3.3, 3.4, 3.5, 3.7
- Phase 4 (vex.timeline_events): 4.2, 4.3, 4.4
- Phase 5 (notify.deliveries): 5.2, 5.3, 5.4
**What's Already Done:**
- ✅ Phase 1: Infrastructure (partition management functions)
- ✅ Phase 6: Automation & Monitoring (maintenance job, health monitor)
- ✅ Partitioned tables created for all 4 schemas
- ✅ BRIN indexes added on temporal columns
- ✅ Initial monthly partitions created
### Unblocking Options
#### Option A: Scheduled Maintenance Window (Recommended)
**Effort:** 4-8 hours downtime
**Risk:** Low (proven approach)
1. **Schedule Window:** Coordinate with ops team for off-peak maintenance window
- Recommended: Weekend early morning (02:00-06:00 UTC)
- Notify stakeholders 1 week in advance
- Prepare rollback scripts
2. **Execute Sequentially:**
```
For each table (scheduler.audit → vuln.merge_events → vex.timeline_events → notify.deliveries):
1. Disable application writes (feature flag/maintenance mode)
2. Run data migration: INSERT INTO {table}_partitioned SELECT * FROM {table}
3. Verify row counts match
4. Swap table names (ALTER TABLE ... RENAME)
5. Update application config/queries if needed
6. Validate partition distribution
7. Re-enable writes
```
3. **Validation:**
- Run partition health checks
- Verify BRIN index efficiency
- Monitor query performance for 24h
#### Option B: Zero-Downtime Online Migration
**Effort:** 2-3 days implementation + 1 week migration window
**Risk:** Medium (more complex)
1. **Implement Dual-Write Trigger:**
```sql
CREATE TRIGGER trg_dual_write_{table}
AFTER INSERT ON {schema}.{table}
FOR EACH ROW EXECUTE FUNCTION {schema}.dual_write_{table}();
```
2. **Backfill Historical Data:**
- Run batched INSERT in background (10k rows/batch)
- Monitor replication lag
- Target: 48-72h for full backfill
3. **Cutover:**
- Verify row counts match
- Brief write pause (<30s)
- Swap table names
- Drop dual-write trigger
#### Option C: Incremental Per-Table Migration
**Effort:** 4 separate windows (1-2h each)
**Risk:** Low (smaller scope per window)
Migrate one table at a time across 4 separate maintenance windows:
- Week 1: scheduler.audit (lowest impact)
- Week 2: notify.deliveries
- Week 3: vex.timeline_events
- Week 4: vuln.merge_events (highest volume)
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-3422-001 | Schedule maintenance window with ops team | DevOps Guild | TBD |
| UNBLOCK-3422-002 | Create rollback scripts for each table | DBA Guild | Before window |
| UNBLOCK-3422-003 | Prepare verification queries | DBA Guild | Before window |
| UNBLOCK-3422-004 | Notify stakeholders of planned downtime | Project Mgmt | 1 week before |
| UNBLOCK-3422-005 | Execute migration during window | DBA Guild + DevOps | During window |
| UNBLOCK-3422-006 | Run post-migration validation | QA Guild | After window |
### Decision Required
**Action:** Ops team to confirm preferred approach (A, B, or C) and provide available maintenance window dates.
**Contact:** @ops-team, @dba-guild
**Escalation Path:** If no response in 5 business days, escalate to platform lead

View File

@@ -99,3 +99,128 @@ Extend the Unknowns registry with native binary-specific classification reasons,
| Risk | Mitigation |
| --- | --- |
| NUC-003B blocked on persistence integration design | Need design decision: should Scanner.Worker directly reference Unknowns.Storage.Postgres, or should an abstraction layer (IUnknownPersister) be introduced? Document decision in sprint before unblocking. |
---
## Unblocking Plan: Native Analyzer Persistence Integration
### Blocker Analysis
**Root Cause:** Design decision needed for how Scanner.Worker should persist Unknowns records. Two architectural approaches are available, and the choice affects the dependency graph and testability.
**Blocked Tasks (2 total):**
- NUC-003B: Wire native analyzer outputs to Unknowns (persistence layer decision)
- NUC-004: Integrate with native analyzer (blocked by NUC-003B)
**What's Already Done:**
- ✅ NUC-001: UnknownKind enum values added
- ✅ NUC-002: NativeUnknownContext model created
- ✅ NUC-003: NativeUnknownClassifier service implemented
- ✅ NUC-003A: Scanner.Worker references Unknowns.Core
- ✅ NUC-005: Unit tests (14 tests passing)
### Design Options
#### Option A: Direct Postgres Reference (Simpler)
**Pros:** Fewer abstractions, direct persistence, matches existing patterns
**Cons:** Tighter coupling, harder to test without database
```
Scanner.Worker → Unknowns.Core
Scanner.Worker → Unknowns.Storage.Postgres
```
**Implementation:**
1. Add project reference: `Scanner.Worker → Unknowns.Storage.Postgres`
2. Register `IUnknownRepository` from Postgres storage in DI
3. Call repository directly from analyzer output handler:
```csharp
// In native analyzer output handler
var unknown = _classifier.Classify(binaryContext);
await _unknownRepository.CreateAsync(unknown, ct);
```
#### Option B: Abstraction Layer (Recommended)
**Pros:** Decoupled, testable, supports different storage backends
**Cons:** Additional abstraction layer
```
Scanner.Worker → Unknowns.Core (IUnknownPersister)
Scanner.WebService → Unknowns.Storage.Postgres (PostgresUnknownPersister)
```
**Implementation:**
1. Create `IUnknownPersister` interface in Unknowns.Core:
```csharp
public interface IUnknownPersister
{
Task PersistAsync(Unknown unknown, CancellationToken ct = default);
Task PersistBatchAsync(IEnumerable<Unknown> unknowns, CancellationToken ct = default);
}
```
2. Implement in Unknowns.Storage.Postgres:
```csharp
public class PostgresUnknownPersister : IUnknownPersister
{
private readonly IUnknownRepository _repository;
// ...
}
```
3. Scanner.Worker depends only on IUnknownPersister
4. DI registration in Scanner.WebService wires PostgresUnknownPersister
#### Option C: Event-Based (Decoupled)
**Pros:** Fully decoupled, async processing, audit trail
**Cons:** More complex, eventual consistency
```
Scanner.Worker → publishes UnknownCreatedEvent
Unknowns.Worker → consumes event → persists to Postgres
```
**Implementation:**
1. Scanner.Worker publishes `UnknownCreatedEvent` to message bus
2. Unknowns module has its own worker that consumes events
3. Events stored in event store for replay/audit
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-3500-001 | Review design options with Architecture Guild | Unknowns Guild | TBD |
| UNBLOCK-3500-002 | Document chosen approach in ADR | Architecture Guild | After review |
| UNBLOCK-3500-003 | Implement chosen approach | Unknowns Guild | After ADR |
| UNBLOCK-3500-004 | Update NUC-003B with implementation | Unknowns Guild | After 003 |
| UNBLOCK-3500-005 | Complete NUC-004 native analyzer integration | Scanner Guild | After 004 |
### Recommended Decision
**Recommendation:** Option B (Abstraction Layer)
**Rationale:**
1. **Consistency:** Matches existing patterns in codebase (e.g., IVexRepository abstraction)
2. **Testability:** Scanner.Worker tests can use in-memory persister
3. **Flexibility:** Allows future storage backends (e.g., CAS, Redis cache)
4. **Separation:** Keeps Scanner.Worker focused on scanning, not storage details
### Decision Template
```markdown
## ADR: Unknowns Persistence Integration
**Status:** PROPOSED
**Date:** TBD
**Decision:** [A/B/C]
**Rationale:** [Reasoning]
**Consequences:** [Impact on codebase]
**Approved by:** @architecture-guild
```
### Next Steps
1. Schedule architecture review (15-30 min)
2. Document decision in ADR
3. Implement chosen approach
4. Unblock NUC-003B and NUC-004

View File

@@ -455,4 +455,164 @@ public sealed record ReachabilityResult(
| Date (UTC) | Update | Owner |
|---|---|---|
| 2025-12-18 | Created sprint from advisory analysis | Agent || 2025-12-19 | Implemented ISurfaceQueryService, SurfaceQueryService, ISurfaceRepository, ReachabilityConfidenceTier, SurfaceAwareReachabilityAnalyzer. Added metrics and caching. Created SurfaceQueryServiceTests. 12/15 tasks DONE. | Agent |
| 2025-12-18 | Created sprint from advisory analysis | Agent |
| 2025-12-19 | Implemented ISurfaceQueryService, SurfaceQueryService, ISurfaceRepository, ReachabilityConfidenceTier, SurfaceAwareReachabilityAnalyzer. Added metrics and caching. Created SurfaceQueryServiceTests. 12/15 tasks DONE. | Agent |
---
## Unblocking Plan: Integration Tests
### Blocker Analysis
**Root Cause:** REACH-013 (Integration tests with end-to-end flow) requires mock setup for `IReachabilityGraphService` and `ICallGraphAccessor` fixtures which are not yet available.
**Blocked Tasks (1 total):**
- REACH-013: Integration tests with end-to-end flow
**What's Already Done:**
- ✅ REACH-001 through REACH-012: All core implementation complete
- ✅ REACH-014, REACH-015: Documentation and metrics
- ✅ SurfaceQueryServiceTests: Unit tests passing
### Missing Test Infrastructure
1. **IReachabilityGraphService Mock:**
- Needs to return pre-built call graphs
- Should support multiple test scenarios (reachable, unreachable, partial)
2. **ICallGraphAccessor Fixture:**
- Requires sample call graph data
- Should represent realistic application structure
3. **ISurfaceRepository Mock:**
- Needs surface/trigger test data
- Should support lookup by (CVE, ecosystem, package, version)
### Unblocking Options
#### Option A: In-Memory Test Fixtures (Recommended)
**Effort:** 1-2 days
**Risk:** Low
1. **Create Test Call Graph Builder:**
```csharp
public class TestCallGraphBuilder
{
public static CallGraph CreateSimpleWebApi()
{
// Creates: Entrypoint → Controller → Service → VulnerableLib.Method()
}
public static CallGraph CreateWithMultiplePaths()
{
// Multiple entrypoints, branching paths to sink
}
public static CallGraph CreateUnreachable()
{
// Sink exists but no path from entrypoints
}
}
```
2. **Create Test Surface Data:**
```csharp
public class TestSurfaceBuilder
{
public static VulnSurface CreateForCve(string cveId, params string[] triggerMethods)
{
return new VulnSurface
{
CveId = cveId,
Ecosystem = "npm",
Package = "test-package",
Triggers = triggerMethods.Select(m => new TriggerMethod(m)).ToList()
};
}
}
```
3. **Wire Into Integration Tests:**
```csharp
public class ReachabilityIntegrationTests
{
private readonly InMemorySurfaceRepository _surfaceRepo;
private readonly InMemoryCallGraphAccessor _graphAccessor;
private readonly SurfaceAwareReachabilityAnalyzer _analyzer;
[Fact]
public async Task Confirmed_WhenSurfaceTriggerIsReachable()
{
// Arrange
var graph = TestCallGraphBuilder.CreateSimpleWebApi();
var surface = TestSurfaceBuilder.CreateForCve("CVE-2024-1234", "VulnerableLib.Deserialize");
_surfaceRepo.Add(surface);
_graphAccessor.Set(graph);
// Act
var result = await _analyzer.AnalyzeVulnerabilityAsync(graph, vuln, CancellationToken.None);
// Assert
Assert.Equal(ReachabilityConfidenceTier.Confirmed, result.ConfidenceTier);
}
}
```
#### Option B: Testcontainers with Real Services
**Effort:** 3-5 days
**Risk:** Medium (infrastructure complexity)
Full E2E with containerized services:
1. PostgreSQL with surface data
2. Scanner API with call graph endpoints
3. Test orchestration via Testcontainers
#### Option C: Contract Tests
**Effort:** 1 day
**Risk:** Low (but less coverage)
Test service contracts without full E2E:
1. Verify SurfaceQueryService returns correct format
2. Verify ReachabilityAnalyzer accepts expected inputs
3. Verify result format matches API contract
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-3700-001 | Create TestCallGraphBuilder with 3+ scenarios | Scanner Guild | 1 day |
| UNBLOCK-3700-002 | Create TestSurfaceBuilder with fixtures | Scanner Guild | 0.5 day |
| UNBLOCK-3700-003 | Implement InMemorySurfaceRepository for tests | Scanner Guild | 0.5 day |
| UNBLOCK-3700-004 | Write integration tests using fixtures | Scanner Guild | 1 day |
| UNBLOCK-3700-005 | Add test scenarios to CI pipeline | DevOps Guild | 0.5 day |
### Test Scenarios to Cover
| Scenario | Graph | Surface | Expected Tier |
|----------|-------|---------|---------------|
| Confirmed reachable | Path exists | Trigger found | Confirmed |
| Likely reachable | Path to package | No surface | Likely |
| Present only | No call graph | N/A | Present |
| Unreachable | No path | Trigger exists | Unreachable |
| Multiple paths | 3+ paths | Trigger found | Confirmed (3 witnesses) |
| Fallback mode | Path to package API | No surface | Likely |
### Recommended Action
**Implement Option A (In-Memory Test Fixtures):**
1. Takes 1-2 days
2. Provides good coverage without infrastructure overhead
3. Runs fast in CI
4. Can be extended to Testcontainers later if needed
### Files to Create
```
src/Scanner/__Tests/StellaOps.Scanner.Reachability.Tests/
├── Fixtures/
│ ├── TestCallGraphBuilder.cs
│ ├── TestSurfaceBuilder.cs
│ └── InMemorySurfaceRepository.cs
├── Integration/
│ └── ReachabilityIntegrationTests.cs
```

View File

@@ -101,8 +101,8 @@ Enable incremental reachability for PR/CI performance:
| 11 | CACHE-011 | DONE | Create StateFlipDetector |
| 12 | CACHE-012 | DONE | Create IncrementalReachabilityService |
| 13 | CACHE-013 | DONE | Add cache hit/miss metrics |
| 14 | CACHE-014 | TODO | Integrate with PR gate workflow |
| 15 | CACHE-015 | TODO | Performance benchmarks |
| 14 | CACHE-014 | DONE | Integrate with PR gate workflow |
| 15 | CACHE-015 | DOING | Performance benchmarks |
| 16 | CACHE-016 | DONE | Create ReachabilityCacheTests |
| 17 | CACHE-017 | DONE | Create GraphDeltaComputerTests |
@@ -649,3 +649,4 @@ public class PrReachabilityGate
| Date (UTC) | Update | Owner |
|---|---|---|
| 2025-12-18 | Created sprint from advisory analysis | Agent |
| 2025-06-14 | Implemented CACHE-014: Created PrReachabilityGate.cs with IPrReachabilityGate interface, PrGateResult model, PrGateDecision enum, configurable blocking thresholds (BlockOnNewReachable, MinConfidenceThreshold, MaxNewReachableCount), PR annotations with source file/line info, markdown summary generation, and observability metrics. Updated StateFlip record with Confidence, SourceFile, StartLine, EndLine properties. Created 12 comprehensive unit tests in PrReachabilityGateTests.cs (all passing). | Agent |

View File

@@ -430,3 +430,144 @@ This sprint addresses architectural alignment between StellaOps and the referenc
**Overall Alignment: 90%**
**Effort to 100%: 3-5 days**
---
## Unblocking Plan: CycloneDX 1.7 Support
### Blocker Analysis
**Root Cause:** CycloneDX.Core NuGet package version 10.0.2 does not expose `SpecificationVersion.v1_7` enum value. The CycloneDX 1.7 specification was released October 2025, but the .NET library has not yet been updated to support it.
**Blocked Tasks (5 total):**
- 1.1 Research CycloneDX.Core 10.0.2+ (library doesn't support v1_7)
- 1.3 Update Specification Version (cannot set `SpecificationVersion.v1_7`)
- 1.4 Update Media Type Constants (should follow code upgrade)
- 1.5 Update Documentation (docs should reflect actual code)
- 1.7 Validate Acceptance Criteria (cannot validate without implementation)
**What's Already Done:**
- ✅ Updated CycloneDX.Core to 10.0.2
- ✅ All tests pass with CycloneDX 1.6
- ✅ Signal mapping documentation complete (Task 2)
- ✅ EPSS clarification documentation complete (Task 3)
- ✅ Alignment report complete (Task 4)
### Unblocking Options
#### Option A: Wait for Upstream Library (Recommended if timeline allows)
**Effort:** 0 (monitoring only)
**Risk:** Unknown timeline
1. **Monitor CycloneDX.Core Releases:**
- GitHub: https://github.com/CycloneDX/cyclonedx-dotnet-library/releases
- NuGet: https://www.nuget.org/packages/CycloneDX.Core
- Subscribe to release notifications
2. **Track Issue:**
- Search/create issue for v1_7 support on GitHub
- Engage with maintainers if urgent
3. **When Available:**
- Update package reference
- Change `SpecificationVersion.v1_6``SpecificationVersion.v1_7`
- Update media type strings
- Run tests and validate
#### Option B: Fork and Patch (For urgent timeline)
**Effort:** 1-2 days
**Risk:** Maintenance overhead
1. **Fork Repository:**
```bash
git clone https://github.com/CycloneDX/cyclonedx-dotnet-library
```
2. **Add v1_7 Enum Value:**
- File: `CycloneDX.Core/Enums/SpecificationVersion.cs`
- Add: `v1_7 = 7`
3. **Update Serialization:**
- Add v1_7 handling in JSON/XML serializers
- Map to spec version string "1.7"
4. **Build and Publish:**
- Build forked package
- Publish to private NuGet feed (configured in `nuget.config`)
- Reference: `<PackageReference Include="CycloneDX.Core" Version="10.0.3-stellaops" />`
5. **Track Upstream:**
- Submit PR to upstream with v1_7 support
- Plan migration back to official package when released
#### Option C: String-Based Workaround (Minimal changes)
**Effort:** 0.5 days
**Risk:** Bypasses type safety
1. **Create Extension:**
```csharp
// File: src/Scanner/__Libraries/StellaOps.Scanner.Emit/Extensions/CycloneDxExtensions.cs
public static class CycloneDxExtensions
{
/// <summary>
/// Workaround for CycloneDX.Core not yet supporting v1_7.
/// Sets spec version string directly in serialized output.
/// </summary>
public static void SetSpecVersion17(this Bom bom)
{
// For JSON serialization, post-process to replace "specVersion": "1.6"
// with "specVersion": "1.7"
}
}
```
2. **Post-Process Serialization:**
- Serialize with v1_6
- Replace version string in output: `"specVersion": "1.6"` → `"specVersion": "1.7"`
- Update media type headers separately
3. **Limitations:**
- Doesn't validate 1.7-specific fields
- Requires migration when official support arrives
#### Option D: Defer to CycloneDX 1.6 (Pragmatic)
**Effort:** 0
**Risk:** None (already working)
1. **Document Decision:**
- CycloneDX 1.6 is current StellaOps baseline
- 1.7 upgrade planned for when library supports it
- No breaking changes expected between 1.6 and 1.7
2. **Update Sprint Status:**
- Mark tasks 1.3-1.7 as DEFERRED (not BLOCKED)
- Create tracking issue for future upgrade
- Set milestone for Q1 2026
3. **Alignment Impact:**
- Current alignment: 95%
- v1_7 is minor enhancement, not blocking requirement
- All critical features already compliant
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-5000-001 | Create GitHub issue to track CycloneDX.Core v1_7 support | Scanner Guild | Immediate |
| UNBLOCK-5000-002 | Subscribe to CycloneDX.Core release notifications | Scanner Guild | Immediate |
| UNBLOCK-5000-003 | Decide on approach (A, B, C, or D) based on timeline | Tech Lead | TBD |
| UNBLOCK-5000-004 | If Option B: Fork and add v1_7 enum | Scanner Guild | If urgent |
| UNBLOCK-5000-005 | Update sprint when library available | Scanner Guild | When released |
### Recommended Action
**If timeline is flexible:** Option D (defer) - document 1.6 as current baseline, upgrade when library supports 1.7.
**If timeline is urgent:** Option B (fork) - fork library, add v1_7, use private feed, submit PR upstream.
### External Links
- CycloneDX 1.7 Announcement: https://cyclonedx.org/news/cyclonedx-v1.7-released/
- CycloneDX .NET Library: https://github.com/CycloneDX/cyclonedx-dotnet-library
- CycloneDX 1.7 Schema: https://cyclonedx.org/docs/1.7/

View File

@@ -815,6 +815,126 @@ public sealed class DriftSarifGenerator
---
## Unblocking Plan: UI Integration
### Blocker Analysis
**Root Cause:** Two tasks remain blocked due to missing infrastructure:
1. **UI-011 (PR View Component):** The RiskDriftCard cannot be integrated into PR view because the PR view component does not exist in the Angular application.
2. **UI-025 (CLI Integration Tests):** End-to-end tests require a running Scanner/API instance which is not available in CI.
**Blocked Tasks (2 total):**
- UI-011: Integrate RiskDriftCard into PR view (component missing)
- UI-025: Integration tests for CLI (E2E infrastructure missing)
**What's Already Done:**
- ✅ UI-001 through UI-010: PathViewer, RiskDriftCard, API service, scan detail integration
- ✅ UI-012 through UI-024: Unit tests, DSSE attestation, CLI commands, SARIF output
- ✅ All core functionality implemented and tested
### Unblocking Options
#### UI-011: PR View Component
##### Option A: Create PR View Component (New Feature)
**Effort:** 3-5 days
**Recommendation:** Defer to separate sprint
The PR view functionality requires:
1. GitHub/GitLab webhook integration
2. PR metadata storage
3. PR-to-scan association
4. PR summary component
5. Comment posting API
This is a substantial feature that should be its own sprint (suggested: SPRINT_3600_0005_0001_pr_integration).
##### Option B: Add to Existing Scan Detail (Quick Win)
**Effort:** 0.5 days
**Recommendation:** Already done (UI-010)
RiskDriftCard is already integrated into scan-detail-page. PR-specific display can be added later when PR view exists.
##### Option C: Mark as DEFERRED
**Effort:** 0
**Recommendation:** Mark task as DEFERRED, not BLOCKED
Since the PR view component is a separate feature, this task should be marked DEFERRED until the PR view sprint is created and completed.
#### UI-025: CLI Integration Tests
##### Option A: Testcontainers-Based E2E
**Effort:** 2-3 days
**Recommendation:** Preferred approach
1. Use Testcontainers to spin up Scanner API in test:
```csharp
public class DriftCliIntegrationTests : IAsyncLifetime
{
private PostgreSqlContainer _postgres;
private IContainer _scannerApi;
public async Task InitializeAsync()
{
_postgres = new PostgreSqlBuilder().Build();
await _postgres.StartAsync();
_scannerApi = new ContainerBuilder()
.WithImage("stellaops/scanner:latest")
.WithEnvironment("ConnectionStrings__Postgres", _postgres.GetConnectionString())
.WithPortBinding(8080, true)
.Build();
await _scannerApi.StartAsync();
}
}
```
2. Run CLI against containerized API
3. Verify output formats (table, JSON, SARIF)
##### Option B: Mock HTTP Client
**Effort:** 1 day
**Recommendation:** Already have unit tests
Mock the HTTP client in CLI tests to simulate API responses. This is what UI-019 through UI-024 already do.
##### Option C: Manual E2E Test Suite
**Effort:** 0.5 days
**Recommendation:** Document manual test procedure
Create `docs/testing/drift-cli-e2e-tests.md` with manual test procedures:
1. Prerequisites (running API, test data)
2. Test scenarios
3. Expected outputs
4. Verification checklist
### Unblocking Tasks
| Task | Description | Owner | Due |
|------|-------------|-------|-----|
| UNBLOCK-3600-001 | Update UI-011 status to DEFERRED (awaiting PR view sprint) | UI Guild | Immediate |
| UNBLOCK-3600-002 | Create tracking issue for PR view sprint | Project Mgmt | This sprint |
| UNBLOCK-3600-003 | Implement Testcontainers E2E for UI-025 | CLI Guild | Optional |
| UNBLOCK-3600-004 | Document manual E2E test procedure | QA Guild | Alternative |
| UNBLOCK-3600-005 | Mark UI-025 as DEFERRED if Testcontainers not feasible | Project Mgmt | If needed |
### Recommended Actions
1. **UI-011:** Change status from BLOCKED to DEFERRED. Create SPRINT_3600_0005 for PR integration as a separate feature.
2. **UI-025:** Either implement Testcontainers E2E tests OR mark as DEFERRED with documented manual test procedure.
### Status Update
| Task | Current | Recommended | Reason |
|------|---------|-------------|--------|
| UI-011 | BLOCKED | DEFERRED | PR view is separate feature |
| UI-025 | BLOCKED | DEFERRED or DONE | Manual tests acceptable |
---
## 3. ACCEPTANCE CRITERIA
### 3.1 Path Viewer Component