Skip to content

Commit

Permalink
Add consistent snapshots to all snapshot Merkle files.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mnm678 committed Sep 29, 2020
1 parent cedde5b commit 342b58f
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
10 changes: 8 additions & 2 deletions tests/test_repository_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ def test_generate_targets_metadata(self):
def test_build_merkle_tree(self):
temporary_directory = tempfile.mkdtemp(dir=self.temporary_directory)
storage_backend = securesystemslib.storage.FilesystemBackend()
version = 1

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

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

root_1, leaves = repo_lib._build_merkle_tree(test_nodes)
repo_lib._write_merkle_paths(root_1, leaves, storage_backend,
temporary_directory)
temporary_directory, version)

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

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

test_nodes['file2'] = tuf.formats.make_metadata_fileinfo(5, None, None)
root_2, leaves = repo_lib._build_merkle_tree(test_nodes)

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

repo_lib._write_merkle_paths(root_4, leaves, storage_backend,
temporary_directory)
temporary_directory, version + 1)

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

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

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

# repo_lib.print_merkle_tree(root_4)
Expand Down
13 changes: 11 additions & 2 deletions tuf/repository_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ def _generate_and_write_metadata(rolename, metadata_filename,
tuf.roledb.update_roleinfo('timestamp', timestamp_roleinfo,
repository_name=repository_name)

_write_merkle_paths(root, leaves, storage_backend, metadata_directory)


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

if rolename == 'snapshot' and snapshot_merkle:
_write_merkle_paths(root, leaves, storage_backend, metadata_directory, metadata['version'])

if rolename in tuf.roledb.TOP_LEVEL_ROLES and not allow_partially_signed:
# Verify that the top-level 'rolename' is fully signed. Only a delegated
# role should not be written to disk without full verification of its
Expand Down Expand Up @@ -1679,7 +1681,7 @@ def _build_merkle_tree(fileinfodict):
# this path to the client for verification
return root, leaves

def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
def _write_merkle_paths(root, leaves, storage_backend, merkle_directory, version):
# The root and leaves must be part of the same fully constructed
# Merkle tree. Create a path from
# Each leaf to the root node. This path will be downloaded by
Expand Down Expand Up @@ -1729,6 +1731,13 @@ def _write_merkle_paths(root, leaves, storage_backend, merkle_directory):
file_object = tempfile.TemporaryFile()
file_object.write(file_content)
filename = os.path.join(merkle_directory, l.name + '-snapshot.json')

# Also write with consistent snapshots for auditing and client verification
consistent_filename = os.path.join(merkle_directory, str(version) + '.'
+ l.name + '-snapshot.json')
securesystemslib.util.persist_temp_file(file_object, consistent_filename,
should_close=False)

storage_backend.put(file_object, filename)
file_object.close()

Expand Down

0 comments on commit 342b58f

Please sign in to comment.