73
73
Timestamp ,
74
74
)
75
75
from tuf .api .serialization .json import JSONSerializer
76
- from tuf .exceptions import FetcherHTTPError , RepositoryError
76
+ from tuf .exceptions import FetcherHTTPError
77
77
from tuf .ngclient .fetcher import FetcherInterface
78
78
79
79
logger = logging .getLogger (__name__ )
83
83
84
84
@dataclass
85
85
class RepositoryTarget :
86
- """Contains actual target data and the related target metadata"""
86
+ """Contains actual target data and the related target metadata. """
87
87
88
88
data : bytes
89
89
target_file : TargetFile
90
90
91
91
92
92
class RepositorySimulator (FetcherInterface ):
93
+ """Simulates a repository that can be used for testing."""
94
+
95
+ # pylint: disable=too-many-instance-attributes
93
96
def __init__ (self ):
94
97
self .md_root : Metadata [Root ] = None
95
98
self .md_timestamp : Metadata [Timestamp ] = None
@@ -136,6 +139,7 @@ def targets(self) -> Targets:
136
139
return self .md_targets .signed
137
140
138
141
def all_targets (self ) -> Iterator [Tuple [str , Targets ]]:
142
+ """Yield role name and signed portion of targets one by one."""
139
143
yield "targets" , self .md_targets .signed
140
144
for role , md in self .md_delegates .items ():
141
145
yield role , md .signed
@@ -151,7 +155,7 @@ def add_signer(self, role: str, signer: SSlibSigner):
151
155
self .signers [role ][signer .key_dict ["keyid" ]] = signer
152
156
153
157
def _initialize (self ):
154
- """Setup a minimal valid repository"""
158
+ """Setup a minimal valid repository. """
155
159
156
160
targets = Targets (1 , SPEC_VER , self .safe_expiry , {}, None )
157
161
self .md_targets = Metadata (targets , OrderedDict ())
@@ -176,7 +180,7 @@ def _initialize(self):
176
180
self .publish_root ()
177
181
178
182
def publish_root (self ):
179
- """Sign and store a new serialized version of root"""
183
+ """Sign and store a new serialized version of root. """
180
184
self .md_root .signatures .clear ()
181
185
for signer in self .signers ["root" ].values ():
182
186
self .md_root .sign (signer , append = True )
@@ -185,6 +189,9 @@ def publish_root(self):
185
189
logger .debug ("Published root v%d" , self .root .version )
186
190
187
191
def fetch (self , url : str ) -> Iterator [bytes ]:
192
+ """Fetches data from the given url and returns an Iterator (or yields
193
+ bytes).
194
+ """
188
195
if not self .root .consistent_snapshot :
189
196
raise NotImplementedError ("non-consistent snapshot not supported" )
190
197
path = parse .urlparse (url ).path
@@ -209,15 +216,20 @@ def fetch(self, url: str) -> Iterator[bytes]:
209
216
else :
210
217
raise FetcherHTTPError (f"Unknown path '{ path } '" , 404 )
211
218
212
- def _fetch_target (self , target_path : str , hash : Optional [str ]) -> bytes :
213
- """Return data for 'target_path', checking 'hash' if it is given.
219
+ def _fetch_target (
220
+ self , target_path : str , target_hash : Optional [str ]
221
+ ) -> bytes :
222
+ """Return data for 'target_path', checking 'target_hash' if it is given.
214
223
215
- If hash is None, then consistent_snapshot is not used
224
+ If hash is None, then consistent_snapshot is not used.
216
225
"""
217
226
repo_target = self .target_files .get (target_path )
218
227
if repo_target is None :
219
228
raise FetcherHTTPError (f"No target { target_path } " , 404 )
220
- if hash and hash not in repo_target .target_file .hashes .values ():
229
+ if (
230
+ target_hash
231
+ and target_hash not in repo_target .target_file .hashes .values ()
232
+ ):
221
233
raise FetcherHTTPError (f"hash mismatch for { target_path } " , 404 )
222
234
223
235
logger .debug ("fetched target %s" , target_path )
@@ -228,41 +240,41 @@ def _fetch_metadata(
228
240
) -> bytes :
229
241
"""Return signed metadata for 'role', using 'version' if it is given.
230
242
231
- If version is None, non-versioned metadata is being requested
243
+ If version is None, non-versioned metadata is being requested.
232
244
"""
233
245
if role == "root" :
234
246
# return a version previously serialized in publish_root()
235
247
if version is None or version > len (self .signed_roots ):
236
248
raise FetcherHTTPError (f"Unknown root version { version } " , 404 )
237
- logger .debug ("fetched root version %d" , role , version )
249
+ logger .debug ("fetched root version %d" , version )
238
250
return self .signed_roots [version - 1 ]
251
+
252
+ # sign and serialize the requested metadata
253
+ if role == "timestamp" :
254
+ md : Metadata = self .md_timestamp
255
+ elif role == "snapshot" :
256
+ md = self .md_snapshot
257
+ elif role == "targets" :
258
+ md = self .md_targets
239
259
else :
240
- # sign and serialize the requested metadata
241
- if role == "timestamp" :
242
- md : Metadata = self .md_timestamp
243
- elif role == "snapshot" :
244
- md = self .md_snapshot
245
- elif role == "targets" :
246
- md = self .md_targets
247
- else :
248
- md = self .md_delegates [role ]
249
-
250
- if md is None :
251
- raise FetcherHTTPError (f"Unknown role { role } " , 404 )
252
- if version is not None and version != md .signed .version :
253
- raise FetcherHTTPError (f"Unknown { role } version { version } " , 404 )
254
-
255
- md .signatures .clear ()
256
- for signer in self .signers [role ].values ():
257
- md .sign (signer , append = True )
258
-
259
- logger .debug (
260
- "fetched %s v%d with %d sigs" ,
261
- role ,
262
- md .signed .version ,
263
- len (self .signers [role ]),
264
- )
265
- return md .to_bytes (JSONSerializer ())
260
+ md = self .md_delegates [role ]
261
+
262
+ if md is None :
263
+ raise FetcherHTTPError (f"Unknown role { role } " , 404 )
264
+ if version is not None and version != md .signed .version :
265
+ raise FetcherHTTPError (f"Unknown { role } version { version } " , 404 )
266
+
267
+ md .signatures .clear ()
268
+ for signer in self .signers [role ].values ():
269
+ md .sign (signer , append = True )
270
+
271
+ logger .debug (
272
+ "fetched %s v%d with %d sigs" ,
273
+ role ,
274
+ md .signed .version ,
275
+ len (self .signers [role ]),
276
+ )
277
+ return md .to_bytes (JSONSerializer ())
266
278
267
279
def _compute_hashes_and_length (
268
280
self , role : str
@@ -274,6 +286,9 @@ def _compute_hashes_and_length(
274
286
return hashes , len (data )
275
287
276
288
def update_timestamp (self ):
289
+ """Update timestamp and assign snapshot version to snapshot_meta
290
+ version.
291
+ """
277
292
self .timestamp .snapshot_meta .version = self .snapshot .version
278
293
279
294
if self .compute_metafile_hashes_length :
@@ -284,6 +299,7 @@ def update_timestamp(self):
284
299
self .timestamp .version += 1
285
300
286
301
def update_snapshot (self ):
302
+ """Update snapshot, assign targets versions and update timestamp."""
287
303
for role , delegate in self .all_targets ():
288
304
hashes = None
289
305
length = None
@@ -298,6 +314,7 @@ def update_snapshot(self):
298
314
self .update_timestamp ()
299
315
300
316
def add_target (self , role : str , data : bytes , path : str ):
317
+ """Create a target from data and add it to the target_files."""
301
318
if role == "targets" :
302
319
targets = self .targets
303
320
else :
@@ -316,6 +333,7 @@ def add_delegation(
316
333
paths : Optional [List [str ]],
317
334
hash_prefixes : Optional [List [str ]],
318
335
):
336
+ """Add delegated target role to the repository."""
319
337
if delegator_name == "targets" :
320
338
delegator = self .targets
321
339
else :
@@ -347,17 +365,17 @@ def write(self):
347
365
print (f"Repository Simulator dumps in { self .dump_dir } " )
348
366
349
367
self .dump_version += 1
350
- dir = os .path .join (self .dump_dir , str (self .dump_version ))
351
- os .makedirs (dir )
368
+ dest_dir = os .path .join (self .dump_dir , str (self .dump_version ))
369
+ os .makedirs (dest_dir )
352
370
353
371
for ver in range (1 , len (self .signed_roots ) + 1 ):
354
- with open (os .path .join (dir , f"{ ver } .root.json" ), "wb" ) as f :
372
+ with open (os .path .join (dest_dir , f"{ ver } .root.json" ), "wb" ) as f :
355
373
f .write (self ._fetch_metadata ("root" , ver ))
356
374
357
375
for role in ["timestamp" , "snapshot" , "targets" ]:
358
- with open (os .path .join (dir , f"{ role } .json" ), "wb" ) as f :
376
+ with open (os .path .join (dest_dir , f"{ role } .json" ), "wb" ) as f :
359
377
f .write (self ._fetch_metadata (role ))
360
378
361
- for role in self .md_delegates . keys () :
362
- with open (os .path .join (dir , f"{ role } .json" ), "wb" ) as f :
379
+ for role in self .md_delegates :
380
+ with open (os .path .join (dest_dir , f"{ role } .json" ), "wb" ) as f :
363
381
f .write (self ._fetch_metadata (role ))
0 commit comments