Files
git.stella-ops.org/src/__Libraries/StellaOps.Evidence.Core
StellaOps Bot e411fde1a9 feat(audit): Apply TreatWarningsAsErrors=true to 160+ production csproj files
Sprint: SPRINT_20251229_049_BE_csproj_audit_maint_tests
Tasks: AUDIT-0001 through AUDIT-0147 APPLY tasks (approved decisions 1-9)

Changes:
- Set TreatWarningsAsErrors=true for all production .NET projects
- Fixed nullable warnings in Scanner.EntryTrace, Scanner.Evidence,
  Scheduler.Worker, Concelier connectors, and other modules
- Injected TimeProvider/IGuidProvider for deterministic time/ID generation
- Added path traversal validation in AirGap.Bundle
- Fixed NULL handling in various cursor classes
- Third-party GostCryptography retains TreatWarningsAsErrors=false (preserves original)
- Test projects excluded per user decision (rejected decision 10)

Note: All 17 ACSC connector tests pass after snapshot fixture sync
2026-01-04 11:21:16 +02:00
..
2025-12-24 21:46:08 +02:00
2026-01-02 11:43:43 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2025-12-24 21:46:08 +02:00
2026-01-02 11:43:43 +02:00

StellaOps.Evidence.Core

Unified evidence model library providing content-addressed, cryptographically verifiable evidence records for the StellaOps platform.

Overview

This library defines the core evidence model that unifies all evidence types across StellaOps modules. Evidence records are:

  • Content-addressed: Each record has a deterministic ID derived from its content
  • Cryptographically verifiable: Records can carry signatures from their producers
  • Linked: Records reference their sources (subjects) and can form chains
  • Typed: Each record has a well-defined type for semantic clarity

Key Types

IEvidence

The core evidence interface that all evidence records implement:

public interface IEvidence
{
    string EvidenceId { get; }                    // Content-addressed ID
    EvidenceType Type { get; }                    // Evidence type enum
    string SubjectNodeId { get; }                 // What this evidence is about
    DateTimeOffset CreatedAt { get; }             // UTC timestamp
    IReadOnlyList<EvidenceSignature> Signatures { get; }  // Cryptographic signatures
    EvidenceProvenance? Provenance { get; }       // Origin information
    IReadOnlyDictionary<string, string> Properties { get; }  // Type-specific data
}

EvidenceType

Enumeration of all supported evidence types:

Type Description
Unknown Unspecified evidence type
Sbom Software Bill of Materials
Vulnerability Vulnerability finding
Vex VEX statement (exploitability)
Attestation DSSE/in-toto attestation
PolicyDecision Policy evaluation result
ScanResult Scanner output
Provenance SLSA provenance
Signature Cryptographic signature
ProofSegment Proof chain segment
Exception Policy exception/waiver
Advisory Security advisory
CveMatch CVE to component match
ReachabilityResult Code reachability analysis

EvidenceRecord

The standard implementation of IEvidence:

public sealed record EvidenceRecord : IEvidence
{
    public required string EvidenceId { get; init; }
    public required EvidenceType Type { get; init; }
    public required string SubjectNodeId { get; init; }
    public required DateTimeOffset CreatedAt { get; init; }
    public IReadOnlyList<EvidenceSignature> Signatures { get; init; } = [];
    public EvidenceProvenance? Provenance { get; init; }
    public IReadOnlyDictionary<string, string> Properties { get; init; } = 
        new Dictionary<string, string>();
}

Adapters

The library provides adapters to convert module-specific types to unified evidence records:

Adapter Source Module Source Type
EvidenceStatementAdapter Attestor EvidenceStatement
ProofSegmentAdapter Scanner ProofSegment
VexObservationAdapter Excititor VexObservation
ExceptionApplicationAdapter Policy ExceptionApplication

Using Adapters

// Convert a VEX observation to evidence records
var adapter = new VexObservationAdapter();
var input = new VexObservationInput
{
    SubjectDigest = imageDigest,
    Upstream = new VexObservationUpstreamInput { ... },
    Statements = new[] { ... }
};
var records = adapter.ToEvidence(input);

Storage

IEvidenceStore

Interface for evidence persistence:

public interface IEvidenceStore
{
    Task<IEvidence?> GetAsync(string evidenceId, CancellationToken ct = default);
    Task<IReadOnlyList<IEvidence>> GetBySubjectAsync(string subjectNodeId, CancellationToken ct = default);
    Task<IReadOnlyList<IEvidence>> GetByTypeAsync(EvidenceType type, CancellationToken ct = default);
    Task StoreAsync(IEvidence evidence, CancellationToken ct = default);
    Task<bool> ExistsAsync(string evidenceId, CancellationToken ct = default);
}

InMemoryEvidenceStore

Thread-safe in-memory implementation for testing and caching:

var store = new InMemoryEvidenceStore();
await store.StoreAsync(evidenceRecord);
var retrieved = await store.GetAsync(evidenceRecord.EvidenceId);

Usage Examples

Creating Evidence Records

var evidence = new EvidenceRecord
{
    EvidenceId = "sha256:abc123...",
    Type = EvidenceType.Vulnerability,
    SubjectNodeId = componentId,
    CreatedAt = DateTimeOffset.UtcNow,
    Signatures = new[]
    {
        new EvidenceSignature
        {
            SignerId = "scanner/grype",
            Algorithm = "Ed25519",
            SignatureBase64 = "...",
            SignedAt = DateTimeOffset.UtcNow,
            SignerType = SignerType.Tool
        }
    },
    Properties = new Dictionary<string, string>
    {
        ["cve"] = "CVE-2024-1234",
        ["severity"] = "HIGH",
        ["cvss"] = "8.5"
    }
};

Querying Evidence

var store = serviceProvider.GetRequiredService<IEvidenceStore>();

// Get all evidence for a specific subject
var subjectEvidence = await store.GetBySubjectAsync(componentId);

// Get all VEX statements
var vexRecords = await store.GetByTypeAsync(EvidenceType.Vex);

// Check if evidence exists
var exists = await store.ExistsAsync(evidenceId);

Integration

Dependency Injection

services.AddSingleton<IEvidenceStore, InMemoryEvidenceStore>();
// Or for PostgreSQL:
// services.AddScoped<IEvidenceStore, PostgresEvidenceStore>();