Skip to content

fix(backup): clean extracted data after verification failure - #3554

Closed
tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/backup-verify-temp-cleanup
Closed

tang-vu wants to merge 1 commit into
Osmantic:mainfrom
tang-vu:fix/backup-verify-temp-cleanup

Conversation

@tang-vu

@tang-vu tang-vu commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Why this matters

ods-backup.sh verify <archive>.tar.gz extracts the full backup into TMPDIR before checking its hashes. The function protected that directory with a Bash RETURN trap, but set -e exits the shell directly when sha256sum -c reports a mismatch, so the function never returns and the trap never fires. A damaged archive therefore leaves the entire extracted backup—potentially configuration and user data—on disk after verification fails.

The invariant is: archive verification must remove extracted data on every terminal path, including checksum failure.

What changed

  • isolate compressed-archive verification in a subshell
  • install an EXIT cleanup trap inside that subshell, so normal completion and set -e failure both remove the extraction directory
  • preserve the existing failure status, checksum output, archive layout, and successful verification behavior

Overlap check

Searched open and closed upstream PRs for backup archive verification, checksum-failure cleanup, verify_backup, backup temp leaks, RETURN traps, and changes to ods/ods-backup.sh. No PR covers failed archive-verification cleanup. PR #3022 changes only the full-backup model source paths in this file; PR #3066 changes update snapshot publication; PR #3541 confines restore backup IDs. None touches this function or behavior.

Regression coverage

tests/test-backup-integrity.sh now drives the public ods-backup.sh ... verify <id>.tar.gz boundary with a real archive whose payload no longer matches checksums.sha256, assigns a dedicated TMPDIR, requires a non-zero verification result, and asserts that no extracted files remain. The assertion fails on upstream main and passes with this change.

Validation

  • bash tests/test-backup-integrity.sh — passed
  • bash tests/test-backup-restore-roundtrip.sh — passed, including compressed restore
  • bash tests/test-backup-restore-cli.sh — 11 passed
  • bash tests/test-update-rollback-contract.sh — passed
  • bash -n ods/ods-backup.sh tests/test-backup-integrity.sh — passed
  • pre-commit run --files ods/ods-backup.sh ods/tests/test-backup-integrity.sh — passed
  • git diff --check — passed

make is unavailable on this Windows host; repository CI remains the full Linux validation gate.

Tradeoffs and rollback

The subshell intentionally isolates both the temporary working directory and its EXIT trap, so it cannot replace a caller trap or change the parent shell's working directory. Rollback simply restores the previous RETURN trap, but would reintroduce data retention on set -e failures.

Combined compatibility validation

Synthetic integration was validated in both relevant merge orders:

Both orders merged without conflicts. The combined backup integrity/round-trip/CLI/update rollback, preset confinement, restore-ID confinement, remote-provider CLI contracts, Bash syntax, and git diff --check all passed. The three PRs in this batch have no required merge order.

@Lightheartdevs

Copy link
Copy Markdown
Collaborator

Thanks for this contribution. We're closing outside-contributor pull requests that have had no activity for 14 days or more, so the queue reflects work that can still land. This isn't a judgment on the change itself. If it's still needed, please rebase onto main and reopen it or open a focused PR. See #7253 for details and the contribution policy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants