diff --git a/STATUS.md b/STATUS.md index 6e35ecc..bed6cfd 100644 --- a/STATUS.md +++ b/STATUS.md @@ -85,9 +85,9 @@ askari.) | Thing | State | |---|---| -| `roles/integration_test/` | **Built** — installs/enables libvirt+QEMU+virtinst on `control` group hosts; adds `sjat`/`claude` to `libvirt` group; creates image-cache dir; drops the driver. Molecule + pytest clean. | -| `scripts/integration-vm.py` | **Built** — stdlib-only lifecycle driver over `virsh`/`virt-install`/`cloud-localds`: `up / apply / reboot / assert / cycle / reset / down / prune / console`. Lazily ensures the golden Debian-13 genericcloud image. pytest clean (transient-inventory generation, var/overlay merge, `--certs` mapping, DHCP-lease parsing, resource-guard math). | -| `tests/integration/` (profile, verify, overrides) | **Built** — "be askari" profile + var overlay + `verify.yml` outcome assertions (Docker up, published-port DNAT, nft sane, `wt0` up). pytest clean. | +| `roles/integration_test/` | **Built** — installs/enables libvirt+QEMU+virtinst on `control` group hosts; adds `sjat`/`claude` to `libvirt` group; creates image-cache dir. Lint clean; applied live to ubongo (substrate installed); molecule scenario present, not run in the build env. | +| `scripts/integration-vm.py` | **Built** — stdlib-only lifecycle driver over `virsh`/`virt-install`/`cloud-localds`: `up / apply / reboot / assert / cycle / down / prune / console`. Lazily ensures the golden Debian-13 genericcloud image. pytest clean (transient-inventory generation, var/overlay merge, `--certs` mapping, DHCP-lease parsing, resource-guard math). | +| `tests/integration/` (profile, verify, overrides) | **Built** — "be askari" profile + var overlay + `verify.yml` outcome assertions (Docker active, forward-chain accepts present, published-port DNAT alive). Validated end-to-end by the RED→GREEN acceptance run. | | `make test-integration` / `make test-integration-clean` | **Built** — wired into `Makefile`. | | ADR-025 | **Accepted (2026-06-18)** — decision recorded, approach A, cert tiers, safety invariants, UEFI boot requirement, and claude-sudo dependency documented. | | **RED/GREEN acceptance (ubongo live pass)** | **PASSED (2026-06-18).** A throwaway KVM VM on ubongo reproduced the 2026-06-17 incident (base nftables forward default-deny kills Docker forwarding on reboot) = RED. Applying the `docker_host` container-forward drop-in and rebooting survived = GREEN. Nine shakedown findings captured in `docs/FRICTION.md`; key learnings (UEFI boot, claude sudo) recorded in ADR-025. `docs/TODO.md` item 2.4 closed. | diff --git a/docs/decisions/015-control-host.md b/docs/decisions/015-control-host.md index 58d58eb..78e0da5 100644 --- a/docs/decisions/015-control-host.md +++ b/docs/decisions/015-control-host.md @@ -98,7 +98,12 @@ Manual, on bare metal: account/key can be revoked without touching the operator's access. (ADR-021 left the on-`ubongo` agent identity unspecified; this records it.) - **Amendment (2026-06-18) — `claude` now has `NOPASSWD:ALL` sudo.** During the + **Amendment (2026-06-18) — `claude` now has `NOPASSWD:ALL` sudo.** + > **Superseded by [ADR-025](025-local-vm-integration-testing.md)** (per ADR-023 §4): the + > "no local sudo" sub-decision is reversed. The shakedown that necessitated it is ADR-025; + > the resulting two-account access model is ADR-021; the accepted risk is R7. + + During the integration-testing harness shakedown, the original "no local sudo" sub-decision was reversed. No-sudo blocked the AI-worker from diagnosing a failed VM: `virsh`, `virt-install`, `cloud-localds`, `journalctl`, `nft` — nearly all low-level diff --git a/docs/decisions/025-local-vm-integration-testing.md b/docs/decisions/025-local-vm-integration-testing.md index ae42f99..fd58b52 100644 --- a/docs/decisions/025-local-vm-integration-testing.md +++ b/docs/decisions/025-local-vm-integration-testing.md @@ -173,7 +173,7 @@ The nine full shakedown findings (including the UEFI boot-loop) are in - ADR-006 — Terraform owns production VM existence (boundary this ADR respects). - ADR-008 — Testing methodology (Levels 1–4); this ADR is the concrete build of Level 2/3. -- ADR-015 — Control host (ubongo); this ADR reconciles "not a hypervisor" with ephemeral test VMs; amended 2026-06-18 for claude sudo. +- ADR-015 — Control host (ubongo); this ADR reconciles "not a hypervisor" with ephemeral test VMs. **Supersedes** ADR-015's "no local sudo" sub-decision for the AI-worker — the shakedown necessitated `claude` NOPASSWD sudo (ADR-023 §4; access model in ADR-021, risk R7). - ADR-016 — Mesh VPN; the "be askari" profile includes the coordinator role. - ADR-020 — Firewall strategy; firewall × Docker interaction is what this harness tests. - ADR-021 — Operational access; sudo model for `claude` and `sjat` on `ubongo`. diff --git a/roles/integration_test/README.md b/roles/integration_test/README.md index e978e85..22609e2 100644 --- a/roles/integration_test/README.md +++ b/roles/integration_test/README.md @@ -31,5 +31,5 @@ the tooling needed to spin up short-lived test VMs (see ADR-015). ## Related decisions -- [ADR-025](../../docs/decisions/025-integration-testing.md) — local VM integration testing +- [ADR-025](../../docs/decisions/025-local-vm-integration-testing.md) — local VM integration testing - [ADR-015](../../docs/decisions/015-control-host.md) — control host scope (ubongo is not a hypervisor) diff --git a/scripts/integration-vm.py b/scripts/integration-vm.py index 417c1e7..b5ec90e 100644 --- a/scripts/integration-vm.py +++ b/scripts/integration-vm.py @@ -11,7 +11,6 @@ import json import os import pathlib import re -import shutil import subprocess import sys import time