StellaOps Excititor (absorbed into the Concelier domain — Sprint 203)
Status: Excititor source code now lives under
src/Concelier/StellaOps.Excititor.*following the advisory-domain consolidation (Sprint 203, 2026-03-04). This page is retained as the canonical Excititor reference and redirect; the full historical archive is atdocs-archive/modules/excititor/, and the ADR is recorded in../concelier/architecture.md.
Excititor is the StellaOps VEX aggregation service. It converts heterogeneous VEX feeds (OpenVEX, CSAF, CycloneDX) into raw, provenance-tagged observations and append-only linksets that honour the Aggregation-Only Contract (AOC). It is strictly aggregation-only: it stores and serves raw observations and linksets and does not compute consensus, merged severity, or derived status — those concerns moved to the Policy Engine / VEX Lens (see “Aggregation-only posture” below).
Audience: operators wiring VEX connectors and offline mirrors, and integrators consuming Excititor observations, linksets, the Risk-Engine feed, or the VEX evidence/chunk APIs.
Latest updates (verified 2026-05-30)
- Excititor remains source-resident under
src/Concelier/StellaOps.Excititor.*; the WebService host isStellaOps.Excititor.WebServiceand the scheduled ingest host isStellaOps.Excititor.Worker. - Observability/runbook assets live in
operations/observability.md,operations/chunk-telemetry.md, andobservability/(timeline events, locker manifests); dashboards stay offline-import friendly. - The evidence/normalization telemetry surface (request counters, statement histogram, signature status, guard violations) is described in the observability guide.
Aggregation-only posture (orphaned consensus content corrected, 2026-05-30): Earlier revisions of this README promoted an “Excititor consensus beta” and pointed at
docs/vex/consensus-json.md, weighting knobs, and DSSE consensus-bundle packaging. Consensus computation was removed from Excititor underEXCITITOR-CORE-AOC-19-004(seeoperations/consensus-removal-runbook.md). The Worker ships withDisableConsensus=trueand AOC guards reject any derived field (mergedSeverity,consensusScore,computedStatus). Treat any remaining consensus references in this module’s history as superseded; consensus now lives in Policy / VEX Lens.
Release references
- Mirror / Offline Kit export packaging:
mirrors.mdand docs/modules/export-center/devportal-offline.md - Module change log:
changes.md
Responsibilities
- Fetch OpenVEX/CSAF/CycloneDX statements via connectors (formats:
StellaOps.Excititor.Formats.OpenVEX,…Formats.CSAF,…Formats.CycloneDX). - Store immutable, append-only VEX observations with full provenance and content/signature metadata.
- Extract append-only linksets (alias + product mappings with provider disagreement tracking) from observations.
- Emit timeline events and a Risk-Engine-ready feed; never derive consensus or severity.
- Provide deterministic exports (mirror domains, evidence bundles) for Offline Kit and downstream tooling.
Key components
StellaOps.Excititor.WebService— API host (observations, linksets, providers, evidence, attestations, mirror, risk feed, graph overlays, timeline SSE).StellaOps.Excititor.Worker— scheduled / orchestrated ingest host (per-tenant Authority client, signature verification, VexHub projection).StellaOps.Excititor.Core— domain models (VexObservation,VexLinkset,VexClaim, status/justification enums), AOC guards, canonicalization.StellaOps.Excititor.Persistence— PostgreSQL storage (auto-migrating; embedded SQL underMigrations/).- Connector libraries under
StellaOps.Excititor.Connectors.*(see “Connectors” below). - Format normalizers (
StellaOps.Excititor.Formats.*), exporters (StellaOps.Excititor.Export), attestation (StellaOps.Excititor.Attestation), policy lookup (StellaOps.Excititor.Policy), and artifact stores (StellaOps.Excititor.ArtifactStores.S3, file-system, offline bundle).
Connectors
Seven VEX providers are wired (canonical IDs use the excititor: prefix). RedHat, Ubuntu, Oracle, and Cisco are seeded at runtime startup; SUSE Rancher, OCI OpenVEX, and MSRC are seeded by the consolidated baseline 001_v1_excititor_baseline.sql (provider-seed block at lines 865-885, folded in from the pre-1.0 008_seed_csaf_providers.sql); msrc and oci-openvex ship enabled=false:
| Provider ID | Kind | Connector library |
|---|---|---|
excititor:redhat | vendor (CSAF) | StellaOps.Excititor.Connectors.RedHat.CSAF |
excititor:ubuntu | vendor (CSAF) | StellaOps.Excititor.Connectors.Ubuntu.CSAF |
excititor:oracle | vendor (CSAF) | StellaOps.Excititor.Connectors.Oracle.CSAF |
excititor:cisco | vendor (CSAF) | StellaOps.Excititor.Connectors.Cisco.CSAF |
excititor:suse-rancher | hub | StellaOps.Excititor.Connectors.SUSE.RancherVEXHub |
excititor:oci-openvex | attestation | StellaOps.Excititor.Connectors.OCI.OpenVEX.Attest |
excititor:msrc | vendor (CSAF) | StellaOps.Excititor.Connectors.MSRC.CSAF |
A StellaOps mirror connector (StellaOps.Excititor.Connectors.StellaOpsMirror) consumes mirror exports for air-gap re-ingest. Each connector binds from Excititor:Connectors:<Name> so air-gap operators can repoint URLs without code changes. Provider control-plane inventory and readiness notes: operations/provider-control-plane.md. Per-connector credentials: operations/provider-credentials.md. Ubuntu CSAF provenance knobs (TrustWeight/Tier, cosign, fingerprint): operations/ubuntu-csaf.md.
API surface & scopes
Routes are served by StellaOps.Excititor.WebService. Authorization is enforced by the gateway JWT bearer middleware plus per-endpoint scope checks. The canonical scope catalog (StellaOps.Auth.Abstractions.StellaOpsScopes) declares vex:read (VexRead), vex:ingest (VexIngest), and vex.admin (VexAdmin); the service additionally accepts the dotted aliases vex.read and vex.ingest, and uses vex.attest for Rekor attestation operations. Endpoints resolve the tenant from the X-StellaOps-TenantId header (falling back to the configured default tenant).
| Route family | Methods | Scope | Notes |
|---|---|---|---|
/excititor/status, /excititor/health | GET | anonymous | Service readiness / health |
/obs/excititor/health | GET | vex:read | Authenticated operational health; storage.connectionState distinguishes measured connected data from an unavailable degraded dependency |
/.well-known/openapi, /openapi/excititor.json | GET | anonymous | Generated OpenAPI 3.1.1 discovery + runtime spec |
/vex/observations, /vex/observations/{id}, /vex/observations/count | GET | vex.read | Raw observations (no derived verdict fields) |
/vex/linksets, /vex/linksets/{id}, /vex/linksets/lookup, /vex/linksets/count, /vex/linksets/conflicts | GET | vex.read | Alias/product linksets + disagreement markers (ERR_AGG_* errors) |
/excititor/init, /excititor/ingest/run, /excititor/ingest/resume, /excititor/reconcile | POST | vex.admin | Ingest control |
/excititor/providers, …/{id}, …/enable, …/disable, …/run, …/configuration, …/artifacts | GET/PUT/POST/DELETE | vex.read (read) / vex.admin (mutate) | Provider control plane |
/excititor/resolve, /policy/v1/vex/lookup | POST | vex.read | Resolve / policy lookup |
/excititor/mirror/domains/** | GET | anonymous (domain list/detail) / vex.read (index, export, download) | Mirror distribution |
/airgap/v1/vex/import, /airgap/v1/mirror/bundles/** | POST/GET | vex.admin (import) / vex.read (bundle queries) | Sealed air-gap bundles |
/evidence/vex/list, /evidence/vex/{bundleId}, /evidence/vex/locker/{bundleId}**, /v1/vex/evidence/chunks | GET | vex.read | Evidence bundles / chunk API |
/attestations/vex/list, /attestations/vex/{id} | GET | vex.read | VEX attestation records (DSSE state) |
/attestations/rekor/observations/{id}, …/batch, …/{id}/verify, /attestations/rekor/pending, /v1/attestations/verify | POST/GET | vex.attest (create) / vex.read (verify, pending) | Rekor transparency attestation |
/risk/v1/feed, /risk/v1/feed/item, /risk/v1/feed/by-advisory/{key}, /risk/v1/feed/by-artifact/** | POST/GET | vex.read | Risk-Engine feed (no derived severity) |
/v1/graph/status, /v1/graph/overlays, /v1/graph/observations, /internal/graph/linkouts | GET/POST | per-endpoint | Graph overlay surface |
/aoc/verify | POST | per-endpoint | Aggregation-Only Contract verifier |
/obs/excititor/timeline | GET (SSE) | vex.read | Timeline event stream (X-Next-Cursor) |
Detailed contracts: vex_observations.md, vex_linksets_api.md, api-reference.md, operations/evidence-api.md, operations/chunk-api-user-guide.md, and the pinned spec openapi/v1.json.
VEX status & justification values
VexClaimStatus (serialized): affected, not_affected, fixed, under_investigation. VexJustification carries the OpenVEX/CSAF justification vocabulary plus reachability-derived values (e.g. component_not_present, vulnerable_code_not_in_execute_path, code_not_reachable, protected_at_runtime). Linkset observation/disagreement rows constrain status to affected | not_affected | fixed | under_investigation.
Integrations & dependencies
- Policy Engine / VEX Lens consume observations + linksets and own all consensus/severity computation.
- UI/CLI for conflict visibility and explanation.
- Risk Engine consumes the
/risk/v1/feedsurface. - Authority (OAuth/OIDC) issues the
vex:*/vex.*scopes; the Worker uses a per-tenant Authority client. - IssuerDirectory (optional) enriches signature/tenant trust.
- Notify for VEX-driven alerts.
Operational notes
- PostgreSQL schemas
vex,vex_app, andexcititor(created by the consolidated baseline001_v1_excititor_baseline.sql, lines 49-51; live forward migrations continue at002–009). Storage auto-migrates on startup; SQL files directly underMigrations/are embedded resources (forward-only per ADR-004), while the pre-1.0 chain underMigrations/_archived/pre_1.0/mig061/is not embedded. - Core tables include
vex.linksets,vex.linkset_observations,vex.linkset_disagreements,vex.linkset_mutations(append-only replay log),vex.vex_raw_documents(+vex_raw_blobs,vex_raw_attachments),vex.timeline_events(monthly-partitioned), andexcititor.calibration_*/source_trust_vectors. Row-Level Security enforces tenant isolation viaapp.tenant_id. - Offline kit packaging aligned with Concelier mirror exports (
mirrors.md). - Connector-specific runbooks (see
docs/modules/concelier/operations/connectors). - Worker / tenant Authority client configuration:
operations/tenant-authority-client.md.
Backlog references
- DOCS-LNM-22-006 / DOCS-LNM-22-007 (shared with Concelier).
- CLI-EXC-25-001…002 follow-up for CLI parity.
Epic alignment
- Epic 1 – AOC enforcement: maintain immutable VEX observations, provenance, and AOC verifier coverage.
- Epic 7 – VEX Consensus Lens: supply trustworthy raw inputs, trust metadata, and consensus hooks for the lens computations.
- Epic 8 – Advisory AI: expose citation-ready VEX payloads for the advisory assistant pipeline.
Implementation Status
Objectives
- Maintain deterministic behaviour and offline parity across releases
- Keep documentation, telemetry, and runbooks aligned with the latest sprint outcomes
Key Milestones
- Epic 1 – AOC enforcement: enforce immutable VEX observation schema, provenance capture, and guardrails
- Epic 7 – VEX Consensus Lens: provide lens-ready metadata (issuer trust, temporal scoping) and consensus APIs
- Epic 8 – Advisory AI: guarantee citation-ready payloads and normalized context for AI summaries/explainers
Recent Delivery Status
- Chunk API is implemented (
/v1/vex/evidence/chunks) with a pinned spec (openapi/v1.json), deterministic samples (samples/chunks-sample.ndjson+.sha256), and a user guide (operations/chunk-api-user-guide.md). - Consensus computation removed from Excititor (
EXCITITOR-CORE-AOC-19-004); the module is now strictly aggregation-only and consensus lives in Policy / VEX Lens. - Observation/linkset APIs and the Risk-Engine feed shipped; observability guide and runbooks tracked under
operations/.
