Skip to content

Commit a0d412f

Browse files
author
Ivana Atanasova
committed
Update ngclient to return loaded metadata
This changes `TrustedMetadataSet` to return new trusted Metadata on successful calls of the `update_<role>` functions and also changes `Updater._load_targets` to return loaded metadata as well Signed-off-by: Ivana Atanasova <[email protected]>
1 parent bb15ecf commit a0d412f

File tree

3 files changed

+61
-15
lines changed

3 files changed

+61
-15
lines changed

tests/test_trusted_metadata_set.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,22 @@ def test_update(self):
129129

130130
self.assertTrue(count, 6)
131131

132+
def test_update_metadata_output(self):
133+
timestamp = self.trusted_set.update_timestamp(self.metadata["timestamp"])
134+
snapshot = self.trusted_set.update_snapshot(self.metadata["snapshot"])
135+
targets = self.trusted_set.update_targets(self.metadata["targets"])
136+
delegeted_targets_1 = self.trusted_set.update_delegated_targets(
137+
self.metadata["role1"], "role1", "targets"
138+
)
139+
delegeted_targets_2 = self.trusted_set.update_delegated_targets(
140+
self.metadata["role2"], "role2", "role1"
141+
)
142+
self.assertIsInstance(timestamp.signed, Timestamp)
143+
self.assertIsInstance(snapshot.signed, Snapshot)
144+
self.assertIsInstance(targets.signed, Targets)
145+
self.assertIsInstance(delegeted_targets_1.signed, Targets)
146+
self.assertIsInstance(delegeted_targets_2.signed, Targets)
147+
132148
def test_out_of_order_ops(self):
133149
# Update snapshot before timestamp
134150
with self.assertRaises(RuntimeError):

tuf/ngclient/_internal/trusted_metadata_set.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def targets(self) -> Optional[Metadata[Targets]]:
141141
return self._trusted_set.get("targets")
142142

143143
# Methods for updating metadata
144-
def update_root(self, data: bytes) -> None:
144+
def update_root(self, data: bytes) -> Metadata[Root]:
145145
"""Verifies and loads 'data' as new root metadata.
146146
147147
Note that an expired intermediate root is considered valid: expiry is
@@ -153,6 +153,9 @@ def update_root(self, data: bytes) -> None:
153153
Raises:
154154
RepositoryError: Metadata failed to load or verify. The actual
155155
error type and content will contain more details.
156+
157+
Returns:
158+
Deserialized and verified root Metadata object
156159
"""
157160
if self.timestamp is not None:
158161
raise RuntimeError("Cannot update root after timestamp")
@@ -182,7 +185,9 @@ def update_root(self, data: bytes) -> None:
182185
self._trusted_set["root"] = new_root
183186
logger.info("Updated root v%d", new_root.signed.version)
184187

185-
def update_timestamp(self, data: bytes) -> None:
188+
return new_root
189+
190+
def update_timestamp(self, data: bytes) -> Metadata[Timestamp]:
186191
"""Verifies and loads 'data' as new timestamp metadata.
187192
188193
Note that an intermediate timestamp is allowed to be expired:
@@ -199,6 +204,9 @@ def update_timestamp(self, data: bytes) -> None:
199204
RepositoryError: Metadata failed to load or verify as final
200205
timestamp. The actual error type and content will contain
201206
more details.
207+
208+
Returns:
209+
Deserialized and verified timestamp Metadata object
202210
"""
203211
if self.snapshot is not None:
204212
raise RuntimeError("Cannot update timestamp after snapshot")
@@ -251,6 +259,8 @@ def update_timestamp(self, data: bytes) -> None:
251259
# timestamp is loaded: raise if it is not valid _final_ timestamp
252260
self._check_final_timestamp()
253261

262+
return new_timestamp
263+
254264
def _check_final_timestamp(self) -> None:
255265
"""Raise if timestamp is expired"""
256266

@@ -260,7 +270,7 @@ def _check_final_timestamp(self) -> None:
260270

261271
def update_snapshot(
262272
self, data: bytes, trusted: Optional[bool] = False
263-
) -> None:
273+
) -> Metadata[Snapshot]:
264274
"""Verifies and loads 'data' as new snapshot metadata.
265275
266276
Note that an intermediate snapshot is allowed to be expired and version
@@ -282,6 +292,9 @@ def update_snapshot(
282292
Raises:
283293
RepositoryError: data failed to load or verify as final snapshot.
284294
The actual error type and content will contain more details.
295+
296+
Returns:
297+
Deserialized and verified snapshot Metadata object
285298
"""
286299

287300
if self.timestamp is None:
@@ -347,6 +360,8 @@ def update_snapshot(
347360
# snapshot is loaded, but we raise if it's not valid _final_ snapshot
348361
self._check_final_snapshot()
349362

363+
return new_snapshot
364+
350365
def _check_final_snapshot(self) -> None:
351366
"""Raise if snapshot is expired or meta version does not match"""
352367

@@ -361,7 +376,7 @@ def _check_final_snapshot(self) -> None:
361376
f"got {self.snapshot.signed.version}"
362377
)
363378

364-
def update_targets(self, data: bytes) -> None:
379+
def update_targets(self, data: bytes) -> Metadata[Targets]:
365380
"""Verifies and loads 'data' as new top-level targets metadata.
366381
367382
Args:
@@ -370,12 +385,16 @@ def update_targets(self, data: bytes) -> None:
370385
Raises:
371386
RepositoryError: Metadata failed to load or verify. The actual
372387
error type and content will contain more details.
388+
389+
Returns:
390+
Deserialized and verified targets Metadata object
373391
"""
374-
self.update_delegated_targets(data, "targets", "root")
392+
targets = self.update_delegated_targets(data, "targets", "root")
393+
return targets
375394

376395
def update_delegated_targets(
377396
self, data: bytes, role_name: str, delegator_name: str
378-
) -> None:
397+
) -> Metadata[Targets]:
379398
"""Verifies and loads 'data' as new metadata for target 'role_name'.
380399
381400
Args:
@@ -386,6 +405,9 @@ def update_delegated_targets(
386405
Raises:
387406
RepositoryError: Metadata failed to load or verify. The actual
388407
error type and content will contain more details.
408+
409+
Returns:
410+
Deserialized and verified targets Metadata object
389411
"""
390412
if self.snapshot is None:
391413
raise RuntimeError("Cannot load targets before snapshot")
@@ -438,6 +460,8 @@ def update_delegated_targets(
438460
self._trusted_set[role_name] = new_delegate
439461
logger.info("Updated %s v%d", role_name, version)
440462

463+
return new_delegate
464+
441465
def _load_trusted_root(self, data: bytes) -> None:
442466
"""Verifies and loads 'data' as trusted root metadata.
443467

tuf/ngclient/updater.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
from securesystemslib import util as sslib_util
6969

7070
from tuf import exceptions
71-
from tuf.api.metadata import TargetFile, Targets
71+
from tuf.api.metadata import Metadata, TargetFile, Targets
7272
from tuf.ngclient._internal import requests_fetcher, trusted_metadata_set
7373
from tuf.ngclient.config import UpdaterConfig
7474
from tuf.ngclient.fetcher import FetcherInterface
@@ -368,12 +368,15 @@ def _load_snapshot(self) -> None:
368368
self._trusted_set.update_snapshot(data)
369369
self._persist_metadata("snapshot", data)
370370

371-
def _load_targets(self, role: str, parent_role: str) -> None:
371+
def _load_targets(self, role: str, parent_role: str) -> Metadata[Targets]:
372372
"""Load local (and if needed remote) metadata for 'role'."""
373373
try:
374374
data = self._load_local_metadata(role)
375-
self._trusted_set.update_delegated_targets(data, role, parent_role)
375+
delegated_targets = self._trusted_set.update_delegated_targets(
376+
data, role, parent_role
377+
)
376378
logger.debug("Local %s is valid: not downloading new one", role)
379+
return delegated_targets
377380
except (OSError, exceptions.RepositoryError) as e:
378381
# Local 'role' does not exist or is invalid: update from remote
379382
logger.debug("Failed to load local %s: %s", role, e)
@@ -386,9 +389,13 @@ def _load_targets(self, role: str, parent_role: str) -> None:
386389
version = metainfo.version
387390

388391
data = self._download_metadata(role, length, version)
389-
self._trusted_set.update_delegated_targets(data, role, parent_role)
392+
delegated_targets = self._trusted_set.update_delegated_targets(
393+
data, role, parent_role
394+
)
390395
self._persist_metadata(role, data)
391396

397+
return delegated_targets
398+
392399
def _preorder_depth_first_walk(
393400
self, target_filepath: str
394401
) -> Optional[TargetFile]:
@@ -417,10 +424,9 @@ def _preorder_depth_first_walk(
417424

418425
# The metadata for 'role_name' must be downloaded/updated before
419426
# its targets, delegations, and child roles can be inspected.
420-
self._load_targets(role_name, parent_role)
427+
targets = self._load_targets(role_name, parent_role).signed
421428

422-
role_metadata: Targets = self._trusted_set[role_name].signed
423-
target = role_metadata.targets.get(target_filepath)
429+
target = targets.targets.get(target_filepath)
424430

425431
if target is not None:
426432
logger.debug("Found target in current role %s", role_name)
@@ -432,11 +438,11 @@ def _preorder_depth_first_walk(
432438
# And also decrement number of visited roles.
433439
number_of_delegations -= 1
434440

435-
if role_metadata.delegations is not None:
441+
if targets.delegations is not None:
436442
child_roles_to_visit = []
437443
# NOTE: This may be a slow operation if there are many
438444
# delegated roles.
439-
for child_role in role_metadata.delegations.roles.values():
445+
for child_role in targets.delegations.roles.values():
440446
if child_role.is_delegated_path(target_filepath):
441447
logger.debug("Adding child role %s", child_role.name)
442448

0 commit comments

Comments
 (0)