Audit fixes: a compat verdict must never be able to brick a working box
CI / shell (shellcheck + syntax) (push) Successful in 8s
CI / python 3.11 (push) Successful in 12s
CI / python 3.12 (push) Successful in 14s
CI / python 3.13 (push) Successful in 13s
TrueNAS compatibility / compat (push) Successful in 38s

The audit found the new machinery could do more harm than the bugs it prevents.

- apply.sh reused the 'nothing left to do' exit -- which touches the PERMANENT
  kill switch, cleared only by install.sh, never by update.sh -- for the
  incompatible case. On TrueNAS 26 (providers ok, nested opt-out) both modules go
  quiet, so the switch would fire and the release that fixed 26 could never
  re-enable itself. Retirement and incompatibility now take different exits.
- A network blip, a re-export, or a conditional def all read as BROKEN. Each is
  now 'unknown', which changes nothing, rather than evidence strong enough to
  disable a module.
- 'native' outranked BROKEN everywhere but apply.sh, so a TrueNAS that reworded
  the guard AND reshaped the functions rendered as good news.
- compat.py --tree read B2_BLOCK's own 'restic = True' as native support, so the
  documented way to check a live box lied on every patched machine.
- The signature check was a name-subset test. It passed reorders, kw-only
  conversions, and added required params -- and it had already passed a real bug:
  restic_backup takes 4 args on 24.10/25.04, and the wrapper forwarded 5. Nested
  backups have been raising TypeError on those releases the whole time. The
  wrapper now forwards *args/**kwargs.
- release.sh --promote was unreachable: it died if the tag existed, the gate died
  if it did not. The tests hid it by always tagging first.
This commit is contained in:
2026-07-13 17:58:15 +00:00
parent f927773f81
commit ea090c7f72
10 changed files with 773 additions and 100 deletions
+4 -3
View File
@@ -84,12 +84,13 @@ jobs:
broken = [
r for r in rows
if any(not m["ok"] and not m["native"] for m in r["modules"].values())
if any(compat.is_broken(m) for m in r["modules"].values())
]
native = [
(r["ref"], mod)
for r in rows
for mod, m in sorted(r["modules"].items()) if m["native"]
for mod, m in sorted(r["modules"].items())
if m["native"] and not compat.is_broken(m)
]
lines = [
@@ -103,7 +104,7 @@ jobs:
lines.append(f"### {r['ref']}")
lines.append("")
for mod, m in sorted(r["modules"].items()):
if m["ok"] or m["native"]:
if not compat.is_broken(m):
continue
lines.append(f"**{mod}** — the patch will not apply:")
lines.append("")