Harden bounded Panama recovery actions
This commit is contained in:
@@ -7,10 +7,22 @@
|
||||
set -euo pipefail
|
||||
|
||||
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
harness="$repo_dir/config/dot/quickshell/health-harness.qml"
|
||||
source_harness="$repo_dir/config/dot/quickshell/health-harness.qml"
|
||||
service="$repo_dir/config/dot/quickshell/services/Health.qml"
|
||||
shell="$repo_dir/config/dot/quickshell/shell.qml"
|
||||
warning_snapshot='{"schemaVersion":1,"generatedAt":"2026-08-18T00:00:00Z","summary":{"status":"warning","healthy":0,"warnings":2,"errors":0,"unconfigured":0},"context":{"session":"hyprland","versions":[{"id":"quickshell","version":"0.3.0"}]},"checks":[{"id":"integration.calendar","group":"integrations","title":"Calendar","status":"warning","detail":"Calendar probe timed out.","action":{"kind":"open","label":"Open Date & Time","confirm":false,"target":"datetime"}},{"id":"panama.caffeine","group":"panama-tools","title":"Caffeine","status":"warning","detail":"Duplicate inhibitors are active.","action":{"kind":"repair","label":"Release duplicate inhibitors","confirm":false}}]}'
|
||||
confirm_snapshot="$(jq -c '
|
||||
.summary.status = "error"
|
||||
| .summary.errors = 1
|
||||
| .checks += [{
|
||||
id: "desktop.quickshell",
|
||||
group: "desktop-foundation",
|
||||
title: "Quickshell",
|
||||
status: "error",
|
||||
detail: "Panama shell needs to restart.",
|
||||
action: {kind: "repair", label: "Restart Panama", confirm: true}
|
||||
}]
|
||||
' <<<"$warning_snapshot")"
|
||||
projection_snapshot="$(jq -c '
|
||||
.fixtureSecret = "fixture-secret"
|
||||
| .summary.fixtureSecret = "fixture-secret"
|
||||
@@ -33,7 +45,7 @@ fail() {
|
||||
}
|
||||
|
||||
[[ -f "$service" ]] || fail 'Health.qml is missing'
|
||||
[[ -f "$harness" ]] || fail 'health harness is missing'
|
||||
[[ -f "$source_harness" ]] || fail 'health harness is missing'
|
||||
[[ -f "$shell" ]] || fail 'shell.qml is missing'
|
||||
|
||||
# shell.qml is not started here: it is the active desktop shell. Keep this
|
||||
@@ -72,6 +84,33 @@ if keys != ["summary", "busy", "generation", "acceptedGeneration", "checks"]:
|
||||
PY
|
||||
|
||||
fixture_dir="$(mktemp -d /tmp/panama-health.XXXXXX)"
|
||||
config_path="$fixture_dir/quickshell"
|
||||
cp -a "$repo_dir/config/dot/quickshell" "$config_path"
|
||||
harness="$config_path/health-harness.qml"
|
||||
python3 - "$harness" <<'PY'
|
||||
import sys
|
||||
|
||||
path = sys.argv[1]
|
||||
source = open(path, encoding="utf-8").read()
|
||||
needle = ' function repair(id: string): bool { return Health.repair(id, false); }\n'
|
||||
replacement = needle + ''' function externalRepair(id: string): bool { return Health.repair(id, true); }
|
||||
function pendingRefreshRace(): string {
|
||||
const before = Health.generation;
|
||||
Health.finishRepair(0, "panama.caffeine", false, JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
checkId: "panama.caffeine",
|
||||
accepted: true,
|
||||
exitCode: 0,
|
||||
message: "Fixture repair completed."
|
||||
}));
|
||||
const accepted = Health.refresh();
|
||||
return JSON.stringify({ accepted: accepted, before: before });
|
||||
}
|
||||
'''
|
||||
if needle not in source:
|
||||
raise SystemExit("health harness repair seam is missing")
|
||||
open(path, "w", encoding="utf-8").write(source.replace(needle, replacement))
|
||||
PY
|
||||
helper="$fixture_dir/panama-doctor"
|
||||
copy_bin="$fixture_dir/bin"
|
||||
copy_file="$fixture_dir/copied-report.json"
|
||||
@@ -96,6 +135,11 @@ printf '%s\n' \
|
||||
' *) printf "not-json\\n"; exit 0 ;;' \
|
||||
' esac' \
|
||||
'fi' \
|
||||
'if [[ "$1" == "--repair" && "$2" == "desktop.quickshell" && "$3" == "--json" ]]; then' \
|
||||
' sleep 0.25' \
|
||||
' printf "{\"schemaVersion\":1,\"checkId\":\"desktop.quickshell\",\"accepted\":true,\"exitCode\":0,\"message\":\"Panama shell restart was requested.\"}\\n"' \
|
||||
' exit 0' \
|
||||
'fi' \
|
||||
'exit 2' >"$helper"
|
||||
chmod +x "$helper"
|
||||
mkdir -p "$copy_bin"
|
||||
@@ -243,12 +287,52 @@ jq -e '.lastRepair.checkId == "panama.caffeine" and .lastRepair.accepted == fals
|
||||
--argjson before "$mismatch_generation" >/dev/null <<<"$state" \
|
||||
|| fail "mismatched repair JSON escaped containment: $state"
|
||||
|
||||
# A refresh arriving after repair settlement but before the deferred mandatory
|
||||
# scan is coalesced into that scan instead of starting an extra generation.
|
||||
pending_race="$(run ipc call health-test pendingRefreshRace)"
|
||||
jq -e '.accepted == false' >/dev/null <<<"$pending_race" \
|
||||
|| fail "refresh escaped the post-repair pending window: $pending_race"
|
||||
pending_generation="$(jq -r .before <<<"$pending_race")"
|
||||
for _ in $(seq 1 120); do
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.busy == false and .generation == ($before + 1) and .queuedRefresh == false' \
|
||||
--argjson before "$pending_generation" >/dev/null <<<"$state" && break
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.busy == false and .generation == ($before + 1) and .queuedRefresh == false' \
|
||||
--argjson before "$pending_generation" >/dev/null <<<"$state" \
|
||||
|| fail "pending-window refresh created duplicate scans: $state"
|
||||
|
||||
# External IPC cannot bypass an authored confirmation. The same current row is
|
||||
# still repairable through Settings' external=false path after UI confirmation.
|
||||
confirm_generation="$(jq -r .generation <<<"$state")"
|
||||
[[ "$(run ipc call health-test accept "$confirm_snapshot" "$confirm_generation")" == "true" ]] \
|
||||
|| fail 'confirmation fixture was rejected'
|
||||
before_repair_lines="$(wc -l <"$repair_log")"
|
||||
[[ "$(run ipc call health-test externalRepair desktop.quickshell)" == "false" ]] \
|
||||
|| fail 'external repair bypassed confirmation'
|
||||
[[ "$(wc -l <"$repair_log")" == "$before_repair_lines" ]] \
|
||||
|| fail 'external confirmation rejection started a process'
|
||||
[[ "$(run ipc call health-test repair desktop.quickshell)" == "true" ]] \
|
||||
|| fail 'confirmed Settings repair was refused'
|
||||
for _ in $(seq 1 120); do
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.busy == false and .generation == ($before + 1)' \
|
||||
--argjson before "$confirm_generation" >/dev/null <<<"$state" && break
|
||||
sleep 0.1
|
||||
done
|
||||
jq -e '.lastRepair == {schemaVersion:1, checkId:"desktop.quickshell", accepted:true, exitCode:0, message:"Panama shell restart was requested."}
|
||||
and .generation == ($before + 1)' --argjson before "$confirm_generation" \
|
||||
>/dev/null <<<"$state" || fail "confirmed Settings repair did not complete safely: $state"
|
||||
[[ "$(grep -Fc -- '--repair desktop.quickshell --json' "$repair_log")" == 1 ]] \
|
||||
|| fail 'confirmed Settings repair did not start exactly one repair process'
|
||||
|
||||
[[ "$(run ipc call health-test repair unknown.check)" == "false" ]] \
|
||||
|| fail 'unknown check started a repair'
|
||||
[[ "$(run ipc call health-test repair integration.calendar)" == "false" ]] \
|
||||
|| fail 'non-repairable check started a repair'
|
||||
state="$(run ipc call health-test status)"
|
||||
jq -e '.repairingId == "" and .generation == ($before + 1)' --argjson before "$mismatch_generation" \
|
||||
jq -e '.repairingId == "" and .generation == ($before + 1)' --argjson before "$confirm_generation" \
|
||||
>/dev/null <<<"$state" || fail "rejected repair altered process state: $state"
|
||||
|
||||
python3 - "$service" <<'PY' || fail 'external repair failure notification is not bounded'
|
||||
|
||||
Reference in New Issue
Block a user