mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
After seeing the coveralls report I realized the projects were not relocatable. While this might be convenient for some uses, moving a project from one place to another might not be optimal. This has been changed now. The only place where absolute filepaths are handled now is with flat project layouts. However, it is possible to overwrite this filepath if the targets folder is to be changed.
447 lines
15 KiB
Python
Executable file
447 lines
15 KiB
Python
Executable file
#!/usr/bin/env python
|
|
|
|
"""
|
|
<Program Name>
|
|
test_developer_tool.py
|
|
|
|
<Authors>
|
|
Santiago Torres Arias <torresariass@gmail.com
|
|
Zane Fisher <zanefisher@gmail.com>
|
|
|
|
<Copyright>
|
|
See LICENSE for licensing inforation
|
|
|
|
<Purpose>
|
|
Unit tests for the 'developer_tool' module
|
|
"""
|
|
|
|
import os
|
|
import time
|
|
import datetime
|
|
import unittest
|
|
import logging
|
|
import tempfile
|
|
import shutil
|
|
|
|
import tuf
|
|
import tuf.log
|
|
import tuf.formats
|
|
import tuf.roledb
|
|
import tuf.keydb
|
|
import tuf.developer_tool as developer_tool
|
|
|
|
from tuf.developer_tool import METADATA_DIRECTORY_NAME
|
|
from tuf.developer_tool import TARGETS_DIRECTORY_NAME
|
|
|
|
logger = logging.getLogger("tuf.test_developer_tool")
|
|
|
|
class TestProject(unittest.TestCase):
|
|
|
|
tmp_dir = None
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
cls.tmp_dir = tempfile.mkdtemp(dir = os.getcwd())
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
shutil.rmtree(cls.tmp_dir)
|
|
|
|
def setUp(self):
|
|
# called before every test case
|
|
pass
|
|
|
|
def tearDown(self):
|
|
# called after every test case
|
|
tuf.roledb.clear_roledb()
|
|
tuf.keydb.clear_keydb()
|
|
pass
|
|
|
|
def test_emtpy(self):
|
|
return
|
|
|
|
def test_create_new_project(self):
|
|
# test cases for the create_new_project function. In this test we will
|
|
# check input, correct file creation and format. We also check
|
|
# that a proper object is generated. We will use the normal layout for this
|
|
# test suite.
|
|
|
|
# create a local subfolder for this test.
|
|
local_tmp = tempfile.mkdtemp(dir = self.tmp_dir)
|
|
|
|
# these are the usual values we will be throwing to the function, however
|
|
# we will swap these for nulls or malformed values every now and then to
|
|
# test input
|
|
project_name = "test_suite"
|
|
metadata_directory = local_tmp
|
|
location_in_repository = '/prefix'
|
|
targets_directory = None
|
|
key = None
|
|
|
|
# create a blank project
|
|
project = developer_tool.create_new_project(project_name, metadata_directory,
|
|
location_in_repository)
|
|
|
|
self.assertTrue(isinstance(project, developer_tool.Project))
|
|
self.assertTrue(project.layout_type == 'repo-like')
|
|
self.assertTrue(project.prefix == location_in_repository)
|
|
self.assertTrue(project._project_name == project_name)
|
|
self.assertTrue(project._metadata_directory ==
|
|
os.path.join(metadata_directory,METADATA_DIRECTORY_NAME))
|
|
self.assertTrue(project._targets_directory ==
|
|
os.path.join(metadata_directory,TARGETS_DIRECTORY_NAME))
|
|
|
|
# create a blank project without a prefix
|
|
project = developer_tool.create_new_project(project_name, metadata_directory)
|
|
self.assertTrue(isinstance(project, developer_tool.Project))
|
|
self.assertTrue(project.layout_type == 'repo-like')
|
|
self.assertTrue(project.prefix == '')
|
|
self.assertTrue(project._project_name == project_name)
|
|
self.assertTrue(project._metadata_directory ==
|
|
os.path.join(metadata_directory,METADATA_DIRECTORY_NAME))
|
|
self.assertTrue(project._targets_directory ==
|
|
os.path.join(metadata_directory,TARGETS_DIRECTORY_NAME))
|
|
|
|
# create a blank project without a valid metadata directory
|
|
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
|
|
0, metadata_directory, location_in_repository)
|
|
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
|
|
project_name, 0, location_in_repository)
|
|
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
|
|
project_name, metadata_directory, 0)
|
|
|
|
|
|
# create a new project with a flat layout
|
|
targets_directory = tempfile.mkdtemp(dir = local_tmp)
|
|
metadata_directory = tempfile.mkdtemp(dir = local_tmp)
|
|
project = developer_tool.create_new_project(project_name, metadata_directory,
|
|
location_in_repository, targets_directory)
|
|
self.assertTrue(isinstance(project, developer_tool.Project))
|
|
self.assertTrue(project.layout_type == 'flat')
|
|
self.assertTrue(project.prefix == location_in_repository)
|
|
self.assertTrue(project._project_name == project_name)
|
|
self.assertTrue(project._metadata_directory == metadata_directory)
|
|
self.assertTrue(project._targets_directory == targets_directory)
|
|
|
|
# finally, check that if targets_directory is set, it is valid
|
|
self.assertRaises(tuf.FormatError, developer_tool.create_new_project,
|
|
project_name, metadata_directory, location_in_repository, 0)
|
|
|
|
# copy a key to our workspace and create a new project with it.
|
|
keystore_path = os.path.join('repository_data','keystore')
|
|
|
|
# I will use the same key as the one provided in the repository
|
|
# tool tests for the root role, but this is not a root role...
|
|
root_key_path = os.path.join(keystore_path,'root_key.pub')
|
|
project_key = developer_tool.import_rsa_publickey_from_file(root_key_path)
|
|
|
|
# test create new project with a key added by default
|
|
project = developer_tool.create_new_project(project_name, metadata_directory,
|
|
location_in_repository, targets_directory, project_key)
|
|
|
|
self.assertTrue(isinstance(project, developer_tool.Project))
|
|
self.assertTrue(project.layout_type == 'flat')
|
|
self.assertTrue(project.prefix == location_in_repository)
|
|
self.assertTrue(project._project_name == project_name)
|
|
self.assertTrue(project._metadata_directory == metadata_directory)
|
|
self.assertTrue(project._targets_directory == targets_directory)
|
|
self.assertTrue(len(project.keys) == 1)
|
|
self.assertTrue(project.keys[0] == project_key['keyid'])
|
|
|
|
# set as readonly and try to write a repo
|
|
shutil.rmtree(targets_directory)
|
|
os.chmod(local_tmp, 0o0555)
|
|
|
|
tuf.roledb.clear_roledb()
|
|
tuf.keydb.clear_keydb()
|
|
self.assertRaises(OSError, developer_tool.create_new_project ,project_name,
|
|
metadata_directory, location_in_repository, targets_directory,
|
|
project_key)
|
|
|
|
os.chmod(local_tmp, 0o0777)
|
|
|
|
shutil.rmtree(metadata_directory)
|
|
os.chmod(local_tmp, 0o0555)
|
|
|
|
tuf.roledb.clear_roledb()
|
|
tuf.keydb.clear_keydb()
|
|
self.assertRaises(OSError, developer_tool.create_new_project ,project_name,
|
|
metadata_directory, location_in_repository, targets_directory,
|
|
project_key)
|
|
|
|
|
|
os.chmod(local_tmp, 0o0777)
|
|
shutil.rmtree(local_tmp)
|
|
|
|
|
|
|
|
def test_load_project(self):
|
|
# this test case will try to load an existing project and test for the result
|
|
# then we will try to load a nonexisting project and expect a correct error
|
|
# handler
|
|
# finally, we will try to overwrite the existing prefix on the loaded project
|
|
|
|
# create a local subfolder for this test.
|
|
local_tmp = tempfile.mkdtemp(dir = self.tmp_dir)
|
|
|
|
# test inexisting project filepath
|
|
nonexistent_path = os.path.join(local_tmp, "nonexistent")
|
|
self.assertRaises(IOError, developer_tool.load_project, nonexistent_path)
|
|
|
|
# copy the pregenerated metadata
|
|
project_data_filepath = os.path.join('repository_data', 'project')
|
|
target_project_data_filepath = os.path.join(local_tmp, 'project')
|
|
shutil.copytree("repository_data/project", target_project_data_filepath)
|
|
|
|
# load a project properly...
|
|
repo_filepath = os.path.join(local_tmp, 'project', 'test-repo')
|
|
project = developer_tool.load_project(repo_filepath)
|
|
|
|
self.assertTrue(project.layout_type == "repo-like")
|
|
|
|
repo_filepath = os.path.join(local_tmp, 'project', 'test-flat')
|
|
new_targets_path = os.path.join(local_tmp, 'project', 'targets')
|
|
project = developer_tool.load_project(repo_filepath,
|
|
new_targets_location = new_targets_path)
|
|
self.assertTrue(project._targets_directory == new_targets_path)
|
|
self.assertTrue(project.layout_type == 'flat')
|
|
|
|
|
|
# load a project ovrwriting the prefix
|
|
project = developer_tool.load_project(repo_filepath, prefix='new')
|
|
self.assertTrue(project.prefix == 'new')
|
|
|
|
# load a project with a file missing
|
|
file_to_corrupt = os.path.join(repo_filepath, 'test-flat','role1.json')
|
|
with open(file_to_corrupt, 'wt') as fp:
|
|
fp.write("this is not a json file")
|
|
|
|
self.assertRaises(tuf.Error, developer_tool.load_project, repo_filepath)
|
|
|
|
|
|
|
|
|
|
def test_add_verification_keys(self):
|
|
|
|
# maybe we need to clear the roledb and keydb
|
|
|
|
# create a new project instance
|
|
project = developer_tool.Project("test_verification_keys", "somepath",
|
|
"someotherpath", "prefix")
|
|
|
|
# add invalid verification key
|
|
self.assertRaises(tuf.FormatError, project.add_verification_key, "invalid")
|
|
|
|
# add verification key
|
|
# - load it first
|
|
keystore_path = os.path.join('repository_data','keystore')
|
|
first_verification_key_path = os.path.join(keystore_path,'root_key.pub')
|
|
first_verification_key = \
|
|
developer_tool.import_rsa_publickey_from_file(first_verification_key_path)
|
|
|
|
project.add_verification_key(first_verification_key)
|
|
|
|
|
|
# add another verification key (should expect exception)
|
|
second_verification_key_path = os.path.join(keystore_path,'snapshot_key.pub')
|
|
second_verification_key = \
|
|
developer_tool.import_rsa_publickey_from_file(second_verification_key_path)
|
|
|
|
self.assertRaises(tuf.Error,
|
|
project.add_verification_key,(second_verification_key))
|
|
|
|
|
|
|
|
# add a verification key for the delegation
|
|
project.delegate("somedelegation", [], [])
|
|
project("somedelegation").add_verification_key(first_verification_key)
|
|
project("somedelegation").add_verification_key(second_verification_key)
|
|
|
|
|
|
# add another delegation of the delegation
|
|
project("somedelegation").delegate("somesubdelegation", [], [])
|
|
project("somedelegation")("somesubdelegation").add_verification_key(
|
|
first_verification_key)
|
|
project("somedelegation")("somesubdelegation").add_verification_key(
|
|
second_verification_key)
|
|
|
|
|
|
def test_write(self):
|
|
|
|
# create tmp directory
|
|
local_tmp = tempfile.mkdtemp(dir=self.tmp_dir)
|
|
|
|
# create new project inside tmp directory
|
|
project = developer_tool.create_new_project("test_write", local_tmp,
|
|
"prefix");
|
|
|
|
# create some target files inside the tmp directory
|
|
target_filepath = os.path.join(local_tmp, "targets", "test_target")
|
|
with open(target_filepath, "wt") as fp:
|
|
fp.write("testing file")
|
|
|
|
|
|
# add the targets
|
|
project.add_target(target_filepath)
|
|
|
|
# add verification keys
|
|
keystore_path = os.path.join('repository_data','keystore')
|
|
project_key_path = os.path.join(keystore_path,'root_key.pub')
|
|
project_key = \
|
|
developer_tool.import_rsa_publickey_from_file(project_key_path)
|
|
|
|
|
|
# call status (for the sake of doing it)
|
|
project.status()
|
|
|
|
project.add_verification_key(project_key)
|
|
|
|
|
|
# add another verification key (should expect exception)
|
|
delegation_key_path = os.path.join(keystore_path,'snapshot_key.pub')
|
|
delegation_key = \
|
|
developer_tool.import_rsa_publickey_from_file(delegation_key_path)
|
|
|
|
# add a subdelegation
|
|
subdelegation_key_path = os.path.join(keystore_path,'timestamp_key.pub')
|
|
subdelegation_key = \
|
|
developer_tool.import_rsa_publickey_from_file(subdelegation_key_path)
|
|
|
|
# add a delegation
|
|
project.delegate("delegation", [delegation_key], [])
|
|
project("delegation").delegate("subdelegation", [subdelegation_key], [])
|
|
|
|
# call write (except)
|
|
self.assertRaises(tuf.Error, project.write, ())
|
|
|
|
# call status (for the sake of doing it)
|
|
project.status()
|
|
|
|
# load private keys
|
|
project_private_key_path = os.path.join(keystore_path, 'root_key')
|
|
project_private_key = \
|
|
developer_tool.import_rsa_privatekey_from_file(project_private_key_path,
|
|
'password')
|
|
|
|
delegation_private_key_path = os.path.join(keystore_path, 'snapshot_key')
|
|
delegation_private_key = \
|
|
developer_tool.import_rsa_privatekey_from_file(delegation_private_key_path,
|
|
'password')
|
|
|
|
subdelegation_private_key_path = \
|
|
os.path.join(keystore_path, 'timestamp_key')
|
|
subdelegation_private_key = \
|
|
developer_tool.import_rsa_privatekey_from_file(subdelegation_private_key_path,
|
|
'password')
|
|
|
|
# test partial write
|
|
# backup everything (again)
|
|
# + backup targets:
|
|
targets_backup = project.target_files
|
|
|
|
# + backup delegations
|
|
delegations_backup = \
|
|
tuf.roledb.get_delegated_rolenames(project._project_name)
|
|
|
|
# + backup layout type
|
|
layout_type_backup = project.layout_type
|
|
|
|
# + backup keyid's
|
|
keys_backup = project.keys
|
|
delegation_keys_backup = project("delegation").keys
|
|
|
|
# + backup the prefix
|
|
prefix_backup = project.prefix
|
|
|
|
# + backup the name
|
|
name_backup = project._project_name
|
|
|
|
# set the compressions, we will be checking this part here too
|
|
project.compressions = ['gz']
|
|
project('delegation').compressions = project.compressions
|
|
|
|
# write and reload
|
|
self.assertRaises(tuf.Error, project.write)
|
|
project.write(write_partial=True)
|
|
|
|
project = developer_tool.load_project(local_tmp)
|
|
|
|
# check against backup
|
|
self.assertEquals(project.target_files, targets_backup)
|
|
new_delegations = tuf.roledb.get_delegated_rolenames(project._project_name)
|
|
self.assertEquals(new_delegations, delegations_backup)
|
|
self.assertEquals(project.layout_type, layout_type_backup)
|
|
self.assertEquals(project.keys, keys_backup)
|
|
self.assertEquals(project("delegation").keys, delegation_keys_backup)
|
|
self.assertEquals(project.prefix, prefix_backup)
|
|
self.assertEquals(project._project_name, name_backup)
|
|
|
|
|
|
|
|
roleinfo = tuf.roledb.get_roleinfo(project._project_name)
|
|
|
|
self.assertEquals(roleinfo['partial_loaded'], True)
|
|
|
|
|
|
|
|
# load_signing_keys
|
|
project("delegation").load_signing_key(delegation_private_key)
|
|
|
|
project.status()
|
|
|
|
project("delegation")("subdelegation").load_signing_key(
|
|
subdelegation_private_key)
|
|
|
|
# import pdb; pdb.set_trace()
|
|
project.status()
|
|
|
|
project.load_signing_key(project_private_key)
|
|
|
|
# backup everything
|
|
# + backup targets:
|
|
targets_backup = project.target_files
|
|
|
|
# + backup delegations
|
|
delegations_backup = \
|
|
tuf.roledb.get_delegated_rolenames(project._project_name)
|
|
|
|
# + backup layout type
|
|
layout_type_backup = project.layout_type
|
|
|
|
# + backup keyid's
|
|
keys_backup = project.keys
|
|
delegation_keys_backup = project("delegation").keys
|
|
|
|
# + backup the prefix
|
|
prefix_backup = project.prefix
|
|
|
|
# + backup the name
|
|
name_backup = project._project_name
|
|
|
|
# call status (for the sake of doing it)
|
|
project.status()
|
|
|
|
# call write
|
|
project.write()
|
|
|
|
# call load
|
|
project = developer_tool.load_project(local_tmp)
|
|
|
|
|
|
# check against backup
|
|
self.assertEquals(project.target_files, targets_backup)
|
|
|
|
new_delegations = tuf.roledb.get_delegated_rolenames(project._project_name)
|
|
self.assertEquals(new_delegations, delegations_backup)
|
|
self.assertEquals(project.layout_type, layout_type_backup)
|
|
self.assertEquals(project.keys, keys_backup)
|
|
self.assertEquals(project("delegation").keys, delegation_keys_backup)
|
|
self.assertEquals(project.prefix, prefix_backup)
|
|
self.assertEquals(project._project_name, name_backup)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|