#!/bin/bash set -euo pipefail source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh" require_command jq require_command python3 migration="$ROOT/migrations/1786643346.sh" test_dir=$(mktemp -d) trap 'rm -rf "$test_dir"' EXIT home="$test_dir/home" preferences="$home/.config/chromium/Default/Preferences" mkdir -p "$(dirname "$preferences")" # Any id Chromium once derived from the extension's keyless load path; the # repair keys off the registered command name, not the id. ghost_id="ikkebdkaanlebnifjnbeiaklodhbjcci" pinned_id="bgpiichlckmfanooecilcjemknkcpngb" write_stale_preferences() { jq -n --arg ghost "$ghost_id" --arg pinned "$pinned_id" '{extensions: {commands: {"linux:Alt+Shift+L": {command_name: "copy-url", extension: $ghost, global: false}}, settings: {($ghost): {commands: {"copy-url": {suggested_key: "Alt+Shift+L", was_assigned: true}}}, ($pinned): {commands: {"copy-url": {suggested_key: "Alt+Shift+L"}}}}}}' >"$preferences" } stub_bin="$test_dir/bin" mkdir -p "$stub_bin" run_migration() { HOME="$home" PATH="$stub_bin:$PATH" bash -euo pipefail "$migration" >/dev/null 2>&1 } # A running browser prompts for the windows to be closed; declining (or having # no terminal to ask in) defers the repair so a rewrite-on-exit cannot revert # it. printf '#!/bin/bash\nexit 0\n' >"$stub_bin/pgrep" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/gum" chmod +x "$stub_bin/pgrep" "$stub_bin/gum" write_stale_preferences before_hash=$(sha256sum "$preferences" | cut -d' ' -f1) run_migration && fail "migration defers while a browser is running" [[ $(sha256sum "$preferences" | cut -d' ' -f1) == "$before_hash" ]] || fail "migration leaves preferences alone while a browser is running" pass "migration defers the repair while a browser is running" # Confirming the prompt after closing the browser lets the repair proceed. cat >"$stub_bin/gum" <<'STUB' #!/bin/bash touch "${GUM_CALLED:?}" exit 0 STUB cat >"$stub_bin/pgrep" <<'STUB' #!/bin/bash count_file="${PGREP_COUNT_FILE:?}" count=$(( $(cat "$count_file" 2>/dev/null || echo 0) + 1 )) printf '%s\n' "$count" >"$count_file" (( count == 1 )) && exit 0 || exit 1 STUB rm -f "$test_dir/pgrep-count" GUM_CALLED="$test_dir/gum-called" PGREP_COUNT_FILE="$test_dir/pgrep-count" \ HOME="$home" PATH="$stub_bin:$PATH" bash -euo pipefail "$migration" >/dev/null 2>&1 || fail "migration proceeds once the browser prompt is confirmed" [[ -e $test_dir/gum-called ]] || fail "migration asks before repairing under a running browser" jq -e --arg pinned "$pinned_id" '.extensions.commands["linux:Alt+Shift+L"].extension == $pinned' "$preferences" >/dev/null || fail "migration repairs after the browser prompt is confirmed" pass "migration asks to close the browser and repairs on confirmation" rm -f "$preferences.omarchy-copy-url-repair.bak" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/gum" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/pgrep" write_stale_preferences # With browsers closed the ghost registration moves to the pinned id. printf '#!/bin/bash\nexit 1\n' >"$stub_bin/pgrep" run_migration || fail "migration repairs the shortcut when no browser is running" jq -e --arg ghost "$ghost_id" --arg pinned "$pinned_id" ' .extensions.commands["linux:Alt+Shift+L"].extension == $pinned and (.extensions.settings | has($ghost) | not) and .extensions.settings[$pinned].commands["copy-url"].was_assigned == true ' "$preferences" >/dev/null || fail "migration rebinds the Copy URL shortcut to the pinned extension id" [[ -f $preferences.omarchy-copy-url-repair.bak ]] || fail "migration backs up preferences before the repair" pass "migration rebinds the Copy URL shortcut to the pinned extension id" # A repaired profile has no ghost registration left, so nothing is pending — # even while a browser is running. rm "$preferences.omarchy-copy-url-repair.bak" repaired_hash=$(sha256sum "$preferences" | cut -d' ' -f1) printf '#!/bin/bash\nexit 0\n' >"$stub_bin/pgrep" run_migration || fail "migration reruns cleanly after the repair" [[ $(sha256sum "$preferences" | cut -d' ' -f1) == "$repaired_hash" && ! -e $preferences.omarchy-copy-url-repair.bak ]] || fail "migration is idempotent after the repair" pass "migration is idempotent after the repair" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/pgrep" # A remapped shortcut keeps the user's chosen key while moving to the pinned id. jq -n --arg ghost "$ghost_id" '{extensions: {commands: {"linux:Ctrl+Alt+P": {command_name: "copy-url", extension: $ghost, global: false}}, settings: {}}}' >"$preferences" run_migration || fail "migration repairs remapped shortcuts" jq -e --arg pinned "$pinned_id" '.extensions.commands["linux:Ctrl+Alt+P"].extension == $pinned' "$preferences" >/dev/null || fail "migration keeps the remapped key while rebinding to the pinned id" pass "migration keeps remapped shortcut keys" # When the pinned extension already holds a copy-url binding (the user fixed # it by hand), the ghost is dropped rather than doubled into a second binding. jq -n --arg ghost "$ghost_id" --arg pinned "$pinned_id" '{extensions: {commands: {"linux:Ctrl+Alt+P": {command_name: "copy-url", extension: $pinned, global: false}, "linux:Alt+Shift+L": {command_name: "copy-url", extension: $ghost, global: false}}, settings: {}}}' >"$preferences" run_migration || fail "migration cleans ghosts alongside a manual repair" jq -e --arg pinned "$pinned_id" ' (.extensions.commands | has("linux:Alt+Shift+L") | not) and .extensions.commands["linux:Ctrl+Alt+P"].extension == $pinned ' "$preferences" >/dev/null || fail "migration drops the ghost instead of double-binding the pinned extension" pass "migration never double-binds the pinned extension" # A browser starting mid-repair may write stale Preferences back on exit, so # the migration must stay pending for a later browser-free run to verify. write_stale_preferences cat >"$stub_bin/pgrep" <<'STUB' #!/bin/bash count_file="${PGREP_COUNT_FILE:?}" count=$(( $(cat "$count_file" 2>/dev/null || echo 0) + 1 )) printf '%s\n' "$count" >"$count_file" (( count >= 2 )) && exit 0 || exit 1 STUB rm -f "$test_dir/pgrep-count" if PGREP_COUNT_FILE="$test_dir/pgrep-count" HOME="$home" PATH="$stub_bin:$PATH" \ bash -euo pipefail "$migration" >/dev/null 2>&1; then fail "migration stays pending when a browser starts mid-repair" fi jq -e --arg pinned "$pinned_id" '.extensions.commands["linux:Alt+Shift+L"].extension == $pinned' "$preferences" >/dev/null || fail "migration still repairs preferences before deferring on a late browser" pass "migration stays pending when a browser starts mid-repair" rm -f "$preferences.omarchy-copy-url-repair.bak" # A browser that started and exited mid-repair restores stale Preferences # before the final process check; the post-repair file verification catches it. write_stale_preferences cp "$preferences" "$test_dir/stale-preferences" cat >"$stub_bin/pgrep" <<'STUB' #!/bin/bash count_file="${PGREP_COUNT_FILE:?}" count=$(( $(cat "$count_file" 2>/dev/null || echo 0) + 1 )) printf '%s\n' "$count" >"$count_file" (( count == 2 )) && cp "$STALE_PREFERENCES" "$REPAIRED_PREFERENCES" exit 1 STUB rm -f "$test_dir/pgrep-count" if PGREP_COUNT_FILE="$test_dir/pgrep-count" STALE_PREFERENCES="$test_dir/stale-preferences" \ REPAIRED_PREFERENCES="$preferences" HOME="$home" PATH="$stub_bin:$PATH" \ bash -euo pipefail "$migration" >/dev/null 2>&1; then fail "migration stays pending when a briefly-lived browser undoes the repair" fi pass "migration stays pending when a briefly-lived browser undoes the repair" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/pgrep" write_stale_preferences run_migration || fail "migration recovers after a reverted repair" rm -f "$preferences.omarchy-copy-url-repair.bak" # A repair attempted while a browser was open leaves its backup behind. A # rerun that sees a clean disk while that browser still runs must stay # pending — the browser can restore the ghost on exit — and only a # browser-free rerun verifies the repair and completes. write_stale_preferences run_migration || fail "repair run before the verification scenario" [[ -f $preferences.omarchy-copy-url-repair.bak ]] || fail "verification scenario has a repair backup" printf '#!/bin/bash\nexit 0\n' >"$stub_bin/pgrep" run_migration && fail "migration must not complete an unverified repair while a browser runs" pass "migration keeps an unverified repair pending while a browser runs" printf '#!/bin/bash\nexit 1\n' >"$stub_bin/pgrep" run_migration || fail "migration completes once the repair is verified with browsers closed" pass "migration verifies an attempted repair on a browser-free rerun" rm -f "$preferences.omarchy-copy-url-repair.bak" # An installed third-party extension with a command that happens to be named # copy-url keeps its own registration. jq -n '{extensions: {commands: {"linux:Alt+Shift+L": {command_name: "copy-url", extension: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", global: false}}, settings: {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: {path: "/home/user/.config/some-extension", commands: {}}}}}' >"$preferences" untouched_hash=$(sha256sum "$preferences" | cut -d' ' -f1) run_migration || fail "migration leaves installed third-party extensions alone" [[ $(sha256sum "$preferences" | cut -d' ' -f1) == "$untouched_hash" ]] || fail "migration does not steal a third-party copy-url command registration" pass "migration leaves installed third-party extensions alone"