Repository: borgbackup/borg

Issue:
manifest: move item_keys to config dict
borg2 / master only.

From the docs:

`config` is a general-purpose location for additional metadata. All versions
of Borg preserve its contents (it may have been a better place for `item_keys`,
which is not preserved by unaware Borg versions, releases predating 1.0.4).

Discussion:

Patch:
diff --git a/setup.cfg b/setup.cfg
index 327a38c7..78762794 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -159,7 +159,7 @@ per_file_ignores =
     src/borg/testsuite/__init__.py:E501,F401
     src/borg/testsuite/archive.py:E128,W504
     src/borg/testsuite/archiver/__init__.py:E128,E501,E722,F401,F405,F811
-    src/borg/testsuite/archiver/debug_cmds.py:E501
+    src/borg/testsuite/archiver/debug_cmds.py:E501,F405
     src/borg/testsuite/archiver/disk_full.py:F401,F405,F811
     src/borg/testsuite/archiver/extract_cmd.py:F405
     src/borg/testsuite/archiver/mount_cmds.py:E501,E722
diff --git a/src/borg/item.pyx b/src/borg/item.pyx
index fac6ea49..5da91c2e 100644
--- a/src/borg/item.pyx
+++ b/src/borg/item.pyx
@@ -562,7 +562,7 @@ cdef class ManifestItem(PropDict):
     archives = PropDictProperty(dict, 'dict of str -> dict')  # name -> dict
     timestamp = PropDictProperty(str)
     config = PropDictProperty(dict)
-    item_keys = PropDictProperty(tuple, 'tuple of str')
+    item_keys = PropDictProperty(tuple, 'tuple of str')  # legacy. new location is inside config.
 
     def update_internal(self, d):
         # legacy support for migration (data from old msgpacks comes in as bytes always, but sometimes we want str)
@@ -650,7 +650,7 @@ class ItemDiff:
         self._can_compare_chunk_ids = can_compare_chunk_ids
         self._chunk_1 = chunk_1
         self._chunk_2 = chunk_2
-        
+
         self._changes = {}
 
         if self._item1.is_link() or self._item2.is_link():
diff --git a/src/borg/manifest.py b/src/borg/manifest.py
index c6409f4b..189caf6a 100644
--- a/src/borg/manifest.py
+++ b/src/borg/manifest.py
@@ -264,7 +264,9 @@ def load(cls, repository, operations, key=None, force_tam_not_required=False, *,
         manifest.timestamp = m.get("timestamp")
         manifest.config = m.config
         # valid item keys are whatever is known in the repo or every key we know
-        manifest.item_keys = ITEM_KEYS | frozenset(m.get("item_keys", []))
+        manifest.item_keys = ITEM_KEYS
+        manifest.item_keys |= frozenset(m.config.get("item_keys", []))  # new location of item_keys since borg2
+        manifest.item_keys |= frozenset(m.get("item_keys", []))  # legacy: borg 1.x: item_keys not in config yet
 
         if manifest.tam_verified:
             manifest_required = manifest.config.get("tam_required", False)
@@ -321,12 +323,12 @@ def write(self):
         assert len(self.archives) <= MAX_ARCHIVES
         assert all(len(name) <= 255 for name in self.archives)
         assert len(self.item_keys) <= 100
+        self.config["item_keys"] = tuple(sorted(self.item_keys))
         manifest = ManifestItem(
-            version=1,
+            version=2,
             archives=StableDict(self.archives.get_raw_dict()),
             timestamp=self.timestamp,
             config=StableDict(self.config),
-            item_keys=tuple(sorted(self.item_keys)),
         )
         self.tam_verified = True
         data = self.key.pack_and_authenticate_metadata(manifest.as_dict())


Test patch:
diff --git a/src/borg/testsuite/archiver/debug_cmds.py b/src/borg/testsuite/archiver/debug_cmds.py
index ee22da55..6f7c251e 100644
--- a/src/borg/testsuite/archiver/debug_cmds.py
+++ b/src/borg/testsuite/archiver/debug_cmds.py
@@ -133,7 +133,8 @@ def test_debug_dump_manifest(self):
             result = json.load(f)
         assert "archives" in result
         assert "config" in result
-        assert "item_keys" in result
+        assert "item_keys" in result["config"]
+        assert frozenset(result["config"]["item_keys"]) == ITEM_KEYS
         assert "timestamp" in result
         assert "version" in result