diff --git a/tests/test_api.py b/tests/test_api.py index 25e8825cfd..67fec81238 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -507,6 +507,56 @@ def test_metadata_root(self): root.signed.remove_key('root', 'nosuchkey') + def test_delegation_class(self): + delegations_dict = { + "keys": {}, + "roles": [{ + "keyids": [], + "name": "project.json", + "paths": ["fn1", "fn2"], + "terminating": False, + "threshold": 1 + }]} + delegations = Delegations.from_dict(delegations_dict) + key_dict = { + "keytype": "ed25519", + "keyval": { + "public": "edcd0a32a07dce33f7c7873aaffbff36d20ea30787574ead335eefd337e4dacd" + }, + "scheme": "ed25519" + } + key = Key.from_dict("id2", key_dict) + + # Assert that delegated role "project.json" does not contain the new key + self.assertNotIn(key.keyid, delegations.roles["project.json"].keyids) + delegations.add_key("project.json", key) + + # Assert that the new key is added to the delegated role "project.json" + self.assertIn(key.keyid, delegations.roles["project.json"].keyids) + + # Confirm that the newly added key does not break the obj serialization + delegations.to_dict() + + # Try adding the same key again and assert its ignored. + past_keyid = delegations.roles["project.json"].keyids.copy() + delegations.add_key("project.json", key) + self.assertEqual(past_keyid, delegations.roles["project.json"].keyids) + + # Try adding a key to a delegated role that doesn't exists + with self.assertRaises(KeyError): + delegations.add_key("abc", key) + + # Remove a key from the delegated "project.json" role + delegations.remove_key("project.json", key.keyid) + + # Assert that delegated role "project.json" doesn't contain the key. + self.assertNotIn(key.keyid, delegations.roles["project.json"].keyids) + + # Try removing a key from delegated role that doesn't exists + with self.assertRaises(KeyError): + delegations.remove_key("abc", key.keyid) + + def test_metadata_targets(self): targets_path = os.path.join( self.repo_dir, 'metadata', 'targets.json') diff --git a/tuf/api/metadata.py b/tuf/api/metadata.py index 8276ddf500..c077ed9245 100644 --- a/tuf/api/metadata.py +++ b/tuf/api/metadata.py @@ -1142,6 +1142,28 @@ def to_dict(self) -> Dict[str, Any]: **self.unrecognized_fields, } + def add_key(self, role: str, key: Key) -> None: + """Adds new signing key for delegated role 'role'. + + Raises: + KeyError: If there is no role 'role' in this Delegations object. + """ + self.roles[role].keyids.add(key.keyid) + self.keys[key.keyid] = key + + def remove_key(self, role: str, keyid: str) -> None: + """Removes key from 'role' and updates the key store. + + Raises: + KeyError: If there is no role 'role' in this Delegations object. + """ + self.roles[role].keyids.remove(keyid) + for keyinfo in self.roles.values(): + if keyid in keyinfo.keyids: + return + + del self.keys[keyid] + class TargetFile(BaseFile): """A container with information about a particular target file.