From a364c1ee7f2ebfd5d55535d8239fd76aba475a6f Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 11 Jul 2026 06:01:17 -0500 Subject: test(net): add the doctor control-plane repair scenarios and runner net Phase 1's three privileged fixes (unmask-nm, disable-rival, chmod-keyfile) can't be verified against fakes past the point where real sudo and a running NetworkManager matter, and the broken states they repair are too dangerous to stage on a daily driver. I added the live-verification harness they need. Three scenario files encode the break/fix/assert for each: mask NetworkManager, enable a rival dhcpcd, and chmod a profile keyfile to 0644, then run the real net doctor --fix and assert the repair. Each also names the read-only diagnose verdict it expects, so a run that breaks catches whether the fault is in the diagnosis or the fix. run-net-scenarios.sh rsyncs the net and panelkit trees into a target VM over ssh and drives the scenarios there. The target is a booted VM, not a container: NetworkManager needs a real kernel and network stack to actually run, so an nspawn container can only show the filesystem-level half (the mask symlink, the keyfile mode) and not "NM is active". A disposable VM you revert is the right environment. The scenario break/fix/assert logic is the reviewed part. The ssh transport plumbing hasn't been exercised against a live target yet, so it's marked first-draft and may need a shakeout on the first real run. The by-hand equivalent already lives in the manual-testing checklist. --- scripts/testing/net-scenarios/10-nm-masked.sh | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 scripts/testing/net-scenarios/10-nm-masked.sh (limited to 'scripts/testing/net-scenarios/10-nm-masked.sh') diff --git a/scripts/testing/net-scenarios/10-nm-masked.sh b/scripts/testing/net-scenarios/10-nm-masked.sh new file mode 100644 index 0000000..d3b382b --- /dev/null +++ b/scripts/testing/net-scenarios/10-nm-masked.sh @@ -0,0 +1,29 @@ +# shellcheck shell=bash disable=SC2034 # sourced by run-net-scenarios.sh +# Scenario: a masked NetworkManager is unmasked and started. +# +# Masking NetworkManager makes the generic "isn't running" verdict useless — +# systemctl can't start a masked unit — so the doctor must name the mask and +# unmask first. Break by masking; the fix's chain should unmask then start. +SCENARIO_DESC="masked NetworkManager is unmasked and started" +SCENARIO_GROUP="control-plane" + +scenario_break() { + nexec "systemctl mask NetworkManager" +} + +# The verdict the read-only diagnose should produce before any fix runs. +scenario_diagnose_expect() { + ndoctor_json ".outcome" | grep -qx fixable \ + && ndoctor_json '.report.control_plane.nm_state' | grep -qx masked +} + +scenario_fix() { + nfix # net doctor --fix +} + +scenario_assert() { + # Unmasked (the state flip, testable anywhere) AND active (needs a real + # NetworkManager, so a container without netlink can only show the unmask). + ! nexec "systemctl is-enabled NetworkManager | grep -qx masked" \ + && nexec "systemctl is-active NetworkManager >/dev/null" +} -- cgit v1.2.3