Add integration tests based on VM
This commit is contained in:
+15
-13
@@ -97,22 +97,24 @@ The host cannot run this build directly because its musl target is absent.
|
||||
The digest-pinned official Rust 1.97.1 Alpine builder command in
|
||||
[TESTING.md](TESTING.md) built the library test harness on 2026-10-23. `file`
|
||||
identified a static PIE and `readelf -l` showed no interpreter; the ignored
|
||||
readiness selector then passed 1/1 in the pinned Alpine runtime using a
|
||||
read-only bind of the nonsecret binary. The selected-daemon M8.4 Testcontainers
|
||||
smoke later copied the current binary into a fresh server container and passed
|
||||
the test-only Create/Commit/first delivery/fixture Apply sequence with real
|
||||
runtime observation. M8.5 traffic and remaining lifecycle scenarios remain
|
||||
pending. The readiness wrapper
|
||||
invokes the harness as
|
||||
readiness selector passed 1/1 in the pinned Alpine runtime using a read-only
|
||||
bind of the nonsecret binary. The selected-daemon M8.4 Testcontainers smoke
|
||||
copied the current binary into a fresh server container and passed the
|
||||
test-only Create/Commit/first delivery/fixture Apply sequence with real runtime
|
||||
observation. M8.5 and M8.7 subsequently completed and M8 was accepted for the
|
||||
documented IPv4 scope. The current integrated host gates and three fresh
|
||||
selected-daemon lifecycle runs are recorded in
|
||||
[evidence/milestone-8.md](evidence/milestone-8.md). The runs covered IPv4
|
||||
traffic, deletion, restore, import/reissue and mandatory-backup failure. The
|
||||
fixture Apply callback is not a systemd job. IPv6 capability/traffic and real
|
||||
systemd/D-Bus remain unverified. The readiness wrapper invokes the harness as
|
||||
`PATH --ignored --exact container_driver::alpine_readiness --test-threads=1`.
|
||||
Cargo printed the executable under
|
||||
`/tmp/wga-m8-build-target/x86_64-unknown-linux-musl/debug/deps/wireguard_admin-<hash>`
|
||||
for the builder command. Discover the current hash from each build; the driver
|
||||
must be recopied after code changes. A target name or successful compilation
|
||||
alone is not Alpine runtime evidence. Shell-tool readiness, Rust harness
|
||||
readiness and the M8.4 Application smoke passed on the selected daemon. No
|
||||
client tunnel traffic or systemd job has been tested. Musl readiness is a
|
||||
milestone 8 prerequisite, not a milestone 1 acceptance gate.
|
||||
for the builder command. Discover the current hash from each build; rebuild the
|
||||
driver after relevant code changes. A target name or successful compilation
|
||||
alone is not Alpine runtime evidence. Musl readiness is an M8 fixture build
|
||||
prerequisite; it is not a milestone 1 acceptance gate.
|
||||
|
||||
## Observed preparation state
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
# Operator setup, backup and recovery
|
||||
|
||||
This guide describes the supported single-interface installation and recovery
|
||||
boundaries. Use it only after qualifying the application for the target host;
|
||||
the current evidence and gaps are listed in
|
||||
[`RELEASE_READINESS.md`](RELEASE_READINESS.md). Do not trial the application on
|
||||
a production service as a substitute for the pending disposable systemd VM
|
||||
qualification.
|
||||
|
||||
## Installation prerequisites and placement
|
||||
|
||||
The application manages one already-configured Linux WireGuard interface and
|
||||
its existing systemd service. The host must provide working WireGuard kernel
|
||||
support, systemd and its system D-Bus, plus the required service setup (such as
|
||||
`wg-quick` when the selected unit uses it). Version 1 does not provision a
|
||||
server, install a service, or manage multiple interfaces. Do not mount the
|
||||
development host's D-Bus into a test environment.
|
||||
|
||||
Build with the pinned Rust 1.97.1 toolchain and locked dependencies. Before
|
||||
installing an artifact, verify its target and dynamic library requirements
|
||||
against the chosen Linux distribution. The current x86-64 GNU release candidate
|
||||
is host-assessed only; it has not been started in a guest. Keep the executable
|
||||
and `wireguard-admin.toml` together in a dedicated root-owned directory that
|
||||
ordinary users cannot modify. Keep the executable outside `PATH`; no installer,
|
||||
service unit, or automatic privilege wrapper is supplied.
|
||||
|
||||
Copy [`../config/wireguard-admin.example.toml`](../config/wireguard-admin.example.toml)
|
||||
to `wireguard-admin.toml` beside the executable and edit it for the existing
|
||||
interface, server configuration, client source directory, address pools,
|
||||
endpoint, DNS, systemd unit, and timeout. The server config path and interface
|
||||
name are installation invariants. Relative paths resolve beside the executable,
|
||||
not from the shell's working directory. By default working data is
|
||||
`Backup/data` and archives are `Backup/archives`, also beside the executable.
|
||||
Test the resolved paths before running management. Preserve the existing
|
||||
configuration and imported client files; import is read-only and anomaly
|
||||
reports require operator decisions.
|
||||
|
||||
Restrict the settings file, server configuration, vault, internal state, and
|
||||
backup tree to root. Existing server configuration and vault files must already
|
||||
be mode `0600` or stricter when opened. Keep private directories at `0700` and
|
||||
secret-bearing files at `0600`; the application creates new owned outputs with
|
||||
these modes but does not silently chmod an unsafe existing server/vault file.
|
||||
Do not make the executable or settings writable by unprivileged users. The
|
||||
application requires root for management; `--help` and `--version` are
|
||||
unprivileged.
|
||||
|
||||
## Initial vault, import and delivery
|
||||
|
||||
At initial setup, import scans the configured source directory without changing
|
||||
or deleting its original files. Review every reported match, mismatch, invalid
|
||||
file, or server-only/client-only anomaly. The server peer set remains
|
||||
authoritative; do not treat an imported file as permission to rewrite server
|
||||
settings.
|
||||
|
||||
Choose and protect the vault password during initial vault creation. The
|
||||
password protects the separate vault secret key; it does not encrypt the
|
||||
server configuration, original client files, or backup archives. Losing it
|
||||
prevents future reissue of stored client private keys. A backup restores the
|
||||
encrypted vault but cannot recover a lost password. Store credentials under
|
||||
your organization's separate secret-custody process; never place the password
|
||||
in settings, a command line, logs, or evidence.
|
||||
|
||||
For a new client, Commit first, then complete first file delivery in the same
|
||||
application session. The initial file is mandatory and can be retried at a
|
||||
different destination after a publication failure while that creation session
|
||||
is still active. Optional QR output represents the same configuration and is
|
||||
available only after file publication. The delivered file is plaintext
|
||||
WireGuard configuration, mode `0600`; treat terminal QR output as a disclosure.
|
||||
If publication reports uncertain output or cleanup is required, follow the
|
||||
exact manual-cleanup instruction before retrying; do not assume an error means
|
||||
no plaintext file was created.
|
||||
Until the saved peer set has been explicitly applied and verified, treat the
|
||||
new client's access as inactive. After that session ends, each reissue requires
|
||||
the vault password for that client and reads installed saved state. The
|
||||
application does not use retained original plaintext files as a password-free
|
||||
fallback. Overwriting a selected output file requires confirmation.
|
||||
|
||||
## Commit, backups, restore and restart
|
||||
|
||||
Keep the three states distinct:
|
||||
|
||||
1. **Draft** is the current session's proposed edit. Cancel preserves it in
|
||||
that session; exiting does not save it.
|
||||
2. **Saved** is what Commit installed on disk. Commit creates a mandatory
|
||||
pre-Commit backup, then saves settings, server configuration, internal state
|
||||
and encrypted vault. Commit never reloads, syncs, or restarts WireGuard.
|
||||
3. **Applied** is saved state verified against the running interface after an
|
||||
explicit restart. A historical verification marker after reopen is not a
|
||||
live observation.
|
||||
|
||||
Every Commit, restore and restart first creates a complete mandatory backup.
|
||||
If that backup fails, the protected operation stops before changing saved files
|
||||
or submitting a restart. Backups are uncompressed archives, not encrypted
|
||||
archives. They can contain the server's private configuration and encrypted
|
||||
vault records. Restrict them to root, include them in the site's protected
|
||||
backup custody, and remember that a backup beside the executable is lost with
|
||||
that disk. The application has no automatic retention or remote-copy feature.
|
||||
Deleting a client from the current vault does not erase old backups.
|
||||
|
||||
Restore is a previewed, confirmed full replacement of saved state. It restores
|
||||
the settings and opaque vault without a vault password, and it does not change
|
||||
the running interface. A restored archive's old verification marker is
|
||||
historical; runtime state becomes unknown. To apply the restored state, start a
|
||||
separate explicit restart and inspect its result. Never describe restore or
|
||||
Commit as a VPN rollback.
|
||||
|
||||
Before confirming restart, review the configured interface/service and the
|
||||
saved-versus-applied differences. The application creates a pre-restart backup,
|
||||
submits the configured systemd job, waits for its terminal result, compares the
|
||||
complete observed peer and route sets, then journals verification state. A
|
||||
successful systemd job alone does not establish that the expected peers are
|
||||
active. A pre-restart backup captures saved files and is not necessarily a
|
||||
known-good working VPN state. Deleted-client addresses remain reserved until
|
||||
verification and its saved-state write both succeed.
|
||||
|
||||
If restart reports failure, timeout, a runtime mismatch, or a persistence
|
||||
failure, read the stage and whether submission occurred or may still complete.
|
||||
A timeout does not cancel a submitted job. Do not immediately issue repeated
|
||||
restarts while a submitted job may still be running. No automatic restart,
|
||||
retry, VPN rollback, or reservation release occurs on these failure paths.
|
||||
Preserve the pre-restart backup and inspect the service and configured
|
||||
interface through the host's normal, independently controlled administration
|
||||
path. Do not infer success from log text alone. When the application remains
|
||||
usable, select a known-good archive through its preview/confirmation flow to
|
||||
restore saved files, then decide separately whether to restart and verify them.
|
||||
|
||||
## Saved-file journal recovery
|
||||
|
||||
The persistence journal recovers interrupted file replacement; it is not
|
||||
runtime rollback. On reopen, an uncommitted prepared journal rolls saved files
|
||||
back to the recorded prior bytes, while a committed journal is cleaned up. If
|
||||
recovery or cleanup fails, the application returns `RecoveryRequired` and
|
||||
rejects mutations. Correct the underlying storage problem (for example,
|
||||
available space or directory access), preserve the journal, and retry opening
|
||||
the application so its recovery can run. Do not delete, hand-edit, or rename
|
||||
journal files to force startup.
|
||||
|
||||
If a journal remains invalid or recovery continues to fail, stop making
|
||||
changes. Preserve the complete data directory and operation backups for a
|
||||
careful, separately reviewed recovery. A known-good archive is the documented
|
||||
saved-state recovery source when the application can safely preview and restore
|
||||
it; it does not repair the runtime automatically. After saved state is recovered,
|
||||
inspect the live interface and use a separate explicit restart only when its
|
||||
target is understood. If the application cannot open to perform a safe
|
||||
previewed restore, do not improvise by copying partial archive members over
|
||||
installation paths.
|
||||
|
||||
Never remove old archives or original client files as an automatic response to
|
||||
an error. Keep secret-bearing files and working backups out of source control,
|
||||
support tickets, screenshots, logs, and evidence reports.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Release readiness and qualification matrix
|
||||
|
||||
This is a scope-qualified M9.4 record, not a release approval. M1–M8 are
|
||||
accepted in [`PLANS.md`](../PLANS.md); M9 real-system acceptance remains
|
||||
incomplete because no explicitly selected disposable systemd VM is available.
|
||||
No production host, VPN, service, key, or configuration was accessed. The
|
||||
operator procedure is in [`OPERATIONS.md`](OPERATIONS.md).
|
||||
|
||||
## Current host release candidate
|
||||
|
||||
The following native artifact was built from the current Rust sources with the
|
||||
pinned compiler and locked dependency set. Its `--help` and `--version` paths
|
||||
were executed on the development host. This assessment does not establish
|
||||
startup in a guest or supported compatibility with another distribution.
|
||||
|
||||
| Property | Observed value |
|
||||
| --- | --- |
|
||||
| Source Git HEAD | `f4a6540df9621c9c5e5d1430243f92e749356a59` |
|
||||
| Working-tree state at build | Pre-existing dirty documentation only: `PLANS.md` modified and `docs/VM_ACCEPTANCE.md` untracked; no source, manifest or lockfile changes |
|
||||
| Relevant input fingerprint | SHA-256 `02ace329ca2ed17aa0b47112a3fcaa090b7d9a7eaa334f293aea9792e35e668a` over sorted `src/`, `Cargo.toml`, and `Cargo.lock` file hashes |
|
||||
| Compiler and target | rustc 1.97.1, host `x86_64-unknown-linux-gnu`; Cargo 1.97.1 |
|
||||
| Build command | `cargo build --locked --release` — exit 0 |
|
||||
| Artifact | `target/release/wireguard-admin`, x86-64 ELF PIE, dynamically linked |
|
||||
| Artifact SHA-256 | `d52d43cd02332352ffbd09c97e3b8095a710359128260c1286006e1c76c1b283` |
|
||||
| Runtime requirements observed | ELF interpreter `/lib64/ld-linux-x86-64.so.2`; `libc.so.6` (GLIBC symbols through `GLIBC_2.39`) and `libgcc_s.so.1`; `ldd` resolved these on the development host |
|
||||
| Artifact smoke | `./target/release/wireguard-admin --help` and `--version` — both exit 0; no settings, terminal, root management, service or interface exercised |
|
||||
|
||||
Commands used to inspect the artifact were `sha256sum target/release/wireguard-admin`,
|
||||
`file target/release/wireguard-admin`, `readelf -h`, `readelf -l`, `readelf -d`,
|
||||
`readelf --version-info`, and `ldd target/release/wireguard-admin`. The linked
|
||||
GLIBC requirement is an observed lower symbol-version bound, not proof that a
|
||||
distribution satisfying it is otherwise compatible. No installer, package,
|
||||
signature, reproducible-build claim, or supported distribution baseline is
|
||||
provided. This native GNU artifact is not an Alpine/musl artifact.
|
||||
|
||||
The source-input fingerprint was calculated from the repository root with:
|
||||
|
||||
```sh
|
||||
rg --files src Cargo.toml Cargo.lock | sort | xargs sha256sum | sha256sum
|
||||
```
|
||||
|
||||
## Specification-to-evidence matrix
|
||||
|
||||
“Accepted” refers to the repository's existing milestone result. It does not
|
||||
mean every production platform or dual-stack behavior has been qualified. For
|
||||
M1–M7, the concise milestone scope, review outcome and commands are in the
|
||||
corresponding accepted sections of [`PLANS.md`](../PLANS.md). M8's detailed
|
||||
source, artifact, run and scope record is
|
||||
[`evidence/milestone-8.md`](evidence/milestone-8.md).
|
||||
|
||||
| Requirement area | Existing evidence | Qualification and limit |
|
||||
| --- | --- | --- |
|
||||
| Settings validation, executable-relative paths, draft/saved/applied model | M1 accepted record in `PLANS.md`; M7 startup/workflow record there | Synthetic/unit and TUI workflow coverage; no guest startup or production configuration. |
|
||||
| Server configuration authority, client identity by public key, byte preservation and metadata | M2 accepted record in `PLANS.md`; specification in `SPEC.md` | Fixture/behavioral evidence for preserving non-client bytes and comments; no real server file was used. |
|
||||
| Secret-safe keys, encrypted vault, read-only imports and originals | M3 accepted record in `PLANS.md`; M8 import/reissue scenario in `evidence/milestone-8.md` | Synthetic import plus accepted Alpine lifecycle scenario; source originals were fixture files and retained. Vault password loss remains unrecoverable by design. |
|
||||
| Backups, mandatory backup boundary, journaled Commit, recovery and previewed restore | M4 accepted record in `PLANS.md`; M8 restore and backup-failure runs in `evidence/milestone-8.md` | Saved-state operations and test-fixture behavior covered. Restore did not apply runtime changes; real-VM manual recovery remains unverified. Archives are not encrypted. |
|
||||
| Read-only runtime observations, restart orchestration, deadline and failure reporting | M5 accepted record in `PLANS.md`; runtime section of `docs/RUNTIME.md`; M8 Rustix observations | Fake-adapter and real Alpine WireGuard reader/IPv4 observations exist. No actual systemd/D-Bus job or `Application::restart` against real systemd has been run. |
|
||||
| Delivery, first issue, password-per-action reissue, QR and private output | M6 accepted record and M7 synthetic PTY/workflow records in `PLANS.md`; `docs/DELIVERY.md` | Synthetic behavior covers file publication/reissue and QR rendering/terminal handling. No user device scan or actual client device qualification is recorded. |
|
||||
| Native TUI, root/startup boundary and exit/terminal cleanup | M7 accepted record in `PLANS.md`, including synthetic PTY and workflow checks | Not a real guest root/non-root startup smoke. The release binary was only exercised for help/version on the build host. |
|
||||
| Alpine real WireGuard lifecycle and IPv4 traffic | M8.7 in `evidence/milestone-8.md` | Accepted M8 used the pinned Alpine 3.22.7 fixture and selected disposable Docker daemon; repeated fresh integrated IPv4 scenarios passed on the recorded source fingerprint. Fixture Apply is a test-only callback, not systemd evidence. |
|
||||
| Dual-stack behavior | M1–M7 synthetic client/configuration tests; M8 scope declaration | Production IPv4+IPv6 creation/full-tunnel requirements remain in force. Real IPv6 capability and traffic were excluded from M8 and are unverified; an IPv4 result does not qualify IPv6. |
|
||||
| Real systemd job, alias/fast completion, failure/timeout, verified apply, restore and release-worker startup | No M9 VM result exists; `docs/VM_ACCEPTANCE.md` is a reviewed safety/scenario contract | **Unverified / M9 incomplete.** No selected disposable guest or VM run. Do not infer this from fake service adapters, Alpine or the host `--help` check. |
|
||||
| Native artifact identity and dynamic dependencies | This document's host release-candidate record | Host-only assessment. Guest compatibility and startup are unverified; no universal Linux support claim. |
|
||||
|
||||
## Qualification status and next action
|
||||
|
||||
- M1–M8 remain accepted at their recorded scope. Later M9 documentation does
|
||||
not change or broaden their evidence.
|
||||
- M9.1 has a reviewed, non-runnable VM safety/scenario contract. M9.2–M9.3
|
||||
real-system work and M9.5–M9.6 review/acceptance remain incomplete.
|
||||
- The release candidate was built and its ELF dependencies inspected on the
|
||||
host, but has not been copied to or started in a guest. Actual guest
|
||||
architecture/distribution compatibility, root management startup,
|
||||
systemd/D-Bus behavior and service recovery are unverified.
|
||||
- Real IPv6 capability and tunnel traffic are unverified. No M8 IPv4 or
|
||||
synthetic dual-stack test is a substitute for that qualification.
|
||||
- No release, installation, production action, Git commit, or deployment is
|
||||
authorized by this report.
|
||||
|
||||
Next action: select and explicitly identify a disposable VM/guest satisfying
|
||||
[`VM_ACCEPTANCE.md`](VM_ACCEPTANCE.md), then complete its target guard and
|
||||
real-system scenarios before independent M9 review. Keep systemd/guest results
|
||||
separate from the existing Alpine and synthetic evidence. Any final release
|
||||
statement must retain the real IPv6 qualification gap unless that coverage is
|
||||
explicitly authorized and completed.
|
||||
+12
-7
@@ -138,11 +138,14 @@ the runtime or service adapters.
|
||||
Application unit tests use private fake adapters and an injected private
|
||||
monotonic clock. Public integration tests exercise cancellation, preview,
|
||||
restore, and saved-setting selection without confirming a host restart. These
|
||||
are synthetic fixture results. The Linux transport has not been validated
|
||||
against a real interface; that check belongs to the isolated Alpine suite at
|
||||
M8. The real zbus/systemd path and end-to-end restart acceptance require the
|
||||
disposable systemd VM at M9. The TUI and management startup wiring are not
|
||||
implemented.
|
||||
are synthetic fixture results. M7 implemented the TUI and management startup
|
||||
wiring, with synthetic workflow and PTY coverage. M8 also validated the Linux
|
||||
Rustix transport against a real WireGuard interface in the isolated Alpine
|
||||
fixture, including IPv4 peer, route, handshake, and counter observations (see
|
||||
[M8 evidence](evidence/milestone-8.md)). That fixture does not exercise the
|
||||
real zbus/systemd path: systemd/D-Bus behavior and end-to-end restart acceptance
|
||||
still require the disposable VM at M9. Real IPv6 capability and traffic remain
|
||||
unverified.
|
||||
|
||||
## Bounded Linux transport
|
||||
|
||||
@@ -164,5 +167,7 @@ errors, timeouts, and limit excess remain separate, redacted categories.
|
||||
Receive buffers are zeroized on every return path because device replies may
|
||||
include private and preshared key attributes, although the decoder borrows and
|
||||
does not retain those attributes. Runtime observation does not itself perform
|
||||
saved-peer comparison or mark state applied. Real-interface behavior remains
|
||||
subject to the isolated Alpine integration milestone.
|
||||
saved-peer comparison or mark state applied. M8 exercised this Rustix reader
|
||||
against a real Alpine WireGuard interface for IPv4 observations; real IPv6
|
||||
capability and traffic remain unverified. See [M8 evidence](evidence/milestone-8.md)
|
||||
for the accepted scope.
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
# Disposable systemd VM acceptance contract
|
||||
|
||||
Status: Milestone 9 is paused at the user's request. The exact disposable VM
|
||||
was powered off after a guarded first start and an installer progress screen;
|
||||
read-only `list runningvms` was empty afterward. Debian installation completion,
|
||||
guest provisioning, reset, cleanup, and systemd acceptance are unverified.
|
||||
|
||||
This contract supplements [Testing and Acceptance](TESTING.md) and the M9
|
||||
criteria in [PLANS.md](../PLANS.md). Product behavior is governed by
|
||||
[SPEC.md](SPEC.md), [Runtime observation and verification](RUNTIME.md), and
|
||||
[ADRs 0001–0003](adr/).
|
||||
|
||||
## Selected target
|
||||
|
||||
The selected target is exactly one new VirtualBox VM:
|
||||
|
||||
| Field | Required value |
|
||||
| --- | --- |
|
||||
| Provider | Oracle VirtualBox, local `VBoxManage` 7.2.8_Gentoo |
|
||||
| VM name | `wga-m9-debian137-20261025` |
|
||||
| Guest base | Official Debian 13.7.0 (Trixie) amd64 netinst ISO |
|
||||
| ISO path | `/media/data/wm/Virtualbox/wga-m9-lab/debian-13.7.0-amd64-netinst.iso` |
|
||||
| ISO SHA-256 | `a7ef94ac2fb9a7fec454552abd629b7cc9d5155c886165a45649f5ce6167e355` |
|
||||
| VirtualBox OS type | `Debian13_64` |
|
||||
| Lab root | `/media/data/wm/Virtualbox/wga-m9-lab` (owner `sasa`, mode `0700`) |
|
||||
| Networking | One NAT NIC only, no forwarding; all other NICs disabled |
|
||||
| VM UUID | `b14c850b-a21e-4a56-acca-785590f0c4ac`, pinned in the mode-`0600` identity manifest |
|
||||
| Guest marker | `/etc/wga-m9-lab-marker`, exact content `wga-m9-debian137-20261025` after provisioning |
|
||||
|
||||
The ISO is present, has the stated SHA-256, and was obtained from Debian's
|
||||
[official amd64 netinst directory](https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/).
|
||||
VBoxManage command forms were checked against the local 7.2.8 help and Oracle's
|
||||
[VirtualBox 7.2 VBoxManage manual](https://docs.oracle.com/en/virtualization/virtualbox/7.2/user/vboxmanage.html).
|
||||
Read-only `VBoxManage unattended detect --iso=... --machine-readable` reported
|
||||
`OSTypeId=Debian13_64`, `OSVersion=13.7.0 Trixie`, and
|
||||
`IsInstallSupported=on`, but then exited 1 with `NS_ERROR_NOT_IMPLEMENTED`.
|
||||
The later bounded `unattended install --dry-run --start-vm=none` succeeded for
|
||||
this exact VM with private synthetic password files, a fully qualified `.invalid`
|
||||
hostname, and the local Guest Additions ISO. The dry run made no VM changes;
|
||||
actual unattended preparation and guest boot remain unverified. VirtualBox's
|
||||
dry-run output contains plaintext password fields, so the wrapper suppressed
|
||||
them and displayed only redacted output. Any actual unattended step needs a
|
||||
reviewed exact-target procedure and post-prepare media inspection before start.
|
||||
|
||||
The approved read-only inventory outside the sandbox found `/dev/vboxdrv`
|
||||
available and `VBoxManage` 7.2.8 working. It initially listed Windows 7 and
|
||||
Windows 11 VMs; neither is a test target or was modified. The create-only run
|
||||
registered only the new Debian target and stopped before configuration. The
|
||||
default sandbox does not expose the host driver/device, so host inventory and
|
||||
later VBoxManage operations must use the approved outside-sandbox path. The
|
||||
guard matches the exact new name/UUID and does not inspect existing VMs'
|
||||
per-VM files.
|
||||
|
||||
## Guarded host operations
|
||||
|
||||
[`tests/vm/guard.py`](../tests/vm/guard.py) is a narrow standard-library Python
|
||||
guard, not a general VirtualBox wrapper. Its default `check`, `start`, and
|
||||
`authorize-guest` actions are outside Cargo's default test targets. The guard:
|
||||
|
||||
- Requires the exact lab root to be a real directory owned by the current user
|
||||
with mode `0700`, and `target-identity.json` to be a regular current-user file
|
||||
with mode `0600`.
|
||||
- Requires the manifest to pin the exact VM name, current owner UID, one valid
|
||||
UUID, and host marker `<VM name>:<UUID>`.
|
||||
- Uses `VBoxManage list vms` to require that exact name occur once with the pinned
|
||||
UUID, then `showvminfo <UUID> --machinereadable` to compare UUID/name/marker.
|
||||
- Requires the VM configuration and its one VDI to reside below the lab root,
|
||||
the VDI to be named exactly `wga-m9-debian137-20261025.vdi`, and any mounted
|
||||
installer ISO to be the pinned Debian ISO in that root.
|
||||
- Requires a complete inventory of all eight NIC slots, with only NIC 1 in NAT
|
||||
mode. NAT forwarding and all VirtualBox shared folders are refused.
|
||||
- Performs every identity, path, and isolation check before `startvm`. A missing,
|
||||
duplicate, malformed, or mismatched identity fails closed. The only start
|
||||
target is the pinned UUID, in the GUI frontend for console installation.
|
||||
- Before guest authorization, repeats all host checks, requires a current-user
|
||||
password file with mode `0600`, and reads only the guest marker via
|
||||
`VBoxManage guestcontrol ... run /usr/bin/cat` with `--wait-stdout` and a
|
||||
15-second guest process timeout. Host stdout/stderr capture is also capped at
|
||||
1 MiB while the process runs. The password is supplied using `--passwordfile`;
|
||||
it is never placed in argv. Marker output is compared exactly and is not
|
||||
echoed. This read is unprivileged inside the guest.
|
||||
|
||||
The host marker is a pre-install bootstrap identity: it binds the created
|
||||
VirtualBox object and protected manifest before the first start. It is not proof
|
||||
of guest identity. The guest marker is installed only after Debian setup and is
|
||||
checked separately after boot. Do not perform root provisioning, run application
|
||||
acceptance, or access the guest system bus until `authorize-guest` succeeds for
|
||||
the exact UUID. The guest marker check is deliberately read-only; it does not
|
||||
grant the caller a general guest command runner.
|
||||
|
||||
The exact current focused checks are:
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests/vm -p 'test_*.py' -v
|
||||
python3 -m py_compile tests/vm/guard.py tests/vm/test_guard.py
|
||||
git diff --check
|
||||
```
|
||||
|
||||
They use a temporary synthetic VM inventory and fake VBoxManage responses. They
|
||||
do not call VBoxManage, start a guest, contact a host service, or read any
|
||||
registered VM configuration. The behavioral cases cover normal exact identity,
|
||||
missing/duplicate/wrong UUID, wrong name, manifest/root permissions, storage
|
||||
escape, NIC mode and incomplete inventory, NAT forwarding, shared folders,
|
||||
host/guest marker mismatch, no `startvm` on refusal, and exact UUID start scope.
|
||||
|
||||
The guard supports these later commands once the selected VM has been created,
|
||||
its manifest and marker have been recorded, and the coordinator has reviewed the
|
||||
mutation step:
|
||||
|
||||
```sh
|
||||
python3 tests/vm/guard.py check
|
||||
python3 tests/vm/guard.py start
|
||||
python3 tests/vm/guard.py authorize-guest --password-file /path/to/private/guest-password
|
||||
```
|
||||
|
||||
The placeholder password path above must name a private file owned by the
|
||||
current user with mode `0600`. Do not put a password value in the command line,
|
||||
environment, terminal history, or output. The `start` command is an implemented
|
||||
guarded operation but has not been run. Running it requires the approved
|
||||
outside-sandbox path because the default sandbox does not expose the host
|
||||
VirtualBox device.
|
||||
|
||||
## Create-only procedure (ran once; do not rerun)
|
||||
|
||||
[`tests/vm/create.py`](../tests/vm/create.py) exposes only the fixed create
|
||||
operation; it accepts no target, path, or action override. After confirming the
|
||||
lab root owner/mode, exact ISO digest, absence of both the identity manifest and
|
||||
the exact target VM path (using `lstat`, so dangling symlinks also count as
|
||||
occupied), and a well-formed VirtualBox inventory without the selected name, it
|
||||
issues bounded VBoxManage calls to:
|
||||
|
||||
1. Register `wga-m9-debian137-20261025` as `Debian13_64` below the lab root.
|
||||
2. Configure 1024 MiB RAM, one CPU, NIC 1 in NAT mode, NICs 2–8 disabled, audio
|
||||
disabled, USB disabled, and DVD then disk boot order.
|
||||
3. Create one dynamically allocated standard 8192 MiB VDI, attach it on SATA
|
||||
port 0, and attach the pinned Debian ISO on SATA port 1.
|
||||
4. Write the actual VM UUID and `<name>:<UUID>` host marker in
|
||||
`target-identity.json` with mode `0600`, set the same marker as the VirtualBox
|
||||
description, then run the existing read-only host guard.
|
||||
|
||||
Run this exact command only after coordinator review of the current host state
|
||||
and the scoped mutations:
|
||||
|
||||
```sh
|
||||
python3 tests/vm/create.py
|
||||
```
|
||||
|
||||
The command must run through the approved outside-sandbox path because the
|
||||
default sandbox cannot access the VirtualBox host driver. Its effects are VM
|
||||
registration, storage/network/device/boot configuration, ISO attachment, and
|
||||
the protected host identity manifest. It does not start the VM, install Debian,
|
||||
use guest control, create snapshots, or delete/clean up resources. VBoxManage
|
||||
calls have 30-second timeouts and 1 MiB per-stream output limits. Errors omit
|
||||
VBoxManage output; after registration they report the exact target name and
|
||||
known UUID. A failed procedure retains any partial target and its identity for
|
||||
inspection; it performs no automatic rollback or broad cleanup. The final guard
|
||||
must pass before the script reports success. The first run registered the UUID
|
||||
above, then stopped when strict parsing rejected VirtualBox's indented
|
||||
`rec_screen0` recording marker. The parser was narrowly repaired and
|
||||
independently re-reviewed. The target path is now occupied, so `create.py` must
|
||||
not be rerun; use the reviewed resume procedure below.
|
||||
|
||||
## Resume the registered partial target (ran once; do not rerun)
|
||||
|
||||
The earlier create attempt registered the selected target before stopping at
|
||||
the initial machine-readable parse. The exact retained target is
|
||||
`wga-m9-debian137-20261025` with UUID
|
||||
`b14c850b-a21e-4a56-acca-785590f0c4ac`; it is powered off and has only its
|
||||
`.vbox` configuration file. Its observed NIC inventory was NIC 1 in NAT with
|
||||
NICs 2–8 disabled. It had no identity manifest or VDI. That prior state was
|
||||
the sole input accepted by [`tests/vm/resume.py`](../tests/vm/resume.py).
|
||||
|
||||
The resume-only procedure is fixed to that UUID and lab root. Before its first
|
||||
mutation it checks the private root, exact pinned ISO path and SHA-256, absent
|
||||
manifest and target VDI, unique registered name/UUID identity, exact `.vbox`
|
||||
path, powered-off state, empty host description, default memory/CPU settings,
|
||||
the observed NIC inventory (NIC 1 in NAT and NICs 2–8 disabled), no attached
|
||||
media or storage controller, no shared folders, and no NAT forwarding. It
|
||||
refuses an unexpected adapter or preexisting state.
|
||||
After preflight it configures memory/CPU, NAT-only networking, disabled audio
|
||||
and USB, boot order, one standard 8192 MiB VDI, and the pinned ISO; then it
|
||||
writes the protected host manifest, sets the host marker, and runs the existing
|
||||
read-only guard. It does not create, start, unregister, delete, or clean up a
|
||||
VM. A failure after mutation retains the exact target and reports its pinned
|
||||
UUID for inspection; no rollback is attempted.
|
||||
|
||||
The focused command is:
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests/vm -p 'test_resume.py' -v
|
||||
```
|
||||
|
||||
It uses only a temporary synthetic lab and fake VBoxManage responses. It does
|
||||
not call VBoxManage or establish host/VM evidence. The implementation command
|
||||
was `python3 tests/vm/resume.py`; it ran once via the approved outside-sandbox
|
||||
path. It configured the exact target and wrote the host marker/manifest. Its
|
||||
final guard call initially refused observed VirtualBox storage metadata;
|
||||
focused repairs and independent re-review closed those parser and guard
|
||||
findings. A subsequent read-only `python3 tests/vm/guard.py check` passed
|
||||
against the actual powered-off target. Do not rerun the resume command on this
|
||||
occupied state.
|
||||
|
||||
Do not infer `unregistervm --delete`, snapshot restore, guest-control, or broad
|
||||
cleanup commands from the CLI help. No provisioning command is documented
|
||||
because Debian installation, Guest Additions/management channel, the unprivileged
|
||||
`wga` account, and guest marker placement have not been validated. No reset or
|
||||
deletion command is documented because a baseline snapshot and exact owned
|
||||
resource IDs do not yet exist. Existing registered VMs must remain untouched.
|
||||
|
||||
## Unattended preparation (ran once; do not rerun)
|
||||
|
||||
[`tests/vm/install_prepare.py`](../tests/vm/install_prepare.py) is pinned to the
|
||||
VM UUID above and accepts no target, path, credential, or action overrides. It
|
||||
first checks the current user's `/tmp/wga-m9-private` directory is a real mode
|
||||
`0700` directory and its nonempty `wga-password` and `root-password` files are
|
||||
current-user-owned regular mode-`0600` files. These are synthetic install
|
||||
credentials only; password contents never enter argv or output. It verifies the
|
||||
pinned Debian ISO and `/usr/share/virtualbox/VBoxGuestAdditions.iso` SHA-256
|
||||
digests, then calls the existing exact-target read-only guard and additionally
|
||||
requires the VM to be powered off, with the expected VDI at `SATA-0-0`, the
|
||||
pinned installer ISO at `SATA-1-0`, and every other reported SATA attachment
|
||||
slot set to `none` or `emptydrive`. This accepts VirtualBox 7.2.8's real
|
||||
`showvminfo` inventory (`SATA-2-0` through `SATA-29-0` are `none`) while
|
||||
rejecting any additional attached media. It refuses before mutation if any
|
||||
check fails.
|
||||
|
||||
The script runs a bounded `VBoxManage unattended install <pinned UUID>` dry run
|
||||
first with `--iso=<pinned Debian ISO>` and
|
||||
`--admin-password-file=/tmp/wga-m9-private/root-password`, using the synthetic
|
||||
`wga` account and password file, `.invalid` FQDN, `en_US`, `UTC`, US country,
|
||||
minimal package adjustment, and the pinned Guest Additions ISO. The root
|
||||
credential option is `--admin-password-file`; `--root-password-file` is not a
|
||||
valid option for the local VBoxManage 7.2.8. Only a successful dry run permits
|
||||
the same bounded command without `--dry-run`. Both commands request
|
||||
`--start-vm=none`; the script has no start, cleanup, or retry operation.
|
||||
VBoxManage output is captured privately because its dry-run output contains
|
||||
plaintext password fields; errors and status output omit captured text. The
|
||||
command has a 120-second deadline and 1 MiB per-stream capture limit.
|
||||
|
||||
After independent review, the command ran once through the approved
|
||||
outside-sandbox VBoxManage path:
|
||||
|
||||
```sh
|
||||
python3 tests/vm/install_prepare.py
|
||||
```
|
||||
|
||||
The command exited 0 and left the VM powered off. Read-only `showvminfo`
|
||||
inspection found the exact VDI at SATA 0 and a VirtualBox-generated auxiliary
|
||||
`.viso` at SATA 1, both in the private target folder. The generated installer
|
||||
files are mode `0600`; the target folder is mode `0700`. The normal host guard
|
||||
refuses the `.viso`, as designed, so the first start requires a separate guard
|
||||
for this exact installer state and independent review. Do not rerun preparation
|
||||
on the occupied state. Guest boot, Guest Additions setup, and guest provisioning
|
||||
are not established by this result or the synthetic tests.
|
||||
|
||||
The focused behavioral tests use only temporary synthetic files and a fake
|
||||
VBoxManage runner:
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests/vm -p 'test_install_prepare.py' -v
|
||||
```
|
||||
|
||||
## First start of the prepared installer (ran once; VM stopped)
|
||||
|
||||
[`tests/vm/install_boot.py`](../tests/vm/install_boot.py) adds a separate,
|
||||
fixed-target `check`/`start` command for the one powered-off installer state.
|
||||
The ordinary [`guard.py`](../tests/vm/guard.py) deliberately continues to
|
||||
reject the generated `.viso`; this installer guard does not loosen that normal
|
||||
guard. It reuses the strict machine-readable parser and checks the exact
|
||||
current-user-owned mode-`0600` identity manifest, pinned UUID and matching host
|
||||
description, exact target name/configuration path, and current-user-owned
|
||||
mode-`0700` target folder. It requires the VDI at SATA 0 and exactly
|
||||
`Unattended-b14c850b-a21e-4a56-acca-785590f0c4ac-aux-iso.viso` at SATA 1;
|
||||
SATA ports 2–29 must all be `none`. The `.viso` and any generated
|
||||
`isolinux`/`preseed`/`postinstall` files are checked as current-user-owned
|
||||
mode-`0600` regular files with exactly one hard link. The VM configuration and
|
||||
VDI are also required to be regular current-user-owned files with exactly one
|
||||
hard link. The guard never opens or prints installer-file contents.
|
||||
The VM must remain powered off during preflight, have only NIC 1 in NAT mode,
|
||||
and have no forwarding rules or shared folders. Symlinked paths, extra media,
|
||||
unknown attachment metadata, and incomplete or mismatched identity refuse
|
||||
before start.
|
||||
|
||||
The exact commands are:
|
||||
|
||||
```sh
|
||||
python3 tests/vm/install_boot.py check
|
||||
python3 tests/vm/install_boot.py start
|
||||
```
|
||||
|
||||
`check` only reads the protected manifest, filesystem metadata, and bounded
|
||||
VirtualBox inventory; it does not change VM state. `start` repeats all checks,
|
||||
then issues only `VBoxManage startvm b14c850b-a21e-4a56-acca-785590f0c4ac
|
||||
--type=headless`. It accepts no UUID, root, media, credential, or action
|
||||
override. Each VBoxManage call uses the existing guard's 15-second deadline and
|
||||
1 MiB per-stream output cap. Output is not copied into errors. If the start call
|
||||
fails or times out, the result explicitly says the VM may have started and
|
||||
requires a separate read-only inspection; there is no retry, cleanup, or
|
||||
rollback. A successful command means only that VirtualBox accepted the start
|
||||
request. It does not prove guest boot, Debian installation, or Guest Additions.
|
||||
|
||||
Focused fake-runner coverage is:
|
||||
|
||||
```sh
|
||||
python3 -m unittest discover -s tests/vm -p 'test_install_boot.py' -v
|
||||
```
|
||||
|
||||
These tests create synthetic private files and never call VBoxManage. Both
|
||||
commands ran once against the actual VM after independent review. `check`
|
||||
passed; `start` returned success; VirtualBox listed only the pinned target as
|
||||
running. A private console screenshot showed Debian's base-system installer at
|
||||
6%. The user then stopped Milestone 9, so the exact target was powered off and
|
||||
read-only `list runningvms` returned no running VMs. Do not restart it without
|
||||
a new explicit request. Installation completion and guest boot remain
|
||||
unverified.
|
||||
|
||||
After installation, provision only synthetic lab packages,
|
||||
fixed reviewed service units, synthetic WireGuard keys/configuration, and the
|
||||
guest-local marker. Keep all server/client data, outputs, and working backups
|
||||
under a guest-only root-owned `0700` directory; secret files are `0600`. The
|
||||
guest-local marker must be readable by the unprivileged `wga` account for the
|
||||
read-only marker gate. This work belongs to the next task after target creation
|
||||
and guard review; it is not claimed as implemented here.
|
||||
|
||||
## Isolation and acceptance boundary
|
||||
|
||||
- Use synthetic server/client keys, configuration, settings, and vault contents
|
||||
generated inside the guest. Preserve imported originals. Do not copy or read
|
||||
production keys, configuration, backups, or credentials.
|
||||
- The VM may have only one NAT management adapter, with no forwarding rules;
|
||||
do not use bridged, host-only, internal, NAT-network, USB network, or physical
|
||||
adapters. NAT-only VM egress still traverses the host's ordinary network; do
|
||||
not claim host-independent network isolation. No host D-Bus, `/etc`, `/run`,
|
||||
`/var`, WireGuard interface, service control, or general shared folder may be
|
||||
mounted or forwarded into the guest.
|
||||
- A guest system D-Bus and PID 1 must be guest-local. Keep console management
|
||||
independent of the VPN under test. Tunnel probes target only synthetic
|
||||
addresses reachable through the test tunnel, never the NAT management path.
|
||||
- Provision only fixed, reviewed lab units/drop-ins and fixture hooks. Imported
|
||||
configuration text remains data. Preserve administrator settings and prove
|
||||
preflight refusal using synthetic fixtures rather than silently rewriting
|
||||
`SaveConfig`.
|
||||
- Exercise the public `Application::restart` flow with the real zbus service
|
||||
adapter and Rustix observer. A test seam may inject persistence failures only
|
||||
where already established; it may not replace service submission or runtime
|
||||
observation as evidence of systemd behavior. Alpine fixture apply remains
|
||||
separate evidence.
|
||||
- Run the actual release executable separately from any `cfg(test)` driver.
|
||||
Capture source/dirty identity, compiler/locked dependencies, target, artifact
|
||||
SHA-256, and dynamic-library requirements for both artifacts. Prove each
|
||||
executable starts in the guest.
|
||||
- Keep secrets out of argv, environment variables, image metadata, logs,
|
||||
transcripts, and evidence. Use bounded typed control, private files/channels,
|
||||
monotonic timeouts, and bounded output. A timeout after service submission
|
||||
means it may still complete; it is not cancellation.
|
||||
- Before every scenario, reset to a recorded clean guest state and verify both
|
||||
the pinned host identity and guest marker. Afterward, stop only resources
|
||||
created by that run and verify their exact IDs. If cleanup is uncertain,
|
||||
preserve IDs and report them; never use broad host cleanup. Preserve the
|
||||
original failure if cleanup also fails.
|
||||
|
||||
## Required scenario evidence
|
||||
|
||||
For every run, record UTC start/end, guest and base identities, kernel/systemd/
|
||||
D-Bus/WireGuard versions, both marker results, source/artifact identities, exact
|
||||
commands, exit status and bounded redacted outcomes, backup/archive identities,
|
||||
reset/cleanup result, and the acceptance criteria supported. Keep raw console
|
||||
output private; evidence must contain no secrets or complete client config.
|
||||
Record each scenario independently so failures cannot be masked by unrelated
|
||||
fixture behavior.
|
||||
|
||||
| Scenario | Required observable evidence |
|
||||
| --- | --- |
|
||||
| Successful apply and fast job | Existing synthetic client has positive tunnel-only IPv4 traffic. Through one `Application`, create and Commit a client; show saved/runtime divergence and that Commit did not submit a service job. Cancel preview with no backup/job/mutation. Confirm restart: pre-restart backup completes first, real zbus job for the resolved primary unit reaches `done`, Rustix observes the expected interface and complete matching peer/routes, and durable verification is written. Verify new tunnel traffic, reopen and show verification is historical. Repeat with fast completion and a configured alias resolving to the primary unit; retain the completion signal. Include application outcomes, not journal inference alone. |
|
||||
| Deletion and reservations | Establish positive traffic before deleting/Committing. Show the client remains in runtime and its address remains reserved until successful real restart and complete verification. Then show it absent, tunnel-only traffic fails within a bounded probe, durable reservation releases, and old backups remain. |
|
||||
| Failure and deadline | Using fixed guest-only units/drop-ins, show terminal job failure and submitted-job deadline expiry with bounded results, accurate submitted/may-still-complete status, no automatic retry/rollback, no false Verified state, and retained reservations. Also show unresolved unit fails before submission and backup failure prevents restart. After late completion, explicitly observe and reset the guest; timeout is not cancellation. |
|
||||
| Job succeeds, verification fails | A dedicated fixed fixture service completes while leaving the interface absent or peers mismatched. Show the real adapter reports verification failure and reservations remain. Separately inject saved-state write failure only through the established persistence seam after real restart/observation; show runtime changed without durable Verified state and `RecoveryRequired` blocks unsafe mutations. |
|
||||
| Restore and manual recovery | Preview and confirm a known-good archive without vault password. Show precautionary backup, full saved settings/config/vault replacement, and unchanged runtime before explicit restart. Then run real restart/verification and expected tunnel check. Demonstrate documented manual recovery; no hidden rollback. Confirm permissions and reopen behavior. |
|
||||
| Release executable smoke | In guest console/PTY, prove identified release binary starts from its private directory and settings resolve beside it. Exercise current-client/statistics view and one controlled Commit/restart through the real worker path; confirm exit/cancel restores terminal. Help/version work as non-root without settings; non-root management is rejected. Record output/backup permissions. |
|
||||
|
||||
The final M9 evidence must map these observations to M9-A1–A9 and the
|
||||
specification-to-evidence matrix. State the tested scope, including IPv4 tunnel
|
||||
coverage, synthetic dual-stack tests, unverified real IPv6 behavior, and
|
||||
QR/device interoperability limits. A mocked bus, Alpine fixture apply, missing
|
||||
prerequisite, skipped test, or guest boot alone does not satisfy real systemd
|
||||
acceptance.
|
||||
|
||||
## Next action
|
||||
|
||||
None while Milestone 9 is paused by the user. The disposable VM is powered off;
|
||||
do not resume installation, provision it, or run acceptance without a new
|
||||
explicit request. No M9-A1–A9 check is complete.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Milestone 9 diagnostics
|
||||
|
||||
Current execution state and acceptance are in [PLANS.md](../../PLANS.md). This
|
||||
file records bounded host preparation failures, not systemd acceptance evidence.
|
||||
All timestamps are UTC; the VM is disposable and contains synthetic data only.
|
||||
|
||||
## 2026-10-25T18:28:55Z — M9.1-R8, initial create parse
|
||||
|
||||
`python3 tests/vm/create.py` registered only
|
||||
`wga-m9-debian137-20261025` (UUID
|
||||
`b14c850b-a21e-4a56-acca-785590f0c4ac`) and stopped before VM configuration.
|
||||
Cause: actual VirtualBox 7.2.8 machine-readable output contains an indented
|
||||
`rec_screen0` recording section marker. The strict parser rejected it. Read-only
|
||||
inventory showed the target powered off with only its `.vbox` file; the existing
|
||||
Windows VMs were unchanged. A narrow marker parser repair and synthetic test
|
||||
passed independent re-review. Creation cannot be rerun because the target path
|
||||
is occupied; a UUID-pinned resume procedure was reviewed instead.
|
||||
|
||||
## 2026-10-25T18:35:00Z — M9.1-R5/R8, resume final guard
|
||||
|
||||
`python3 tests/vm/resume.py` verified the exact partial target, then configured
|
||||
the VDI, pinned installer ISO, NAT-only NICs, and private host marker/manifest.
|
||||
Its final read-only guard refused actual quoted SATA attachment keys and
|
||||
per-port metadata. `python3 tests/vm/guard.py check` first reported an
|
||||
unrecognized machine-readable key; after quoted-key parsing it reported an
|
||||
unrecognized attachment-shaped metadata key. Read-only `showvminfo` identified
|
||||
`SATA-IsEjected-1-0` among the actual metadata. Focused repairs accepted only
|
||||
the observed key forms, required the exact SATA controller, and rejected
|
||||
unrecognized/extra media and a symlinked target folder. Independent re-review
|
||||
closed the findings; the integrated synthetic VM suite passed 26/26 and the
|
||||
actual read-only `guard.py check` exited 0. No second resume or VM start occurred.
|
||||
|
||||
## 2026-10-25T18:47:20Z — M9.1 unattended prerequisite (recorded)
|
||||
|
||||
The first no-change `VBoxManage unattended install ... --dry-run --start-vm=none`
|
||||
refused a single-label hostname. Repeating with the fully qualified synthetic
|
||||
hostname `wga-m9-debian137.invalid` exited 0, including a separate dry run with
|
||||
the local Guest Additions ISO. Both used current-user mode-`0600` private
|
||||
synthetic password files. VirtualBox prints password values in dry-run output;
|
||||
the wrapper redacted them before display. These runs created no files or VM
|
||||
configuration changes. Actual installer preparation, boot, Guest Additions,
|
||||
and guest systemd remain unverified.
|
||||
|
||||
## 2026-10-25T18:53:05Z — M9.1 installer preparation (recorded)
|
||||
|
||||
Independent review found that the first prepare-only script omitted the
|
||||
required `--iso` and used an unsupported root-password option; its media
|
||||
comparison also rejected VirtualBox's empty SATA ports. M9.1-R9/R10 repairs
|
||||
passed re-review and 33/33 synthetic VM tests. The corrected
|
||||
`python3 tests/vm/install_prepare.py` exited 0 outside the sandbox with
|
||||
password-bearing VirtualBox output suppressed. Read-only `showvminfo` showed the
|
||||
same pinned VM powered off, NAT-only, with its one VDI at SATA 0 and the private
|
||||
generated `Unattended-<UUID>-aux-iso.viso` at SATA 1. Generated installer files
|
||||
were mode `0600` in the mode-`0700` target folder. The normal guard intentionally
|
||||
refuses `.viso`; first start awaits a separately reviewed installer-state guard.
|
||||
|
||||
## 2026-10-26T20:30:15Z — User stopped M9.1
|
||||
|
||||
The installer-state guard and start code passed independent review after a
|
||||
hard-link isolation repair; the full synthetic VM suite passed 44/44. Actual
|
||||
`python3 tests/vm/install_boot.py check` and `start` exited 0 against only the
|
||||
pinned target. Read-only `list runningvms` listed only that VM; a private
|
||||
console screenshot showed Debian base-system installation at 6%. Completion
|
||||
was not observed. After the user explicitly stopped Milestone 9, the exact VM
|
||||
was powered off; a subsequent read-only running-VM inventory was empty. Guest
|
||||
installation, Guest Additions, systemd, WireGuard, and M9 acceptance remain
|
||||
unverified. No existing Windows VM, production resource, Git commit, or
|
||||
deployment was touched.
|
||||
@@ -0,0 +1,42 @@
|
||||
# TUI navigation repair
|
||||
|
||||
Validated on 2026-10-26 at 22:32 +02:00. Bounded maintenance; M9 remains
|
||||
paused and unaccepted. No production, Alpine or VM execution was performed.
|
||||
|
||||
## Behavior and review
|
||||
|
||||
List Up/Down previously called the details-opening selection method. The repair
|
||||
separates highlighting from opening: arrows update selection, Enter opens the
|
||||
selected peer, and Esc returns to the list. Existing detail/help/message scrolling
|
||||
is preserved. Unsupported peers remain inspectable without mutation identity.
|
||||
Independent reviewer NAV-001 identified an initial-highlight mismatch; the repair
|
||||
treats the renderer's implicit first row as current. Re-review closed NAV-001
|
||||
with no remaining actionable scoped findings.
|
||||
|
||||
Regression coverage exercises initial Down, initial Up wrap, explicit selection,
|
||||
Enter, Esc, scroll reset and unsupported peer inspection. Focused command
|
||||
`cargo test --locked tui::terminal::tests::` passed 7/7.
|
||||
|
||||
## Integrated checks and identity
|
||||
|
||||
Rust/Cargo 1.97.1, native x86_64 GNU host. All commands exited 0:
|
||||
|
||||
- `cargo fmt --all -- --check`
|
||||
- `cargo clippy --locked --all-targets -- -D warnings`
|
||||
- `cargo test --locked`: 323 passed, 3 explicitly ignored, none failed,
|
||||
including 2 documentation tests. Ignored real-environment tests were not run.
|
||||
- `cargo build --locked --release`
|
||||
- `git diff --check`
|
||||
|
||||
Base commit: `f4a6540df9621c9c5e5d1430243f92e749356a59`. Dirty inputs include
|
||||
the navigation repair plus pre-existing documentation/VM preparation changes;
|
||||
the latter were preserved. SHA256 of changed Rust files:
|
||||
|
||||
- `src/tui/state.rs`: `3b9ea1540c26a372c781a8194cedff74bb56320a698ae28e56ce22f38d159c5d`
|
||||
- `src/tui/terminal.rs`: `368bf0be11c35202127b7ac5c95f62a312f9de9b464de6e6816cb4b7523cdb1e`
|
||||
|
||||
Native artifact `target/release/wireguard-admin` SHA256:
|
||||
`de5b7efe9f8615fcb13d8779a86451d62e64c3f1da976ba706d6773f8a573d9e`.
|
||||
This is host build and fixture evidence only; target-server deployment and
|
||||
interactive SSH confirmation remain unverified. Previous release artifact
|
||||
identities do not identify this build.
|
||||
Reference in New Issue
Block a user