#!/bin/bash set -euo pipefail source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh" source "$SHELL_TEST_DIR/fixtures/passwordless-sudo-test.sh" ( source "$library" printf 'deleteduser ALL=(ALL) NOPASSWD: ALL\n' >"$(rule_file 1000)" printf 'buildbot$ ALL=(ALL) NOPASSWD: ALL\n' >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-buildbot$" # The legacy command never validated the account name, so a manual or NSS # account outside the current policy still has its exact old grant removed. printf 'Alice ALL=(ALL) NOPASSWD: ALL\n' >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-Alice" printf 'admin ALL=(ALL) NOPASSWD: /usr/bin/true\n' >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-custom" printf 'Alice ALL=(ALL) NOPASSWD: ALL\n' >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-handwritten" TEST_DELETE_FAIL=1 assert_status 1 cleanup_all_locked [[ -e $(rule_file 1000) ]] cleanup_all_locked [[ ! -e $(rule_file 1000) && ! -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-Alice ]] [[ -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-custom && -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-handwritten ]] ! compgen -G "$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-buildbot*" rm "$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-custom" "$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-handwritten" ) pass "legacy cleanup removes generated orphan rules for any account and preserves custom policy" # Run the actual migration queue for separate temporary homes. Sudo only calls # the mapped helper and can be refused without requesting host authorization. mkdir -p "$test_tmp/source/migrations" sed "s|/usr/bin/omarchy-sudo-passwordless|$test_tmp/omarchy-sudo-passwordless|g" \ "$ROOT/migrations/1788163635.sh" >"$test_tmp/source/migrations/1788163635.sh" printf 'echo "later migration ran"\n' >"$test_tmp/source/migrations/1788163636.sh" run_migrations() { TEST_MIGRATION=1 OMARCHY_PATH="$test_tmp/source" OMARCHY_MIGRATION_STATE="$test_tmp/$1" \ PATH="$test_tmp/bin:$PATH" /usr/bin/bash "$ROOT/bin/omarchy-migrate" >"$test_tmp/migrations.log" 2>&1 } marker="$test_tmp/var/lib/omarchy/migrations/1788163635" ( source "$library" printf 'audituser ALL=(ALL) NOPASSWD: ALL\n' >"$(rule_file 1000)" printf 'Alice ALL=(ALL) NOPASSWD: ALL\n' >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-Alice" TEST_DELETE_FAIL=1 assert_status 1 run_migrations first [[ ! -e $marker && ! -e $test_tmp/first/1788163636.sh ]] run_migrations first [[ -f $marker && -f $test_tmp/first/1788163636.sh ]] [[ ! -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-Alice ]] enable_locked 1000 15 cp "$(rule_file 1000)" "$test_tmp/renewed" : >"$test_tmp/commands" TEST_NO_SUDO=1 run_migrations second [[ -f $test_tmp/second/1788163636.sh ]] ! grep -q '^sudo ' "$test_tmp/commands" cmp "$(rule_file 1000)" "$test_tmp/renewed" ) pass "migration completion is machine-wide, retryable, and needs no sudo for later users" ( source "$library" TEST_BAD_PATH="$marker" assert_status 1 migration_complete rm "$marker" ln -s "$test_tmp/renewed" "$marker" assert_status 1 migration_complete assert_status 1 migrate_locked [[ -L $marker ]] rm "$marker" ) pass "migration checks marker ownership and rejects symlinks" # Keep real package scripts in the contract: source and packaging share the # same lock and blocker, including the legacy scriptlet fallback. pkgs_path=${OMARCHY_PKGS_PATH:-$ROOT/../omarchy-pkgs} [[ ! -d $pkgs_path/pkgbuilds ]] || pkgs_path=$pkgs_path/pkgbuilds for name in omarchy-settings omarchy-settings-dev; do script="$pkgs_path/$name/$name.install" [[ -f $script ]] || fail "set OMARCHY_PKGS_PATH to the companion package checkout" sed -e "s|/etc/|$test_tmp/etc/|g" -e "s|/run|$test_tmp/run|g" \ -e "s|/usr/bin/stat|$test_tmp/bin/stat|g" -e "s|/usr/bin/rm|$test_tmp/bin/rm|g" \ "$script" >"$test_tmp/$name.install" reset_grant ( source "$library" source "$test_tmp/$name.install" _etc_overrides_apply() { :; } enable_locked 1000 15 TEST_DELETE_FAIL=1 assert_status 1 pre_remove [[ -e $REMOVAL_BLOCKER && -e $(rule_file 1000) ]] assert_status 1 enable_locked 1000 15 pre_remove && post_remove [[ ! -e $(rule_file 1000) ]] post_install [[ ! -e $REMOVAL_BLOCKER ]] enable_locked 1000 15 pre_upgrade && post_upgrade [[ ! -e $(rule_file 1000) && ! -e $REMOVAL_BLOCKER ]] ) done pass "both settings packages revoke grants, block publication, and recover on installation" reset_grant # Hold the source lock, then start package removal. A native flock on the # mapped file must serialize both implementations. cat >"$test_tmp/worker" <<'WORKER' #!/bin/bash set -euo pipefail source "$TEST_LIBRARY" critical() { touch "$TEST_GRANT_ROOT/entered" for (( attempt=0; attempt<500; attempt++ )); do [[ ! -e $TEST_GRANT_ROOT/release ]] || break sleep 0.01 done [[ -e $TEST_GRANT_ROOT/release ]] || return 1 enable_locked 1000 15 } with_root_lock critical WORKER TEST_LIBRARY="$library" /usr/bin/bash "$test_tmp/worker" >"$test_tmp/publisher.log" 2>&1 & publisher=$! children+=("$publisher") for (( attempt=0; attempt<200; attempt++ )); do [[ ! -e $test_tmp/entered ]] || break sleep 0.01 done [[ -f $test_tmp/entered ]] || fail "publisher failed to acquire the lock" /usr/bin/bash -euo pipefail -c 'source "$1"; pre_remove; post_remove' bash "$test_tmp/omarchy-settings.install" >"$test_tmp/removal.log" 2>&1 & removal=$! children+=("$removal") touch "$test_tmp/release" wait "$publisher" || fail "publisher failed" "$(cat "$test_tmp/publisher.log")" wait "$removal" || fail "removal failed" "$(cat "$test_tmp/removal.log")" children=() [[ ! -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-1000 ]] [[ -f $test_tmp/run/omarchy-sudo-passwordless-package-removing ]] pass "native lock serializes grant publication with package removal" # systemd-tmpfiles operates on an explicit disposable root, never the host. reset_grant : >"$test_tmp/etc/sudoers.d/99-omarchy-nopasswd-1000" : >"$test_tmp/etc/sudoers.d/unrelated" rule='r! /etc/sudoers.d/99-omarchy-nopasswd-*' /usr/bin/systemd-tmpfiles --root="$test_tmp" --remove --inline "$rule" [[ -f $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-1000 ]] || fail "routine tmpfiles shortened a live grant" /usr/bin/systemd-tmpfiles --root="$test_tmp" --remove --boot --inline "$rule" [[ ! -e $test_tmp/etc/sudoers.d/99-omarchy-nopasswd-1000 && -f $test_tmp/etc/sudoers.d/unrelated ]] || fail "boot cleanup boundary" pass "native boot cleanup removes grants while routine tmpfiles preserves them"