From dab483339aaeb845a73020676a777bdb27345298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 2 Aug 2023 11:36:49 +0200 Subject: [PATCH] test list/remove secret --- pkgs/clan-cli/clan_cli/__init__.py | 41 +-------------------- pkgs/clan-cli/clan_cli/cli.py | 44 +++++++++++++++++++++++ pkgs/clan-cli/clan_cli/secrets/secrets.py | 10 +++--- pkgs/clan-cli/clan_cli/secrets/sops.py | 2 +- pkgs/clan-cli/tests/test_secrets.py | 14 ++++++-- 5 files changed, 63 insertions(+), 48 deletions(-) create mode 100644 pkgs/clan-cli/clan_cli/cli.py diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py index dfc11c9fd..7e5cb3451 100644 --- a/pkgs/clan-cli/clan_cli/__init__.py +++ b/pkgs/clan-cli/clan_cli/__init__.py @@ -1,45 +1,6 @@ # !/usr/bin/env python3 -import argparse -import sys - -from . import admin, secrets, ssh -from .errors import ClanError - -has_argcomplete = True -try: - import argcomplete -except ImportError: - has_argcomplete = False - - -# this will be the entrypoint under /bin/clan (see pyproject.toml config) -def main() -> None: - parser = argparse.ArgumentParser(description="cLAN tool") - subparsers = parser.add_subparsers() - - parser_admin = subparsers.add_parser("admin") - admin.register_parser(parser_admin) - - parser_ssh = subparsers.add_parser("ssh", help="ssh to a remote machine") - ssh.register_parser(parser_ssh) - - parser_secrets = subparsers.add_parser("secrets", help="manage secrets") - secrets.register_parser(parser_secrets) - - if has_argcomplete: - argcomplete.autocomplete(parser) - - if len(sys.argv) == 1: - parser.print_help() - - args = parser.parse_args() - if hasattr(args, "func"): - try: - args.func(args) - except ClanError as e: - print(f"{sys.argv[0]}: {e}") - sys.exit(1) +from .cli import main if __name__ == "__main__": main() diff --git a/pkgs/clan-cli/clan_cli/cli.py b/pkgs/clan-cli/clan_cli/cli.py new file mode 100644 index 000000000..1319a3d32 --- /dev/null +++ b/pkgs/clan-cli/clan_cli/cli.py @@ -0,0 +1,44 @@ +import argparse +import sys + +from . import admin, secrets, ssh +from .errors import ClanError + +has_argcomplete = True +try: + import argcomplete +except ImportError: + has_argcomplete = False + + +# this will be the entrypoint under /bin/clan (see pyproject.toml config) +def main() -> None: + parser = argparse.ArgumentParser(description="cLAN tool") + subparsers = parser.add_subparsers() + + parser_admin = subparsers.add_parser("admin") + admin.register_parser(parser_admin) + + parser_ssh = subparsers.add_parser("ssh", help="ssh to a remote machine") + ssh.register_parser(parser_ssh) + + parser_secrets = subparsers.add_parser("secrets", help="manage secrets") + secrets.register_parser(parser_secrets) + + if has_argcomplete: + argcomplete.autocomplete(parser) + + if len(sys.argv) == 1: + parser.print_help() + + args = parser.parse_args() + if hasattr(args, "func"): + try: + args.func(args) + except ClanError as e: + print(f"{sys.argv[0]}: {e}") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/pkgs/clan-cli/clan_cli/secrets/secrets.py b/pkgs/clan-cli/clan_cli/secrets/secrets.py index eda8657f0..52c62c6f2 100644 --- a/pkgs/clan-cli/clan_cli/secrets/secrets.py +++ b/pkgs/clan-cli/clan_cli/secrets/secrets.py @@ -1,6 +1,7 @@ import argparse import getpass import os +import shutil import subprocess import sys from io import StringIO @@ -43,16 +44,15 @@ def encrypt_secret(key: SopsKey, secret: Path, value: IO[str]) -> None: def set_command(args: argparse.Namespace) -> None: - secret: str = args.secret key = ensure_sops_key() secret_value = os.environ.get("SOPS_NIX_SECRET") if secret_value: - encrypt_secret(key, sops_secrets_folder() / secret, StringIO(secret_value)) + encrypt_secret(key, sops_secrets_folder() / args.secret, StringIO(secret_value)) elif tty.is_interactive(): secret = getpass.getpass(prompt="Paste your secret: ") - encrypt_secret(key, sops_secrets_folder() / secret, StringIO(secret)) + encrypt_secret(key, sops_secrets_folder() / args.secret, StringIO(secret)) else: - encrypt_secret(key, sops_secrets_folder() / secret, sys.stdin) + encrypt_secret(key, sops_secrets_folder() / args.secret, sys.stdin) def remove_command(args: argparse.Namespace) -> None: @@ -60,7 +60,7 @@ def remove_command(args: argparse.Namespace) -> None: path = sops_secrets_folder() / secret if not path.exists(): raise ClanError(f"Secret '{secret}' does not exist") - path.unlink() + shutil.rmtree(path) def add_secret_argument(parser: argparse.ArgumentParser) -> None: diff --git a/pkgs/clan-cli/clan_cli/secrets/sops.py b/pkgs/clan-cli/clan_cli/secrets/sops.py index a995f46f4..459c5b3ee 100644 --- a/pkgs/clan-cli/clan_cli/secrets/sops.py +++ b/pkgs/clan-cli/clan_cli/secrets/sops.py @@ -39,7 +39,7 @@ def get_user_name(user: str) -> str: """Ask the user for their name until a unique one is provided.""" while True: name = input( - f"Enter your user name for which the key will be stored as [{user}]: " + f"Enter your user name for which your sops key will be stored in the repository [default: {user}]: " ) if name: user = name diff --git a/pkgs/clan-cli/tests/test_secrets.py b/pkgs/clan-cli/tests/test_secrets.py index 59e3d0601..b9425abf9 100644 --- a/pkgs/clan-cli/tests/test_secrets.py +++ b/pkgs/clan-cli/tests/test_secrets.py @@ -114,7 +114,17 @@ def test_secrets( with mock_env( SOPS_NIX_SECRET="foo", SOPS_AGE_KEY_FILE=str(clan_flake / ".." / "age.key") ): - cli.run(["set", "nonexisting"]) + cli.run(["set", "key"]) capsys.readouterr() - cli.run(["get", "nonexisting"]) + cli.run(["get", "key"]) assert capsys.readouterr().out == "foo" + + capsys.readouterr() # empty the buffer + cli.run(["list"]) + assert capsys.readouterr().out == "key\n" + + cli.run(["remove", "key"]) + + capsys.readouterr() # empty the buffer + cli.run(["list"]) + assert capsys.readouterr().out == ""