From e61f6f36b916a22e5c6c5d51869ca1ffcaaa7187 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Thu, 8 Mar 2018 11:34:18 -0500 Subject: [PATCH 1/2] Edit CLI.md to include text for --remove option Signed-off-by: Vladimir Diaz --- docs/CLI.md | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/docs/CLI.md b/docs/CLI.md index 3df06d9f..5e761edb 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -51,10 +51,10 @@ $ repo.py --init --consistent_snapshot ## Add a target file ## -Copy a target file to the repo and add it to Targets metadata. More than one -target file, or directory, may be specified with --add. The --recursive option -may be selected to also include files in subdirectories of a specified -directory. +Copy a target file to the repo and add it to the Targets metadata (or the +Targets role specified in --role). More than one target file, or directory, +may be specified in --add. The --recursive option may be toggled to also +include files in subdirectories of a specified directory. ```Bash $ repo.py --add $ repo.py --add [--recursive] @@ -67,6 +67,30 @@ $ repo.py --add --path + +## Remove a target file ## + +Remove a target file from the Targets metadata (or the Targets role specified +in --role). More than one target file or glob pattern may be specified in +--remove. + +```Bash +$ repo.py --remove ... +``` + +Examples: + +Remove all target files, that match `foo*.tgz,` from the Targets metadata. +```Bash +$ repo.py --remove "foo*.tgz" +``` + +Remove all target files from the `my_role` Targets metadata. +```Bash +$ repo.py --remove "*" --role my_role --sign tufkeystore/my_role_key +``` + + ## Generate key ## Generate a cryptographic key. The generated key can later be used to sign specific metadata with `--sign`. The supported key types are: `ecdsa`, @@ -105,7 +129,7 @@ Delegate trust of target files from the targets role (or the one specified in --role) to some other role (--delegatee). --delegatee is trusted to sign for target files that match the delegated glob patterns. ```Bash -$ repo.py --delegate ... --delegatee --pubkeys +$ repo.py --delegate ... --delegatee --pubkeys ... [--role --terminating --threshold --sign ] ``` From 829bc32213e3aab48403b98c704f868f20fa23a7 Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Thu, 8 Mar 2018 11:36:20 -0500 Subject: [PATCH 2/2] Add --remove command-line option Signed-off-by: Vladimir Diaz --- tuf/scripts/repo.py | 81 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/tuf/scripts/repo.py b/tuf/scripts/repo.py index a5facafd..59fc3759 100755 --- a/tuf/scripts/repo.py +++ b/tuf/scripts/repo.py @@ -53,6 +53,7 @@ import errno import getpass import time +import fnmatch import tuf import tuf.log @@ -61,6 +62,8 @@ import securesystemslib from colorama import Fore +import six + # See 'log.py' to learn how logging is handled in TUF. logger = logging.getLogger('tuf.scripts.repo') @@ -122,6 +125,9 @@ def process_arguments(parsed_arguments): if parsed_arguments.add: add_targets(parsed_arguments) + if parsed_arguments.remove: + remove_targets(parsed_arguments) + if parsed_arguments.sign: sign_role(parsed_arguments) @@ -453,6 +459,36 @@ def add_target_to_repo(target_path, repo_targets_path, repository): +def remove_target_files_from_metadata(repository): + + if parsed_arguments.role in ['root', 'snapshot', 'timestamp']: + raise tuf.exceptions.Error( + 'Invalid rolename specified: ' + repr(parsed_arguments.role) + '.' + ' It must be "targets" or a delegated rolename.') + + else: + # NOTE: The following approach of using tuf.roledb to update the target + # files will be modified in the future when the repository tool's API is + # refactored. + roleinfo = tuf.roledb.get_roleinfo( + parsed_arguments.role, repository._repository_name) + + for glob_pattern in parsed_arguments.remove: + for path in list(six.iterkeys(roleinfo['paths'])): + if fnmatch.fnmatch(path, glob_pattern): + del roleinfo['paths'][path] + + else: + logger.debug('Delegated path ' + repr(path) + ' does not match' + ' given path/glob pattern ' + repr(glob_pattern)) + continue + + tuf.roledb.update_roleinfo( + parsed_arguments.role, roleinfo, mark_role_as_dirty=True, + repository_name=repository._repository_name) + + + def add_targets(parsed_arguments): target_paths = os.path.join(parsed_arguments.add) @@ -502,6 +538,47 @@ def add_targets(parsed_arguments): +def remove_targets(parsed_arguments): + target_paths = os.path.join(parsed_arguments.remove) + + 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)) + + # Remove target files from the Targets metadata (or the role specified in + # --role) that match the glob patterns specified in --remove. + remove_target_files_from_metadata(repository) + + # Examples of how the --pw command-line option is interpreted: + # repo.py --init': parsed_arguments.pw = 'pw' + # repo.py --init --pw my_password: parsed_arguments.pw = 'my_password' + # repo.py --init --pw: The user is prompted for a password, as follows: + if not parsed_arguments.pw: + parsed_arguments.pw = securesystemslib.interface.get_password( + prompt='Enter a password for the top-level role keys: ', confirm=True) + + # Load the top-level, non-root, keys to make a new release. + targets_private = import_privatekey_from_file( + os.path.join(parsed_arguments.path, KEYSTORE_DIR, TARGETS_KEY_NAME), + parsed_arguments.pw) + snapshot_private = import_privatekey_from_file( + os.path.join(parsed_arguments.path, KEYSTORE_DIR, SNAPSHOT_KEY_NAME), + parsed_arguments.pw) + timestamp_private = import_privatekey_from_file( + 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) + repository.timestamp.load_signing_key(timestamp_private) + + repository.writeall() + + # Move staged metadata directory to "live" metadata directory. + write_to_live_repo() + + + def init_repo(parsed_arguments): """ Create a repo at the specified location in --path (the current working @@ -667,6 +744,10 @@ def parse_arguments(): ' "targets" role (or the role specified in --role). If a directory' ' is given, all files in the directory are added.') + parser.add_argument('--remove', type=str, nargs='+', + metavar='', help='Remove one or more target files from the' + ' "targets" role (or the role specified in --role).') + parser.add_argument('--role', nargs='?', type=str, const='targets', default='targets', metavar='', help='Specify a rolename.' ' The rolename "targets" is used by default.')