- 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.
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 ingestionPOST /api/signals/callgraph/ingest- Call graph + SBOM ingestion
Related Files:
src/Scanner/StellaOps.Scanner.WebService/Endpoints/SbomEndpoints.cssrc/Signals/StellaOps.Signals/Services/CallgraphIngestionService.cssrc/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:
CreatedAtin 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.jsonsrc/Attestor/StellaOps.Attestor.Types/samples/vex-attestation.v1.jsonsrc/Attestor/StellaOps.Attestor.Types/samples/scan-results.v1.json
Equivalence Proof:
- ✅ Subject:
Subjectlist 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
TriageReachabilityResultentity - ✅ EPSS:
EpssScore,EpssPercentile,EpssModelDate - ✅ CVSS:
CvssBaseScore,CvssVector,CvssVersion - ✅ VEX Status:
TriageEffectiveVex.Status - ✅ Notes:
LatticeExplanationJson - ✅ Evidence Refs:
TriageEvidenceArtifactwithContentHash,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 changesGET /smart-diff/scans/{scanId}/sarif- SARIF 2.1.0 formatGET /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:
DriftCausewithKind(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 decisionDELETE /triage/decisions/{decisionId}- Revoke decisionGET /triage/findings/{findingId}/decisions- List decisions for finding
Equivalence Proof:
- ✅ Subject: Linked via
FindingId→TriageFinding.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
scanIdorAssetId - ✅ Type:
EventKindorEventType - ✅ 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.envelopestable for DSSE envelopes - PostgreSQL:
scanner.triage_evidence_artifactsfor 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:
FindingIdlinks to evidence
API Endpoint Mapping
| Signal | Advisory Endpoint | StellaOps Endpoint |
|---|---|---|
| Signal-10 | POST /sbom/intake |
POST /api/scanner/sboms/ingestPOST /api/signals/callgraph/ingest |
| Signal-12 | POST /attestations |
Implicit via signing servicesGET /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}/changesGET /api/smart-diff/images/{digest}/candidates |
| Signal-18 | POST /decisions |
POST /api/triage/decisionsGET /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:
TriageDecisionwith DSSE signatures and structured rationale
Key Advantages of StellaOps Implementation:
- Type Safety: Strong entity types vs. generic JSON blobs
- Relational Integrity: PostgreSQL foreign keys enforce referential integrity
- Query Performance: Indexed tables for fast lookups
- Domain Clarity: Names reflect business concepts (Triage, Risk, Evidence)
- 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.cssrc/Attestor/__Libraries/StellaOps.Attestor.ProofChain/Statements/InTotoStatement.cssrc/Scanner/__Libraries/StellaOps.Scanner.Triage/Entities/*.cssrc/Scanner/__Libraries/StellaOps.Scanner.SmartDiff/Detection/MaterialRiskChangeDetector.cssrc/Scanner/__Libraries/StellaOps.Scanner.ReachabilityDrift/Services/*.cssrc/Signer/StellaOps.Signer/StellaOps.Signer.Core/PredicateTypes.cs
Advisory References
- Advisory architecture document (CycloneDX 1.7 / VEX-first / in-toto)
- Signal contracts specification (10/12/14/16/18)
- DSSE specification: https://github.com/secure-systems-lab/dsse
- in-toto attestation framework: https://github.com/in-toto/attestation
StellaOps Documentation
docs/07_HIGH_LEVEL_ARCHITECTURE.mddocs/modules/scanner/architecture.mddocs/modules/attestor/transparency.mddocs/contracts/witness-v1.md