Improvements for clan secrets key generate.

I am not sure to understand what `extract_public_key` was for. It seems
like `age-keygen -y` will just work fine for a file like
`extract_public_key` is looking for. Unless someone intentionally made a
file with a comment like that without the private key in it.

Messages are moved to stdout rather being logged. It feels like the
output is meaningful in the first step users are going to take. Also
makes testing easier, as log messages are captured differently than
stdout. The call to add an user is changed to be easier to copy paste
and work whether PGP or age is in use.

A description for the command is added instead of help which does not
seem to be displayed.
This commit is contained in:
Louis Opter
2024-10-01 19:53:22 -07:00
committed by Mic92
parent 611d8b40f3
commit ab46e3c1e2
2 changed files with 26 additions and 36 deletions

View File

@@ -2,57 +2,40 @@ import argparse
import json import json
import logging import logging
import sys import sys
from pathlib import Path
from clan_cli.errors import ClanError from clan_cli.errors import ClanError
from clan_cli.git import commit_files from clan_cli.git import commit_files
from . import sops from . import sops
from .secrets import update_secrets from .secrets import update_secrets
from .sops import default_admin_key_path, generate_private_key from .sops import (
default_admin_key_path,
generate_private_key,
maybe_get_admin_public_key,
)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def extract_public_key(filepath: Path) -> str: def generate_key() -> sops.SopsKey:
""" key = maybe_get_admin_public_key()
Extracts the public key from a given text file. if key is not None:
""" print(f"{key.key_type.name} key {key.pubkey} is already set")
try: return key
with filepath.open() as file:
for line in file:
# Check if the line contains the public key
if line.startswith("# public key:"):
# Extract and return the public key part after the prefix
return line.strip().split(": ")[1]
except FileNotFoundError as e:
msg = f"The file at {filepath} was not found."
raise ClanError(msg) from e
except OSError as e:
msg = f"An error occurred while extracting the public key: {e}"
raise ClanError(msg) from e
msg = f"Could not find the public key in the file at {filepath}."
raise ClanError(msg)
def generate_key() -> str:
path = default_admin_key_path() path = default_admin_key_path()
if path.exists(): _, pub_key = generate_private_key(out_file=path)
log.info(f"Key already exists at {path}") print(
return extract_public_key(path) f"Generated age private key at '{path}' for your user. Please back it up on a secure location or you will lose access to your secrets."
priv_key, pub_key = generate_private_key(out_file=path)
log.info(
f"Generated age private key at '{default_admin_key_path()}' for your user. Please back it up on a secure location or you will lose access to your secrets."
) )
return pub_key return sops.SopsKey(pub_key, username="", key_type=sops.KeyType.AGE)
def generate_command(args: argparse.Namespace) -> None: def generate_command(args: argparse.Namespace) -> None:
pub_key = generate_key() key = generate_key()
log.info( print("Also add your age public key to the repository with:")
f"Also add your age public key to the repository with: \nclan secrets users add <username> {pub_key}" key_type = key.key_type.name.lower()
) print(f"clan secrets users add --{key_type}-key <username>")
def show_command(args: argparse.Namespace) -> None: def show_command(args: argparse.Namespace) -> None:
@@ -76,7 +59,13 @@ def register_key_parser(parser: argparse.ArgumentParser) -> None:
required=True, required=True,
) )
parser_generate = subparser.add_parser("generate", help="generate age key") parser_generate = subparser.add_parser(
"generate",
description=(
"Generate an age key for the Clan, "
"to use PGP set `SOPS_PGP_FP` in your environment."
),
)
parser_generate.set_defaults(func=generate_command) parser_generate.set_defaults(func=generate_command)
parser_show = subparser.add_parser("show", help="show public key") parser_show = subparser.add_parser("show", help="show public key")

View File

@@ -180,6 +180,7 @@ def register_users_parser(parser: argparse.ArgumentParser) -> None:
"--pgp-key", "--pgp-key",
help=( help=(
"public PGP encryption key of the user. " "public PGP encryption key of the user. "
# Use --fingerprint --fingerprint to get fingerprints for subkeys:
"Execute `gpg -k --fingerprint --fingerprint` and remove spaces to get it." "Execute `gpg -k --fingerprint --fingerprint` and remove spaces to get it."
), ),
) )