Finish the wonderland: System told truthfully, in eight tabs instead of ten

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 23:31:52 -04:00
parent 9ffaf45a4d
commit be0e55214b
57 changed files with 5040 additions and 925 deletions
+145
View File
@@ -138,6 +138,151 @@ if not any(e['source'] == 'flatpak' for e in entries) and not any(e['source'] ==
raise SystemExit('neither source produced anything, so nothing was parsed')
" || fail 'the update history is not usable'
# ── 5. A download size is the whole download, or it is not offered ──────────
#
# dnf5 prices packages from repository metadata, flatpak renders "36.2 MB" and
# has no machine-readable column at all, and either can come back short. A
# figure that covers some of what is pending, shown as the download, understates
# it -- and understating it is the direction that costs somebody money on a
# metered connection. So the total is present only when every item was priced.
printf '%s' "$state" | python3 -c "
import json, sys
state = json.load(sys.stdin)
for name, key in ((\"dnf\", \"packages\"), (\"flatpak\", \"applications\")):
source = state.get(name, {})
items = source.get(key, [])
if \"downloadBytes\" not in source:
continue
if not items:
raise SystemExit(name + \" priced an empty list\")
unpriced = [item for item in items if \"bytes\" not in item]
if unpriced:
raise SystemExit(name + \" reports a total while items have no size\")
total = sum(int(item[\"bytes\"]) for item in items)
if int(source[\"downloadBytes\"]) != total:
raise SystemExit(name + \" totals \" + str(source[\"downloadBytes\"]) + \" for items summing to \" + str(total))
" || fail 'a reported download size does not add up to the items it is a size for'
# ── 6. A changelog is a read ────────────────────────────────────────────────
#
# This verb takes a package name from a settings page and hands it to dnf, which
# is the one place in this helper where the page names the subject. Two things
# have to hold and neither is visible from reading the happy path: the name is
# constrained before it reaches argv, and nothing on this path installs, removes
# or upgrades anything.
#
# Proved by construction rather than by inspection: dnf5, flatpak and pkexec are
# replaced with stubs that record their argv and produce nothing, so whatever
# the helper decides to run is written down and checked afterwards. A stub that
# answers nothing also exercises the honest-absence path, which is the common
# case on a machine with third-party repositories.
changelog_work="$(mktemp -d /tmp/panama-updates-changelog.XXXXXX)"
trap 'rm -rf "$changelog_work"' EXIT
changelog_bin="$changelog_work/bin"
changelog_log="$changelog_work/argv.log"
mkdir -p "$changelog_bin" "$changelog_work/cache/panama"
for tool in dnf5 flatpak fwupdmgr pkexec systemctl; do
cat >"$changelog_bin/$tool" <<EOF
#!/usr/bin/env bash
printf '%s\t%s\n' "\${0##*/}" "\$*" >>"$changelog_log"
exit 1
EOF
chmod +x "$changelog_bin/$tool"
done
run_changelog() {
PATH="$changelog_bin:$PATH" XDG_CACHE_HOME="$changelog_work/cache" "$helper" "$@"
}
: >"$changelog_log"
answer="$(run_changelog changelog dnf zsh)" || fail 'the changelog verb failed'
jq -e '.source == "dnf" and .name == "zsh" and .error == ""
and (.kind | IN("advisory", "changelog", "none"))
and (.text | type == "string")' <<<"$answer" >/dev/null \
|| fail "a changelog answered in an unusable shape: $answer"
[[ "$(jq -r .kind <<<"$answer")" == "none" ]] \
|| fail "a source that produced nothing was not reported as having no changelog: $answer"
[[ -n "$(jq -r .text <<<"$answer")" ]] \
|| fail 'a package with no changelog says nothing at all, which reads as a failure to load'
run_changelog changelog flatpak org.example.Fixture >/dev/null \
|| fail 'the flatpak changelog verb failed'
run_changelog changelog firmware FixtureDevice >/dev/null \
|| fail 'the firmware changelog verb failed'
python3 - "$changelog_log" <<'PY' || fail 'reading a changelog runs something that changes this machine'
import sys
mutating = {
"install", "remove", "erase", "upgrade", "update", "reinstall", "downgrade",
"autoremove", "distro-sync", "swap", "-y", "--assumeyes", "--noninteractive",
}
lines = [line.rstrip("\n") for line in open(sys.argv[1], encoding="utf-8") if line.strip()]
if not lines:
raise SystemExit("no commands were recorded, so this proves nothing")
for line in lines:
executable, _, arguments = line.partition("\t")
if executable == "pkexec":
raise SystemExit("a changelog asked for privilege")
for token in arguments.split():
if token in mutating:
raise SystemExit(f"{executable} was run with {token!r} while reading a changelog")
PY
# A name the machine would not have produced never reaches argv.
: >"$changelog_log"
for hostile in '../../etc/passwd' '/etc/passwd' 'zsh; rm -rf /' '' '-rf'; do
refusal="$(run_changelog changelog dnf "$hostile" 2>/dev/null)" \
|| fail "the changelog verb crashed on \"$hostile\" instead of refusing it"
[[ -n "$(jq -r '.error // ""' <<<"$refusal")" ]] \
|| fail "the changelog verb accepted the name \"$hostile\""
done
[[ ! -s "$changelog_log" ]] || fail "a refused changelog name still started a process: $(<"$changelog_log")"
[[ -n "$(run_changelog changelog nonsense zsh | jq -r '.error // ""')" ]] \
|| fail 'an unknown changelog source was accepted'
# ── 7. One application, updated by name ─────────────────────────────────────
#
# `apply flatpak` updated everything, so the only way to take one application's
# update was to take all of them -- including the 900 MB one nobody asked about.
# The per-application verb appends exactly one ID to the same command, and the
# ID is checked against the last scan rather than trusted: the page is not the
# authority on what is pending, and this is the only verb that takes a name
# from it.
printf '%s' '{"flatpak":{"available":true,"count":1,"applications":[{"id":"org.example.Fixture","version":"1.0","origin":"flathub"}]}}' \
>"$changelog_work/cache/panama/updates.json"
: >"$changelog_log"
run_changelog apply flatpak org.example.Fixture >/dev/null \
|| fail 'a per-application update failed to answer'
# Only the flatpak lines: the refusal path re-reads the snapshot afterwards,
# which asks systemctl about the two unattended-update timers.
[[ "$(grep -c $'^flatpak\t' "$changelog_log")" == "1" ]] \
|| fail "a per-application update ran flatpak more than once: $(<"$changelog_log")"
grep -Fxq "$(printf 'flatpak\tupdate -y --noninteractive org.example.Fixture')" "$changelog_log" \
|| fail "the per-application argv was not exact: $(<"$changelog_log")"
: >"$changelog_log"
refusal="$(run_changelog apply flatpak org.example.NotPending)"
[[ -n "$(jq -r '.error // ""' <<<"$refusal")" ]] \
|| fail 'an application with no pending update was accepted'
! grep -q $'^flatpak\t' "$changelog_log" \
|| fail "a refused per-application update still ran flatpak: $(<"$changelog_log")"
[[ -n "$(run_changelog apply dnf somepackage | jq -r '.error // ""')" ]] \
|| fail 'a per-item target was accepted for a source that cannot take one'
# ── 8. The service offers all three, and the stale comment is gone ──────────
for api in 'function changelogFor(source: string, name: string): var' \
'function applyFlatpakApp(id: string): void' \
'readonly property string downloadSize'; do
grep -Fq "$api" "$service" || fail "the Updates service does not expose: $api"
done
grep -Fq 'dnf-automatic is not installed' "$helper" \
&& fail 'panama-updates still says dnf-automatic is not installed, which stopped being true when set-auto-dnf landed'
grep -q 'def set_auto_dnf' "$helper" \
|| fail 'automatic package updates are reported but cannot be turned on'
printf 'updates contract: PASS (%s dnf, %s flatpak, %s firmware; reboot needed: %s)\n' \
"$(jq -r '.dnf.count // 0' <<<"$state")" \
"$(jq -r '.flatpak.count // 0' <<<"$state")" \