python-tuf/examples/uploader/uploader
Jussi Kukkonen 26495a5d0a examples: Improve uploader docs/messages
Signed-off-by: Jussi Kukkonen <jkukkonen@google.com>
2023-02-08 10:47:34 +02:00

140 lines
4.2 KiB
Python
Executable file

#!/usr/bin/env python
# Copyright 2021-2022 python-tuf contributors
# SPDX-License-Identifier: MIT OR Apache-2.0
"""Simple uploader tool example
Uploader is a maintainer application that communicates with the repository
example. Uploader controls offline signing keys and produces signed metadata
that it sends to the repository application so that the metadata can be added
to the repository.
"""
import argparse
import logging
import os
import sys
from hashlib import sha256
from pathlib import Path
from typing import List, Optional
from urllib import request
from _localrepo import LocalRepository
logger = logging.getLogger(__name__)
def build_metadata_dir(base_url: str) -> str:
"""build a unique and reproducible metadata dirname for the repo url"""
name = sha256(base_url.encode()).hexdigest()[:8]
# TODO: Make this not windows hostile?
return f"{Path.home()}/.local/share/tuf-upload-example/{name}"
def build_key_dir(base_url: str) -> str:
"""build a unique and reproducible private key dir for the repository url"""
name = sha256(base_url.encode()).hexdigest()[:8]
# TODO: Make this not windows hostile?
return f"{Path.home()}/.config/tuf-upload-example/{name}"
def init_tofu(base_url: str) -> bool:
"""Initialize local trusted metadata (Trust-On-First-Use)"""
metadata_dir = build_metadata_dir(base_url)
if not os.path.isdir(metadata_dir):
os.makedirs(metadata_dir)
root_url = f"{base_url}/metadata/1.root.json"
try:
request.urlretrieve(root_url, f"{metadata_dir}/root.json")
except OSError:
print(f"Failed to download initial root from {root_url}")
return False
print(f"Trust-on-First-Use: Initialized new root in {metadata_dir}")
return True
def init(base_url: str) -> Optional[LocalRepository]:
"""Initialize a LocalRepository: local root.json must already exist"""
metadata_dir = build_metadata_dir(base_url)
keydir = build_key_dir(base_url)
if not os.path.isfile(f"{metadata_dir}/root.json"):
print(
"Trusted local root not found. Use 'tofu' command to "
"Trust-On-First-Use or copy trusted root metadata to "
f"{metadata_dir}/root.json"
)
return None
print(f"Using trusted root in {metadata_dir}")
return LocalRepository(metadata_dir, keydir, base_url)
def main(argv: List[str]) -> None:
"""Example uploader tool"""
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", action="count", default=0)
parser.add_argument(
"-u",
"--url",
help="Base repository URL",
default="http://127.0.0.1:8001",
)
subparsers = parser.add_subparsers(dest="sub_command")
tofu_cmd = subparsers.add_parser(
"tofu",
help="Initialize client with Trust-On-First-Use",
)
add_delegation_cmd = subparsers.add_parser(
"add-delegation",
help="Create a delegation and signing key",
)
add_delegation_cmd.add_argument("rolename")
add_target_cmd = subparsers.add_parser(
"add-target",
help="Add a target to a delegated role",
)
add_target_cmd.add_argument("rolename")
add_target_cmd.add_argument("targetpath")
args = parser.parse_args()
if args.verbose == 0:
loglevel = logging.ERROR
elif args.verbose == 1:
loglevel = logging.WARNING
elif args.verbose == 2:
loglevel = logging.INFO
else:
loglevel = logging.DEBUG
logging.basicConfig(level=loglevel)
if args.sub_command == "tofu":
if not init_tofu(args.url):
return "Failed to initialize local repository"
elif args.sub_command == "add-delegation":
repo = init(args.url)
if not repo:
return "Failed to initialize"
if not repo.add_delegation(args.rolename):
return "Failed to add delegation"
elif args.sub_command == "add-target":
repo = init(args.url)
if not repo:
return "Failed to initialize"
if not repo.add_target(args.rolename, args.targetpath):
return "Failed to add target"
else:
parser.print_help()
if __name__ == "__main__":
sys.exit(main(sys.argv))