repository: single config/config text object (repo version 5) - #10377
Draft
ThomasWaldmann wants to merge 1 commit into
Draft
ThomasWaldmann wants to merge 1 commit into
ThomasWaldmann wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #10377 +/- ##
==========================================
- Coverage 88.12% 88.11% -0.02%
==========================================
Files 103 103
Lines 18928 18809 -119
Branches 2923 2915 -8
==========================================
- Hits 16681 16574 -107
+ Misses 1556 1550 -6
+ Partials 691 685 -6 ☔ View full report in Codecov by Harness. |
ThomasWaldmann
commented
Sep 16, 2026
ThomasWaldmann
commented
Sep 16, 2026
ThomasWaldmann
commented
Sep 16, 2026
ThomasWaldmann
commented
Sep 16, 2026
ThomasWaldmann
commented
Sep 16, 2026
ThomasWaldmann
marked this pull request as draft
September 16, 2026 04:31
…, id and manifest (repo version 5)
Opening a repository loaded four store objects: config/readme (sanity check),
config/version, config/id and config/manifest (only read for its key type
byte since the manifest lost all other content). Now there is one plain text
INI object, config/config, e.g.:
# This is a Borg Backup repository.
# See https://borgbackup.readthedocs.io/
[repository]
version = 5
id = <64 hex digits>
encryption = aes256-ocb
id_hash = sha256
The crypto suite of the key is recorded by the --encryption / --id-hash
names, so key_factory() selects the key class from the config without
reading any repository object. Both names are recorded or none; a config
with one but not the other is invalid, an unsupported suite raises
InvalidRepositoryConfig. The repository version is 5; only version 5 is
accepted, there is no code to read the old layout and no migration (betas
are for new repositories only).
The manifest object is gone for borg 2 repositories: Manifest is now only
the in-memory container for key, repo_objs, repository and archives; its
write() and all callers, get_manifest()/put_manifest(), the manifest checks
and rebuild in "borg check", "borg debug dump-manifest", the key type
detection from stored objects (key_from_repository) and the ROBJ_MANIFEST
type are removed. borg 1.x repositories are still read via their manifest
(legacy_key_factory), as it holds their archives list. NoManifestError is
kept (never raised) so that rc 26 stays reserved.
Repository.create() writes the config (version, id, no key info) right
away, so a repository created via the Python API is an openable key/value
store. "borg repo-create" alone defers it (create_config=False) and writes
the config once, last, after the key was created, so nothing that looks
like a repository exists until repo-create succeeds: any failure or
interruption before that destroys the store (and the keyfile, in keyfile
mode), and a failure inside create() destroys the store as well.
A store without repository config (only possible after a hard kill) is
reported as not a valid repository (InvalidRepository; DoesNotExist is only
for a missing store backend, the rest:// case from borgbackup#10365), repo-create on
it says what borg knows (IncompleteRepository, rc 11: no repository config,
not a borg 2 repository or the leftover of an interrupted repo-create), and
"borg repo-delete --force" destroys it if it looks like such a leftover (a
chunk index, but no packs and no archives), so that ssh/rest/s3 users can
remove it without other access to the storage. key_factory() on a config
without key info raises RepositoryKeyInfoMissing (rc 54).
The cache config's [cache]/[integrity] cross-check (manifest id) could
never detect anything and is dropped.
Docs: new "Repository config" section replaces the manifest section
(including how to recreate a lost config by hand, as check --repair can
not), the layout list, packs and security internals (where the protection
against a swapped crypto suite lives), repo-info example, error list and the
remaining manifest mentions are updated; no migration from version 4 to 5.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
ThomasWaldmann
force-pushed
the
repo-config-file
branch
from
September 16, 2026 05:40
e15ae19 to
8da9797
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #10371 .. #10374, which emptied the manifest. Opening a repository loaded four store objects:
config/readme,config/version,config/idandconfig/manifest(only read for its key type byte). Now it loads one:The config object
config/configis a plain text INI object (configparser), the readme text lives on as comment lines.encryption/id_hashrecord the crypto suite by the--encryption/--id-hashnames;key_factory()selects the key class from them without reading any repository object. Both names are recorded or none: a config with one but not the other is invalid, an unsupported suite raisesInvalidRepositoryConfig. Key storage (keyfile vs repokey) stays a property of each key.No manifest object for borg 2 repositories.
Manifestis only the in-memory container for key, repo_objs, repository and archives. Removed:write()and its callers,get_manifest()/put_manifest(), the manifest checks and rebuild inborg check,borg debug dump-manifest,key_from_repository()and theROBJ_MANIFESTtype (no stored object ever had it, borg 1.x objects carry no type at all). borg 1.x repositories are still read via their manifest (legacy_key_factory), since it holds their archives list.NoManifestErrorstays defined (never raised) so rc 26 remains reserved.repo-create leaves nothing behind when it fails.
Repository.create()writes the config (version, id, no key info) by default, so a repository created via the Python API is an openable key/value store.borg repo-createalone usescreate_config=Falseand writes the config once, last, after the key exists, so nothing that looks like a repository exists until it succeeds: any failure or interruption before that destroys the store and, in keyfile mode, the keyfile just written; a failure insidecreate()itself destroys the store as well.A store without config (only possible after a hard kill, or a repository that lost its config):
InvalidRepository);DoesNotExistis only for a missing store backend, therest://case from repo-info on a non-existent remote repo raises BackendDoesNotExist #10365;repo-createon it says what borg knows, with the newIncompleteRepositoryerror (rc 11): no repository config, so not a borg 2 repository or the leftover of an interrupted repo-create (the store backend refuses any non-empty directory, so this is all borg can tell);borg repo-delete --forcedestroys it, but only if it looks like the leftover of an interrupted repo-create (a chunk index, but no packs and no archives), so that ssh/rest/s3 users can remove a leftover without other access to the storage, and a repository that merely lost its config is never destroyed;key_factory()on a config without key info raisesRepositoryKeyInfoMissing(rc 54).Cache config: the
[cache]/[integrity]cross-check on the manifest id could never detect anything (every borg that can open the repository knows the integrity section) and is dropped, together with its warning and test.Docs: a new "Repository config" section replaces the manifest section, including how to recreate a lost config by hand (
check --repaircan not restore it); the layout list, packs (no migration from 4 to 5 either) and security internals (where the protection against a swapped crypto suite lives: the security directory and the unknown-unencrypted prompt for swaps to a non-encrypting suite, the security directory for swaps between the encrypting suites), therepo-infoexample, the error list (rc 11, 54) and the remaining manifest mentions are updated. Sphinx builds without warnings.Tests: manifest-specific tests removed; new tests for the config round trip, a store without config (open: invalid, create: incomplete,
repo-delete --force: destroyed only if a leftover), a repository that lost its config (invalid, not destroyed), bad configs (wrong version, no section, missing / invalid / half-present entries, not text),key_class_forover all creatable suites,repo-createfailing while writing the config or insidecreate()leaving neither store nor keyfile behind, and a plain data directory refused byrepo-createandrepo-delete --force.Full suite passes locally (FUSE mount tests deselected, macFUSE is unavailable on this machine).
🤖 Generated with Claude Code