diff --git a/tests/test_updater_fetch_target.py b/tests/test_updater_fetch_target.py index 84caccfd29..7207d0fd7f 100644 --- a/tests/test_updater_fetch_target.py +++ b/tests/test_updater_fetch_target.py @@ -16,6 +16,7 @@ from tests import utils from tests.repository_simulator import RepositorySimulator from tuf.api.exceptions import RepositoryError +from tuf.api.metadata import DelegatedRole, Delegations from tuf.ngclient import Updater @@ -209,6 +210,19 @@ def test_invalid_target_cache(self) -> None: with open(path, "rb") as f: self.assertEqual(f.read(), target.content) + def test_meta_missing_delegated_role(self) -> None: + """Test a delegation where the role is not part of the snapshot""" + + # Add new delegation, update snapshot. Do not add the actual role + role = DelegatedRole("role1", [], 1, True, ["*"]) + self.sim.targets.delegations = Delegations({}, roles={role.name: role}) + self.sim.update_snapshot() + + # assert that RepositoryError is raised when role1 is needed + updater = self._init_updater() + with self.assertRaises(RepositoryError): + updater.get_targetinfo("") + if __name__ == "__main__": if "--dump" in sys.argv: diff --git a/tuf/ngclient/updater.py b/tuf/ngclient/updater.py index 54118268a3..737002b614 100644 --- a/tuf/ngclient/updater.py +++ b/tuf/ngclient/updater.py @@ -389,7 +389,14 @@ def _load_targets(self, role: str, parent_role: str) -> Metadata[Targets]: logger.debug("Failed to load local %s: %s", role, e) assert self._trusted_set.snapshot is not None # nosec - metainfo = self._trusted_set.snapshot.signed.meta[f"{role}.json"] + + snapshot = self._trusted_set.snapshot.signed + metainfo = snapshot.meta.get(f"{role}.json") + if metainfo is None: + raise exceptions.RepositoryError( + f"Role {role} was delegated but is not part of snapshot" + ) + length = metainfo.length or self.config.targets_max_length version = None if self._trusted_set.root.signed.consistent_snapshot: