Skip to content

Commit 377eac1

Browse files
author
Jussi Kukkonen
committed
MetadataBundle: Improve docstrings
Document arguments and exceptions, improve prose in general. Remove mention of local file deletion now that file IO is not done here. Signed-off-by: Jussi Kukkonen <[email protected]>
1 parent f2cff95 commit 377eac1

File tree

1 file changed

+77
-19
lines changed

1 file changed

+77
-19
lines changed

tuf/client_rework/metadata_bundle.py

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Metadata must be loaded/updated in order:
2020
root -> timestamp -> snapshot -> targets -> (other delegated targets)
2121
22+
2223
Exceptions are raised if metadata fails to load in any way.
2324
2425
Example of loading root, timestamp and snapshot:
@@ -121,54 +122,79 @@ def verify_with_threshold(
121122
class MetadataBundle(abc.Mapping):
122123
"""Internal class to keep track of valid metadata in Updater
123124
124-
MetadataBundle ensures that metadata is valid. It provides easy ways to
125-
update the metadata with the caller making decisions on what is updated.
125+
MetadataBundle ensures that the collection of metadata in the bundle is
126+
valid. It provides easy ways to update the metadata with the caller making
127+
decisions on what is updated.
126128
"""
127129

128-
def __init__(self, data: bytes):
129-
"""Initialize by loading trusted root metadata"""
130+
def __init__(self, root_data: bytes):
131+
"""Initialize bundle by loading trusted root metadata
132+
133+
Args:
134+
root_data: Trusted root metadata as bytes. Note that this metadata
135+
will only be verified by itself: it is the source of trust for
136+
all metadata in the bundle.
137+
138+
Raises:
139+
RepositoryError: Metadata failed to load or verify. The actual
140+
error type and content will contain more details.
141+
"""
130142
self._bundle = {} # type: Dict[str: Metadata]
131143
self.reference_time = datetime.utcnow()
132144
self._root_update_finished = False
133145

134-
# Load and validate the local root metadata
135-
# Valid root metadata is required
146+
# Load and validate the local root metadata. Valid initial trusted root
147+
# metadata is required
136148
logger.debug("Updating initial trusted root")
137-
self.update_root(data)
149+
self.update_root(root_data)
138150

139-
# Implement Mapping
140-
def __getitem__(self, key: str) -> Metadata:
141-
return self._bundle[key]
151+
def __getitem__(self, role: str) -> Metadata:
152+
"""Returns current Metadata for 'role'"""
153+
return self._bundle[role]
142154

143155
def __len__(self) -> int:
156+
"""Returns number of Metadata objects in bundle"""
144157
return len(self._bundle)
145158

146159
def __iter__(self) -> Iterator[Metadata]:
160+
"""Returns iterator over all Metadata objects in bundle"""
147161
return iter(self._bundle)
148162

149163
# Helper properties for top level metadata
150164
@property
151165
def root(self) -> Optional[Metadata]:
166+
"""Current root Metadata or None"""
152167
return self._bundle.get("root")
153168

154169
@property
155170
def timestamp(self) -> Optional[Metadata]:
171+
"""Current timestamp Metadata or None"""
156172
return self._bundle.get("timestamp")
157173

158174
@property
159175
def snapshot(self) -> Optional[Metadata]:
176+
"""Current snapshot Metadata or None"""
160177
return self._bundle.get("snapshot")
161178

162179
@property
163180
def targets(self) -> Optional[Metadata]:
181+
"""Current targets Metadata or None"""
164182
return self._bundle.get("targets")
165183

166184
# Methods for updating metadata
167185
def update_root(self, data: bytes):
168186
"""Verifies and loads 'data' as new root metadata.
169187
170188
Note that an expired intermediate root is considered valid: expiry is
171-
only checked for the final root in root_update_finished()."""
189+
only checked for the final root in root_update_finished().
190+
191+
Args:
192+
data: unverified new root metadata as bytes
193+
194+
Raises:
195+
RepositoryError: Metadata failed to load or verify. The actual
196+
error type and content will contain more details.
197+
"""
172198
if self._root_update_finished:
173199
raise RuntimeError(
174200
"Cannot update root after root update is finished"
@@ -206,21 +232,30 @@ def update_root(self, data: bytes):
206232
logger.debug("Updated root")
207233

208234
def root_update_finished(self):
209-
"""Mark root metadata as final."""
235+
"""Marks root metadata as final and verifies it is not expired
236+
237+
Raises:
238+
ExpiredMetadataError: The final root metadata is expired.
239+
"""
210240
if self._root_update_finished:
211241
raise RuntimeError("Root update is already finished")
212242

213243
if self.root.signed.is_expired(self.reference_time):
214244
raise exceptions.ExpiredMetadataError("New root.json is expired")
215245

216-
# We skip specification step 5.3.11: deleting timestamp and snapshot
217-
# with rotated keys is not needed as they will be invalid, are not
218-
# loaded and cannot be loaded
219246
self._root_update_finished = True
220247
logger.debug("Verified final root.json")
221248

222249
def update_timestamp(self, data: bytes):
223-
"""Verifies and loads 'data' as new timestamp metadata."""
250+
"""Verifies and loads 'data' as new timestamp metadata.
251+
252+
Args:
253+
data: unverified new timestamp metadata as bytes
254+
255+
Raises:
256+
RepositoryError: Metadata failed to load or verify. The actual
257+
error type and content will contain more details.
258+
"""
224259
if not self._root_update_finished:
225260
# root_update_finished() not called
226261
raise RuntimeError("Cannot update timestamp before root")
@@ -270,7 +305,15 @@ def update_timestamp(self, data: bytes):
270305

271306
# TODO: remove pylint disable once the hash verification is in metadata.py
272307
def update_snapshot(self, data: bytes): # pylint: disable=too-many-branches
273-
"""Verifies and loads 'data' as new snapshot metadata."""
308+
"""Verifies and loads 'data' as new snapshot metadata.
309+
310+
Args:
311+
data: unverified new snapshot metadata as bytes
312+
313+
Raises:
314+
RepositoryError: Metadata failed to load or verify. The actual
315+
error type and content will contain more details.
316+
"""
274317

275318
if self.timestamp is None:
276319
raise RuntimeError("Cannot update snapshot before timestamp")
@@ -339,15 +382,30 @@ def update_snapshot(self, data: bytes): # pylint: disable=too-many-branches
339382
logger.debug("Updated snapshot")
340383

341384
def update_targets(self, data: bytes):
342-
"""Verifies and loads 'data' as new top-level targets metadata."""
385+
"""Verifies and loads 'data' as new top-level targets metadata.
386+
387+
Args:
388+
data: unverified new targets metadata as bytes
389+
390+
Raises:
391+
RepositoryError: Metadata failed to load or verify. The actual
392+
error type and content will contain more details.
393+
"""
343394
self.update_delegated_targets(data, "targets", "root")
344395

345396
def update_delegated_targets(
346397
self, data: bytes, role_name: str, delegator_name: str
347398
):
348399
"""Verifies and loads 'data' as new metadata for target 'role_name'.
349400
350-
Raises if verification fails
401+
Args:
402+
data: unverified new metadata as bytes
403+
role_name: The role name of the new metadata
404+
delegator_name: The name of the role delegating the new metadata
405+
406+
Raises:
407+
RepositoryError: Metadata failed to load or verify. The actual
408+
error type and content will contain more details.
351409
"""
352410
if self.snapshot is None:
353411
raise RuntimeError("Cannot load targets before snapshot")

0 commit comments

Comments
 (0)