Merge pull request #618 from vladimir-v-diaz/improve_repo.py

Add --path command-line option to repo.py CLI
This commit is contained in:
Vladimir Diaz 2018-02-01 15:26:32 -05:00 committed by GitHub
commit 303418f1a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 82 additions and 44 deletions

View file

@ -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 </path/to/repo>`
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 </path/to/repo>
```
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 <foo.tar.gz> <bar.tar.gz>
```
Similar to the --init case, the repository location can be specified.
```Bash
$ repo.py --add <foo.tar.gz> --path </path/to/my_repo>
```
Note: Support for directories will be added in the near future.
`$ repo.py --add </path/to/dir> [--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 </path/to/dirty/repo>
```
(--clean by itself removes TUF files from the current working directory.)

View file

@ -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:

View file

@ -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'