Files
Panama/tests/quickshell/wifi-qr-contract.sh
T
Gabriel Brown 2a716dac9e Fix correctness bugs across the helper scripts
panama-osd read the wrong brightnessctl field, showing the hardware
max instead of a percentage on any backlight device. panama-doctor
called three sibling scripts by bare name with nothing on PATH,
making three health checks permanently and falsely report broken; its
repair actions also reused the short probe timeout, so a slow-but-
successful restart was reported as failed. panama-wifi-qr left the
cleartext passphrase temp file behind on its failure path (the RETURN
trap doesn't fire on exit), and its nmcli parsing broke on connection
names containing a colon or backslash -- verified against a real
NetworkManager profile.

panama-power-profile's set command always returned success regardless
of whether the write actually took. panama-keyring's daemon-origin
check picked whichever gnome-keyring-daemon process happened to
enumerate first in /proc, defeating the exact dual-daemon scenario it
exists to detect; it now resolves the PID that actually owns the
Secret Service D-Bus name. gnf aborted before running a firmware
update whenever the metadata was already current (a non-error exit
under set -e), and its flatpak update lacked the -y its own docs
promise.

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
2026-08-18 21:23:28 -04:00

150 lines
6.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# panama-wifi-qr renders a saved network as a QR code a phone can scan.
#
# The QR contains the network PASSWORD in machine-readable form, so most of what
# is worth testing here is about handling that safely rather than about QR
# codes. Both nmcli and qrencode are stubbed: the real ones would read this
# machine's actual passphrases, and a test that writes the daily driver's Wi-Fi
# password into a fixture directory is not one worth having.
set -uo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
helper="$repo_dir/config/dot/quickshell/scripts/panama-wifi-qr"
fail() {
printf 'wifi qr contract: %s\n' "$1" >&2
exit 1
}
work="$(mktemp -d /tmp/panama-wifiqr.XXXXXX)"
trap 'rm -rf "$work"' EXIT
mkdir -p "$work/bin" "$work/run"
readonly SECRET='hunter2-secret'
cat >"$work/bin/nmcli" <<STUB
#!/usr/bin/env bash
# -e no -t -f NAME connection show: one name per line, no field to split, so
# a name containing ':' or '\\' (real nmcli would otherwise backslash-escape
# both) comes back byte-for-byte.
if [[ "\$*" == *"-f NAME connection show"* ]]; then
printf 'home net\n'
printf 'work-eap\n'
printf 'Cafe: Guest\n'
printf 'Wired connection 1\n'
exit 0
fi
name="\${@: -1}"
case "\$*" in
*connection.type*)
case "\$name" in
"home net"|"work-eap"|"Cafe: Guest") printf '802-11-wireless\n' ;;
"Wired connection 1") printf '802-3-ethernet\n' ;;
esac ;;
*802-11-wireless.ssid*)
# An SSID containing reserved characters, to prove they are escaped.
case "\$name" in
"home net") printf 'home;net\n' ;;
"work-eap") printf 'work-eap\n' ;;
"Cafe: Guest") printf 'Cafe: Guest\n' ;;
esac ;;
*802-11-wireless.hidden*) printf 'no\n' ;;
*802-11-wireless-security.psk*)
# work-eap is enterprise: no passphrase exists to share.
[[ "\$name" == "home net" ]] && printf '%s\n' "$SECRET" ;;
esac
exit 0
STUB
chmod +x "$work/bin/nmcli"
# Records its argv and its stdin separately, so the test can prove the secret
# arrived on stdin and never on the command line -- argv is world-readable
# through /proc while a process runs.
cat >"$work/bin/qrencode" <<'STUB'
#!/usr/bin/env bash
printf '%s\n' "$*" >>"$QRENCODE_ARGV_LOG"
out=""
prev=""
for arg in "$@"; do
[[ "$prev" == "-o" ]] && out="$arg"
prev="$arg"
done
cat >"$QRENCODE_STDIN_LOG"
printf 'fake-png' >"$out"
exit 0
STUB
chmod +x "$work/bin/qrencode"
export QRENCODE_ARGV_LOG="$work/argv.log"
export QRENCODE_STDIN_LOG="$work/stdin.log"
: >"$QRENCODE_ARGV_LOG"
: >"$QRENCODE_STDIN_LOG"
run() { PATH="$work/bin:$PATH" XDG_RUNTIME_DIR="$work/run" "$helper" "$@"; }
# ── Listing distinguishes shareable from not ────────────────────────────────
out="$(run list)"
jq -e . >/dev/null 2>&1 <<<"$out" || fail "list did not emit JSON: $out"
[[ "$(jq -r '.networks | length' <<<"$out")" == "3" ]] \
|| fail "only wireless connections belong in the list: $out"
jq -e '.networks[] | select(.name == "home net") | .shareable == true' >/dev/null <<<"$out" \
|| fail "a network with a passphrase must be shareable: $out"
jq -e '.networks[] | select(.name == "work-eap") | .shareable == false' >/dev/null <<<"$out" \
|| fail "an enterprise network has no passphrase, so a QR code for it cannot work: $out"
# A name containing a colon must survive intact: nmcli's terse mode would
# backslash-escape it (real nmcli escapes ':' and '\' in terse/-g output), and
# a naive colon-split parser truncates the name and misaligns the next field,
# dropping the network from the list entirely.
jq -e '.networks[] | select(.name == "Cafe: Guest")' >/dev/null <<<"$out" \
|| fail "a network name containing a colon was mangled or dropped: $out"
# ── The payload ─────────────────────────────────────────────────────────────
path="$(run qr 'home net' | jq -r .path)"
[[ -n "$path" && -e "$path" ]] || fail 'no image was produced'
payload="$(cat "$QRENCODE_STDIN_LOG")"
grep -q "P:$SECRET;" <<<"$payload" \
|| fail 'the passphrase did not reach the payload intact'
# The SSID is "home;net": unescaped, the semicolon ends the S: field early and
# the code describes a different network.
grep -qF 'S:home\;net;' <<<"$payload" \
|| fail "a reserved character in the SSID was not escaped: $payload"
[[ "$(wc -l <"$QRENCODE_STDIN_LOG")" == "0" ]] \
|| fail "the payload contains a newline; nmcli's trailing newline must be stripped: $(cat -A "$QRENCODE_STDIN_LOG")"
grep -q ';;$' <<<"$payload" || fail "the WIFI: URI must be terminated with ;;: $payload"
# ── The secret must never appear in argv ────────────────────────────────────
grep -q "$SECRET" "$QRENCODE_ARGV_LOG" \
&& fail 'the passphrase was passed as a command-line argument, where /proc exposes it to every process on the machine'
# ── The image and its directory must not be readable by others ──────────────
[[ "$(stat -c '%a' "$path")" == "600" ]] \
|| fail "the QR image is mode $(stat -c '%a' "$path"); it contains a password"
[[ "$(stat -c '%a' "$(dirname "$path")")" == "700" ]] \
|| fail "the directory holding QR images is mode $(stat -c '%a' "$(dirname "$path")")"
# ── No temporary payload files may survive ──────────────────────────────────
leftovers="$(find "$work/run" -name 'payload.*' | wc -l)"
[[ "$leftovers" == "0" ]] \
|| fail "$leftovers temporary payload file(s) containing the passphrase were left behind"
# ── An unknown network is an error, not an empty image ──────────────────────
out="$(run qr 'no-such-network')"
jq -e '.path == "" and .error != ""' >/dev/null <<<"$out" \
|| fail "an unknown network must be reported: $out"
# ── A name with a colon round-trips from list into qr ───────────────────────
# The name `list` emits must be exactly what `qr` needs to look the network
# back up; escaping it either direction breaks this lookup.
out="$(run qr 'Cafe: Guest')"
[[ "$(jq -r '.path' <<<"$out")" != "" ]] \
|| fail "a saved network name containing a colon could not be looked back up: $out"
printf 'wifi qr contract: PASS\n'