Fix six audit findings: dead code, missing status records, missing fallback, unsafe JSON read

create_task.py:
- Remove dead make_client() call before the verify branch; it was called
  unconditionally with host=None/key=None, creating a broken client that was
  immediately discarded or overwritten.
- Remove "verify" from the dispatch dict; it was never reached through dispatch
  (the if/cmd==verify branch above it handled it). Dispatch now only contains
  commands that actually use a client.
- Wrap json.load() in try/except (OSError, JSONDecodeError) so a corrupt or
  partially-written status file produces a useful message instead of a traceback.

sitecustomize.py:
- Call _record_status() on the early-return paths in both _patch_b2 and
  _patch_restic. Without this, if TrueNAS natively supports B2 or the patch
  is already applied, the status file was never written and `verify` always
  reported failure even when everything was fine.
- Add idempotency guard to _record_status(): first call wins; duplicate calls
  for the same module are ignored so the entry count stays accurate.
- Make B2 get_restic_config a @staticmethod. The method never used self; the
  noqa comment was suppressing the evidence of a design mismatch. Removing the
  unused parameter makes the intent explicit.
- Add NamedTuple._replace() fallback after dataclasses.replace() in the restic
  wrapper. If ResticConfig is ever refactored to a NamedTuple, the TypeError
  from dataclasses.replace() would have surfaced as a backup job failure rather
  than a graceful recovery.
This commit is contained in:
2026-06-15 02:59:57 +00:00
parent 06de1e15c0
commit 4b07ce459a
2 changed files with 32 additions and 17 deletions
+17 -12
View File
@@ -92,8 +92,14 @@ def cmd_verify(_client, _args):
print(f" Expected: {_STATUS_FILE}")
sys.exit(1)
with open(_STATUS_FILE, encoding="utf-8") as fh:
status = json.load(fh)
try:
with open(_STATUS_FILE, encoding="utf-8") as fh:
status = json.load(fh)
except (OSError, json.JSONDecodeError) as exc:
print(f"Could not read status file: {exc}")
print(f" Path: {_STATUS_FILE}")
print("Try restarting middlewared to regenerate it.")
sys.exit(1)
print(f"Hook status (recorded at {status.get('patched_at', 'unknown')})")
print()
@@ -225,22 +231,21 @@ def main():
help="Create the task in a disabled state")
args = p.parse_args()
client = make_client(args.host, args.api_key, args.insecure)
if args.cmd == "verify":
cmd_verify(None, args)
return
if not args.host or not args.api_key:
p.error("--host and --api-key are required for this command")
client = make_client(args.host, args.api_key, args.insecure)
dispatch = {
"verify": cmd_verify,
"list-credentials": cmd_list_credentials,
"list-tasks": cmd_list_tasks,
"create": cmd_create,
}
if args.cmd == "verify":
cmd_verify(None, args)
else:
if not args.host or not args.api_key:
p.error("--host and --api-key are required for this command")
client = make_client(args.host, args.api_key, args.insecure)
dispatch[args.cmd](client, args)
dispatch[args.cmd](client, args)
if __name__ == "__main__":