security-hardening: recognise the guard-lib shutdown guard

Test 10 only knew the retired shutdown-schedule-guard.path, so it
reported a skip while guard-file@shutdown-schedule.path was actively
protecting /etc/shutdown-schedule.conf. That understated the real
protection in the same way tests 2, 3 and 5 did before the last
commit.

It now accepts the guard-lib unit and passes. The
disabled-is-intentional branch stays for hosts running neither unit.

Host: 19 passed / 0 failed / 5 skipped. Container: exit 0.
This commit is contained in:
Krzysztof Rudnicki 2026-07-19 20:09:24 +02:00
parent 2d4331c703
commit 5faed23977
2 changed files with 35 additions and 2 deletions

View File

@ -0,0 +1,29 @@
{
"intent": "Report the shutdown schedule as guarded rather than skipped, now that guard-file@shutdown-schedule.path is confirmed active.",
"scope": [
"linux_configuration/tests/test_security_hardening.sh: Test 10 only",
"Non-goal: system state — the legacy units were disabled by the user, not by this change"
],
"changes": [
"Test 10 now accepts guard-file@shutdown-schedule.path, the guard-lib replacement that actually protects /etc/shutdown-schedule.conf today. Previously it only knew the retired shutdown-schedule-guard.path and reported a skip, which understated the real protection. The disabled-is-intentional branch is kept for hosts that have neither unit."
],
"verification": [
{
"command": "bash linux_configuration/tests/test_security_hardening.sh (real host)",
"result": "pass",
"evidence": "19 passed / 0 failed / 5 skipped, up from 18/0/6: 'shutdown schedule is guarded' now PASSes instead of skipping. /etc/shutdown-schedule.conf carries the immutable flag and guard-file@shutdown-schedule.path is active."
},
{
"command": "docker run --network=none archlinux:base-devel <the suite>",
"result": "pass",
"evidence": "exit 0 — off-host behaviour unchanged."
}
],
"risks": [
"Same pattern as the other guard checks: if the unit is renamed again, this reports a false skip rather than a failure. The disabled-is-intentional branch is what makes that possible, and it is the deliberate trade for not failing on a host that legitimately retired the guard."
],
"rollback": [
"git revert this commit; Test 10 returns to skipping on this host.",
"Validate after rollback: the suite reports 18 passed / 6 skipped with 'shutdown-schedule-guard.path is active' skipped."
]
}

View File

@ -201,8 +201,12 @@ fi
# and never compare equal. Capture stdout and discard the exit status instead.
shutdown_guard_enabled=$(systemctl is-enabled shutdown-schedule-guard.path 2>/dev/null || true)
[[ -n "$shutdown_guard_enabled" ]] || shutdown_guard_enabled=unknown
if systemctl is-active --quiet shutdown-schedule-guard.path 2>/dev/null; then
test_result "shutdown-schedule-guard.path is active" "pass"
if systemctl is-active --quiet guard-file@shutdown-schedule.path 2>/dev/null ||
systemctl is-active --quiet shutdown-schedule-guard.path 2>/dev/null; then
# guard-file@shutdown-schedule.path is the guard-lib replacement and is the
# unit actually protecting the schedule today, so this is a pass, not a
# concession that the schedule went unguarded.
test_result "shutdown schedule is guarded" "pass"
elif [[ "$shutdown_guard_enabled" == "disabled" ]]; then
test_result "shutdown-schedule-guard.path is active" "skip" \
"intentionally retired with the old poweroff flow (night lockdown replaced it)"