mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge branch 'repository-tools' of github.com:theupdateframework/tuf into developer-tools
This commit is contained in:
commit
5d641ef4db
28 changed files with 506 additions and 496 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 86 KiB |
|
|
@ -792,7 +792,7 @@
|
|||
it is updated. In the next subsection, we will see how clients will
|
||||
reproduce the name of the intended file.
|
||||
|
||||
Finally, the root metadata should write the Boolean "consistent_snapshots"
|
||||
Finally, the root metadata should write the Boolean "consistent_snapshot"
|
||||
attribute at the root level of its keys of attributes. If consistent
|
||||
snapshots are not written by the repository, then the attribute may either
|
||||
be left unspecified or be set to the False value. Otherwise, it must be
|
||||
|
|
@ -807,7 +807,7 @@
|
|||
snapshot.
|
||||
|
||||
If the root metadata (root.txt) is either missing the Boolean
|
||||
"consistent_snapshots" attribute or the attribute is set to False, then the
|
||||
"consistent_snapshot" attribute or the attribute is set to False, then the
|
||||
client should do nothing different from the workflow in Section 5.1.
|
||||
|
||||
Otherwise, the client must perform as follows:
|
||||
|
|
|
|||
|
|
@ -181,8 +181,8 @@ def test_arbitrary_package_attack(using_tuf=False, modify_metadata=False):
|
|||
try:
|
||||
test_arbitrary_package_attack(using_tuf=True, modify_metadata=False)
|
||||
except ArbitraryPackageAlert, error:
|
||||
>>>>>>> develop
|
||||
print(error)
|
||||
|
||||
else:
|
||||
print('Extraneous dependency attack failed.')
|
||||
print()
|
||||
|
|
|
|||
|
|
@ -21,10 +21,8 @@
|
|||
<Purpose>
|
||||
Run all the unit tests from every .py file beginning with "test_" in
|
||||
'tuf/tests'. Use --random to run the tests in random order.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
import glob
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
<Purpose>
|
||||
Unit test for 'formats.py'
|
||||
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
|
@ -108,7 +107,7 @@ def test_schemas(self):
|
|||
'custom': {'type': 'paintjob'}}),
|
||||
|
||||
'FILEDICT_SCHEMA': (tuf.formats.FILEDICT_SCHEMA,
|
||||
{'metadata/root.txt': {'length': 1024,
|
||||
{'metadata/root.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}),
|
||||
|
||||
|
|
@ -156,7 +155,7 @@ def test_schemas(self):
|
|||
|
||||
'SCPCONFIG_SCHEMA': (tuf.formats.SCPCONFIG_SCHEMA,
|
||||
{'general': {'transfer_module': 'scp',
|
||||
'metadata_path': '/path/meta.txt',
|
||||
'metadata_path': '/path/meta.json',
|
||||
'targets_directory': '/targets'},
|
||||
'scp': {'host': 'http://localhost:8001',
|
||||
'user': 'McFly',
|
||||
|
|
@ -184,6 +183,7 @@ def test_schemas(self):
|
|||
'ROOT_SCHEMA': (tuf.formats.ROOT_SCHEMA,
|
||||
{'_type': 'Root',
|
||||
'version': 8,
|
||||
'consistent_snapshot': False,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'keys': {'123abc': {'keytype': 'rsa',
|
||||
'keyval': {'public': 'pubkey',
|
||||
|
|
@ -196,7 +196,7 @@ def test_schemas(self):
|
|||
{'_type': 'Targets',
|
||||
'version': 8,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'targets': {'metadata/targets.txt': {'length': 1024,
|
||||
'targets': {'metadata/targets.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}},
|
||||
'delegations': {'keys': {'123abc': {'keytype':'rsa',
|
||||
|
|
@ -206,11 +206,11 @@ def test_schemas(self):
|
|||
'threshold': 1,
|
||||
'paths': ['path1/', 'path2']}]}}),
|
||||
|
||||
'RELEASE_SCHEMA': (tuf.formats.RELEASE_SCHEMA,
|
||||
{'_type': 'Release',
|
||||
'SNAPSHOT_SCHEMA': (tuf.formats.SNAPSHOT_SCHEMA,
|
||||
{'_type': 'Snapshot',
|
||||
'version': 8,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'meta': {'metadata/release.txt': {'length': 1024,
|
||||
'meta': {'metadata/snapshot.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}}),
|
||||
|
||||
|
|
@ -218,7 +218,7 @@ def test_schemas(self):
|
|||
{'_type': 'Timestamp',
|
||||
'version': 8,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'meta': {'metadata/timestamp.txt': {'length': 1024,
|
||||
'meta': {'metadata/timestamp.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}}),
|
||||
|
||||
|
|
@ -246,8 +246,8 @@ def test_schemas(self):
|
|||
'confined_target_dirs': ['path1/', 'path2/'],
|
||||
'custom': {'type': 'mirror'}}]})}
|
||||
|
||||
# Iterate through 'valid_schemas', ensuring each 'valid_schema' correctly
|
||||
# matches its respective 'schema_type'.
|
||||
# Iterate 'valid_schemas', ensuring each 'valid_schema' correctly matches
|
||||
# its respective 'schema_type'.
|
||||
for schema_name, (schema_type, valid_schema) in valid_schemas.items():
|
||||
self.assertEqual(True, schema_type.matches(valid_schema))
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ def test_TimestampFile(self):
|
|||
# Test conditions for valid instances of 'tuf.formats.TimestampFile'.
|
||||
version = 8
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
filedict = {'metadata/timestamp.txt': {'length': 1024,
|
||||
filedict = {'metadata/timestamp.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}
|
||||
|
||||
|
|
@ -322,7 +322,8 @@ def test_TimestampFile(self):
|
|||
def test_RootFile(self):
|
||||
# Test conditions for valid instances of 'tuf.formats.RootFile'.
|
||||
version = 8
|
||||
expiration_seconds = 691200
|
||||
consistent_snapshot = False
|
||||
expires = '2018-10-16 06:42:12 UTC'
|
||||
keydict = {'123abc': {'keytype': 'rsa',
|
||||
'keyval': {'public': 'pubkey',
|
||||
'private': 'privkey'}}}
|
||||
|
|
@ -335,50 +336,56 @@ def test_RootFile(self):
|
|||
from_metadata = tuf.formats.RootFile.from_metadata
|
||||
ROOT_SCHEMA = tuf.formats.ROOT_SCHEMA
|
||||
|
||||
self.assertTrue(ROOT_SCHEMA.matches(make_metadata(version, expiration_seconds,
|
||||
keydict, roledict)))
|
||||
metadata = make_metadata(version, expiration_seconds, keydict, roledict,)
|
||||
self.assertTrue(ROOT_SCHEMA.matches(make_metadata(version, expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)))
|
||||
metadata = make_metadata(version, expires, keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertTrue(isinstance(from_metadata(metadata), tuf.formats.RootFile))
|
||||
|
||||
# Test conditions for invalid arguments.
|
||||
bad_version = '8'
|
||||
bad_expiration_seconds = 'eight'
|
||||
bad_expires = 'eight'
|
||||
bad_keydict = 123
|
||||
bad_roledict = 123
|
||||
|
||||
self.assertRaises(tuf.FormatError, make_metadata, bad_version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertRaises(tuf.FormatError, make_metadata, version,
|
||||
bad_expiration_seconds,
|
||||
keydict, roledict)
|
||||
bad_expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertRaises(tuf.FormatError, make_metadata, version,
|
||||
expiration_seconds,
|
||||
bad_keydict, roledict)
|
||||
expires,
|
||||
bad_keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertRaises(tuf.FormatError, make_metadata, version,
|
||||
expiration_seconds,
|
||||
keydict, bad_roledict)
|
||||
expires,
|
||||
keydict, bad_roledict,
|
||||
consistent_snapshot)
|
||||
|
||||
self.assertRaises(tuf.FormatError, from_metadata, 'bad')
|
||||
|
||||
|
||||
|
||||
def test_ReleaseFile(self):
|
||||
# Test conditions for valid instances of 'tuf.formats.ReleaseFile'.
|
||||
def test_SnapshotFile(self):
|
||||
# Test conditions for valid instances of 'tuf.formats.SnapshotFile'.
|
||||
version = 8
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
filedict = {'metadata/release.txt': {'length': 1024,
|
||||
filedict = {'metadata/snapshot.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}
|
||||
|
||||
make_metadata = tuf.formats.ReleaseFile.make_metadata
|
||||
from_metadata = tuf.formats.ReleaseFile.from_metadata
|
||||
RELEASE_SCHEMA = tuf.formats.RELEASE_SCHEMA
|
||||
make_metadata = tuf.formats.SnapshotFile.make_metadata
|
||||
from_metadata = tuf.formats.SnapshotFile.from_metadata
|
||||
SNAPSHOT_SCHEMA = tuf.formats.SNAPSHOT_SCHEMA
|
||||
|
||||
self.assertTrue(RELEASE_SCHEMA.matches(make_metadata(version, expires,
|
||||
self.assertTrue(SNAPSHOT_SCHEMA.matches(make_metadata(version, expires,
|
||||
filedict)))
|
||||
metadata = make_metadata(version, expires, filedict)
|
||||
self.assertTrue(isinstance(from_metadata(metadata), tuf.formats.ReleaseFile))
|
||||
self.assertTrue(isinstance(from_metadata(metadata), tuf.formats.SnapshotFile))
|
||||
|
||||
# Test conditions for invalid arguments.
|
||||
bad_version = '8'
|
||||
|
|
@ -399,7 +406,7 @@ def test_TargetsFile(self):
|
|||
# Test conditions for valid instances of 'tuf.formats.TargetsFile'.
|
||||
version = 8
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
filedict = {'metadata/targets.txt': {'length': 1024,
|
||||
filedict = {'metadata/targets.json': {'length': 1024,
|
||||
'hashes': {'sha256': 'ABCD123'},
|
||||
'custom': {'type': 'metadata'}}}
|
||||
|
||||
|
|
@ -490,6 +497,7 @@ def test_make_signable(self):
|
|||
# Test conditions for expected make_signable() behavior.
|
||||
root = {'_type': 'Root',
|
||||
'version': 8,
|
||||
'consistent_snapshot': False,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'keys': {'123abc': {'keytype': 'rsa',
|
||||
'keyval': {'public': 'pubkey',
|
||||
|
|
@ -580,7 +588,7 @@ def test_get_role_class(self):
|
|||
|
||||
self.assertEqual(tuf.formats.RootFile, get_role_class('Root'))
|
||||
self.assertEqual(tuf.formats.TargetsFile, get_role_class('Targets'))
|
||||
self.assertEqual(tuf.formats.ReleaseFile, get_role_class('Release'))
|
||||
self.assertEqual(tuf.formats.SnapshotFile, get_role_class('Snapshot'))
|
||||
self.assertEqual(tuf.formats.TimestampFile, get_role_class('Timestamp'))
|
||||
self.assertEqual(tuf.formats.MirrorsFile, get_role_class('Mirrors'))
|
||||
|
||||
|
|
@ -599,7 +607,7 @@ def test_expected_meta_rolename(self):
|
|||
|
||||
self.assertEqual('Root', expected_rolename('root'))
|
||||
self.assertEqual('Targets', expected_rolename('targets'))
|
||||
self.assertEqual('Release', expected_rolename('release'))
|
||||
self.assertEqual('Snapshot', expected_rolename('snapshot'))
|
||||
self.assertEqual('Timestamp', expected_rolename('timestamp'))
|
||||
self.assertEqual('Mirrors', expected_rolename('mirrors'))
|
||||
self.assertEqual('Targets Role', expected_rolename('targets role'))
|
||||
|
|
@ -616,6 +624,7 @@ def test_check_signable_object_format(self):
|
|||
# Test condition for a valid argument.
|
||||
root = {'_type': 'Root',
|
||||
'version': 8,
|
||||
'consistent_snapshot': False,
|
||||
'expires': '2012-10-16 06:42:12 UTC',
|
||||
'keys': {'123abc': {'keytype': 'rsa',
|
||||
'keyval': {'public': 'pubkey',
|
||||
|
|
|
|||
|
|
@ -170,11 +170,13 @@ def test_create_keydb_from_root_metadata(self):
|
|||
roledict = {'Root': {'keyids': [keyid], 'threshold': 1},
|
||||
'Targets': {'keyids': [keyid2], 'threshold': 1}}
|
||||
version = 8
|
||||
expiration_seconds = 200
|
||||
consistent_snapshot = False
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertEqual(None, tuf.keydb.create_keydb_from_root_metadata(root_metadata))
|
||||
# Ensure 'keyid' and 'keyid2' were added to the keydb database.
|
||||
self.assertEqual(rsakey, tuf.keydb.get_key(keyid))
|
||||
|
|
@ -206,11 +208,12 @@ def test_create_keydb_from_root_metadata(self):
|
|||
rsakey3['keytype'] = 'bad_keytype'
|
||||
keydict[keyid3] = rsakey3
|
||||
version = 8
|
||||
expiration_seconds = 200
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertEqual(None, tuf.keydb.create_keydb_from_root_metadata(root_metadata))
|
||||
|
||||
# Ensure only 'keyid2' was added to the keydb database. 'keyid' and
|
||||
|
|
|
|||
|
|
@ -319,11 +319,13 @@ def test_create_roledb_from_root_metadata(self):
|
|||
roledict = {'root': {'keyids': [keyid], 'threshold': 1},
|
||||
'targets': {'keyids': [keyid2], 'threshold': 1}}
|
||||
version = 8
|
||||
expiration_seconds = 200
|
||||
consistent_snapshot = False
|
||||
expires = '2012-10-16 06:42:12 UTC'
|
||||
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertEqual(None,
|
||||
tuf.roledb.create_roledb_from_root_metadata(root_metadata))
|
||||
# Ensure 'Root' and 'Targets' were added to the role database.
|
||||
|
|
@ -354,22 +356,23 @@ def test_create_roledb_from_root_metadata(self):
|
|||
'targets/role1': {'keyids': [keyid2], 'threshold': 1},
|
||||
'release': {'keyids': [keyid3], 'threshold': 1}}
|
||||
version = 8
|
||||
expiration_seconds = 200
|
||||
|
||||
# Add a third key for 'release'.
|
||||
keydict[keyid3] = rsakey3
|
||||
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertRaises(tuf.Error,
|
||||
tuf.roledb.create_roledb_from_root_metadata, root_metadata)
|
||||
# Remove the invalid role and re-generate 'root_metadata' to test for the
|
||||
# other two roles.
|
||||
del roledict['targets/role1']
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version,
|
||||
expiration_seconds,
|
||||
keydict, roledict)
|
||||
expires,
|
||||
keydict, roledict,
|
||||
consistent_snapshot)
|
||||
self.assertEqual(None,
|
||||
tuf.roledb.create_roledb_from_root_metadata(root_metadata))
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
unittest_toolbox module was created to provide additional testing tools for
|
||||
tuf's modules. For more info see unittest_toolbox.py.
|
||||
|
||||
|
||||
<Methodology>
|
||||
Unit tests must follow a specific structure i.e. independent methods should
|
||||
be tested prior to dependent methods. More accurately: least dependent
|
||||
|
|
@ -32,7 +31,6 @@ class guarantees the order of unit tests. So that, 'test_something_A'
|
|||
a number will be placed after 'test' and before methods name like so:
|
||||
'test_1_check_directory'. The number is a measure of dependence, where 1
|
||||
is less dependent than 2.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
|
@ -51,7 +49,7 @@ class guarantees the order of unit tests. So that, 'test_something_A'
|
|||
import tuf.formats
|
||||
import tuf.keydb
|
||||
import tuf.repo.keystore as keystore
|
||||
import tuf.repo.signerlib as signerlib
|
||||
import tuf.repository_tool as repo_tool
|
||||
import tuf.roledb
|
||||
import tuf.tests.repository_setup as setup
|
||||
import tuf.tests.unittest_toolbox as unittest_toolbox
|
||||
|
|
@ -108,7 +106,7 @@ def test__init__exceptions(self):
|
|||
for directory, junk, role_list in os.walk(client_current_dir):
|
||||
for role_filepath in role_list:
|
||||
role_filepath = os.path.join(directory, role_filepath)
|
||||
if role_filepath.endswith('root.txt'):
|
||||
if role_filepath.endswith('root.json'):
|
||||
continue
|
||||
os.remove(role_filepath)
|
||||
updater.Updater('Repo_Name', self.mirrors)
|
||||
|
|
@ -134,18 +132,18 @@ def setUpClass(cls):
|
|||
# Server side references.
|
||||
cls.server_repo_dir = cls.repositories['server_repository']
|
||||
cls.server_meta_dir = os.path.join(cls.server_repo_dir, 'metadata')
|
||||
cls.root_filepath = os.path.join(cls.server_meta_dir, 'root.txt')
|
||||
cls.timestamp_filepath = os.path.join(cls.server_meta_dir, 'timestamp.txt')
|
||||
cls.targets_filepath = os.path.join(cls.server_meta_dir, 'targets.txt')
|
||||
cls.release_filepath = os.path.join(cls.server_meta_dir, 'release.txt')
|
||||
cls.root_filepath = os.path.join(cls.server_meta_dir, 'root.json')
|
||||
cls.timestamp_filepath = os.path.join(cls.server_meta_dir, 'timestamp.json')
|
||||
cls.targets_filepath = os.path.join(cls.server_meta_dir, 'targets.json')
|
||||
cls.snapshot_filepath = os.path.join(cls.server_meta_dir, 'snapshot.json')
|
||||
|
||||
# References to delegated metadata paths and directories.
|
||||
cls.delegated_dir1 = os.path.join(cls.server_meta_dir, 'targets')
|
||||
cls.delegated_filepath1 = os.path.join(cls.delegated_dir1,
|
||||
'delegated_role1.txt')
|
||||
'delegated_role1.json')
|
||||
cls.delegated_dir2 = os.path.join(cls.delegated_dir1, 'delegated_role1')
|
||||
cls.delegated_filepath2 = os.path.join(cls.delegated_dir2,
|
||||
'delegated_role2.txt')
|
||||
'delegated_role2.json')
|
||||
cls.targets_dir = os.path.join(cls.server_repo_dir, 'targets')
|
||||
|
||||
# Client side references.
|
||||
|
|
@ -172,7 +170,7 @@ def setUp(self):
|
|||
# used as an optional argument to 'download_url_to_tempfileobj' patch
|
||||
# function.
|
||||
self.all_role_paths = [self.timestamp_filepath,
|
||||
self.release_filepath,
|
||||
self.snapshot_filepath,
|
||||
self.root_filepath,
|
||||
self.targets_filepath,
|
||||
self.delegated_filepath1,
|
||||
|
|
@ -248,7 +246,7 @@ def _remove_filepath(self, filepath):
|
|||
def _add_target_to_targets_dir(self, targets_keyids):
|
||||
"""
|
||||
Adds a file to server's 'targets' directory and rebuilds
|
||||
targets metadata (targets.txt).
|
||||
targets metadata (targets.json).
|
||||
"""
|
||||
|
||||
targets_sub_dir = os.path.join(self.targets_dir, 'targets_sub_dir')
|
||||
|
|
@ -274,7 +272,7 @@ def _add_target_to_targets_dir(self, targets_keyids):
|
|||
def _remove_target_from_targets_dir(self, target_filename, remove_all=True):
|
||||
"""
|
||||
Remove a target 'target_filename' from server's targets directory and
|
||||
rebuild 'targets', 'release', 'timestamp' metadata files.
|
||||
rebuild 'targets', 'snapshot', 'timestamp' metadata files.
|
||||
'target_filename' is relative to targets directory.
|
||||
Example of 'target_filename': 'targets_sub_dir/somefile.txt'.
|
||||
|
||||
|
|
@ -345,8 +343,8 @@ def _update_top_level_roles(self):
|
|||
# Reference self.Repository._update_metadata_if_changed().
|
||||
update_if_changed = self.Repository._update_metadata_if_changed
|
||||
|
||||
self._mock_download_url_to_tempfileobj(self.release_filepath)
|
||||
update_if_changed('release', referenced_metadata = 'timestamp')
|
||||
self._mock_download_url_to_tempfileobj(self.snapshot_filepath)
|
||||
update_if_changed('snapshot', referenced_metadata = 'timestamp')
|
||||
|
||||
self._mock_download_url_to_tempfileobj(self.root_filepath)
|
||||
update_if_changed('root')
|
||||
|
|
@ -363,9 +361,9 @@ def _update_top_level_roles(self):
|
|||
def test_1__load_metadata_from_file(self):
|
||||
|
||||
# Setup
|
||||
# Get root.txt file path. Extract root metadata,
|
||||
# Get root.json file path. Extract root metadata,
|
||||
# it will be compared with content of loaded root metadata.
|
||||
root_filepath = os.path.join(self.client_current_dir, 'root.txt')
|
||||
root_filepath = os.path.join(self.client_current_dir, 'root.json')
|
||||
root_meta = tuf.util.load_json_file(root_filepath)
|
||||
|
||||
|
||||
|
|
@ -414,16 +412,16 @@ def test_1__update_fileinfo(self):
|
|||
# Load file info for top level roles. This populates the fileinfo
|
||||
# dictionary.
|
||||
for role in self.role_list:
|
||||
self.Repository._update_fileinfo(role+'.txt')
|
||||
self.Repository._update_fileinfo(role+'.json')
|
||||
|
||||
# Verify that fileinfo has been populated and contains appropriate data.
|
||||
self.assertTrue(self.Repository.fileinfo)
|
||||
for role in self.role_list:
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.txt')
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.json')
|
||||
role_info = tuf.util.get_file_details(role_filepath)
|
||||
role_info_dict = {'length':role_info[0], 'hashes':role_info[1]}
|
||||
self.assertTrue(role+'.txt' in self.Repository.fileinfo.keys())
|
||||
self.assertEqual(self.Repository.fileinfo[role+'.txt'], role_info_dict)
|
||||
self.assertTrue(role+'.json' in self.Repository.fileinfo.keys())
|
||||
self.assertEqual(self.Repository.fileinfo[role+'.json'], role_info_dict)
|
||||
|
||||
|
||||
|
||||
|
|
@ -477,7 +475,7 @@ def test_2__ensure_all_targets_allowed(self):
|
|||
targets_meta_dir = os.path.join(self.server_meta_dir, 'targets')
|
||||
role1_meta_dir = os.path.join(targets_meta_dir, 'delegated_role1')
|
||||
|
||||
role1_path = os.path.join(targets_meta_dir, 'delegated_role1.txt')
|
||||
role1_path = os.path.join(targets_meta_dir, 'delegated_role1.json')
|
||||
role1_metadata_signable = tuf.util.load_json_file(role1_path)
|
||||
role1_metadata = role1_metadata_signable['signed']
|
||||
|
||||
|
|
@ -495,7 +493,7 @@ def test_2__ensure_all_targets_allowed(self):
|
|||
# delegated role's metadata are not indicated in the metadata of the
|
||||
# delegated role's parent, we need to modify delegated role's 'targets'
|
||||
# field.
|
||||
target = self.random_string()+'.txt'
|
||||
target = self.random_string()+'.json'
|
||||
deleg_target_path = os.path.join('delegated_level', target)
|
||||
role1_metadata['targets'][deleg_target_path] = self.random_string()
|
||||
|
||||
|
|
@ -511,26 +509,26 @@ def test_2__ensure_all_targets_allowed(self):
|
|||
def test_2__fileinfo_has_changed(self):
|
||||
# Verify that the method returns 'False' if file info was not changed.
|
||||
for role in self.role_list:
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.txt')
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.json')
|
||||
role_info = tuf.util.get_file_details(role_filepath)
|
||||
role_info_dict = {'length':role_info[0], 'hashes':role_info[1]}
|
||||
self.assertFalse(self.Repository._fileinfo_has_changed(role+'.txt',
|
||||
self.assertFalse(self.Repository._fileinfo_has_changed(role+'.json',
|
||||
role_info_dict))
|
||||
|
||||
# Verify that the method returns 'True' if length or hashes were changed.
|
||||
for role in self.role_list:
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.txt')
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.json')
|
||||
role_info = tuf.util.get_file_details(role_filepath)
|
||||
role_info_dict = {'length':8, 'hashes':role_info[1]}
|
||||
self.assertTrue(self.Repository._fileinfo_has_changed(role+'.txt',
|
||||
self.assertTrue(self.Repository._fileinfo_has_changed(role+'.json',
|
||||
role_info_dict))
|
||||
|
||||
for role in self.role_list:
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.txt')
|
||||
role_filepath = os.path.join(self.client_current_dir, role+'.json')
|
||||
role_info = tuf.util.get_file_details(role_filepath)
|
||||
role_info_dict = {'length':role_info[0],
|
||||
'hashes':{'sha256':self.random_string()}}
|
||||
self.assertTrue(self.Repository._fileinfo_has_changed(role+'.txt',
|
||||
self.assertTrue(self.Repository._fileinfo_has_changed(role+'.json',
|
||||
role_info_dict))
|
||||
|
||||
|
||||
|
|
@ -540,13 +538,13 @@ def test_2__move_current_to_previous(self):
|
|||
# The test will consist of removing a metadata file from client's
|
||||
# {client_repository}/metadata/previous directory, executing the method
|
||||
# and then verifying that the 'previous' directory contains
|
||||
# the release file.
|
||||
release_meta_path = os.path.join(self.client_previous_dir, 'release.txt')
|
||||
os.remove(release_meta_path)
|
||||
self.assertFalse(os.path.exists(release_meta_path))
|
||||
self.Repository._move_current_to_previous('release')
|
||||
self.assertTrue(os.path.exists(release_meta_path))
|
||||
shutil.copy(release_meta_path, self.client_current_dir)
|
||||
# the snapshot file.
|
||||
snapshot_meta_path = os.path.join(self.client_previous_dir, 'snapshot.json')
|
||||
os.remove(snapshot_meta_path)
|
||||
self.assertFalse(os.path.exists(snapshot_meta_path))
|
||||
self.Repository._move_current_to_previous('snapshot')
|
||||
self.assertTrue(os.path.exists(snapshot_meta_path))
|
||||
shutil.copy(snapshot_meta_path, self.client_current_dir)
|
||||
|
||||
|
||||
|
||||
|
|
@ -561,7 +559,7 @@ def test_2__delete_metadata(self):
|
|||
self.Repository._delete_metadata('timestamp')
|
||||
self.assertFalse('timestamp' in self.Repository.metadata['current'])
|
||||
timestamp_meta_path = os.path.join(self.client_previous_dir,
|
||||
'timestamp.txt')
|
||||
'timestamp.json')
|
||||
shutil.copy(timestamp_meta_path, self.client_current_dir)
|
||||
|
||||
|
||||
|
|
@ -614,7 +612,7 @@ def test_3__update_metadata(self):
|
|||
|
||||
# Test: Invalid file downloaded.
|
||||
# Patch 'download.download_url_to_tempfileobj' function.
|
||||
self._mock_download_url_to_tempfileobj(self.release_filepath)
|
||||
self._mock_download_url_to_tempfileobj(self.snapshot_filepath)
|
||||
|
||||
# TODO: Is this the original intent of this test?
|
||||
self.assertRaises(TypeError, _update_metadata, 'targets', None)
|
||||
|
|
@ -624,7 +622,7 @@ def test_3__update_metadata(self):
|
|||
# Patch 'download.download_url_to_tempfileobj' function.
|
||||
self._mock_download_url_to_tempfileobj(self.targets_filepath)
|
||||
uncompressed_fileinfo = \
|
||||
signerlib.get_metadata_file_info(self.targets_filepath)
|
||||
repo_tool.get_metadata_file_info(self.targets_filepath)
|
||||
_update_metadata('targets', uncompressed_fileinfo)
|
||||
list_of_targets = self.Repository.metadata['current']['targets']['targets']
|
||||
|
||||
|
|
@ -637,12 +635,12 @@ def test_3__update_metadata(self):
|
|||
# Add a file to targets directory and rebuild targets metadata.
|
||||
added_target_2 = self._add_target_to_targets_dir(targets_keyids)
|
||||
uncompressed_fileinfo = \
|
||||
signerlib.get_metadata_file_info(self.targets_filepath)
|
||||
repo_tool.get_metadata_file_info(self.targets_filepath)
|
||||
|
||||
# To test compressed file handling, compress targets metadata file.
|
||||
targets_filepath_compressed = self._compress_file(self.targets_filepath)
|
||||
compressed_fileinfo = \
|
||||
signerlib.get_metadata_file_info(targets_filepath_compressed)
|
||||
repo_tool.get_metadata_file_info(targets_filepath_compressed)
|
||||
|
||||
# Re-patch 'download.download_url_to_tempfileobj' function.
|
||||
self._mock_download_url_to_tempfileobj(targets_filepath_compressed)
|
||||
|
|
@ -663,7 +661,7 @@ def test_3__update_metadata(self):
|
|||
|
||||
# Restoring server's repository to the initial state.
|
||||
os.remove(targets_filepath_compressed)
|
||||
os.remove(os.path.join(self.client_current_dir,'targets.txt'))
|
||||
os.remove(os.path.join(self.client_current_dir,'targets.json'))
|
||||
self._remove_target_from_targets_dir(added_target_1)
|
||||
|
||||
|
||||
|
|
@ -688,24 +686,24 @@ def test_3__update_metadata_if_changed(self):
|
|||
update_if_changed = self.Repository._update_metadata_if_changed
|
||||
|
||||
|
||||
# Test: normal case. Update 'release' metadata.
|
||||
# Test: normal case. Update 'snapshot' metadata.
|
||||
# Patch download_file.
|
||||
self._mock_download_url_to_tempfileobj(self.timestamp_filepath)
|
||||
|
||||
# Update timestamp metadata, it will indicate change in release metadata.
|
||||
# Update timestamp metadata, it will indicate change in snapshot metadata.
|
||||
self.Repository._update_metadata('timestamp', DEFAULT_TIMESTAMP_FILEINFO)
|
||||
|
||||
# Save current release metadata before updating. It will be used to
|
||||
# Save current snapshot metadata before updating. It will be used to
|
||||
# verify the update.
|
||||
old_release_meta = self.Repository.metadata['current']['release']
|
||||
self._mock_download_url_to_tempfileobj(self.release_filepath)
|
||||
old_snapshot_meta = self.Repository.metadata['current']['snapshot']
|
||||
self._mock_download_url_to_tempfileobj(self.snapshot_filepath)
|
||||
|
||||
# Update release metadata, it will indicate change in targets metadata.
|
||||
update_if_changed(metadata_role='release', referenced_metadata='timestamp')
|
||||
current_release_meta = self.Repository.metadata['current']['release']
|
||||
previous_release_meta = self.Repository.metadata['previous']['release']
|
||||
self.assertEqual(old_release_meta, previous_release_meta)
|
||||
self.assertNotEqual(old_release_meta, current_release_meta)
|
||||
# Update snapshot metadata, it will indicate change in targets metadata.
|
||||
update_if_changed(metadata_role='snapshot', referenced_metadata='timestamp')
|
||||
current_snapshot_meta = self.Repository.metadata['current']['snapshot']
|
||||
previous_snapshot_meta = self.Repository.metadata['previous']['snapshot']
|
||||
self.assertEqual(old_snapshot_meta, previous_snapshot_meta)
|
||||
self.assertNotEqual(old_snapshot_meta, current_snapshot_meta)
|
||||
|
||||
|
||||
# Test: normal case. Update 'targets' metadata.
|
||||
|
|
@ -719,37 +717,37 @@ def test_3__update_metadata_if_changed(self):
|
|||
self.fail('\nFailed to update targets metadata.')
|
||||
|
||||
|
||||
# Test: normal case. Update compressed release file.
|
||||
release_filepath_compressed = self._compress_file(self.release_filepath)
|
||||
# Test: normal case. Update compressed snapshot file.
|
||||
snapshot_filepath_compressed = self._compress_file(self.snapshot_filepath)
|
||||
|
||||
# Since client's '.../metadata/current' will need to have separate
|
||||
# gzipped metadata file in order to test compressed file handling,
|
||||
# we need to copy it there.
|
||||
shutil.copy(release_filepath_compressed, self.client_current_dir)
|
||||
shutil.copy(snapshot_filepath_compressed, self.client_current_dir)
|
||||
|
||||
# Add a target file and rebuild metadata files at the server side.
|
||||
added_target_2 = self._add_target_to_targets_dir(targets_keyids)
|
||||
|
||||
# Since release file was updated, update compressed release file.
|
||||
release_filepath_compressed = self._compress_file(self.release_filepath)
|
||||
# Since snapshot file was updated, update compressed snapshot file.
|
||||
snapshot_filepath_compressed = self._compress_file(self.snapshot_filepath)
|
||||
|
||||
# Patch download_file.
|
||||
self._mock_download_url_to_tempfileobj(self.timestamp_filepath)
|
||||
|
||||
# Update timestamp metadata, it will indicate change in release metadata.
|
||||
# Update timestamp metadata, it will indicate change in snapshot metadata.
|
||||
self.Repository._update_metadata('timestamp', DEFAULT_TIMESTAMP_FILEINFO)
|
||||
|
||||
# Save current release metadata before updating. It will be used to
|
||||
# Save current snapshot metadata before updating. It will be used to
|
||||
# verify the update.
|
||||
old_release_meta = self.Repository.metadata['current']['release']
|
||||
self._mock_download_url_to_tempfileobj(self.release_filepath)
|
||||
old_snapshot_meta = self.Repository.metadata['current']['snapshot']
|
||||
self._mock_download_url_to_tempfileobj(self.snapshot_filepath)
|
||||
|
||||
# Update release metadata, and verify the change.
|
||||
update_if_changed(metadata_role='release', referenced_metadata='timestamp')
|
||||
current_release_meta = self.Repository.metadata['current']['release']
|
||||
previous_release_meta = self.Repository.metadata['previous']['release']
|
||||
self.assertEqual(old_release_meta, previous_release_meta)
|
||||
self.assertNotEqual(old_release_meta, current_release_meta)
|
||||
# Update snapshot metadata, and verify the change.
|
||||
update_if_changed(metadata_role='snapshot', referenced_metadata='timestamp')
|
||||
current_snapshot_meta = self.Repository.metadata['current']['snapshot']
|
||||
previous_snapshot_meta = self.Repository.metadata['previous']['snapshot']
|
||||
self.assertEqual(old_snapshot_meta, previous_snapshot_meta)
|
||||
self.assertNotEqual(old_snapshot_meta, current_snapshot_meta)
|
||||
|
||||
|
||||
# Test: Invalid targets metadata file downloaded.
|
||||
|
|
@ -764,8 +762,8 @@ def test_3__update_metadata_if_changed(self):
|
|||
assert isinstance(mirror_error, tuf.DownloadLengthMismatchError)
|
||||
|
||||
# Restoring repositories to the initial state.
|
||||
os.remove(release_filepath_compressed)
|
||||
os.remove(os.path.join(self.client_current_dir, 'release.txt.gz'))
|
||||
os.remove(snapshot_filepath_compressed)
|
||||
os.remove(os.path.join(self.client_current_dir, 'snapshot.json.gz'))
|
||||
self._remove_target_from_targets_dir(added_target_1)
|
||||
|
||||
|
||||
|
|
@ -786,7 +784,7 @@ def test_3__targets_of_role(self):
|
|||
for target in range(len(targets_list)):
|
||||
targets_filepaths.append(targets_list[target]['filepath'])
|
||||
for dir_target in targets_dir_content:
|
||||
if dir_target.endswith('.txt'):
|
||||
if dir_target.endswith('.json'):
|
||||
self.assertTrue(dir_target in targets_filepaths)
|
||||
|
||||
|
||||
|
|
@ -843,9 +841,9 @@ def test_4__refresh_targets_metadata(self):
|
|||
|
||||
# Delegated roles paths.
|
||||
role1_dir = os.path.join(self.server_meta_dir, 'targets')
|
||||
role1_filepath = os.path.join(role1_dir, 'delegated_role1.txt')
|
||||
role1_filepath = os.path.join(role1_dir, 'delegated_role1.json')
|
||||
role2_dir = os.path.join(role1_dir, 'delegated_role1')
|
||||
role2_filepath = os.path.join(role2_dir, 'delegated_role2.txt')
|
||||
role2_filepath = os.path.join(role2_dir, 'delegated_role2.json')
|
||||
|
||||
# Create a file in the delegated targets directory.
|
||||
deleg_target_filepath2 = self._add_file_to_directory(targets_deleg_dir2)
|
||||
|
|
@ -914,7 +912,7 @@ def test_5_all_targets(self):
|
|||
# Verify that there is a correct number of records in 'all_targets' list.
|
||||
# On the repository there are 4 target files, 2 of which are delegated.
|
||||
# The targets role lists all targets, for a total of 4. The two delegated
|
||||
# roles each list 1 of the already listed targets in 'targets.txt', for a
|
||||
# roles each list 1 of the already listed targets in 'targets.json', for a
|
||||
# total of 2 (the delegated targets are listed twice). The total number of
|
||||
# targets in 'all_targets' should then be 6.
|
||||
self.assertTrue(len(all_targets) is 6)
|
||||
|
|
@ -937,7 +935,7 @@ def test_5_targets_of_role(self):
|
|||
for target in range(len(targets_list)):
|
||||
targets_filepaths.append(targets_list[target]['filepath'])
|
||||
for dir_target in targets_dir_content:
|
||||
if dir_target.endswith('.txt'):
|
||||
if dir_target.endswith('.json'):
|
||||
self.assertTrue(dir_target in targets_filepaths)
|
||||
|
||||
|
||||
|
|
@ -960,7 +958,7 @@ def test_6_target(self):
|
|||
|
||||
# Test: normal case.
|
||||
for _target in targets_dir_content:
|
||||
if _target.endswith('.txt'):
|
||||
if _target.endswith('.json'):
|
||||
target_info = target(_target)
|
||||
# Verify that 'target_info' corresponds to 'TARGETFILE_SCHEMA'.
|
||||
self.assertTrue(tuf.formats.TARGETFILE_SCHEMA.matches(target_info))
|
||||
|
|
|
|||
|
|
@ -93,14 +93,14 @@ def test_correct_directory_structure(self):
|
|||
metadata_dir = os.path.join(tuf_repo, 'metadata')
|
||||
current_dir = os.path.join(tuf_client, 'metadata', 'current')
|
||||
|
||||
# Verify '{root_repo}/tuf_repo/metadata/role.txt' paths exists.
|
||||
for role in ['root', 'targets', 'release', 'timestamp']:
|
||||
# Verify '{root_repo}/tuf_repo/metadata/role.json' paths exists.
|
||||
for role in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
# Repository side.
|
||||
role_file = os.path.join(metadata_dir, role+'.txt')
|
||||
role_file = os.path.join(metadata_dir, role+'.json')
|
||||
self.assertTrue(os.path.isfile(role_file))
|
||||
|
||||
# Client side.
|
||||
role_file = os.path.join(current_dir, role+'.txt')
|
||||
role_file = os.path.join(current_dir, role+'.json')
|
||||
self.assertTrue(os.path.isfile(role_file))
|
||||
|
||||
# Verify '{root_repo}/tuf_repo/keystore/keyid.key' exists.
|
||||
|
|
@ -126,8 +126,8 @@ def test_methods(self):
|
|||
|
||||
Note: here file at the 'filepath' and the 'target' file at tuf-targets
|
||||
directory are identical files.
|
||||
Ex: filepath = '{root_repo}/reg_repo/file.txt'
|
||||
target = '{root_repo}/tuf_repo/targets/file.txt'
|
||||
Ex: filepath = '{root_repo}/reg_repo/file.json'
|
||||
target = '{root_repo}/tuf_repo/targets/file.json'
|
||||
"""
|
||||
|
||||
reg_repo = os.path.join(self.root_repo, 'reg_repo')
|
||||
|
|
|
|||
|
|
@ -81,14 +81,14 @@ Enter a password for the encrypted ED25519 key:
|
|||
# Continuing from the previous section . . .
|
||||
|
||||
# Create a new Repository object that holds the file path to the repository and the four
|
||||
# top-level role objects (Root, Targets, Release, Timestamp). Metadata files are created when
|
||||
# top-level role objects (Root, Targets, Snapshot, Timestamp). Metadata files are created when
|
||||
# repository.write() is called. The repository directory is created if it does not exist.
|
||||
repository = create_new_repository("path/to/repository/")
|
||||
|
||||
# The Repository instance, 'repository', initially contains top-level Metadata objects.
|
||||
# Add one of the public keys, created in the previous section, to the root role. Metadata is
|
||||
# considered valid if it is signed by the public key's corresponding private key.
|
||||
repository.root.add_key(public_root_key)
|
||||
repository.root.add_verification_key(public_root_key)
|
||||
|
||||
# Role keys (i.e., the key's keyid) may be queried. Other attributes include: signing_keys, version,
|
||||
# signatures, expiration, threshold, delegations (Targets role), and compressions.
|
||||
|
|
@ -98,7 +98,7 @@ repository.root.keys
|
|||
# Add a second public key to the root role. Although previously generated and saved to a file,
|
||||
# the second public key must be imported before it can added to a role.
|
||||
public_root_key2 = import_rsa_publickey_from_file("path/to/root_key2.pub")
|
||||
repository.root.add_key(public_root_key2)
|
||||
repository.root.add_verification_key(public_root_key2)
|
||||
|
||||
# Threshold of each role defaults to 1. Users may change the threshold value, but repository_tool.py
|
||||
# validates thresholds and warns users. Set the threshold of the root role to 2,
|
||||
|
|
@ -121,12 +121,12 @@ repository.status()
|
|||
try:
|
||||
repository.write()
|
||||
|
||||
# An exception is raised here by write() because the other top-level roles (targets, release,
|
||||
# An exception is raised here by write() because the other top-level roles (targets, snapshot,
|
||||
# and timestamp) have not been configured with keys. Another option is to call
|
||||
# repository.write_partial() and generate metadata that may contain an invalid threshold of
|
||||
# signatures, required public keys, etc. write_partial() allows multiple repository maintainers to
|
||||
# independently sign metadata and generate them separately. load_repository() can load partially
|
||||
# written metadata.q
|
||||
# written metadata.
|
||||
except tuf.Error, e:
|
||||
print e
|
||||
Not enough signatures for 'path/to/repository/metadata.staged/targets.json'
|
||||
|
|
@ -134,7 +134,7 @@ Not enough signatures for 'path/to/repository/metadata.staged/targets.json'
|
|||
# In the next section, update the other top-level roles and create a repository with valid metadata.
|
||||
```
|
||||
|
||||
#### Create Timestamp, Release, Targets
|
||||
#### Create Timestamp, Snapshot, Targets
|
||||
|
||||
```python
|
||||
# Continuing from the previous section . . .
|
||||
|
|
@ -142,19 +142,19 @@ Not enough signatures for 'path/to/repository/metadata.staged/targets.json'
|
|||
# Generate keys for the remaining top-level roles. The root keys have been set above.
|
||||
# The password argument may be omitted if a password prompt is needed.
|
||||
generate_and_write_rsa_keypair("path/to/targets_key", password="password")
|
||||
generate_and_write_rsa_keypair("path/to/release_key", password="password")
|
||||
generate_and_write_rsa_keypair("path/to/snapshot_key", password="password")
|
||||
generate_and_write_rsa_keypair("path/to/timestamp_key", password="password")
|
||||
|
||||
# Add the public keys of the remaining top-level roles.
|
||||
repository.targets.add_key(import_rsa_publickey_from_file("path/to/targets_key.pub"))
|
||||
repository.release.add_key(import_rsa_publickey_from_file("path/to/release_key.pub"))
|
||||
repository.timestamp.add_key(import_rsa_publickey_from_file("path/to/timestamp_key.pub"))
|
||||
repository.targets.add_verification_key(import_rsa_publickey_from_file("path/to/targets_key.pub"))
|
||||
repository.snapshot.add_verification_key(import_rsa_publickey_from_file("path/to/snapshot_key.pub"))
|
||||
repository.timestamp.add_verification_key(import_rsa_publickey_from_file("path/to/timestamp_key.pub"))
|
||||
|
||||
# Import the signing keys of the remaining top-level roles. Prompt for passwords.
|
||||
private_targets_key = import_rsa_privatekey_from_file("path/to/targets_key")
|
||||
Enter a password for the encrypted RSA key:
|
||||
|
||||
private_release_key = import_rsa_privatekey_from_file("path/to/release_key")
|
||||
private_snapshot_key = import_rsa_privatekey_from_file("path/to/snapshot_key")
|
||||
Enter a password for the encrypted RSA key:
|
||||
|
||||
private_timestamp_key = import_rsa_privatekey_from_file("path/to/timestamp_key")
|
||||
|
|
@ -163,16 +163,16 @@ Enter a password for the encrypted RSA key:
|
|||
# Load the signing keys of the remaining roles so that valid signatures are generated when
|
||||
# repository.write() is called.
|
||||
repository.targets.load_signing_key(private_targets_key)
|
||||
repository.release.load_signing_key(private_release_key)
|
||||
repository.snapshot.load_signing_key(private_snapshot_key)
|
||||
repository.timestamp.load_signing_key(private_timestamp_key)
|
||||
|
||||
# Optionally set the expiration date of the timestamp role. By default, roles are set to expire
|
||||
# as follows: root(1 year), targets(3 months), release(1 week), timestamp(1 day).
|
||||
# as follows: root(1 year), targets(3 months), snapshot(1 week), timestamp(1 day).
|
||||
repository.timestamp.expiration = "2014-10-28 12:08:00"
|
||||
|
||||
# Metadata files may also be compressed. Only "gz" is currently supported.
|
||||
repository.targets.compressions = ["gz"]
|
||||
repository.release.compressions = ["gz"]
|
||||
repository.snapshot.compressions = ["gz"]
|
||||
|
||||
# Write all metadata to "path/to/repository/metadata.staged/". The common case is to crawl the
|
||||
# filesystem for all delegated roles in "path/to/repository/metadata.staged/targets/".
|
||||
|
|
@ -225,7 +225,7 @@ Enter a password for the encrypted RSA key:
|
|||
private_root_key2 = import_rsa_privatekey_from_file("path/to/root_key2")
|
||||
Enter a password for the encrypted RSA key:
|
||||
|
||||
private_release_key = import_rsa_privatekey_from_file("path/to/release_key")
|
||||
private_snapshot_key = import_rsa_privatekey_from_file("path/to/snapshot_key")
|
||||
Enter a password for the encrypted RSA key:
|
||||
|
||||
private_timestamp_key = import_rsa_privatekey_from_file("path/to/timestamp_key")
|
||||
|
|
@ -233,7 +233,7 @@ Enter a password for the encrypted RSA key:
|
|||
|
||||
repository.root.load_signing_key(private_root_key)
|
||||
repository.root.load_signing_key(private_root_key2)
|
||||
repository.release.load_signing_key(private_release_key)
|
||||
repository.snapshot.load_signing_key(private_snapshot_key)
|
||||
repository.timestamp.load_signing_key(private_timestamp_key)
|
||||
|
||||
# Generate new versions of all the top-level metadata.
|
||||
|
|
@ -249,7 +249,7 @@ repository.write()
|
|||
repository.targets.remove_target("path/to/repository/targets/file3.txt")
|
||||
|
||||
# repository.write() creates any new metadata files, updates those that have changed, and any that
|
||||
# need updating to make a new "release" (new release.json and timestamp.json).
|
||||
# need updating to make a new "snapshot" (new snapshot.json and timestamp.json).
|
||||
repository.write()
|
||||
```
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ repository.targets('unclaimed')('django').load_signing_key(private_unclaimed_key
|
|||
repository.targets('unclaimed')('django').add_target("path/to/repository/targets/django/file4.txt")
|
||||
repository.targets('unclaimed')('django').compressions = ["gz"]
|
||||
|
||||
# Write the metadata of "targets/unclaimed", "targets/unclaimed/django", root, targets, release,
|
||||
# Write the metadata of "targets/unclaimed", "targets/unclaimed/django", root, targets, snapshot,
|
||||
# and timestamp.
|
||||
repository.write()
|
||||
```
|
||||
|
|
|
|||
|
|
@ -21,11 +21,11 @@ for more information on interposing Python urllib calls with TUF.
|
|||
|
||||
2. TUF downloads and verifies timestamp.json.
|
||||
|
||||
3. If timestamp.json indicates that release.json has changed, TUF downloads and
|
||||
verifies release.json.
|
||||
3. If timestamp.json indicates that snapshot.json has changed, TUF downloads and
|
||||
verifies snapshot.json.
|
||||
|
||||
4. TUF determines which metadata files listed in release.json differ from those
|
||||
described in the last release.json that TUF has seen. If root.json has changed,
|
||||
4. TUF determines which metadata files listed in snapshot.json differ from those
|
||||
described in the last snapshot.json that TUF has seen. If root.json has changed,
|
||||
the update process starts over using the new root.json.
|
||||
|
||||
5. TUF provides the software update system with a list of available files
|
||||
|
|
@ -75,7 +75,7 @@ repository_mirrors = {'mirror1': {'url_prefix': 'http://localhost:8001',
|
|||
updater = tuf.client.updater.Updater('updater', repository_mirrors)
|
||||
|
||||
# The client calls the refresh() method to ensure it has the latest
|
||||
# copies of the top-level metadata files (i.e., Root, Targets, Release,
|
||||
# copies of the top-level metadata files (i.e., Root, Targets, Snapshot,
|
||||
# Timestamp).
|
||||
updater.refresh()
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ for target in updated_targets:
|
|||
updater.download_target(target, destination_directory)
|
||||
|
||||
# Remove any files from the destination directory that are no longer being
|
||||
# tracked. For example, a target file from a previous release that has since
|
||||
# tracked. For example, a target file from a previous snapshot that has since
|
||||
# been removed on the remote repository.
|
||||
updater.remove_obsolete_targets(destination_directory)
|
||||
```
|
||||
|
|
@ -107,7 +107,7 @@ updater.remove_obsolete_targets(destination_directory)
|
|||
# Example demonstrating an update that only downloads the targets of
|
||||
# a specific role (i.e., 'targets/django').
|
||||
|
||||
# Refresh the metadata of the top-level roles (i.e., Root, Targets, Release, Timestamp).
|
||||
# Refresh the metadata of the top-level roles (i.e., Root, Targets, Snapshot, Timestamp).
|
||||
updater.refresh()
|
||||
|
||||
# Update the 'targets/django' role, and determine the target files that have changed.
|
||||
|
|
@ -124,7 +124,7 @@ for target in updated_targets:
|
|||
```Python
|
||||
# Example demonstrating an update that downloads a specific target.
|
||||
|
||||
# Refresh the metadata of the top-level roles (i.e., Root, Targets, Release, Timestamp).
|
||||
# Refresh the metadata of the top-level roles (i.e., Root, Targets, Snapshot, Timestamp).
|
||||
updater.refresh()
|
||||
|
||||
# target() updates role metadata when required.
|
||||
|
|
@ -154,7 +154,7 @@ reported_length (545) < required_length (2048)
|
|||
Downloaded 545 bytes, but expected 2048 bytes. There is a difference of 1503 bytes!
|
||||
|
||||
[2013-12-16 16:17:05,611 UTC] [tuf.download] [INFO][_download_file:726@download.py]
|
||||
Downloading: http://localhost:8001/metadata/release.json
|
||||
Downloading: http://localhost:8001/metadata/snapshot.json
|
||||
|
||||
[2013-12-16 16:17:05,612 UTC] [tuf.client.updater] [INFO][_check_hashes:636@updater.py]
|
||||
The file\'s sha256 hash is correct: 782675fadd650eeb2926d33c401b5896caacf4fd6766498baf2bce2f3b739db4
|
||||
|
|
|
|||
|
|
@ -28,11 +28,11 @@
|
|||
|
||||
2. TUF downloads and verifies timestamp.json.
|
||||
|
||||
3. If timestamp.json indicates that release.json has changed, TUF downloads
|
||||
and verifies release.json.
|
||||
3. If timestamp.json indicates that snapshot.json has changed, TUF downloads
|
||||
and verifies snapshot.json.
|
||||
|
||||
4. TUF determines which metadata files listed in release.json differ from
|
||||
those described in the last release.json that TUF has seen. If root.json
|
||||
4. TUF determines which metadata files listed in snapshot.json differ from
|
||||
those described in the last snapshot.json that TUF has seen. If root.json
|
||||
has changed, the update process starts over using the new root.json.
|
||||
|
||||
5. TUF provides the software update system with a list of available files
|
||||
|
|
@ -160,7 +160,7 @@ class Updater(object):
|
|||
<Updater Methods>
|
||||
refresh():
|
||||
This method downloads, verifies, and loads metadata for the top-level
|
||||
roles in a specific order (i.e., timestamp -> release -> root -> targets)
|
||||
roles in a specific order (i.e., timestamp -> snapshot -> root -> targets)
|
||||
The expiration time for downloaded metadata is also verified.
|
||||
|
||||
The metadata for delegated roles are not refreshed by this method, but by
|
||||
|
|
@ -324,7 +324,7 @@ def __init__(self, updater_name, repository_mirrors):
|
|||
|
||||
# Load current and previous metadata.
|
||||
for metadata_set in ['current', 'previous']:
|
||||
for metadata_role in ['root', 'targets', 'release', 'timestamp']:
|
||||
for metadata_role in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
self._load_metadata_from_file(metadata_set, metadata_role)
|
||||
|
||||
# Raise an exception if the repository is missing the required 'root'
|
||||
|
|
@ -430,7 +430,7 @@ def _rebuild_key_and_role_db(self):
|
|||
'root' metadata object extracted from 'root.json'. This private
|
||||
method is called when a new/updated 'root' metadata file is loaded.
|
||||
This method will only store the role information for the top-level
|
||||
roles (i.e., 'root', 'targets', 'release', 'timestamp').
|
||||
roles (i.e., 'root', 'targets', 'snapshot', 'timestamp').
|
||||
|
||||
<Arguments>
|
||||
None.
|
||||
|
|
@ -604,7 +604,7 @@ def refresh(self, unsafely_update_root_if_necessary=True):
|
|||
# require strict checks on its required length.
|
||||
try:
|
||||
self._update_metadata('timestamp', DEFAULT_TIMESTAMP_FILEINFO)
|
||||
self._update_metadata_if_changed('release',
|
||||
self._update_metadata_if_changed('snapshot',
|
||||
referenced_metadata='timestamp')
|
||||
self._update_metadata_if_changed('root')
|
||||
self._update_metadata_if_changed('targets')
|
||||
|
|
@ -625,7 +625,7 @@ def refresh(self, unsafely_update_root_if_necessary=True):
|
|||
# Updated the top-level metadata (which all had valid signatures),
|
||||
# however, have they expired? Raise 'tuf.ExpiredMetadataError' if any of
|
||||
# the metadata has expired.
|
||||
for metadata_role in ['timestamp', 'root', 'release', 'targets']:
|
||||
for metadata_role in ['timestamp', 'root', 'snapshot', 'targets']:
|
||||
self._ensure_not_expired(metadata_role)
|
||||
|
||||
|
||||
|
|
@ -1210,7 +1210,7 @@ def _update_metadata(self, metadata_role, uncompressed_fileinfo,
|
|||
|
||||
compression:
|
||||
A string designating the compression type of 'metadata_role'.
|
||||
The 'release' metadata file may be optionally downloaded and stored in
|
||||
The 'snapshot' metadata file may be optionally downloaded and stored in
|
||||
compressed form. Currently, only metadata files compressed with 'gzip'
|
||||
are considered. Any other string is ignored.
|
||||
|
||||
|
|
@ -1240,7 +1240,7 @@ def _update_metadata(self, metadata_role, uncompressed_fileinfo,
|
|||
metadata_filename = metadata_role + '.json'
|
||||
uncompressed_metadata_filename = metadata_filename
|
||||
|
||||
# The 'release' or Targets metadata may be compressed. Add the appropriate
|
||||
# The 'snapshot' or Targets metadata may be compressed. Add the appropriate
|
||||
# extension to 'metadata_filename'.
|
||||
if compression == 'gzip':
|
||||
metadata_filename = metadata_filename + '.gz'
|
||||
|
|
@ -1352,7 +1352,7 @@ def _update_metadata(self, metadata_role, uncompressed_fileinfo,
|
|||
|
||||
|
||||
|
||||
def _update_metadata_if_changed(self, metadata_role, referenced_metadata='release'):
|
||||
def _update_metadata_if_changed(self, metadata_role, referenced_metadata='snapshot'):
|
||||
"""
|
||||
<Purpose>
|
||||
Update the metadata for 'metadata_role' if it has changed. With the
|
||||
|
|
@ -1360,7 +1360,7 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
by this method. The 'timestamp' role is always downloaded from a mirror
|
||||
without first checking if it has been updated; it is updated in refresh()
|
||||
by calling _update_metadata('timestamp'). This method is also called for
|
||||
delegated role metadata, which are referenced by 'release'.
|
||||
delegated role metadata, which are referenced by 'snapshot'.
|
||||
|
||||
If the metadata needs to be updated but an update cannot be obtained,
|
||||
this method will delete the file (with the exception of the root
|
||||
|
|
@ -1368,7 +1368,7 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
|
||||
Due to the way in which metadata files are updated, it is expected that
|
||||
'referenced_metadata' is not out of date and trusted. The refresh()
|
||||
method updates the top-level roles in 'timestamp -> release ->
|
||||
method updates the top-level roles in 'timestamp -> snapshot ->
|
||||
root -> targets' order. For delegated metadata, the parent role is
|
||||
updated before the delegated role. Taking into account that
|
||||
'referenced_metadata' is updated and verified before 'metadata_role',
|
||||
|
|
@ -1382,11 +1382,11 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
|
||||
referenced_metadata:
|
||||
This is the metadata that provides the role information for
|
||||
'metadata_role'. For the top-level roles, the 'release' role
|
||||
'metadata_role'. For the top-level roles, the 'snapshot' role
|
||||
is the referenced metadata for the 'root', and 'targets' roles.
|
||||
The 'timestamp' metadata is always downloaded regardless. In
|
||||
other words, it is updated by calling _update_metadata('timestamp')
|
||||
and not by this method. The referenced metadata for 'release'
|
||||
and not by this method. The referenced metadata for 'snapshot'
|
||||
is 'timestamp'. See refresh().
|
||||
|
||||
<Exceptions>
|
||||
|
|
@ -1412,7 +1412,7 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
uncompressed_metadata_filename = metadata_role + '.json'
|
||||
|
||||
# Ensure the referenced metadata has been loaded. The 'root' role may be
|
||||
# updated without having 'release' available.
|
||||
# updated without having 'snapshot' available.
|
||||
if referenced_metadata not in self.metadata['current']:
|
||||
message = 'Cannot update '+repr(metadata_role)+' because ' \
|
||||
+referenced_metadata+' is missing.'
|
||||
|
|
@ -1425,11 +1425,11 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
repr(referenced_metadata)+'. '+repr(metadata_role)+' may be updated.'
|
||||
logger.debug(message)
|
||||
|
||||
# There might be a compressed version of 'release.json' or Targets
|
||||
# There might be a compressed version of 'snapshot.json' or Targets
|
||||
# metadata available for download. Check the 'meta' field of
|
||||
# 'referenced_metadata' to see if it is listed when 'metadata_role'
|
||||
# is 'release'. The full rolename for delegated Targets metadata
|
||||
# must begin with 'targets/'. The Release role lists all the Targets
|
||||
# is 'snapshot'. The full rolename for delegated Targets metadata
|
||||
# must begin with 'targets/'. The snapshot role lists all the Targets
|
||||
# metadata available on the repository, including any that may be in
|
||||
# compressed form.
|
||||
#
|
||||
|
|
@ -1446,12 +1446,12 @@ def _update_metadata_if_changed(self, metadata_role, referenced_metadata='releas
|
|||
['meta'] \
|
||||
[uncompressed_metadata_filename]
|
||||
|
||||
# Check for the availability of compressed versions of 'release.json',
|
||||
# Check for the availability of compressed versions of 'snapshot.json',
|
||||
# 'targets.json', and delegated Targets (that also start with 'targets').
|
||||
# For 'targets.json' and delegated metadata, 'referenced_metata'
|
||||
# should always be 'release'. 'release.json' specifies all roles
|
||||
# should always be 'snapshot'. 'snapshot.json' specifies all roles
|
||||
# provided by a repository, including their file lengths and hashes.
|
||||
if metadata_role == 'release' or metadata_role.startswith('targets'):
|
||||
if metadata_role == 'snapshot' or metadata_role.startswith('targets'):
|
||||
gzip_metadata_filename = uncompressed_metadata_filename + '.gz'
|
||||
if gzip_metadata_filename in self.metadata['current'] \
|
||||
[referenced_metadata]['meta']:
|
||||
|
|
@ -1514,10 +1514,10 @@ def _fileinfo_has_changed(self, metadata_filename, new_fileinfo):
|
|||
differs from 'new_fileinfo'. The 'new_fileinfo' argument
|
||||
should be extracted from the latest copy of the metadata
|
||||
that references 'metadata_filename'. Example: 'root.json'
|
||||
would be referenced by 'release.json'.
|
||||
would be referenced by 'snapshot.json'.
|
||||
|
||||
'new_fileinfo' should only be 'None' if this is for updating
|
||||
'root.json' without having 'release.json' available.
|
||||
'root.json' without having 'snapshot.json' available.
|
||||
|
||||
<Arguments>
|
||||
metadadata_filename:
|
||||
|
|
@ -1527,7 +1527,7 @@ def _fileinfo_has_changed(self, metadata_filename, new_fileinfo):
|
|||
new_fileinfo:
|
||||
A dict object representing the new file information for
|
||||
'metadata_filename'. 'new_fileinfo' may be 'None' when
|
||||
updating 'root' without having 'release' available. This
|
||||
updating 'root' without having 'snapshot' available. This
|
||||
dict conforms to 'tuf.formats.FILEINFO_SCHEMA' and has
|
||||
the form:
|
||||
{'length': 23423
|
||||
|
|
@ -1774,7 +1774,7 @@ def all_targets(self):
|
|||
<Exceptions>
|
||||
tuf.RepositoryError:
|
||||
If the metadata for the 'targets' role is missing from
|
||||
the 'release' metadata.
|
||||
the 'snapshot' metadata.
|
||||
|
||||
tuf.UnknownRoleError:
|
||||
If one of the roles could not be found in the role database.
|
||||
|
|
@ -1830,7 +1830,7 @@ def _refresh_targets_metadata(self, rolename='targets', include_delegations=Fals
|
|||
<Exceptions>
|
||||
tuf.RepositoryError:
|
||||
If the metadata file for the 'targets' role is missing
|
||||
from the 'release' metadata.
|
||||
from the 'snapshot' metadata.
|
||||
|
||||
<Side Effects>
|
||||
The metadata for the delegated roles are loaded and updated if they
|
||||
|
|
@ -1846,7 +1846,7 @@ def _refresh_targets_metadata(self, rolename='targets', include_delegations=Fals
|
|||
# See if this role provides metadata and, if we're including
|
||||
# delegations, look for metadata from delegated roles.
|
||||
role_prefix = rolename + '/'
|
||||
for metadata_path in self.metadata['current']['release']['meta'].keys():
|
||||
for metadata_path in self.metadata['current']['snapshot']['meta'].keys():
|
||||
if metadata_path == rolename + '.json':
|
||||
roles_to_update.append(metadata_path[:-len('.json')])
|
||||
elif include_delegations and metadata_path.startswith(role_prefix):
|
||||
|
|
@ -1861,7 +1861,7 @@ def _refresh_targets_metadata(self, rolename='targets', include_delegations=Fals
|
|||
try:
|
||||
roles_to_update.remove('targets')
|
||||
except ValueError:
|
||||
message = 'The Release metadata file is missing the targets.json entry.'
|
||||
message = 'The snapshot metadata file is missing the targets.json entry.'
|
||||
raise tuf.RepositoryError(message)
|
||||
|
||||
# If there is nothing to refresh, we are done.
|
||||
|
|
@ -1922,7 +1922,7 @@ def refresh_targets_metadata_chain(self, rolename):
|
|||
|
||||
tuf.RepositoryError:
|
||||
If the metadata of any of the parent roles of 'rolename' is missing
|
||||
from the 'release.json' metadata file.
|
||||
from the 'snapshot.json' metadata file.
|
||||
|
||||
<Side Effects>
|
||||
The metadata of the parent roles of 'rolename' are loaded from disk and
|
||||
|
|
@ -1966,15 +1966,15 @@ def refresh_targets_metadata_chain(self, rolename):
|
|||
repr(parent_roles)+'.'
|
||||
logger.info(message)
|
||||
|
||||
# Check if 'release.json' provides metadata for each of the roles in
|
||||
# Check if 'snapshot.json' provides metadata for each of the roles in
|
||||
# 'parent_roles'. All the available roles on the repository are specified
|
||||
# in the 'release.json' metadata.
|
||||
targets_metadata_allowed = self.metadata['current']['release']['meta'].keys()
|
||||
# in the 'snapshot.json' metadata.
|
||||
targets_metadata_allowed = self.metadata['current']['snapshot']['meta'].keys()
|
||||
for parent_role in parent_roles:
|
||||
parent_role = parent_role + '.json'
|
||||
|
||||
if parent_role not in targets_metadata_allowed:
|
||||
message = '"release.json" does not provide all the parent roles '+\
|
||||
message = '"snapshot.json" does not provide all the parent roles '+\
|
||||
'of '+repr(rolename)+'.'
|
||||
raise tuf.RepositoryError(message)
|
||||
|
||||
|
|
@ -1984,7 +1984,7 @@ def refresh_targets_metadata_chain(self, rolename):
|
|||
try:
|
||||
parent_roles.remove('targets')
|
||||
except ValueError:
|
||||
message = 'The Release metadata file is missing the "targets.json" entry.'
|
||||
message = 'The snapshot metadata file is missing the "targets.json" entry.'
|
||||
raise tuf.RepositoryError(message)
|
||||
|
||||
# If there is nothing to refresh, we are done.
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@
|
|||
object_name = 'ROOT_SCHEMA',
|
||||
_type = SCHEMA.String('Root'),
|
||||
version = METADATAVERSION_SCHEMA,
|
||||
consistent_snapshots = BOOLEAN_SCHEMA,
|
||||
consistent_snapshot = BOOLEAN_SCHEMA,
|
||||
expires = TIME_SCHEMA,
|
||||
keys = KEYDICT_SCHEMA,
|
||||
roles = ROLEDICT_SCHEMA)
|
||||
|
|
@ -407,15 +407,15 @@
|
|||
targets = FILEDICT_SCHEMA,
|
||||
delegations = SCHEMA.Optional(DELEGATIONS_SCHEMA))
|
||||
|
||||
# Release role: indicates the latest versions of all metadata (except timestamp).
|
||||
RELEASE_SCHEMA = SCHEMA.Object(
|
||||
object_name = 'RELEASE_SCHEMA',
|
||||
_type = SCHEMA.String('Release'),
|
||||
# Snapshot role: indicates the latest versions of all metadata (except timestamp).
|
||||
SNAPSHOT_SCHEMA = SCHEMA.Object(
|
||||
object_name = 'SNAPSHOT_SCHEMA',
|
||||
_type = SCHEMA.String('Snapshot'),
|
||||
version = METADATAVERSION_SCHEMA,
|
||||
expires = TIME_SCHEMA,
|
||||
meta = FILEDICT_SCHEMA)
|
||||
|
||||
# Timestamp role: indicates the latest version of the release file.
|
||||
# Timestamp role: indicates the latest version of the snapshot file.
|
||||
TIMESTAMP_SCHEMA = SCHEMA.Object(
|
||||
object_name = 'TIMESTAMP_SCHEMA',
|
||||
_type = SCHEMA.String('Timestamp'),
|
||||
|
|
@ -450,8 +450,8 @@
|
|||
expires = TIME_SCHEMA,
|
||||
mirrors = SCHEMA.ListOf(MIRROR_SCHEMA))
|
||||
|
||||
# Any of the role schemas (e.g., TIMESTAMP_SCHEMA, RELEASE_SCHEMA, etc.)
|
||||
ANYROLE_SCHEMA = SCHEMA.OneOf([ROOT_SCHEMA, TARGETS_SCHEMA, RELEASE_SCHEMA,
|
||||
# Any of the role schemas (e.g., TIMESTAMP_SCHEMA, SNAPSHOT_SCHEMA, etc.)
|
||||
ANYROLE_SCHEMA = SCHEMA.OneOf([ROOT_SCHEMA, TARGETS_SCHEMA, SNAPSHOT_SCHEMA,
|
||||
TIMESTAMP_SCHEMA, MIRROR_SCHEMA])
|
||||
|
||||
|
||||
|
|
@ -463,7 +463,7 @@ class MetaFile(object):
|
|||
<Purpose>
|
||||
Base class for all metadata file classes.
|
||||
Classes representing metadata files such as RootFile
|
||||
and ReleaseFile all inherit from MetaFile. The
|
||||
and SnapshotFile all inherit from MetaFile. The
|
||||
__eq__, __ne__, perform 'equal' and 'not equal' comparisons
|
||||
between Metadata File objects.
|
||||
"""
|
||||
|
|
@ -531,13 +531,13 @@ def make_metadata(version, expiration_date, filedict):
|
|||
|
||||
|
||||
class RootFile(MetaFile):
|
||||
def __init__(self, version, expires, keys, roles, consistent_snapshots):
|
||||
def __init__(self, version, expires, keys, roles, consistent_snapshot):
|
||||
self.info = {}
|
||||
self.info['version'] = version
|
||||
self.info['expires'] = expires
|
||||
self.info['keys'] = keys
|
||||
self.info['roles'] = roles
|
||||
self.info['consistent_snapshots'] = consistent_snapshots
|
||||
self.info['consistent_snapshot'] = consistent_snapshot
|
||||
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -550,20 +550,20 @@ def from_metadata(object):
|
|||
expires = parse_time(object['expires'])
|
||||
keys = object['keys']
|
||||
roles = object['roles']
|
||||
consistent_snapshots = object['consistent_snapshots']
|
||||
consistent_snapshot = object['consistent_snapshot']
|
||||
|
||||
return RootFile(version, expires, keys, roles, consistent_snapshots)
|
||||
return RootFile(version, expires, keys, roles, consistent_snapshot)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def make_metadata(version, expiration_date, keydict, roledict,
|
||||
consistent_snapshots):
|
||||
consistent_snapshot):
|
||||
result = {'_type' : 'Root'}
|
||||
result['version'] = version
|
||||
result['expires'] = expiration_date
|
||||
result['keys'] = keydict
|
||||
result['roles'] = roledict
|
||||
result['consistent_snapshots'] = consistent_snapshots
|
||||
result['consistent_snapshot'] = consistent_snapshot
|
||||
|
||||
# Is 'result' a Root metadata file?
|
||||
# Raise 'tuf.FormatError' if not.
|
||||
|
|
@ -575,7 +575,7 @@ def make_metadata(version, expiration_date, keydict, roledict,
|
|||
|
||||
|
||||
|
||||
class ReleaseFile(MetaFile):
|
||||
class SnapshotFile(MetaFile):
|
||||
def __init__(self, version, expires, filedict):
|
||||
self.info = {}
|
||||
self.info['version'] = version
|
||||
|
|
@ -585,27 +585,27 @@ def __init__(self, version, expires, filedict):
|
|||
|
||||
@staticmethod
|
||||
def from_metadata(object):
|
||||
# Is 'object' a Release metadata file?
|
||||
# Is 'object' a Snapshot metadata file?
|
||||
# Raise 'tuf.FormatError' if not.
|
||||
RELEASE_SCHEMA.check_match(object)
|
||||
SNAPSHOT_SCHEMA.check_match(object)
|
||||
|
||||
version = object['version']
|
||||
expires = parse_time(object['expires'])
|
||||
filedict = object['meta']
|
||||
|
||||
return ReleaseFile(version, expires, filedict)
|
||||
return SnapshotFile(version, expires, filedict)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def make_metadata(version, expiration_date, filedict):
|
||||
result = {'_type' : 'Release'}
|
||||
result = {'_type' : 'Snapshot'}
|
||||
result['version'] = version
|
||||
result['expires'] = expiration_date
|
||||
result['meta'] = filedict
|
||||
|
||||
# Is 'result' a Release metadata file?
|
||||
# Is 'result' a Snapshot metadata file?
|
||||
# Raise 'tuf.FormatError' if not.
|
||||
RELEASE_SCHEMA.check_match(result)
|
||||
SNAPSHOT_SCHEMA.check_match(result)
|
||||
|
||||
return result
|
||||
|
||||
|
|
@ -687,7 +687,7 @@ def make_metadata():
|
|||
SCHEMAS_BY_TYPE = {
|
||||
'Root' : ROOT_SCHEMA,
|
||||
'Targets' : TARGETS_SCHEMA,
|
||||
'Release' : RELEASE_SCHEMA,
|
||||
'Snapshot' : SNAPSHOT_SCHEMA,
|
||||
'Timestamp' : TIMESTAMP_SCHEMA,
|
||||
'Mirrors' : MIRRORLIST_SCHEMA}
|
||||
|
||||
|
|
@ -696,7 +696,7 @@ def make_metadata():
|
|||
ROLE_CLASSES_BY_TYPE = {
|
||||
'Root' : RootFile,
|
||||
'Targets' : TargetsFile,
|
||||
'Release' : ReleaseFile,
|
||||
'Snapshot' : SnapshotFile,
|
||||
'Timestamp' : TimestampFile,
|
||||
'Mirrors' : MirrorsFile}
|
||||
|
||||
|
|
@ -858,7 +858,7 @@ def make_signable(object):
|
|||
|
||||
<Arguments>
|
||||
object:
|
||||
A role schema dict (e.g., 'ROOT_SCHEMA', 'RELEASE_SCHEMA').
|
||||
A role schema dict (e.g., 'ROOT_SCHEMA', 'SNAPSHOT_SCHEMA').
|
||||
|
||||
<Exceptions>
|
||||
None.
|
||||
|
|
@ -1022,8 +1022,8 @@ def get_role_class(expected_rolename):
|
|||
|
||||
<Returns>
|
||||
The class corresponding to 'expected_rolename'.
|
||||
E.g., 'Release' as an argument to this function causes
|
||||
'ReleaseFile' to be returned.
|
||||
E.g., 'Snapshot' as an argument to this function causes
|
||||
SnapshotFile' to be returned.
|
||||
"""
|
||||
|
||||
# Does 'expected_rolename' have the correct type?
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ def download_target(self, target_filepath):
|
|||
|
||||
# Locate the fileinfo of 'target_filepath'. updater.target() searches
|
||||
# Targets metadata in order of trust, according to the currently trusted
|
||||
# release. To prevent consecutive target file requests from referring to
|
||||
# different releases, top-level metadata is not automatically refreshed.
|
||||
# snapshot. To prevent consecutive target file requests from referring to
|
||||
# different snapshots, top-level metadata is not automatically refreshed.
|
||||
targets = [self.updater.target(target_filepath)]
|
||||
|
||||
# TODO: targets are always updated if destination directory is new, right?
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
<Purpose>
|
||||
To extract a list of mirror urls corresponding to the file type and
|
||||
the location of the file with respect to the base url.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
|
@ -55,7 +54,7 @@ def get_list_of_mirrors(file_type, file_path, mirrors_dict):
|
|||
{'url_prefix': 'http://localhost:8001',
|
||||
'metadata_path': 'metadata/',
|
||||
'targets_path': 'targets/',
|
||||
'confined_target_dirs': ['targets/release1/', ...],
|
||||
'confined_target_dirs': ['targets/snapshot1/', ...],
|
||||
'custom': {...}}
|
||||
|
||||
The 'custom' field is optional.
|
||||
|
|
@ -68,7 +67,6 @@ def get_list_of_mirrors(file_type, file_path, mirrors_dict):
|
|||
<Return>
|
||||
List of mirror urls corresponding to the file_type and file_path. If no
|
||||
match is found, empty list is returned.
|
||||
|
||||
"""
|
||||
|
||||
# Checking if all the arguments have appropriate format.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
# The metadata filenames for the top-level roles.
|
||||
ROOT_FILENAME = 'root.txt'
|
||||
TARGETS_FILENAME = 'targets.txt'
|
||||
RELEASE_FILENAME = 'release.txt'
|
||||
SNAPSHOT_FILENAME = 'snapshot.txt'
|
||||
TIMESTAMP_FILENAME = 'timestamp.txt'
|
||||
|
||||
# The filename for the repository configuration file.
|
||||
|
|
@ -183,7 +183,7 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
|
||||
filenames = {'root': 'metadata/root.txt',
|
||||
'targets': 'metadata/targets.txt',
|
||||
'release': 'metadata/release.txt',
|
||||
'snapshot': 'metadata/snapshot.txt',
|
||||
'timestamp': 'metadata/timestamp.txt'}
|
||||
|
||||
If the metadata directory is not set by the caller, the current
|
||||
|
|
@ -201,7 +201,7 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
|
||||
<Returns>
|
||||
A dictionary containing the expected filenames of the top-level
|
||||
metadata files, such as 'root.txt' and 'release.txt'.
|
||||
metadata files, such as 'root.txt' and 'snapshot.txt'.
|
||||
"""
|
||||
|
||||
if metadata_directory is None:
|
||||
|
|
@ -214,7 +214,7 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
filenames = {}
|
||||
filenames['root'] = os.path.join(metadata_directory, ROOT_FILENAME)
|
||||
filenames['targets'] = os.path.join(metadata_directory, TARGETS_FILENAME)
|
||||
filenames['release'] = os.path.join(metadata_directory, RELEASE_FILENAME)
|
||||
filenames['snapshot'] = os.path.join(metadata_directory, SNAPSHOT_FILENAME)
|
||||
filenames['timestamp'] = os.path.join(metadata_directory, TIMESTAMP_FILENAME)
|
||||
|
||||
return filenames
|
||||
|
|
@ -268,7 +268,7 @@ def generate_root_metadata(config_filepath, version):
|
|||
|
||||
# Extract the role, threshold, and keyid information from the config.
|
||||
# The necessary role metadata is generated from this information.
|
||||
for rolename in ['root', 'targets', 'release', 'timestamp']:
|
||||
for rolename in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
# If a top-level role is missing from the config, raise an exception.
|
||||
if rolename not in config:
|
||||
raise tuf.Error('No '+rolename+' section found in config file.')
|
||||
|
|
@ -312,7 +312,7 @@ def generate_root_metadata(config_filepath, version):
|
|||
# Generate the root metadata object.
|
||||
expiration_date = tuf.formats.format_time(time.time()+expiration_seconds)
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version, expiration_date,
|
||||
keydict, roledict)
|
||||
keydict, roledict, False)
|
||||
|
||||
# Note: make_signable() returns the following dictionary:
|
||||
# {'signed' : role_metadata, 'signatures' : []}
|
||||
|
|
@ -399,13 +399,13 @@ def generate_targets_metadata(repository_directory, target_files, version,
|
|||
|
||||
|
||||
|
||||
def generate_release_metadata(metadata_directory, version, expiration_date):
|
||||
def generate_snapshot_metadata(metadata_directory, version, expiration_date):
|
||||
"""
|
||||
<Purpose>
|
||||
Create the release metadata. The minimum metadata must exist
|
||||
Create the snapshot metadata. The minimum metadata must exist
|
||||
(i.e., 'root.txt' and 'targets.txt'). This will also look through
|
||||
the 'targets/' directory in 'metadata_directory' and the resulting
|
||||
release file will list all the delegated roles.
|
||||
snapshot file will list all the delegated roles.
|
||||
|
||||
<Arguments>
|
||||
metadata_directory:
|
||||
|
|
@ -423,14 +423,14 @@ def generate_release_metadata(metadata_directory, version, expiration_date):
|
|||
<Exceptions>
|
||||
tuf.FormatError, if 'metadata_directory' is improperly formatted.
|
||||
|
||||
tuf.Error, if an error occurred trying to generate the release metadata
|
||||
tuf.Error, if an error occurred trying to generate the snapshot metadata
|
||||
object.
|
||||
|
||||
<Side Effects>
|
||||
The 'root.txt' and 'targets.txt' files are read.
|
||||
|
||||
<Returns>
|
||||
The release 'signable' object, conformant to 'tuf.formats.SIGNABLE_SCHEMA'.
|
||||
The snapshot 'signable' object, conformant to 'tuf.formats.SIGNABLE_SCHEMA'.
|
||||
"""
|
||||
|
||||
# Does 'metadata_directory' have the correct format?
|
||||
|
|
@ -453,7 +453,7 @@ def generate_release_metadata(metadata_directory, version, expiration_date):
|
|||
|
||||
# Walk the 'targets/' directory and generate the file info for all
|
||||
# the files listed there. This information is stored in the 'meta'
|
||||
# field of the release metadata object.
|
||||
# field of the snapshot metadata object.
|
||||
targets_metadata = os.path.join(metadata_directory, 'targets')
|
||||
if os.path.exists(targets_metadata) and os.path.isdir(targets_metadata):
|
||||
for directory_path, junk, files in os.walk(targets_metadata):
|
||||
|
|
@ -463,26 +463,26 @@ def generate_release_metadata(metadata_directory, version, expiration_date):
|
|||
metadata_name = metadata_path[len(metadata_directory):].lstrip(os.path.sep)
|
||||
filedict[metadata_name] = get_metadata_file_info(metadata_path)
|
||||
|
||||
# Generate the release metadata object.
|
||||
release_metadata = tuf.formats.ReleaseFile.make_metadata(version,
|
||||
expiration_date,
|
||||
filedict)
|
||||
# Generate the snapshot metadata object.
|
||||
snapshot_metadata = tuf.formats.SnapshotFile.make_metadata(version,
|
||||
expiration_date,
|
||||
filedict)
|
||||
|
||||
return tuf.formats.make_signable(release_metadata)
|
||||
return tuf.formats.make_signable(snapshot_metadata)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def generate_timestamp_metadata(release_filename, version,
|
||||
def generate_timestamp_metadata(snapshot_filename, version,
|
||||
expiration_date, compressions=()):
|
||||
"""
|
||||
<Purpose>
|
||||
Generate the timestamp metadata object. The 'release.txt' file must exist.
|
||||
Generate the timestamp metadata object. The 'snapshot.txt' file must exist.
|
||||
|
||||
<Arguments>
|
||||
release_filename:
|
||||
The required filename of the release metadata file.
|
||||
snapshot_filename:
|
||||
The required filename of the snapshot metadata file.
|
||||
|
||||
version:
|
||||
The metadata version number. Clients use the version number to
|
||||
|
|
@ -493,7 +493,7 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
Conformant to 'tuf.formats.TIME_SCHEMA'.
|
||||
|
||||
compressions:
|
||||
Compression extensions (e.g., 'gz'). If 'release.txt' is also saved in
|
||||
Compression extensions (e.g., 'gz'). If 'snapshot.txt' is also saved in
|
||||
compressed form, these compression extensions should be stored in
|
||||
'compressions' so the compressed timestamp files can be added to the
|
||||
timestamp metadata object.
|
||||
|
|
@ -511,25 +511,25 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
|
||||
# Do the arguments have the correct format?
|
||||
# Raise 'tuf.FormatError' if there is mismatch.
|
||||
tuf.formats.PATH_SCHEMA.check_match(release_filename)
|
||||
tuf.formats.PATH_SCHEMA.check_match(snapshot_filename)
|
||||
tuf.formats.METADATAVERSION_SCHEMA.check_match(version)
|
||||
tuf.formats.TIME_SCHEMA.check_match(expiration_date)
|
||||
|
||||
# Retrieve the file info for the release metadata file.
|
||||
# Retrieve the file info for the snapshot metadata file.
|
||||
# This file information contains hashes, file length, custom data, etc.
|
||||
fileinfo = {}
|
||||
fileinfo['release.txt'] = get_metadata_file_info(release_filename)
|
||||
fileinfo['snapshot.txt'] = get_metadata_file_info(snapshot_filename)
|
||||
|
||||
# Save the file info of the compressed versions of 'timestamp.txt'.
|
||||
for file_extension in compressions:
|
||||
compressed_filename = release_filename + '.' + file_extension
|
||||
compressed_filename = snapshot_filename + '.' + file_extension
|
||||
try:
|
||||
compressed_fileinfo = get_metadata_file_info(compressed_filename)
|
||||
except:
|
||||
logger.warn('Could not get fileinfo about '+str(compressed_filename))
|
||||
else:
|
||||
logger.info('Including fileinfo about '+str(compressed_filename))
|
||||
fileinfo['release.txt.' + file_extension] = compressed_fileinfo
|
||||
fileinfo['snapshot.txt.' + file_extension] = compressed_fileinfo
|
||||
|
||||
# Generate the timestamp metadata object.
|
||||
timestamp_metadata = tuf.formats.TimestampFile.make_metadata(version,
|
||||
|
|
@ -893,7 +893,7 @@ def get_target_keyids(metadata_directory):
|
|||
|
||||
# Walk the 'targets/' directory and generate the file info for all
|
||||
# the targets. This information is stored in the 'meta' field of
|
||||
# the release metadata object. The keyids for the optional
|
||||
# the snapshot metadata object. The keyids for the optional
|
||||
# delegated roles will now be extracted.
|
||||
targets_metadata = os.path.join(metadata_directory, 'targets')
|
||||
if os.path.exists(targets_metadata) and os.path.isdir(targets_metadata):
|
||||
|
|
@ -969,7 +969,7 @@ def build_config_file(config_file_directory, timeout, role_info):
|
|||
|
||||
# Verify that only the top-level roles are presented.
|
||||
for role in role_info.keys():
|
||||
if role not in ['root', 'targets', 'release', 'timestamp']:
|
||||
if role not in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
msg = ('\nCannot build configuration file: role '+repr(role)+
|
||||
' is not a top-level role.')
|
||||
raise tuf.Error(msg)
|
||||
|
|
@ -1158,19 +1158,19 @@ def build_targets_file(target_paths, targets_keyids, metadata_directory,
|
|||
|
||||
|
||||
|
||||
def build_release_file(release_keyids, metadata_directory,
|
||||
def build_snapshot_file(snapshot_keyids, metadata_directory,
|
||||
version, expiration_date, compress=False):
|
||||
"""
|
||||
<Purpose>
|
||||
Build the release metadata file using the signing keys in 'release_keyids'.
|
||||
Build the snapshot metadata file using the signing keys in 'snapshot_keyids'.
|
||||
The generated metadata file is saved in 'metadata_directory'.
|
||||
|
||||
<Arguments>
|
||||
release_keyids:
|
||||
The list of keyids to be used as the signing keys for the release file.
|
||||
snapshot_keyids:
|
||||
The list of keyids to be used as the signing keys for the snapshot file.
|
||||
|
||||
metadata_directory:
|
||||
The directory (absolute path) to save the release metadata file.
|
||||
The directory (absolute path) to save the snapshot metadata file.
|
||||
|
||||
version:
|
||||
The metadata version number. Clients use the version number to
|
||||
|
|
@ -1181,48 +1181,48 @@ def build_release_file(release_keyids, metadata_directory,
|
|||
Conformant to 'tuf.formats.TIME_SCHEMA'.
|
||||
|
||||
compress:
|
||||
Should we *include* a compressed version of the release file? By default,
|
||||
Should we *include* a compressed version of the snapshot file? By default,
|
||||
the answer is no.
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if any of the arguments are improperly formatted.
|
||||
|
||||
tuf.Error, if there was an error while building the release file.
|
||||
tuf.Error, if there was an error while building the snapshot file.
|
||||
|
||||
<Side Effects>
|
||||
The release metadata file is written to a file.
|
||||
The snapshot metadata file is written to a file.
|
||||
|
||||
<Returns>
|
||||
The path for the written release metadata file.
|
||||
The path for the written snapshot metadata file.
|
||||
"""
|
||||
|
||||
# Do the arguments have the correct format?
|
||||
# Raise 'tuf.FormatError' if there is a mismatch.
|
||||
tuf.formats.KEYIDS_SCHEMA.check_match(release_keyids)
|
||||
tuf.formats.KEYIDS_SCHEMA.check_match(snapshot_keyids)
|
||||
tuf.formats.PATH_SCHEMA.check_match(metadata_directory)
|
||||
tuf.formats.METADATAVERSION_SCHEMA.check_match(version)
|
||||
tuf.formats.TIME_SCHEMA.check_match(expiration_date)
|
||||
|
||||
metadata_directory = check_directory(metadata_directory)
|
||||
|
||||
# Generate the file path of the release metadata.
|
||||
release_filepath = os.path.join(metadata_directory, RELEASE_FILENAME)
|
||||
# Generate the file path of the snapshot metadata.
|
||||
snapshot_filepath = os.path.join(metadata_directory, SNAPSHOT_FILENAME)
|
||||
|
||||
# Generate and sign the release metadata.
|
||||
release_metadata = generate_release_metadata(metadata_directory,
|
||||
# Generate and sign the snapshot metadata.
|
||||
snapshot_metadata = generate_snapshot_metadata(metadata_directory,
|
||||
version, expiration_date)
|
||||
signable = sign_metadata(release_metadata, release_keyids, release_filepath)
|
||||
signable = sign_metadata(snapshot_metadata, snapshot_keyids, snapshot_filepath)
|
||||
|
||||
# Should we also include a compressed version of release.txt?
|
||||
# Should we also include a compressed version of snapshot.txt?
|
||||
if compress:
|
||||
# If so, write a gzip version of release.txt.
|
||||
# If so, write a gzip version of snapshot.txt.
|
||||
compressed_written_filepath = \
|
||||
write_metadata_file(signable, release_filepath, compression='gz')
|
||||
write_metadata_file(signable, snapshot_filepath, compression='gz')
|
||||
logger.info('Wrote '+str(compressed_written_filepath))
|
||||
else:
|
||||
logger.debug('No compressed version of release metadata will be included.')
|
||||
logger.debug('No compressed version of snapshot metadata will be included.')
|
||||
|
||||
written_filepath = write_metadata_file(signable, release_filepath)
|
||||
written_filepath = write_metadata_file(signable, snapshot_filepath)
|
||||
logger.info('Wrote '+str(written_filepath))
|
||||
|
||||
return written_filepath
|
||||
|
|
@ -1233,7 +1233,7 @@ def build_release_file(release_keyids, metadata_directory,
|
|||
|
||||
def build_timestamp_file(timestamp_keyids, metadata_directory,
|
||||
version, expiration_date,
|
||||
include_compressed_release=True):
|
||||
include_compressed_snapshot=True):
|
||||
"""
|
||||
<Purpose>
|
||||
Build the timestamp metadata file using the signing keys in 'timestamp_keyids'.
|
||||
|
|
@ -1254,8 +1254,8 @@ def build_timestamp_file(timestamp_keyids, metadata_directory,
|
|||
The expiration date, in UTC, of the metadata file.
|
||||
Conformant to 'tuf.formats.TIME_SCHEMA'.
|
||||
|
||||
include_compressed_release:
|
||||
Should the timestamp role *include* compression versions of the release
|
||||
include_compressed_snapshot:
|
||||
Should the timestamp role *include* compression versions of the snapshot
|
||||
metadata, if any? We do this by default.
|
||||
|
||||
<Exceptions>
|
||||
|
|
@ -1279,23 +1279,23 @@ def build_timestamp_file(timestamp_keyids, metadata_directory,
|
|||
|
||||
metadata_directory = check_directory(metadata_directory)
|
||||
|
||||
# Generate the file path of the release and timestamp metadata.
|
||||
release_filepath = os.path.join(metadata_directory, RELEASE_FILENAME)
|
||||
# Generate the file path of the snapshot and timestamp metadata.
|
||||
snapshot_filepath = os.path.join(metadata_directory, SNAPSHOT_FILENAME)
|
||||
timestamp_filepath = os.path.join(metadata_directory, TIMESTAMP_FILENAME)
|
||||
|
||||
# Should we include compressed versions of release in timestamp?
|
||||
# Should we include compressed versions of snapshot in timestamp?
|
||||
compressions = ()
|
||||
if include_compressed_release:
|
||||
if include_compressed_snapshot:
|
||||
# Presently, we include only gzip versions by default.
|
||||
compressions = ('gz',)
|
||||
logger.info('Including '+str(compressions)+' versions of release in '\
|
||||
logger.info('Including '+str(compressions)+' versions of snapshot in '\
|
||||
'timestamp.')
|
||||
else:
|
||||
logger.warn('No compressed versions of release will be included in '\
|
||||
logger.warn('No compressed versions of snapshot will be included in '\
|
||||
'timestamp.')
|
||||
|
||||
# Generate and sign the timestamp metadata.
|
||||
timestamp_metadata = generate_timestamp_metadata(release_filepath,
|
||||
timestamp_metadata = generate_timestamp_metadata(snapshot_filepath,
|
||||
version,
|
||||
expiration_date,
|
||||
compressions=compressions)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
# The metadata filenames of the top-level roles.
|
||||
ROOT_FILENAME = 'root' + METADATA_EXTENSION
|
||||
TARGETS_FILENAME = 'targets' + METADATA_EXTENSION
|
||||
RELEASE_FILENAME = 'release' + METADATA_EXTENSION
|
||||
SNAPSHOT_FILENAME = 'snapshot' + METADATA_EXTENSION
|
||||
TIMESTAMP_FILENAME = 'timestamp' + METADATA_EXTENSION
|
||||
|
||||
# The targets and metadata directory names. Metadata files are written
|
||||
|
|
@ -94,8 +94,8 @@
|
|||
# Initial 'targets.json' expiration time of 3 months.
|
||||
TARGETS_EXPIRATION = 7889230
|
||||
|
||||
# Initial 'release.json' expiration time of 1 week.
|
||||
RELEASE_EXPIRATION = 604800
|
||||
# Initial 'snapshot.json' expiration time of 1 week.
|
||||
SNAPSHOT_EXPIRATION = 604800
|
||||
|
||||
# Initial 'timestamp.json' expiration time of 1 day.
|
||||
TIMESTAMP_EXPIRATION = 86400
|
||||
|
|
@ -113,13 +113,13 @@ class Repository(object):
|
|||
|
||||
repository.root.version = 2
|
||||
repository.timestamp.expiration = "2015-08-08 12:00:00"
|
||||
repository.release.add_key(...)
|
||||
repository.snapshot.add_verification_key(...)
|
||||
repository.targets.delegate('unclaimed', ...)
|
||||
|
||||
Delegating a role from 'targets' updates the attributes of the parent
|
||||
delegation, which then provides:
|
||||
|
||||
repository.targets('unclaimed').add_key(...)
|
||||
repository.targets('unclaimed').add_verification_key(...)
|
||||
|
||||
|
||||
<Arguments>
|
||||
|
|
@ -165,13 +165,13 @@ def __init__(self, repository_directory, metadata_directory, targets_directory):
|
|||
|
||||
# Set the top-level role objects.
|
||||
self.root = Root()
|
||||
self.release = Release()
|
||||
self.snapshot = Snapshot()
|
||||
self.timestamp = Timestamp()
|
||||
self.targets = Targets(self._targets_directory, 'targets')
|
||||
|
||||
|
||||
|
||||
def write(self, write_partial=False, consistent_snapshots=False):
|
||||
def write(self, write_partial=False, consistent_snapshot=False):
|
||||
"""
|
||||
<Purpose>
|
||||
Write all the JSON Metadata objects to their corresponding files.
|
||||
|
|
@ -187,7 +187,7 @@ def write(self, write_partial=False, consistent_snapshots=False):
|
|||
exception if a metadata role cannot be written due to not having enough
|
||||
signatures.
|
||||
|
||||
consistent_snapshots:
|
||||
consistent_snapshot:
|
||||
A boolean indicating whether written metadata and target files should
|
||||
include a digest in the filename (i.e., <digest>.root.json,
|
||||
<digest>.targets.json.gz, <digest>.README.json, where <digest> is the
|
||||
|
|
@ -211,7 +211,7 @@ def write(self, write_partial=False, consistent_snapshots=False):
|
|||
# types, and that all dict keys are properly named.
|
||||
# Raise 'tuf.FormatError' if any are improperly formatted.
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(write_partial)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshots)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshot)
|
||||
|
||||
# At this point the tuf.keydb and tuf.roledb stores must be fully
|
||||
# populated, otherwise write() throwns a 'tuf.Repository' exception if
|
||||
|
|
@ -243,7 +243,7 @@ def write(self, write_partial=False, consistent_snapshots=False):
|
|||
_generate_and_write_metadata(delegated_rolename, delegated_filename,
|
||||
write_partial, self._targets_directory,
|
||||
self._metadata_directory,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
# Generate the 'root.json' metadata file.
|
||||
# _generate_and_write_metadata() raises a 'tuf.Error' exception if the
|
||||
|
|
@ -254,7 +254,7 @@ def write(self, write_partial=False, consistent_snapshots=False):
|
|||
_generate_and_write_metadata('root', root_filename, write_partial,
|
||||
self._targets_directory,
|
||||
self._metadata_directory,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
# Generate the 'targets.json' metadata file.
|
||||
targets_filename = 'targets' + METADATA_EXTENSION
|
||||
|
|
@ -263,32 +263,32 @@ def write(self, write_partial=False, consistent_snapshots=False):
|
|||
_generate_and_write_metadata('targets', targets_filename, write_partial,
|
||||
self._targets_directory,
|
||||
self._metadata_directory,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
# Generate the 'release.json' metadata file.
|
||||
release_filename = os.path.join(self._metadata_directory, 'release')
|
||||
release_filename = 'release' + METADATA_EXTENSION
|
||||
release_filename = os.path.join(self._metadata_directory, release_filename)
|
||||
# Generate the 'snapshot.json' metadata file.
|
||||
snapshot_filename = os.path.join(self._metadata_directory, 'snapshot')
|
||||
snapshot_filename = 'snapshot' + METADATA_EXTENSION
|
||||
snapshot_filename = os.path.join(self._metadata_directory, snapshot_filename)
|
||||
filenames = {'root': root_filename, 'targets': targets_filename}
|
||||
release_signable, release_filename = \
|
||||
_generate_and_write_metadata('release', release_filename, write_partial,
|
||||
snapshot_signable, snapshot_filename = \
|
||||
_generate_and_write_metadata('snapshot', snapshot_filename, write_partial,
|
||||
self._targets_directory,
|
||||
self._metadata_directory,
|
||||
consistent_snapshots, filenames)
|
||||
consistent_snapshot, filenames)
|
||||
|
||||
# Generate the 'timestamp.json' metadata file.
|
||||
timestamp_filename = 'timestamp' + METADATA_EXTENSION
|
||||
timestamp_filename = os.path.join(self._metadata_directory, timestamp_filename)
|
||||
filenames = {'release': release_filename}
|
||||
filenames = {'snapshot': snapshot_filename}
|
||||
_generate_and_write_metadata('timestamp', timestamp_filename, write_partial,
|
||||
self._targets_directory,
|
||||
self._metadata_directory, consistent_snapshots,
|
||||
self._metadata_directory, consistent_snapshot,
|
||||
filenames)
|
||||
|
||||
# Delete the metadata of roles no longer in 'tuf.roledb'. Obsolete roles
|
||||
# may have been revoked.
|
||||
_delete_obsolete_metadata(self._metadata_directory,
|
||||
release_signable['signed'], consistent_snapshots)
|
||||
snapshot_signable['signed'], consistent_snapshot)
|
||||
|
||||
|
||||
|
||||
|
|
@ -319,12 +319,13 @@ def status(self):
|
|||
"""
|
||||
<Purpose>
|
||||
Determine the status of the top-level roles, including those delegated by
|
||||
the targets role. status() checks if each role provides sufficient public
|
||||
keys, signatures, and that a valid metadata file is generated if write()
|
||||
were to be called. Metadata files are temporary written to check that
|
||||
proper metadata files are written, where file hashes and lengths are
|
||||
calculated and referenced by the top-level roles. status() does not do a
|
||||
simple check for number of threshold keys and signatures.
|
||||
the Targets role. status() checks if each role provides sufficient public
|
||||
and private keys, signatures, and that a valid metadata file is generated
|
||||
if write() were to be called. Metadata files are temporarily written so
|
||||
that file hashes and lengths may be verified, determine if delegated role
|
||||
trust is fully obeyed, and target paths valid according to parent roles.
|
||||
status() does not do a simple check for number of threshold keys and
|
||||
signatures.
|
||||
|
||||
<Arguments>
|
||||
None.
|
||||
|
|
@ -478,7 +479,7 @@ class Metadata(object):
|
|||
"""
|
||||
<Purpose>
|
||||
Provide a base class to represent a TUF Metadata role. There are four
|
||||
top-level roles: Root, Targets, Release, and Timestamp. The Metadata class
|
||||
top-level roles: Root, Targets, Snapshot, and Timestamp. The Metadata class
|
||||
provides methods that are needed by all top-level roles, such as adding
|
||||
and removing public keys, private keys, and signatures. Metadata
|
||||
attributes, such as rolename, version, threshold, expiration, key list, and
|
||||
|
|
@ -502,7 +503,7 @@ def __init__(self):
|
|||
|
||||
|
||||
|
||||
def add_key(self, key):
|
||||
def add_verification_key(self, key):
|
||||
"""
|
||||
<Purpose>
|
||||
Add 'key' to the role. Adding a key, which should contain only the public
|
||||
|
|
@ -556,7 +557,7 @@ def add_key(self, key):
|
|||
|
||||
|
||||
|
||||
def remove_key(self, key):
|
||||
def remove_verification_key(self, key):
|
||||
"""
|
||||
<Purpose>
|
||||
Remove 'key' from the role's currently recognized list of role keys.
|
||||
|
|
@ -570,7 +571,7 @@ def remove_key(self, key):
|
|||
key:
|
||||
The role's key, conformant to 'tuf.formats.ANYKEY_SCHEMA'. 'key'
|
||||
should contain the only the public portion, as only the public key
|
||||
is needed. The 'add_key()' method should have previously added 'key'.
|
||||
is needed. The 'add_verification_key()' method should have previously added 'key'.
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if the 'key' argument is improperly formatted.
|
||||
|
|
@ -792,7 +793,7 @@ def signatures(self):
|
|||
A getter method that returns the role's signatures. A role is considered
|
||||
fully signed if it contains a threshold number of signatures, where each
|
||||
signature must be provided by the generated by the private key. Keys
|
||||
are added to a role with the add_key() method.
|
||||
are added to a role with the add_verification_key() method.
|
||||
|
||||
<Arguments>
|
||||
None.
|
||||
|
|
@ -1245,12 +1246,12 @@ def __init__(self):
|
|||
|
||||
self._rolename = 'root'
|
||||
|
||||
# By default, 'release' metadata is set to expire 1 week from the current
|
||||
# By default, 'snapshot' metadata is set to expire 1 week from the current
|
||||
# time. The expiration may be modified.
|
||||
expiration = tuf.formats.format_time(time.time()+ROOT_EXPIRATION)
|
||||
|
||||
roleinfo = {'keyids': [], 'signing_keyids': [], 'threshold': 1,
|
||||
'signatures': [], 'version': 0, 'consistent_snapshots': False,
|
||||
'signatures': [], 'version': 0, 'consistent_snapshot': False,
|
||||
'compressions': [''], 'expires': expiration,
|
||||
'partial_loaded': False}
|
||||
try:
|
||||
|
|
@ -1266,7 +1267,7 @@ class Timestamp(Metadata):
|
|||
"""
|
||||
<Purpose>
|
||||
Represent a Timestamp role object. The timestamp role is responsible for
|
||||
referencing the latest version of the Release role. Under normal
|
||||
referencing the latest version of the Snapshot role. Under normal
|
||||
conditions, it is the only role to be downloaded from a remote repository
|
||||
without a known file length and hash. An upper length limit is set, though.
|
||||
Also, its signatures are also verified to be valid according to the Root
|
||||
|
|
@ -1278,7 +1279,7 @@ class Timestamp(Metadata):
|
|||
This Timestamp object sub-classes Metadata, so the expected Metadata
|
||||
operations like adding/removing public keys, signatures, private keys, and
|
||||
updating metadata attributes (e.g., version and expiration) is supported.
|
||||
Since Release is a top-level role and must exist, a default Timestamp object
|
||||
Since Snapshot is a top-level role and must exist, a default Timestamp object
|
||||
is instantiated when a new Repository object is created.
|
||||
|
||||
>>>
|
||||
|
|
@ -1304,7 +1305,7 @@ def __init__(self):
|
|||
|
||||
self._rolename = 'timestamp'
|
||||
|
||||
# By default, 'release' metadata is set to expire 1 week from the current
|
||||
# By default, 'snapshot' metadata is set to expire 1 week from the current
|
||||
# time. The expiration may be modified.
|
||||
expiration = tuf.formats.format_time(time.time()+TIMESTAMP_EXPIRATION)
|
||||
|
||||
|
|
@ -1321,18 +1322,18 @@ def __init__(self):
|
|||
|
||||
|
||||
|
||||
class Release(Metadata):
|
||||
class Snapshot(Metadata):
|
||||
"""
|
||||
<Purpose>
|
||||
Represent a Release role object. The release role is responsible for
|
||||
Represent a Snapshot role object. The snapshot role is responsible for
|
||||
referencing the other top-level roles (excluding Timestamp) and all
|
||||
delegated roles.
|
||||
|
||||
This Release object sub-classes Metadata, so the expected
|
||||
This Snapshot object sub-classes Metadata, so the expected
|
||||
Metadata operations like adding/removing public keys, signatures, private
|
||||
keys, and updating metadata attributes (e.g., version and expiration) is
|
||||
supported. Since Release is a top-level role and must exist, a default
|
||||
Release object is instantiated when a new Repository object is created.
|
||||
supported. Since Snapshot is a top-level role and must exist, a default
|
||||
Snapshot object is instantiated when a new Repository object is created.
|
||||
|
||||
>>>
|
||||
>>>
|
||||
|
|
@ -1345,7 +1346,7 @@ class Release(Metadata):
|
|||
None.
|
||||
|
||||
<Side Effects>
|
||||
A 'release' role is added to 'tuf.roledb.py'.
|
||||
A 'snapshot' role is added to 'tuf.roledb.py'.
|
||||
|
||||
<Returns>
|
||||
None.
|
||||
|
|
@ -1353,13 +1354,13 @@ class Release(Metadata):
|
|||
|
||||
def __init__(self):
|
||||
|
||||
super(Release, self).__init__()
|
||||
super(Snapshot, self).__init__()
|
||||
|
||||
self._rolename = 'release'
|
||||
self._rolename = 'snapshot'
|
||||
|
||||
# By default, 'release' metadata is set to expire 1 week from the current
|
||||
# By default, 'snapshot' metadata is set to expire 1 week from the current
|
||||
# time. The expiration may be modified.
|
||||
expiration = tuf.formats.format_time(time.time()+RELEASE_EXPIRATION)
|
||||
expiration = tuf.formats.format_time(time.time()+SNAPSHOT_EXPIRATION)
|
||||
|
||||
roleinfo = {'keyids': [], 'signing_keyids': [], 'threshold': 1,
|
||||
'signatures': [], 'version': 0, 'compressions': [''],
|
||||
|
|
@ -2022,7 +2023,7 @@ def delegate(self, rolename, public_keys, list_of_targets,
|
|||
|
||||
# Update the public keys of 'new_targets_object'.
|
||||
for key in public_keys:
|
||||
new_targets_object.add_key(key)
|
||||
new_targets_object.add_verification_key(key)
|
||||
|
||||
# Add the new delegation to this Targets object. For example, 'django' is
|
||||
# added to 'repository.targets' (i.e., repository.targets('django')).
|
||||
|
|
@ -2121,7 +2122,7 @@ def delegate_hashed_bins(self, list_of_targets, keys_of_hashed_bins,
|
|||
The initial public keys of the delegated roles. Public keys may be
|
||||
later added or removed by calling the usual methods of the delegated
|
||||
Targets object. For example:
|
||||
repository.targets('unclaimed')('000-003').add_key()
|
||||
repository.targets('unclaimed')('000-003').add_verification_key()
|
||||
|
||||
number_of_bins:
|
||||
The number of delegated roles, or hashed bins, that should be generated
|
||||
|
|
@ -2277,7 +2278,7 @@ def delegations(self):
|
|||
|
||||
def _generate_and_write_metadata(rolename, metadata_filename, write_partial,
|
||||
targets_directory, metadata_directory,
|
||||
consistent_snapshots=False, filenames=None):
|
||||
consistent_snapshot=False, filenames=None):
|
||||
"""
|
||||
Non-public function that can generate and write the metadata of the specified
|
||||
top-level 'rolename'. It also increments version numbers if:
|
||||
|
|
@ -2293,12 +2294,12 @@ def _generate_and_write_metadata(rolename, metadata_filename, write_partial,
|
|||
# Retrieve the roleinfo of 'rolename' to extract the needed metadata
|
||||
# attributes, such as version number, expiration, etc.
|
||||
roleinfo = tuf.roledb.get_roleinfo(rolename)
|
||||
release_compressions = tuf.roledb.get_roleinfo('release')['compressions']
|
||||
snapshot_compressions = tuf.roledb.get_roleinfo('snapshot')['compressions']
|
||||
|
||||
# Generate the appropriate role metadata for 'rolename'.
|
||||
if rolename == 'root':
|
||||
metadata = generate_root_metadata(roleinfo['version'],
|
||||
roleinfo['expires'], consistent_snapshots)
|
||||
roleinfo['expires'], consistent_snapshot)
|
||||
|
||||
# Check for the Targets role, including delegated roles.
|
||||
elif rolename.startswith('targets'):
|
||||
|
|
@ -2307,23 +2308,23 @@ def _generate_and_write_metadata(rolename, metadata_filename, write_partial,
|
|||
roleinfo['version'],
|
||||
roleinfo['expires'],
|
||||
roleinfo['delegations'],
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
elif rolename == 'release':
|
||||
elif rolename == 'snapshot':
|
||||
root_filename = filenames['root']
|
||||
targets_filename = filenames['targets']
|
||||
metadata = generate_release_metadata(metadata_directory,
|
||||
metadata = generate_snapshot_metadata(metadata_directory,
|
||||
roleinfo['version'],
|
||||
roleinfo['expires'], root_filename,
|
||||
targets_filename,
|
||||
consistent_snapshots )
|
||||
consistent_snapshot )
|
||||
|
||||
elif rolename == 'timestamp':
|
||||
release_filename = filenames['release']
|
||||
metadata = generate_timestamp_metadata(release_filename,
|
||||
snapshot_filename = filenames['snapshot']
|
||||
metadata = generate_timestamp_metadata(snapshot_filename,
|
||||
roleinfo['version'],
|
||||
roleinfo['expires'],
|
||||
release_compressions)
|
||||
snapshot_compressions)
|
||||
|
||||
signable = sign_metadata(metadata, roleinfo['signing_keyids'],
|
||||
metadata_filename)
|
||||
|
|
@ -2354,14 +2355,14 @@ def _generate_and_write_metadata(rolename, metadata_filename, write_partial,
|
|||
_remove_invalid_and_duplicate_signatures(signable)
|
||||
compressions = roleinfo['compressions']
|
||||
filename = write_metadata_file(signable, metadata_filename, compressions,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
# The root and timestamp files should also be written without a digest if
|
||||
# 'consistent_snaptshots' is True. Client may request a timestamp and root
|
||||
# file without knowing its digest and file size.
|
||||
if rolename == 'root' or rolename == 'timestamp':
|
||||
write_metadata_file(signable, metadata_filename, compressions,
|
||||
consistent_snapshots=False)
|
||||
consistent_snapshot=False)
|
||||
|
||||
|
||||
# 'signable' contains an invalid threshold of signatures.
|
||||
|
|
@ -2380,14 +2381,14 @@ def _print_status_of_top_level_roles(targets_directory, metadata_directory):
|
|||
Non-public function that prints whether any of the top-level roles contain an
|
||||
invalid number of public and private keys, or an insufficient threshold of
|
||||
signatures. Considering that the top-level metadata have to be verified in
|
||||
the expected root -> targets -> release -> timestamp order, this function
|
||||
the expected root -> targets -> snapshot -> timestamp order, this function
|
||||
prints the error message and returns as soon as a required metadata file is
|
||||
found to be invalid. It is assumed here that the delegated roles have been
|
||||
written and verified. Example output:
|
||||
|
||||
'root' role contains 1 / 1 signatures.
|
||||
'targets' role contains 1 / 1 signatures.
|
||||
'release' role contains 1 / 1 signatures.
|
||||
'snapshot' role contains 1 / 1 signatures.
|
||||
'timestamp' role contains 1 / 1 signatures.
|
||||
"""
|
||||
|
||||
|
|
@ -2396,12 +2397,12 @@ def _print_status_of_top_level_roles(targets_directory, metadata_directory):
|
|||
filenames = get_metadata_filenames(metadata_directory)
|
||||
root_filename = filenames[ROOT_FILENAME]
|
||||
targets_filename = filenames[TARGETS_FILENAME]
|
||||
release_filename = filenames[RELEASE_FILENAME]
|
||||
snapshot_filename = filenames[SNAPSHOT_FILENAME]
|
||||
timestamp_filename = filenames[TIMESTAMP_FILENAME]
|
||||
|
||||
# Verify that the top-level roles contain a valid number of public keys and
|
||||
# that their corresponding private keys have been loaded.
|
||||
for rolename in ['root', 'targets', 'release', 'timestamp']:
|
||||
for rolename in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
try:
|
||||
_check_role_keys(rolename)
|
||||
|
||||
|
|
@ -2410,7 +2411,7 @@ def _print_status_of_top_level_roles(targets_directory, metadata_directory):
|
|||
return
|
||||
|
||||
# Do the top-level roles contain a valid threshold of signatures? Top-level
|
||||
# metadata is verified in Root -> Targets -> Release -> Timestamp order.
|
||||
# metadata is verified in Root -> Targets -> Snapshot -> Timestamp order.
|
||||
# Verify the metadata of the Root role.
|
||||
try:
|
||||
signable, root_filename = \
|
||||
|
|
@ -2437,25 +2438,25 @@ def _print_status_of_top_level_roles(targets_directory, metadata_directory):
|
|||
_print_status('targets', signable)
|
||||
return
|
||||
|
||||
# Verify the metadata of the Release role.
|
||||
# Verify the metadata of the snapshot role.
|
||||
filenames = {'root': root_filename, 'targets': targets_filename}
|
||||
try:
|
||||
signable, release_filename = \
|
||||
_generate_and_write_metadata('release', release_filename, False,
|
||||
signable, snapshot_filename = \
|
||||
_generate_and_write_metadata('snapshot', snapshot_filename, False,
|
||||
targets_directory, metadata_directory,
|
||||
False, filenames)
|
||||
_print_status('release', signable)
|
||||
_print_status('snapshot', signable)
|
||||
|
||||
except tuf.UnsignedMetadataError, e:
|
||||
signable = e[1]
|
||||
_print_status('release', signable)
|
||||
_print_status('snapshot', signable)
|
||||
return
|
||||
|
||||
# Verify the metadata of the Timestamp role.
|
||||
filenames = {'release': release_filename}
|
||||
filenames = {'snapshot': snapshot_filename}
|
||||
try:
|
||||
signable, release_filename = \
|
||||
_generate_and_write_metadata('timestamp', release_filename, False,
|
||||
signable, snapshot_filename = \
|
||||
_generate_and_write_metadata('timestamp', snapshot_filename, False,
|
||||
targets_directory, metadata_directory,
|
||||
False, filenames)
|
||||
_print_status('timestamp', signable)
|
||||
|
|
@ -2659,8 +2660,8 @@ def _remove_invalid_and_duplicate_signatures(signable):
|
|||
|
||||
|
||||
|
||||
def _delete_obsolete_metadata(metadata_directory, release_metadata,
|
||||
consistent_snapshots):
|
||||
def _delete_obsolete_metadata(metadata_directory, snapshot_metadata,
|
||||
consistent_snapshot):
|
||||
"""
|
||||
Non-public function that deletes metadata files marked as removed by
|
||||
repository_tool.py. Metadata files marked as removed are not actually deleted
|
||||
|
|
@ -2686,11 +2687,11 @@ def _delete_obsolete_metadata(metadata_directory, release_metadata,
|
|||
metadata_name = \
|
||||
metadata_path[len(metadata_directory):].lstrip(os.path.sep)
|
||||
|
||||
# Strip the digest if 'consistent_snapshots' is True.
|
||||
# Strip the digest if 'consistent_snapshot' is True.
|
||||
# Example: 'targets/unclaimed/13df98ab0.django.json' -->
|
||||
# 'targets/unclaimed/django.json'
|
||||
metadata_name, embeded_digest = \
|
||||
_strip_consistent_snapshots_digest(metadata_name, consistent_snapshots)
|
||||
_strip_consistent_snapshot_digest(metadata_name, consistent_snapshot)
|
||||
|
||||
# Strip filename extensions. The role database does not include the
|
||||
# metadata extension.
|
||||
|
|
@ -2706,11 +2707,11 @@ def _delete_obsolete_metadata(metadata_directory, release_metadata,
|
|||
logger.info('Removing outdated metadata: ' + repr(metadata_path))
|
||||
os.remove(metadata_path)
|
||||
|
||||
# Delete outdated consistent snapshots. release metadata includes
|
||||
# Delete outdated consistent snapshots. snapshot metadata includes
|
||||
# the file extension of roles.
|
||||
if consistent_snapshots:
|
||||
if consistent_snapshot:
|
||||
#metadata_name_extension = metadata_name + METADATA_EXTENSION
|
||||
file_hashes = release_metadata['meta'][metadata_name] \
|
||||
file_hashes = snapshot_metadata['meta'][metadata_name] \
|
||||
['hashes'].values()
|
||||
if embeded_digest not in file_hashes:
|
||||
logger.info('Removing outdated metadata: ' + repr(metadata_path))
|
||||
|
|
@ -2741,7 +2742,7 @@ def _get_written_metadata_and_digests(metadata_signable):
|
|||
|
||||
|
||||
|
||||
def _strip_consistent_snapshots_digest(metadata_filename, consistent_snapshots):
|
||||
def _strip_consistent_snapshot_digest(metadata_filename, consistent_snapshot):
|
||||
"""
|
||||
Strip from 'metadata_filename' any digest data (in the expected
|
||||
'{dirname}/digest.filename' format) that it may contain, and return it.
|
||||
|
|
@ -2749,10 +2750,10 @@ def _strip_consistent_snapshots_digest(metadata_filename, consistent_snapshots):
|
|||
|
||||
embeded_digest = ''
|
||||
|
||||
# Strip the digest if 'consistent_snapshots' is True.
|
||||
# Strip the digest if 'consistent_snapshot' is True.
|
||||
# Example: 'targets/unclaimed/13df98ab0.django.json' -->
|
||||
# 'targets/unclaimed/django.json'
|
||||
if consistent_snapshots:
|
||||
if consistent_snapshot:
|
||||
dirname, basename = os.path.split(metadata_filename)
|
||||
embeded_digest = basename[:basename.find('.')]
|
||||
basename = basename[basename.find('.'):]
|
||||
|
|
@ -2828,7 +2829,7 @@ def create_new_repository(repository_directory):
|
|||
os.path.join(repository_directory, TARGETS_DIRECTORY_NAME)
|
||||
|
||||
# Try to create the metadata directory that will hold all of the metadata
|
||||
# files, such as 'root.json' and 'release.json'.
|
||||
# files, such as 'root.json' and 'snapshot.json'.
|
||||
try:
|
||||
message = 'Creating '+repr(metadata_directory)
|
||||
logger.info(message)
|
||||
|
|
@ -2903,19 +2904,19 @@ def load_repository(repository_directory):
|
|||
filenames = get_metadata_filenames(metadata_directory)
|
||||
|
||||
# The Root file is always available without a consistent snapshots digest
|
||||
# attached to the filename. Store the 'consistent_snapshots' value read the
|
||||
# attached to the filename. Store the 'consistent_snapshot' value read the
|
||||
# loaded Root file so that other metadata files may be located.
|
||||
# 'consistent_snapshots' value.
|
||||
consistent_snapshots = False
|
||||
# 'consistent_snapshot' value.
|
||||
consistent_snapshot = False
|
||||
|
||||
# Load the metadata of the top-level roles (i.e., Root, Timestamp, Targets,
|
||||
# and Release).
|
||||
repository, consistent_snapshots = _load_top_level_metadata(repository,
|
||||
# and Snapshot).
|
||||
repository, consistent_snapshot = _load_top_level_metadata(repository,
|
||||
filenames)
|
||||
|
||||
# Load delegated targets metadata.
|
||||
# Walk the 'targets/' directory and generate the fileinfo of all the files
|
||||
# listed. This information is stored in the 'meta' field of the release
|
||||
# listed. This information is stored in the 'meta' field of the snapshot
|
||||
# metadata object.
|
||||
targets_objects = {}
|
||||
loaded_metadata = []
|
||||
|
|
@ -2932,11 +2933,11 @@ def load_repository(repository_directory):
|
|||
metadata_name = \
|
||||
metadata_path[len(metadata_directory):].lstrip(os.path.sep)
|
||||
|
||||
# Strip the digest if 'consistent_snapshots' is True.
|
||||
# Strip the digest if 'consistent_snapshot' is True.
|
||||
# Example: 'targets/unclaimed/13df98ab0.django.json' -->
|
||||
# 'targets/unclaimed/django.json'
|
||||
metadata_name, digest_junk = \
|
||||
_strip_consistent_snapshots_digest(metadata_name, consistent_snapshots)
|
||||
_strip_consistent_snapshot_digest(metadata_name, consistent_snapshot)
|
||||
|
||||
if metadata_name.endswith(METADATA_EXTENSION):
|
||||
extension_length = len(METADATA_EXTENSION)
|
||||
|
|
@ -2946,7 +2947,7 @@ def load_repository(repository_directory):
|
|||
|
||||
# Keep a store metadata previously loaded metadata to prevent
|
||||
# re-loading duplicate versions. Duplicate versions may occur with
|
||||
# consistent_snapshots, where the same metadata may be available in
|
||||
# consistent_snapshot, where the same metadata may be available in
|
||||
# multiples files (the different hash is included in each filename.
|
||||
if metadata_name in loaded_metadata:
|
||||
continue
|
||||
|
|
@ -3014,18 +3015,18 @@ def load_repository(repository_directory):
|
|||
|
||||
def _load_top_level_metadata(repository, top_level_filenames):
|
||||
"""
|
||||
Load the metadata of the Root, Timestamp, Targets, and Release roles.
|
||||
Load the metadata of the Root, Timestamp, Targets, and Snapshot roles.
|
||||
At a minimum, the Root role must exist and successfully load.
|
||||
"""
|
||||
|
||||
root_filename = top_level_filenames[ROOT_FILENAME]
|
||||
targets_filename = top_level_filenames[TARGETS_FILENAME]
|
||||
release_filename = top_level_filenames[RELEASE_FILENAME]
|
||||
snapshot_filename = top_level_filenames[SNAPSHOT_FILENAME]
|
||||
timestamp_filename = top_level_filenames[TIMESTAMP_FILENAME]
|
||||
|
||||
root_metadata = None
|
||||
targets_metadata = None
|
||||
release_metadata = None
|
||||
snapshot_metadata = None
|
||||
timestamp_metadata = None
|
||||
|
||||
# Load ROOT.json. A Root role file without a digest is always written.
|
||||
|
|
@ -3050,8 +3051,8 @@ def _load_top_level_metadata(repository, top_level_filenames):
|
|||
_check_if_partial_loaded('root', signable, roleinfo)
|
||||
tuf.roledb.update_roleinfo('root', roleinfo)
|
||||
|
||||
# Ensure the 'consistent_snapshots' field is extracted.
|
||||
consistent_snapshots = root_metadata['consistent_snapshots']
|
||||
# Ensure the 'consistent_snapshot' field is extracted.
|
||||
consistent_snapshot = root_metadata['consistent_snapshot']
|
||||
|
||||
else:
|
||||
message = 'Cannot load the required root file: '+repr(root_filename)
|
||||
|
|
@ -3078,38 +3079,38 @@ def _load_top_level_metadata(repository, top_level_filenames):
|
|||
else:
|
||||
pass
|
||||
|
||||
# Load RELEASE.json. A consistent snapshot of Release must be calculated
|
||||
# if 'consistent_snapshots' is True.
|
||||
if consistent_snapshots:
|
||||
release_hashes = timestamp_metadata['meta'][RELEASE_FILENAME]['hashes']
|
||||
release_digest = random.choice(release_hashes.values())
|
||||
dirname, basename = os.path.split(release_filename)
|
||||
release_filename = os.path.join(dirname, release_digest + '.' + basename)
|
||||
# Load SNAPSHOT.json. A consistent snapshot of Snapshot must be calculated
|
||||
# if 'consistent_snapshot' is True.
|
||||
if consistent_snapshot:
|
||||
snapshot_hashes = timestamp_metadata['meta'][SNAPSHOT_FILENAME]['hashes']
|
||||
snapshot_digest = random.choice(snapshot_hashes.values())
|
||||
dirname, basename = os.path.split(snapshot_filename)
|
||||
snapshot_filename = os.path.join(dirname, snapshot_digest + '.' + basename)
|
||||
|
||||
if os.path.exists(release_filename):
|
||||
signable = tuf.util.load_json_file(release_filename)
|
||||
if os.path.exists(snapshot_filename):
|
||||
signable = tuf.util.load_json_file(snapshot_filename)
|
||||
tuf.formats.check_signable_object_format(signable)
|
||||
release_metadata = signable['signed']
|
||||
snapshot_metadata = signable['signed']
|
||||
for signature in signable['signatures']:
|
||||
repository.release.add_signature(signature)
|
||||
repository.snapshot.add_signature(signature)
|
||||
|
||||
# Load Release's roleinfo and update 'tuf.roledb'.
|
||||
roleinfo = tuf.roledb.get_roleinfo('release')
|
||||
roleinfo['expires'] = release_metadata['expires']
|
||||
roleinfo['version'] = release_metadata['version']
|
||||
if os.path.exists(release_filename+'.gz'):
|
||||
# Load Snapshot's roleinfo and update 'tuf.roledb'.
|
||||
roleinfo = tuf.roledb.get_roleinfo('snapshot')
|
||||
roleinfo['expires'] = snapshot_metadata['expires']
|
||||
roleinfo['version'] = snapshot_metadata['version']
|
||||
if os.path.exists(snapshot_filename+'.gz'):
|
||||
roleinfo['compressions'].append('gz')
|
||||
|
||||
_check_if_partial_loaded('release', signable, roleinfo)
|
||||
tuf.roledb.update_roleinfo('release', roleinfo)
|
||||
_check_if_partial_loaded('snapshot', signable, roleinfo)
|
||||
tuf.roledb.update_roleinfo('snapshot', roleinfo)
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
# Load TARGETS.json. A consistent snapshot of Targets must be calculated if
|
||||
# 'consistent_snapshots' is True.
|
||||
if consistent_snapshots:
|
||||
targets_hashes = release_metadata['meta'][TARGETS_FILENAME]['hashes']
|
||||
# 'consistent_snapshot' is True.
|
||||
if consistent_snapshot:
|
||||
targets_hashes = snapshot_metadata['meta'][TARGETS_FILENAME]['hashes']
|
||||
targets_digest = random.choice(targets_hashes.values())
|
||||
dirname, basename = os.path.split(targets_filename)
|
||||
targets_filename = os.path.join(dirname, targets_digest + '.' + basename)
|
||||
|
|
@ -3151,7 +3152,7 @@ def _load_top_level_metadata(repository, top_level_filenames):
|
|||
else:
|
||||
pass
|
||||
|
||||
return repository, consistent_snapshots
|
||||
return repository, consistent_snapshot
|
||||
|
||||
|
||||
|
||||
|
|
@ -3565,7 +3566,7 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
|
||||
filenames = {'root': 'metadata/root.json',
|
||||
'targets': 'metadata/targets.json',
|
||||
'release': 'metadata/release.json',
|
||||
'snapshot': 'metadata/snapshot.json',
|
||||
'timestamp': 'metadata/timestamp.json'}
|
||||
|
||||
If the metadata directory is not set by the caller, the current
|
||||
|
|
@ -3583,7 +3584,7 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
|
||||
<Returns>
|
||||
A dictionary containing the expected filenames of the top-level
|
||||
metadata files, such as 'root.json' and 'release.json'.
|
||||
metadata files, such as 'root.json' and 'snapshot.json'.
|
||||
"""
|
||||
|
||||
# Does 'metadata_directory' have the correct format?
|
||||
|
|
@ -3609,8 +3610,8 @@ def get_metadata_filenames(metadata_directory=None):
|
|||
filenames[TARGETS_FILENAME] = \
|
||||
os.path.join(metadata_directory, TARGETS_FILENAME)
|
||||
|
||||
filenames[RELEASE_FILENAME] = \
|
||||
os.path.join(metadata_directory, RELEASE_FILENAME)
|
||||
filenames[SNAPSHOT_FILENAME] = \
|
||||
os.path.join(metadata_directory, SNAPSHOT_FILENAME)
|
||||
|
||||
filenames[TIMESTAMP_FILENAME] = \
|
||||
os.path.join(metadata_directory, TIMESTAMP_FILENAME)
|
||||
|
|
@ -3732,7 +3733,7 @@ def get_target_hash(target_filepath):
|
|||
|
||||
|
||||
|
||||
def generate_root_metadata(version, expiration_date, consistent_snapshots):
|
||||
def generate_root_metadata(version, expiration_date, consistent_snapshot):
|
||||
"""
|
||||
<Purpose>
|
||||
Create the root metadata. 'tuf.roledb.py' and 'tuf.keydb.py' are read and
|
||||
|
|
@ -3749,7 +3750,7 @@ def generate_root_metadata(version, expiration_date, consistent_snapshots):
|
|||
The expiration date, in UTC, of the metadata file. Conformant to
|
||||
'tuf.formats.TIME_SCHEMA'.
|
||||
|
||||
consistent_snapshots:
|
||||
consistent_snapshot:
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if the generated root metadata object could not
|
||||
|
|
@ -3771,7 +3772,7 @@ def generate_root_metadata(version, expiration_date, consistent_snapshots):
|
|||
# Raise 'tuf.FormatError' if any of the arguments are improperly formatted.
|
||||
tuf.formats.METADATAVERSION_SCHEMA.check_match(version)
|
||||
tuf.formats.TIME_SCHEMA.check_match(expiration_date)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshots)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshot)
|
||||
|
||||
# The role and key dictionaries to be saved in the root metadata object.
|
||||
# Conformant to 'ROLEDICT_SCHEMA' and 'KEYDICT_SCHEMA', respectively.
|
||||
|
|
@ -3781,7 +3782,7 @@ def generate_root_metadata(version, expiration_date, consistent_snapshots):
|
|||
# Extract the role, threshold, and keyid information of the top-level roles,
|
||||
# which Root stores in its metadata. The necessary role metadata is generated
|
||||
# from this information.
|
||||
for rolename in ['root', 'targets', 'release', 'timestamp']:
|
||||
for rolename in ['root', 'targets', 'snapshot', 'timestamp']:
|
||||
|
||||
# If a top-level role is missing from 'tuf.roledb.py', raise an exception.
|
||||
if not tuf.roledb.role_exists(rolename):
|
||||
|
|
@ -3829,7 +3830,7 @@ def generate_root_metadata(version, expiration_date, consistent_snapshots):
|
|||
# Generate the root metadata object.
|
||||
root_metadata = tuf.formats.RootFile.make_metadata(version, expiration_date,
|
||||
keydict, roledict,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
|
||||
return root_metadata
|
||||
|
||||
|
|
@ -3951,15 +3952,15 @@ def generate_targets_metadata(targets_directory, target_files, version,
|
|||
|
||||
|
||||
|
||||
def generate_release_metadata(metadata_directory, version, expiration_date,
|
||||
def generate_snapshot_metadata(metadata_directory, version, expiration_date,
|
||||
root_filename, targets_filename,
|
||||
consistent_snapshots):
|
||||
consistent_snapshot):
|
||||
"""
|
||||
<Purpose>
|
||||
Create the release metadata. The minimum metadata must exist
|
||||
Create the snapshot metadata. The minimum metadata must exist
|
||||
(i.e., 'root.json' and 'targets.json'). This will also look through
|
||||
the 'targets/' directory in 'metadata_directory' and the resulting
|
||||
release file will list all the delegated roles.
|
||||
snapshot file will list all the delegated roles.
|
||||
|
||||
<Arguments>
|
||||
metadata_directory:
|
||||
|
|
@ -3979,19 +3980,19 @@ def generate_release_metadata(metadata_directory, version, expiration_date,
|
|||
|
||||
targets_filename:
|
||||
|
||||
consistent_snapshots:
|
||||
consistent_snapshot:
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'metadata_directory' is improperly formatted.
|
||||
|
||||
tuf.Error, if an error occurred trying to generate the release metadata
|
||||
tuf.Error, if an error occurred trying to generate the snapshot metadata
|
||||
object.
|
||||
|
||||
<Side Effects>
|
||||
The 'root.json' and 'targets.json' files are read.
|
||||
|
||||
<Returns>
|
||||
The release metadata object, conformant to 'tuf.formats.RELEASE_SCHEMA'.
|
||||
The snapshot metadata object, conformant to 'tuf.formats.SNAPSHOT_SCHEMA'.
|
||||
"""
|
||||
|
||||
# Do the arguments have the correct format?
|
||||
|
|
@ -4028,7 +4029,7 @@ def generate_release_metadata(metadata_directory, version, expiration_date,
|
|||
get_metadata_file_info(compressed_targets_filename)
|
||||
|
||||
# Walk the 'targets/' directory and generate the fileinfo of all the role
|
||||
# files found. This information is stored in the 'meta' field of the release
|
||||
# files found. This information is stored in the 'meta' field of the snapshot
|
||||
# metadata object.
|
||||
targets_metadata = os.path.join(metadata_directory, 'targets')
|
||||
if os.path.exists(targets_metadata) and os.path.isdir(targets_metadata):
|
||||
|
|
@ -4040,43 +4041,43 @@ def generate_release_metadata(metadata_directory, version, expiration_date,
|
|||
metadata_name = \
|
||||
metadata_path[len(metadata_directory):].lstrip(os.path.sep)
|
||||
|
||||
# Strip the digest if 'consistent_snapshots' is True.
|
||||
# Strip the digest if 'consistent_snapshot' is True.
|
||||
# Example: 'targets/unclaimed/13df98ab0.django.json' -->
|
||||
# 'targets/unclaimed/django.json'
|
||||
metadata_name, digest_junk = \
|
||||
_strip_consistent_snapshots_digest(metadata_name, consistent_snapshots)
|
||||
_strip_consistent_snapshot_digest(metadata_name, consistent_snapshot)
|
||||
|
||||
# All delegated roles are added to the release file, including
|
||||
# All delegated roles are added to the snapshot file, including
|
||||
# compressed versions.
|
||||
for metadata_extension in METADATA_EXTENSIONS:
|
||||
if metadata_name.endswith(metadata_extension):
|
||||
rolename = metadata_name[:-len(metadata_extension)]
|
||||
|
||||
# Obsolete role files may still be found. Ensure only roles loaded
|
||||
# in the roledb are included in the release metadata.
|
||||
# in the roledb are included in the snapshot metadata.
|
||||
if tuf.roledb.role_exists(rolename):
|
||||
filedict[metadata_name] = get_metadata_file_info(metadata_path)
|
||||
|
||||
# Generate the release metadata object.
|
||||
release_metadata = tuf.formats.ReleaseFile.make_metadata(version,
|
||||
# Generate the snapshot metadata object.
|
||||
snapshot_metadata = tuf.formats.SnapshotFile.make_metadata(version,
|
||||
expiration_date,
|
||||
filedict)
|
||||
|
||||
return release_metadata
|
||||
return snapshot_metadata
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def generate_timestamp_metadata(release_filename, version,
|
||||
def generate_timestamp_metadata(snapshot_filename, version,
|
||||
expiration_date, compressions=()):
|
||||
"""
|
||||
<Purpose>
|
||||
Generate the timestamp metadata object. The 'release.json' file must exist.
|
||||
Generate the timestamp metadata object. The 'snapshot.json' file must exist.
|
||||
|
||||
<Arguments>
|
||||
release_filename:
|
||||
The required filename of the release metadata file.
|
||||
snapshot_filename:
|
||||
The required filename of the snapshot metadata file.
|
||||
|
||||
version:
|
||||
The timestamp's version number. Clients use the version number to
|
||||
|
|
@ -4087,10 +4088,10 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
The expiration date, in UTC, of the metadata file, conformant to
|
||||
'tuf.formats.TIME_SCHEMA'.
|
||||
|
||||
release_filename:
|
||||
snapshot_filename:
|
||||
|
||||
compressions:
|
||||
Compression extensions (e.g., 'gz'). If 'release.json' is also saved in
|
||||
Compression extensions (e.g., 'gz'). If 'snapshot.json' is also saved in
|
||||
compressed form, these compression extensions should be stored in
|
||||
'compressions' so the compressed timestamp files can be added to the
|
||||
timestamp metadata object.
|
||||
|
|
@ -4110,15 +4111,15 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
# This check ensures arguments have the appropriate number of objects and
|
||||
# object types, and that all dict keys are properly named.
|
||||
# Raise 'tuf.FormatError' if the check fails.
|
||||
tuf.formats.PATH_SCHEMA.check_match(release_filename)
|
||||
tuf.formats.PATH_SCHEMA.check_match(snapshot_filename)
|
||||
tuf.formats.METADATAVERSION_SCHEMA.check_match(version)
|
||||
tuf.formats.TIME_SCHEMA.check_match(expiration_date)
|
||||
tuf.formats.COMPRESSIONS_SCHEMA.check_match(compressions)
|
||||
|
||||
# Retrieve the fileinfo of the release metadata file.
|
||||
# Retrieve the fileinfo of the snapshot metadata file.
|
||||
# This file information contains hashes, file length, custom data, etc.
|
||||
fileinfo = {}
|
||||
fileinfo[RELEASE_FILENAME] = get_metadata_file_info(release_filename)
|
||||
fileinfo[SNAPSHOT_FILENAME] = get_metadata_file_info(snapshot_filename)
|
||||
|
||||
# Save the fileinfo of the compressed versions of 'timestamp.json'
|
||||
# in 'fileinfo'. Log the files included in 'fileinfo'.
|
||||
|
|
@ -4126,7 +4127,7 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
if not len(file_extension):
|
||||
continue
|
||||
|
||||
compressed_filename = release_filename + '.' + file_extension
|
||||
compressed_filename = snapshot_filename + '.' + file_extension
|
||||
try:
|
||||
compressed_fileinfo = get_metadata_file_info(compressed_filename)
|
||||
|
||||
|
|
@ -4135,7 +4136,7 @@ def generate_timestamp_metadata(release_filename, version,
|
|||
|
||||
else:
|
||||
logger.info('Including fileinfo about '+str(compressed_filename))
|
||||
fileinfo[RELEASE_FILENAME+'.'+file_extension] = compressed_fileinfo
|
||||
fileinfo[SNAPSHOT_FILENAME+'.'+file_extension] = compressed_fileinfo
|
||||
|
||||
# Generate the timestamp metadata object.
|
||||
timestamp_metadata = tuf.formats.TimestampFile.make_metadata(version,
|
||||
|
|
@ -4232,7 +4233,7 @@ def sign_metadata(metadata_object, keyids, filename):
|
|||
|
||||
|
||||
|
||||
def write_metadata_file(metadata, filename, compressions, consistent_snapshots):
|
||||
def write_metadata_file(metadata, filename, compressions, consistent_snapshot):
|
||||
"""
|
||||
<Purpose>
|
||||
If necessary, write the 'metadata' signable object to 'filename', and the
|
||||
|
|
@ -4277,7 +4278,7 @@ def write_metadata_file(metadata, filename, compressions, consistent_snapshots):
|
|||
tuf.formats.SIGNABLE_SCHEMA.check_match(metadata)
|
||||
tuf.formats.PATH_SCHEMA.check_match(filename)
|
||||
tuf.formats.COMPRESSIONS_SCHEMA.check_match(compressions)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshots)
|
||||
tuf.formats.BOOLEAN_SCHEMA.check_match(consistent_snapshot)
|
||||
|
||||
# Verify the directory of 'filename', and convert 'filename' to its absolute
|
||||
# path so that temporary files are moved to their expected destinations.
|
||||
|
|
@ -4292,7 +4293,7 @@ def write_metadata_file(metadata, filename, compressions, consistent_snapshots):
|
|||
# if re-saving is required.
|
||||
file_content, new_digests = _get_written_metadata_and_digests(metadata)
|
||||
|
||||
if consistent_snapshots:
|
||||
if consistent_snapshot:
|
||||
for new_digest in new_digests.values():
|
||||
dirname, basename = os.path.split(filename)
|
||||
digest_and_filename = new_digest + '.' + basename
|
||||
|
|
@ -4365,7 +4366,7 @@ def write_metadata_file(metadata, filename, compressions, consistent_snapshots):
|
|||
# Re-savign the same compressed version may cause its digest to unexpectedly
|
||||
# change (gzip includes a timestamp) even though content has not changed.
|
||||
_write_compressed_metadata(file_object, compressed_filename,
|
||||
consistent_snapshots)
|
||||
consistent_snapshot)
|
||||
return written_filename
|
||||
|
||||
|
||||
|
|
@ -4373,7 +4374,7 @@ def write_metadata_file(metadata, filename, compressions, consistent_snapshots):
|
|||
|
||||
|
||||
def _write_compressed_metadata(file_object, compressed_filename,
|
||||
consistent_snapshots):
|
||||
consistent_snapshot):
|
||||
"""
|
||||
Write compressed versions of metadata, ensuring compressed file that have
|
||||
not changed are not re-written, the digest of the compressed file is properly
|
||||
|
|
@ -4384,7 +4385,7 @@ def _write_compressed_metadata(file_object, compressed_filename,
|
|||
|
||||
# If a consistent snapshot is unneeded, 'file_object' may be simply moved
|
||||
# 'compressed_filename' if not already written.
|
||||
if not consistent_snapshots:
|
||||
if not consistent_snapshot:
|
||||
if not os.path.exists(compressed_filename):
|
||||
file_object.move(compressed_filename)
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ def add_role(rolename, roleinfo, require_parent=True):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
roleinfo:
|
||||
An object representing the role associated with 'rolename', conformant to
|
||||
|
|
@ -193,7 +193,7 @@ def update_roleinfo(rolename, roleinfo):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
roleinfo:
|
||||
An object representing the role associated with 'rolename', conformant to
|
||||
|
|
@ -255,7 +255,7 @@ def get_parent_rolename(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -295,7 +295,7 @@ def get_all_parent_roles(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -347,7 +347,7 @@ def role_exists(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -383,7 +383,7 @@ def remove_role(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -422,7 +422,7 @@ def remove_delegated_roles(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -493,7 +493,7 @@ def get_roleinfo(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' is improperly formatted.
|
||||
|
|
@ -529,7 +529,7 @@ def get_role_keyids(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -564,7 +564,7 @@ def get_role_threshold(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -599,7 +599,7 @@ def get_role_paths(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
@ -640,7 +640,7 @@ def get_delegated_rolenames(rolename):
|
|||
<Arguments>
|
||||
rolename:
|
||||
An object representing the role's name, conformant to 'ROLENAME_SCHEMA'
|
||||
(e.g., 'root', 'release', 'timestamp').
|
||||
(e.g., 'root', 'snapshot', 'timestamp').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'rolename' does not have the correct object format.
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
keys into different categories. As keys are added and removed, the
|
||||
system must securely and efficiently verify the status of these signatures.
|
||||
For instance, a bunch of keys have recently expired. How many valid keys
|
||||
are now available to the Release role? This question can be answered by
|
||||
are now available to the Snapshot role? This question can be answered by
|
||||
get_signature_status(), which will return a full 'status report' of these
|
||||
'signable' dicts. This module also provides a convenient verify() function
|
||||
that will determine if a role still has a sufficient number of valid keys.
|
||||
|
|
@ -62,7 +62,7 @@ def get_signature_status(signable, role=None):
|
|||
Conformant to tuf.formats.SIGNABLE_SCHEMA.
|
||||
|
||||
role:
|
||||
TUF role (e.g., 'root', 'targets', 'release').
|
||||
TUF role (e.g., 'root', 'targets', 'snapshot').
|
||||
|
||||
<Exceptions>
|
||||
tuf.FormatError, if 'signable' does not have the correct format.
|
||||
|
|
@ -180,7 +180,7 @@ def verify(signable, role):
|
|||
signable = {'signed':, 'signatures': [{'keyid':, 'method':, 'sig':}]}
|
||||
|
||||
role:
|
||||
TUF role (e.g., 'root', 'targets', 'release').
|
||||
TUF role (e.g., 'root', 'targets', 'snapshot').
|
||||
|
||||
<Exceptions>
|
||||
tuf.UnknownRoleError, if 'role' is not recognized.
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@
|
|||
import tuf.formats
|
||||
import tuf.repo.keystore as keystore
|
||||
import tuf.repo.signerlib as signerlib
|
||||
import tuf.repository_tool as repo_tool
|
||||
import tuf.repo.signercli as signercli
|
||||
import tuf.tests.unittest_toolbox as unittest_toolbox
|
||||
|
||||
|
||||
|
||||
# Role:keyids dictionary.
|
||||
role_keyids = {}
|
||||
|
||||
|
|
@ -215,8 +215,8 @@ def _mock_get_keyids(junk):
|
|||
keystore._keystore = unittest_toolbox.Modified_TestCase.rsa_keystore
|
||||
keystore._derived_keys = unittest_toolbox.Modified_TestCase.rsa_passwords
|
||||
|
||||
# Build release file.
|
||||
signerlib.build_release_file(role_keyids['release'], server_metadata_dir,
|
||||
# Build snapshot file.
|
||||
signerlib.build_snapshot_file(role_keyids['snapshot'], server_metadata_dir,
|
||||
version, expiration_date+' UTC')
|
||||
|
||||
# Build timestamp file.
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ def setUp():
|
|||
"""
|
||||
|
||||
# List of all top level roles.
|
||||
role_list = ['root', 'targets', 'release', 'timestamp']
|
||||
role_list = ['root', 'targets', 'snapshot', 'timestamp']
|
||||
|
||||
# List of delegated roles.
|
||||
delegated_role_list = ['targets/delegated_role1',
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
| | |
|
||||
keystore metadata targets
|
||||
| | |
|
||||
key1.key ... role.txt ... file(1) ...
|
||||
key1.key ... role.json ... file(1) ...
|
||||
|
||||
'{root_repo}/tuf_repo/': developer's tuf-repository directory containing
|
||||
following subdirectories:
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
| |
|
||||
current previous
|
||||
| |
|
||||
role.txt ... role.txt ...
|
||||
role.json ... role.json ...
|
||||
|
||||
'{root_repo}/tuf_client/': client directory containing tuf metadata.
|
||||
'{root_repo}/tuf_client/metadata/current': directory where client stores
|
||||
|
|
@ -113,14 +113,14 @@
|
|||
and keys.
|
||||
|
||||
tuf_refresh_repo():
|
||||
Refreshes metadata files at the 'tuf_repo' directory i.e. role.txt's at
|
||||
Refreshes metadata files at the 'tuf_repo' directory i.e. role.json's at
|
||||
'{root_repo}/tuf_repo/metadata/'. Following roles are refreshed:
|
||||
targets, release and timestamp. Also, the whole 'reg_repo' directory is
|
||||
targets, snapshot and timestamp. Also, the whole 'reg_repo' directory is
|
||||
copied to targets directory i.e. '{root_repo}/tuf_repo/targets/'.
|
||||
|
||||
Note: metadata files are root.txt, targets.txt, release.txt and
|
||||
timestamp.txt (denoted as 'role.txt in the diagrams'). There could be
|
||||
more metadata files such us mirrors.txt. The metadata files are signed
|
||||
Note: metadata files are root.json, targets.json, snapshot.json and
|
||||
timestamp.json (denoted as 'role.json in the diagrams'). There could be
|
||||
more metadata files such us mirrors.json. The metadata files are signed
|
||||
by their corresponding roles i.e. root, targets etc.
|
||||
|
||||
More documentation is provided in the comment and doc blocks.
|
||||
|
|
@ -174,8 +174,8 @@ def init_repo(using_tuf=False, port=None):
|
|||
server_proc = subprocess.Popen(command, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
# Tailor url for the repository. In order to download a 'file.txt'
|
||||
# from 'reg_repo' do: url+'reg_repo/file.txt'
|
||||
# Tailor url for the repository. In order to download a 'file.json'
|
||||
# from 'reg_repo' do: url+'reg_repo/file.json'
|
||||
relpath = os.path.basename(root_repo)
|
||||
url = 'http://localhost:'+str(port)+'/'+relpath+'/'
|
||||
|
||||
|
|
@ -326,7 +326,7 @@ def init_tuf(root_repo):
|
|||
# In our case 'role_info[keyids]' will only have on entry since only one
|
||||
# is being used.
|
||||
role_info = {}
|
||||
role_list = ['root', 'targets', 'release', 'timestamp']
|
||||
role_list = ['root', 'targets', 'snapshot', 'timestamp']
|
||||
for role in role_list:
|
||||
role_info[role] = info
|
||||
|
||||
|
|
@ -336,17 +336,17 @@ def init_tuf(root_repo):
|
|||
# Build the configuration file.
|
||||
conf_path = signerlib.build_config_file(metadata_dir, 365, role_info)
|
||||
|
||||
# Generate the 'root.txt' metadata file.
|
||||
# Generate the 'root.json' metadata file.
|
||||
signerlib.build_root_file(conf_path, keyids, metadata_dir, version)
|
||||
|
||||
# Generate the 'targets.txt' metadata file.
|
||||
# Generate the 'targets.json' metadata file.
|
||||
signerlib.build_targets_file([targets_dir], keyids, metadata_dir, version,
|
||||
expiration)
|
||||
|
||||
# Generate the 'release.txt' metadata file.
|
||||
signerlib.build_release_file(keyids, metadata_dir, version, expiration)
|
||||
# Generate the 'snapshot.json' metadata file.
|
||||
signerlib.build_snapshot_file(keyids, metadata_dir, version, expiration)
|
||||
|
||||
# Generate the 'timestamp.txt' metadata file.
|
||||
# Generate the 'timestamp.json' metadata file.
|
||||
signerlib.build_timestamp_file(keyids, metadata_dir, version, expiration)
|
||||
|
||||
# Move the metadata to the client's 'current' and 'previous' directories.
|
||||
|
|
@ -435,14 +435,14 @@ def tuf_refresh_repo(root_repo, keyids):
|
|||
shutil.copytree(reg_repo, targets_dir)
|
||||
|
||||
version = version+1
|
||||
# Regenerate the 'targets.txt' metadata file.
|
||||
# Regenerate the 'targets.json' metadata file.
|
||||
signerlib.build_targets_file([targets_dir], keyids, metadata_dir,
|
||||
version, expiration)
|
||||
|
||||
# Regenerate the 'release.txt' metadata file.
|
||||
signerlib.build_release_file(keyids, metadata_dir, version, expiration)
|
||||
# Regenerate the 'snapshot.json' metadata file.
|
||||
signerlib.build_snapshot_file(keyids, metadata_dir, version, expiration)
|
||||
|
||||
# Regenerate the 'timestamp.txt' metadata file.
|
||||
# Regenerate the 'timestamp.json' metadata file.
|
||||
signerlib.build_timestamp_file(keyids, metadata_dir, version, expiration)
|
||||
|
||||
|
||||
|
|
@ -450,9 +450,9 @@ def tuf_refresh_repo(root_repo, keyids):
|
|||
|
||||
|
||||
|
||||
def tuf_refresh_release_timestamp(metadata_dir, keyids):
|
||||
# Regenerate the 'release.txt' metadata file.
|
||||
signerlib.build_release_file(keyids, metadata_dir)
|
||||
def tuf_refresh_snapshot_timestamp(metadata_dir, keyids):
|
||||
# Regenerate the 'snapshot.json' metadata file.
|
||||
signerlib.build_snapshot_file(keyids, metadata_dir)
|
||||
|
||||
def tuf_refresh_and_download():
|
||||
"""
|
||||
|
|
@ -543,8 +543,8 @@ def make_targets_meta(root_repo):
|
|||
_make_role_metadata_wrapper(root_repo, signercli.make_targets_metadata)
|
||||
|
||||
|
||||
def make_release_meta(root_repo):
|
||||
_make_role_metadata_wrapper(root_repo, signercli.make_release_metadata)
|
||||
def make_snapshot_meta(root_repo):
|
||||
_make_role_metadata_wrapper(root_repo, signercli.make_snapshot_metadata)
|
||||
|
||||
|
||||
def make_timestamp_meta(root_repo):
|
||||
|
|
|
|||
Loading…
Reference in a new issue