Files
skeptical-updater/tests/e2e/aur.bats
T
bryanpedini def537af58 feat(aur): list and upgrade AUR packages through paru or yay on Arch
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.
2026-10-10 15:06:18 +02:00

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")"
}