Skip to content

Commit d869cc4

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 <mnm678@gmail.com>
1 parent 0498991 commit d869cc4

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
@@ -470,6 +470,7 @@ def test_generate_targets_metadata(self):
470470
def test_build_merkle_tree(self):
471471
temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory)
472472
storage_backend = securesystemslib.storage.FilesystemBackend()
473+
version = 1
473474

474475
# Test building the tree one node at a time to verify the hashes
475476

@@ -478,11 +479,14 @@ def test_build_merkle_tree(self):
478479

479480
root_1, leaves = repo_lib._build_merkle_tree(test_nodes)
480481
repo_lib._write_merkle_paths(root_1, leaves, storage_backend,
481-
temporary_directory)
482+
temporary_directory, version)
482483

483484
file_path = os.path.join(temporary_directory, 'file1-snapshot.json')
484485
self.assertTrue(os.path.exists(file_path))
485486

487+
file_path = os.path.join(temporary_directory, '1.file1-snapshot.json')
488+
self.assertTrue(os.path.exists(file_path))
489+
486490
test_nodes['file2'] = tuf.formats.make_metadata_fileinfo(5, None, None)
487491
root_2, leaves = repo_lib._build_merkle_tree(test_nodes)
488492

@@ -500,13 +504,15 @@ def test_build_merkle_tree(self):
500504
root_4, leaves = repo_lib._build_merkle_tree(test_nodes)
501505

502506
repo_lib._write_merkle_paths(root_4, leaves, storage_backend,
503-
temporary_directory)
507+
temporary_directory, version + 1)
504508

505509
self.assertEqual(root_4.left.digest, root_3.digest)
506510

507511
# Ensure that the paths are written to the directory
508512
file_path = os.path.join(temporary_directory, 'file1-snapshot.json')
513+
self.assertTrue(os.path.exists(file_path))
509514

515+
file_path = os.path.join(temporary_directory, '2.file1-snapshot.json')
510516
self.assertTrue(os.path.exists(file_path))
511517

512518
# 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
@@ -140,7 +140,6 @@ def _generate_and_write_metadata(rolename, metadata_filename,
140140
tuf.roledb.update_roleinfo('timestamp', timestamp_roleinfo,
141141
repository_name=repository_name)
142142

143-
_write_merkle_paths(root, leaves, storage_backend, metadata_directory)
144143

145144

146145
_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
@@ -1693,7 +1695,7 @@ def _build_merkle_tree(fileinfodict):
16931695
# this path to the client for verification
16941696
return root, leaves
16951697

1696-
def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
1698+
def _write_merkle_paths(root, leaves, storage_backend, merkle_directory, version):
16971699
# The root and leaves must be part of the same fully constructed
16981700
# Merkle tree. Create a path from
16991701
# Each leaf to the root node. This path will be downloaded by
@@ -1743,6 +1745,13 @@ def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
17431745
file_object = tempfile.TemporaryFile()
17441746
file_object.write(file_content)
17451747
filename = os.path.join(merkle_directory, l.name + '-snapshot.json')
1748+
1749+
# Also write with consistent snapshots for auditing and client verification
1750+
consistent_filename = os.path.join(merkle_directory, str(version) + '.'
1751+
+ l.name + '-snapshot.json')
1752+
securesystemslib.util.persist_temp_file(file_object, consistent_filename,
1753+
should_close=False)
1754+
17461755
storage_backend.put(file_object, filename)
17471756
file_object.close()
17481757

0 commit comments

Comments
 (0)