Docs/Get started/Core concepts

Core concepts.

Four ideas explain most of the platform: a scan is a plan of tools in an untrusted band; a finding is a node in an ontology; lineage is a walk over provenance-tagged edges; a decision is a signed, fail-closed evaluation.

Reading time 10 minutesUpdated September 2026

1 · Scans and the tool plan

A scan targets a repository, an image, a URL, an API specification, a cloud account or a cluster. For repositories the orchestrator builds a tool plan: the native engine and the baseline tools always, plus language-specific tools from the languages it detects. Every tool runs in the same per-scan Kubernetes Job in the securityvault-scans namespace with a shared fetcher and one tool/adapter container pair per tool.

The scan moves through PENDING → QUEUED → RUNNING → COMPLETED | PARTIAL | FAILED | FAILED_TIMEOUT | FAILED_DEPENDENCY | FAILED_CONFIG. Each tool carries its own deadline persisted on the scan; the reaper turns a missed deadline into PARTIAL (other tools kept) or FAILED_TIMEOUT (nothing usable).

Scanners are hostile. No database, cache, vault or object-storage credentials exist in a scan pod. The adapter holds a single-use scan token and a body-signing key and posts results to the callback plane. That callback is the only path that writes findings.

2 · The finding ontology

Results are observations. They are accepted or quarantined, matched to existing entities through aliases with a fixed source-precedence order, and folded into logical findings. A logical finding is an entity with edges: it affects a Package, a File span or a CloudResource; corroborating tool results become corroborates edges rather than duplicate rows.

The vocabulary is frozen and versioned — 52 entity types across organisation, source-to-production, cloud and infrastructure, identity and access, API and data, security objects and findings; 32 relationship verbs such as contains, triggered, produces, stored_in, runs_image, routes_to, exposes, assumes, can_access, affects, violates_control, duplicate_of, remediated_by. A shipped vocabulary is never mutated; additions create a new version.

Every edge carries a provenance class:

  • observed — reported by telemetry, a provider API or a verified attestation (SCM webhook, CI ledger, cluster state, SLSA provenance).
  • derived — a deterministic join over immutable identifiers (image digest, full commit SHA, ARN, Kubernetes UID).
  • inferred — a heuristic candidate (tag match, name similarity, uncorroborated OCI label). Displayed, never part of a strict path.

3 · Lineage, blast radius, exploit paths

Lineage walks the code-origin template Repository → Commit → Build → ContainerImage → Registry → Workload (→ KubeService → KubeIngress) using observed and derived edges. Hops are satisfied, missing (with reason no_producer_data, source_gap, unbound_endpoint) or conflicting (two claims disagree). Missing and conflicting are read-time states and are never stored as edges.

Blast radius is a bounded breadth-first walk from a subject along creation and deployment edges to the workloads, services and ingresses that carry it. Sibling findings on the same subject are excluded so the number measures impact.

Exploit paths start at exposure edges and traverse identities, roles, policies and data stores; chokepoints and candidate interventions are ranked. An empty result says why: no_exposure_edges or no_attack_paths_computed.

Risk is a versioned model on a fixed scale with factor groups and an explanation per score; incremental scoring re-evaluates only what an event touched.

4 · Policy, decisions, disposition

Policies are Open Policy Agent Rego, authored directly or through the visual builder (rules → AND/OR groups → action, compiled to Rego from an allow-listed field model). Evaluation runs OPA over a structured input and parses the result; any evaluator error is a DENY with reason OPA_EVALUATION_FAILED. Control decisions are signed with Ed25519 over a canonical payload and the audit log is HMAC-chained.

Disposition (true positive, false positive, by design, accepted risk) is written only throughPOST /api/v2/findings/{id}/disposition by a signed-in principal with a reason code. An ORM-level guard and a database trigger both refuse any other writer, including AI triage. Exceptions carry an owner, an expiry, an approver chain and optional dual control.