New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add repository initialization #1
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
venv/ | ||
bin/ | ||
__pycache__/ | ||
*.egg-info/ | ||
.vscode/ | ||
testing/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.PHONY: bootstrap | ||
bootstrap: | ||
python3 -m venv venv && \ | ||
. ./venv/bin/activate && \ | ||
pip3 install -r requirements.txt | ||
|
||
.PHONY: build | ||
build: | ||
pip3 install --editable . |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import click | ||
import pathlib | ||
|
||
import tuf_helpers | ||
|
||
global_options = [ | ||
click.option('--trustdir', default=tuf_helpers.default_trust_dir, | ||
help='Directory where the trust data is persisted', show_default=True) | ||
] | ||
|
||
|
||
def apply_global_options(func): | ||
for option in global_options: | ||
func = option(func) | ||
return func | ||
|
||
|
||
@click.group() | ||
def cli(): | ||
"""PySigny is a Python implementation of the CNAB Security Specification.""" | ||
pass | ||
|
||
|
||
@apply_global_options | ||
@click.command() | ||
@click.argument('target') | ||
@click.argument('name') | ||
def sign(target, name, trustdir): | ||
"""Initializes a new trust collection.""" | ||
|
||
click.echo('Signing file {0} and adding to repo {1} in trust dir {2}'.format( | ||
target, name, trustdir)) | ||
|
||
tuf_helpers.init_repo(target, name, trustdir) | ||
|
||
|
||
cli.add_command(sign) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
### Setup | ||
|
||
``` | ||
$ make boostrap build | ||
$ pysigny --help | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from setuptools import setup | ||
|
||
setup( | ||
name='pysigny', | ||
version='0.0.1', | ||
py_modules=['pysigny'], | ||
install_requires=[ | ||
'Click', | ||
'securesystemslib', | ||
'tuf' | ||
], | ||
entry_points=''' | ||
[console_scripts] | ||
pysigny=pysigny:cli | ||
''', | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: empty line. |
||
import os | ||
import pathlib | ||
import shutil | ||
from typing import Dict | ||
|
||
import securesystemslib as sslib | ||
import tuf.scripts.repo as tuf_repo | ||
import tuf.repository_tool as repo_tool | ||
|
||
|
||
default_trust_dir = pathlib.Path.joinpath(pathlib.Path.home(), '.pysigny') | ||
keystore_dir = 'private' | ||
root_key_name = 'root_key' | ||
targets_key_name = 'targets_key' | ||
snapshot_key_name = 'snapshot_key' | ||
timestamp_key_name = 'timestamp_key' | ||
metadata_staged_dir = 'metadata.staged' | ||
metadata_dir = 'metadata' | ||
|
||
|
||
class TUFKey: | ||
private: None | ||
public: None | ||
passphrase: None | ||
|
||
|
||
keys: Dict[str, TUFKey] = { | ||
root_key_name: TUFKey, | ||
targets_key_name: TUFKey, | ||
snapshot_key_name: TUFKey, | ||
timestamp_key_name: TUFKey | ||
} | ||
|
||
|
||
def init_repo(target, name, trustdir): | ||
repo_path = pathlib.Path.joinpath(trustdir, name) | ||
repository = repo_tool.create_new_repository(str(repo_path)) | ||
create_and_set_keys(repository, name, trustdir) | ||
write_repo(name, trustdir) | ||
|
||
|
||
def create_and_set_keys(repository, name, trustdir): | ||
for k in keys: | ||
p = os.environ.get(k.upper() + '_PASSPHRASE') | ||
if p == None: | ||
keys[k].passphrase = sslib.interface.get_password( | ||
prompt='Enter password for {0}: '.format(k), confirm=True) | ||
else: | ||
keys[k].passphrase = p | ||
|
||
repo_tool.generate_and_write_ecdsa_keypair(os.path.join( | ||
trustdir, name, keystore_dir, k), password=keys[k].passphrase) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The example repository tool generates the keys for all repositories in the same directory (I assume for reusing the root key?) I am still evaluating whether to:
I think it is still early in this tool to take this decision, but we should have this conversation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sharing the same root key by default per repo makes sense, considering that most people are likely to have a separate repo per bundle, following the DCT model. However, we should give an option to override this. |
||
|
||
keys[k].private = tuf_repo.import_privatekey_from_file( | ||
os.path.join(trustdir, name, keystore_dir, k), keys[k].passphrase) | ||
|
||
print('trying to load public key from {0}'.format( | ||
os.path.join(trustdir, name, keystore_dir, k) + '.pub')) | ||
keys[k].public = tuf_repo.import_publickey_from_file( | ||
os.path.join(trustdir, name, keystore_dir, k) + '.pub') | ||
|
||
repository.root.add_verification_key(keys[root_key_name].public) | ||
repository.targets.add_verification_key(keys[targets_key_name].public) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @trishankatdatadog - this generates 3 warnings for the targets, snapshot, and timestamp public keys:
While using the same key here is not an error:
I am wondering though why the keys appear to be shared, since they are generated every time for now (they do share the same passphrase in all my tests so far). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pyTUF repo tool has some spurious messages like that. Will look into this. |
||
repository.snapshot.add_verification_key(keys[snapshot_key_name].public) | ||
repository.timestamp.add_verification_key(keys[timestamp_key_name].public) | ||
|
||
repository.root.load_signing_key(keys[root_key_name].private) | ||
repository.targets.load_signing_key(keys[targets_key_name].private) | ||
repository.snapshot.load_signing_key(keys[snapshot_key_name].private) | ||
repository.timestamp.load_signing_key(keys[timestamp_key_name].private) | ||
|
||
|
||
def write_repo(name, trustdir): | ||
staged_meta = os.path.join(trustdir, name, metadata_staged_dir) | ||
meta = os.path.join(trustdir, name, metadata_dir) | ||
shutil.rmtree(meta, ignore_errors=True) | ||
shutil.copytree(staged_meta, meta) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a more robust way of ensuring a clean virtual environment and Python3?
(And in general, what would be the best practice for ensuring the desired environment?)