From f6e3a4e94bb3ee938245d1ba948346fbe22e9154 Mon Sep 17 00:00:00 2001 From: Levente Polyak Date: Thu, 21 Oct 2021 21:04:16 +0200 Subject: [PATCH] feature(keyringctl): use build command to create final artifacts This allows an easy to use cli which invokes the export function to get the keyring and uses the ownertrust and revoke functions to write all artifacts into a target directory. --- .gitignore | 1 + Makefile | 4 +- README.md | 7 +++ keyringctl | 133 +++++++++++++---------------------------------------- 4 files changed, 42 insertions(+), 103 deletions(-) diff --git a/.gitignore b/.gitignore index eb8805f..2c7a16e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/build *~ archlinux-keyring-*.tar.gz archlinux-keyring-*.tar.gz.sig diff --git a/Makefile b/Makefile index a6ddec8..c8dacac 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PREFIX ?= /usr/local KEYRING_TARGET_DIR=$(DESTDIR)$(PREFIX)/share/pacman/keyrings/ -KEYRING_FILES=$(wildcard keyring/output/*.gpg) $(wildcard keyring/output/*-revoked) $(wildcard keyring/output/*-trusted) +KEYRING_FILES=$(wildcard build/*.gpg) $(wildcard build/*-revoked) $(wildcard build/*-trusted) all: build @@ -11,7 +11,7 @@ lint: mypy --install-types --non-interactive keyringctl build: - ./keyringctl -v export-keyring + ./keyringctl -v build install: install -vDm 755 $(KEYRING_FILES) -t $(KEYRING_TARGET_DIR) diff --git a/README.md b/README.md index 08932eb..4ff64a9 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,13 @@ from the provided data structure and to install it: ## Usage +### Build + +Build all PGP artifacts (keyring, ownertrust, revoked files) to the build directory +```bash +./keyringctl build +``` + ### Import Import a new packager key by deriving the username from the filename. diff --git a/keyringctl b/keyringctl index ccdac26..745028c 100755 --- a/keyringctl +++ b/keyringctl @@ -835,45 +835,6 @@ def convert( return target_dir -def temp_join_keys(sources: List[Path], temp_dir: Path, force: bool) -> List[Path]: - """Temporarily join the key material of a given set of keys in a temporary location and return their paths - - Parameters - ---------- - sources: List[Path] - A list of paths below which PGP packets are found - temp_dir: Path - The temporary directory below which to join PGP keys - force: bool - Whether to force the joining of files - """ - - certs: List[Path] = [] - - for source_number, source in enumerate(sources): - if source.is_dir(): - for user_number, user_dir in enumerate(sorted(source.iterdir())): - if user_dir.is_dir(): - for user_cert_number, user_cert_dir in enumerate(sorted(user_dir.iterdir())): - if user_cert_dir.is_dir(): - cert_path = temp_dir / ( - f"{str(source_number).zfill(4)}" - f"-{str(user_number).zfill(4)}" - f"-{str(user_cert_number).zfill(4)}.asc" - ) - debug(f"Joining {user_dir.name}/{user_cert_dir.name} in {cert_path}.") - packet_join( - packets=sorted(user_cert_dir.glob("**/*.asc")), - output=cert_path, - force=force, - ) - certs.append(cert_path) - elif source.is_file() and not source.is_symlink(): - certs.append(source) - - return certs - - def get_all_and_revoked_certs(certs: List[Path]) -> Tuple[List[Fingerprint], List[Fingerprint]]: """Get the fingerprints of all public keys and all fingerprints of all (self) revoked public keys in a directory @@ -1131,67 +1092,40 @@ def export( ) certificates.append(cert_path) - return keyring_merge(certificates, output) + return keyring_merge(certificates, output, force=True) -def export_keyring( +def build( working_dir: Path, - main: List[Path], - sources: List[Path], - output: Path, - force: bool, - pacman_integration: bool, + keyring_root: Path, + target_dir: Path, ) -> None: - """Export all provided PGP packet files to a single output file - - If sources contains directories, any .asc files below them are considered. + """Build keyring PGP artifacts alongside ownertrust and revoked status files Parameters ---------- working_dir: Path A directory to use for temporary files - main: List[Path] - A list of directories or files from which to read PGP packet information, that is considered as public keys - that are used to sign those found in sources - sources: List[Path] - A list of directories or files from which to read PGP packet information - output: Path - An output file that all PGP packet data is written to - force: bool - Whether to force the execution of packet_join() - pacman_integration: bool - Whether to write pacman compatible trust files + keyring_root: Path + The keyring root directory to build the artifacts from + target_dir: Path + Output directory that all artifacts are written to """ - main = [source.absolute() for source in main] - sources = [source.absolute() for source in sources] - output = output.absolute() + target_dir.mkdir(parents=True, exist_ok=True) - main_certs = temp_join_keys(sources=main, temp_dir=Path(mkdtemp(dir=working_dir)).absolute(), force=force) - sources_certs = temp_join_keys(sources=sources, temp_dir=Path(mkdtemp(dir=working_dir)).absolute(), force=force) - debug( - f"Creating keyring {output} from {[str(source_dir) for source_dir in main]} " - f"and {[str(source_dir) for source_dir in sources]}." + keyring: Path = target_dir / Path("archlinux.gpg") + export(working_dir=working_dir, keyring_root=keyring_root, output=keyring) + + [trusted_main_keys, all_main_keys] = export_ownertrust( + certs=[keyring_root / "main"], + output=target_dir / "archlinux-trusted", + ) + export_revoked( + certs=[keyring_root / "main", keyring_root / "packager"], + main_keys=all_main_keys, + output=target_dir / "archlinux-revoked", ) - - output.parent.mkdir(parents=True, exist_ok=True) - cmd = ["sq", "keyring", "merge", "-o", str(output)] - if force: - cmd.insert(1, "--force") - cmd += [str(cert) for cert in sorted(main_certs)] - cmd += [str(cert) for cert in sorted(sources_certs)] - system(cmd, exit_on_error=False) - - if pacman_integration: - [trusted_main_keys, all_main_keys] = export_ownertrust( - certs=main, - output=Path(f"{str(output).split('.gpg')[0]}-trusted"), - ) - export_revoked( - certs=main + sources, - main_keys=all_main_keys, - output=Path(f"{str(output).split('.gpg')[0]}-revoked"), - ) def absolute_path(path: str) -> Path: @@ -1252,11 +1186,6 @@ if __name__ == "__main__": ) import_parser.add_argument("--main", action="store_true", help="Import a main signing key into the keyring") - export_keyring_parser = subcommands.add_parser( - "export-keyring", - help="export PGP packet data below main/ and packager/ to output/archlinux.gpg alongside pacman integration", - ) - export_parser = subcommands.add_parser( "export", help="export a directory structure of PGP packet data to a combined file", @@ -1269,6 +1198,11 @@ if __name__ == "__main__": type=absolute_path, ) + build_parser = subcommands.add_parser( + "build", + help="build keyring PGP artifacts alongside ownertrust and revoked status files", + ) + args = parser.parse_args() if args.verbose: @@ -1297,15 +1231,6 @@ if __name__ == "__main__": ), ) ) - elif "export-keyring" == args.subcommand: - export_keyring( - working_dir=working_dir, - main=[keyring_root / "main"], - sources=[keyring_root / "packager"], - output=keyring_root / "output" / "archlinux.gpg", - force=True, - pacman_integration=True, - ) elif "export" == args.subcommand: print( export( @@ -1316,6 +1241,12 @@ if __name__ == "__main__": ), end="", ) + elif "build" == args.subcommand: + build( + working_dir=working_dir, + keyring_root=keyring_root, + target_dir=keyring_root.parent / "build", + ) else: parser.print_help()