Browse Source

docs: What happens when a new keyfile repo is created at the same path?, fixes #6230

Also add a test.
Thomas Waldmann 3 days ago
parent
commit
80818c1588
2 changed files with 66 additions and 2 deletions
  1. 22 2
      docs/faq.rst
  2. 44 0
      src/borg/testsuite/archiver.py

+ 22 - 2
docs/faq.rst

@@ -496,8 +496,8 @@ Another option is to not consider inode numbers in the files cache by passing
 Why are backups slow on a Linux server that is a member of a Windows domain?
 Why are backups slow on a Linux server that is a member of a Windows domain?
 ----------------------------------------------------------------------------
 ----------------------------------------------------------------------------
 
 
-If a Linux server is a member of a Windows domain, username to userid resolution might be 
-performed via ``winbind`` without caching, which can slow down backups significantly. 
+If a Linux server is a member of a Windows domain, username to userid resolution might be
+performed via ``winbind`` without caching, which can slow down backups significantly.
 You can use e.g. ``nscd`` to add caching and improve the speed.
 You can use e.g. ``nscd`` to add caching and improve the speed.
 
 
 Security
 Security
@@ -554,6 +554,26 @@ The Borg config directory has content that you should take care of:
 
 
 Make sure that only you have access to the Borg config directory.
 Make sure that only you have access to the Borg config directory.
 
 
+
+Note about creating multiple keyfile repositories at the same path
+------------------------------------------------------------------
+
+If you create a new keyfile-encrypted repository at the same filesystem
+path multiple times (for example, when a previous repository at that path
+was moved away or unmounted), Borg will not overwrite or reuse the existing
+key file in your keys directory. Instead, it creates a new key file by
+appending a numeric suffix to the base name (e.g., .2, .3, ...).
+
+This means you may see multiple key files like:
+
+- ~/.config/borg/keys/home_user_backup
+- ~/.config/borg/keys/home_user_backup.2
+- ~/.config/borg/keys/home_user_backup.3
+
+Each of these corresponds to a distinct repository created at the same
+path at different times. This behavior avoids accidental key reuse or
+overwrite.
+
 .. _cache_security:
 .. _cache_security:
 
 
 Do I need to take security precautions regarding the cache?
 Do I need to take security precautions regarding the cache?

+ 44 - 0
src/borg/testsuite/archiver.py

@@ -3116,6 +3116,50 @@ class ArchiverTestCase(ArchiverTestCaseBase):
                 after = file.read()
                 after = file.read()
             assert before == after
             assert before == after
 
 
+    def test_init_keyfile_same_path_creates_new_keys(self):
+        """Regression test for GH issue #6230.
+
+        When creating a new keyfile-encrypted repository at the same filesystem path
+        multiple times (e.g., after moving/unmounting the previous one), Borg must not
+        overwrite or reuse the existing key file. Instead, it should create a new key
+        file in the keys directory, appending a numeric suffix like .2, .3, ...
+        """
+        # First init at path A
+        self.cmd('init', '--encryption=keyfile', self.repository_location)
+        keys = sorted(os.listdir(self.keys_path))
+        assert len(keys) == 1
+        base_key = keys[0]
+        base_path = os.path.join(self.keys_path, base_key)
+        with open(base_path, 'rb') as f:
+            base_contents = f.read()
+
+        # Simulate moving/unmounting the repo by changing the path and initializing again at the same path
+        # We remove the repo to allow re-init at the same path
+        shutil.rmtree(self.repository_path)
+        self.cmd('init', '--encryption=keyfile', self.repository_location)
+        keys = sorted(os.listdir(self.keys_path))
+        assert len(keys) == 2
+        assert base_key in keys
+        # The new file should be base_key suffixed with .2
+        assert any(k == base_key + '.2' for k in keys)
+        second_path = os.path.join(self.keys_path, base_key + '.2')
+        with open(second_path, 'rb') as f:
+            second_contents = f.read()
+        assert second_contents != base_contents
+
+        # Remove repo again and init a third time at same path
+        shutil.rmtree(self.repository_path)
+        self.cmd('init', '--encryption=keyfile', self.repository_location)
+        keys = sorted(os.listdir(self.keys_path))
+        assert len(keys) == 3
+        assert any(k == base_key + '.3' for k in keys)
+        third_path = os.path.join(self.keys_path, base_key + '.3')
+        with open(third_path, 'rb') as f:
+            third_contents = f.read()
+        # Ensure all keys are distinct
+        assert third_contents != base_contents
+        assert third_contents != second_contents
+
     def check_cache(self):
     def check_cache(self):
         # First run a regular borg check
         # First run a regular borg check
         self.cmd('check', self.repository_location)
         self.cmd('check', self.repository_location)