fix: close the four known installer bugs (DU-H1, DU-H2, BUG-1, BUG-2)

- DU-H1: flags are parsed wherever they sit, so `install --unattended`
  and `--unattended install` are the same run; any unknown flag, word,
  or subcommand exits 2 to stderr before a package manager is touched.
- DU-H2: every download lands in one private mktemp -d (mode 700)
  workdir per run, is checked non-empty before sudo tar sees it, and an
  EXIT/INT/TERM trap cleans up. No fixed /tmp paths remain.
- BUG-1: ^t is now toggle-shown — it ticks only the rows the active
  filter is showing, and @needs expansion stops at the first invasive
  row, so an invasive package can never be ticked off-screen.
- BUG-2: ^t journals what it added, so a second ^t over the same shown
  set unticks exactly that set; the bind no longer clears the query.
- lab: the type verb polls fzf's reported query to a deadline instead
  of a fixed sleep; marks_settled retries within its deadline.

Suite 256/0 host, 214/0 docker (ubuntu:24.04), mutations 24/24 killed
(six new mutants re-introduce each bug and all die), lab 6/6 green.
This commit is contained in:
bcherb2
2026-08-22 13:25:21 -04:00
parent 084fb7a730
commit 4043787a58
13 changed files with 537 additions and 58 deletions
+2 -2
View File
@@ -3,7 +3,7 @@
# kills: the tarball is extracted where the symlink points
# run: unit
<<<OLD
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf /tmp/nvim.tgz -C /opt/nvim --strip-components=1" \
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf '$WORKDIR/nvim.tgz' -C /opt/nvim --strip-components=1" \
<<<NEW
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf /tmp/nvim.tgz -C /opt/nvim-TYPO --strip-components=1" \
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf '$WORKDIR/nvim.tgz' -C /opt/nvim-TYPO --strip-components=1" \
<<<END
@@ -0,0 +1,56 @@
# what: the parser stops at the subcommand again, so flags after it are dropped
# why: DU-H1 as it shipped: `dotup install --unattended` ran a FULL ATTENDED install and said nothing, which is how invasive packages reached a machine that had asked for the safe defaults
# kills: install --unattended refuses invasive too
# run: unit
<<<OLD
CMD=
endopts=0
n=$#; i=0
while [ "$i" -lt "$n" ]; do
i=$((i + 1)); a=$1; shift
if [ "$endopts" -eq 0 ]; then
case $a in
--) endopts=1; continue ;;
--unattended) UNATTENDED=1; ASSUME_YES=1; continue ;;
--print|-n) DRYRUN=1; continue ;;
--yes|-y) ASSUME_YES=1; continue ;;
-h|--help) usage; exit 0 ;;
-?*) err "unknown flag: $a"; usage; exit 2 ;;
esac
fi
# The first bare word is the subcommand; every later one is an operand,
# rotated to the back of "$@" so the dispatch below reads them in the order
# they were typed with the flags taken out from between them.
if [ -z "$CMD" ]; then CMD=$a; else set -- "$@" "$a"; fi
done
# What each subcommand accepts. -1 is "as many as you like". An unknown
# subcommand, or one word more than a subcommand can use, is the same class of
# mistake as an unknown flag and gets the same answer: say so, and stop.
# This list and the dispatch below must name the same commands.
amin=0; amax=0
case ${CMD:-run} in
run|pick|install|private|render|expand-all|plan|preflight|fzf-path) ;;
toggle|toggle-shown|expand) amax=-1 ;;
preset|explain|resolve) amax=1 ;;
vercmp) amin=2; amax=2 ;;
*) err "unknown command: $CMD"; usage; exit 2 ;;
esac
[ "$#" -ge "$amin" ] || { err "${CMD:-run} needs $amin argument(s), got $#"; usage; exit 2; }
[ "$amax" -lt 0 ] || [ "$#" -le "$amax" ] || {
err "${CMD:-run} takes at most $amax argument(s), got $#:$(printf ' %s' "$@")"
usage; exit 2; }
<<<NEW
CMD=
while [ $# -gt 0 ]; do
case $1 in
--unattended) UNATTENDED=1; ASSUME_YES=1 ;;
--print|-n) DRYRUN=1 ;;
--yes|-y) ASSUME_YES=1 ;;
-h|--help) usage; exit 0 ;;
--*) err "unknown flag: $1"; usage; exit 2 ;;
*) CMD=$1; shift; break ;;
esac
shift
done
<<<END
@@ -0,0 +1,9 @@
# what: an unrecognised flag is skipped instead of stopping the run
# why: the other half of DU-H1 -- a parser that shrugs at `--unatended` installs a different set of packages than the operator asked for, with no way to tell
# kills: an unknown flag after the subcommand is refused
# run: unit
<<<OLD
-?*) err "unknown flag: $a"; usage; exit 2 ;;
<<<NEW
-?*) continue ;;
<<<END
@@ -0,0 +1,13 @@
# what: the neovim tarball is downloaded to and extracted from /tmp/nvim.tgz again
# why: DU-H2: a fixed name in a world-writable directory, unpacked by `sudo tar` -- anyone on the box can pre-create it as a symlink or swap it between the two commands and have tar write their content as root
# kills: no download is written to a fixed /tmp path
# run: unit
<<<OLD
run_sh "{ curl -fsSL '$b/nvim-linux-$a.tar.gz' -o '$WORKDIR/nvim.tgz' || curl -fsSL '$b/nvim-linux64.tar.gz' -o '$WORKDIR/nvim.tgz'; } && [ -s '$WORKDIR/nvim.tgz' ]" \
|| { note_fail "$key" "tarball download failed or arrived empty"; continue; }
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf '$WORKDIR/nvim.tgz' -C /opt/nvim --strip-components=1" \
<<<NEW
run_sh "curl -fsSL '$b/nvim-linux-$a.tar.gz' -o /tmp/nvim.tgz || curl -fsSL '$b/nvim-linux64.tar.gz' -o /tmp/nvim.tgz" \
|| { note_fail "$key" "tarball download failed"; continue; }
run_sh "${SUDO:+$SUDO }rm -rf /opt/nvim && ${SUDO:+$SUDO }mkdir -p /opt/nvim && ${SUDO:+$SUDO }tar -xzf /tmp/nvim.tgz -C /opt/nvim --strip-components=1" \
<<<END
@@ -0,0 +1,9 @@
# what: the EXIT trap that removes the run's private download directory is gone
# why: the directory holds whatever was fetched on the way through; leaving one behind per run turns a fix for a race into a slow leak of downloaded payloads under /tmp
# kills: …and which does not outlive the run
# run: unit
<<<OLD
trap dotup_cleanup EXIT INT TERM
<<<NEW
:
<<<END
@@ -0,0 +1,9 @@
# what: ^t's dependency walk no longer stops at an invasive row (BUG-1, reintroduced)
# why: filtering for `nvidia` and pressing ^t ticks the three docker rows off screen — a root-equivalent daemon group nobody looked at
# kills: …and the invasive group it @needs stays off
# run: unit
<<<OLD
go=$(printf '%s\n' "$shown" | expand_deps invasive-stop)
<<<NEW
go=$(printf '%s\n' "$shown" | expand_deps)
<<<END
@@ -0,0 +1,13 @@
# what: ^t's second press goes back to the reverse @needs closure instead of the journal (BUG-2, reintroduced)
# why: the reverse edges do not retract what the forward ones pulled in, so ^t ^t leaves the dependencies ticked and is not an undo
# kills: …and ^t ^t hands that back too, node included
# run: unit
<<<OLD
if [ -f "$TICK" ] && [ "$shown" = "$(sed '/^=$/,$d' "$TICK")" ]; then
go=$(sed '1,/^=$/d' "$TICK")
else
go=$(printf '%s\n' "$shown" | expand_rdeps)
fi
<<<NEW
go=$(printf '%s\n' "$shown" | expand_rdeps)
<<<END