Complete command-scoped authentication across update phases

This commit is contained in:
Afonso Oliveira committed 2026-09-06 22:26:06 +01:00
1 parent 7f9a401bb1
commit 35b318ed09
16 files changed
+583 -1643

No files matched your search

+8 -6
View File
@@ -105,7 +105,7 @@ assert_log_line() {
}
run_channel stable
assert_log_line $'refresh\tstable' "stable refreshes the stable pacman channel"
assert_log_line $'refresh\tstable\tdefer-hook' "stable refreshes the stable pacman channel"
assert_log_line $'sudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy\tomarchy-settings' "stable installs stable Omarchy packages"
assert_log_line $'unlink\t--no-reboot' "stable restores the package-backed Omarchy path without an early reboot prompt"
assert_log_line $'update\t-y\tOMARCHY_PATH=/usr/share/omarchy' "stable runs the normal update pipeline from the package-backed path"
@@ -115,13 +115,13 @@ fi
pass "stable does not require reboot when already package-backed"
run_channel rc
assert_log_line $'refresh\trc' "rc refreshes the rc pacman channel"
assert_log_line $'refresh\trc\tdefer-hook' "rc refreshes the rc pacman channel"
assert_log_line $'sudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy\tomarchy-settings' "rc installs rc Omarchy packages"
assert_log_line $'unlink\t--no-reboot' "rc restores the package-backed Omarchy path without an early reboot prompt"
assert_log_line $'update\t-y\tOMARCHY_PATH=/usr/share/omarchy' "rc runs the normal update pipeline from the package-backed path"
OMARCHY_TEST_PATH="$ROOT" run_channel edge
assert_log_line $'refresh\tedge' "edge refreshes the edge pacman channel"
assert_log_line $'refresh\tedge\tdefer-hook' "edge refreshes the edge pacman channel"
assert_log_line $'sudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy-dev\tomarchy-settings-dev' "edge installs development Omarchy packages"
assert_log_line $'unlink\t--no-reboot' "edge unlinks dev without an early reboot prompt"
assert_log_line $'state\tset\treboot-required' "edge marks reboot required when leaving dev"
@@ -137,7 +137,7 @@ if run_channel dev >"$test_tmp/occupied.out" 2>"$test_tmp/occupied.err"; then
fi
grep -q "already exists and is not a git checkout" "$test_tmp/occupied.err" || fail "dev explains occupied checkout paths" "$(cat "$test_tmp/occupied.err")"
if grep -Fx $'refresh\tedge' "$log_file" >/dev/null; then
if grep -Fx $'refresh\tedge\tdefer-hook' "$log_file" >/dev/null; then
fail "dev validates checkout path before changing packages" "$(cat "$log_file")"
fi
pass "dev refuses occupied non-checkout paths before package changes"
@@ -145,15 +145,17 @@ pass "dev refuses occupied non-checkout paths before package changes"
rmdir "$checkout"
run_channel dev
assert_log_line $'gum\tconfirm\t--default=false\tSwitch to dev channel?' "dev asks for confirmation"
assert_log_line $'refresh\tedge' "dev refreshes the edge pacman channel"
assert_log_line $'refresh\tedge\tdefer-hook' "dev refreshes the edge pacman channel"
assert_log_line $'sudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy-dev\tomarchy-settings-dev' "dev installs development Omarchy packages"
assert_log_line $'git\tclone\thttps://github.com/basecamp/omarchy.git\t'"$checkout" "dev clones the source checkout to ~/omarchy"
assert_log_line $'link\t'"$checkout"$'\t--no-reboot' "dev links ~/omarchy without an early reboot prompt"
assert_log_line $'state\tset\treboot-required' "dev defers the reboot prompt to the update pipeline"
assert_log_line $'update\t-y\tOMARCHY_PATH='"$checkout" "dev runs the normal update pipeline from the source checkout"
[[ $(grep -E '^(git|link|state|refresh|sudo|update)' "$log_file") == $'git\tclone\thttps://github.com/basecamp/omarchy.git\t'"$checkout"$'\nlink\t'"$checkout"$'\t--no-reboot\nstate\tset\treboot-required\nrefresh\tedge\nsudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy-dev\tomarchy-settings-dev\nupdate\t-y\tOMARCHY_PATH='"$checkout" ]] ||
[[ $(grep -E '^(git|link|state|refresh|sudo|update)' "$log_file" | sed '/run-deferred/d') == $'git\tclone\thttps://github.com/basecamp/omarchy.git\t'"$checkout"$'\nlink\t'"$checkout"$'\t--no-reboot\nstate\tset\treboot-required\nrefresh\tedge\tdefer-hook\nsudo\tenv\tOMARCHY_UPDATE_PACMAN=1\tpacman\t-S\t--needed\t--noconfirm\t--ask\t4\tomarchy-dev\tomarchy-settings-dev\nupdate\t-y\tOMARCHY_PATH='"$checkout" ]] ||
fail "dev activates the checkout before changing or updating packages" "$(cat "$log_file")"
pass "dev activates the checkout before changing or updating packages"
[[ $(tail -1 "$log_file") == $'refresh\tedge\trun-deferred' ]] || fail "channel refresh hook must run after the complete update"
pass "channel changes defer the refresh hook until all update work finishes"
OMARCHY_TEST_PATH="$checkout" run_channel stable
assert_log_line $'unlink\t--no-reboot' "switching from dev to stable unlinks without an early reboot prompt"
+124
View File
@@ -0,0 +1,124 @@
#!/bin/bash
# Test the real orchestration with fixed privileged paths redirected to harmless
# stand-ins. No host sudo, package transaction, namespace root, or exploit runs.
boundary_tmp=$(mktemp -d)
trap 'rm -rf "$boundary_tmp"' EXIT
export SUDO_TEST_ROOT="$boundary_tmp/omarchy"
export SUDO_TEST_LOG="$boundary_tmp/events"
export SUDO_TEST_CACHE="$boundary_tmp/cache"
export OMARCHY_PATH="$SUDO_TEST_ROOT"
export SUDO_TEST_HOME="$boundary_tmp/home"
mkdir -p "$SUDO_TEST_HOME"
mkdir -p "$SUDO_TEST_ROOT/bin" "$SUDO_TEST_ROOT/mock" "$SUDO_TEST_ROOT/default/omarchy/sudo-no-update"
: >"$SUDO_TEST_LOG"
copy_boundary_file() {
python3 - "$ROOT" "$SUDO_TEST_ROOT" "$1" <<'PY'
import sys
from pathlib import Path
source, target, name = map(Path,sys.argv[1:])
p=target/name
p.parent.mkdir(parents=True,exist_ok=True)
s=(source/name).read_text().replace('$HOME', '$SUDO_TEST_HOME')
for command in ['sudo','pacman','omarchy-pkg-missing','systemd-inhibit','setpriv','snapper']:
s=s.replace('/usr/bin/'+command, str(target/'mock'/command))
s=s.replace('PATH=/usr/bin:/usr/sbin:/bin:/sbin', 'PATH="'+str(target/'bin')+':/usr/bin:/usr/sbin:/bin:/sbin"')
p.write_text(s)
p.chmod((source/name).stat().st_mode & 0o777)
PY
}
copy_boundary_file bin/omarchy-security-functions
copy_boundary_file default/omarchy/sudo-no-update/sudo
cat >"$SUDO_TEST_ROOT/mock/sudo" <<'STUB'
#!/bin/bash
set -euo pipefail
printf 'sudo' >>"$SUDO_TEST_LOG"
printf ' %q' "$@" >>"$SUDO_TEST_LOG"
printf '\n' >>"$SUDO_TEST_LOG"
if [[ ${1:-} == "-h" ]]; then
if [[ ${SUDO_TEST_UNSUPPORTED:-0} == "1" ]]; then
echo 'usage: sudo [-ABbEHknPS] command'
else
echo 'usage: sudo [-ABbEHkNnPS] command'
fi
exit 0
fi
if [[ ${1:-} == "-k" || ${1:-} == "-K" ]]; then
[[ ${SUDO_TEST_REVOKE_FAIL:-0} != "1" ]] || exit 1
rm -f "$SUDO_TEST_CACHE"
exit 0
fi
if [[ ${1:-} == "-N" ]]; then
shift
else
touch "$SUDO_TEST_CACHE"
fi
[[ ${SUDO_TEST_SUDO_FAIL:-0} != "1" ]] || exit 1
background=0
while (( $# )); do
case "$1" in
-N|-n) shift ;;
-b) background=1; shift ;;
-v) exit 0 ;;
-u|--user) shift 2 ;;
--) shift; break ;;
*) break ;;
esac
done
(( $# )) || exit 0
if (( background )); then
"$@" &
else
"$@"
fi
STUB
chmod +x "$SUDO_TEST_ROOT/mock/sudo"
cat >"$SUDO_TEST_ROOT/bin/test-step" <<'STUB'
#!/bin/bash
set -euo pipefail
step=${0##*/}
printf 'step:%s %s\n' "$step" "$*" >>"$SUDO_TEST_LOG"
if [[ $step == "omarchy-hook" || $step == "omarchy-update-mise" ]]; then
[[ ! -e $SUDO_TEST_CACHE ]] || exit 91
fi
if [[ ${SUDO_TEST_FAIL_STEP:-} == "$step" ]]; then
# Model a misbehaving child leaving state behind, then failing. Cleanup must
# still revoke it. This never invokes real sudo or exercises a privilege flaw.
touch "$SUDO_TEST_CACHE"
exit 17
fi
if [[ ${SUDO_TEST_SIGNAL_STEP:-} == "$step" ]]; then
touch "$SUDO_TEST_CACHE"
kill -TERM "$PPID"
exit 0
fi
case "$step" in
omarchy-update-system-pkgs|omarchy-update-keyring|omarchy-snapshot)
sudo /usr/bin/true
;;
pacman) exit 0 ;;
yay)
[[ $* == *"--sudo $OMARCHY_PATH/default/omarchy/sudo-no-update/sudo"* ]] || exit 92
[[ $* == *"--nosudoloop"* ]] || exit 93
;;
esac
STUB
chmod +x "$SUDO_TEST_ROOT/bin/test-step"
for step in omarchy-update-lock omarchy-update-requires-free-space omarchy-update-confirm omarchy-update-pkg-prune omarchy-snapshot omarchy-update-stay-awake omarchy-update-dev omarchy-update-keyring omarchy-update-system-pkgs omarchy-migrate omarchy-hook omarchy-update-aur-pkgs omarchy-update-mise omarchy-update-orphan-pkgs omarchy-update-analyze-logs omarchy-update-status omarchy-update-restart omarchy-pkg-aur-accessible omarchy-notification-dismiss pacman cp yay; do
ln -s test-step "$SUDO_TEST_ROOT/bin/$step"
done
ln -s ../bin/test-step "$SUDO_TEST_ROOT/mock/pacman"
reset_boundary() {
: >"$SUDO_TEST_LOG"
rm -f "$SUDO_TEST_CACHE"
unset SUDO_TEST_FAIL_STEP SUDO_TEST_SIGNAL_STEP SUDO_TEST_SUDO_FAIL SUDO_TEST_REVOKE_FAIL SUDO_TEST_UNSUPPORTED
}
assert_boundary_cold() {
[[ ! -e $SUDO_TEST_CACHE ]] || fail "$1 left cached authorization"
[[ $(tail -1 "$SUDO_TEST_LOG") == "sudo -k" ]] || fail "$1 did not revoke at exit" "$(<"$SUDO_TEST_LOG")"
}
+95 -1018
View File
File diff suppressed because it is too large. Load diff
+44 -27
View File
@@ -4,16 +4,31 @@ set -euo pipefail
source "$(dirname "$0")/base-test.sh"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
stub_bin="$test_tmp/bin"
test_home="$test_tmp/home"
source "$SHELL_TEST_DIR/fixtures/sudo-boundary-test.sh"
test_tmp="$boundary_tmp"
stub_bin="$SUDO_TEST_ROOT/bin"
test_home="$SUDO_TEST_HOME"
runtime_dir="$test_tmp/runtime"
mkdir -p "$stub_bin" "$test_home" "$runtime_dir"
mkdir -p "$runtime_dir"
for command in omarchy-update omarchy-update-lock omarchy-update-stay-awake; do
rm -f "$SUDO_TEST_ROOT/bin/$command"
copy_boundary_file "bin/$command"
done
cat >"$SUDO_TEST_ROOT/mock/setpriv" <<'STUB'
#!/bin/bash
while [[ ${1:-} == --* ]]; do
case "$1" in
--reuid|--regid) shift 2 ;;
--clear-groups) shift ;;
*) exit 90 ;;
esac
done
exec "$@"
STUB
chmod +x "$SUDO_TEST_ROOT/mock/setpriv"
run_with_lock_env() {
HOME="$test_home" \
SUDO_TEST_HOME="$test_home" \
XDG_RUNTIME_DIR="$runtime_dir" \
XDG_STATE_HOME="$test_tmp/state" \
PATH="$stub_bin:$ROOT/bin:$PATH" \
@@ -24,6 +39,7 @@ write_stub() {
local name="$1"
local body="$2"
rm -f "$stub_bin/$name"
cat >"$stub_bin/$name" <<SH
#!/bin/bash
$body
@@ -51,13 +67,15 @@ for command in \
done
write_stub omarchy-update-available 'exit 1'
write_stub pkexec 'exec "$@"'
write_stub systemd-inhibit 'while [[ $1 == --* ]]; do shift; done; exec "$@"'
ln -s ../bin/systemd-inhibit "$SUDO_TEST_ROOT/mock/systemd-inhibit"
# omarchy-update should hold the lock before snapshotting, so a second update
# cannot even enter its pre-update snapshot.
update_snapshot_marker="$test_tmp/update-snapshot-started"
write_stub omarchy-snapshot 'echo started >"$TEST_MARKER"; sleep 2; exit 0'
OMARCHY_UPDATE_LOGGED=1 TEST_MARKER="$update_snapshot_marker" run_with_lock_env "$ROOT/bin/omarchy-update" -y >"$test_tmp/update-first.out" 2>&1 &
OMARCHY_UPDATE_LOGGED=1 TEST_MARKER="$update_snapshot_marker" run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update" -y >"$test_tmp/update-first.out" 2>&1 &
update_pid=$!
for _ in {1..50}; do
@@ -67,7 +85,7 @@ done
[[ -f $update_snapshot_marker ]] || fail "first omarchy-update reached snapshot under lock"
set +e
OMARCHY_UPDATE_LOGGED=1 TEST_MARKER="$test_tmp/update-second-snapshot-started" run_with_lock_env "$ROOT/bin/omarchy-update" -y >"$test_tmp/update-second.out" 2>&1
OMARCHY_UPDATE_LOGGED=1 TEST_MARKER="$test_tmp/update-second-snapshot-started" run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update" -y >"$test_tmp/update-second.out" 2>&1
update_second_status=$?
set -e
@@ -85,11 +103,11 @@ pass "omarchy-update prevents overlapping top-level updates"
inhibit_pid_file="$test_tmp/inhibit-pid"
keyring_marker="$test_tmp/keyring-started"
write_stub omarchy-snapshot 'exit 0'
write_stub systemd-inhibit 'echo "$$" >"$INHIBIT_PID_FILE"; exec sleep 30'
write_stub systemd-inhibit '[[ -z ${INHIBIT_PID_FILE:-} ]] || echo "$$" >"$INHIBIT_PID_FILE"; while [[ $1 == --* ]]; do shift; done; exec "$@"'
write_stub omarchy-update-keyring 'echo started >"$TEST_MARKER"; sleep 3; exit 0'
OMARCHY_UPDATE_LOGGED=1 TEST_MARKER="$keyring_marker" INHIBIT_PID_FILE="$inhibit_pid_file" \
run_with_lock_env "$ROOT/bin/omarchy-update" -y >"$test_tmp/update-inhibit.out" 2>&1 &
run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update" -y >"$test_tmp/update-inhibit.out" 2>&1 &
inhibit_update_pid=$!
for _ in {1..100}; do
@@ -123,11 +141,10 @@ if (( EUID != 0 )); then
terminal_inhibit_pid_file="$test_tmp/terminal-inhibit-pid"
write_stub sudo '
printf "%s\n" "$*" >>"$SUDO_LOG"
if [[ $1 == "-v" ]]; then
exit 0
fi
exec "$@"'
write_stub pkexec 'touch "$PKEXEC_MARKER"; exec "$@"'
[[ $1 == "-N" && $2 == "-b" && $3 == "--" ]] || exit 90
shift 3
"$@" &'
write_stub pkexec '[[ -z ${PKEXEC_MARKER:-} ]] || touch "$PKEXEC_MARKER"; exec "$@"'
# start leaves the inhibitor running on purpose, but script tears the pty down
# the moment its command returns, which SIGHUPs that inhibitor before it can
@@ -137,7 +154,7 @@ exec "$@"'
#!/bin/bash
omarchy-update-stay-awake start
for _ in {1..200}; do
grep -q '^systemd-inhibit ' "$SUDO_LOG" && break
grep -q -- '^-N -b -- ' "$SUDO_LOG" && break
sleep 0.05
done
SH
@@ -146,10 +163,10 @@ SH
SUDO_LOG="$sudo_log" PKEXEC_MARKER="$pkexec_marker" INHIBIT_PID_FILE="$terminal_inhibit_pid_file" \
run_with_lock_env script -qefc "$terminal_driver" /dev/null >/dev/null
grep -qx -- '-v' "$sudo_log" || fail "terminal sleep inhibition validates sudo in the foreground"
grep -q '^systemd-inhibit ' "$sudo_log" || fail "terminal sleep inhibition runs through sudo"
grep -q -- '^-N -b -- ' "$sudo_log" || fail "terminal inhibition authenticates its background command without a reusable timestamp"
grep -q -- '^-N -b -- ' "$sudo_log" || fail "terminal sleep inhibition runs through sudo"
[[ ! -e $pkexec_marker ]] || fail "terminal sleep inhibition does not use pkexec"
run_with_lock_env "$ROOT/bin/omarchy-update-stay-awake" stop
run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update-stay-awake" stop
pass "terminal updates use sudo instead of Polkit for sleep inhibition"
fi
@@ -158,7 +175,7 @@ fi
write_stub omarchy-snapshot 'exit 0'
write_stub omarchy-update-keyring 'exit 0'
write_stub omarchy-toggle-idle '
state_file="$HOME/.local/state/omarchy/indicators/stay-awake"
state_file="$SUDO_TEST_HOME/.local/state/omarchy/indicators/stay-awake"
case "$1" in
stay-awake)
mkdir -p "$(dirname "$state_file")"
@@ -169,20 +186,20 @@ case "$1" in
;;
esac'
write_stub omarchy-update-restart '
state_file="$HOME/.local/state/omarchy/indicators/stay-awake"
if [[ ${EXPECT_STAY_AWAKE:-0} == "1" ]]; then
state_file="$SUDO_TEST_HOME/.local/state/omarchy/indicators/stay-awake"
if [[ ${1:-} == "--services-only" || ${EXPECT_STAY_AWAKE:-0} == "1" ]]; then
[[ -f $state_file ]]
else
[[ ! -f $state_file ]]
fi'
rm -f "$test_home/.local/state/omarchy/indicators/stay-awake"
OMARCHY_UPDATE_LOGGED=1 run_with_lock_env "$ROOT/bin/omarchy-update" -y
OMARCHY_UPDATE_LOGGED=1 run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update" -y
[[ ! -f $test_home/.local/state/omarchy/indicators/stay-awake ]] || fail "update clears its Stay Awake state before restart handling"
mkdir -p "$test_home/.local/state/omarchy/indicators"
touch "$test_home/.local/state/omarchy/indicators/stay-awake"
OMARCHY_UPDATE_LOGGED=1 EXPECT_STAY_AWAKE=1 run_with_lock_env "$ROOT/bin/omarchy-update" -y
OMARCHY_UPDATE_LOGGED=1 EXPECT_STAY_AWAKE=1 run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update" -y
[[ -f $test_home/.local/state/omarchy/indicators/stay-awake ]] || fail "update preserves pre-existing Stay Awake state"
pass "omarchy-update restores only its own Stay Awake state before restart handling"
@@ -194,7 +211,7 @@ mkdir -p "$stay_awake_helper_state" "$(dirname "$stay_awake_state")"
printf '%s\n' "old-update-owner" >"$stay_awake_helper_state/idle-owner"
printf '%s\n' "user-choice" >"$stay_awake_state"
run_with_lock_env "$ROOT/bin/omarchy-update-stay-awake" stop
run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update-stay-awake" stop
[[ $(<"$stay_awake_state") == "user-choice" ]] ||
fail "stale update ownership does not remove a newer Stay Awake choice"
pass "stale update ownership preserves a newer Stay Awake choice"
@@ -206,7 +223,7 @@ unrelated_start_time=$(awk '{ print $22 }' "/proc/$unrelated_pid/stat")
mkdir -p "$stay_awake_helper_state"
printf '%s %s\n' "$unrelated_pid" "$((unrelated_start_time + 1))" >"$stay_awake_helper_state/inhibit-pid"
run_with_lock_env "$ROOT/bin/omarchy-update-stay-awake" stop
run_with_lock_env "$SUDO_TEST_ROOT/bin/omarchy-update-stay-awake" stop
kill -0 "$unrelated_pid" 2>/dev/null ||
fail "stale inhibitor state does not terminate a reused PID"
kill "$unrelated_pid"
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
source "$SHELL_TEST_DIR/fixtures/sudo-boundary-test.sh"
rm "$SUDO_TEST_ROOT/bin/omarchy-update-restart"
copy_boundary_file bin/omarchy-update-restart
for step in omarchy-state omarchy-restart-sshd omarchy-restart-shell omarchy-system-reboot; do
ln -s test-step "$SUDO_TEST_ROOT/bin/$step"
done
cat >"$SUDO_TEST_ROOT/bin/gum" <<'STUB'
#!/bin/bash
printf 'prompt:%s\n' "$*" >>"$SUDO_TEST_LOG"
exit 1
STUB
chmod +x "$SUDO_TEST_ROOT/bin/gum"
mkdir -p "$SUDO_TEST_HOME/.local/state/omarchy"
touch "$SUDO_TEST_HOME/.local/state/omarchy/reboot-required" "$SUDO_TEST_HOME/.local/state/omarchy/restart-sshd-required"
for mode in --services-only --reboot-only; do
reset_boundary
PATH="$SUDO_TEST_ROOT/bin:$PATH" "$SUDO_TEST_ROOT/bin/omarchy-update-restart" "$mode" >"$boundary_tmp/output" 2>&1
if [[ $mode == "--services-only" ]]; then
grep -q '^step:omarchy-restart-sshd ' "$SUDO_TEST_LOG" || fail "service phase did not restart a marked service"
grep -q '^step:omarchy-restart-shell ' "$SUDO_TEST_LOG" || fail "service phase did not restart the shell"
if grep -q '^prompt:' "$SUDO_TEST_LOG"; then fail "service phase offered a reboot before update cleanup"; fi
else
grep -q '^prompt:' "$SUDO_TEST_LOG" || fail "reboot phase did not offer the required reboot"
if grep -q '^step:omarchy-restart-' "$SUDO_TEST_LOG"; then fail "reboot phase performed later service work"; fi
fi
pass "restart $mode performs only its selected phase"
done
reset_boundary
OMARCHY_UPDATE_UNATTENDED=1 PATH="$SUDO_TEST_ROOT/bin:$PATH" "$SUDO_TEST_ROOT/bin/omarchy-update-restart" --reboot-only >"$boundary_tmp/output" 2>&1
if grep -Eq "^(prompt:|step:omarchy-restart-|step:omarchy-system-reboot)" "$SUDO_TEST_LOG"; then
fail "unattended reboot phase prompted or performed service work"
fi
pass "unattended reboot phase reports a required reboot without prompting"
+7 -55
View File
@@ -2,60 +2,11 @@
set -euo pipefail
source "$(dirname "$0")/base-test.sh"
if [[ -z ${OMARCHY_UPDATE_SEQUENCE_NS:-} ]]; then
outer_uid=$(id -u)
outer_gid=$(id -g)
subuid=$(awk -F: -v user="$(id -un)" '$1 == user { print $2; exit }' /etc/subuid)
subgid=$(awk -F: -v group="$(id -gn)" '$1 == group { print $2; exit }' /etc/subgid)
if [[ -z $subuid || -z $subgid ]]; then
pass "no subordinate uid/gid range; skipping authorized update-sequence test"
exit 0
fi
exec unshare --user --mount \
--map-users "0:$outer_uid:1" --map-users "1:$subuid:65536" \
--map-groups "0:$outer_gid:1" --map-groups "1:$subgid:65536" \
env OMARCHY_UPDATE_SEQUENCE_NS=setup bash "$0"
elif [[ $OMARCHY_UPDATE_SEQUENCE_NS == setup ]]; then
mount -t tmpfs -o mode=0755 tmpfs /run
namespace_tmp=$(mktemp -d -p /run omarchy-update-sequence.XXXXXXXX)
chmod 0755 "$namespace_tmp"
mkdir -p "$namespace_tmp/default/omarchy/sudo-no-update"
cp "$ROOT/default/omarchy/sudo-no-update/sudo" "$namespace_tmp/default/omarchy/sudo-no-update/sudo"
chmod 0755 "$namespace_tmp/default/omarchy/sudo-no-update/sudo"
cat >"$namespace_tmp/fixed-sudo" <<'STUB'
#!/bin/bash
if [[ ${1:-} == "-h" ]]; then
echo 'usage: sudo [-ABbEHkNnPS] command'
fi
exit 0
STUB
chmod 0755 "$namespace_tmp/fixed-sudo"
mount --bind "$namespace_tmp/fixed-sudo" /usr/bin/sudo
mount -t tmpfs -o mode=0755 tmpfs /etc
printf 'export OMARCHY_PATH="%s"\n' "$namespace_tmp" >/etc/omarchy.conf
chmod 0644 /etc/omarchy.conf
chown -R 1000:1000 "$namespace_tmp"
set +e
setpriv --reuid 1000 --regid 1000 --clear-groups \
env OMARCHY_UPDATE_SEQUENCE_NS=run OMARCHY_AUTHORIZED_TEST_ROOT="$namespace_tmp" bash "$0"
status=$?
set -e
umount /usr/bin/sudo
umount /etc
rm -rf "$namespace_tmp"
umount /run
exit "$status"
fi
test_tmp="$OMARCHY_AUTHORIZED_TEST_ROOT"
trap 'rm -rf "$test_tmp"/*' EXIT
stub_bin="$test_tmp/bin"
mkdir -p "$stub_bin"
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
source "$SHELL_TEST_DIR/fixtures/sudo-boundary-test.sh"
copy_boundary_file bin/omarchy-update
test_tmp="$boundary_tmp"
stub_bin="$SUDO_TEST_ROOT/bin"
# Every step omarchy-update runs, recorded in order with the unattended flag it
# was handed. One of them can be told to fail.
@@ -80,6 +31,7 @@ steps=(
)
for step in "${steps[@]}"; do
rm -f "$stub_bin/$step"
cat >"$stub_bin/$step" <<'STUB'
#!/bin/bash
printf '%s unattended=%s\n' "${0##*/}" "${OMARCHY_UPDATE_UNATTENDED:-}" >>"$STEP_LOG"
@@ -96,7 +48,7 @@ run_update() {
FAILING_STEP="${FAILING_STEP:-}" \
OMARCHY_UPDATE_LOGGED=1 \
PATH="$stub_bin:$PATH" \
"$ROOT/bin/omarchy-update" "$@" >"$test_tmp/out" 2>"$test_tmp/err"
"$SUDO_TEST_ROOT/bin/omarchy-update" "$@" >"$test_tmp/out" 2>"$test_tmp/err"
}
steps_run() {