mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge branch 'add_test_cases_to_test_util' of https://github.com/vladimir-v-diaz/tuf into add_test_cases_to_test_util
This commit is contained in:
commit
8d1ef5bbfc
2 changed files with 221 additions and 12 deletions
|
|
@ -5,7 +5,7 @@
|
|||
test_util.py
|
||||
|
||||
<Author>
|
||||
Konstantin Andrianov
|
||||
Konstantin Andrianov.
|
||||
|
||||
<Started>
|
||||
February 1, 2013
|
||||
|
|
@ -280,11 +280,17 @@ def test_B4_import_json(self):
|
|||
|
||||
|
||||
def test_B5_load_json_string(self):
|
||||
# Test normal case.
|
||||
data = ['a', {'b': ['c', None, 30.3, 29]}]
|
||||
json_string = util.json.dumps(data)
|
||||
self.assertEquals(data, util.load_json_string(json_string))
|
||||
|
||||
|
||||
# Test invalid arguments.
|
||||
self.assertRaises(tuf.Error, util.load_json_string, 8)
|
||||
invalid_json_string = {'a': tuf.FormatError}
|
||||
self.assertRaises(tuf.Error, util.load_json_string, invalid_json_string)
|
||||
|
||||
|
||||
|
||||
def test_B6_load_json_file(self):
|
||||
data = ['a', {'b': ['c', None, 30.3, 29]}]
|
||||
|
|
@ -297,6 +303,205 @@ def test_B6_load_json_file(self):
|
|||
for bogus_arg in ['a', 1, ['a'], {'a':'b'}]:
|
||||
self.assertRaises(Errors, util.load_json_file, bogus_arg)
|
||||
|
||||
|
||||
|
||||
def test_C1_get_target_hash(self):
|
||||
# Test normal case.
|
||||
expected_target_hashes = {
|
||||
'/file1.txt': 'e3a3d89eb3b70ce3fbce6017d7b8c12d4abd5635427a0e8a238f53157df85b3d',
|
||||
'/README.txt': '8faee106f1bb69f34aaf1df1e3c2e87d763c4d878cb96b91db13495e32ceb0b0',
|
||||
'/warehouse/file2.txt': 'd543a573a2cec67026eff06e75702303559e64e705eba06f65799baaf0424417'
|
||||
}
|
||||
for filepath, target_hash in expected_target_hashes.items():
|
||||
self.assertTrue(tuf.formats.RELPATH_SCHEMA.matches(filepath))
|
||||
self.assertTrue(tuf.formats.HASH_SCHEMA.matches(target_hash))
|
||||
self.assertEqual(util.get_target_hash(filepath), target_hash)
|
||||
|
||||
# Test for improperly formatted argument.
|
||||
self.assertRaises(tuf.FormatError, util.get_target_hash, 8)
|
||||
|
||||
|
||||
|
||||
def test_C2_find_delegated_role(self):
|
||||
# Test normal case. Create an expected role list, which is one of the
|
||||
# required arguments to 'find_delegated_role()'.
|
||||
role_list = [
|
||||
{
|
||||
"keyids": [
|
||||
"a394c28384648328b16731f81440d72243c77bb44c07c040be99347f0df7d7bf"
|
||||
],
|
||||
"name": "targets/warehouse",
|
||||
"paths": [
|
||||
"/file1.txt", "/README.txt", '/warehouse/'
|
||||
],
|
||||
"threshold": 3
|
||||
},
|
||||
{
|
||||
"keyids": [
|
||||
"a394c28384648328b16731f81440d72243c77bb44c07c040be99347f0df7d7bf"
|
||||
],
|
||||
"name": "targets/tuf",
|
||||
"paths": [
|
||||
"/updater.py", "formats.py", '/tuf/'
|
||||
],
|
||||
"threshold": 4
|
||||
}
|
||||
]
|
||||
|
||||
self.assertTrue(tuf.formats.ROLELIST_SCHEMA.matches(role_list))
|
||||
self.assertEqual(util.find_delegated_role(role_list, 'targets/tuf'), 1)
|
||||
self.assertEqual(util.find_delegated_role(role_list, 'targets/warehouse'), 0)
|
||||
# Test for non-existent role. 'find_delegated_role()' returns 'None'
|
||||
# if the role is not found.
|
||||
self.assertEqual(util.find_delegated_role(role_list, 'targets/non-existent'),
|
||||
None)
|
||||
|
||||
# Test improperly formatted arguments.
|
||||
self.assertRaises(tuf.FormatError, util.find_delegated_role, 8, role_list)
|
||||
self.assertRaises(tuf.FormatError, util.find_delegated_role, 8, 'targets/tuf')
|
||||
|
||||
# Test duplicate roles.
|
||||
role_list.append(role_list[1])
|
||||
self.assertRaises(tuf.RepositoryError, util.find_delegated_role, role_list,
|
||||
'targets/tuf')
|
||||
|
||||
# Test missing 'name' attribute (optional, but required by
|
||||
# 'find_delegated_role()'.
|
||||
# Delete the duplicate role, and the remaining role's 'name' attribute.
|
||||
del role_list[2]
|
||||
del role_list[0]['name']
|
||||
self.assertRaises(tuf.RepositoryError, util.find_delegated_role, role_list,
|
||||
'targets/warehouse')
|
||||
|
||||
|
||||
|
||||
def test_C3_paths_are_consistent_with_hash_prefixes(self):
|
||||
# Test normal case.
|
||||
path_hash_prefixes = ['e3a3', '8fae', 'd543']
|
||||
list_of_targets = ['/file1.txt', '/README.txt', '/warehouse/file2.txt']
|
||||
|
||||
# Ensure the paths of 'list_of_targets' each have the epected path hash
|
||||
# prefix listed in 'path_hash_prefixes'.
|
||||
for filepath in list_of_targets:
|
||||
self.assertTrue(util.get_target_hash(filepath)[0:4] in path_hash_prefixes)
|
||||
|
||||
self.assertTrue(util.paths_are_consistent_with_hash_prefixes(list_of_targets,
|
||||
path_hash_prefixes))
|
||||
|
||||
extra_invalid_prefix = ['e3a3', '8fae', 'd543', '0000']
|
||||
self.assertTrue(util.paths_are_consistent_with_hash_prefixes(list_of_targets,
|
||||
extra_invalid_prefix))
|
||||
|
||||
# Test improperly formatted arguments.
|
||||
self.assertRaises(tuf.FormatError,
|
||||
util.paths_are_consistent_with_hash_prefixes, 8,
|
||||
path_hash_prefixes)
|
||||
|
||||
self.assertRaises(tuf.FormatError,
|
||||
util.paths_are_consistent_with_hash_prefixes,
|
||||
list_of_targets, 8)
|
||||
|
||||
self.assertRaises(tuf.FormatError,
|
||||
util.paths_are_consistent_with_hash_prefixes,
|
||||
list_of_targets, ['zza1'])
|
||||
|
||||
# Test invalid list of targets.
|
||||
bad_target_path = '/file5.txt'
|
||||
self.assertTrue(util.get_target_hash(bad_target_path)[0:4] not in
|
||||
path_hash_prefixes)
|
||||
self.assertFalse(util.paths_are_consistent_with_hash_prefixes([bad_target_path],
|
||||
path_hash_prefixes))
|
||||
|
||||
# Add invalid target path to 'list_of_targets'.
|
||||
list_of_targets.append(bad_target_path)
|
||||
self.assertFalse(util.paths_are_consistent_with_hash_prefixes(list_of_targets,
|
||||
path_hash_prefixes))
|
||||
|
||||
|
||||
|
||||
def test_C4_ensure_all_targets_allowed(self):
|
||||
# Test normal case.
|
||||
rolename = 'targets/warehouse'
|
||||
self.assertTrue(tuf.formats.ROLENAME_SCHEMA.matches(rolename))
|
||||
list_of_targets = ['/file1.txt', '/README.txt', '/warehouse/file2.txt']
|
||||
self.assertTrue(tuf.formats.RELPATHS_SCHEMA.matches(list_of_targets))
|
||||
parent_delegations = {"keys": {
|
||||
"a394c28384648328b16731f81440d72243c77bb44c07c040be99347f0df7d7bf": {
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "3eb81026ded5af2c61fb3d4b272ac53cd1049a810ee88f4df1fc35cdaf918157"
|
||||
}
|
||||
}
|
||||
},
|
||||
"roles": [
|
||||
{
|
||||
"keyids": [
|
||||
"a394c28384648328b16731f81440d72243c77bb44c07c040be99347f0df7d7bf"
|
||||
],
|
||||
"name": "targets/warehouse",
|
||||
"paths": [
|
||||
"/file1.txt", "/README.txt", '/warehouse/'
|
||||
],
|
||||
"threshold": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
self.assertTrue(tuf.formats.DELEGATIONS_SCHEMA.matches(parent_delegations))
|
||||
|
||||
util.ensure_all_targets_allowed(rolename, list_of_targets,
|
||||
parent_delegations)
|
||||
|
||||
# The target files of 'targets' are always allowed. 'list_of_targets' and
|
||||
# 'parent_delegations' are not checked in this case.
|
||||
util.ensure_all_targets_allowed('targets', list_of_targets,
|
||||
parent_delegations)
|
||||
|
||||
# Test improperly formatted arguments.
|
||||
self.assertRaises(tuf.FormatError, util.ensure_all_targets_allowed,
|
||||
8, list_of_targets, parent_delegations)
|
||||
|
||||
self.assertRaises(tuf.FormatError, util.ensure_all_targets_allowed,
|
||||
rolename, 8, parent_delegations)
|
||||
|
||||
self.assertRaises(tuf.FormatError, util.ensure_all_targets_allowed,
|
||||
rolename, list_of_targets, 8)
|
||||
|
||||
# Test for invalid 'rolename', which has not been delegated by its parent,
|
||||
# 'targets'.
|
||||
self.assertRaises(tuf.RepositoryError, util.ensure_all_targets_allowed,
|
||||
'targets/non-delegated_rolename', list_of_targets,
|
||||
parent_delegations)
|
||||
|
||||
# Test for target file that is not allowed by the parent role.
|
||||
self.assertRaises(tuf.ForbiddenTargetError, util.ensure_all_targets_allowed,
|
||||
'targets/warehouse', ['file8.txt'], parent_delegations)
|
||||
|
||||
self.assertRaises(tuf.ForbiddenTargetError, util.ensure_all_targets_allowed,
|
||||
'targets/warehouse', ['file1.txt', 'bad-README.txt'],
|
||||
parent_delegations)
|
||||
|
||||
# Test for required attributes.
|
||||
# Missing 'paths' attribute.
|
||||
del parent_delegations['roles'][0]['paths']
|
||||
self.assertRaises(tuf.FormatError, util.ensure_all_targets_allowed,
|
||||
'targets/warehouse', list_of_targets, parent_delegations)
|
||||
|
||||
# Test 'path_hash_prefixes' attribute.
|
||||
path_hash_prefixes = ['e3a3', '8fae', 'd543']
|
||||
parent_delegations['roles'][0]['path_hash_prefixes'] = path_hash_prefixes
|
||||
|
||||
# Test normal case for 'path_hash_prefixes'.
|
||||
util.ensure_all_targets_allowed('targets/warehouse', list_of_targets,
|
||||
parent_delegations)
|
||||
|
||||
# Test target file with a path_hash_prefix that is not allowed in its
|
||||
# parent role.
|
||||
path_hash_prefix = util.get_target_hash('file5.txt')[0:4]
|
||||
self.assertTrue(path_hash_prefix not in parent_delegations['roles'][0]
|
||||
['path_hash_prefixes'])
|
||||
self.assertRaises(tuf.ForbiddenTargetError, util.ensure_all_targets_allowed,
|
||||
'targets/warehouse', ['file5.txt'], parent_delegations)
|
||||
|
||||
|
||||
|
||||
# Run unit test.
|
||||
|
|
|
|||
24
tuf/util.py
24
tuf/util.py
|
|
@ -544,10 +544,12 @@ def find_delegated_role(roles, delegated_role):
|
|||
def ensure_all_targets_allowed(rolename, list_of_targets, parent_delegations):
|
||||
"""
|
||||
<Purpose>
|
||||
Ensure the delegated targets of 'rolename' are allowed; this is
|
||||
Ensure that the list of targets specified by 'rolename' are allowed; this is
|
||||
determined by inspecting the 'delegations' field of the parent role
|
||||
of 'rolename'. If a target specified by 'rolename' is not found in the
|
||||
delegations field of 'metadata_object_of_parent', raise an exception.
|
||||
delegations field of 'metadata_object_of_parent', raise an exception. The
|
||||
top-level role 'targets' is allowed to list any target file, so this
|
||||
function does not raise an exception if 'rolename' is 'targets'.
|
||||
|
||||
Targets allowed are either exlicitly listed under the 'paths' field, or
|
||||
implicitly exist under a subdirectory of a parent directory listed
|
||||
|
|
@ -559,9 +561,9 @@ def ensure_all_targets_allowed(rolename, list_of_targets, parent_delegations):
|
|||
by the parent role).
|
||||
|
||||
TODO: Should the TUF spec restrict the repository to one particular
|
||||
algorithm when calcutating path hash prefixes? Should we allow the
|
||||
repository to specify in the role dictionary the algorithm used for these
|
||||
generated hashed paths?
|
||||
algorithm when calcutating path hash prefixes (currently restricted to
|
||||
SHA256)? Should we allow the repository to specify in the role dictionary
|
||||
the algorithm used for these generated hashed paths?
|
||||
|
||||
<Arguments>
|
||||
rolename:
|
||||
|
|
@ -607,7 +609,8 @@ def ensure_all_targets_allowed(rolename, list_of_targets, parent_delegations):
|
|||
tuf.formats.RELPATHS_SCHEMA.check_match(list_of_targets)
|
||||
tuf.formats.DELEGATIONS_SCHEMA.check_match(parent_delegations)
|
||||
|
||||
# Return if 'rolename' is 'targets'. 'targets' is not a delegated role.
|
||||
# Return if 'rolename' is 'targets'. 'targets' is not a delegated role. Any
|
||||
# target file listed in 'targets' is allowed.
|
||||
if rolename == 'targets':
|
||||
return
|
||||
|
||||
|
|
@ -634,8 +637,7 @@ def ensure_all_targets_allowed(rolename, list_of_targets, parent_delegations):
|
|||
if not consistent(actual_child_targets,
|
||||
allowed_child_path_hash_prefixes):
|
||||
message = repr(rolename)+' specifies a target that does not'+\
|
||||
' have a path hash prefix listed in its parent role '+\
|
||||
repr(parent_role)+'.'
|
||||
' have a path hash prefix listed in its parent role.'
|
||||
raise tuf.ForbiddenTargetError(message)
|
||||
|
||||
elif allowed_child_paths is not None:
|
||||
|
|
@ -671,7 +673,7 @@ def ensure_all_targets_allowed(rolename, list_of_targets, parent_delegations):
|
|||
# 'rolename' child role.
|
||||
else:
|
||||
raise tuf.RepositoryError('The parent role has not delegated to '+\
|
||||
repr(metadata_role)+'.')
|
||||
repr(rolename)+'.')
|
||||
|
||||
|
||||
|
||||
|
|
@ -681,7 +683,7 @@ def paths_are_consistent_with_hash_prefixes(paths, path_hash_prefixes):
|
|||
"""
|
||||
<Purpose>
|
||||
Determine whether a list of paths are consistent with theirs alleged
|
||||
path hash prefixes. By default, the SHA256 hash function will be used.
|
||||
path hash prefixes. By default, the SHA256 hash function is used.
|
||||
|
||||
<Arguments>
|
||||
paths:
|
||||
|
|
@ -894,11 +896,13 @@ def load_json_file(filepath):
|
|||
if filepath.endswith('.gz'):
|
||||
logger.debug('gzip.open('+str(filepath)+')')
|
||||
fileobject = gzip.open(filepath)
|
||||
|
||||
else:
|
||||
logger.debug('open('+str(filepath)+')')
|
||||
fileobject = open(filepath)
|
||||
|
||||
try:
|
||||
return json.load(fileobject)
|
||||
|
||||
finally:
|
||||
fileobject.close()
|
||||
|
|
|
|||
Loading…
Reference in a new issue