diff --git a/docs/CLI.md b/docs/CLI.md index df922bb3..f4d26f2d 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -11,14 +11,18 @@ any targets nor does it delegate trust to any roles. ```Bash $ repo.py --init ``` -Note: Support for arbitrary repo paths will be added in the near future. -`$ repo.py --init --path ` -By default, `pw` is used to encrypt the top-level key files created with ---init. Instead, the user can enter a password on the command line, or be -prompted for one. +Optionally, the repository can be written to a specified location. ```Bash -$ repo.py --init --pw my_pw +$ repo.py --init --path +``` + +Note: The default top-level key files created with --init are saved to disk +encrypted, with a default password of 'pw'. Instead of using the default +password, the user can enter one on the command line or be prompted +for it via password masking. +```Bash +$ repo.py --init --pw my_password ``` ```Bash @@ -51,6 +55,12 @@ More than one target file may be specified. ```Bash $ repo.py --add ``` + +Similar to the --init case, the repository location can be specified. +```Bash +$ repo.py --add --path +``` + Note: Support for directories will be added in the near future. `$ repo.py --add [--recursive]` @@ -68,4 +78,6 @@ $ repo.py --verbose <0-5> Remove the files created via `repo.py --init`. ```Bash $ repo.py --clean +$ repo.py --clean --path ``` +(--clean by itself removes TUF files from the current working directory.) diff --git a/tuf/scripts/client.py b/tuf/scripts/client.py index bdba95bf..867f9533 100755 --- a/tuf/scripts/client.py +++ b/tuf/scripts/client.py @@ -197,7 +197,6 @@ def parse_arguments(): parsed_arguments = parser.parse_args() - print('parsed_arguments: ' + repr(parsed_arguments)) # Set the logging level. if parsed_arguments.verbose == 5: diff --git a/tuf/scripts/repo.py b/tuf/scripts/repo.py index 23649614..7b9e1074 100755 --- a/tuf/scripts/repo.py +++ b/tuf/scripts/repo.py @@ -58,17 +58,17 @@ PROG_NAME = 'repo.py' -DEFAULT_REPO_PATH = 'tufrepo' -DEFAULT_CLIENT_PATH = 'tufclient' -DEFAULT_KEYSTORE = 'tufkeystore' +REPO_DIR = 'tufrepo' +CLIENT_DIR = 'tufclient' +KEYSTORE_DIR = 'tufkeystore' -DEFAULT_ROOT_KEY = 'root_key' -DEFAULT_TARGETS_KEY = 'targets_key' -DEFAULT_SNAPSHOT_KEY = 'snapshot_key' -DEFAULT_TIMESTAMP_KEY = 'timestamp_key' +ROOT_KEY_NAME = 'root_key' +TARGETS_KEY_NAME = 'targets_key' +SNAPSHOT_KEY_NAME = 'snapshot_key' +TIMESTAMP_KEY_NAME = 'timestamp_key' -DEFAULT_STAGED_DIR = 'metadata.staged' -DEFAULT_METADATA_DIR = 'metadata' +STAGED_METADATA_DIR = 'metadata.staged' +METADATA_DIR = 'metadata' @@ -114,9 +114,9 @@ def process_arguments(parsed_arguments): def clean_repo(parsed_arguments): - repo_dir = os.path.join(parsed_arguments.clean, DEFAULT_REPO_PATH) - client_dir = os.path.join(parsed_arguments.clean, DEFAULT_CLIENT_PATH) - keystore_dir = os.path.join(parsed_arguments.clean, DEFAULT_KEYSTORE) + repo_dir = os.path.join(parsed_arguments.path, REPO_DIR) + client_dir = os.path.join(parsed_arguments.path, CLIENT_DIR) + keystore_dir = os.path.join(parsed_arguments.path, KEYSTORE_DIR) shutil.rmtree(repo_dir, ignore_errors=True) shutil.rmtree(client_dir, ignore_errors=True) @@ -125,8 +125,10 @@ def clean_repo(parsed_arguments): def write_to_live_repo(): - staged_meta_directory = os.path.join(DEFAULT_REPO_PATH, DEFAULT_STAGED_DIR) - live_meta_directory = os.path.join(DEFAULT_REPO_PATH, DEFAULT_METADATA_DIR) + staged_meta_directory = os.path.join( + parsed_arguments.path, REPO_DIR, STAGED_METADATA_DIR) + live_meta_directory = os.path.join( + parsed_arguments.path, REPO_DIR, METADATA_DIR) shutil.rmtree(live_meta_directory, ignore_errors=True) shutil.copytree(staged_meta_directory, live_meta_directory) @@ -136,8 +138,9 @@ def write_to_live_repo(): def add_targets(parsed_arguments): target_paths = os.path.join(parsed_arguments.add) - repo_targets_path = os.path.join(DEFAULT_REPO_PATH, 'targets') - repository = repo_tool.load_repository(DEFAULT_REPO_PATH) + repo_targets_path = os.path.join(parsed_arguments.path, REPO_DIR, 'targets') + repository = repo_tool.load_repository( + os.path.join(parsed_arguments.path, REPO_DIR)) for target_path in target_paths: if not os.path.exists(target_path): @@ -158,11 +161,14 @@ def add_targets(parsed_arguments): # Load the top-level, non-root, keys to make a new release. targets_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TARGETS_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, TARGETS_KEY_NAME), + parsed_arguments.pw) snapshot_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_SNAPSHOT_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, SNAPSHOT_KEY_NAME), + parsed_arguments.pw) timestamp_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TIMESTAMP_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TIMESTAMP_KEY_NAME), parsed_arguments.pw) repository.targets.load_signing_key(targets_private) repository.snapshot.load_signing_key(snapshot_private) @@ -177,10 +183,13 @@ def add_targets(parsed_arguments): def init_repo(parsed_arguments): """ - Create default repo. Each top-level role has one key, if - 'parsed_argument.bare' is False (default). + Create a repo at the specified location in --path (the current working + directory, by default). Each top-level role has one key, if --bare' is False + (default). """ - repository = repo_tool.create_new_repository(DEFAULT_REPO_PATH) + + repo_path = os.path.join(parsed_arguments.path, REPO_DIR) + repository = repo_tool.create_new_repository(repo_path) if not parsed_arguments.bare: set_top_level_keys(repository) @@ -188,7 +197,8 @@ def init_repo(parsed_arguments): consistent_snapshot=parsed_arguments.consistent_snapshot) else: - repository.write('root', consistent_snapshot=parsed_arguments.consistent_snapshot) + repository.write( + 'root', consistent_snapshot=parsed_arguments.consistent_snapshot) repository.write('targets') repository.write('snapshot') repository.write('timestamp') @@ -198,8 +208,9 @@ def init_repo(parsed_arguments): # Create the client files. The client directory contains the required # directory structure and metadata files for clients to successfully perform # an update. - repo_tool.create_tuf_client_directory(DEFAULT_REPO_PATH, - os.path.join(DEFAULT_CLIENT_PATH, DEFAULT_REPO_PATH)) + repo_tool.create_tuf_client_directory( + os.path.join(parsed_arguments.path, REPO_DIR), + os.path.join(parsed_arguments.path, CLIENT_DIR, REPO_DIR)) @@ -217,36 +228,48 @@ def set_top_level_keys(repository): prompt='Enter a password for the top-level role keys: ', confirm=True) repo_tool.generate_and_write_ecdsa_keypair( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_ROOT_KEY), password=parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + ROOT_KEY_NAME), password=parsed_arguments.pw) repo_tool.generate_and_write_ecdsa_keypair( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TARGETS_KEY), password=parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TARGETS_KEY_NAME), password=parsed_arguments.pw) repo_tool.generate_and_write_ecdsa_keypair( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_SNAPSHOT_KEY), password=parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + SNAPSHOT_KEY_NAME), password=parsed_arguments.pw) repo_tool.generate_and_write_ecdsa_keypair( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TIMESTAMP_KEY), password=parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TIMESTAMP_KEY_NAME), password=parsed_arguments.pw) # Import the public keys. They are needed so that metadata roles are # assigned verification keys, which clients need in order to verify the # signatures created by the corresponding private keys. root_public = repo_tool.import_ecdsa_publickey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_ROOT_KEY) + '.pub') + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + ROOT_KEY_NAME) + '.pub') targets_public = repo_tool.import_ecdsa_publickey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TARGETS_KEY) + '.pub') + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TARGETS_KEY_NAME) + '.pub') snapshot_public = repo_tool.import_ecdsa_publickey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_SNAPSHOT_KEY) + '.pub') + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + SNAPSHOT_KEY_NAME) + '.pub') timestamp_public = repo_tool.import_ecdsa_publickey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TIMESTAMP_KEY) + '.pub') + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TIMESTAMP_KEY_NAME) + '.pub') # Import the private keys. They are needed to generate the signatures # included in metadata. root_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_ROOT_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + ROOT_KEY_NAME), parsed_arguments.pw) targets_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TARGETS_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TARGETS_KEY_NAME), parsed_arguments.pw) snapshot_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_SNAPSHOT_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + SNAPSHOT_KEY_NAME), parsed_arguments.pw) timestamp_private = repo_tool.import_ecdsa_privatekey_from_file( - os.path.join(DEFAULT_KEYSTORE, DEFAULT_TIMESTAMP_KEY), parsed_arguments.pw) + os.path.join(parsed_arguments.path, KEYSTORE_DIR, + TIMESTAMP_KEY_NAME), parsed_arguments.pw) # Add the verification keys to the top-level roles. repository.root.add_verification_key(root_public) @@ -306,6 +329,10 @@ def parse_arguments(): parser.add_argument('-i', '--init', nargs='?', const='.', help='Create a repository.') + parser.add_argument('-p', '--path', nargs='?', default='.', + help='Specify a repository path. If used with --init, the initialized' + ' repository is saved to the specified path.') + parser.add_argument('-b', '--bare', type=bool, nargs='?', const=True, default=False, choices=[True, False], help='If initializing a repository, ' + repr(PROG_NAME) + ' should not'