@@ -77,14 +77,14 @@ def __init__(
77
77
self .signatures = signatures
78
78
79
79
def as_dict (self ) -> JsonDict :
80
- """Returns the JSON-compatible dictionary representation. """
80
+ """Returns the JSON-serializable dictionary representation of self . """
81
81
return {
82
82
'signatures' : self .signatures ,
83
83
'signed' : self .signed .as_dict ()
84
84
}
85
85
86
86
def as_json (self , compact : bool = False ) -> None :
87
- """Returns the optionally compacted JSON representation. """
87
+ """Returns the optionally compacted JSON representation of self . """
88
88
return json .dumps (
89
89
self .as_dict (),
90
90
indent = (None if compact else 1 ),
@@ -141,7 +141,7 @@ def read_from_json(
141
141
cls , filename : str ,
142
142
storage_backend : Optional [StorageBackendInterface ] = None
143
143
) -> 'Metadata' :
144
- """Loads JSON-formatted TUF metadata from a file storage.
144
+ """Loads JSON-formatted TUF metadata from file storage.
145
145
146
146
Arguments:
147
147
filename: The path to read the file from.
@@ -183,7 +183,7 @@ def read_from_json(
183
183
def write_to_json (
184
184
self , filename : str , compact : bool = False ,
185
185
storage_backend : StorageBackendInterface = None ) -> None :
186
- """Writes the JSON representation of the instance to file storage.
186
+ """Writes the JSON representation of self to file storage.
187
187
188
188
Arguments:
189
189
filename: The path to write the file to.
@@ -203,6 +203,21 @@ def write_to_json(
203
203
204
204
205
205
class Signed :
206
+ """A base class for the signed part of TUF metadata.
207
+
208
+ Objects with base class Signed are usually included in a Metablock object
209
+ on the signed attribute. This class provides attributes and methods that
210
+ are common for all TUF metadata types (roles).
211
+
212
+ Attributes:
213
+ _type: The metadata type string.
214
+ version: The metadata version number.
215
+ spec_version: The TUF specification version number (semver) the
216
+ metadata format adheres to.
217
+ expires: The metadata expiration date in 'YYYY-MM-DDTHH:MM:SSZ' format.
218
+ signed_bytes: The UTF-8 encoded canonical JSON representation of self.
219
+
220
+ """
206
221
# NOTE: Signed is a stupid name, because this might not be signed yet, but
207
222
# we keep it to match spec terminology (I often refer to this as "payload",
208
223
# or "inner metadata")
@@ -237,19 +252,18 @@ def signed_bytes(self) -> bytes:
237
252
238
253
@property
239
254
def expires (self ) -> str :
240
- """The expiration property in TUF metadata format."""
241
255
return self .__expiration .isoformat () + 'Z'
242
256
243
257
def bump_expiration (self , delta : timedelta = timedelta (days = 1 )) -> None :
258
+ """Increments the expires attribute by the passed timedelta. """
244
259
self .__expiration = self .__expiration + delta
245
260
246
261
def bump_version (self ) -> None :
262
+ """Increments the metadata version number by 1."""
247
263
self .version += 1
248
264
249
265
def as_dict (self ) -> JsonDict :
250
- # NOTE: The classes should be the single source of truth about metadata
251
- # let's define the dict representation here and not in some dubious
252
- # build_dict_conforming_to_schema
266
+ """Returns the JSON-serializable dictionary representation of self. """
253
267
return {
254
268
'_type' : self ._type ,
255
269
'version' : self .version ,
@@ -263,7 +277,24 @@ def read_from_json(
263
277
storage_backend : Optional [StorageBackendInterface ] = None
264
278
) -> Metadata :
265
279
signable = load_json_file (filename , storage_backend )
280
+ """Loads corresponding JSON-formatted metadata from file storage.
281
+
282
+ Arguments:
283
+ filename: The path to read the file from.
284
+ storage_backend: An object that implements
285
+ securesystemslib.storage.StorageBackendInterface. Per default
286
+ a (local) FilesystemBackend is used.
287
+
288
+ Raises:
289
+ securesystemslib.exceptions.StorageError: The file cannot be read.
290
+ securesystemslib.exceptions.Error, ValueError: The metadata cannot
291
+ be parsed.
292
+
293
+ Returns:
294
+ A TUF Metadata object whose signed attribute contains an object
295
+ of this class.
266
296
297
+ """
267
298
# FIXME: It feels dirty to access signable["signed"]["version"] here in
268
299
# order to do this check, and also a bit random (there are likely other
269
300
# things to check), but later we don't have the filename anymore. If we
@@ -281,21 +312,37 @@ def read_from_json(
281
312
282
313
283
314
class Timestamp (Signed ):
315
+ """A container for the signed part of timestamp metadata.
316
+
317
+ Attributes:
318
+ meta: A dictionary that contains information about snapshot metadata::
319
+
320
+ {
321
+ "snapshot.json": {
322
+ "version" : <snapshot metadata version number>,
323
+ "length" : <snapshot metadata file size> // optional
324
+ "hashes" : <snapshot metadata file hash dict> // optional
325
+ }
326
+ }
327
+
328
+ """
284
329
def __init__ (self , meta : JsonDict = None , ** kwargs ) -> None :
285
330
super ().__init__ (** kwargs )
286
331
# TODO: How much init magic do we want?
287
332
# TODO: Is there merit in creating classes for dict fields?
288
333
self .meta = meta
289
334
290
335
def as_dict (self ) -> JsonDict :
336
+ """Returns the JSON-serializable dictionary representation of self. """
291
337
json_dict = super ().as_dict ()
292
338
json_dict .update ({
293
339
'meta' : self .meta
294
340
})
295
341
return json_dict
296
342
297
- # Update metadata about the snapshot metadata.
298
343
def update (self , version : int , length : int , hashes : JsonDict ) -> None :
344
+ """Assigns passed info about snapshot metadata to meta dictionary. """
345
+ # TODO: Should we assign it
299
346
fileinfo = self .meta .get ('snapshot.json' , {})
300
347
fileinfo ['version' ] = version
301
348
fileinfo ['length' ] = length
@@ -304,13 +351,35 @@ def update(self, version: int, length: int, hashes: JsonDict) -> None:
304
351
305
352
306
353
class Snapshot (Signed ):
354
+ """A container for the signed part of snapshot metadata.
355
+
356
+ Attributes:
357
+ meta: A dictionary that contains information about targets metadata::
358
+
359
+ {
360
+ "targets.json": {
361
+ "version" : <targets metadata version number>,
362
+ "length" : <targets metadata file size> // optional
363
+ "hashes" : <targets metadata file hash dict> // optional
364
+ },
365
+ "<delegated targets role 1>.json>: {
366
+ ...
367
+ },
368
+ "<delegated targets role 2>.json>: {
369
+ ...
370
+ },
371
+ ...
372
+ }
373
+
374
+ """
307
375
def __init__ (self , meta : JsonDict = None , ** kwargs ) -> None :
308
376
# TODO: How much init magic do we want?
309
377
# TODO: Is there merit in creating classes for dict fields?
310
378
super ().__init__ (** kwargs )
311
379
self .meta = meta
312
380
313
381
def as_dict (self ) -> JsonDict :
382
+ """Returns the JSON-serializable dictionary representation of self. """
314
383
json_dict = super ().as_dict ()
315
384
json_dict .update ({
316
385
'meta' : self .meta
@@ -321,6 +390,7 @@ def as_dict(self) -> JsonDict:
321
390
def update (
322
391
self , rolename : str , version : int , length : Optional [int ] = None ,
323
392
hashes : Optional [JsonDict ] = None ) -> None :
393
+ """Add or update the meta dictionary for a given targets role. """
324
394
metadata_fn = f'{ rolename } .json'
325
395
326
396
self .meta [metadata_fn ] = {'version' : version }
0 commit comments