diff options
| -rw-r--r-- | configs/maintenance-thresholds.toml | 4 | ||||
| -rwxr-xr-x | scripts/hypr-live-update-guard | 11 | ||||
| -rw-r--r-- | tests/hypr-live-update-guard/test_hypr_live_update_guard.py | 19 |
3 files changed, 31 insertions, 3 deletions
diff --git a/configs/maintenance-thresholds.toml b/configs/maintenance-thresholds.toml index b522f88..c14eaec 100644 --- a/configs/maintenance-thresholds.toml +++ b/configs/maintenance-thresholds.toml @@ -180,7 +180,9 @@ entries = [ "/etc/cups/subscriptions.conf", "/var/lib/passim*", # StateDirectory re-chowns "/var/log/journal", # tmpfiles re-groups - "/etc/ssl/private", # hardened below packaged mode + # /etc/ssl/private deliberately NOT here: both hosts had it world-listable + # (755 vs packaged 700) — a real misconfig the metric caught. pacman warns + # but never resets existing dir perms; fixed by chmod 2026-07-08. "/usr/lib/utempter/utempter", # setgid-helper ownership; # NOTE: also silences a # content change on this diff --git a/scripts/hypr-live-update-guard b/scripts/hypr-live-update-guard index 614414b..e78200d 100755 --- a/scripts/hypr-live-update-guard +++ b/scripts/hypr-live-update-guard @@ -42,8 +42,15 @@ set -u sentinel="${HYPR_GUARD_SENTINEL:-/run/archsetup-allow-live-gpu-update}" -# Explicit override: the user knows what they're doing. -if [ "${HYPR_ALLOW_LIVE_UPDATE:-0}" = "1" ] || [ -e "$sentinel" ]; then +# Explicit override: the user knows what they're doing. The sentinel is +# consumed as it's honored — one touch buys exactly one transaction, so a +# leftover from a crashed caller can't keep the guard disarmed until +# reboot. +if [ "${HYPR_ALLOW_LIVE_UPDATE:-0}" = "1" ]; then + exit 0 +fi +if [ -e "$sentinel" ]; then + rm -f "$sentinel" 2>/dev/null || true exit 0 fi diff --git a/tests/hypr-live-update-guard/test_hypr_live_update_guard.py b/tests/hypr-live-update-guard/test_hypr_live_update_guard.py index 578edc7..a6c6f68 100644 --- a/tests/hypr-live-update-guard/test_hypr_live_update_guard.py +++ b/tests/hypr-live-update-guard/test_hypr_live_update_guard.py @@ -137,6 +137,25 @@ class HyprLiveUpdateGuard(unittest.TestCase): r = run_guard(stdin="mesa\n", running="1", sentinel=f.name) self.assertEqual(r.returncode, 0, r.stderr) + def test_sentinel_is_consumed_on_use(self): + # one touch = one transaction: if the override's cleanup never runs + # (a crashed caller), a leftover sentinel must not keep the guard + # disarmed until reboot — the hook deletes it as it honors it + fd, path = tempfile.mkstemp(prefix="guard-allow-") + os.close(fd) + try: + r = run_guard(stdin="mesa\n", running="1", sentinel=path) + self.assertEqual(r.returncode, 0, r.stderr) + self.assertFalse(os.path.exists(path)) + finally: + if os.path.exists(path): + os.unlink(path) + + def test_env_override_consumes_nothing(self): + # the env override isn't a file; nothing to consume, still proceeds + r = run_guard(stdin="mesa\n", running="1", allow="1") + self.assertEqual(r.returncode, 0, r.stderr) + def test_override_env_zero_does_not_bypass(self): r = run_guard(stdin="mesa\n", running="1", allow="0") self.assertEqual(r.returncode, 1, r.stderr) |
