SPS · log · files · refs · tags · releases · people · languages · GitHub · file
tests/test_audit_recipes.sh
7929 bytes at 2909919 · GitHub
#!/bin/sh
set -eu
case $0 in */*) test_dir=${0%/*} ;; *) test_dir=. ;; esac
project_dir=$(CDPATH= cd "$test_dir/.." 2>/dev/null && pwd) || exit 1
fail() { printf 'test_audit_recipes: %s\n' "$*" >&2; exit 1; }
tool=$project_dir/tools/audit-recipes
[ -f "$tool" ] || fail "missing $tool"
command -v python3 >/dev/null 2>&1 || fail 'python3 is required for audit-recipes'
tmp=$(mktemp -d "${TMPDIR:-/tmp}/sps-audit-test.XXXXXX") || fail mktemp
trap 'rm -rf "$tmp"' 0 HUP INT TERM
# audit-recipes never reaches the network unless --net is passed, so every
# case below is offline and deterministic.
audit() { python3 "$tool" --trees "$1" --json 2>/dev/null; }
codes() {
python3 -c '
import json, sys
doc = json.load(sys.stdin)
print(" ".join(sorted({f["code"] for f in doc["findings"]})))
'
}
# A clean tree must produce no findings and exit 0.
mkdir -p "$tmp/clean/base/alpha" "$tmp/clean/base/beta"
cat >"$tmp/clean/base/alpha/recipe" <<'EOF'
name alpha
version 1.0
release 1
arch any
description alpha: clean fixture
source https://example.org/alpha-1.0.tar.gz
hash sha256:8ed3f6ad685b959ead7022518e1af76cd816f8e8ec7ccdda1ed4018e8f2223f8
depend beta
install mkdir -p "$PKG/usr/share/alpha"
EOF
cat >"$tmp/clean/base/beta/recipe" <<'EOF'
name beta
version 2.0
release 1
arch any
description beta: clean fixture
source https://example.org/beta-2.0.tar.gz
hash sha256:f44e64e75f3948e9f73f8dfa94721c4ce8cbb4f265c4790c702b2d41cfbf2753
install mkdir -p "$PKG/usr/share/beta"
EOF
if ! python3 "$tool" --trees "$tmp/clean" >/dev/null 2>&1; then
fail 'a clean tree must exit 0'
fi
[ -z "$(audit "$tmp/clean" | codes)" ] ||
fail "clean tree reported findings: $(audit "$tmp/clean" | codes)"
# A dependency on a package no recipe provides halts a real install, so it
# must be an error rather than a warning.
mkdir -p "$tmp/missing/base/alpha"
cat >"$tmp/missing/base/alpha/recipe" <<'EOF'
name alpha
version 1.0
release 1
arch any
description alpha: missing dependency fixture
depend nosuchpackage
install mkdir -p "$PKG/usr/share/alpha"
EOF
audit "$tmp/missing" | codes | grep -q MISSING-DEPENDENCY ||
fail 'a dependency with no providing recipe must be reported'
if python3 "$tool" --trees "$tmp/missing" >/dev/null 2>&1; then
fail 'a missing dependency must make audit-recipes exit nonzero'
fi
# sget rejects a dependency cycle at install time; the audit must find it in
# the tree first.
mkdir -p "$tmp/cycle/base/one" "$tmp/cycle/base/two"
cat >"$tmp/cycle/base/one/recipe" <<'EOF'
name one
version 1.0
release 1
arch any
description one: cycle fixture
depend two
install mkdir -p "$PKG/usr/share/one"
EOF
cat >"$tmp/cycle/base/two/recipe" <<'EOF'
name two
version 1.0
release 1
arch any
description two: cycle fixture
depend one
install mkdir -p "$PKG/usr/share/two"
EOF
audit "$tmp/cycle" | codes | grep -q DEPENDENCY-CYCLE ||
fail 'a runtime dependency cycle must be reported'
# Two recipes for one name in a single repository is the duplicate src(1)
# rejects; the same name in two trees only shadows, so it is a warning.
mkdir -p "$tmp/dup/base/thing" "$tmp/dup/other/thing"
for dir in "$tmp/dup/base/thing" "$tmp/dup/other/thing"; do
cat >"$dir/recipe" <<'EOF'
name thing
version 1.0
release 1
arch any
description thing: duplicate fixture
install mkdir -p "$PKG/usr/share/thing"
EOF
done
audit "$tmp/dup" | codes | grep -q DUPLICATE-IN-REPOSITORY ||
fail 'a duplicate package name in one tree must be reported'
# Malformed metadata.
mkdir -p "$tmp/bad/base/broken"
cat >"$tmp/bad/base/broken/recipe" <<'EOF'
name broken
version 1.0
release 1
arch any
description broken: malformed fixture
homepage https://example.org/
source https://example.org/broken-1.0.tar.gz
source https://example.org/extra.patch
hash sha256:nothexatall
depend broken
install make install
EOF
bad_codes=$(audit "$tmp/bad" | codes)
for expected in UNKNOWN-KEY SOURCE-HASH-COUNT BAD-HASH-FORMAT SELF-DEPENDENCY \
INSTALL-OUTSIDE-PKG; do
case " $bad_codes " in
*" $expected "*) ;;
*) fail "expected $expected in: $bad_codes" ;;
esac
done
# A recipe whose name does not match its directory still indexes, but the
# maintainer tooling and `cd extra/CATEGORY/NAME` both key off the directory.
mkdir -p "$tmp/mismatch/base/oldname"
cat >"$tmp/mismatch/base/oldname/recipe" <<'EOF'
name newname
version 1.0
release 1
arch any
description newname: directory mismatch fixture
install mkdir -p "$PKG/usr/share/newname"
EOF
audit "$tmp/mismatch" | codes | grep -q NAME-DIR-MISMATCH ||
fail 'a recipe whose name differs from its directory must be reported'
# A recipe that reuses another package's digest for a different URL is a
# copy-paste mistake that silently builds the wrong source.
mkdir -p "$tmp/reuse/base/aaa" "$tmp/reuse/base/bbb"
cat >"$tmp/reuse/base/aaa/recipe" <<'EOF'
name aaa
version 1.0
release 1
arch any
description aaa: hash reuse fixture
source https://example.org/aaa-1.0.tar.gz
hash sha256:a4d26868017c0ccffe2efe50944ef4211834660cca834c6e9f86dec6a88246fa
install mkdir -p "$PKG/usr/share/aaa"
EOF
cat >"$tmp/reuse/base/bbb/recipe" <<'EOF'
name bbb
version 1.0
release 1
arch any
description bbb: hash reuse fixture
source https://example.org/bbb-1.0.tar.gz
hash sha256:a4d26868017c0ccffe2efe50944ef4211834660cca834c6e9f86dec6a88246fa
install mkdir -p "$PKG/usr/share/bbb"
EOF
audit "$tmp/reuse" | codes | grep -q HASH-REUSED-DIFFERENT-SOURCE ||
fail 'one digest shared by two different URLs must be reported'
# The sudo package configures --with-vardir=/var/db/sudo. That is not
# privilege escalation and must not be flagged.
mkdir -p "$tmp/sudo/base/sudo"
cat >"$tmp/sudo/base/sudo/recipe" <<'EOF'
name sudo
version 1.0
release 1
arch any
description sudo: false-positive fixture
configure ./configure --prefix=/usr --with-vardir=/var/db/sudo
install make install DESTDIR="$PKG"
EOF
if audit "$tmp/sudo" | codes | grep -q PHASE-USES-SUDO; then
fail 'the sudo package must not be flagged as using sudo'
fi
mkdir -p "$tmp/realsudo/base/thing"
cat >"$tmp/realsudo/base/thing/recipe" <<'EOF'
name thing
version 1.0
release 1
arch any
description thing: real escalation fixture
install sudo make install DESTDIR="$PKG"
EOF
audit "$tmp/realsudo" | codes | grep -q PHASE-USES-SUDO ||
fail 'a phase that actually runs sudo must be reported'
# SPS builds CPython with --with-platlibdir=lib64. A module staged under
# /usr/lib/pythonX.Y is unimportable, but naming that path in order to
# relocate it into lib64 is exactly right and must not be flagged.
mkdir -p "$tmp/pylib/base/python-bad"
cat >"$tmp/pylib/base/python-bad/recipe" <<'EOF'
name python-bad
version 1.0
release 1
arch any
description python-bad: wrong site-packages fixture
install mkdir -p "$PKG/usr/lib/python3.14/site-packages"
EOF
audit "$tmp/pylib" | codes | grep -q PYTHON-SITE-PACKAGES-LIB ||
fail 'a module staged under /usr/lib/pythonX.Y must be reported'
mkdir -p "$tmp/pyok/base/python-good"
cat >"$tmp/pyok/base/python-good/recipe" <<'EOF'
name python-good
version 1.0
release 1
arch any
description python-good: relocating fixture
install python3 -m pip install --root="$PKG" --prefix=/usr .
install if [ -d "$PKG/usr/lib/python3.14" ]; then \
cp -a "$PKG/usr/lib/python3.14/." "$PKG/usr/lib64/python3.14/"; \
rm -rf "$PKG/usr/lib/python3.14"; fi
EOF
if audit "$tmp/pyok" | codes | grep -q PYTHON-SITE-PACKAGES-LIB; then
fail 'a recipe that relocates into lib64 must not be flagged'
fi
printf '%s\n' 'audit-recipes tests passed'