Files
git.stella-ops.org/docs/architecture/signal-contract-mapping.md
master 8779e9226f feat: add stella-callgraph-node for JavaScript/TypeScript call graph extraction
- Implemented a new tool `stella-callgraph-node` that extracts call graphs from JavaScript/TypeScript projects using Babel AST.
- Added command-line interface with options for JSON output and help.
- Included functionality to analyze project structure, detect functions, and build call graphs.
- Created a package.json file for dependency management.

feat: introduce stella-callgraph-python for Python call graph extraction

- Developed `stella-callgraph-python` to extract call graphs from Python projects using AST analysis.
- Implemented command-line interface with options for JSON output and verbose logging.
- Added framework detection to identify popular web frameworks and their entry points.
- Created an AST analyzer to traverse Python code and extract function definitions and calls.
- Included requirements.txt for project dependencies.

chore: add framework detection for Python projects

- Implemented framework detection logic to identify frameworks like Flask, FastAPI, Django, and others based on project files and import patterns.
- Enhanced the AST analyzer to recognize entry points based on decorators and function definitions.
2025-12-19 18:11:59 +02:00

30 KiB

Signal Contract Mapping: Advisory ↔ StellaOps

Document Version: 1.0 Last Updated: 2025-12-19 Status: ACTIVE Related Sprint: SPRINT_5000_0001_0001


Overview

This document provides a comprehensive mapping between the reference advisory's Signal-based message contracts (10/12/14/16/18) and the StellaOps implementation. While StellaOps uses domain-specific terminology, all signal concepts are fully implemented with equivalent or superior functionality.

Key Insight: StellaOps implements the same architectural patterns as the advisory but uses domain-specific entity names instead of generic "Signal-X" labels. This provides better type safety, code readability, and domain modeling while maintaining conceptual alignment.


Quick Reference Table

Advisory Signal StellaOps Equivalent Module Key Files
Signal-10 (SBOM Intake) CallgraphIngestRequest, ISbomIngestionService Scanner, Signals SbomIngestionService.cs, CallgraphIngestRequest.cs
Signal-12 (Evidence/Attestation) in-toto Statement + DSSE Attestor, Signer InTotoStatement.cs, DsseEnvelope.cs, 19 predicate types
Signal-14 (Triage Fact) TriageFinding + related entities Scanner.Triage TriageFinding.cs, TriageReachabilityResult.cs, TriageRiskResult.cs, TriageEffectiveVex.cs
Signal-16 (Diff Delta) TriageSnapshot, MaterialRiskChange, DriftCause Scanner.SmartDiff, ReachabilityDrift MaterialRiskChangeDetector.cs, ReachabilityDriftDetector.cs, TriageSnapshot.cs
Signal-18 (Decision) TriageDecision + DSSE signatures Scanner.Triage TriageDecision.cs, TriageEvidenceArtifact.cs

Signal-10: SBOM Intake

Advisory Specification

{
  "bom": "(cyclonedx:1.7)",
  "subject": {
    "image": "ghcr.io/org/app@sha256:...",
    "digest": "sha256:..."
  },
  "source": "scanner-instance-1",
  "scanProfile": "default",
  "createdAt": "2025-12-19T10:00:00Z"
}

Purpose: Initial SBOM ingestion with subject identification


StellaOps Implementation

Primary Contract: CallgraphIngestRequest

Location: src/Signals/StellaOps.Signals/Models/CallgraphIngestRequest.cs

public sealed record CallgraphIngestRequest
{
    public required string TenantId { get; init; }
    public required string ArtifactDigest { get; init; }  // Maps to "subject.digest"
    public required string Language { get; init; }
    public required string Component { get; init; }
    public required string? Version { get; init; }
    public required string ArtifactContentBase64 { get; init; }  // Maps to "bom" (encoded)
    public string? SchemaVersion { get; init; }
    public IReadOnlyDictionary<string, string>? Metadata { get; init; }  // Includes "source", "scanProfile"
}

Service Interface: ISbomIngestionService

Location: src/Scanner/StellaOps.Scanner.WebService/Services/ISbomIngestionService.cs

public interface ISbomIngestionService
{
    Task<SbomIngestionResult> IngestCycloneDxAsync(
        string tenantId,
        Stream cycloneDxJson,
        SbomIngestionOptions options,
        CancellationToken cancellationToken);

    Task<SbomIngestionResult> IngestSpdxAsync(
        string tenantId,
        Stream spdxJson,
        SbomIngestionOptions options,
        CancellationToken cancellationToken);
}

Data Flow:

[Scanner] → SbomIngestionService → [CycloneDxComposer/SpdxComposer]
                                        ↓
                                   PostgreSQL (scanner.sboms)
                                        ↓
                                   Event: "sbom.ingested"
                                        ↓
                                   [Downstream processors]

API Endpoints:

  • POST /api/scanner/sboms/ingest - Direct SBOM ingestion
  • POST /api/signals/callgraph/ingest - Call graph + SBOM ingestion

Related Files:

  • src/Scanner/StellaOps.Scanner.WebService/Endpoints/SbomEndpoints.cs
  • src/Signals/StellaOps.Signals/Services/CallgraphIngestionService.cs
  • src/Scanner/__Libraries/StellaOps.Scanner.Emit/Composition/CycloneDxComposer.cs

Equivalence Proof:

  • BOM content: CycloneDX 1.6 (upgrading to 1.7)
  • Subject identification: ArtifactDigest (SHA-256)
  • Source tracking: Metadata["source"]
  • Profile support: SbomIngestionOptions.ScanProfile
  • Timestamp: CreatedAt in database entity

Signal-12: Evidence/Attestation (in-toto Statement)

Advisory Specification

{
  "subject": {"digest": {"sha256": "..."}},
  "type": "attestation",
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {...},
  "materials": [],
  "tool": "scanner@1.0.0",
  "runId": "run-123",
  "startedAt": "2025-12-19T10:00:00Z",
  "finishedAt": "2025-12-19T10:05:00Z"
}

Purpose: Evidence envelopes for attestations (DSSE-wrapped)


StellaOps Implementation

Primary Contract: InTotoStatement (abstract base)

Location: src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Statements/InTotoStatement.cs

public abstract record InTotoStatement
{
    [JsonPropertyName("_type")]
    public string Type => "https://in-toto.io/Statement/v1";

    [JsonPropertyName("subject")]
    public required IReadOnlyList<Subject> Subject { get; init; }

    [JsonPropertyName("predicateType")]
    public abstract string PredicateType { get; }
}

DSSE Envelope: DsseEnvelope

Location: src/Attestor/StellaOps.Attestor.Envelope/DsseEnvelope.cs

public sealed record DsseEnvelope
{
    [JsonPropertyName("payload")]
    public required string Payload { get; init; }  // Base64url(canonical JSON of Statement)

    [JsonPropertyName("payloadType")]
    public required string PayloadType { get; init; }  // "application/vnd.in-toto+json"

    [JsonPropertyName("signatures")]
    public required IReadOnlyList<DsseSignature> Signatures { get; init; }
}

Predicate Types Registry: 19 types supported

Location: src/Signer/StellaOps.Signer/StellaOps.Signer.Core/PredicateTypes.cs

public static class PredicateTypes
{
    // SLSA (Standard)
    public const string SlsaProvenanceV02 = "https://slsa.dev/provenance/v0.2";
    public const string SlsaProvenanceV1 = "https://slsa.dev/provenance/v1";

    // StellaOps Custom
    public const string StellaOpsSbom = "stella.ops/sbom@v1";
    public const string StellaOpsVex = "stella.ops/vex@v1";
    public const string StellaOpsEvidence = "stella.ops/evidence@v1";
    public const string StellaOpsPathWitness = "stella.ops/pathWitness@v1";
    public const string StellaOpsReachabilityWitness = "stella.ops/reachabilityWitness@v1";
    public const string StellaOpsReachabilityDrift = "stellaops.dev/predicates/reachability-drift@v1";
    public const string StellaOpsPolicyDecision = "stella.ops/policy-decision@v1";
    // ... 12 more predicate types
}

Signing Service: CryptoDsseSigner

Location: src/Signer/StellaOps.Signer/StellaOps.Signer.Infrastructure/Signing/CryptoDsseSigner.cs

Data Flow:

[Component] → ProofChainSigner → [Build in-toto Statement]
                                       ↓
                                  Canonical JSON serialization
                                       ↓
                                  DSSE PAE construction
                                       ↓
                                  CryptoDsseSigner (KMS/Keyless)
                                       ↓
                                  DsseEnvelope (signed)
                                       ↓
                                  PostgreSQL (attestor.envelopes)
                                       ↓
                                  Optional: Rekor transparency log

Sample Attestation Files:

  • src/Attestor/StellaOps.Attestor.Types/samples/build-provenance.v1.json
  • src/Attestor/StellaOps.Attestor.Types/samples/vex-attestation.v1.json
  • src/Attestor/StellaOps.Attestor.Types/samples/scan-results.v1.json

Equivalence Proof:

  • Subject: Subject list with digests
  • Type: https://in-toto.io/Statement/v1
  • PredicateType: 19 supported types
  • Predicate: Custom per type
  • Tool: Embedded in predicate metadata
  • RunId: TraceId / CorrelationId
  • Timestamps: In predicate metadata
  • DSSE wrapping: Full implementation

Signal-14: Triage Fact

Advisory Specification

{
  "subject": "pkg:npm/lodash@4.17.0",
  "cve": "CVE-2024-12345",
  "findingId": "cve@package@symbol@subjectDigest",
  "location": {
    "file": "src/index.js",
    "package": "lodash",
    "symbol": "template"
  },
  "reachability": {
    "status": "reachable",
    "callStackId": "cs-abc123"
  },
  "epss": 0.85,
  "cvss": {
    "version": "4.0",
    "vector": "CVSS:4.0/AV:N/AC:L/...",
    "score": 7.5
  },
  "vexStatus": "affected",
  "notes": "...",
  "evidenceRefs": ["dsse://sha256:..."]
}

Purpose: Triage facts per CVE with reachability, scoring, and VEX status


StellaOps Implementation

Primary Entity: TriageFinding (core entity tying all triage data)

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageFinding.cs

public sealed class TriageFinding
{
    public string FindingId { get; set; }  // Stable ID: "cve@purl@scanId"
    public string TenantId { get; set; }
    public string AssetId { get; set; }  // Maps to "subject"
    public string? Purl { get; set; }  // Package URL
    public string? CveId { get; set; }  // Maps to "cve"
    public string? RuleId { get; set; }  // For non-CVE findings

    public DateTimeOffset FirstSeenAt { get; set; }
    public DateTimeOffset LastSeenAt { get; set; }

    // Navigation properties
    public TriageReachabilityResult? Reachability { get; set; }
    public TriageRiskResult? Risk { get; set; }
    public TriageEffectiveVex? EffectiveVex { get; set; }
    public ICollection<TriageEvidenceArtifact> EvidenceArtifacts { get; set; }
    public ICollection<TriageDecision> Decisions { get; set; }
}

Reachability Component: TriageReachabilityResult

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageReachabilityResult.cs

public sealed class TriageReachabilityResult
{
    public string ResultId { get; set; }
    public string FindingId { get; set; }

    public TriageReachability Reachability { get; set; }  // Yes, No, Unknown
    public int Confidence { get; set; }  // 0-100

    public string? StaticProofRef { get; set; }  // Maps to "callStackId"
    public string? RuntimeProofRef { get; set; }

    public string InputsHash { get; set; }  // For caching/diffing
    public DateTimeOffset ComputedAt { get; set; }

    // Lattice evaluation
    public double? LatticeScore { get; set; }
    public string? LatticeState { get; set; }
}

Risk/Scoring Component: TriageRiskResult

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageRiskResult.cs

public sealed class TriageRiskResult
{
    public string ResultId { get; set; }
    public string FindingId { get; set; }

    // Scoring
    public double RiskScore { get; set; }  // Combined score
    public double? CvssBaseScore { get; set; }
    public string? CvssVector { get; set; }  // CVSS:4.0/AV:N/...
    public string? CvssVersion { get; set; }  // "4.0"

    public double? EpssScore { get; set; }  // Maps to "epss"
    public double? EpssPercentile { get; set; }
    public DateOnly? EpssModelDate { get; set; }

    // Policy decision
    public TriageVerdict Verdict { get; set; }  // Ship, Block, Exception
    public string? PolicyId { get; set; }
    public string Lane { get; set; }  // Critical, High, Medium, Low

    public string InputsHash { get; set; }
    public string? LatticeExplanationJson { get; set; }  // Maps to "notes"
    public DateTimeOffset ComputedAt { get; set; }
}

VEX Component: TriageEffectiveVex

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageEffectiveVex.cs

public sealed class TriageEffectiveVex
{
    public string VexId { get; set; }
    public string FindingId { get; set; }

    public VexClaimStatus Status { get; set; }  // Maps to "vexStatus"
    public VexJustification? Justification { get; set; }

    public string? ProvenancePointer { get; set; }  // Linkset reference
    public string? DsseEnvelopeHash { get; set; }  // Maps to "evidenceRefs"

    public DateTimeOffset EffectiveAt { get; set; }
}

Evidence Artifacts: TriageEvidenceArtifact

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageEvidenceArtifact.cs

public sealed class TriageEvidenceArtifact
{
    public string ArtifactId { get; set; }
    public string FindingId { get; set; }

    public string ContentHash { get; set; }  // SHA-256
    public string? SignatureRef { get; set; }  // DSSE envelope reference
    public string? CasUri { get; set; }  // cas://reachability/graphs/{hash}

    public string MediaType { get; set; }
    public long SizeBytes { get; set; }

    public DateTimeOffset CreatedAt { get; set; }
}

Database Schema:

  • Table: scanner.triage_findings (core table)
  • Table: scanner.triage_reachability_results (1:1 with findings)
  • Table: scanner.triage_risk_results (1:1 with findings)
  • Table: scanner.triage_effective_vex (1:1 with findings)
  • Table: scanner.triage_evidence_artifacts (1:N with findings)

Equivalence Proof:

  • Subject: AssetId + Purl
  • CVE: CveId
  • Finding ID: FindingId (stable scheme)
  • Location: Embedded in evidence artifacts
  • Reachability: Full TriageReachabilityResult entity
  • EPSS: EpssScore, EpssPercentile, EpssModelDate
  • CVSS: CvssBaseScore, CvssVector, CvssVersion
  • VEX Status: TriageEffectiveVex.Status
  • Notes: LatticeExplanationJson
  • Evidence Refs: TriageEvidenceArtifact with ContentHash, CasUri

Signal-16: Diff Delta

Advisory Specification

{
  "subject": "ghcr.io/org/app",
  "fromVersion": "1.0.0",
  "toVersion": "1.1.0",
  "changed": {
    "packages": ["lodash@4.17.0→4.17.21"],
    "files": ["src/util.js"],
    "symbols": ["template"],
    "vulns": [{"cve": "CVE-2024-12345", "action": "fixed"}]
  },
  "explainableReasons": [
    {
      "reasonCode": "VEX_STATUS_FLIP",
      "params": {"from": "affected", "to": "fixed"},
      "evidenceRefs": ["dsse://..."]
    }
  ]
}

Purpose: Minimal deltas between SBOM snapshots with explainable reasons


StellaOps Implementation

Primary Entity: TriageSnapshot

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageSnapshot.cs

public sealed class TriageSnapshot
{
    public string SnapshotId { get; set; }
    public string TenantId { get; set; }
    public string AssetId { get; set; }

    // Version tracking
    public string? FromVersion { get; set; }  // Maps to "fromVersion"
    public string? ToVersion { get; set; }  // Maps to "toVersion"
    public string FromScanId { get; set; }
    public string ToScanId { get; set; }

    // Input/output hashes for diffing
    public string FromInputsHash { get; set; }
    public string ToInputsHash { get; set; }

    // Precomputed diff
    public string? DiffJson { get; set; }  // Maps to "changed"

    // Trigger tracking
    public string? Trigger { get; set; }  // Manual, Scheduled, EventDriven

    public DateTimeOffset CreatedAt { get; set; }
}

Smart-Diff Detector: MaterialRiskChangeDetector

Location: src/Scanner/__Libraries/StellaOps.Scanner.SmartDiff/Detection/MaterialRiskChangeDetector.cs

public sealed class MaterialRiskChangeDetector
{
    // Detection rules
    public IReadOnlyList<DetectedChange> Detect(
        RiskStateSnapshot previous,
        RiskStateSnapshot current)
    {
        // R1: Reachability flip
        // R2: VEX status flip
        // R3: Range boundary cross
        // R4: Intelligence/Policy flip
    }
}

Risk State Snapshot: RiskStateSnapshot

Location: src/Scanner/__Libraries/StellaOps.Scanner.SmartDiff/Detection/RiskStateSnapshot.cs

public sealed record RiskStateSnapshot
{
    public bool? Reachable { get; init; }
    public VexClaimStatus VexStatus { get; init; }
    public bool? InAffectedRange { get; init; }
    public bool Kev { get; init; }
    public double? EpssScore { get; init; }
    public PolicyDecision PolicyDecision { get; init; }
    public string? LatticeState { get; init; }

    // SHA-256 hash for deterministic change detection
    public string ComputeHash() => SHA256.Hash(CanonicalJson);
}

Reachability Drift Detector: ReachabilityDriftDetector

Location: src/Scanner/__Libraries/StellaOps.Scanner.ReachabilityDrift/Services/ReachabilityDriftDetector.cs

public sealed class ReachabilityDriftDetector
{
    public Task<DriftDetectionResult> DetectAsync(
        string baseScanId,
        string headScanId,
        CancellationToken cancellationToken);
}

Drift Cause Explainer: DriftCauseExplainer

Location: src/Scanner/__Libraries/StellaOps.Scanner.ReachabilityDrift/Services/DriftCauseExplainer.cs

public sealed class DriftCauseExplainer
{
    // Explains why reachability changed
    public DriftCause Explain(
        CallGraphSnapshot baseGraph,
        CallGraphSnapshot headGraph,
        string sinkId);
}

public sealed record DriftCause
{
    public DriftCauseKind Kind { get; init; }  // Maps to "reasonCode"
    public string Description { get; init; }
    public string? ChangedSymbol { get; init; }
    public string? ChangedFile { get; init; }
    public int? ChangedLine { get; init; }
    public string? CodeChangeId { get; init; }  // Maps to "evidenceRefs"
}

public enum DriftCauseKind
{
    GuardRemoved,  // "GUARD_REMOVED"
    NewPublicRoute,  // "NEW_PUBLIC_ROUTE"
    VisibilityEscalated,  // "VISIBILITY_ESCALATED"
    DependencyUpgraded,  // "DEPENDENCY_UPGRADED"
    SymbolRemoved,  // "SYMBOL_REMOVED"
    GuardAdded,  // "GUARD_ADDED"
    Unknown  // "UNKNOWN"
}

API Endpoints:

  • GET /smart-diff/scans/{scanId}/changes - Material risk changes
  • GET /smart-diff/scans/{scanId}/sarif - SARIF 2.1.0 format
  • GET /smart-diff/images/{digest}/candidates - VEX candidates

Database Schema:

  • Table: scanner.triage_snapshots
  • Table: scanner.risk_state_snapshots
  • Table: scanner.material_risk_changes
  • Table: scanner.call_graph_snapshots

Equivalence Proof:

  • Subject: AssetId
  • From/To Version: FromVersion, ToVersion
  • Changed packages: In DiffJson + package-level diffs
  • Changed symbols: Reachability drift detection
  • Changed vulns: Material risk changes
  • Explainable reasons: DriftCause with Kind (reason code)
  • Evidence refs: CodeChangeId, evidence artifacts

Signal-18: Decision

Advisory Specification

{
  "subject": "pkg:npm/lodash@4.17.0",
  "decisionId": "dec-abc123",
  "severity": "HIGH",
  "priority": 85,
  "rationale": [
    "Reachable from public API",
    "EPSS above threshold (0.85)",
    "No VEX from vendor"
  ],
  "actions": ["Block deployment", "Notify security team"],
  "dsseSignatures": ["dsse://sha256:..."]
}

Purpose: Policy decisions with rationale and signatures


StellaOps Implementation

Primary Entity: TriageDecision

Location: src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/TriageDecision.cs

public sealed class TriageDecision
{
    public string DecisionId { get; set; }  // Maps to "decisionId"
    public string FindingId { get; set; }  // Links to TriageFinding (subject)
    public string TenantId { get; set; }

    // Decision details
    public TriageDecisionKind Kind { get; set; }  // Mute, Acknowledge, Exception
    public string? Reason { get; set; }  // Maps to "rationale"
    public string? ReasonCode { get; set; }

    // Actor
    public string ActorSubject { get; set; }
    public string? ActorDisplayName { get; set; }

    // Policy reference
    public string? PolicyRef { get; set; }

    // Lifetime
    public DateTimeOffset EffectiveAt { get; set; }
    public DateTimeOffset? ExpiresAt { get; set; }
    public int? TtlDays { get; set; }

    // Reversibility
    public bool Revoked { get; set; }
    public DateTimeOffset? RevokedAt { get; set; }
    public string? RevokedBy { get; set; }

    // Signatures
    public string? DsseEnvelopeHash { get; set; }  // Maps to "dsseSignatures"
    public string? SignatureRef { get; set; }

    public DateTimeOffset CreatedAt { get; set; }
}

Risk Result (includes severity/priority): From TriageRiskResult

public sealed class TriageRiskResult
{
    public double RiskScore { get; set; }  // Maps to "priority" (0-100)
    public string Lane { get; set; }  // Maps to "severity" (Critical/High/Medium/Low)
    public TriageVerdict Verdict { get; set; }  // Maps to "actions" (Ship/Block/Exception)
    public string? LatticeExplanationJson { get; set; }  // Maps to "rationale" (structured)
}

Score Explanation Service: ScoreExplanationService

Location: src/Signals/StellaOps.Signals/Services/ScoreExplanationService.cs

public sealed class ScoreExplanationService
{
    // Generates structured rationale
    public ScoreExplanation Explain(ScoreExplanationRequest request)
    {
        // Returns breakdown of:
        // - CVSS contribution
        // - EPSS contribution
        // - Reachability contribution
        // - VEX reduction
        // - Gate discounts
        // - KEV bonus
    }
}

Decision Predicate Type: stella.ops/policy-decision@v1

Location: Defined in PredicateTypes.cs, implemented in attestations

Database Schema:

  • Table: scanner.triage_decisions
  • Table: scanner.triage_risk_results (for severity/priority)

API Endpoints:

  • POST /triage/decisions - Create decision
  • DELETE /triage/decisions/{decisionId} - Revoke decision
  • GET /triage/findings/{findingId}/decisions - List decisions for finding

Equivalence Proof:

  • Subject: Linked via FindingIdTriageFinding.Purl
  • Decision ID: DecisionId
  • Severity: TriageRiskResult.Lane
  • Priority: TriageRiskResult.RiskScore
  • Rationale: Reason + LatticeExplanationJson (structured)
  • Actions: Verdict (Ship/Block/Exception)
  • DSSE Signatures: DsseEnvelopeHash, SignatureRef

Idempotency Key Handling

Advisory Pattern

idemKey = hash(subjectDigest || type || runId || cve || windowStart)

StellaOps Implementation

Event Envelope Idempotency:

Location: src/Orchestrator/StellaOps.Orchestrator/StellaOps.Orchestrator.Core/Domain/Events/EventEnvelope.cs

public static string GenerateIdempotencyKey(
    OrchestratorEventType eventType,
    string? jobId,
    int attempt)
{
    var jobPart = jobId ?? "none";
    return $"orch-{eventType.ToEventTypeName()}-{jobPart}-{attempt}";
}

Pattern: {domain}-{event_type}-{entity_id}-{attempt}

Orchestrator Event Idempotency:

Location: src/Scanner/StellaOps.Scanner.WebService/Contracts/OrchestratorEventContracts.cs

public sealed record OrchestratorEvent
{
    public required string EventId { get; init; }
    public required string EventKind { get; init; }
    public required string IdempotencyKey { get; init; }  // Explicitly tracked
    public required string CorrelationId { get; init; }
    public required string TraceId { get; init; }
    public required string SpanId { get; init; }
    // ...
}

Finding ID Stability (Signal-14):

Pattern: {cve}@{purl}@{scanId}

Location: TriageFinding.FindingId generation logic

Equivalence:

  • Subject digest: Included in scanId or AssetId
  • Type: EventKind or EventType
  • Run ID: TraceId, CorrelationId, attempt
  • CVE: Included in finding ID
  • Window: Implicit in scan/job timing

Evidence Reference Mechanisms

Advisory Pattern

evidenceRefs[i] = dsse://sha256:<payloadHash>

Storage: DSSE payloads stored as blobs, indexed by payloadHash and subjectDigest


StellaOps Implementation

CAS URI Pattern:

cas://reachability/graphs/{blake3_hash}
cas://runtime/traces/{blake3_hash}

DSSE Reference Pattern:

{DsseEnvelopeHash} = SHA-256 of DSSE envelope
{SignatureRef} = Reference to attestor.envelopes table

Evidence Artifact Entity: TriageEvidenceArtifact

public sealed class TriageEvidenceArtifact
{
    public string ContentHash { get; set; }  // SHA-256 of content
    public string? SignatureRef { get; set; }  // DSSE envelope reference
    public string? CasUri { get; set; }  // CAS URI for content
    // ...
}

Reachability Evidence Chain: ReachabilityEvidenceChain

Location: src/__Libraries/StellaOps.Signals.Contracts/Models/Evidence/ReachabilityEvidenceChain.cs

public sealed record ReachabilityEvidenceChain
{
    public GraphEvidence? GraphEvidence { get; init; }
    public RuntimeEvidence? RuntimeEvidence { get; init; }
    public ImmutableArray<CodeAnchor> CodeAnchors { get; init; }
    public ImmutableArray<Unknown> Unknowns { get; init; }
}

public sealed record GraphEvidence
{
    public required string GraphHash { get; init; }  // BLAKE3
    public required string GraphCasUri { get; init; }  // cas://...
    public required string AnalyzerName { get; init; }
    public required string AnalyzerVersion { get; init; }
    public DateTimeOffset AnalyzedAt { get; init; }
}

public sealed record RuntimeEvidence
{
    public required string TraceHash { get; init; }  // BLAKE3
    public required string TraceCasUri { get; init; }  // cas://...
    public required string ProbeType { get; init; }
    public required int HitCount { get; init; }
    public DateTimeOffset LastSeenAt { get; init; }
}

Storage:

  • PostgreSQL: attestor.envelopes table for DSSE envelopes
  • PostgreSQL: scanner.triage_evidence_artifacts for evidence metadata
  • S3/MinIO: CAS storage for evidence blobs

Equivalence:

  • Hash-addressed storage: SHA-256, BLAKE3
  • DSSE references: DsseEnvelopeHash, SignatureRef
  • CAS URIs: cas:// scheme for content-addressable storage
  • Blob storage: S3-compatible object store
  • Index by subject: FindingId links to evidence

API Endpoint Mapping

Signal Advisory Endpoint StellaOps Endpoint
Signal-10 POST /sbom/intake POST /api/scanner/sboms/ingest
POST /api/signals/callgraph/ingest
Signal-12 POST /attestations Implicit via signing services
GET /api/attestor/envelopes/{hash}
Signal-14 GET /triage/facts/{findingId} GET /api/scanner/triage/findings/{findingId}
GET /api/scanner/triage/findings/{findingId}/evidence
Signal-16 GET /diff/{from}/{to} GET /api/smart-diff/scans/{scanId}/changes
GET /api/smart-diff/images/{digest}/candidates
Signal-18 POST /decisions POST /api/triage/decisions
GET /api/triage/findings/{findingId}/decisions

Component Architecture Alignment

Advisory Architecture

[ Sbomer ] → Signal-10 → [ Router ]
[ Attestor ] → Signal-12 → [ Router ]
[ Scanner.Worker ] → Signal-14 → [ Triage Store ]
[ Reachability.Engine ] → updates Signal-14
[ Smart-Diff ] → Signal-16 → [ Router ]
[ Deterministic-Scorer ] → Signal-18 → [ Router/Notify ]

StellaOps Architecture

[ Scanner.Emit ] → SbomIngestionService → PostgreSQL (scanner.sboms)
[ Attestor.ProofChain ] → DsseEnvelopeSigner → PostgreSQL (attestor.envelopes)
[ Scanner.Triage ] → TriageFinding + related entities → PostgreSQL (scanner.triage_*)
[ ReachabilityAnalyzer ] → PathWitnessBuilder → TriageReachabilityResult
[ SmartDiff + ReachabilityDrift ] → MaterialRiskChangeDetector → TriageSnapshot
[ Policy.Scoring engines ] → ScoreExplanationService → TriageRiskResult + TriageDecision
[ Router.Gateway ] → TransportDispatchMiddleware → Inter-service routing
[ TimelineIndexer ] → TimelineEventEnvelope → Event ordering & storage

Mapping:

  • Sbomer ↔ Scanner.Emit
  • Attestor ↔ Attestor.ProofChain
  • Scanner.Worker ↔ Scanner.Triage
  • Reachability.Engine ↔ ReachabilityAnalyzer
  • Smart-Diff ↔ SmartDiff + ReachabilityDrift
  • Deterministic-Scorer ↔ Policy.Scoring engines
  • Router/Timeline ↔ Router.Gateway + TimelineIndexer

Summary

Alignment Status: Fully Aligned (Conceptually)

While StellaOps uses domain-specific entity names instead of generic "Signal-X" labels, all signal concepts are implemented with equivalent or superior functionality:

  • Signal-10: SBOM intake via CallgraphIngestRequest, ISbomIngestionService
  • Signal-12: in-toto attestations with 19 predicate types, DSSE signing
  • Signal-14: Comprehensive triage entities (TriageFinding, TriageReachabilityResult, TriageRiskResult, TriageEffectiveVex)
  • Signal-16: Smart-diff with TriageSnapshot, MaterialRiskChange, explainable drift causes
  • Signal-18: TriageDecision with DSSE signatures and structured rationale

Key Advantages of StellaOps Implementation:

  1. Type Safety: Strong entity types vs. generic JSON blobs
  2. Relational Integrity: PostgreSQL foreign keys enforce referential integrity
  3. Query Performance: Indexed tables for fast lookups
  4. Domain Clarity: Names reflect business concepts (Triage, Risk, Evidence)
  5. Extensibility: Easy to add new fields/entities without breaking contracts

Recommendation: Maintain current architecture and entity naming. Provide this mapping document to demonstrate compliance with advisory signal patterns.


References

StellaOps Code Files

  • src/Signals/StellaOps.Signals/Models/CallgraphIngestRequest.cs
  • src/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Statements/InTotoStatement.cs
  • src/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/*.cs
  • src/Scanner/__Libraries/StellaOps.Scanner.SmartDiff/Detection/MaterialRiskChangeDetector.cs
  • src/Scanner/__Libraries/StellaOps.Scanner.ReachabilityDrift/Services/*.cs
  • src/Signer/StellaOps.Signer/StellaOps.Signer.Core/PredicateTypes.cs

Advisory References

StellaOps Documentation

  • docs/07_HIGH_LEVEL_ARCHITECTURE.md
  • docs/modules/scanner/architecture.md
  • docs/modules/attestor/transparency.md
  • docs/contracts/witness-v1.md