Skip to content

Commit 342b58f

Browse files
committed
Add consistent snapshots to all snapshot Merkle files.
In order to support third party or client auditing of Merkle trees, auditors need to be able to access previous versions of the snapshot merkle metadata (at least since the last timestamp key replacement). This commit allows this by writing snapshot Merkle files with consistent snapshots so that previous versions can be accessed. Signed-off-by: marinamoore <[email protected]>
1 parent cedde5b commit 342b58f

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

tests/test_repository_lib.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ def test_generate_targets_metadata(self):
438438
def test_build_merkle_tree(self):
439439
temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory)
440440
storage_backend = securesystemslib.storage.FilesystemBackend()
441+
version = 1
441442

442443
# Test building the tree one node at a time to verify the hashes
443444

@@ -446,11 +447,14 @@ def test_build_merkle_tree(self):
446447

447448
root_1, leaves = repo_lib._build_merkle_tree(test_nodes)
448449
repo_lib._write_merkle_paths(root_1, leaves, storage_backend,
449-
temporary_directory)
450+
temporary_directory, version)
450451

451452
file_path = os.path.join(temporary_directory, 'file1-snapshot.json')
452453
self.assertTrue(os.path.exists(file_path))
453454

455+
file_path = os.path.join(temporary_directory, '1.file1-snapshot.json')
456+
self.assertTrue(os.path.exists(file_path))
457+
454458
test_nodes['file2'] = tuf.formats.make_metadata_fileinfo(5, None, None)
455459
root_2, leaves = repo_lib._build_merkle_tree(test_nodes)
456460

@@ -468,13 +472,15 @@ def test_build_merkle_tree(self):
468472
root_4, leaves = repo_lib._build_merkle_tree(test_nodes)
469473

470474
repo_lib._write_merkle_paths(root_4, leaves, storage_backend,
471-
temporary_directory)
475+
temporary_directory, version + 1)
472476

473477
self.assertEqual(root_4.left.digest, root_3.digest)
474478

475479
# Ensure that the paths are written to the directory
476480
file_path = os.path.join(temporary_directory, 'file1-snapshot.json')
481+
self.assertTrue(os.path.exists(file_path))
477482

483+
file_path = os.path.join(temporary_directory, '2.file1-snapshot.json')
478484
self.assertTrue(os.path.exists(file_path))
479485

480486
# repo_lib.print_merkle_tree(root_4)

tuf/repository_lib.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ def _generate_and_write_metadata(rolename, metadata_filename,
146146
tuf.roledb.update_roleinfo('timestamp', timestamp_roleinfo,
147147
repository_name=repository_name)
148148

149-
_write_merkle_paths(root, leaves, storage_backend, metadata_directory)
150149

151150

152151
_log_warning_if_expires_soon(SNAPSHOT_FILENAME, roleinfo['expires'],
@@ -201,6 +200,9 @@ def _generate_and_write_metadata(rolename, metadata_filename,
201200
else:
202201
logger.debug('Not incrementing ' + repr(rolename) + '\'s version number.')
203202

203+
if rolename == 'snapshot' and snapshot_merkle:
204+
_write_merkle_paths(root, leaves, storage_backend, metadata_directory, metadata['version'])
205+
204206
if rolename in tuf.roledb.TOP_LEVEL_ROLES and not allow_partially_signed:
205207
# Verify that the top-level 'rolename' is fully signed. Only a delegated
206208
# role should not be written to disk without full verification of its
@@ -1679,7 +1681,7 @@ def _build_merkle_tree(fileinfodict):
16791681
# this path to the client for verification
16801682
return root, leaves
16811683

1682-
def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
1684+
def _write_merkle_paths(root, leaves, storage_backend, merkle_directory, version):
16831685
# The root and leaves must be part of the same fully constructed
16841686
# Merkle tree. Create a path from
16851687
# Each leaf to the root node. This path will be downloaded by
@@ -1729,6 +1731,13 @@ def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
17291731
file_object = tempfile.TemporaryFile()
17301732
file_object.write(file_content)
17311733
filename = os.path.join(merkle_directory, l.name + '-snapshot.json')
1734+
1735+
# Also write with consistent snapshots for auditing and client verification
1736+
consistent_filename = os.path.join(merkle_directory, str(version) + '.'
1737+
+ l.name + '-snapshot.json')
1738+
securesystemslib.util.persist_temp_file(file_object, consistent_filename,
1739+
should_close=False)
1740+
17321741
storage_backend.put(file_object, filename)
17331742
file_object.close()
17341743

0 commit comments

Comments
 (0)