39
39
)
40
40
from tuf .api .serialization import DeserializationError
41
41
from tuf .api .serialization .json import CanonicalJSONSerializer , JSONSerializer
42
+ from tuf .api .metadata import RoleNames
42
43
43
44
logger = logging .getLogger (__name__ )
44
45
@@ -70,7 +71,7 @@ def setUpClass(cls):
70
71
71
72
# Load keys into memory
72
73
cls .keystore = {}
73
- for role in ["delegation" , "snapshot" , "targets" , "timestamp" ]:
74
+ for role in ["delegation" , RoleNames . SNAPSHOT . value , RoleNames . TARGETS . value , RoleNames . TIMESTAMP . value ]:
74
75
cls .keystore [role ] = import_ed25519_privatekey_from_file (
75
76
os .path .join (cls .keystore_dir , role + "_key" ),
76
77
password = "password" ,
@@ -84,10 +85,10 @@ def tearDownClass(cls):
84
85
85
86
def test_generic_read (self ):
86
87
for metadata , inner_metadata_cls in [
87
- ("root" , Root ),
88
- ("snapshot" , Snapshot ),
89
- ("timestamp" , Timestamp ),
90
- ("targets" , Targets ),
88
+ (RoleNames . ROOT . value , Root ),
89
+ (RoleNames . SNAPSHOT . value , Snapshot ),
90
+ (RoleNames . TIMESTAMP . value , Timestamp ),
91
+ (RoleNames . TARGETS . value , Targets ),
91
92
]:
92
93
93
94
# Load JSON-formatted metdata of each supported type from file
@@ -128,7 +129,7 @@ def test_compact_json(self):
128
129
)
129
130
130
131
def test_read_write_read_compare (self ):
131
- for metadata in ["root" , "snapshot" , "timestamp" , "targets" ]:
132
+ for metadata in [RoleNames . ROOT . value , RoleNames . SNAPSHOT . value , RoleNames . TIMESTAMP . value , RoleNames . TARGETS . value ]:
132
133
path = os .path .join (self .repo_dir , "metadata" , metadata + ".json" )
133
134
md_obj = Metadata .from_file (path )
134
135
@@ -140,7 +141,7 @@ def test_read_write_read_compare(self):
140
141
os .remove (path_2 )
141
142
142
143
def test_to_from_bytes (self ):
143
- for metadata in ["root" , "snapshot" , "timestamp" , "targets" ]:
144
+ for metadata in [RoleNames . ROOT . value , RoleNames . SNAPSHOT . value , RoleNames . TIMESTAMP . value , RoleNames . TARGETS . value ]:
144
145
path = os .path .join (self .repo_dir , "metadata" , metadata + ".json" )
145
146
with open (path , "rb" ) as f :
146
147
metadata_bytes = f .read ()
@@ -161,11 +162,11 @@ def test_sign_verify(self):
161
162
root = Metadata [Root ].from_file (root_path ).signed
162
163
163
164
# Locate the public keys we need from root
164
- targets_keyid = next (iter (root .roles ["targets" ].keyids ))
165
+ targets_keyid = next (iter (root .roles [RoleNames . TARGETS . value ].keyids ))
165
166
targets_key = root .keys [targets_keyid ]
166
- snapshot_keyid = next (iter (root .roles ["snapshot" ].keyids ))
167
+ snapshot_keyid = next (iter (root .roles [RoleNames . SNAPSHOT . value ].keyids ))
167
168
snapshot_key = root .keys [snapshot_keyid ]
168
- timestamp_keyid = next (iter (root .roles ["timestamp" ].keyids ))
169
+ timestamp_keyid = next (iter (root .roles [RoleNames . TIMESTAMP . value ].keyids ))
169
170
timestamp_key = root .keys [timestamp_keyid ]
170
171
171
172
# Load sample metadata (targets) and assert ...
@@ -184,7 +185,7 @@ def test_sign_verify(self):
184
185
with self .assertRaises (exceptions .UnsignedMetadataError ):
185
186
targets_key .verify_signature (md_obj , JSONSerializer ())
186
187
187
- sslib_signer = SSlibSigner (self .keystore ["snapshot" ])
188
+ sslib_signer = SSlibSigner (self .keystore [RoleNames . SNAPSHOT . value ])
188
189
# Append a new signature with the unrelated key and assert that ...
189
190
sig = md_obj .sign (sslib_signer , append = True )
190
191
# ... there are now two signatures, and
@@ -195,7 +196,7 @@ def test_sign_verify(self):
195
196
# ... the returned (appended) signature is for snapshot key
196
197
self .assertEqual (sig .keyid , snapshot_keyid )
197
198
198
- sslib_signer = SSlibSigner (self .keystore ["timestamp" ])
199
+ sslib_signer = SSlibSigner (self .keystore [RoleNames . TIMESTAMP . value ])
199
200
# Create and assign (don't append) a new signature and assert that ...
200
201
md_obj .sign (sslib_signer , append = False )
201
202
# ... there now is only one signature,
@@ -210,7 +211,7 @@ def test_verify_failures(self):
210
211
root = Metadata [Root ].from_file (root_path ).signed
211
212
212
213
# Locate the timestamp public key we need from root
213
- timestamp_keyid = next (iter (root .roles ["timestamp" ].keyids ))
214
+ timestamp_keyid = next (iter (root .roles [RoleNames . TIMESTAMP . value ].keyids ))
214
215
timestamp_key = root .keys [timestamp_keyid ]
215
216
216
217
# Load sample metadata (timestamp)
@@ -361,20 +362,20 @@ def test_metadata_verify_delegate(self):
361
362
role2 = Metadata [Targets ].from_file (role2_path )
362
363
363
364
# test the expected delegation tree
364
- root .verify_delegate ("root" , root )
365
- root .verify_delegate ("snapshot" , snapshot )
366
- root .verify_delegate ("targets" , targets )
365
+ root .verify_delegate (RoleNames . ROOT . value , root )
366
+ root .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
367
+ root .verify_delegate (RoleNames . TARGETS . value , targets )
367
368
targets .verify_delegate ("role1" , role1 )
368
369
role1 .verify_delegate ("role2" , role2 )
369
370
370
371
# only root and targets can verify delegates
371
372
with self .assertRaises (TypeError ):
372
- snapshot .verify_delegate ("snapshot" , snapshot )
373
+ snapshot .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
373
374
# verify fails for roles that are not delegated by delegator
374
375
with self .assertRaises (ValueError ):
375
376
root .verify_delegate ("role1" , role1 )
376
377
with self .assertRaises (ValueError ):
377
- targets .verify_delegate ("targets" , targets )
378
+ targets .verify_delegate (RoleNames . TARGETS . value , targets )
378
379
# verify fails when delegator has no delegations
379
380
with self .assertRaises (ValueError ):
380
381
role2 .verify_delegate ("role1" , role1 )
@@ -383,31 +384,31 @@ def test_metadata_verify_delegate(self):
383
384
expires = snapshot .signed .expires
384
385
snapshot .signed .bump_expiration ()
385
386
with self .assertRaises (exceptions .UnsignedMetadataError ):
386
- root .verify_delegate ("snapshot" , snapshot )
387
+ root .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
387
388
snapshot .signed .expires = expires
388
389
389
390
# verify fails if roles keys do not sign the metadata
390
391
with self .assertRaises (exceptions .UnsignedMetadataError ):
391
- root .verify_delegate ("timestamp" , snapshot )
392
+ root .verify_delegate (RoleNames . TIMESTAMP . value , snapshot )
392
393
393
394
# Add a key to snapshot role, make sure the new sig fails to verify
394
- ts_keyid = next (iter (root .signed .roles ["timestamp" ].keyids ))
395
- root .signed .add_key ("snapshot" , root .signed .keys [ts_keyid ])
395
+ ts_keyid = next (iter (root .signed .roles [RoleNames . TIMESTAMP . value ].keyids ))
396
+ root .signed .add_key (RoleNames . SNAPSHOT . value , root .signed .keys [ts_keyid ])
396
397
snapshot .signatures [ts_keyid ] = Signature (ts_keyid , "ff" * 64 )
397
398
398
399
# verify succeeds if threshold is reached even if some signatures
399
400
# fail to verify
400
- root .verify_delegate ("snapshot" , snapshot )
401
+ root .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
401
402
402
403
# verify fails if threshold of signatures is not reached
403
- root .signed .roles ["snapshot" ].threshold = 2
404
+ root .signed .roles [RoleNames . SNAPSHOT . value ].threshold = 2
404
405
with self .assertRaises (exceptions .UnsignedMetadataError ):
405
- root .verify_delegate ("snapshot" , snapshot )
406
+ root .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
406
407
407
408
# verify succeeds when we correct the new signature and reach the
408
409
# threshold of 2 keys
409
- snapshot .sign (SSlibSigner (self .keystore ["timestamp" ]), append = True )
410
- root .verify_delegate ("snapshot" , snapshot )
410
+ snapshot .sign (SSlibSigner (self .keystore [RoleNames . TIMESTAMP . value ]), append = True )
411
+ root .verify_delegate (RoleNames . SNAPSHOT . value , snapshot )
411
412
412
413
def test_key_class (self ):
413
414
# Test if from_securesystemslib_key removes the private key from keyval
@@ -433,44 +434,44 @@ def test_root_add_key_and_remove_key(self):
433
434
)
434
435
435
436
# Assert that root does not contain the new key
436
- self .assertNotIn (keyid , root .signed .roles ["root" ].keyids )
437
+ self .assertNotIn (keyid , root .signed .roles [RoleNames . ROOT . value ].keyids )
437
438
self .assertNotIn (keyid , root .signed .keys )
438
439
439
440
# Add new root key
440
- root .signed .add_key ("root" , key_metadata )
441
+ root .signed .add_key (RoleNames . ROOT . value , key_metadata )
441
442
442
443
# Assert that key is added
443
- self .assertIn (keyid , root .signed .roles ["root" ].keyids )
444
+ self .assertIn (keyid , root .signed .roles [RoleNames . ROOT . value ].keyids )
444
445
self .assertIn (keyid , root .signed .keys )
445
446
446
447
# Confirm that the newly added key does not break
447
448
# the object serialization
448
449
root .to_dict ()
449
450
450
451
# Try adding the same key again and assert its ignored.
451
- pre_add_keyid = root .signed .roles ["root" ].keyids .copy ()
452
- root .signed .add_key ("root" , key_metadata )
453
- self .assertEqual (pre_add_keyid , root .signed .roles ["root" ].keyids )
452
+ pre_add_keyid = root .signed .roles [RoleNames . ROOT . value ].keyids .copy ()
453
+ root .signed .add_key (RoleNames . ROOT . value , key_metadata )
454
+ self .assertEqual (pre_add_keyid , root .signed .roles [RoleNames . ROOT . value ].keyids )
454
455
455
456
# Add the same key to targets role as well
456
- root .signed .add_key ("targets" , key_metadata )
457
+ root .signed .add_key (RoleNames . TARGETS . value , key_metadata )
457
458
458
459
# Add the same key to a nonexistent role.
459
460
with self .assertRaises (ValueError ):
460
461
root .signed .add_key ("nosuchrole" , key_metadata )
461
462
462
463
# Remove the key from root role (targets role still uses it)
463
- root .signed .remove_key ("root" , keyid )
464
- self .assertNotIn (keyid , root .signed .roles ["root" ].keyids )
464
+ root .signed .remove_key (RoleNames . ROOT . value , keyid )
465
+ self .assertNotIn (keyid , root .signed .roles [RoleNames . ROOT . value ].keyids )
465
466
self .assertIn (keyid , root .signed .keys )
466
467
467
468
# Remove the key from targets as well
468
- root .signed .remove_key ("targets" , keyid )
469
- self .assertNotIn (keyid , root .signed .roles ["targets" ].keyids )
469
+ root .signed .remove_key (RoleNames . TARGETS . value , keyid )
470
+ self .assertNotIn (keyid , root .signed .roles [RoleNames . TARGETS . value ].keyids )
470
471
self .assertNotIn (keyid , root .signed .keys )
471
472
472
473
with self .assertRaises (ValueError ):
473
- root .signed .remove_key ("root" , "nosuchkey" )
474
+ root .signed .remove_key (RoleNames . ROOT . value , "nosuchkey" )
474
475
with self .assertRaises (ValueError ):
475
476
root .signed .remove_key ("nosuchrole" , keyid )
476
477
@@ -661,7 +662,7 @@ def test_length_and_hash_validation(self):
661
662
targets_path = os .path .join (self .repo_dir , "metadata" , "targets.json" )
662
663
targets = Metadata [Targets ].from_file (targets_path )
663
664
file1_targetfile = targets .signed .targets ["file1.txt" ]
664
- filepath = os .path .join (self .repo_dir , "targets" , "file1.txt" )
665
+ filepath = os .path .join (self .repo_dir , RoleNames . TARGETS . value , "file1.txt" )
665
666
666
667
with open (filepath , "rb" ) as file1 :
667
668
file1_targetfile .verify_length_and_hashes (file1 )
@@ -679,7 +680,7 @@ def test_length_and_hash_validation(self):
679
680
680
681
def test_targetfile_from_file (self ):
681
682
# Test with an existing file and valid hash algorithm
682
- file_path = os .path .join (self .repo_dir , "targets" , "file1.txt" )
683
+ file_path = os .path .join (self .repo_dir , RoleNames . TARGETS . value , "file1.txt" )
683
684
targetfile_from_file = TargetFile .from_file (
684
685
file_path , file_path , ["sha256" ]
685
686
)
@@ -688,20 +689,20 @@ def test_targetfile_from_file(self):
688
689
targetfile_from_file .verify_length_and_hashes (file )
689
690
690
691
# Test with a non-existing file
691
- file_path = os .path .join (self .repo_dir , "targets" , "file123.txt" )
692
+ file_path = os .path .join (self .repo_dir , RoleNames . TARGETS . value , "file123.txt" )
692
693
with self .assertRaises (FileNotFoundError ):
693
694
TargetFile .from_file (
694
695
file_path , file_path , [sslib_hash .DEFAULT_HASH_ALGORITHM ]
695
696
)
696
697
697
698
# Test with an unsupported algorithm
698
- file_path = os .path .join (self .repo_dir , "targets" , "file1.txt" )
699
+ file_path = os .path .join (self .repo_dir , RoleNames . TARGETS . value , "file1.txt" )
699
700
with self .assertRaises (exceptions .UnsupportedAlgorithmError ):
700
701
TargetFile .from_file (file_path , file_path , ["123" ])
701
702
702
703
def test_targetfile_from_data (self ):
703
704
data = b"Inline test content"
704
- target_file_path = os .path .join (self .repo_dir , "targets" , "file1.txt" )
705
+ target_file_path = os .path .join (self .repo_dir , RoleNames . TARGETS . value , "file1.txt" )
705
706
706
707
# Test with a valid hash algorithm
707
708
targetfile_from_data = TargetFile .from_data (
0 commit comments