Signals
The reachability and runtime-evidence plane for Stella Ops — call graphs, reachability facts, and runtime observations that make vulnerability verdicts reachability-aware.
Status: Implemented Source: src/Signals/ Owner: Policy Guild
Purpose
Signals is the reachability and runtime-evidence plane. It ingests and serves call graphs, reachability facts, runtime facts (observed symbol execution), unknown symbols, execution evidence, and verification beacons over an HTTP API under /signals (plus SCM/CI webhooks under /webhooks and a compatibility /api/v1/signals surface), owns the signals PostgreSQL schema, and publishes signals.fact.updated.v1 (reachability) and runtime.updated events. The host also owns the tenant-scoped /api/v1/score evaluation, history, weights, replay, verification, and explanation surface backed by signals.score_history; its established OAuth claims are the canonical score.read and score.evaluate scopes.
Components
Host:
StellaOps.Signals- Minimal-API host: ingest/serve endpoints (Program.cs), the/webhooks/{github,gitlab,gitea}SCM endpoints (Scm/ScmWebhookEndpoints.cs), the/api/v1/signalscompatibility surface (CompatibilityApiV1Endpoints.cs), theHotSymbolsController/RuntimeAgentController/RuntimeFactsControllerMVC controllers, and the EWS / Unified Score scoring code (EvidenceWeightedScore/,UnifiedScore/).
Libraries / referenced projects:
StellaOps.Signals.Persistence- PostgreSQL repositories + embedded SQL migrations (schema:signals)StellaOps.Signals.RuntimeAgent- Runtime evidence agent abstractions (CLR EventPipe viaDotNetEventPipeAgent); referenced by the host and surfaced throughRuntimeAgentControllerStellaOps.Signals.Scheduler- Scheduler queue client (SchedulerQueueJobClient) for unknowns rescan jobsStellaOps.Signals.Ebpf- eBPF micro-witness support (probe loaders, NDJSON evidence writer, chunk signing)
Evidence Normalizers (EWS scoring code, EvidenceWeightedScore/Normalizers/):
- Reachability (RCH) - Code path reachability to vulnerable sink
- Runtime (RTS) - Live observation strength (eBPF/dyld/ETW)
- Backport (BKP) - Patch evidence from distro/changelog/binary
- Exploit (XPL) - Exploit probability (EPSS + KEV)
- Source Trust (SRC) - VEX source trustworthiness
- Mitigation (MIT) - Active mitigation effectiveness
HTTP API
All /signals/* handlers authorize per-request via Program.TryAuthorize (Authority bearer token or X-Scopes header dev fallback) and run the sealed-mode gate (SignalsSealedModeMonitor). Scopes are defined in Routing/SignalsPolicies.cs and the canonical catalog StellaOpsScopes (signals:read / signals:write / signals:admin). See ./architecture.md and ./api-reference.md for the full route reference. Highlights:
| Method | Route | Scope | Notes |
|---|---|---|---|
| GET | /signals/ping, /signals/status | signals:read | Liveness / version + sealed-mode status. |
| POST | /signals/callgraphs | signals:write | Ingest a call graph; 202 + callgraphId. Audited. |
| GET | /signals/callgraphs/{id} , /{id}/manifest | signals:read | Fetch document / stream manifest blob. |
| POST | /signals/runtime-facts , /runtime-facts/ndjson | signals:write | Ingest runtime facts (JSON or gzip-aware NDJSON). Audited. |
| POST | /signals/runtime-facts/synthetic | signals:write | Local-harness only (not mapped in production). Audited. |
| GET | /signals/facts/{subjectKey} | signals:read | Fetch the reachability fact for a subject. |
| POST | /signals/reachability/union | signals:write | Ingest a union graph (application/zip, X-Analysis-Id). Audited. |
| GET | /signals/reachability/union/{analysisId}/meta , /files/{fileName} | signals:read | Stream union artifacts. |
| POST | /signals/reachability/recompute | signals:admin | Recompute a reachability fact. Audited. |
| POST/GET | /signals/unknowns (+ /{subjectKey}, /{id}/explain) | signals:write / signals:read | Ingest / query / explain unknown symbols. Ingest audited. |
| POST | /signals/execution-evidence | signals:write | Build execution evidence; 202 / rate_limited / 422. Audited. |
| POST/GET | /signals/beacons , /beacons/rate/{artifactId}/{environmentId} | signals:write / signals:read | Verification beacon ingest / rate query. Ingest audited. |
| GET | /api/v1/signals/hot-symbols (+ /top, /stats, /correlated) | — (controller) | Hot-symbol index queries by image digest (HotSymbolsController). |
| POST/GET/DELETE/PATCH | /api/v1/agents (+ /{agentId} , /register , /heartbeat , /commands , /posture , /{agentId}/facts) | — (controller) | Runtime-agent registration, heartbeat, commands, posture, facts ingest. |
| POST | /api/v1/runtime/observations | Anonymous (network-edge trust) | Deployment-observation agent dual-write into signals.runtime_facts tagged with release_id; 503 when no durable PostgreSQL is configured. |
| POST | /webhooks/{github,gitlab,gitea} | Anonymous + HMAC/token signature | SCM/CI webhook ingest (scan/SBOM trigger evaluation); 202 on success. |
| GET | /api/v1/signals , /api/v1/signals/stats | signals:read or orch:read | Compatibility list/stats surface — see Current Status (serves static demo records, not live data). |
| GET | /api/v1/score/{id}, /history, /weights*, /explain/{digest}, /{id}/replay | score.read | Tenant-scoped unified-score reads. |
| POST | /api/v1/score/evaluate | score.read + score.evaluate | Compute and persist a unified score. Audited. |
| POST | /api/v1/score/verify | score.read | Re-execute and compare a replay envelope. Audited. |
| GET | /healthz , /readyz , /openapi/v1.json , /api/v1/buildinfo | Anonymous | Health, readiness (sealed-mode aware), OpenAPI discovery, image provenance. |
Configuration
See etc/signals.yaml.sample for configuration options (section Signals:).
Key settings (all under the Signals: root, bound to SignalsOptions):
Postgres— PostgreSQL connection (schema:signals, auto-migrated on startup); the connection string is also resolved fromConnectionStrings:Signals/Postgres:Signals:ConnectionString/Signals__Postgres__ConnectionStringAuthority— OIDC resource-server integration (issuer, audiences, required scopes/tenants, bypass networks, anonymous fallback)Storage— artifact-store driver (filesystemdefault, orrustfsfor CAS-backed; bucketsignals-data)Scoring— reachability confidence parameters (reachable/unreachable confidence, runtime bonus, min/max)Cache— Redis-backed reachability-fact cache (always Redis;ConnectionString,DefaultTtlSeconds)Events— event publishing (Driver:redis/router/inmemory;Stream,DeadLetterStream, producer/pipeline metadata)Retention— retention policy for runtime facts and artifacts (SignalsRetentionOptions)Scm— SCM/CI webhook signature-validation settings (SignalsScmWebhookOptions)AirGap— optional air-gap event topic override andSealedModeenforcement (evidence path, age, cache lifetime)OpenApi— OpenAPI document exposure- EWS weight manifests — versioned JSON under
etc/weights/(e.g.v2026-01-22.weights.json), loaded byFileBasedWeightManifestLoaderwhen the scoring code is used
Dependencies
- PostgreSQL (schema:
signals) - Authority (authentication)
- Redis/Valkey (reachability-fact cache)
- Stella Router / messaging (event publishing)
- Scheduler (unknowns rescan jobs)
- RustFS object store (production artifact storage)
Signals has no build-time project references to Policy, Concelier, Scanner, or Excititor. Evidence reaches Signals over its HTTP ingest API, not via direct module calls.
Persistence (schema: signals)
Embedded SQL migrations live in StellaOps.Signals.Persistence/Migrations/ and apply on startup. 001_v1_signals_baseline.sql is the collapsed v1 baseline; 002_v1_score_history.sql adds the unified-score history store. The earlier 001–005 source migrations are archived pre-v1 history. Tables include:
- Static analysis / call graph:
scans,artifacts,cg_nodes,cg_edges,entrypoints,symbol_component_map,callgraphs,func_nodes,call_edges - Reachability:
reachability_components,reachability_findings,reachability_facts,cve_func_hits - Runtime:
runtime_samples,runtime_agents,runtime_facts(including release and optional stack-frame evidence),agent_heartbeats,agent_commands - Deployment / metrics / triage:
deploy_refs,graph_metrics,unknowns - Unified score: tenant-scoped
score_history
Migration policy is forward-only (ADR-004). Without a configured PostgreSQL connection the host falls back to in-memory repositories only in the explicit local-harness mode.
Related Documentation
- Architecture:
./architecture.md - API reference:
./api-reference.md - Unified Score:
./unified-score.md - Contract:
./contracts/ebpf-micro-witness-determinism-profile.md - Policy Engine:
../policy/ - VexLens:
../vex-lens/ - High-Level Architecture:
../../ARCHITECTURE_OVERVIEW.md
Current Status
Implemented: callgraph / reachability / runtime-facts / unknowns ingest and serve over HTTP, hot-symbol and runtime-agent controllers, SCM/CI webhook ingest, durable signals PostgreSQL schema (auto-migrated), artifact storage (filesystem / RustFS CAS), reachability-fact events (signals.fact.updated.v1) and runtime-update events (runtime.updated), and the six-dimension EWS / Unified Score scoring code with deterministic scoring and evidence decomposition, plus the live /api/v1/score surface and durable score history.
Caveats grounded in source:
- Two score abstractions coexist. The live HTTP surface is implemented by
ScoreEvaluationServiceunderScore/; the olderUnifiedScore/facade remains an in-process library and is not the endpoint handler itself. - Compatibility
/api/v1/signalsreturns static demo records.CompatibilityApiV1Endpointsserves five hardcoded fixture records (sig-001…sig-005) and aggregate stats derived from them — it is a UI/contract compatibility shim, not a query over ingested data.
