bur-cli
BUR-7Encrypt, decrypt, and store backups locally
Description
crypto.py and storage.py: the encrypt-and-write half of the pipeline. The pipefail check here is the highest-risk non-pure code in the project.
- crypto:
encrypt(stdin, recipients, out)chainsPopenso dump stdout flows intoage -r …and on to the file, and checks both return codes. Apg_dumpfailure mid-stream must fail the backup even thoughageexits 0. This is theset -o pipefailequivalent, and getting it wrong is how you end up with truncated "successful" backups.decrypt(in, identity) -> stream. Recipients are public keys; the identity is supplied only at restore and never stored. - storage:
write(app, name, stream)writes atomically (temp then rename);list(app) -> [meta]returns name, size, mtime, and parsed time, newest first;open(app, name) -> stream.
Acceptance
- a mid-stream dump failure fails the backup despite
ageexiting 0, tested with a fake command that exits non-zero mid-stream (no Postgres needed). - the output is a valid
agefile; decrypt with the matching identity reproduces the exact dump bytes. - local writes are atomic, so a crashed run never leaves a half-file that looks valid;
listreturns sizes and parsed times.
Sub-tickets
0No sub-tickets yet.
Links
No links.
Summary
src/bur/crypto.py:encryptpipes a dump process throughageto a file, and fails the backup if the dump dies mid-stream even when age exits 0.decryptreturns anage -dprocess with plaintext on stdout.src/bur/storage.py:atomic_writewrites to a temp file and renames into place once fsynced, so a crashed run never leaves a half-file.writecopies a stream through itlist_backupsreturns name/size/mtime/parsed-time newest first,open_backupreads one back.> uv run ruff check All checks passed! > uv run mypy Success: no issues found in 14 source files > uv run pytest ...................................................... [100%] 54 passed in 0.10sCode: https://github.com/jmmd2000/bur-cli/commit/b1bea626a9449e87953819951c41700ac8fe243d