11import logging
2+ from typing import Optional , Union
23import os
34import sys
45import unittest
56from datetime import datetime
67
78from tuf import exceptions
8- from tuf .api .metadata import Metadata
9- from tuf .ngclient ._internal .trusted_metadata_set import (
10- TrustedMetadataSet
11- )
9+ from tuf .api .metadata import Metadata , MetaFile
10+ from tuf .ngclient ._internal .trusted_metadata_set import TrustedMetadataSet
11+
1212from securesystemslib .signer import SSlibSigner
1313from securesystemslib .interface import (
1414 import_ed25519_privatekey_from_file ,
@@ -48,14 +48,77 @@ def setUpClass(cls):
4848 def setUp (self ) -> None :
4949 self .trusted_set = TrustedMetadataSet (self .metadata ["root" ])
5050
51- def _root_update_finished_and_update_timestamp (self ):
52- self .trusted_set .root_update_finished ()
53- self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
51+ def _root_updated_and_update_timestamp (
52+ self , timestamp_bytes : Optional [bytes ] = None
53+ ):
54+ """Finsh root update and update timestamp with passed timestamp_bytes.
55+
56+ Args:
57+ timestamp_bytes:
58+ Bytes used when calling trusted_set.update_timestamp().
59+ Default self.metadata["timestamp"].
5460
55- def _update_all_besides_targets (self ):
61+ """
62+ timestamp_bytes = timestamp_bytes or self .metadata ["timestamp" ]
5663 self .trusted_set .root_update_finished ()
57- self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
58- self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
64+ self .trusted_set .update_timestamp (timestamp_bytes )
65+
66+
67+ def _update_all_besides_targets (
68+ self ,
69+ timestamp_bytes : Optional [bytes ] = None ,
70+ snapshot_bytes : Optional [bytes ] = None ,
71+ ):
72+ """Update all metadata roles besides targets.
73+
74+ Args:
75+ timestamp_bytes:
76+ Bytes used when calling trusted_set.update_timestamp().
77+ Default self.metadata["timestamp"].
78+ snapshot_bytes:
79+ Bytes used when calling trusted_set.update_snapshot().
80+ Default self.metadata["snapshot"].
81+
82+ """
83+ self ._root_updated_and_update_timestamp (timestamp_bytes )
84+ snapshot_bytes = snapshot_bytes or self .metadata ["snapshot" ]
85+ self .trusted_set .update_snapshot (snapshot_bytes )
86+
87+ def _modify_timestamp_meta (self , version : Optional [int ] = 1 ):
88+ """Remove hashes and length from timestamp.meta["snapshot.json"].
89+ Create a timestamp.meta["snapshot.json"] containing only version.
90+
91+ Args:
92+ version:
93+ Version used when instantiating MetaFile for timestamp.meta.
94+
95+ """
96+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
97+ timestamp .signed .meta ["snapshot.json" ] = MetaFile (version )
98+ timestamp .sign (self .keystore ["timestamp" ])
99+ return timestamp .to_bytes ()
100+
101+ def _modify_snapshot_meta (
102+ self , version : Union [int , None ] = 1 , length : Optional [int ]= None
103+ ):
104+ """Modify hashes and length from snapshot_meta.meta["snapshot.json"].
105+ If version and length is None, then snapshot meta will be an empty dictionary.
106+
107+ Args:
108+ version:
109+ Version used when instantiating MetaFile for snapshot.meta.
110+ length:
111+ Length used when instantiating MetaFile for snapshot.meta.
112+
113+ """
114+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
115+ if version is None and length is None :
116+ snapshot .signed .meta = {}
117+ else :
118+ for metafile_path in snapshot .signed .meta :
119+ snapshot .signed .meta [metafile_path ] = MetaFile (version , length )
120+ snapshot .sign (self .keystore ["snapshot" ])
121+ return snapshot .to_bytes ()
59122
60123 def test_update (self ):
61124 self .trusted_set .root_update_finished ()
@@ -183,21 +246,23 @@ def test_root_update_finished_expired(self):
183246
184247
185248 def test_update_timestamp_new_timestamp_ver_below_trusted_ver (self ):
186- self ._root_update_finished_and_update_timestamp ()
187249 # new_timestamp.version < trusted_timestamp.version
188- self .trusted_set .timestamp .signed .version = 2
250+ timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
251+ timestamp .signed .version = 3
252+ timestamp .sign (self .keystore ["timestamp" ])
253+ self ._root_updated_and_update_timestamp (timestamp .to_bytes ())
189254 with self .assertRaises (exceptions .ReplayedMetadataError ):
190255 self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
191256
192257 def test_update_timestamp_snapshot_ver_below_trusted_snapshot_ver (self ):
193- self ._root_update_finished_and_update_timestamp ()
258+ modified_timestamp = self ._modify_timestamp_meta (version = 3 )
259+ self ._root_updated_and_update_timestamp (modified_timestamp )
194260 # new_timestamp.snapshot.version < trusted_timestamp.snapshot.version
195- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
196261 with self .assertRaises (exceptions .ReplayedMetadataError ):
197262 self .trusted_set .update_timestamp (self .metadata ["timestamp" ])
198263
199264 def test_update_timestamp_expired (self ):
200- self ._root_update_finished_and_update_timestamp ()
265+ self .trusted_set . root_update_finished ()
201266 # new_timestamp has expired
202267 timestamp = Metadata .from_bytes (self .metadata ["timestamp" ])
203268 timestamp .signed .expires = datetime (1970 , 1 , 1 )
@@ -207,70 +272,86 @@ def test_update_timestamp_expired(self):
207272
208273
209274 def test_update_snapshot_cannot_verify_snapshot_with_threshold (self ):
210- self ._root_update_finished_and_update_timestamp ()
211- # remove keyids representing snapshot signatures from root data
212- self .trusted_set .root .signed .roles ["snapshot" ].keyids = []
275+ modified_timestamp = self ._modify_timestamp_meta ()
276+ self ._root_updated_and_update_timestamp (modified_timestamp )
277+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
278+ snapshot .signatures .clear ()
213279 with self .assertRaises (exceptions .UnsignedMetadataError ):
214- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
280+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
215281
216282 def test_update_snapshot_version_different_timestamp_snapshot_version (self ):
217- self ._root_update_finished_and_update_timestamp ()
283+ modified_timestamp = self ._modify_timestamp_meta (version = 2 )
284+ self ._root_updated_and_update_timestamp (modified_timestamp )
218285 # new_snapshot.version != trusted timestamp.meta["snapshot"].version
219- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].version = 2
286+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
287+ snapshot .signed .version = 3
288+ snapshot .sign (self .keystore ["snapshot" ])
220289 with self .assertRaises (exceptions .BadVersionNumberError ):
221- self .trusted_set .update_snapshot (self . metadata [ " snapshot" ] )
290+ self .trusted_set .update_snapshot (snapshot . to_bytes () )
222291
223292 def test_update_snapshot_after_successful_update_new_snapshot_no_meta (self ):
224- self ._update_all_besides_targets ()
293+ modified_timestamp = self ._modify_timestamp_meta ()
294+ self ._update_all_besides_targets (modified_timestamp )
225295 # Test removing a meta_file in new_snapshot compared to the old snapshot
226296 snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
227297 snapshot .signed .meta = {}
228298 snapshot .sign (self .keystore ["snapshot" ])
229- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].hashes = None
230- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].length = None
231299 with self .assertRaises (exceptions .RepositoryError ):
232300 self .trusted_set .update_snapshot (snapshot .to_bytes ())
233301
234302 def test_update_snapshot_after_succesfull_update_new_snapshot_meta_version_different (self ):
235- self ._update_all_besides_targets ()
303+ modified_timestamp = self ._modify_timestamp_meta ()
304+ self ._root_updated_and_update_timestamp (modified_timestamp )
236305 # snapshot.meta["project1"].version != new_snapshot.meta["project1"].version
237- for metafile in self .trusted_set .snapshot .signed .meta .values ():
238- metafile .version += 1
306+ snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
307+ for metafile_path in snapshot .signed .meta .keys ():
308+ snapshot .signed .meta [metafile_path ].version += 1
309+ snapshot .sign (self .keystore ["snapshot" ])
310+ self .trusted_set .update_snapshot (snapshot .to_bytes ())
239311 with self .assertRaises (exceptions .BadVersionNumberError ):
240312 self .trusted_set .update_snapshot (self .metadata ["snapshot" ])
241313
242- def test_update_snapshot_after_succesfull_expired_new_snapshot (self ):
243- self ._update_all_besides_targets ()
314+ def test_update_snapshot_expired_new_snapshot (self ):
315+ modified_timestamp = self ._modify_timestamp_meta ()
316+ self ._root_updated_and_update_timestamp (modified_timestamp )
244317 # new_snapshot has expired
245318 snapshot = Metadata .from_bytes (self .metadata ["snapshot" ])
246319 snapshot .signed .expires = datetime (1970 , 1 , 1 )
247320 snapshot .sign (self .keystore ["snapshot" ])
248- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].hashes = None
249- self .trusted_set .timestamp .signed .meta ["snapshot.json" ].length = None
250321 with self .assertRaises (exceptions .ExpiredMetadataError ):
251322 self .trusted_set .update_snapshot (snapshot .to_bytes ())
252323
253324
254325 def test_update_targets_no_meta_in_snapshot (self ):
255- self ._update_all_besides_targets ()
326+ modified_timestamp = self ._modify_timestamp_meta ()
327+ modified_snapshot = self ._modify_snapshot_meta (version = None )
328+ self ._update_all_besides_targets (
329+ timestamp_bytes = modified_timestamp ,
330+ snapshot_bytes = modified_snapshot
331+ )
256332 # remove meta information with information about targets from snapshot
257- self .trusted_set .snapshot .signed .meta = {}
258333 with self .assertRaises (exceptions .RepositoryError ):
259334 self .trusted_set .update_targets (self .metadata ["targets" ])
260335
261336 def test_update_targets_hash_different_than_snapshot_meta_hash (self ):
262- self ._update_all_besides_targets ()
337+ modified_timestamp = self ._modify_timestamp_meta ()
338+ modified_snapshot = self ._modify_snapshot_meta (version = 1 , length = 1 )
339+ self ._update_all_besides_targets (
340+ timestamp_bytes = modified_timestamp ,
341+ snapshot_bytes = modified_snapshot
342+ )
263343 # observed_hash != stored hash in snapshot meta for targets
264- for target_path in self .trusted_set .snapshot .signed .meta .keys ():
265- self .trusted_set .snapshot .signed .meta [target_path ].hashes = {"sha256" : "b" }
266344 with self .assertRaises (exceptions .RepositoryError ):
267345 self .trusted_set .update_targets (self .metadata ["targets" ])
268346
269347 def test_update_targets_version_different_snapshot_meta_version (self ):
270- self ._update_all_besides_targets ()
348+ modified_timestamp = self ._modify_timestamp_meta ()
349+ modified_snapshot = self ._modify_snapshot_meta (version = 2 )
350+ self ._update_all_besides_targets (
351+ timestamp_bytes = modified_timestamp ,
352+ snapshot_bytes = modified_snapshot
353+ )
271354 # new_delegate.signed.version != meta.version stored in snapshot
272- for target_path in self .trusted_set .snapshot .signed .meta .keys ():
273- self .trusted_set .snapshot .signed .meta [target_path ].version = 2
274355 with self .assertRaises (exceptions .BadVersionNumberError ):
275356 self .trusted_set .update_targets (self .metadata ["targets" ])
276357
0 commit comments