A flag to explicitly "save" all archives older than a certain timestamp,
and to function as a base timestamp from which to base interval
timedelta calculations. Allows for precise time interval manipulation
for superusers and as a bonus simplifies time-based testing and
alleviates the need for an external dependency to freeze time in test.
Includes some refactoring of do_prune for logical flow & naming that
came up while iterating on these changes.
Support is added for setting prune retention with either an int (keep n
archives) or an interval (keep within). This works much like
--keep-within currently does, but extends support to all retention
filters.
Additionally adds a generic --keep flag to take over (or live alongside)
both --keep-last and --keep-within. --keep-last is no longer an alias of
--keep-secondly, now keeps archives made on the same second.
Comparisons against archive timestamp are made to use local timezone
instead of UTC. Should be equal result in practice, but allows for
easier testing with frozen local time.
Accepts either int or interval, first tries parsing int then tries
parsing as interval if that fails. Returns a timedelta for easy date
math later. Now allows intervals of length 0 as a 0-length timedelta is
perfectly fine to work with.
Implement the read-only repository check by hashing pack and index
objects and comparing against the stored hashes, without writing to the
repository.
Report check progress separately for the index and for the packs, each
ending at 100%.
Port of borgbackup/borg#9790 to master.
Note: the PR's second commit (Archive.delete: don't reuse msgpack Unpacker
after an unpacking failure) does not apply here - on master Archive.delete
no longer unpacks item metadata (it just removes the archive and lets
"borg compact" reclaim space), so the reuse-after-failure code path does
not exist. The streaming RobustUnpacker already creates a fresh Unpacker
on resync.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove the dead BORG_TESTONLY_SHA256_PACK_ID tox env and CI job, fix the packs.rst pack-id docs, and reword comments/tests to describe sha256 pack naming instead of the removed shortcut.
Drop the single-chunk shortcut that reused the chunk_id as the pack_id.
A pack is now always named by sha256 of its bytes, even when it holds a
single chunk, so no code can depend on pack_id == chunk_id.
The repo-create.rst examples were not updated after --encryption was
split into --encryption + --id-hash. Use the real mode name (aes256-ocb)
and show --id-hash as an orthogonal option.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The new borgstore-based Repository inherited put(..., wait=) / delete(..., wait=)
and async_response() from the legacy RemoteRepository's pipelined RPC protocol.
In the new architecture these are dead: borgstore's API is strictly synchronous,
so put/delete ignored wait and ran synchronously, and async_response() was an
empty stub always returning None.
Remove wait and async_response() so the synchronous behavior is explicit, and
clean up every caller that still threaded wait=False / drained async_response()
(cache.add_chunk, archive.py, transfer_cmd.py, and the archive_test mock).
The legacy repository/remote keep their real wait/async implementation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NAME was only read by "borg repo-info" to show the crypto suite. Remove it from
all (current and legacy) key classes and let repo-info assemble the display from
the two real dimensions instead: "<mode>, <ENC_NAME>, <IDHASH_NAME>", e.g.
"Encrypted: Yes (repokey, aes256-ocb, sha256)" or
"Encrypted: No (repokey, authenticated, blake3)".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "you need KEY AND PASSPHRASE" warning was gated on key.NAME != "plaintext",
a brittle dependency on a human-readable display string. Use the cipher dimension
instead: only plaintext has ENC_NAME == "none"; every key-bearing suite (including
the authenticated ones, which should warn) differs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The keyfile detection used `key.NAME.startswith("key file")`, but since the
keyfile/repokey unification no key class has such a NAME, so encryption.keyfile
was never emitted (even for keyfile repos). Decide it from the key storage
(KeyBlobStorage.KEYFILE), matching the text repo-info output. Add a test.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ARG_NAME had no readers left after the JSON output switched to ENC_NAME/IDHASH_NAME,
so remove it from all (current and legacy) key classes.
Give the legacy (borg 1.x, read-only) key classes the two dimensions so that
repo-info/list --json reports a meaningful crypto suite for legacy repos instead
of null/null:
- AESCTRKey: encryption=aes256-ctr, id_hash=sha256
- Blake2AESCTRKey: encryption=aes256-ctr, id_hash=blake2
- Blake2AuthenticatedKey: encryption=authenticated, id_hash=blake2
IDHASH_NAME="blake2" is set on the ID_BLAKE2b_256 mix-in (parallel to the
ID_HMAC_SHA_256 / ID_BLAKE3_256 mix-ins). These legacy values never become CLI
choices: encryption_argument_names()/id_hash_argument_names() only iterate
AVAILABLE_KEY_TYPES, not LEGACY_KEY_TYPES.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Stop using key.ARG_NAME (the combined crypto-suite name) for the JSON output.
The "encryption" object now mirrors the split CLI options: the "mode" field is
replaced by "encryption" (cipher / AE algorithm, key.ENC_NAME) and "id_hash"
(id hash function, key.IDHASH_NAME).
This is a breaking change to the documented JSON API.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The combined --encryption value packed two orthogonal dimensions (cipher / AE
algorithm and id hash function) into a single string, causing a combinatorial
explosion of mode names. Key location was already split out into --key-location.
Now:
- --encryption selects only the cipher / AE algorithm:
none, authenticated, aes256-ocb, chacha20-poly1305
- --id-hash selects the id hash function: sha256 (default) or blake3
- --key-location (unchanged) selects key storage: repokey (default) or keyfile
The old combined names were removed (clean break): select a BLAKE3 suite via
--encryption ... --id-hash blake3 instead of blake3-*. aes-ocb was renamed to
aes256-ocb (key NAME shown by repo-info and ARG_NAME in JSON updated to match).
"none" has no key, so it only supports the sha256 id hash.
No on-disk format, key-type byte, or crypto behavior changes: the existing key
classes form a clean cross-product of {cipher} x {id-hash}, selected via the new
ENC_NAME / IDHASH_NAME class attributes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>