test: seal the fake PATH instead of prepending it

The old harness put .tests/fakebin at the front of $PATH, which fails OPEN: a
package manager with no fake fell through to the real one, and an audit of this
suite invoked the host's actual `brew`. The twelve one-line fakes are replaced
by a single dispatcher every fake symlinks to, plus seal.sh, which builds the
WHOLE of $PATH for a run — real binaries for the pure tools, fakes for anything
that installs, downloads or needs root, and command-not-found for everything
else. Runs go under `env -i` so they inherit nothing.

Two audits ship with it: any `have`/`find_tool` probe the seal has never heard
of is an error, and the four absolute paths find_tool probes are written to
.shadowed so a test needing a tool to be genuinely absent can say so.

The dispatcher also fails on demand (FAKE_FAIL), which is what makes the
installers' failure paths reachable at all — the apt and npm one-at-a-time
retries, note_fail, and cmd_install's non-zero exit had all been unreachable,
and all three survived being deleted outright.

_curl stands in for every remote the installer talks to and for nothing else:
an unrecognised URL is a failed download, so a typo'd host shows up as the
failure it would really be. The fzf fake records its argv, which is what makes
the picker's bindings testable.
This commit is contained in:
bcherb2
2026-08-21 22:34:30 -04:00
parent 1ea6b492eb
commit 042320208e
15 changed files with 335 additions and 43 deletions
Executable
+109
View File
@@ -0,0 +1,109 @@
#!/bin/sh
# Build a SEALED bin directory: the whole of $PATH for a run under test.
#
# sh seal.sh <dir> [--with name ...] [--without name ...]
#
# The old harness prepended .tests/fakebin to the caller's $PATH. That fails
# OPEN: a package manager with no fake here simply fell through to the real one,
# and an audit of this suite invoked the host's actual `brew`. The seal fails
# CLOSED. It holds exactly two kinds of thing --
#
# REAL pure, local, side-effect-free tools dotup is entitled to use: awk,
# sed, install, sha256sum, tar. Faking these would weaken the test;
# `sha256sum` in particular has to be the real one or the checksum
# comparison is checking a fixture against itself.
# FAKE anything that installs, downloads, or needs root. Symlinks to _fake.
#
# -- and nothing else. A tool that is neither is command-not-found, which is a
# visible failure rather than a silent hand-off to the machine.
#
# One hole cannot be closed from here and is reported rather than hidden:
# find_tool probes /usr/local/bin, /usr/local/go/bin, /home/linuxbrew/... and
# /opt/homebrew/bin by ABSOLUTE path, so on a developer box those directories
# can satisfy a lookup no matter what PATH says. The seal therefore ships a fake
# for every name that is shadowed there -- `command -v` is tried first, so the
# fake wins -- and writes the shadow list to <dir>/.shadowed so a test that
# needs a tool to be genuinely ABSENT can say so instead of quietly passing.
set -eu
# gzip is here because tar shells out to it: without it `tar xz` dies with
# "gzip: not found" -- which is the seal working, and is how it was found.
REAL='sh awk grep sed sort cut tr head tail id uname mkdir cp mv rm cat
dirname basename chmod mktemp find install sha256sum stty tar gzip ln
touch true false env expr wc'
# Deliberately NOT here by default, each for a reason a test depends on:
# sudo absent means SUDO='' and apt-get is invoked directly, which is the
# only way FAKE_FAIL=apt-get can reach the installer at all.
# fzf absent is what makes ensure_fzf actually fetch one.
# bws absent is what makes the private tier actually install it.
FAKE='curl apt-get apt-cache brew npm uv snap flatpak xcode-select
git dpkg unzip chezmoi'
OPTIONAL='sudo fzf bws nvim go node'
dir=${1:?usage: seal.sh <dir> [--with name ...] [--without name ...]}; shift
# Everything the seal KNOWS about, fixed before --without takes anything out: a
# hole punched on purpose is still an accounted-for tool, and must not trip the
# coverage audit below.
KNOWN="$REAL $FAKE $OPTIONAL"
mode=
for a in "$@"; do
case $a in
--with) mode=with ;;
--without) mode=without ;;
*) case $mode in
with) FAKE="$FAKE $a"; KNOWN="$KNOWN $a" ;;
without) FAKE=$(printf '%s\n' $FAKE | grep -vx "$a" | tr '\n' ' ') ;;
*) echo "seal.sh: stray argument $a" >&2; exit 2 ;;
esac ;;
esac
done
here=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
FB=$here/fakebin
[ -x "$FB/_fake" ] || { echo "seal.sh: no $FB/_fake" >&2; exit 1; }
rm -rf "$dir"; mkdir -p "$dir"
ln -s "$FB/_fake" "$dir/_fake"
ln -s "$FB/_curl" "$dir/_curl"
# Resolved by looking, not by `command -v`: an interactive shell reports
# aliases and functions, and a symlink to a bare name is a loop.
miss=
for t in $REAL; do
found=
for bd in /usr/bin /bin /usr/local/bin /sbin /usr/sbin; do
[ -x "$bd/$t" ] && { ln -sf "$bd/$t" "$dir/$t"; found=1; break; }
done
[ -n "$found" ] || miss="$miss $t"
done
[ -z "$miss" ] || { echo "seal.sh: host is missing real tools:$miss" >&2; exit 1; }
for t in $FAKE; do ln -sf "$dir/_fake" "$dir/$t"; done
# ------------------------------------------------------------- the audits ---
# 1. Anything dotup probes for must be accounted for. A new `have foo` with no
# fake would otherwise fall through to the host the moment someone adds one.
D=${DOTUP_SEAL_TARGET:-$here/../dot_local/bin/executable_dotup}
probes=$(grep -v '^[[:space:]]*#' "$D" \
| grep -oE '\b(have|find_tool) [a-z][a-z0-9-]*' \
| awk '{print $2}' | sort -u || :)
unknown=
for p in $probes; do
case " $KNOWN " in *" $p "*) ;; *) unknown="$unknown $p" ;; esac
done
[ -z "$unknown" ] || {
echo "seal.sh: dotup probes for tools the seal has never heard of:$unknown" >&2
echo " add them to REAL, FAKE or OPTIONAL -- do not let them fall through" >&2
exit 1; }
# 2. The absolute-path hole, reported rather than papered over. $KNOWN, not
# $FAKE: a name taken out with --without is exactly the name a test wants to
# be absent, so it is the one that most needs checking.
: > "$dir/.shadowed"
for t in $KNOWN; do
for bd in /usr/local/bin /usr/local/go/bin /home/linuxbrew/.linuxbrew/bin /opt/homebrew/bin; do
[ -x "$bd/$t" ] || continue
[ -e "$dir/$t" ] || printf '%s\t%s\n' "$t" "$bd/$t" >> "$dir/.shadowed"
done
done
printf '%s\n' "$dir"