Skip to content

Commit 0a92cb9

Browse files
author
Martin Vrachev
committed
Add helper methods in SuccinctRoles
Add two helper methods in SuccinctRoles. Those methods proved useful in the testing code, but I believe they have a potential value for production code as well. Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
1 parent d8808fb commit 0a92cb9

2 files changed

Lines changed: 57 additions & 0 deletions

File tree

tests/test_api.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
Metadata,
3636
Root,
3737
Snapshot,
38+
SuccinctRoles,
3839
TargetFile,
3940
Targets,
4041
Timestamp,
@@ -695,6 +696,31 @@ def test_is_delegated_role(self) -> None:
695696
self.assertFalse(role.is_delegated_path("a/non-matching path"))
696697
self.assertTrue(role.is_delegated_path("a/path"))
697698

699+
def test_is_delegated_role_in_succinct_roles(self) -> None:
700+
succinct_roles = SuccinctRoles([], 1, 5, "bin")
701+
false_role_name_examples = ["foo", "bin-", "bin-s", "bin-20", "bin-100"]
702+
for role_name in false_role_name_examples:
703+
msg = f"Error for {role_name}"
704+
self.assertFalse(succinct_roles.is_delegated_role(role_name), msg)
705+
706+
# delegated role name suffixes are in hex format.
707+
true_name_examples = ["bin-00", "bin-0f", "bin-1f"]
708+
for role_name in true_name_examples:
709+
msg = f"Error for {role_name}"
710+
self.assertTrue(succinct_roles.is_delegated_role(role_name), msg)
711+
712+
def test_get_roles_in_succinct_roles(self) -> None:
713+
succinct_roles = SuccinctRoles([], 1, 16, "bin")
714+
# bin names are in hex format and 4 hex digits are enough to represent
715+
# all bins between 0 and 2^16 - 1 meaning suffix_len must be 4
716+
expected_suffix_length = 4
717+
self.assertEqual(succinct_roles.suffix_len, expected_suffix_length)
718+
for bin_numer, role_name in enumerate(succinct_roles.get_roles()):
719+
# This adds zero-padding if the bin_numer is represented by a hex
720+
# number with a length less than expected_suffix_length.
721+
expected_bin_suffix = f"{bin_numer:0{expected_suffix_length}x}"
722+
self.assertEqual(role_name, f"bin-{expected_bin_suffix}")
723+
698724

699725
# Run unit test.
700726
if __name__ == "__main__":

tuf/api/metadata.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
ClassVar,
4040
Dict,
4141
Generic,
42+
Iterator,
4243
List,
4344
Mapping,
4445
Optional,
@@ -1548,6 +1549,36 @@ def get_role_for_target(self, target_filepath: str) -> str:
15481549
suffix = f"{bin_number:0{self.suffix_len}x}"
15491550
return f"{self.name_prefix}-{suffix}"
15501551

1552+
def get_roles(self) -> Iterator[str]:
1553+
"""Yield the names of all different delegated roles one by one."""
1554+
for i in range(0, self.number_of_bins):
1555+
suffix = f"{i:0{self.suffix_len}x}"
1556+
yield f"{self.name_prefix}-{suffix}"
1557+
1558+
def is_delegated_role(self, role_name: str) -> bool:
1559+
"""Determines whether the given ``role_name`` is in one of
1560+
the delegated roles that ``SuccinctRoles`` represents.
1561+
1562+
Args:
1563+
role_name: The name of the role to check against.
1564+
"""
1565+
desired_prefix = self.name_prefix + "-"
1566+
1567+
if not role_name.startswith(desired_prefix):
1568+
return False
1569+
1570+
suffix = role_name[len(desired_prefix) :]
1571+
if len(suffix) != self.suffix_len:
1572+
return False
1573+
1574+
try:
1575+
# make sure suffix is hex value
1576+
num = int(suffix, 16)
1577+
except ValueError:
1578+
return False
1579+
1580+
return 0 <= num < self.number_of_bins
1581+
15511582

15521583
class Delegations:
15531584
"""A container object storing information about all delegations.

0 commit comments

Comments
 (0)