Skip to content

Commit

Permalink
Minor CLI fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
danixeee committed Jan 28, 2020
1 parent 2914383 commit dae535e
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 78 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning][semver].

### Changed

- Separated commands into subcommands
- Separated commands into sub-commands ([96])
- Use `root-dir` and `namespace` instead of `target-dir` ([96])

### Fixed
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Install extra dependencies when using _Yubikey_:
pip install taf[yubikey]
```

Add bash completion:

1. copy `taf-complete.sh` to user's directory
1. add `source ./taf-complete.sh` to `~/.bash_profile` or `~/.bashrc`
1. source `~/.bash_profile`

## Development Setup

We are using [pre-commit](https://pre-commit.com/) to run _black_ code formatter, _flake8_ and _bandit_ code quality checks.
Expand All @@ -70,7 +76,7 @@ pytest
To run tests with real Yubikey:

1. Insert **test** Yubikey
2. Run `taf setup_test_yubikey`
2. Run `taf setup_test_key`
WARNING: This command will import targets private key to signature slot of your Yubikey, as well as new self-signed x509 certificate!
3. Run `REAL_YK=True pytest` or `set REAL_YK=True pytest` depending on platform.

Expand Down
8 changes: 8 additions & 0 deletions taf-complete.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_taf_completion() {
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
COMP_CWORD=$COMP_CWORD \
_TAF_COMPLETE=complete $1 ) )
return 0
}

complete -F _taf_completion -o default taf;
8 changes: 4 additions & 4 deletions taf/auth_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ def __init__(
default_branch="master",
):
super().__init__(repo_path, repo_urls, additional_info, default_branch)
self.targets_path = targets_path
self.metadata_path = metadata_path
self.targets_path = str(Path(self.repo_path, targets_path))
self.metadata_path = str(Path(self.repo_path, metadata_path))


class NamedAuthenticationRepo(AuthRepoMixin, NamedGitRepository):
Expand All @@ -193,5 +193,5 @@ def __init__(
super().__init__(
root_dir, repo_name, repo_urls, additional_info, default_branch
)
self.targets_path = targets_path
self.metadata_path = metadata_path
self.targets_path = str(Path(self.repo_path, targets_path))
self.metadata_path = str(Path(self.repo_path, metadata_path))
6 changes: 3 additions & 3 deletions taf/developer_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def create_repository(
return

tuf.repository_tool.METADATA_STAGED_DIRECTORY_NAME = METADATA_DIRECTORY_NAME
repository = create_new_repository(repo_path)
repository = create_new_repository(repo.repo_path)

def _register_roles_keys(role_name, key_info, repository):
num_of_keys = key_info.get("number", 1)
Expand Down Expand Up @@ -396,8 +396,7 @@ def _register_roles_keys(role_name, key_info, repository):

# if the repository is a test repository, add a target file called test-auth-repo
if test:
target_paths = Path(repo_path) / "targets"
test_auth_file = target_paths / "test-auth-repo"
test_auth_file = Path(repo.targets_path) / "test-auth-repo"
test_auth_file.touch()
targets_obj = _role_obj("targets", repository)
targets_obj.add_target(str(test_auth_file))
Expand Down Expand Up @@ -480,6 +479,7 @@ def export_yk_certificate(certs_dir, key):


def _get_namespace_and_root(repo_path, namespace, root_dir):
repo_path = Path(repo_path)
if namespace is None:
namespace = repo_path.parent.name
if root_dir is None:
Expand Down
2 changes: 1 addition & 1 deletion taf/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(
additional_info: a dictionary containing other data (optional)
default_branch: repository's default branch
"""
self.repo_path = str(repo_path)
self.repo_path = str(Path(repo_path).resolve())
self.default_branch = default_branch
if repo_urls is not None:
if settings.update_from_filesystem is False:
Expand Down
31 changes: 16 additions & 15 deletions taf/tools/keystore/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ def generate(path, keys_description):
It is necessary to either directly specify this dictionary when calling this command or
to provide a path to a `.json` file which contains the needed information.
Keys description example: \n
{\n
"root": {\n
"number": 3,\n
"length": 2048,\n
"passwords": ["password1", "password2", "password3"]\n
"threshold": 2,\n
},\n
"targets": {\n
"length": 2048\n
},\n
"snapshot": {},\n
"timestamp": {}\n
}\n
\b
Keys description example:
{
"root": {
"number": 3,
"length": 2048,
"passwords": ["password1", "password2", "password3"],
"threshold": 2
},
"targets": {
"length": 2048
},
"snapshot": {},
"timestamp": {}
}
Default number of keys and threshold are 1, length 3072 and password is an emtpy string
Default number of keys and threshold are 1, length 3072 and password is an empty string.
"""
developer_tool.generate_keys(path, keys_description)
92 changes: 47 additions & 45 deletions taf/tools/repo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,39 @@ def repo():
@click.option("--keys-description", help="A dictionary containing information about the "
"keys or a path to a json file which stores the needed information")
@click.option("--keystore", default=None, help="Location of the keystore files")
@click.option("--commit", is_flag=True, help="Indicates if the changes should be "
@click.option("--commit", is_flag=True, default=False, help="Indicates if the changes should be "
"committed automatically")
@click.option("--test", is_flag=True, default=False, help="Indicates if the created repository "
"is a test authentication repository")
def create(path, keys_description, keystore, commit, test):
"""
\b
Create a new authentication repository at the specified location by registering
signing keys and generating initial metadata files. Information about the roles
can be provided through a dictionary - either specified directly or contained
by a .json file whose path is specified when calling this command. This allows
definition of: \n
- total number of keys per role \n
- threshold of signatures per role \n
- should keys of a role be on Yubikeys or should keystore files be used \n
- scheme (the default scheme is rsa-pkcs1v15-sha256) \n
For example:\n
{\n
"root": {\n
"number": 3,\n
"length": 2048,\n
"passwords": ["password1", "password2", "password3"]\n
"threshold": 2,\n
"yubikey": true\n
},\n
"targets": {\n
"length": 2048\n
},\n
"snapshot": {},\n
"timestamp": {}\n
}\n
definition of:
- total number of keys per role
- threshold of signatures per role
- should keys of a role be on Yubikeys or should keystore files be used
- scheme (the default scheme is rsa-pkcs1v15-sha256)
\b
For example:
{
"root": {
"number": 3,
"length": 2048,
"passwords": ["password1", "password2", "password3"],
"threshold": 2,
"yubikey": true
},
"targets": {
"length": 2048
},
"snapshot": {},
"timestamp": {}
}
In cases when this dictionary is not specified, it is necessary to enter the needed
information when asked to do so, or confirm that default values should be used.
Expand All @@ -63,7 +65,7 @@ def create(path, keys_description, keystore, commit, test):
@click.option("--root-dir", default=None, help="Directory where target repositories and, "
"optionally, authentication repository are located. If omitted it is "
"calculated based on authentication repository's path. "
"Authentication repo is persumed to be at root-dir/namespace/auth-repo-name")
"Authentication repo is presumed to be at root-dir/namespace/auth-repo-name")
@click.option("--namespace", default=None, help="Namespace of the target repositories. "
"If omitted, it will be assumed that namespace matches the name of the "
"directory which contains the authentication repository")
Expand All @@ -85,7 +87,7 @@ def generate_repositories_json(path, root_dir, namespace, targets_rel_dir, custo
and namespace is namespace1, target repositories should be in E:\\examples\\root\\namespace1.
If the authentication repository and the target repositories are in the same root directory and
the authentication repository is also directly inside a namespace directory, then the common root
directory is calculated as two repositories up from the authetication repository's directory.
directory is calculated as two repositories up from the authentication repository's directory.
Authentication repository's namespace can, but does not have to be equal to the namespace of target,
repositories. If the authentication repository's path is E:\\root\\namespace\\auth-repo, root
directory will be determined as E:\\root. If this default value is not correct, it can be redefined
Expand All @@ -105,31 +107,30 @@ def generate_repositories_json(path, root_dir, namespace, targets_rel_dir, custo
dictionary are names of the repositories whose custom data should be set and values are
custom data dictionaries. For example:
{\n
"test/html-repo": {\n
"type": "html"\n
\b
{
"test/html-repo": {
"type": "html"
},
"test/xml-repo": {\n
"type": "xml"\n
}\n
}\n
"test/xml-repo": {
"type": "xml"
}
}
Note: this command does not automatically register repositories.json as a target file.
It is recommended that the content of the file is reviewed before doing so manually.
"""
developer_tool.generate_repositories_json(path, root_dir, namespace, targets_rel_dir, custom)

@repo.command()
@click.argument('path')
@click.argument("path")
@click.option("--root-dir", default=None, help="Directory where target repositories and, "
"optionally, authentication repository are located. If omitted it is "
"calculated based on authentication repository's path. "
"Authentication repo is persumed to be at root-dir/namespace/auth-repo-name")
"Authentication repo is presumed to be at root-dir/namespace/auth-repo-name")
@click.option("--namespace", default=None, help="Namespace of the target repositories. "
"If omitted, it will be assumed that namespace matches the name of the "
"directory which contains the authentication repository")
@click.option('--targets-rel-dir', default=None, help=' Directory relative to which urls '
'of the target repositories are set, if they do not have remote set')
@click.option("--targets-rel-dir", default=None, help="Directory relative to which "
"urls of the target repositories are calculated. Only useful when "
"the target repositories do not have remotes set")
Expand All @@ -144,17 +145,18 @@ def generate_repositories_json(path, root_dir, namespace, targets_rel_dir, custo
"committed automatically")
@click.option("--test", is_flag=True, default=False, help="Indicates if the created repository "
"is a test authentication repository")
@click.option('--scheme', default=DEFAULT_RSA_SIGNATURE_SCHEME, help='A signature scheme used for signing.')
@click.option("--scheme", default=DEFAULT_RSA_SIGNATURE_SCHEME, help="A signature scheme used for signing.")
def initialize(path, root_dir, namespace, targets_rel_dir, custom, add_branch, keystore,
keys_description, commit, test, scheme):
"""
Create and initialize a new authentication repository:\n
1. Crete an authentication repository (generate initial metadata files)\n
2. Commit initial metadata files if commit == True\n
3. Add target files corresponding to target repositories\n
4. Generate repositories.json\n
5. Update metadata files\n
6. Commit the changes if commit == True\n
\b
Create and initialize a new authentication repository:
1. Create an authentication repository (generate initial metadata files)
2. Commit initial metadata files if commit == True
3. Add target files corresponding to target repositories
4. Generate repositories.json
5. Update metadata files
6. Commit the changes if commit == True
Combines create, generate_repositories_json, update_repos and targets sign commands.
In order to have greater control over individual steps and be able to review files created
in the initialization process, execute the mentioned commands separately.
Expand All @@ -168,7 +170,7 @@ def initialize(path, root_dir, namespace, targets_rel_dir, custom, add_branch, k
@click.option("--clients-root-dir", default=None, help="Directory where target repositories and, "
"optionally, authentication repository are located. If omitted it is "
"calculated based on authentication repository's path. "
"Authentication repo is persumed to be at root-dir/namespace/auth-repo-name")
"Authentication repo is presumed to be at root-dir/namespace/auth-repo-name")
@click.option("--from-fs", is_flag=True, default=False, help="Indicates if the we want to clone a "
"repository from the filesystem")
@click.option("--authenticate-test-repo", is_flag=True, help="Indicates that the authentication "
Expand All @@ -183,7 +185,7 @@ def update(url, clients_auth_path, clients_root_dir, from_fs, authenticate_test_
--clients-root-dir option. This means that if authentication repository's path is
E:\\root\\namespace\\auth-repo, it will be assumed that E:\\root is the root direcotry
if clients-root-dir is not specified.
Names of target repositories (as defined in repositories.json) are appened to the root repository's
Names of target repositories (as defined in repositories.json) are appended to the root repository's
path thus defining the location of each target repository. If names of target repositories
are namespace/repo1, namespace/repo2 etc and the root directory is E:\\root, path of target
repositories will be calculated as E:\\root\\namespace\\repo1, E:\\root\\namespace\\root2 etc.
Expand Down
Loading

0 comments on commit dae535e

Please sign in to comment.