Skip to content

Commit 06097b8

Browse files
committed
Raise if none of paths and path_hash_prefixes is set
The specification does not state clearly what is the behaviour when none of delegation's "paths" and "path_hash_prefixes" is set. See #1497. Until this issue is clarified, copy current Updater which raises an error in such case. Signed-off-by: Teodora Sechkova <[email protected]>
1 parent 02cf9ff commit 06097b8

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

tests/test_metadata_serialization.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,9 @@ def test_snapshot_serialization(self, test_case_data: str):
242242
"no path attribute":
243243
'{"keyids": ["keyid"], "name": "a", "terminating": false, \
244244
"path_hash_prefixes": ["h1", "h2"], "threshold": 99}',
245-
"no hash or path prefix":
246-
'{"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3}',
247245
"unrecognized field":
248-
'{"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3, "foo": "bar"}',
246+
'{"keyids": ["keyid"], "name": "a", "paths": ["fn1", "fn2"], \
247+
"terminating": true, "threshold": 3, "foo": "bar"}',
249248
}
250249

251250
@run_sub_tests_with_dataset(valid_delegated_roles)
@@ -255,12 +254,27 @@ def test_delegated_role_serialization(self, test_case_data: str):
255254
self.assertDictEqual(case_dict, deserialized_role.to_dict())
256255

257256

257+
invalid_delegated_roles: DataSet = {
258+
"missing hash prefixes and paths":
259+
'{"name": "a", "keyids": ["keyid"], "threshold": 1, "terminating": false}',
260+
"both hash prefixes and paths":
261+
'{"name": "a", "keyids": ["keyid"], "threshold": 1, "terminating": false, \
262+
"paths": ["fn1", "fn2"], "path_hash_prefixes": ["h1", "h2"]}',
263+
}
264+
265+
@run_sub_tests_with_dataset(invalid_delegated_roles)
266+
def test_invalid_delegated_role_serialization(self, test_case_data: str):
267+
case_dict = json.loads(test_case_data)
268+
with self.assertRaises(ValueError):
269+
DelegatedRole.from_dict(copy.copy(case_dict))
270+
271+
258272
valid_delegations: DataSet = {
259273
"all": '{"keys": {"keyid" : {"keytype": "rsa", "scheme": "rsassa-pss-sha256", "keyval": {"public": "foo"}}}, \
260-
"roles": [ {"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3} ]}',
274+
"roles": [ {"keyids": ["keyid"], "name": "a", "paths": ["fn1", "fn2"], "terminating": true, "threshold": 3} ]}',
261275
"unrecognized field":
262276
'{"keys": {"keyid" : {"keytype": "rsa", "scheme": "rsassa-pss-sha256", "keyval": {"public": "foo"}}}, \
263-
"roles": [ {"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3} ], \
277+
"roles": [ {"keyids": ["keyid"], "name": "a", "paths": ["fn1", "fn2"], "terminating": true, "threshold": 3} ], \
264278
"foo": "bar"}',
265279
}
266280

@@ -305,13 +319,13 @@ def test_targetfile_serialization(self, test_case_data: str):
305319
"targets": { "file.txt": {"length": 12, "hashes": {"sha256" : "abc"} } }, \
306320
"delegations": {"keys": {"keyid" : {"keytype": "rsa", \
307321
"scheme": "rsassa-pss-sha256", "keyval": {"public": "foo"} }}, \
308-
"roles": [ {"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3} ]} \
322+
"roles": [ {"keyids": ["keyid"], "name": "a", "paths": ["fn1", "fn2"], "terminating": true, "threshold": 3} ]} \
309323
}',
310324
"empty targets": '{"_type": "targets", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
311325
"targets": {}, \
312326
"delegations": {"keys": {"keyid" : {"keytype": "rsa", \
313327
"scheme": "rsassa-pss-sha256", "keyval": {"public": "foo"} }}, \
314-
"roles": [ {"keyids": ["keyid"], "name": "a", "terminating": true, "threshold": 3} ]} \
328+
"roles": [ {"keyids": ["keyid"], "name": "a", "paths": ["fn1", "fn2"], "terminating": true, "threshold": 3} ]} \
315329
}',
316330
"no delegations": '{"_type": "targets", "spec_version": "1.0.0", "version": 1, "expires": "2030-01-01T00:00:00Z", \
317331
"targets": { "file.txt": {"length": 12, "hashes": {"sha256" : "abc"} } } \

tuf/api/metadata.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -962,12 +962,12 @@ def update(self, rolename: str, role_info: MetaFile) -> None:
962962
class DelegatedRole(Role):
963963
"""A container with information about a delegated role.
964964
965-
A delegation can happen in three ways:
966-
- paths is None and path_hash_prefixes is None: delegates all targets
965+
A delegation can happen in two ways:
967966
- paths is set: delegates targets matching any path pattern in paths
968967
- path_hash_prefixes is set: delegates targets whose target path hash
969968
starts with any of the prefixes in path_hash_prefixes
970-
paths and path_hash_prefixes are mutually exclusive: both cannot be set.
969+
paths and path_hash_prefixes are mutually exclusive: both cannot be set,
970+
at least one of them must be set.
971971
972972
Attributes:
973973
name: A string giving the name of the delegated role.
@@ -992,10 +992,11 @@ def __init__(
992992
self.name = name
993993
self.terminating = terminating
994994
if paths is not None and path_hash_prefixes is not None:
995-
raise ValueError(
996-
"Only one of the attributes 'paths' and"
997-
"'path_hash_prefixes' can be set!"
998-
)
995+
raise ValueError("Either paths or path_hash_prefixes can be set")
996+
997+
if paths is None and path_hash_prefixes is None:
998+
raise ValueError("One of paths or path_hash_prefixes must be set")
999+
9991000
self.paths = paths
10001001
self.path_hash_prefixes = path_hash_prefixes
10011002

0 commit comments

Comments
 (0)