307 lines
14 KiB
Markdown
307 lines
14 KiB
Markdown
# 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
|
|
|
|
```yaml
|
|
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` |
|
|
|
|
## Related Documentation
|
|
|
|
- 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`:
|
|
|
|
```csharp
|
|
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
|