Files
git.stella-ops.org/docs/modules/signals/architecture.md

14 KiB

Signals Module Architecture

Overview

The Signals module provides a unified evidence-weighted scoring system for vulnerability findings. It aggregates evidence from multiple sources (reachability analysis, runtime observations, backport detection, exploit intelligence, source trust, and mitigations) into a single 0-100 score that enables rapid triage.

Module Purpose

  • Unify Scoring: Combine disparate evidence signals into one actionable score
  • Enable Triage: Support sorting, filtering, and prioritization by evidence strength
  • Maintain Determinism: Same inputs + policy = same score, always
  • Provide Transparency: Decomposable scores with explanations

Location

src/Signals/
├── StellaOps.Signals/
│   └── EvidenceWeightedScore/
│       ├── EvidenceWeightedScoreCalculator.cs
│       ├── EvidenceWeightedScoreInput.cs
│       ├── EvidenceWeightedScoreResult.cs
│       ├── Normalizers/
│       │   ├── BackportEvidenceNormalizer.cs
│       │   ├── ExploitLikelihoodNormalizer.cs
│       │   ├── MitigationNormalizer.cs
│       │   ├── ReachabilityNormalizer.cs
│       │   ├── RuntimeSignalNormalizer.cs
│       │   └── SourceTrustNormalizer.cs
│       ├── Guardrails/
│       │   └── ScoreGuardrails.cs
│       └── Policy/
│           ├── EvidenceWeightPolicy.cs
│           └── EvidenceWeightPolicyProvider.cs
└── __Tests/
    └── StellaOps.Signals.Tests/
        └── EvidenceWeightedScore/

Core Concepts

Evidence Dimensions

Dimension Symbol Description Source Module
Reachability RCH Code path reachability to vulnerable sink Policy
Runtime RTS Live observation strength (eBPF/dyld/ETW) Policy
Backport BKP Patch evidence from distro/changelog/binary Concelier
Exploit XPL Exploit probability (EPSS + KEV) Scanner, Concelier
Source Trust SRC VEX source trustworthiness Excititor
Mitigations MIT Active protective controls Policy

Scoring Formula

Score = clamp01(W_rch*RCH + W_rts*RTS + W_bkp*BKP + W_xpl*XPL + W_src*SRC - W_mit*MIT) * 100

Note: MIT is subtractive — mitigations reduce risk.

Guardrails

Hard caps and floors based on evidence conditions:

  1. Not-Affected Cap: If vendor says not-affected (BKP=1) and no runtime contradiction (RTS<0.6), cap at 15
  2. Runtime Floor: If strong live signal (RTS>=0.8), floor at 60
  3. Speculative Cap: If no reachability and no runtime (RCH=0, RTS=0), cap at 45

Score Buckets

Bucket Range Meaning
ActNow 90-100 Strong evidence of exploitable risk; immediate action
ScheduleNext 70-89 Likely real; schedule for next sprint
Investigate 40-69 Moderate evidence; investigate when touching component
Watchlist 0-39 Low/insufficient evidence; monitor

Architecture

Component Diagram

┌─────────────────────────────────────────────────────────────────┐
│                        Signals Module                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────┐    ┌──────────────────────────────────┐   │
│  │ NormalizerAggr. │───▶│ EvidenceWeightedScoreCalculator  │   │
│  └────────┬────────┘    └──────────────┬───────────────────┘   │
│           │                            │                        │
│           ▼                            ▼                        │
│  ┌─────────────────┐    ┌──────────────────────────────────┐   │
│  │   Normalizers   │    │        ScoreGuardrails           │   │
│  │ ┌─────┐ ┌─────┐ │    └──────────────────────────────────┘   │
│  │ │ BKP │ │ XPL │ │                                           │
│  │ └─────┘ └─────┘ │    ┌──────────────────────────────────┐   │
│  │ ┌─────┐ ┌─────┐ │    │   EvidenceWeightPolicyProvider   │   │
│  │ │ MIT │ │ RCH │ │    └──────────────────────────────────┘   │
│  │ └─────┘ └─────┘ │                                           │
│  │ ┌─────┐ ┌─────┐ │                                           │
│  │ │ RTS │ │ SRC │ │                                           │
│  │ └─────┘ └─────┘ │                                           │
│  └─────────────────┘                                           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
           │                          │
           ▼                          ▼
┌─────────────────────┐   ┌───────────────────────────────────────┐
│   External Modules  │   │            Consumers                  │
│                     │   │                                       │
│ • Policy (RCH, RTS) │   │ • Policy Engine (verdict enrichment)  │
│ • Concelier (BKP)   │   │ • Findings API (score endpoints)      │
│ • Scanner (XPL)     │   │ • Web UI (score components)           │
│ • Excititor (SRC)   │   │                                       │
└─────────────────────┘   └───────────────────────────────────────┘

Data Flow

  1. Finding arrives for scoring
  2. NormalizerAggregator collects evidence from source modules
  3. Individual normalizers convert raw evidence to 0-1 values
  4. EvidenceWeightedScoreCalculator applies formula
  5. ScoreGuardrails apply caps/floors
  6. Result returned with score, bucket, breakdown, explanations

Policy Configuration

Weight policies are loaded from YAML and can vary by:

  • Tenant: Different organizations may prioritize differently
  • Environment: Production may weight runtime higher than dev
  • Policy version: Changes are versioned for reproducibility
version: "ews.v1"
profile: production

weights:
  rch: 0.30
  rts: 0.25
  bkp: 0.15
  xpl: 0.15
  src: 0.10
  mit: 0.10

guardrails:
  not_affected_cap:
    enabled: true
    max_score: 15
  runtime_floor:
    enabled: true
    min_score: 60
  speculative_cap:
    enabled: true
    max_score: 45

Integration Points

Inbound (Evidence Sources)

Source Data Interface
Policy/ConfidenceCalculator ReachabilityEvidence, RuntimeEvidence Direct type reference
Concelier/BackportProofService ProofBlob Direct type reference
Scanner/EpssPriorityCalculator EPSS score, percentile Direct type reference
Concelier/VendorRiskSignalExtractor KEV status Direct type reference
Excititor/TrustVector Trust vector components Direct type reference
Policy/GateMultipliers Active mitigations Direct type reference

Outbound (Consumers)

Consumer Usage
Policy Engine Verdict enrichment, score-based rules
Findings API Score endpoints (calculate, get, history)
Web UI Score display components
Webhooks Score change notifications
Attestor Scoring proofs in attestations

Determinism

The Signals module maintains strict determinism:

  1. Same inputs + same policy = same score: No randomness, no time-dependent factors in formula
  2. Policy versioning: Every policy has a digest; scores include policy digest
  3. Reproducible proofs: Scoring proofs can be verified by recalculation
  4. Stable ordering: Input order doesn't affect result

Performance

Metric Target
Single score calculation <10ms
Batch (100 findings) <1s
Policy load <100ms
Cache hit ratio >80%

Testing Strategy

Level Focus Location
L0 Unit Calculator, normalizers, guardrails *.Tests
L0 Property Monotonicity, bounds, determinism *.Tests/Properties
S1 Integration Cross-module evidence flow *.Tests/Integration
S1 Snapshot Result JSON structure *.Tests/Snapshots
  • Product Advisory: docs/product-advisories/24-Dec-2025 - Evidence-Weighted Score Model.md
  • Sprint Plans: docs/implplan/SPRINT_8200_0012_*.md
  • Policy Confidence (deprecated): docs/modules/policy/confidence-scoring.md
  • Backport Detection: docs/modules/concelier/backport-detection.md
  • EPSS Enrichment: docs/modules/scanner/epss-enrichment.md
  • Trust Vector: docs/modules/excititor/trust-vector.md

SCM/CI Integration (Webhooks)

The Signals module also handles webhook ingestion from SCM (Source Code Management) and CI (Continuous Integration) providers. This enables:

  • Triggering scans on push/PR/release events
  • SBOM uploads from CI pipelines
  • Image push detection and automated scanning

Location

src/Signals/StellaOps.Signals/Scm/
├── Models/
│   ├── NormalizedScmEvent.cs      # Provider-agnostic event payload
│   ├── ScmEventType.cs            # Event type enumeration
│   └── ScmProvider.cs             # Provider enumeration
├── Webhooks/
│   ├── IWebhookSignatureValidator.cs
│   ├── GitHubWebhookValidator.cs  # HMAC-SHA256 validation
│   ├── GitLabWebhookValidator.cs  # Token-based validation
│   ├── GiteaWebhookValidator.cs   # HMAC-SHA256 validation
│   ├── IScmEventMapper.cs
│   ├── GitHubEventMapper.cs       # GitHub -> NormalizedScmEvent
│   ├── GitLabEventMapper.cs       # GitLab -> NormalizedScmEvent
│   └── GiteaEventMapper.cs        # Gitea -> NormalizedScmEvent
├── Services/
│   ├── IScmWebhookService.cs
│   ├── ScmWebhookService.cs       # Orchestrates validation + mapping
│   ├── IScmTriggerService.cs
│   └── ScmTriggerService.cs       # Routes events to Scanner/Orchestrator
└── ScmWebhookEndpoints.cs         # Minimal API webhook endpoints

Supported Providers

Provider Webhook Endpoint Signature Header Validation
GitHub /webhooks/github X-Hub-Signature-256 HMAC-SHA256
GitLab /webhooks/gitlab X-Gitlab-Token Token match
Gitea /webhooks/gitea X-Gitea-Signature HMAC-SHA256

Event Types

Event Type Description Triggers
Push Code push to branch Scan (main/release branches)
PullRequestOpened PR opened
PullRequestMerged PR merged Scan
ReleasePublished Release created Scan
ImagePushed Container image pushed Scan
PipelineSucceeded CI pipeline completed Scan
SbomUploaded SBOM artifact uploaded SBOM ingestion

Webhook Payload Normalization

All provider-specific payloads are normalized to NormalizedScmEvent:

public sealed record NormalizedScmEvent
{
    public required string EventId { get; init; }
    public ScmProvider Provider { get; init; }
    public ScmEventType EventType { get; init; }
    public DateTimeOffset Timestamp { get; init; }
    public required ScmRepository Repository { get; init; }
    public ScmActor? Actor { get; init; }
    public string? Ref { get; init; }
    public string? CommitSha { get; init; }
    public ScmPullRequest? PullRequest { get; init; }
    public ScmRelease? Release { get; init; }
    public ScmPipeline? Pipeline { get; init; }
    public ScmArtifact? Artifact { get; init; }
    public string? TenantId { get; init; }
    public string? IntegrationId { get; init; }
}

Trigger Routing

The ScmTriggerService determines which events should trigger:

  1. Scans: Push to main/release, PR merges, releases, image pushes, successful pipelines
  2. SBOM uploads: Explicit SbomUploaded events or artifact releases with SBOM content

Security

  • Signature verification: All webhooks validate signatures before processing
  • AuthRef integration: Webhook secrets are managed via AuthRef (not stored in code)
  • Rate limiting: Built-in rate limiting to prevent webhook floods
  • Audit trail: All webhook deliveries are logged with delivery ID and result