<feed xmlns='http://www.w3.org/2005/Atom'>
<title>archsetup/scripts/testing, branch main</title>
<subtitle>Builds a full dev workstation from a bare Arch Linux install.
</subtitle>
<id>https://git.cjennings.net/archsetup/atom?h=main</id>
<link rel='self' href='https://git.cjennings.net/archsetup/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/'/>
<updated>2026-07-25T20:00:44+00:00</updated>
<entry>
<title>refactor(test): share runner and scenario contracts</title>
<updated>2026-07-25T20:00:44+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-25T20:00:44+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=d52da959bc416e09bc0f3e54994563bd80e19c64'/>
<id>urn:sha1:d52da959bc416e09bc0f3e54994563bd80e19c64</id>
<content type='text'>
</content>
</entry>
<entry>
<title>test: fix the weak assertions from the S6/S7 audit</title>
<updated>2026-07-21T04:44:35+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-21T04:44:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=179fbd55795c27ed388860e3c6b3d8c0651422ac'/>
<id>urn:sha1:179fbd55795c27ed388860e3c6b3d8c0651422ac</id>
<content type='text'>
The Hyprland socket check passed a shell glob to `test -S`, which breaks at both edges: zero matches leaves the literal pattern and several instances pass multiple args, failing for reasons unrelated to the socket. It now resolves one socket with find -type s.

The gen_tokens degenerate-marker test asserted properties loose enough to pass on garbled output. It now pins the exact reconstruction as a characterization, with the impossible-input caveat stated, so any change to the branch surfaces.

The gallery tick count leaned on split-string omit-nulls arithmetic that happened to equal the match count. It now counts occurrences directly. gallery-widget-write-svg, the last uncovered public entry point, gets a Normal-case test.
</content>
</entry>
<entry>
<title>fix(test): harden four VM-framework paths from the S5 audit</title>
<updated>2026-07-21T04:40:56+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-21T04:40:56+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=866d327f0bad3a0730801a22654bac45e02ee14b'/>
<id>urn:sha1:866d327f0bad3a0730801a22654bac45e02ee14b</id>
<content type='text'>
init_vm_paths suffixed the disk and NVRAM by FS_PROFILE but left PID_FILE, MONITOR_SOCK, and SERIAL_LOG shared. A concurrent btrfs and zfs run read each other's PID file, so the second run's stop logic could kill the first run's VM. All runtime paths now carry the suffix.

kill_qemu sent kill -9 and returned without waiting, so the force-kill fallback could run qemu-img snapshot against a qcow2 the dying qemu still held locked (the restore failed silently behind || true, leaving the base image dirty). It now reaps or polls the process to death before returning.

debug-vm.sh hardcoded the btrfs base-disk name, so FS_PROFILE=zfs booted the wrong base or fatalled. It now takes DISK_PATH from init_vm_paths.

Both runners reported a completion-marker grep as "ArchSetup Exit Code," but the installer runs detached with set -e off, so its real exit status was never captured -- a run that errored mid-way and still reached its last line reported exit 0. The flag is now ARCHSETUP_COMPLETED with the report labeled honestly; Testinfra stays the pass/fail authority.
</content>
</entry>
<entry>
<title>fix(test): count a diagnose miss as a failed net scenario</title>
<updated>2026-07-21T04:33:02+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-21T04:33:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=cf211cd8dd8dd0ff18673c88a3eef2c63549d6d5'/>
<id>urn:sha1:cf211cd8dd8dd0ff18673c88a3eef2c63549d6d5</id>
<content type='text'>
The scenario_diagnose_expect else-branch printed its FAIL line but never forced a non-zero subshell exit. A scenario whose only failure was the diagnose check counted as passed, so the run printed "all scenarios passed" and exited 0 over a real net-doctor diagnosis regression.

The miss now sets a per-scenario rc that carries to the subshell exit. The fix and assert still run first, since the repair result is worth having either way.

The new harness drives the real script with stubbed ssh/rsync/jq and a controllable fake scenario, pinning all four check outcomes.
</content>
</entry>
<entry>
<title>fix: order pacman safety hooks</title>
<updated>2026-07-19T00:46:05+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-19T00:46:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=80017365527b612ca8763b29c5771fc41d58def5'/>
<id>urn:sha1:80017365527b612ca8763b29c5771fc41d58def5</id>
<content type='text'>
Install snapshot and live-update hooks before mkinitcpio removal, migrate legacy paths, and cover the ordering invariant.
</content>
</entry>
<entry>
<title>test(net): add the doctor control-plane repair scenarios and runner</title>
<updated>2026-07-11T11:01:17+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-11T11:01:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=4c1b9811927aee572624aa03527dab9ec5f3a12a'/>
<id>urn:sha1:4c1b9811927aee572624aa03527dab9ec5f3a12a</id>
<content type='text'>
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.
</content>
</entry>
<entry>
<title>test(maint): add VM and nspawn remedy scenario harness</title>
<updated>2026-07-08T10:45:51+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-08T10:45:51+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=25b33d2a990a8c0c0f5d724fe4b9ea726dee9cf0'/>
<id>urn:sha1:25b33d2a990a8c0c0f5d724fe4b9ea726dee9cf0</id>
<content type='text'>
Nine break/fix/assert scenarios run the real maint fix inside the test VM. The runner batches non-conflicting scenarios into one VM boot, restores the snapshot only between groups, and leaves the base image pristine afterwards. A systemd-nspawn fast lane runs the pacman-level group against a cached pacstrap rootfs in seconds. The plan layer validates the scenario contract without a VM and carries a 19-test unit suite. make test-maint wires the VM lane in.

The zfs lane is filtered but unexercised: the FS_PROFILE=zfs base image fails to build (ZFS DKMS module not found on linux-lts 6.18). The failure is tracked in the todo.
</content>
</entry>
<entry>
<title>test(vm): collect network evidence before failing in pre-flight diagnostics</title>
<updated>2026-07-04T21:23:57+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-04T21:23:12+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=bf44f9f5a351af5b2e9adaef66e3a4d7802dc5b7'/>
<id>urn:sha1:bf44f9f5a351af5b2e9adaef66e3a4d7802dc5b7</id>
<content type='text'>
run_network_diagnostics tested HTTP before DNS and returned on the first failure, so a DNS failure surfaced as a generic "no internet" and the IP/route/resolver evidence was never reached. It now collects read-only facts first (ip -brief addr, default route, resolv.conf) and prints them regardless of outcome, runs every check, and reports all failures together in a summary. Generic checks (DNS, egress, TLS) are split from Arch-specific ones (mirror, AUR) so a DNS failure is named as DNS, not a mirror problem. Raw fact output is saved to the results dir when one is set.
</content>
</entry>
<entry>
<title>feat(vpn): proton CLI replaces the GTK app, tailscale operator at install</title>
<updated>2026-07-02T23:16:52+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-02T23:16:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=94aeb80d9b0f539c0a5917264b7921eafab5ee22'/>
<id>urn:sha1:94aeb80d9b0f539c0a5917264b7921eafab5ee22</id>
<content type='text'>
The net panel's Tunnels view drives proton-vpn-cli, and the CLI and GTK app can't run concurrently, so the installer swaps them. tailscaled now enables with --now and the install grants operator to the primary user (brief retry — the daemon takes a moment to accept its socket), so tailscale up/down works without sudo from the panel. VM asserts the vpn stack, the retirement, and the OperatorUser pref (format verified against a live daemon).
</content>
</entry>
<entry>
<title>feat(packages): retire zoom, meetings open in the browser</title>
<updated>2026-07-02T21:50:49+00:00</updated>
<author>
<name>Craig Jennings</name>
<email>c@cjennings.net</email>
</author>
<published>2026-07-02T21:50:49+00:00</published>
<link rel='alternate' type='text/html' href='https://git.cjennings.net/archsetup/commit/?id=dffcd168749e033fc15c8cccb4447efbac11b9a7'/>
<id>urn:sha1:dffcd168749e033fc15c8cccb4447efbac11b9a7</id>
<content type='text'>
The dotfiles zoom-web handler rewrites zoommtg:// links to the web client, so the AUR zoom package leaves the install. The retired-package VM assertion now covers blueman and zoom.
</content>
</entry>
</feed>
