Migrate Diagnostics menu; bump to v2.4.0

Deliberately skipped Upgrade/Full Reinstall/Complete Uninstall for now:
all three are large (130-250 lines), genuinely destructive (wipe/
reinstall the kiosk), and Upgrade specifically is coupled to the legacy
script's own self-extraction mechanism (it greps its own running source
for embedded heredocs to pull out main.js/preload.js) - there's no
modular equivalent to migrate it to yet, since those files don't exist
as separate assets outside the monolith. Migrated Diagnostics instead:
4 of the legacy Advanced menu's 12 items (System Status, View Logs,
Audio Diagnostics, Network Test), all read-only except one optional
"play a test sound?" prompt - a deliberate change of pace with no
destructive-action risk to design around, after Sites/WiFi/Power.

- lib/menu.sh: ported get_vpn_ips alongside get_ip_address.
- menus/diagnostics.sh: straight port, using $KIOSK_USER/$KIOSK_HOME
  throughout instead of the legacy code's mix of the variable and a
  hardcoded "kiosk" literal.

Bug fixed, same set -e-safety class as v2.1.0's run_menu fix and
v2.3.0's netplan/systemctl fixes, but a bigger batch this time: nearly
every diagnostic command here was a bare unguarded statement whose
*expected, common* failure - no lightdm running, no audio hardware, no
network, missing log files, ping/nslookup not even installed - would
have crashed the entire session instead of reporting "not found" and
continuing. A diagnostics tool has to be the most crash-proof code in
the project, since it exists to run when something is already broken.
Fixed at every call site: systemctl status | head, tail on lightdm's
log, journalctl, ping, nslookup, and three pactl-backed variable
assignments.

Also noted for future menus in this migration: writing `local var;` and
`var=$(cmd)` as separate statements (good practice, and how several
earlier real bugs were caught) removes an accidental safety net -
`local x=$(cmd)` on one line masks the substitution's exit code with
`local`'s own always-success status. Splitting them is correct, but
each split assignment needs an explicit `|| true` (or real fallback)
where failure is expected and non-fatal, rather than relying on that
masking by accident. Caught three instances of exactly this while
writing this file fresh, not just porting old bugs.

Verified:
- Full regression: re-ran every existing scratch-config/stub test suite
  (sites, display, timezone/pin, lockout, power schedule + RTC, wifi) -
  all still clean after the lib/menu.sh change.
- New test for diagnostics.sh, exercised mostly for real (no
  destructive-mutation risk here, so minimal stubbing needed): system
  status, all three log views (including the "no such file" paths for
  lightdm log and electron log), full 8-step audio diagnostic with test
  sound declined, and network test - all report gracefully instead of
  crashing, confirmed by re-running after each fix until every bare
  unguarded statement was accounted for.
- End-to-end: ran the real install.sh as a genuine non-root, non-
  "kiosk" user, navigating Diagnostics -> System status -> View Logs ->
  System journal -> Audio diagnostics (declined test sound) -> Network
  test -> exit. Confirmed every diagnostic path completes and returns
  to its menu cleanly (exit code 0) even with ping/nslookup missing and
  no audio hardware/network present in this environment.
This commit is contained in:
Claude
2026-08-18 18:48:26 +00:00
parent 2375bf5eab
commit 459da53182
5 changed files with 324 additions and 8 deletions
+27
View File
@@ -57,6 +57,33 @@ get_ip_address() {
fi
}
# "WireGuard: 10.x.x.x | Tailscale: 100.x.x.x" for whichever VPN clients
# are installed and connected, or "None" if none are.
get_vpn_ips() {
local vpn_info=""
if command -v wg &>/dev/null && sudo wg show 2>/dev/null | grep -q interface; then
local wg_ip
wg_ip=$(sudo wg show all | grep "allowed ips" | head -1 | awk '{print $3}' | cut -d'/' -f1)
[[ -n "$wg_ip" ]] && vpn_info="${vpn_info}WireGuard: $wg_ip | "
fi
if command -v tailscale &>/dev/null; then
local ts_ip
ts_ip=$(tailscale ip -4 2>/dev/null)
[[ -n "$ts_ip" ]] && vpn_info="${vpn_info}Tailscale: $ts_ip | "
fi
if command -v netbird &>/dev/null; then
local nb_ip
nb_ip=$(netbird status 2>/dev/null | grep "NetBird IP:" | awk '{print $3}')
[[ -n "$nb_ip" ]] && vpn_info="${vpn_info}Netbird: $nb_ip | "
fi
vpn_info="${vpn_info% | }"
[[ -n "$vpn_info" ]] && echo "$vpn_info" || echo "None"
}
pause() {
read -r -p "Press Enter to continue..."
}