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.
This commit is contained in:
bryanpedini committed 2026-10-10 15:06:18 +02:00
1 parent 875c8294bf
commit def537af58
39 files changed
+1903 -115

No files matched your search

+32 -32
View File
@@ -18,16 +18,16 @@ setup() { common_setup; }
FAKE_APT_SIM=real run skup list --no-refresh
assert_success
assert_line '10 upgradable, 0 trusted (hidden, use --all to show), 10 to review:'
assert_line --regexp '^ \[1\] libaudit-common +1:3\.1\.2-2\.1build1\.1 +-> +1:3\.1\.2-2\.1ubuntu0\.1 +Ubuntu:24\.04/noble-updates$'
assert_line --regexp '^ \[2\] libaudit1 +1:3\.1\.2-2\.1build1\.1 +-> +1:3\.1\.2-2\.1ubuntu0\.1 +Ubuntu:24\.04/noble-updates$'
assert_line --regexp '^ \[3\] libc6:i386 +2\.36-9 +-> +2\.36-9\+deb12u10 +Debian-Security:12/oldstable-security, Debian:12\.12/oldstable$'
assert_line --regexp '^ \[4\] libssl3t64 +3\.0\.13-0ubuntu3\.15 +-> +3\.0\.13-0ubuntu3\.16 +Ubuntu:24\.04/noble-updates, Ubuntu:24\.04/noble-security$'
assert_line --regexp '^ \[5\] perl-base +5\.36\.0-7\+deb12u3 +-> +5\.36\.0-7\+deb12u4 +http://deb\.debian\.org/debian-security bookworm-security/main amd64 \[held\]$'
assert_line --regexp '^ \[6\] su-dummy-c +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
assert_line --regexp '^ \[7\] su-dummy-e +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
assert_line --regexp '^ \[8\] su-dummy-m +1\.0 +-> +2\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[9\] su-dummy-newdep +- +-> +1\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[10\] su-dummy-slow +0\.9 +-> +1\.0$'
assert_line --regexp '^ \[1\] libaudit-common +1:3\.1\.2-2\.1build1\.1 +-> +1:3\.1\.2-2\.1ubuntu0\.1 +Ubuntu:24\.04/noble-updates$'
assert_line --regexp '^ \[2\] libaudit1 +1:3\.1\.2-2\.1build1\.1 +-> +1:3\.1\.2-2\.1ubuntu0\.1 +Ubuntu:24\.04/noble-updates$'
assert_line --regexp '^ \[3\] libc6:i386 +2\.36-9 +-> +2\.36-9\+deb12u10 +Debian-Security:12/oldstable-security, Debian:12\.12/oldstable$'
assert_line --regexp '^ \[4\] libssl3t64 +3\.0\.13-0ubuntu3\.15 +-> +3\.0\.13-0ubuntu3\.16 +Ubuntu:24\.04/noble-updates, Ubuntu:24\.04/noble-security$'
assert_line --regexp '^ \[5\] perl-base +5\.36\.0-7\+deb12u3 +-> +5\.36\.0-7\+deb12u4 +http://deb\.debian\.org/debian-security bookworm-security/main amd64 \[held\]$'
assert_line --regexp '^ \[6\] su-dummy-c +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
assert_line --regexp '^ \[7\] su-dummy-e +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
assert_line --regexp '^ \[8\] su-dummy-m +1\.0 +-> +2\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[9\] su-dummy-newdep +- +-> +1\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[10\] su-dummy-slow +0\.9 +-> +1\.0$'
refute_output --partial 'su-dummy-f'
log_has 'apt-get -s --with-new-pkgs upgrade'
log_has 'apt-cache policy perl-base su-dummy-c su-dummy-e'
@@ -36,8 +36,8 @@ setup() { common_setup; }
@test "apt: a held package from the fixture shows up with the held flag" {
FAKE_APT_SIM=held run skup list --no-refresh
assert_success
assert_line --regexp '^ \[1\] su-dummy-a +1\.0 +-> +2\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[3\] su-dummy-c +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
assert_line --regexp '^ \[1\] su-dummy-a +1\.0 +-> +2\.0 +su-fixture:su-repo$'
assert_line --regexp '^ \[3\] su-dummy-c +1\.0 +-> +2\.0 +file:/srv/su-repo \./ \[held\]$'
}
@test "apt: nothing to upgrade" {
@@ -182,10 +182,10 @@ EOF
FAKE_PACMAN_QU=real run skup list --no-refresh
assert_success
assert_line '6 upgradable, 0 trusted (hidden, use --all to show), 6 to review:'
assert_line ' [1] ca-certificates-mozilla 3.130-1 -> 3.131-1 core'
assert_line --regexp '^ \[2\] expat +2\.8\.5-1 +-> +2\.9\.0-1 +core \[held\]$'
assert_line --regexp '^ \[3\] glib2 +2\.88\.3-1 +-> +2\.90\.1-1 +core \[held\]$'
assert_line --regexp '^ \[5\] su-dummy-b +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line ' [1] ca-certificates-mozilla 3.130-1 -> 3.131-1 core'
assert_line --regexp '^ \[2\] expat +2\.8\.5-1 +-> +2\.9\.0-1 +core \[held\]$'
assert_line --regexp '^ \[3\] glib2 +2\.88\.3-1 +-> +2\.90\.1-1 +core \[held\]$'
assert_line --regexp '^ \[5\] su-dummy-b +1\.0-1 +-> +2\.0-1 +su-dummy$'
refute_output --partial 'su-dummy2'
}
@@ -194,7 +194,7 @@ EOF
FAKE_PACMAN_SL=empty run skup list --no-refresh
assert_success
assert_line '3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:'
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1'
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1'
}
@test "pacman: packages only the transaction (-Sup) shows become a note" {
@@ -361,14 +361,14 @@ EOF
run skup list --no-refresh
assert_success
assert_line '6 upgradable, 0 trusted (hidden, use --all to show), 6 to review:'
assert_line ' [1] gnutls 3.8.10-4.el9_8 -> 3.8.10-9.el9_8 baseos'
assert_line ' [1] gnutls 3.8.10-4.el9_8 -> 3.8.10-9.el9_8 baseos'
# installonly: the highest installed version is the old one
assert_line --regexp '^ \[2\] kernel-core +5\.14\.0-611\.5\.el9 +-> +5\.14\.0-612\.1\.el9 +baseos$'
assert_line --regexp '^ \[3\] su-dummy-a +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line --regexp '^ \[5\] su-dummy-c +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line --regexp '^ \[2\] kernel-core +5\.14\.0-611\.5\.el9 +-> +5\.14\.0-612\.1\.el9 +baseos$'
assert_line --regexp '^ \[3\] su-dummy-a +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line --regexp '^ \[5\] su-dummy-c +1\.0-1 +-> +2\.0-1 +su-dummy$'
# epoch kept on both sides
assert_line --regexp '^ \[6\] vim-minimal +2:8\.2\.2637-26\.el9_8\.21 +-> +2:8\.2\.2637-26\.el9_8\.23 +baseos$'
refute_line --regexp '\] su-dummy-new'
assert_line --regexp '^ \[6\] vim-minimal +2:8\.2\.2637-26\.el9_8\.21 +-> +2:8\.2\.2637-26\.el9_8\.23 +baseos$'
refute_line --regexp '\] +su-dummy-new'
refute_output --partial 'su-dummy-old'
refute_output --partial 'Obsoleting'
assert_line 'Note: the upgrade also installs (obsoleting installed packages): su-dummy-new'
@@ -390,8 +390,8 @@ EOF
FAKE_DNF_MAJOR=5 run skup list --no-refresh
assert_success
assert_line '5 upgradable, 0 trusted (hidden, use --all to show), 5 to review:'
assert_line --regexp '^ \[1\] ca-certificates +2025\.2\.80_v9\.0\.305-91\.el9 +-> +2026\.2\.90_v9\.0\.317-1\.fc44 +updates$'
assert_line --regexp '^ \[2\] curl +8\.18\.0-1\.fc44 +-> +8\.18\.0-12\.fc44 +updates$'
assert_line --regexp '^ \[1\] ca-certificates +2025\.2\.80_v9\.0\.305-91\.el9 +-> +2026\.2\.90_v9\.0\.317-1\.fc44 +updates$'
assert_line --regexp '^ \[2\] curl +8\.18\.0-1\.fc44 +-> +8\.18\.0-12\.fc44 +updates$'
refute_output --partial 'Upgrades'
}
@@ -600,10 +600,10 @@ EOF
FAKE_ZYPPER_LU=real run skup list --no-refresh
assert_success
assert_line '4 upgradable, 0 trusted (hidden, use --all to show), 4 to review:'
assert_line ' [1] openSUSE-build-key 1.0-68.1 -> 1.0-69.1 repo-update'
assert_line --regexp '^ \[2\] su-dummy-a +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line --regexp '^ \[3\] su-dummy-b +1\.0-1 +-> +2\.0-1 +openSUSE:repo-oss & co$'
assert_line --regexp '^ \[4\] su-dummy-c +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line ' [1] openSUSE-build-key 1.0-68.1 -> 1.0-69.1 repo-update'
assert_line --regexp '^ \[2\] su-dummy-a +1\.0-1 +-> +2\.0-1 +su-dummy$'
assert_line --regexp '^ \[3\] su-dummy-b +1\.0-1 +-> +2\.0-1 +openSUSE:repo-oss & co$'
assert_line --regexp '^ \[4\] su-dummy-c +1\.0-1 +-> +2\.0-1 +su-dummy$'
log_has 'zypper --non-interactive --xmlout list-updates'
}
@@ -615,7 +615,7 @@ EOF
log_has 'zypper --non-interactive --no-refresh --xmlout dist-upgrade --dry-run'
log_lacks 'list-updates'
assert_line '3 upgradable, 0 trusted (hidden, use --all to show), 3 to review:'
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1 su-dummy'
assert_line ' [1] su-dummy-a 1.0-1 -> 2.0-1 su-dummy'
refute_output --partial 'openSUSE-release'
}
@@ -624,7 +624,7 @@ EOF
export SKEPTICAL_UPDATER_OS_RELEASE=$FAKE_DATA/os-release-tumbleweed
FAKE_ZYPPER_DUP=removes run skup list --no-refresh
assert_success
assert_line ' [2] su-dummy-newdep - -> 1.0-1 su-dummy'
assert_line ' [2] su-dummy-newdep - -> 1.0-1 su-dummy'
assert_line 'Note: the dist-upgrade also removes: libcurl-mini4'
}
@@ -734,7 +734,7 @@ EOF
export SKEPTICAL_UPDATER_OS_RELEASE=$FAKE_DATA/os-release-tumbleweed
FAKE_ZYPPER_DUP=removes run skup --no-refresh <<<$'2?\nq'
assert_success
assert_line ' [2] su-dummy-newdep - -> 1.0-1 su-dummy'
assert_line ' [2] su-dummy-newdep - -> 1.0-1 su-dummy'
assert_line 'reason: not installed'
assert_line 'required by: nothing'
log_lacks 'zypper --non-interactive --no-refresh --quiet info su-dummy-newdep'