mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
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:
commit
303418f1a9
3 changed files with 82 additions and 44 deletions
24
docs/CLI.md
24
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 </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.)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
Loading…
Reference in a new issue