TechVault live validation gate¶
The live validation gate (aptl.validation.techvault_live_gate) is the
operational counterpart to the static validation
gate. The static gate parses, compiles,
conformance-checks, and interprets the scenario without starting Docker. The
live gate boots the full TechVault lab through APTL's public start path and
proves the running range is realized from the interpreted RAES model rather than
from a TechVault preset, then captures operational and provenance evidence in
the run archive. It implements requirement SCN-010 (issue #323).
The gate is scenario-generic by construction. validate_live_deployment() takes
a scenario path, a backend profile, the project directory, and a run id, so the
next scenario in APTL's full-remote-control-plane expressivity class passes
through by changing inputs rather than by editing the gate. TechVault is the
proving input, never a hardcoded branch (ADR-035).
APTL's public start path (orchestrate_lab_start()) accepts the selected RAES
scenario path and passes it through the same _step_start_containers() handoff
used by the default boot. The backend capability profile remains the public
default, so the gate still fails loud before destructive boot when a caller
requests a profile the public start path will not realize.
What the gate checks¶
validate_live_deployment() composes existing lifecycle, snapshot, and
collector owners and returns a LiveGateReport. Each stage is one
LiveGateCheck tagged with a stable failure category so a failure names the
layer that broke:
- Static prerequisite (
raes_specification). The static gate runs first. A parse, compile, or conformance failure blocks the live boot rather than degrading to a warning. - Boot-input agreement (
backend_instantiation). The selected scenario is passed through to public startup. The profile under validation must still be the public start path's capability profile (full-remote-control-plane). A profile mismatch is a hard failure raised before any destructive boot, so the gate never validates a profile the boot path will not realize. - RAES-driven boot (
backend_interpretationorbackend_instantiation). The gate computes the realization matrix fromRuntimeManager.plan()andinterpret_provisioning_plan(), the same interpretationAptlProvisionerperforms, so the expected node, service, network, and profile surface is keyed by RAES resource addresses. Realization expands selected-node dependencies through RAES provisioning edges and Composedepends_onmetadata before the backend starts; missing, ambiguous, or config-disabled support services fail asbackend_interpretationinstead of booting an incomplete range. It then runsstop_lab(remove_volumes)cleanup andorchestrate_lab_start(), whose only container-start path is the RAES handoff in_step_start_containers(). A realization with errors fails asbackend_interpretation; a failed boot fails asbackend_instantiation. - Defensive-stack readiness (
defensive_stack_readiness). Every RAES-realized node maps to a running, healthy container in the post-boot snapshot. Pass or fail is keyed to the realized node surface, not a hardcoded container list. Unhealthy non-node infrastructure is a degraded note rather than a hard failure of the scenario surface. - Kali reachability (
kali_reachability). From Kali, the gate reaches every lab host it shares a declared network with. Targets come from network co-membership in the snapshot (the realized network attachments), not a hardcoded host list. Every probe runs throughDeploymentBackend.container_exec(). - Telemetry evidence path (
evidence_capture). The gate generates one representative event from Kali against a reachable host, then collects Suricata EVE and Wazuh alerts in a bounded window through the existing collectors. At least one evidence artifact must traverse the defensive stack. - Scenario variation (
backend_interpretation). Two declared RAES nodes from the booted scenario run through the same interpreter path and must yield distinct realization details. This is the anti-collapse property of #324 (SCN-010G) generalized as a live diagnostic. - Run-archive manifest (
evidence_capture). Written last so the persisted archive reflects the complete check set, the gate writes scenario identity, RAES provenance (realization details with resource addresses preserved), the selected profiles, validation evidence, the post-boot snapshot, and the telemetry summary throughLocalRunStore's redacting boundary (ADR-029).
Failure categories¶
A failing report names the layers that broke, drawn from this closed set:
raes_specification, backend_interpretation, backend_instantiation,
defensive_stack_readiness, kali_reachability, and evidence_capture. The
categories map onto existing RAES diagnostics and APTL startup diagnostics. The
gate adds no parallel exception hierarchy.
Run-archive manifest¶
The manifest lands at <run-store>/<run-id>/live-gate/manifest.json under the
schema aptl.live-gate.manifest/v1. It records:
scenario: the scenario identity (path and name).raes_provenance: the realization details verbatim (node addresses, aliases, profiles, services, rendered configs, evidence and telemetry paths, networks, static addresses, and placements), the RAES-selected compose profiles, and the interpretation diagnostic count. This is the auditable proof that the lab was realized by interpreting RAES content rather than by a preset.validation: each check's name, category, outcome, and diagnostics.snapshot: the post-boot range snapshot (containers, networks, health, endpoints).evidence: the telemetry-path summary (event types and counts, never raw payloads).evaluator_surfaces: the evaluator component of the declaredfull-remote-control-planebackend profile and its RAES evaluation result/history contracts for conditions and objectives. This is an evidence index, not a score source; live evaluator progression belongs in RAESevaluation_resultsandevaluation_historyderived from observed run state.
Observable surface¶
The live gate validates the operational startup contract. The public boot
SDL from the validated acquired techvault bundle is the contract: it names
the steady-state Compose services and networks the range actually realizes at
range granularity, and there is no separate capture/parity evidence surface
behind it (ADR-046). Evaluator contracts are part of the declared
full-remote-control-plane surface; #606 narrows that surface to
condition/objective evaluation after RAES ADR-073 moved SDL scoring-chain
semantics out of scope. The run archive is proof of what the operational model
realized; it does not substitute for SDL encoding or for RAES evaluation
result/history envelopes.
Prerequisites¶
The gate boots the full lab, so the runner needs:
- Docker with enough memory and disk for the full TechVault stack (the SOC tools alone need several gigabytes).
- A populated
.envwith real secrets. The boot refuses to start while sensitive values are still.env.exampleplaceholders. - The installed
raeswheel and theraescommand for the static prerequisite. - An isolated, project-scoped Docker daemon. The destructive cleanup removes the
aptlcompose project's volumes, so do not run it against a shared daemon.
Where the semantic verdict comes from¶
The gate's framework holds no scenario knowledge: which node is the attacker and
which nodes make up the defensive stack is knowledge about one scenario on one
backend. That lives in a per-scenario adapter package, discovered through the
aptl.scenario_verifiers entry-point group. For TechVault it is aptl_techvault,
which ships inside aptl-labs, so there is nothing extra to install.
A scenario with no adapter of its own reports terminal blocked and the gate
reaches no verdict. That is deliberate, and it is not a pass, a skip, or a
detection failure: a range whose verification could not run has not been
verified. The same outcome covers an adapter whose declared qualification does
not match the range. Admission requires an exact match on the extension API, the
admitted pack's identity, version and content digest, and the backend's target,
version, profile and transport. Empty declarations are not wildcards.
src/aptl_techvault/README.md states which combinations this release admits and
what a pack change requires of it.
The gate does not generate attack traffic. It establishes that the declared range is realized, that its nodes are healthy, and that the attacker node reaches its shared-network peers. Proving an event traverses the sensor and the SIEM would mean generating that event and reading it back, which leaves its alerts and sensor records in the range after the run.
Running the gate¶
The gate is destructive and minutes long. It targets maintainers and a documented CI runner rather than fast CI or pre-commit. The fast gate-logic tests that cover the orchestrator and every check branch run in the default suite without a lab:
Run the full destructive boot through the CLI:
The command warns and prompts before destroying lab data. Pass --yes to skip
the prompt in automation, or --skip-clean-boot to validate an already-running
lab without the destructive stop -v and reboot. --scenario accepts an
explicit RAES SDL path for the live gate and is passed through to public lab
startup. --profile must remain the public startup capability profile
(full-remote-control-plane); profile mismatches fail the boot-input agreement
check before boot. --run-id sets the run-archive id.
The same boot runs as the explicitly gated integration test:
Without APTL_LIVE_GATE=1 the destructive test stays skipped, so an ordinary
pytest -m integration run never tears down a lab.