aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/maintenance-thresholds.toml4
-rwxr-xr-xscripts/hypr-live-update-guard11
-rw-r--r--tests/hypr-live-update-guard/test_hypr_live_update_guard.py19
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)