Close desktop safety gaps

This commit is contained in:
Gabriel Brown
2026-08-20 22:00:26 -04:00
parent c4733e0624
commit c4642919f7
13 changed files with 194 additions and 35 deletions
@@ -223,16 +223,18 @@ failed_state="$(wait_for '.busy == false and .awaiting == false')"
jq -e '.lastError | contains("rejected")' <<<"$failed_state" >/dev/null \
|| fail "failed apply did not retain a useful recovery message: $failed_state"
# If an output disconnects while a change is pending, rollback sends one
# transaction containing every output that is still connected.
# If an output disconnects while a change is pending, the screen-model observer
# refreshes topology and rolls back with only the still-connected output. This
# intentionally does not call Displays.refresh() through the public harness API.
[[ "$(run ipc --pid "$harness_pid" call displays-test applyLayoutFixture 3000 320)" == "true" ]] \
|| fail 'disconnect fixture could not start'
wait_for '.canConfirm == true' >/dev/null
jq '.[0:1]' "$monitor_state" >"$fixture/connected.json"
mv "$fixture/connected.json" "$monitor_state"
run ipc --pid "$harness_pid" call displays-test refresh >/dev/null
wait_for '.layout | length == 1' >/dev/null
run ipc --pid "$harness_pid" call displays-test revertChange >/dev/null
run ipc --pid "$harness_pid" call displays-test setScreenModel '["DP-2"]' >/dev/null
wait_for '(.layout | length == 1) and .awaiting == false and .busy == false' >/dev/null
[[ "$(transaction_status | jq -c .primaryFirst)" == '["DP-2"]' ]] \
|| fail "primary-first monitor list did not reconcile after hot-unplug: $(transaction_status)"
wait_for '.busy == false and .awaiting == false' >/dev/null
disconnect_payload="$(tail -1 "$eval_log")"
[[ "$(rg -o 'hl\.monitor' <<<"$disconnect_payload" | wc -l)" == "1" ]] \
+33 -8
View File
@@ -14,6 +14,9 @@ settings="$config_home/panama/settings.json"
generated="$state_home/panama/hyprlock.conf"
hyprlock_log="$fixture/hyprlock.log"
theme_helper="$repo_dir/config/dot/quickshell/scripts/panama-theme-apps"
shipped_wallpaper="$fixture_home/Pictures/Wallpapers/faroe_islands.jpg"
global_wallpaper="$fixture_home/Pictures/Wallpapers/global.jpg"
portrait_wallpaper="$fixture_home/Pictures/Wallpapers/portrait.jpg"
fail() {
printf 'lock screen helper contract: %s\n' "$1" >&2
@@ -28,6 +31,9 @@ trap cleanup EXIT
mkdir -p "$fixture_home/Pictures/Wallpapers" "$config_home/panama" \
"$config_home/hypr" "$state_home" "$test_bin"
printf 'shipped wallpaper\n' >"$shipped_wallpaper"
printf 'global wallpaper\n' >"$global_wallpaper"
printf 'portrait wallpaper\n' >"$portrait_wallpaper"
cp "$repo_dir/config/dot/hypr/hyprlock.conf.template" \
"$config_home/hypr/hyprlock.conf.template"
HOME="$fixture_home" XDG_CONFIG_HOME="$config_home" \
@@ -131,19 +137,38 @@ write_settings '{"accentName":"not-a-real-accent","colorScheme":"dark"}'
run_helper generate
rg -Fq 'outer_color = rgba(130, 170, 255, 0.9)' "$generated" || fail 'an unknown accent name did not fall back to blue'
write_settings '{
"lockBackgroundMode":"wallpaper",
"wallpaperMode":"per-monitor",
"wallpaperPath":"/images/global.jpg",
"wallpaperPerMonitor":{"DP-2":"/images/portrait.jpg"}
}'
write_settings "$(jq -n \
--arg global "$global_wallpaper" \
--arg portrait "$portrait_wallpaper" \
'{lockBackgroundMode:"wallpaper",wallpaperMode:"per-monitor",wallpaperPath:$global,wallpaperPerMonitor:{"DP-2":$portrait}}')"
run_helper generate
[[ "$(rg -c '^background \{' "$generated")" -eq 2 ]] || fail 'wallpaper mode did not create one block per output'
awk '/^background \{/{block++} block==1 && /monitor = DP-2/{monitor=1} block==1 && /path = \/images\/portrait.jpg/{path=1} END{exit !(monitor && path)}' "$generated" \
awk -v path="$portrait_wallpaper" '/^background \{/{block++} block==1 && /monitor = DP-2/{monitor=1} block==1 && index($0, "path = " path){path_seen=1} END{exit !(monitor && path_seen)}' "$generated" \
|| fail 'per-monitor wallpaper was not used for DP-2'
awk '/^background \{/{block++} block==2 && /monitor = HDMI-A-1/{monitor=1} block==2 && /path = \/images\/global.jpg/{path=1} END{exit !(monitor && path)}' "$generated" \
awk -v path="$global_wallpaper" '/^background \{/{block++} block==2 && /monitor = HDMI-A-1/{monitor=1} block==2 && index($0, "path = " path){path_seen=1} END{exit !(monitor && path_seen)}' "$generated" \
|| fail 'missing monitor assignment did not fall back to the global wallpaper'
# A selected but unreadable image never reaches hyprlock. One bounded warning
# covers both missing global and per-monitor choices while the shipped image is
# still readable.
write_settings "$(jq -n \
--arg missing "$fixture/missing.jpg" \
'{lockBackgroundMode:"wallpaper",wallpaperMode:"per-monitor",wallpaperPath:$missing,wallpaperPerMonitor:{"DP-2":$missing}}')"
run_helper generate
[[ "$(rg -c "path = $shipped_wallpaper" "$generated")" -eq 2 ]] \
|| fail 'missing selected wallpapers did not fall back to the readable shipped image'
jq -e '.generated == true and .fallback == false
and .error == "One or more lock-screen wallpapers were unavailable; a safe fallback is in use."' \
<<<"$(run_helper status)" >/dev/null \
|| fail 'missing wallpaper fallback did not report one bounded warning'
# If no image is readable, screenshot is the only background source that
# hyprlock can still render safely.
rm -f "$shipped_wallpaper"
run_helper generate
[[ "$(rg -c 'path = screenshot' "$generated")" -eq 2 ]] \
|| fail 'missing wallpapers without the shipped image did not fall back to screenshots'
write_settings '{"lockBackgroundMode":"screenshot","lockShowClock":true,"lockShowDate":false,"lockShowUser":false,"use24Hour":true}'
run_helper generate
rg -Fq 'text = cmd[update:1000] date +"%H:%M"' "$generated" || fail '24-hour clock setting was ignored'
+27 -2
View File
@@ -15,6 +15,8 @@ active_state="$fixture/active.json"
control="$fixture/control"
shell_log="$fixture/quickshell.log"
harness_pid=""
quoted_home="$fixture/home's"
quoted_wallpaper="$quoted_home/Pictures/Wallpapers/quoted.jpg"
fail() {
printf 'wallpaper service contract: %s\n' "$1" >&2
@@ -46,9 +48,18 @@ cleanup() {
}
trap cleanup EXIT
mkdir -p "$config_home/panama" "$state_home" "$test_bin"
mkdir -p "$config_home/panama" "$state_home" "$test_bin" \
"$quoted_home/Pictures/Wallpapers"
cp -a "$repo_dir/config/dot/quickshell" "$config_path"
printf '%s\n' '{}' >"$config_home/panama/settings.json"
printf 'quoted wallpaper\n' >"$quoted_wallpaper"
cat >"$config_home/panama/settings.json" <<'JSON'
{
"displays": {
"DP-2": {"mode":"[email protected]","scale":1.5,"transform":0,"x":0,"y":0,"primary":true},
"HDMI-A-1": {"mode":"[email protected]","scale":1,"transform":0,"x":3000,"y":0,"primary":false}
}
}
JSON
printf '%s\n' '{}' >"$active_state"
: >"$command_log"
: >"$control"
@@ -92,6 +103,7 @@ qs_for_harness() {
XDG_CONFIG_HOME="$config_home"
XDG_STATE_HOME="$state_home"
PATH="$test_bin:$PATH"
HOME="$quoted_home"
PANAMA_WALLPAPER_COMMAND_LOG="$command_log"
PANAMA_WALLPAPER_ACTIVE_STATE="$active_state"
PANAMA_WALLPAPER_CONTROL="$control"
@@ -113,6 +125,18 @@ wait_idle() {
fail "wallpaper transaction did not settle: $status"
}
wait_for_scan() {
local status=""
for _ in $(seq 1 80); do
status="$(qs_for_harness ipc call wallpaper-service-test status)"
jq -e --arg path "$quoted_wallpaper" \
'.scanning == false and (.available | index($path) != null)' \
<<<"$status" >/dev/null && return
sleep 0.1
done
fail "argument-safe wallpaper scan did not discover the quoted HOME image: $status"
}
qs_for_harness --daemonize >"$shell_log" 2>&1 || fail 'isolated service harness did not launch'
for _ in $(seq 1 60); do
harness_pid="$(instances_for_harness | head -1)"
@@ -123,6 +147,7 @@ for _ in $(seq 1 60); do
sleep 0.1
done
[[ "$harness_pid" =~ ^[0-9]+$ ]] || fail 'isolated service harness process did not start'
wait_for_scan
wait_idle >/dev/null
: >"$command_log"
@@ -68,6 +68,15 @@ done
[[ "$(qs_for_harness ipc call wallpaper-settings-test activate per-monitor /images/c.jpg)" \
== '["assign:DP-2:/images/c.jpg"]' ]] || fail 'Per-display mode did not assign the selected output'
qs_for_harness ipc call wallpaper-settings-test selectOutput HDMI-A-1 >/dev/null
qs_for_harness ipc call wallpaper-settings-test updateOutputs 'DP-2|HDMI-A-1' >/dev/null
[[ "$(qs_for_harness ipc call wallpaper-settings-test selectedOutput)" == 'HDMI-A-1' ]] \
|| fail 'a valid per-monitor selection was reset during topology reconciliation'
qs_for_harness ipc call wallpaper-settings-test updateOutputs 'DP-2' >/dev/null
selected_after_disconnect="$(qs_for_harness ipc call wallpaper-settings-test selectedOutput)"
[[ "$selected_after_disconnect" == 'DP-2' ]] \
|| fail "a disconnected per-monitor selection did not fall back to the primary output: $selected_after_disconnect"
states="$(qs_for_harness ipc call wallpaper-settings-test states)"
jq -e '.selectedOutput == "DP-2"
and .single == {"current":true,"selected":true}