@@ -116,6 +116,22 @@ def test_init(self):
116
116
117
117
118
118
119
+ def create_repository_directory (self ):
120
+ # Create a repository directory and copy in test targets data
121
+ temporary_directory = tempfile .mkdtemp (dir = self .temporary_directory )
122
+ targets_directory = os .path .join (temporary_directory , 'repository' ,
123
+ repo_tool .TARGETS_DIRECTORY_NAME )
124
+ original_targets_directory = os .path .join ('repository_data' ,
125
+ 'repository' , 'targets' )
126
+ shutil .copytree (original_targets_directory , targets_directory )
127
+
128
+ # In this case, create_new_repository() creates the 'repository/'
129
+ # sub-directory in 'temporary_directory' if it does not exist.
130
+ return os .path .join (temporary_directory , 'repository' )
131
+
132
+
133
+
134
+
119
135
def test_writeall (self ):
120
136
# Test creation of a TUF repository.
121
137
#
@@ -129,16 +145,7 @@ def test_writeall(self):
129
145
# Copy the target files from 'tuf/tests/repository_data' so that writeall()
130
146
# has target fileinfo to include in metadata.
131
147
repository_name = 'test_repository'
132
- temporary_directory = tempfile .mkdtemp (dir = self .temporary_directory )
133
- targets_directory = os .path .join (temporary_directory , 'repository' ,
134
- repo_tool .TARGETS_DIRECTORY_NAME )
135
- original_targets_directory = os .path .join ('repository_data' ,
136
- 'repository' , 'targets' )
137
- shutil .copytree (original_targets_directory , targets_directory )
138
-
139
- # In this case, create_new_repository() creates the 'repository/'
140
- # sub-directory in 'temporary_directory' if it does not exist.
141
- repository_directory = os .path .join (temporary_directory , 'repository' )
148
+ repository_directory = self .create_repository_directory ()
142
149
metadata_directory = os .path .join (repository_directory ,
143
150
repo_tool .METADATA_STAGED_DIRECTORY_NAME )
144
151
@@ -550,6 +557,170 @@ def test_get_filepaths_in_directory(self):
550
557
551
558
552
559
560
+ def test_writeall_abstract_storage (self ):
561
+ # Test creation of a TUF repository with a custom storage backend to ensure
562
+ # that functions relying on a storage backend being supplied operate
563
+ # correctly
564
+
565
+
566
+ class TestStorageBackend (securesystemslib .storage .StorageBackendInterface ):
567
+ """
568
+ An implementation of securesystemslib.storage.StorageBackendInterface
569
+ which mutates filenames on put()/get(), translating filename in memory
570
+ to filename + '.tst' on-disk, such that trying to read the
571
+ expected/canonical file paths from local storage doesn't find the TUF
572
+ metadata files.
573
+ """
574
+
575
+ from contextlib import contextmanager
576
+
577
+
578
+ @contextmanager
579
+ def get (self , filepath ):
580
+ file_object = open (filepath + '.tst' , 'rb' )
581
+ yield file_object
582
+ file_object .close ()
583
+
584
+
585
+ def put (self , fileobj , filepath ):
586
+ if not fileobj .closed :
587
+ fileobj .seek (0 )
588
+
589
+ with open (filepath + '.tst' , 'wb' ) as destination_file :
590
+ shutil .copyfileobj (fileobj , destination_file )
591
+ destination_file .flush ()
592
+ os .fsync (destination_file .fileno ())
593
+
594
+
595
+ def remove (self , filepath ):
596
+ os .remove (filepath + '.tst' )
597
+
598
+
599
+ def getsize (self , filepath ):
600
+ return os .path .getsize (filepath + '.tst' )
601
+
602
+
603
+ def create_folder (self , filepath ):
604
+ if not filepath :
605
+ return
606
+ try :
607
+ os .makedirs (filepath )
608
+ except OSError as err :
609
+ pass
610
+
611
+
612
+ def list_folder (self , filepath ):
613
+ contents = []
614
+ files = os .listdir (filepath )
615
+
616
+ for fi in files :
617
+ if fi .endswith ('.tst' ):
618
+ contents .append (fi .split ('.tst' )[0 ])
619
+ else :
620
+ contents .append (fi )
621
+
622
+ return contents
623
+
624
+
625
+
626
+ # Set up the repository directory
627
+ repository_name = 'test_repository'
628
+ repository_directory = self .create_repository_directory ()
629
+ metadata_directory = os .path .join (repository_directory ,
630
+ repo_tool .METADATA_STAGED_DIRECTORY_NAME )
631
+ targets_directory = os .path .join (repository_directory ,
632
+ repo_tool .TARGETS_DIRECTORY_NAME )
633
+
634
+ # TestStorageBackend expects all files on disk to have an additional '.tst'
635
+ # file extension
636
+ for target in os .listdir (targets_directory ):
637
+ src = os .path .join (targets_directory , target )
638
+ dst = os .path .join (targets_directory , target + '.tst' )
639
+ os .rename (src , dst )
640
+
641
+ # (0) Create a repository with TestStorageBackend()
642
+ storage_backend = TestStorageBackend ()
643
+ repository = repo_tool .create_new_repository (repository_directory ,
644
+ repository_name ,
645
+ storage_backend )
646
+
647
+ # (1) Load the public and private keys of the top-level roles, and one
648
+ # delegated role.
649
+ keystore_directory = os .path .join ('repository_data' , 'keystore' )
650
+
651
+ # Load the public keys.
652
+ root_pubkey_path = os .path .join (keystore_directory , 'root_key.pub' )
653
+ targets_pubkey_path = os .path .join (keystore_directory , 'targets_key.pub' )
654
+ snapshot_pubkey_path = os .path .join (keystore_directory , 'snapshot_key.pub' )
655
+ timestamp_pubkey_path = os .path .join (keystore_directory , 'timestamp_key.pub' )
656
+
657
+ root_pubkey = repo_tool .import_rsa_publickey_from_file (root_pubkey_path )
658
+ targets_pubkey = \
659
+ repo_tool .import_ed25519_publickey_from_file (targets_pubkey_path )
660
+ snapshot_pubkey = \
661
+ repo_tool .import_ed25519_publickey_from_file (snapshot_pubkey_path )
662
+ timestamp_pubkey = \
663
+ repo_tool .import_ed25519_publickey_from_file (timestamp_pubkey_path )
664
+
665
+ # Load the private keys.
666
+ root_privkey_path = os .path .join (keystore_directory , 'root_key' )
667
+ targets_privkey_path = os .path .join (keystore_directory , 'targets_key' )
668
+ snapshot_privkey_path = os .path .join (keystore_directory , 'snapshot_key' )
669
+ timestamp_privkey_path = os .path .join (keystore_directory , 'timestamp_key' )
670
+
671
+ root_privkey = \
672
+ repo_tool .import_rsa_privatekey_from_file (root_privkey_path , 'password' )
673
+ targets_privkey = \
674
+ repo_tool .import_ed25519_privatekey_from_file (targets_privkey_path ,
675
+ 'password' )
676
+ snapshot_privkey = \
677
+ repo_tool .import_ed25519_privatekey_from_file (snapshot_privkey_path ,
678
+ 'password' )
679
+ timestamp_privkey = \
680
+ repo_tool .import_ed25519_privatekey_from_file (timestamp_privkey_path ,
681
+ 'password' )
682
+
683
+
684
+ # (2) Add top-level verification keys.
685
+ repository .root .add_verification_key (root_pubkey )
686
+ repository .targets .add_verification_key (targets_pubkey )
687
+ repository .snapshot .add_verification_key (snapshot_pubkey )
688
+ repository .timestamp .add_verification_key (timestamp_pubkey )
689
+
690
+
691
+ # (3) Load top-level signing keys.
692
+ repository .root .load_signing_key (root_privkey )
693
+ repository .targets .load_signing_key (targets_privkey )
694
+ repository .snapshot .load_signing_key (snapshot_privkey )
695
+ repository .timestamp .load_signing_key (timestamp_privkey )
696
+
697
+
698
+ # (4) Add target files.
699
+ target1 = 'file1.txt'
700
+ target2 = 'file2.txt'
701
+ target3 = 'file3.txt'
702
+ repository .targets .add_target (target1 )
703
+ repository .targets .add_target (target2 )
704
+ repository .targets .add_target (target3 )
705
+
706
+ # (6) Write repository.
707
+ repository .writeall ()
708
+
709
+
710
+ # Ensure all of the metadata files exist at the mutated file location and
711
+ # that those files are valid metadata
712
+ for role in ['root.json.tst' , 'targets.json.tst' , 'snapshot.json.tst' ,
713
+ 'timestamp.json.tst' ]:
714
+ role_filepath = os .path .join (metadata_directory , role )
715
+ self .assertTrue (os .path .exists (role_filepath ))
716
+
717
+ role_signable = securesystemslib .util .load_json_file (role_filepath )
718
+ # Raise 'securesystemslib.exceptions.FormatError' if 'role_signable' is
719
+ # an invalid signable.
720
+ tuf .formats .check_signable_object_format (role_signable )
721
+
722
+
723
+
553
724
554
725
555
726
class TestMetadata (unittest .TestCase ):
0 commit comments