Skip to content

Commit 6450a3a

Browse files
committed
ngclient: Fail gracefully on missing role
If role is delegated but missing from snapshot, we currently raise a undocumented KeyError: a generic RepositoryError seems better as callers are expected to handle it (and adding a more specific error seems useless as this is a repository software bug, not just expired metadata or something). The same check is also done later in TrustedMetadataSet but I think keeping the check in both is clearest. Fixes #2195 Signed-off-by: Jussi Kukkonen <jkukkonen@google.com>
1 parent 6ce8bb8 commit 6450a3a

2 files changed

Lines changed: 22 additions & 1 deletion

File tree

tests/test_updater_fetch_target.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from tests import utils
1717
from tests.repository_simulator import RepositorySimulator
1818
from tuf.api.exceptions import RepositoryError
19+
from tuf.api.metadata import DelegatedRole, Delegations
1920
from tuf.ngclient import Updater
2021

2122

@@ -209,6 +210,19 @@ def test_invalid_target_cache(self) -> None:
209210
with open(path, "rb") as f:
210211
self.assertEqual(f.read(), target.content)
211212

213+
def test_meta_missing_delegated_role(self) -> None:
214+
"""Test a delegation where the role is not part of the snapshot"""
215+
216+
# Add new delegation, update snapshot. Do not add the actual role
217+
role = DelegatedRole("role1", [], 1, True, ["*"])
218+
self.sim.targets.delegations = Delegations({}, roles={role.name: role})
219+
self.sim.update_snapshot()
220+
221+
# assert that RepositoryError is raised when role1 is needed
222+
updater = self._init_updater()
223+
with self.assertRaises(RepositoryError):
224+
updater.get_targetinfo("")
225+
212226

213227
if __name__ == "__main__":
214228
if "--dump" in sys.argv:

tuf/ngclient/updater.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,14 @@ def _load_targets(self, role: str, parent_role: str) -> Metadata[Targets]:
389389
logger.debug("Failed to load local %s: %s", role, e)
390390

391391
assert self._trusted_set.snapshot is not None # nosec
392-
metainfo = self._trusted_set.snapshot.signed.meta[f"{role}.json"]
392+
393+
snapshot = self._trusted_set.snapshot.signed
394+
metainfo = snapshot.meta.get(f"{role}.json")
395+
if metainfo is None:
396+
raise exceptions.RepositoryError(
397+
f"Role {role} was delegated but is not part of snapshot"
398+
)
399+
393400
length = metainfo.length or self.config.targets_max_length
394401
version = None
395402
if self._trusted_set.root.signed.consistent_snapshot:

0 commit comments

Comments
 (0)