703 lines
48 KiB
Markdown
703 lines
48 KiB
Markdown
# Milestone 8 historical execution record
|
||
|
||
Archived on 2026-10-24 during documentation workflow cleanup. This is a
|
||
historical snapshot, including superseded and contradictory status statements.
|
||
Use [PLANS.md](../../PLANS.md) for current state. Evidence below is preserved
|
||
as previously reported; no checks were rerun by this archival operation.
|
||
|
||
### Milestone 8 — Alpine Testcontainers integration
|
||
|
||
Status: in progress (2026-10-22; user removed IPv6 capability and traffic
|
||
testing from M8. The selected disposable daemon remains the test environment;
|
||
M8.4–M8.5 and real-container acceptance remain unrun).
|
||
Prerequisites: milestones 1–7 accepted; pinned Rust toolchain; an explicitly
|
||
selected disposable Docker-compatible Linux environment with kernel WireGuard,
|
||
scoped NET_ADMIN and IPv4 support; an Alpine-compatible test executable.
|
||
Missing prerequisites are blockers/incomplete evidence, never passing tests.
|
||
|
||
#### Outcome and scope
|
||
|
||
Add an opt-in Rust Testcontainers suite using small Alpine server/client images.
|
||
Exercise the actual application, encrypted vault/persistence/delivery APIs, and
|
||
M5's real rustix Generic Netlink reader inside the server container against real
|
||
kernel WireGuard interfaces. Establish real tunnels, generate IPv4 traffic,
|
||
and prove that saved changes remain separate from runtime application.
|
||
The user explicitly excluded IPv6 capability and traffic tests on 2026-10-22.
|
||
Production dual-stack behavior in SPEC.md is unchanged; real IPv6 behavior is
|
||
therefore unverified by this milestone.
|
||
|
||
Read SPEC.md Operations and states, Connection delivery, Backups and restoration,
|
||
Client screen and statistics, and acceptance criteria; ADRs 0001–0003; TESTING.md,
|
||
ENVIRONMENT.md, RUNTIME.md, DELIVERY.md, VAULT_FORMAT.md, PERSISTENCE.md,
|
||
BACKUP_FORMAT.md, DEPENDENCIES.md and current application/worker code.
|
||
|
||
This is real-WireGuard integration, not real-systemd acceptance. Alpine fixtures
|
||
have no systemd; a test-only apply operation may configure the interface explicitly.
|
||
Actual zbus service job behavior, production restart and VM acceptance remain M9.
|
||
M7's synthetic TUI/PTY evidence remains separate; M8 does not require live terminal
|
||
screens, phone QR decoding, public Internet access, external DNS, production
|
||
configuration, new product commands, or a production apply mode.
|
||
|
||
#### Existing code and integration constraints
|
||
|
||
- M1–M7 are accepted. The normal executable now starts the management TUI; do not
|
||
invoke it with host/production settings as a shortcut for a test driver.
|
||
- Application has open-from-store, setup/import, creation, Commit, delivery/reissue,
|
||
deletion, backup/list/restore and confirmed restart flows. Use these real APIs,
|
||
not a parallel shell-only client manager that would leave application behavior
|
||
untested. Public-key identity and source preservation remain authoritative.
|
||
- Real observation is `runtime::transport::observe_interface`, currently crate-
|
||
private, with the validated decoder and bounded rustix transport. Do not use
|
||
only `wg show` output or a fake observation as evidence that this reader works.
|
||
- `Application::restart` always invokes the actual zbus path, while injected
|
||
restart functions are private. Plan an in-crate test seam so a test-only fixture
|
||
service operation can apply peers and the real observation/persistence path can
|
||
verify them. Preserve backup ordering and per-attempt authority from M5.
|
||
- Prefer cfg(test) in-container test scenarios/driver code, compiled for musl and
|
||
selected explicitly, to reach private adapters without exposing an unauthenticated
|
||
public apply API. If another arrangement is needed, document its compile-time
|
||
isolation before implementation. No environment variable may switch production
|
||
restart to a fake service or bypass password/backup/root checks.
|
||
- The TUI ApplicationWorker already has synthetic workflow tests. An optional
|
||
in-container worker scenario may test its real statistics reader, but network
|
||
acceptance must not depend on automating every terminal key sequence again.
|
||
- No Testcontainers crate, container image recipe or integration driver is present.
|
||
Add approved `testcontainers` as a dev-dependency with compatible pinned version
|
||
and minimal features. Prefer its supported synchronous facade if it avoids a
|
||
direct executor dependency. Other direct helpers, Docker client crates or
|
||
Tokio still require prior agreement; transitive dependencies are not new direct
|
||
approvals. Use Cargo.lock and inspect official APIs for the selected version.
|
||
- Native tools use system Rust 1.97.1; musl readiness was previously unverified.
|
||
Recheck rather than assuming rust-toolchain.toml installed targets or a linker.
|
||
|
||
#### Context and implementation steps
|
||
|
||
Use GPT-6-Sol/medium coordination and GPT-6-Luna/high implementation, fresh review
|
||
and repairs. Execute bounded tasks sequentially with one writer and explicit file
|
||
ownership. The coordinator alone updates milestone acceptance and evidence.
|
||
|
||
| Task | Owner | Files and deliverable |
|
||
| --- | --- | --- |
|
||
| M8.1 | implementer | `docs/TESTING.md`/ENVIRONMENT additions and test support: exact opt-in architecture, prerequisites, image/build and driver contracts |
|
||
| M8.2 | implementer | `tests/containers/alpine/Dockerfile`, fixture-only setup scripts, musl build recipe: small reproducible cached image and executable compatibility checks |
|
||
| M8.3 | implementer | `tests/testcontainers_wireguard.rs`, `tests/support/` modules and Cargo files: host orchestration, private network/container ownership, prerequisite checks, bounded execution and cleanup |
|
||
| M8.4 | implementer | in-crate cfg(test) scenarios/private adapters, test driver coordination: real netlink reads, fixture apply and application state verification inside server |
|
||
| M8.5 | implementer | container scenarios and TESTING/README documentation: required lifecycle, restore, delivery/import/failure assertions and executed evidence |
|
||
| M8.6 | reviewer, repairer | Independent isolation, real-adapter coverage and negative-test review; bounded fixes and real-suite re-review |
|
||
| M8.7 | coordinator | Default and explicit container gates, redacted results, prerequisites/limitations, acceptance and M9 handoff |
|
||
|
||
M8.1 defines two execution locations: host harness uses Testcontainers to manage
|
||
containers; server-side code uses the real application and kernel reader in that
|
||
container's namespaces. Document how driver sessions persist across staged create,
|
||
Commit, first delivery and apply phases, and how the client is configured from the
|
||
actual delivered file. Do not lose the creation session between Commit and first
|
||
issue or reconstruct password-free authority on reopen.
|
||
|
||
Choose a named ignored integration target/scenarios or another explicit opt-in
|
||
mechanism that default cargo test never starts. The host suite must also opt into
|
||
all in-container scenario processes. Ensure --ignored does not select unrelated
|
||
privileged tests. Fail an explicitly requested suite nonzero on missing required
|
||
prerequisites; never return early with a successful test result labelled skipped.
|
||
|
||
M8.2 pins an Alpine base release/digest and records the resolved image identity
|
||
and package versions. Install only wireguard-tools, iproute2 and minimal fixture
|
||
requirements. Use BusyBox capabilities when sufficient; justify any extra package
|
||
in the test recipe. Runtime images contain no Cargo registry/compiler or systemd.
|
||
Build/cache image layers and compatible driver artifacts before repeated tests;
|
||
use fresh mutable containers/volumes for each scenario, not reusable dirty servers.
|
||
Keep build context small with explicit copies/ignore rules, no .git, host Backup,
|
||
credentials or private configuration. Never bake generated keys into image layers.
|
||
|
||
Build server/client driver code for x86_64-unknown-linux-musl or in a pinned
|
||
Alpine builder matching the toolchain. Inspect dynamic requirements and actually
|
||
execute a harmless readiness command inside Alpine. Do not rely on a glibc host
|
||
binary, target name or successful host compilation as runtime compatibility proof.
|
||
Only build required test targets; avoid pulling compiler/debug layers into the
|
||
small runtime fixture. No global package installation or toolchain update is
|
||
implicitly authorized by a missing cross-build prerequisite.
|
||
|
||
M8.3 checks Docker API access and explicit disposable-environment selection.
|
||
Do not use a configured remote daemon without establishing that it is the selected
|
||
non-production test environment. Probe WireGuard interface creation inside
|
||
a disposable probe container, never by creating host interfaces or loading modules.
|
||
Container tools alone do not supply the host kernel module. Refuse to repair
|
||
prerequisites via SYS_MODULE, privileged mode or host sysctl changes automatically.
|
||
|
||
Create a dedicated uniquely named IPv4 network with a test subnet that does
|
||
not overlap the tunnel ranges. Run server/client as container root with scoped
|
||
NET_ADMIN in their own network/PID namespaces; no host networking, namespace joins
|
||
to host, host D-Bus, host /etc/wireguard, Docker socket mount, or production binds.
|
||
No host UDP publication is needed for container-to-container endpoints. Use
|
||
container-internal reachable endpoint/port values, not localhost mapped ports.
|
||
All settings/server/vault/output paths are private fixture directories created
|
||
with the application's required permissions.
|
||
|
||
Use Testcontainers copy/exec APIs or an explicitly safe bounded transport for
|
||
fixture data. Secret-bearing configs/passwords never enter command arguments,
|
||
image metadata, public environment variables or raw stdout/stderr logs. Any
|
||
necessary copied plaintext exists only in private temporary/container storage.
|
||
Generate keys per scenario. Reports carry public keys, phase/status and redacted
|
||
categories, not full configurations, QR matrices or `wg show all dump` output.
|
||
|
||
Bound image/start/driver/readiness/traffic/teardown operations. Poll explicit
|
||
conditions with monotonic deadlines, not fixed sleeps. Use unique ownership and
|
||
RAII/explicit cleanup for containers, networks and volumes on failures as well as
|
||
success; cleanup must not mask the original failure or delete unrelated resources.
|
||
Do not default to retain-failed-containers with secrets. Report leftover owned
|
||
resources if daemon failure prevents cleanup.
|
||
|
||
M8.4 keeps fixture `ip`/`wg` calls solely in setup or test-only apply code. It may
|
||
use wg-quick strip or equivalent explicit fixture setup, but must not execute
|
||
arbitrary imported hooks. Handle optional DNS/MTU fields in delivered configs via
|
||
a documented fixture setup, without mutating the delivered payload just to pass.
|
||
Avoid an unneeded resolvconf dependency by configuring networking explicitly when
|
||
appropriate. No subprocess apply path is added to production.
|
||
|
||
Configure endpoint reachability outside the tunnel before full-tunnel policy so
|
||
an encrypted UDP endpoint is not recursively routed into its own VPN. Set full
|
||
IPv4 routes within the client's isolated namespace only. Exercise traffic
|
||
to server tunnel addresses; an external Internet gateway/DNS is not required and
|
||
successful tunnel reachability does not claim public Internet egress works.
|
||
Ensure test success cannot come from the Docker underlay: target tunnel-only
|
||
addresses, use an explicit interface/route assertion, and verify public counters
|
||
through the actual rustix reader. Test-only service apply reports must be labelled
|
||
fixture results, never actual systemd job evidence.
|
||
|
||
If fixture restart orchestration verifies and releases application reservations,
|
||
use the existing private adapter seam with a real backup, fixture apply, actual
|
||
netlink read/comparison and journaled verification. Do not simply call
|
||
mark_applied or clear reservations to satisfy assertions. A direct fixture apply
|
||
outside that orchestration proves only kernel state change; it cannot by itself
|
||
prove the production successful-restart state transition.
|
||
|
||
M8.5 implements these required scenarios, splitting tests where isolation helps:
|
||
|
||
1. **Baseline and reader interoperability.** Bring up a server plus an existing
|
||
client with synthetic configuration, establish real IPv4 tunnel traffic,
|
||
and observe the configured interface's complete peer set, routes, nonzero fresh
|
||
handshake and increasing counters through the actual Rust reader. Capture
|
||
before/after counters, not exact packet-byte totals. Empty/not-yet-handshaken
|
||
observations must not be misreported as a reader failure or online heuristic.
|
||
2. **Create, Commit, deliver, then apply.** Use Application to prepare a new client,
|
||
Commit and save the actual first-delivery file (QR optional). Assert saved
|
||
server/vault change, mandatory pre-Commit archive, unchanged runtime peers and
|
||
explicit activation warning. Configure a fresh client from delivered bytes;
|
||
prove it cannot reach tunnel-only targets before apply. Apply through the
|
||
test-only boundary, then require real handshake and IPv4 traffic.
|
||
3. **Saved deletion versus live access.** Delete and Commit an active client;
|
||
assert current vault record removal, existing backup retention, and unchanged
|
||
runtime peer/access before apply. Reopen saved state to verify the IP remains
|
||
reserved. After fixture restart plus real verification/persistence, assert
|
||
peer removal, failed fresh tunnel traffic and address release. Use a finite
|
||
negative-check window and establish a working baseline so unrelated setup
|
||
failure cannot masquerade as successful revocation.
|
||
4. **Backup/restore separation.** Save a known client set, mutate/Commit, preview
|
||
and restore the archive without providing a vault password. Assert restored
|
||
settings/server/vault/state and precautionary backup, plus unchanged kernel
|
||
state until explicit fixture apply. Then verify the restored peer set and
|
||
renewed tunnel traffic. Restoration alone never releases pending addresses.
|
||
5. **Import, reissue and file safety.** Import a valid generated existing client
|
||
plus invalid/conflicting candidates from private source files. Assert original
|
||
bytes unchanged, anomalies visible and conflicts blocked. Reopen and reissue
|
||
a matched client through password-authorized output; verify wrong password
|
||
fails and a valid delivered file can configure a real tunnel. Preserve first-
|
||
issue/password boundaries and do not add plaintext source fallback.
|
||
6. **Failure prevents application.** Produce a deterministic backup failure in the
|
||
container (not chmod-only when root can bypass it) and assert Commit/fixture
|
||
restart does not install/apply prepared changes or release addresses. Cover
|
||
default reader deadline/missing-interface behavior inside its namespace without
|
||
changing host state. Keep already exhaustive malformed/archive/failure-unit
|
||
cases in ordinary tests rather than duplicating them in every costly container.
|
||
|
||
For all negative reachability assertions, stop/restart client traffic as needed
|
||
and use new requests; stale timestamps/counters or buffered packets cannot prove
|
||
continued/revoked access. Use a fixture endpoint/traffic generator with its own
|
||
bounded error classification. Record that IPv6 traffic is intentionally untested.
|
||
|
||
#### Acceptance and validation
|
||
|
||
- [ ] M8-A1: documented opt-in commands run an actual Testcontainers suite with
|
||
pinned/cached Alpine runtime images and compatible in-container driver; default
|
||
tests/help/version do not start Docker, require root or query host interfaces.
|
||
- [ ] M8-A2: explicit prerequisite checks reject unavailable daemon/kernel/capability
|
||
or incompatible artifacts as incomplete/failure; no production or automatic
|
||
privileged/module/sysctl workaround is used.
|
||
- [ ] M8-A3: isolated real peers establish IPv4 traffic, and the actual
|
||
rustix reader reports complete public peer/routes, fresh handshake and traffic
|
||
increments without relying solely on wg text or fake decoded observations.
|
||
- [ ] M8-A4: new client creation/Commit/file delivery use real Application and vault
|
||
APIs; the delivered configuration works only after explicit fixture application,
|
||
and Commit itself never changes runtime state.
|
||
- [ ] M8-A5: saved deletion removes only current secret, keeps archives and retains
|
||
reservation/live peer until explicit apply; actual observation and journaled
|
||
verification precede reservation release. Fresh traffic is revoked afterward.
|
||
- [ ] M8-A6: password-free restore replaces the saved set but does not apply it;
|
||
fixture apply restores real tunnel behavior. Source files remain unchanged and
|
||
imported conflict/wrong-password outputs remain blocked.
|
||
- [ ] M8-A7: deterministic mandatory-backup failure prevents protected write/apply;
|
||
negative traffic and missing-interface results cannot pass due to unrelated
|
||
broken setup or a silent empty/partial observation.
|
||
- [ ] M8-A8: fixture adapter cannot be selected in production or bypass root/password/
|
||
backup controls; no public alternate restart API or runtime environment bypass
|
||
is introduced. Alpine results explicitly exclude actual zbus/systemd coverage.
|
||
- [ ] M8-A9: secret-free diagnostics, private copied files, limits/deadlines and
|
||
cleanup work on both success and failure; only test-owned resources are removed.
|
||
- [ ] M8-A10: integrated default and real-container gates pass; a clean repeated run
|
||
reuses image layers while starting fresh mutable scenarios and produces the same
|
||
behavioral outcomes. Independent review closes actionable isolation/coverage issues.
|
||
|
||
Planned host commands once the proposed test target and documented image/driver
|
||
build steps exist, from repository root:
|
||
|
||
```sh
|
||
cargo fmt --all -- --check
|
||
cargo clippy --locked --all-targets -- -D warnings
|
||
cargo test --locked
|
||
cargo build --locked --release
|
||
cargo test --locked --test testcontainers_wireguard -- --ignored --test-threads=1
|
||
./target/release/wireguard-admin --help
|
||
./target/release/wireguard-admin --version
|
||
git diff --check
|
||
```
|
||
|
||
Document and execute exact image-build and in-container driver-build commands in
|
||
TESTING.md before the explicit suite command; include prerequisites and output
|
||
artifact paths. The in-container target must exist before claiming those commands
|
||
work. A musl cargo test --no-run build is one possible cfg(test) driver mechanism;
|
||
resolve its actual compilation/link/dependency implications rather than listing
|
||
an unverified artifact name. Network downloads/build setup are distinct from
|
||
locked test execution, and new dependencies require the normal approval policy.
|
||
|
||
Record image identities, kernel/runtime/toolchain versions, target architecture,
|
||
scenario names and actual outcomes/durations/counts. All required scenarios must
|
||
execute and pass before M8 acceptance; compile-only/default-test success with
|
||
unavailable Docker is not scoped acceptance of M8. Do not use a successful
|
||
ignored-test summary as evidence that ignored tests ran. Real systemd remains M9.
|
||
|
||
#### Progress
|
||
|
||
- [x] Description prepared against accepted M1–M7 and approved Alpine methodology.
|
||
- [x] M8.1 — implementer `/root/m8_1` prepared the host/container contract in
|
||
`docs/TESTING.md` and `docs/ENVIRONMENT.md`; documentation link and diff checks
|
||
passed. Fresh independent reviewer `/root/m8_1_review` raised M8.1-R1, which
|
||
`/root/m8_1_repair` corrected and the reviewer closed on re-review. Exact
|
||
driver transport remains an M8.4 decision against the pinned Testcontainers API.
|
||
- [x] M8.2 — implementer `/root/m8_2` added a pinned Alpine runtime recipe,
|
||
allowlisted context, package record and harmless readiness script, plus
|
||
documentation. Fresh reviewer `/root/m8_2_review` raised M8.2-R1/R2;
|
||
`/root/m8_2_repair` repaired both and independent re-review closed them.
|
||
Selected-daemon image build and rebuild with 33 exact package constraints,
|
||
image inspection (`sha256:f41cd6b848d8280d4d86bcaceea962e1b3e5a73e9496c6f9d7929470d0e874d5`,
|
||
linux/amd64), read-only/networkless/capability-dropped readiness and full
|
||
`apk info -v` lock match passed. Rust driver execution awaits M8.4.
|
||
- [x] M8.3 — implementer `/root/m8_3` added the approved Testcontainers 0.28.0
|
||
blocking development dependency and named ignored host probe. Focused fmt,
|
||
Clippy and default locked tests passed; explicit selected-daemon run failed
|
||
nonzero before network creation because Docker lacks IPv6 iptables support.
|
||
Independent reviewer `/root/m8_3_review` raised M8.3-R1/R2/R3; targeted
|
||
repairs by `/root/m8_3_repair` and independent re-reviews closed all three.
|
||
This completes the bounded host-probe implementation, not the blocked
|
||
real-container M8 acceptance. No tunnel scenario has run.
|
||
- [x] M8.3 scope revision — `/root/m8_ipv4_revision` changed only the
|
||
test harness and guidance to use isolated IPv4 networking as requested by the
|
||
user. Default gates pass; the selected-daemon probe passed 1/1 after R4–R7
|
||
repairs. Independent `/root/m8_ipv4_review` re-reviews closed all findings.
|
||
- [x] M8.4 — implementer `/root/m8_4_driver` added the in-crate test-only driver
|
||
and private runtime/application seams; musl builder prerequisite research is
|
||
complete from `/root/m8_musl_explore`. The exact ignored readiness and
|
||
Application smoke run in the pinned Alpine image. Independent
|
||
`/root/m8_4_review` and `/root/m8_4_host_review` raised R1–R4; targeted
|
||
repairers closed all findings on re-review. The coordinator rebuilt the final
|
||
musl test binary, reran the selected-daemon smoke (1/1, 4.05s), and found no
|
||
leftover named resources. M8.5 scenarios remain pending.
|
||
- [ ] M8.5 — `/root/m8_5_traffic` owns the first bounded scenario set:
|
||
delivered-file client transfer, baseline real peer observation, pre-Apply
|
||
nonreachability and post-Apply IPv4 tunnel/handshake/counter proof. Deletion,
|
||
restore, import/reissue and backup-failure scenarios follow sequentially;
|
||
independent review and full real-suite evidence are pending. Local focused
|
||
support tests currently pass 18/18 with one ignored privileged target, and
|
||
default `cargo test --locked` passed 250 library tests plus other suites;
|
||
the current musl driver built in the pinned Alpine builder (5m06s). The first
|
||
selected-daemon traffic run reached the scenario but failed a stale pre-Apply
|
||
assertion that expected zero peers even though the new required baseline peer
|
||
remained applied. The assertion is being changed to require exactly that
|
||
baseline and exclude the new peer; no traffic acceptance is claimed yet.
|
||
A later bounded run reached fixture Apply but `preview_restart` rejected the
|
||
raw baseline peer because it lacked managed alias metadata. The synthetic
|
||
fixture is being corrected through `ConfigDocument::insert_legacy_metadata`
|
||
before saved state opens. Cleanup completed after that failed run; real
|
||
traffic acceptance is still pending.
|
||
The next real run passed baseline handshake/counters, new-client Create,
|
||
Commit and delivery, pre-Apply peer exclusion, verified fixture Apply and
|
||
IPv4 ping. It failed only an overly exact host route-string assertion:
|
||
actual new-peer routes include product-required `0.0.0.0/0` and `::/0`.
|
||
The assertion is being made IPv4-specific; no IPv6 capability or traffic
|
||
test is being added. A final successful traffic suite is still pending.
|
||
A subsequent reader sample after IPv4 ping showed the new peer's fresh
|
||
handshake and nonzero received/transmitted counters (916/732 bytes in that
|
||
run). The host assertion still used the wrong route perspective: on the
|
||
server, the peer's AllowedIPs are its assigned tunnel hosts, not the client's
|
||
full-tunnel routes. The assertion is being corrected to the assigned IPv4
|
||
`/32`; the delivered client file is where `0.0.0.0/0` belongs. No passing
|
||
end-to-end traffic summary is claimed yet.
|
||
The host then added an immediate post-Apply/pre-ping reader sample and
|
||
requires both received and transmitted counters to rise after a new IPv4
|
||
ping. The worker's final turn stalled after implementing this assertion;
|
||
coordinator stopped that turn, ran the exact selected-daemon test once and
|
||
observed 1/1 pass in 16.25s. Exact-name Docker container/network listings
|
||
were empty afterward. Fresh independent `/root/m8_5_traffic_review` is
|
||
inspecting the integrated scenario. That reviewer raised M8.5-R1 (P2):
|
||
the fresh client used a host-derived setconf copy rather than consuming the
|
||
intact copied first-delivery file, so traffic did not prove the artifact is
|
||
usable. M8.5-R2 (P2): route assertions accepted unintended extra IPv4
|
||
prefixes. `/root/m8_5_traffic_repair` owns targeted fixes and real-suite
|
||
rerun. Exact route assertions apply to IPv4 only per user direction; no IPv6
|
||
capability or route check is added. This bounded slice is not yet accepted;
|
||
remaining M8.5 scenarios have not started.
|
||
The repair added private client-copy byte comparison, in-container
|
||
`wg-quick strip` consumption of the copied file, and exact IPv4 route-set
|
||
assertions. The first sandboxed selected-daemon attempt was denied Docker
|
||
access; the elevated rerun reached the scenario and failed nonzero at the
|
||
fixed category `copied client configuration could not be safely stripped`.
|
||
The strip prerequisite/fixture invocation is being diagnosed with synthetic
|
||
inputs; no secret config was logged and no repaired traffic pass is claimed.
|
||
Synthetic diagnostics isolated the cause to a copied `.conf` basename longer
|
||
than wg-quick's 15-character interface-name limit. The repair uses short
|
||
fixed private names without changing file bytes. The worker turn stalled
|
||
after editing; coordinator stopped it and ran the repaired selected-daemon
|
||
test once: 1/1 pass in 14.23s, with no named container/network afterward.
|
||
Focused host target passed 21 tests with one ignored privileged test; fmt and
|
||
diff checks passed. Independent R1/R2 re-review was interrupted by an agent
|
||
usage limit before a finding report, so `/root/m8_5_traffic_review` resumed
|
||
on 2026-10-24. That independent re-review closed both findings with no new
|
||
issue: the copied first-delivery bytes are compared privately and consumed
|
||
by wg-quick in the client namespace; exact IPv4 route sets reject extra
|
||
prefixes. The bounded baseline/new-client traffic slice is complete as
|
||
Alpine fixture evidence. `/root/m8_5_delete` now owns saved deletion versus
|
||
live access. Its local fmt, full locked tests (251 library passed, two
|
||
ignored), all-target Clippy, release build and focused saved-deletion test
|
||
passed; pinned musl rebuild passed. The coordinator's exact selected-daemon
|
||
run failed 1/1 after saved deletion: the baseline client's fresh IPv4 ping
|
||
stopped before explicit fixture Apply. This is a real-scenario failure, so
|
||
deletion is not accepted. `/root/m8_5_delete_repair` owns diagnosis and a
|
||
targeted repair. A fresh continuity probe moved immediately after the prior
|
||
new-client fixture Apply failed 1/1 on the same selected daemon in 14.25s;
|
||
the baseline disruption therefore precedes deletion Commit. A separate
|
||
sandbox-only attempt could not access Docker and supplies no scenario evidence.
|
||
A bounded selected-daemon diagnostic run then failed 1/1 in 15.52s and
|
||
reported the baseline peer still present with exact IPv4 route but no fresh
|
||
handshake, zero reset counters, no learned endpoint and three lost pings
|
||
after full fixture `wg setconf`. The repair is testing explicit reconnect of
|
||
the existing client after that fixture apply, then requiring new traffic and
|
||
reader evidence before continuing the deletion assertions. That reconnect
|
||
passed far enough to reach deletion Apply. A pinned musl rebuild and exact
|
||
selected-daemon run reported `RestartStage::Complete`, followed by fixture
|
||
phase failure; inspection identified the release assertion parsing the
|
||
client's CIDR as bare `IpAddr`. A targeted typed-address repair and rerun are
|
||
complete. The next exact selected-daemon run reached post-deletion observation
|
||
and exposed that full fixture `wg setconf` resets the baseline handshake and
|
||
counters again; the harness now proves the exact retained/deleted peer set
|
||
immediately, then reconnects the retained client and requires fresh traffic
|
||
and reader counter deltas while fresh traffic from the deleted client fails.
|
||
The coordinator's integrated exact run passed 1/1 in 24.88s, host support
|
||
tests passed 22 with one privileged test ignored, focused CIDR validation
|
||
passed, fmt/diff checks passed, and exact-name Docker container/network
|
||
listings were empty. Fresh independent `/root/m8_5_delete_review` raised
|
||
M8.5-R3 (P2): the negative ping helper treats any Docker CLI nonzero exit,
|
||
including failed `docker exec`, as lost tunnel traffic. `/root/m8_5_delete_repair`
|
||
is changing it to require a bounded ping summary with transmitted packets and
|
||
zero received packets. The repaired host support target passed 23 tests with
|
||
one ignored, the coordinator's exact selected-daemon rerun passed 1/1 in
|
||
42.96s, and exact-name container/network listings were empty. Independent
|
||
`/root/m8_5_delete_review` closed R3 on re-review with no new finding:
|
||
completed zero-reply traffic is distinguished from Docker execution and
|
||
timeout errors. The saved-deletion bounded slice is accepted as Alpine IPv4
|
||
fixture evidence. `/root/m8_5_restore` implemented the two-restore scenario:
|
||
pre-delete archive re-adds a saved client while runtime remains baseline-only;
|
||
an earlier baseline archive later removes a saved live client and retains its
|
||
address reservation until verified fixture Apply. Local fmt, focused tests,
|
||
locked full tests, all-target Clippy, release build and diff check passed.
|
||
Pinned musl rebuild passed, but the coordinator's first selected-daemon run
|
||
failed 1/1 after 7.47s because the host archive-name parser selected the
|
||
driver's `status=started` line rather than its completed result line. The
|
||
targeted parser repair passed focused tests and the next real run advanced
|
||
through the first password-free restore, explicit Apply and renewed restored
|
||
client traffic. It failed 1/1 after 58.28s at the second restore of the
|
||
baseline archive (`phase=restore status=started` only). A separate repairer
|
||
is diagnosing that in-container phase with bounded diagnostics before another
|
||
pinned musl rebuild, selected-daemon rerun and independent review.
|
||
Import/reissue and backup-failure slices remain pending.
|
||
- [ ] M8.6 — independent implementation reviews and repairs complete for
|
||
M8.1–M8.3 only; M8.4–M8.5 and integrated real-scenario review pending.
|
||
- [ ] M8.7 — prior default coordinator gates pass; the revised explicit
|
||
real-container gate and remaining scenarios are pending. Acceptance incomplete.
|
||
|
||
#### Review and repair
|
||
|
||
Record stable finding IDs, iteration, location/impact,
|
||
owner, fix evidence and disposition. Review actual namespace/daemon targeting,
|
||
secret transport/logs, capability/mount boundaries, endpoint/full-route setup,
|
||
real-reader invocation and state-persistence proof. Re-review negative tests so
|
||
underlay connectivity or an unrelated failed setup cannot produce false success.
|
||
The user-authorized IPv6 testing exclusion applies only to M8 integration tests;
|
||
do not replace real IPv4 observations with mocks.
|
||
|
||
M8.1 R1 review dispatched after coordinator inspected the two-file documentation
|
||
diff. M8.1-R1 (low): `docs/TESTING.md` linked `SyncRunner` under the wrong
|
||
Testcontainers module; repair changed the link to `runners/trait.SyncRunner.html`.
|
||
Independent re-review closed the finding. Both rounds reported `git diff --check`
|
||
passing on the M8.1 docs; link/consistency checks passed. No Docker evidence.
|
||
|
||
M8.2 R1 review of the actual image recipe/docs raised two P2 findings:
|
||
M8.2-R1 (`runtime-check.sh`): planned libtest artifact cannot accept the
|
||
script's custom `--readiness` argument. M8.2-R2 (Dockerfile/package record):
|
||
direct package pins still resolve dependencies from a mutable Alpine repository,
|
||
and the record/inspection omits the installed closure. Targeted repair
|
||
`/root/m8_2_repair` addressed both. Reviewer confirmed the pinned direct package
|
||
versions and Alpine platform digest from primary indexes, plus passing shell
|
||
syntax, documentation link and diff checks. R1 re-review closed both recipe
|
||
findings after the repair. `runtime-check.sh` now uses a libtest-compatible
|
||
exact ignored selector; the test itself remains pending M8.4. The full installed
|
||
closure was recorded as 33 exact constraints; a second build succeeded with the
|
||
lock, and read-only shell readiness and inspection passed on the selected daemon.
|
||
The reviewer did not independently rerun the Docker commands. Coordinator also
|
||
ran a disposable `--network none --cap-add NET_ADMIN` Alpine probe that created
|
||
and removed `wg-m8-probe` and added an IPv6 address inside that namespace
|
||
(exit 0); no host interface, module, or sysctl operation was performed.
|
||
|
||
M8.3 R1 review raised M8.3-R1 (P2, `tests/testcontainers_wireguard.rs`): the
|
||
outer timeout detaches a worker that may later create/hold test resources, so
|
||
timeout cleanup is not guaranteed. First repair used a killed child and
|
||
label-verified cleanup, but independent re-review kept R1 open because a
|
||
Testcontainers request can run for 120 seconds and finish after the 75-second
|
||
kill/cleanup pass. Second repair made the probe synchronous, retained finite
|
||
per-request limits, added conservative aggregate documentation and explicitly
|
||
reports uncertain late daemon completion. Independent re-review closed R1.
|
||
The same re-review raised M8.3-R2 (P2, `container_harness.rs`): fixture exec
|
||
stream reads can block indefinitely if a command hangs, invalidating the
|
||
documented aggregate bound. First R2 repair wrapped commands in BusyBox
|
||
`timeout`, capped retained output and drained streams, but independent re-review
|
||
kept R2 open because the host attach read can still block after the stream is
|
||
established. Coordinator separately verified BusyBox timeout in the cached
|
||
Alpine image with a harmless delayed command (one-second elapsed inside,
|
||
status 137); this does not prove the host stream is bounded. Second R2 repair
|
||
uses a bounded Docker CLI exec transport and independent re-review closed R2.
|
||
That re-review raised M8.3-R3 (P2, `container_process.rs`): the CLI exit code
|
||
for an in-container timeout was discarded, so a timed-out command could be
|
||
misclassified as a generic capability failure. Targeted repair mapped CLI exit
|
||
codes 124/137/143 to the fixed timeout category, and independent re-review
|
||
closed R3. No open M8.1–M8.3 review finding remains. The host-side bounded CLI
|
||
exec path is not runtime-tested because network creation fails first.
|
||
The selected-daemon explicit harness failed before network/container creation
|
||
with `Docker host lacks required IPv6 iptables support`; separate disposable
|
||
regular, internal and routed dual-stack network attempts failed on missing
|
||
IPv6 NAT, `DOCKER-INTERNAL` filter and `DOCKER` filter chains respectively.
|
||
No host networking, firewall, module, or sysctl remediation was attempted.
|
||
|
||
M8.4 R1 independent review of `src/container_driver.rs` raised M8.4-R1 (P1):
|
||
the only runnable ignored driver test is harmless readiness; no bounded
|
||
in-container phase protocol retains an Application across create, Commit,
|
||
delivery and fixture apply, so the new seam cannot yet reach real Rustix
|
||
observation or lifecycle assertions. M8.4-R2 (P2): `SetWireGuard` lexical path
|
||
validation allows a symlink under the fixture root to escape. Focused 7 driver
|
||
argument tests passed, but no live fixture command ran. Targeted repair is
|
||
pending; no M8.4 acceptance is claimed.
|
||
|
||
M8.4 R1/R2 first repair by `/root/m8_4_repair` added an ignored
|
||
`alpine_scenario_driver`, a bounded typed stdin/stdout phase protocol retaining
|
||
one Application through Create, Commit, first delivery and fixture Apply, plus
|
||
real Rustix verification through the test-only restart seam. It also added
|
||
symlink component rejection and a regular-file/confined-path check for
|
||
`wg setconf`; 10 focused driver tests, default tests (244 library tests, two
|
||
ignored), fmt, all-target Clippy, release build and diff check passed. One
|
||
initial default run had a transient TUI `Busy` failure; immediate rerun passed.
|
||
Independent `/root/m8_4_review` re-review closed R2. It kept R1 open (P2):
|
||
the existing host harness has no bounded stdin channel to invoke the driver,
|
||
and the protocol does not yet cover M8.5's remaining lifecycle operations.
|
||
The next bounded repair is host protocol transport and a real in-container
|
||
Create/Commit/Deliver/Apply smoke path; M8.5 owns the additional scenarios.
|
||
After the 2026-10-23 daemon/session interruption, coordinator inspection found
|
||
no host-transport edits from the interrupted worker. `/root/m8_4_host_repair`
|
||
was dispatched with ownership of the host harness and test-only driver to
|
||
resume R1; no scenario acceptance is inferred from the prior musl readiness.
|
||
The worker added bounded `docker exec -i` phase exchange and a private synthetic
|
||
fixture bootstrap. Its current musl driver rebuilt in the pinned Alpine builder
|
||
in 3m04s; focused host/driver checks and all-target Clippy passed. On the
|
||
selected daemon, a first smoke attempt failed before application phases with a
|
||
generic Docker category and left no owned resources. A diagnostic rerun passed
|
||
link-up, IPv4 address setup, binary copy and chmod, then failed inside the
|
||
application driver protocol. The failure stage is being isolated with fixed
|
||
redacted phase markers; neither run is scenario acceptance. The worker also
|
||
changed generated settings/server secret files to mode 0600 at creation and
|
||
discovers the fixture endpoint inside the server namespace.
|
||
The phase markers subsequently localized the error to Create: the synthetic
|
||
server document lacked `[Interface] Address`, which the actual application
|
||
requires for server address ownership. The fixture now includes IPv4/IPv6
|
||
server addresses in saved configuration while removing the wg-quick-only
|
||
`Address` directive from a private 0600 copy passed to `wg setconf`. The
|
||
authoritative saved file is unchanged. This is fixture setup, not an IPv6
|
||
capability or traffic check. A unique per-apply copy and exact cleanup are
|
||
being added for repeated M8.5 apply phases; the corrected real smoke rerun
|
||
is pending. One subsequent scenario process exited zero, but libtest captured
|
||
its success output because the host invocation omitted `--nocapture`, so the
|
||
host could not verify the expected phase sequence. This is not accepted as
|
||
scenario evidence; the host invocation is being repaired and rerun.
|
||
The completed host repair then passed the explicit selected-daemon smoke
|
||
(1/1, 3.80s), and the coordinator independently reran it (1/1, 3.60s) with
|
||
no `wga-m83` container/network on follow-up listing. It exercised one exact
|
||
ignored driver test and observed Create, Commit, first delivery activation
|
||
warning, and fixture Apply with real Rustix verification. Final worker default
|
||
gates passed: fmt, all-target Clippy, `cargo test --locked` (247 library tests,
|
||
two ignored), release build, focused driver/harness checks and diff check.
|
||
Fresh independent `/root/m8_4_host_review` found M8.4-R3 (P2: a successful
|
||
`wg setconf` followed by cleanup failure was reported as not submitted) and
|
||
M8.4-R4 (P2: preview or partial-write failure could leave a secret-bearing
|
||
setconf copy). `/root/m8_4_cleanup_repair` separated setconf submission from
|
||
copy-cleanup outcome and added an armed cleanup guard; focused 15 driver tests,
|
||
default tests (250 library tests, two ignored), fmt, all-target Clippy, release
|
||
build and diff check passed. Independent `/root/m8_4_host_review` re-review
|
||
closed R3/R4 with no new finding. The current test-only driver is being rebuilt
|
||
for a fresh Alpine smoke; M8.4 is not yet accepted and M8.5 has not started.
|
||
|
||
2026-10-23 resume: the prior `/root/m8_4_repair` turn hit an agent usage limit
|
||
before changing files; the same GPT-6-Luna/high repairer was resumed for R1/R2.
|
||
The official `rust:1.97.1-alpine3.22` linux/amd64 builder manifest was resolved
|
||
to `sha256:b348cb409ac0a73de15065997a360063cf87465574a15e3e4469862cb8996f02`,
|
||
pulled onto the selected disposable daemon, and inspected as image ID
|
||
`sha256:bc2b74a0f3f942897f678aa466c3cce54048cf1e094893af3596cf43766153c2`.
|
||
A read-only/networkless/capability-dropped container reported rustc/Cargo
|
||
1.97.1 and installed `x86_64-unknown-linux-musl`; no application harness has
|
||
yet been used for a scenario. A subsequent read-only source-mounted builder
|
||
`cargo test --locked --lib --no-run --target x86_64-unknown-linux-musl`
|
||
completed in 4m25s and produced a 114 MiB static PIE test binary under
|
||
`/tmp/wga-m8-build-target/.../wireguard_admin-dcc9c812241bb031`.
|
||
`file`/`readelf` showed no dynamic interpreter. A networkless, read-only,
|
||
capability-dropped run in the pinned Alpine runtime selected only
|
||
`container_driver::alpine_readiness` and passed 1/1. This proves the binary
|
||
loads in Alpine; no real `wg`, application scenario, or Rustix observation ran.
|
||
|
||
After R3/R4 repair, coordinator rebuilt the current musl harness in the pinned
|
||
builder (`cargo test --locked --lib --no-run --target x86_64-unknown-linux-musl`,
|
||
3m22s), then ran the exact ignored host smoke with matching selected daemon ID
|
||
and `WIREGUARD_ADMIN_TEST_DRIVER` pointing at that artifact. It passed 1/1 in
|
||
4.05s and verified the test-only Create/Commit/first delivery/fixture Apply
|
||
phase sequence through the real Application and Rustix observation path.
|
||
`docker ps -a --filter name=wga-m83` and `docker network ls --filter name=wga-m83`
|
||
both returned empty afterward. This is Alpine fixture evidence; no client
|
||
tunnel traffic, restore/delete/import, or actual systemd job ran yet.
|
||
|
||
After the user excluded IPv6 testing, `/root/m8_ipv4_revision` changed the
|
||
probe and M8 test guidance to isolated IPv4 while keeping SPEC.md untouched.
|
||
The revised default suite, fmt, all-target Clippy, release build and diff check
|
||
passed. The elevated selected-daemon probe created its IPv4 network, but its
|
||
first Testcontainers container start failed with a generic redacted category;
|
||
exact-name inspection found no owned resources afterward. A coordinator-only
|
||
disposable `docker run` on a separately named internal IPv4 network succeeded
|
||
with `NET_ADMIN`, and that network was removed. Independent reviewer
|
||
`/root/m8_ipv4_review` raised M8.3-R4 (P2: swallowed Testcontainers error
|
||
prevents diagnosing this start failure) and M8.3-R5 (P2: route read did not
|
||
exercise IPv4 route mutation claimed by the guidance). `/root/m8_ipv4_repair`
|
||
added fixed typed error categories and route add/assert/delete; independent
|
||
re-review closed R4/R5 but the real route commands remain unrun because the
|
||
probe still fails at container creation. It raised M8.3-R6 (P2: the `PullImage`
|
||
category conceals that any Docker create 404 triggers Testcontainers' image-pull
|
||
fallback). `/root/m8_ipv4_repair_r6` owns the category repair and diagnosis.
|
||
The repair changed it to a fixed `container creation not-found image fallback
|
||
failed` category with redaction regression; independent `/root/m8_ipv4_review`
|
||
re-review closed R6. The explicit probe still fails there, before runtime route
|
||
commands. No open scoped review finding remains, but actual M8.3 probe
|
||
acceptance has not passed.
|
||
The selected daemon is Docker 29.1.3, API 1.52; a direct Docker CLI create/start
|
||
using the fixture image, internal network, `NET_ADMIN`, label, entrypoint and
|
||
command succeeded and exact resources were removed. Testcontainers 0.28.0 uses
|
||
Bollard 0.21.1 (default API 1.53); this was investigated, but the source-level
|
||
image-name override below explains the observed create 404 without an API
|
||
version change. No real tunnel or application scenario has run.
|
||
|
||
Coordinator inspection of pinned Testcontainers 0.28.0 identified M8.3-R7
|
||
(P1, startup blocker): the host harness used `ImageExt::with_name` for unique
|
||
container names, but that method overrides the image name. The nonexistent
|
||
image explains the create 404 and pull fallback. `with_container_name` is the
|
||
intended API. `/root/m8_name_repair` owns a narrow repair and live-probe
|
||
regression; `with_container_name` and descriptor/name/owner assertions are in
|
||
place. Independent `/root/m8_ipv4_review` re-review closed R7. The repairer's
|
||
elevated selected-daemon probe passed (1/1); a concurrent
|
||
coordinator probe collided on the fixed subnet, then a separate coordinator
|
||
rerun passed (1/1, 1.46 seconds) with cleanup. M8.3 prerequisite acceptance
|
||
is satisfied for the user-scoped IPv4 test path; no application scenario ran.
|
||
|
||
#### Evidence and handoff
|
||
|
||
Planning inspected current Cargo/module/test layout, Application public/private
|
||
restart and delivery boundaries, runtime reader visibility, M7 acceptance record,
|
||
and current TESTING/ENVIRONMENT/runtime documentation. Existing M7 evidence is
|
||
synthetic workflow/PTY and ordinary library integration; it is not a real tunnel.
|
||
This planning task did not rerun Cargo tests, contact Docker, probe kernel support,
|
||
start containers, install toolchains/packages, add dependencies, or inspect keys.
|
||
|
||
2026-10-22 execution preparation: the active coordinator session `turn_context`
|
||
reported `gpt-6-sol`/`medium`; project role files and explicit dispatch select
|
||
`gpt-6-luna`/`high`. M1–M7 are accepted in this plan. Native rustc/Cargo are
|
||
1.97.1, rustfmt 1.9.0 and Clippy 0.1.97. The host lacks rustup, a musl linker,
|
||
and the musl standard-library directory. The default local Docker daemon is
|
||
reachable with approved access and identifies as Gentoo Linux, ID
|
||
`1baad80e-d79d-49ab-b19a-fb00fd3662d7`; the user explicitly selected it as
|
||
the disposable M8 environment. The scoped container WireGuard/IPv6 capability
|
||
probe described above passed. No host WireGuard probe ran. The pre-existing
|
||
expanded M8 description edit is preserved.
|
||
|
||
2026-10-22 integrated coordinator gates on the final M8.1–M8.3 revision:
|
||
`cargo fmt --all -- --check`, `cargo clippy --locked --all-targets -- -D warnings`,
|
||
`cargo test --locked`, `cargo build --locked --release`, release `--help` and
|
||
`--version`, documentation local-link check, and `git diff --check` all exited
|
||
zero. The default test run passed 235 library tests plus integration/doc tests;
|
||
the Testcontainers target had 8 passing local support tests and one ignored
|
||
privileged probe. The ignored count is not container evidence. The exact named
|
||
probe was then explicitly selected with matching local Unix endpoint and daemon
|
||
ID; it ran one test and exited 101 with `Docker host lacks required IPv6 iptables
|
||
support`. The first sandboxed attempt could not access the socket, so the
|
||
coordinator reran it with approved elevated access; only the latter establishes
|
||
the daemon result. An elevated `docker network ls` and `docker ps -a` afterward
|
||
showed no `wga-m83` network or container. Existing unrelated resources were
|
||
untouched. No real peer traffic, netlink observation, application lifecycle,
|
||
in-container Rust driver, or systemd behavior was verified.
|
||
|
||
2026-10-22 user scope change: skip IPv6 capability and traffic tests. The prior
|
||
dual-stack network failure is historical evidence, no longer an M8 blocker.
|
||
Use the already selected local disposable daemon with a unique isolated IPv4
|
||
bridge and scoped `NET_ADMIN`; run the revised named probe. An elevated
|
||
coordinator run reached container creation but failed after 5.9 seconds with
|
||
`Testcontainers could not start an owned fixture container`; the fresh IPv4
|
||
network and container were absent on follow-up inspection. Investigate this
|
||
failure through scoped implementation/review before claiming the probe passes.
|
||
Do not modify this
|
||
host's firewall/modules/sysctls. Then settle the Alpine-compatible in-crate driver
|
||
build/runtime path (host musl standard library/linker remain absent, so a pinned
|
||
Alpine builder may be needed), execute M8.4–M8.5 sequentially, independently
|
||
review/repair the complete scenarios, and rerun all M8 acceptance gates.
|
||
|
||
#### Decisions and discoveries
|
||
|
||
The production reader is bounded rustix netlink, not wireguard-uapi, and the
|
||
restart adapter is private zbus. M8 must test that actual reader and preserve
|
||
production API boundaries rather than resurrect a discarded library path or
|
||
expose a fake-systemd switch. A test-only service apply plus real comparison is
|
||
useful integration evidence but does not validate the systemd adapter itself.
|
||
Image layers may be cached for speed/space while secret-bearing container state
|
||
must be fresh. The container host shares its kernel with Alpine, so the fixture
|
||
cannot manufacture missing kernel support by installing wireguard-tools.
|
||
|
||
Primary implementation references (check selected versions at dispatch):
|
||
[Testcontainers requirements](https://rust.testcontainers.org/system_requirements/docker/),
|
||
[Testcontainers image options](https://docs.rs/testcontainers/latest/testcontainers/core/trait.ImageExt.html),
|
||
and [WireGuard namespaces](https://www.wireguard.com/netns/).
|
||
|
||
#### Outcome
|
||
|
||
M8.1–M8.3 were implemented and independently reviewed, with all original
|
||
findings closed. The user removed IPv6 testing from M8, and an IPv4-only harness
|
||
revision is in progress. M8.4–M8.5 and real-container acceptance remain pending;
|
||
M8 is not accepted. Milestone 9 must not start until M8 acceptance; actual
|
||
systemd/VM validation remains separate and pending.
|
||
|