#!/usr/bin/env bash # Decision 62 (Felhom R-750): a version IN USE is never in the delete plan, whatever --keep says; --keep defaults to # 20; an unreadable in-use list refuses the prune. No network, no token: the script's test seams # (PRUNE_TEST_VERSIONS, PRUNE_TEST_PROTECT) replace the registry API and the hub. Never passes --apply. # COMPANION RED-PROOF: case 2 runs the same plan with an EMPTY in-use list and must see 0.262.0 in the delete plan — # proof that case 1's pass comes from the protection and not from the fixture. set -uo pipefail HERE="$(cd "$(dirname "$0")" && pwd)"; S="$HERE/../gitea-image-prune.sh" T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT fail=0; ok() { echo "PASS $*"; }; bad() { echo "FAIL $*"; fail=1; } # 25 controller releases 0.261.0 .. 0.285.0 (oldest first), plus :latest and two digest manifests python3 - "$T/versions.json" <<'PY' import json, sys v = [{"name": "felhom-controller", "version": "0.%d.0" % n, "created_at": "2026-09-%02dT10:00:00Z" % (n - 260)} for n in range(261, 286)] v += [{"name": "felhom-controller", "version": "latest", "created_at": "2026-09-30T12:00:00Z"}, {"name": "felhom-controller", "version": "sha256:" + "a" * 64, "created_at": "2026-09-30T12:00:00Z"}] json.dump(v, open(sys.argv[1], "w")) PY printf 'felhom-controller 0.262.0 the controller floor (fixture)\n' > "$T/protect" : > "$T/empty" run() { PRUNE_TEST_VERSIONS="$T/versions.json" PRUNE_TEST_PROTECT="$1" bash "$S" --repo felhom-controller prune --no-sizes --log "$T/log" 2>&1; } # 1. default keep 20 + an OLD in-use version kept out="$(run "$T/protect")"; rc=$? plan="$(printf '%s\n' "$out" | sed -n '/Would delete/,/DRY-RUN/p')" [[ $rc -eq 0 ]] || bad "case 1 rc=$rc" printf '%s\n' "$out" | grep -q 'keep-last 20' && ok "--keep defaults to 20" || bad "--keep did not default to 20" printf '%s\n' "$out" | grep -q 'Would delete 4 tag(s); keep 20; protect 2' && ok "plan: delete 4, keep 20, protect 2 (latest + the floor)" || bad "plan counts: $(printf '%s\n' "$out" | grep 'Would delete')" printf '%s\n' "$plan" | grep -qE '^ +0\.262\.0' && bad "the in-use 0.262.0 is in the delete plan" || ok "the in-use 0.262.0 is not in the delete plan" printf '%s\n' "$out" | grep -q 'PROTECTED 0.262.0 — the controller floor (fixture)' && ok "the plan says why 0.262.0 is kept" || bad "no reason printed for 0.262.0" printf '%s\n' "$out" | grep -q 'DRY-RUN — nothing deleted' && ok "dry-run" || bad "not a dry-run" # 2. RED-PROOF: the same plan with nothing in use deletes 0.262.0 out="$(run "$T/empty")" printf '%s\n' "$out" | sed -n '/Would delete/,/DRY-RUN/p' | grep -qE '^ +0\.262\.0' && ok "red: without the in-use list 0.262.0 WOULD be deleted" || bad "red-proof: 0.262.0 not deleted even without protection — the test proves nothing" # 3. an unreadable in-use list refuses (never 'protect nothing') out="$(PRUNE_TEST_VERSIONS="$T/versions.json" HUB_PW= HUB_URL=http://127.0.0.1:9 FELHOM_EU=/nonexistent bash "$S" --repo felhom-controller prune --no-sizes --log "$T/log" 2>&1)"; rc=$? [[ $rc -eq 3 ]] && printf '%s\n' "$out" | grep -q 'REFUSING to prune' && ok "unreadable in-use list -> refused (exit 3)" || bad "case 3 rc=$rc: $(printf '%s\n' "$out" | tail -2)" exit $fail