On the pacman backend, an installed AUR helper (paru, else yay;
--aur-helper=paru|yay|none, --no-aur) adds the AUR updates to the review
list. The helper never runs as root: when the tool is root through sudo it
runs as SUDO_USER (runuser -u, else sudo -u, with that user's HOME, from
that home); unprivileged it runs as is; a root login gets no AUR, with a
warning. The banner names the helper ("+ AUR via paru").
- listing: <helper> -Qua (also with --no-refresh), rows with repository
"aur"; [ignored] is shown [held]; a failing -Qua warns and the session
goes on with the repository rows
- every row has a marker column after the number: "*" for AUR rows, a
space otherwise (on every backend)
- N?? merges pacman -Qi with <helper> -Sia; N?, N+, Nx stay with pacman;
N- excludes through the helper's --ignore
- <enter>: the repository step exactly as before, then <helper> -Sua
--ignore <excluded> as the invoking user (--noconfirm only when stdin is
not a terminal); pacman is skipped when only AUR rows are left; a helper
failure is reported and its status returned; --dry-run prints it
- other backends never run a helper; --aur-helper is ignored with a warning
paru 2.1.0 and yay 13.0.1 formats verified in discovery/pacman.md section
15 (proof: discovery/pacman/aur.sh). Unit tests replay the recorded output
(fake paru, yay, runuser, getent); the archlinux E2E run installs the
foreign su-dummy-aur and drives a fake paru through a fake sudo built on
passwordless su for wheel.
181 lines
8.2 KiB
Bash
181 lines
8.2 KiB
Bash
#!/usr/bin/env bats
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
# Copyright (C) 2026 Bryan Joshua Pedini
|
|
|
|
# E2E: AUR packages. pacman backend (archlinux): su-dummy-aur 1.0 is a foreign package (fixture
|
|
# FIXTURE_AUR=1), the fake paru (fixtures/fake-paru.sh) offers it at 2.0 and installs it through
|
|
# the fake sudo (fixtures/fake-sudo.sh: su, passwordless for wheel). The applet runs either as the
|
|
# test user su-tester, re-executing itself through that sudo, or as root with SUDO_USER=su-tester
|
|
# (what the re-exec leaves behind). Rows: [1] su-dummy-a [2]* su-dummy-aur [3] su-dummy-b
|
|
# [4] su-dummy-c. Other backends: the marker column is a space and no AUR helper ever runs.
|
|
|
|
load helpers
|
|
|
|
PARU_LOG=/tmp/su-aur-paru.log
|
|
AUR_OLD=/srv/su-aur/su-dummy-aur-1.0-1-any.pkg.tar.zst
|
|
|
|
setup_file() {
|
|
e2e_setup_file
|
|
if [[ $BE == pacman ]]; then
|
|
install -m 0755 "$BATS_TEST_DIRNAME/fixtures/fake-paru.sh" /usr/local/bin/paru
|
|
install -m 0755 "$BATS_TEST_DIRNAME/fixtures/fake-sudo.sh" /usr/local/bin/sudo
|
|
else
|
|
# a paru that only records that it ran (it never may: AUR helpers are for pacman only)
|
|
printf '#!/bin/sh\necho "$*" >>%s\n' "$PARU_LOG" >/usr/local/bin/paru
|
|
chmod 0755 /usr/local/bin/paru
|
|
fi
|
|
}
|
|
teardown_file() {
|
|
rm -f /usr/local/bin/paru "$PARU_LOG"
|
|
if [[ $BE == pacman ]]; then rm -f /usr/local/bin/sudo; fi
|
|
}
|
|
setup() {
|
|
e2e_reset
|
|
if [[ $BE == pacman ]]; then
|
|
pacman -U --noconfirm "$AUR_OLD" >/dev/null 2>&1
|
|
[[ $(pkg_ver su-dummy-aur) == 1.0 ]]
|
|
fi
|
|
: >"$PARU_LOG"
|
|
chmod 0666 "$PARU_LOG"
|
|
}
|
|
|
|
# as_tester ARGS...: run skeptical-updater as the unprivileged su-tester (its TMPDIR: the suite's
|
|
# is root's); a run that needs root re-executes itself through the fake sudo
|
|
as_tester() { runuser -u su-tester -- env TMPDIR=/tmp HOME=/home/su-tester skeptical-updater "$@"; }
|
|
pacman_only() { [[ $BE == pacman ]] || skip "pacman backend only"; }
|
|
|
|
@test "AUR: the row is listed with * and repo aur; paru ran as the invoking user after the sudo re-exec" {
|
|
pacman_only
|
|
run as_tester list
|
|
assert_success
|
|
assert_line --index 0 "Backend: pacman ($(pretty_name)) + AUR via paru"
|
|
assert_line 'Refreshing package lists... done.'
|
|
assert_line '4 upgradable, 0 trusted (hidden, use --all to show), 4 to review:'
|
|
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1 su-dummy'
|
|
assert_line ' [2]* su-dummy-aur 1.0-1 -> 2.0-1 aur'
|
|
assert_line ' [3] su-dummy-b 1.0-1 -> 2.0-1 su-dummy'
|
|
assert_line ' [4] su-dummy-c 1.0-1 -> 2.0-1 su-dummy'
|
|
run cat "$PARU_LOG"
|
|
assert_output 'su-tester HOME=/home/su-tester PWD=/home/su-tester -Qua'
|
|
}
|
|
|
|
@test "AUR: N? and N?? on the AUR row (pacman -Qi; merged with paru -Sia)" {
|
|
pacman_only
|
|
SUDO_USER=su-tester run skeptical-updater --no-refresh <<<$'2?\n2??\nq'
|
|
assert_success
|
|
assert_output --partial "$(printf '%s\n' \
|
|
'su-dummy-aur: Skeptical-updater dummy package AUR (foreign: in no repository)' \
|
|
'reason: explicitly installed' \
|
|
'required by: nothing')"
|
|
assert_line '# lines starting with > come from the upstream candidate: a differing value, or a field the installed record lacks'
|
|
assert_output --partial "$(printf '%s\n' 'Version : 1.0-1' '> Version : 2.0-1')"
|
|
assert_line 'Install Reason : Explicitly installed'
|
|
assert_line '> Repository : aur'
|
|
assert_line '> Maintainer : su-fixture'
|
|
assert_line '> AUR URL : https://aur.archlinux.org/packages/su-dummy-aur'
|
|
run grep -c 'su-tester HOME=/home/su-tester PWD=/home/su-tester -Sia su-dummy-aur' "$PARU_LOG"
|
|
assert_output 1
|
|
}
|
|
|
|
@test "AUR: N- keeps su-dummy-aur at 1.0 while the repository packages upgrade; paru is not run" {
|
|
pacman_only
|
|
SUDO_USER=su-tester run skeptical-updater <<<$'2-\n'
|
|
assert_success
|
|
assert_line 'Excluded from this run: su-dummy-aur'
|
|
assert_line 'Upgrade finished.'
|
|
[[ $(versions) == "a=2.0 b=2.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-aur) == 1.0 ]] || fail "su-dummy-aur: $(pkg_ver su-dummy-aur)"
|
|
run grep -c -- '-Sua' "$PARU_LOG"
|
|
assert_output 0
|
|
}
|
|
|
|
@test "AUR: a plain <enter> upgrades su-dummy-aur to 2.0 with paru, after the repository packages" {
|
|
pacman_only
|
|
run as_tester <<<''
|
|
assert_success
|
|
assert_line 'Excluded from this run: none'
|
|
assert_line '+ runuser -u su-tester -- env HOME=/home/su-tester paru -Sua --noconfirm'
|
|
assert_line 'Upgrade finished.'
|
|
[[ $(versions) == "a=2.0 b=2.0 c=2.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-aur) == 2.0 ]] || fail "su-dummy-aur: $(pkg_ver su-dummy-aur)"
|
|
# the repository step came first: su-dummy-a was 2.0 already when paru -Sua started
|
|
run grep -A1 -- ' -Sua --noconfirm$' "$PARU_LOG"
|
|
assert_line --index 0 'su-tester HOME=/home/su-tester PWD=/home/su-tester -Sua --noconfirm'
|
|
assert_line --index 1 ' (at -Sua: su-dummy-a 2.0-1)'
|
|
run skeptical-updater list --no-refresh --no-aur
|
|
assert_output --partial 'Nothing to upgrade.'
|
|
SUDO_USER=su-tester run skeptical-updater list --no-refresh
|
|
assert_output --partial 'Nothing to upgrade.'
|
|
}
|
|
|
|
@test "AUR: only the AUR row left to upgrade: pacman is not run, only paru" {
|
|
pacman_only
|
|
# (the files only: `..` changes with the db.lck of paru's pacman -U)
|
|
before=$(ls -l --time-style=full-iso /var/lib/pacman/sync)
|
|
SUDO_USER=su-tester run skeptical-updater <<<$'1- 3- 4-\n'
|
|
assert_success
|
|
assert_line 'No repository package to upgrade: pacman is not run, only paru.'
|
|
assert_line '+ runuser -u su-tester -- env HOME=/home/su-tester paru -Sua --noconfirm --ignore su-dummy-a,su-dummy-b,su-dummy-c'
|
|
refute_line --regexp '^\+ pacman '
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" ]] || fail "versions after the run: $(versions)"
|
|
[[ $(pkg_ver su-dummy-aur) == 2.0 ]] || fail "su-dummy-aur: $(pkg_ver su-dummy-aur)"
|
|
[[ $(ls -l --time-style=full-iso /var/lib/pacman/sync) == "$before" ]] || fail "the sync database changed although pacman was not run"
|
|
}
|
|
|
|
@test "AUR: --dry-run prints paru's command line (as the invoking user) and changes nothing" {
|
|
pacman_only
|
|
SUDO_USER=su-tester run skeptical-updater --dry-run --no-refresh <<<$'3-\n'
|
|
assert_success
|
|
assert_line '+ pacman -Su --noconfirm --ignore su-dummy-b'
|
|
assert_line '+ runuser -u su-tester -- env HOME=/home/su-tester paru -Sua --noconfirm --ignore su-dummy-b'
|
|
assert_line 'Dry run: nothing was changed.'
|
|
[[ $(versions) == "a=1.0 b=1.0 c=1.0" && $(pkg_ver su-dummy-aur) == 1.0 ]]
|
|
run grep -c -- '-Sua' "$PARU_LOG"
|
|
assert_output 0
|
|
}
|
|
|
|
@test "AUR: unprivileged list --no-refresh runs paru directly, as that user" {
|
|
pacman_only
|
|
run as_tester list --no-refresh
|
|
assert_success
|
|
assert_line ' [2]* su-dummy-aur 1.0-1 -> 2.0-1 aur'
|
|
run cat "$PARU_LOG"
|
|
assert_output --regexp '^su-tester HOME=/home/su-tester PWD=[^ ]+ -Qua$'
|
|
}
|
|
|
|
@test "AUR: a root login (no SUDO_USER): skipped with a warning, the repository rows listed, paru never run" {
|
|
pacman_only
|
|
run skeptical-updater list --no-refresh
|
|
assert_success
|
|
assert_line --index 0 "Backend: pacman ($(pretty_name))"
|
|
assert_line --index 1 'skeptical-updater: warning: aur: paru is never run as root and there is no invoking user (SUDO_USER is not set): AUR packages are neither listed nor upgraded (run skeptical-updater through sudo from your own account, or use --no-aur)'
|
|
assert_line '3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:'
|
|
refute_output --partial 'su-dummy-aur'
|
|
[[ ! -s $PARU_LOG ]]
|
|
}
|
|
|
|
@test "AUR: --no-aur lists the repository rows only and never runs paru" {
|
|
pacman_only
|
|
run as_tester --no-aur list --no-refresh
|
|
assert_success
|
|
assert_line --index 0 "Backend: pacman ($(pretty_name))"
|
|
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1 su-dummy'
|
|
refute_output --partial 'su-dummy-aur'
|
|
[[ ! -s $PARU_LOG ]]
|
|
}
|
|
|
|
@test "other backends: the marker column is a space; no AUR helper is ever run, --aur-helper is ignored" {
|
|
[[ $BE != pacman ]] || skip "not the pacman backend"
|
|
run skeptical-updater list --no-refresh
|
|
assert_success
|
|
assert_line --regexp '^ \[1\] su-dummy-a +1\.0(-1)? +-> +2\.0(-1)? +[^ ]+$'
|
|
run skeptical-updater --aur-helper=paru list --no-refresh
|
|
assert_success
|
|
assert_line "skeptical-updater: warning: --aur-helper=paru is ignored: AUR helpers only apply to the pacman backend (Arch Linux and derivatives)"
|
|
assert_line --regexp '^ \[3\] su-dummy-c '
|
|
run skeptical-updater --dry-run --no-refresh <<<''
|
|
assert_success
|
|
refute_output --partial 'paru'
|
|
[[ ! -s $PARU_LOG ]] || fail "paru ran: $(cat "$PARU_LOG")"
|
|
}
|