From d600a927eab0fac566e4027638b242dcad3eff0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 24 Aug 2023 17:29:31 +0200 Subject: [PATCH] tests: generalize secret cli parser to work for all cli commands --- pkgs/clan-cli/clan_cli/__init__.py | 13 +-- .../tests/helpers/{secret_cli.py => cli.py} | 10 +- pkgs/clan-cli/tests/test_admin_cli.py | 13 +-- pkgs/clan-cli/tests/test_import_sops_cli.py | 19 ++-- pkgs/clan-cli/tests/test_secrets_cli.py | 91 ++++++++++--------- 5 files changed, 71 insertions(+), 75 deletions(-) rename pkgs/clan-cli/tests/helpers/{secret_cli.py => cli.py} (50%) diff --git a/pkgs/clan-cli/clan_cli/__init__.py b/pkgs/clan-cli/clan_cli/__init__.py index d12d0c65b..9f49bb60f 100644 --- a/pkgs/clan-cli/clan_cli/__init__.py +++ b/pkgs/clan-cli/clan_cli/__init__.py @@ -16,8 +16,8 @@ except ImportError: pass -def parse_args(args: list[str]) -> argparse.Namespace: - parser = argparse.ArgumentParser(description="cLAN tool") +def create_parser(prog: Optional[str] = None) -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(prog=prog, description="cLAN tool") subparsers = parser.add_subparsers() parser_admin = subparsers.add_parser("admin", help="administrate a clan") @@ -46,14 +46,15 @@ def parse_args(args: list[str]) -> argparse.Namespace: if len(sys.argv) == 1: parser.print_help() - - return parser.parse_args(args) + return parser # this will be the entrypoint under /bin/clan (see pyproject.toml config) def main() -> None: - args = parse_args(sys.argv[1:]) - assert hasattr(args, "func") + parser = create_parser() + args = parser.parse_args() + if not hasattr(args, "func"): + return try: args.func(args) except ClanError as e: diff --git a/pkgs/clan-cli/tests/helpers/secret_cli.py b/pkgs/clan-cli/tests/helpers/cli.py similarity index 50% rename from pkgs/clan-cli/tests/helpers/secret_cli.py rename to pkgs/clan-cli/tests/helpers/cli.py index d43408d05..ea633c2b1 100644 --- a/pkgs/clan-cli/tests/helpers/secret_cli.py +++ b/pkgs/clan-cli/tests/helpers/cli.py @@ -1,14 +1,14 @@ import argparse -from clan_cli.secrets import register_parser +from clan_cli import create_parser -class SecretCli: +class Cli: def __init__(self) -> None: - self.parser = argparse.ArgumentParser() - register_parser(self.parser) + self.parser = create_parser(prog="clan") def run(self, args: list[str]) -> argparse.Namespace: parsed = self.parser.parse_args(args) - parsed.func(parsed) + if hasattr(parsed, "func"): + parsed.func(parsed) return parsed diff --git a/pkgs/clan-cli/tests/test_admin_cli.py b/pkgs/clan-cli/tests/test_admin_cli.py index db829c873..dba43d147 100644 --- a/pkgs/clan-cli/tests/test_admin_cli.py +++ b/pkgs/clan-cli/tests/test_admin_cli.py @@ -1,21 +1,14 @@ -import argparse from typing import Union import pytest_subprocess.fake_process +from cli import Cli from pytest_subprocess import utils -from clan_cli import admin - - -def test_make_parser() -> None: - parser = argparse.ArgumentParser() - admin.register_parser(parser) - # using fp fixture from pytest-subprocess def test_create(fp: pytest_subprocess.fake_process.FakeProcess) -> None: cmd: list[Union[str, utils.Any]] = ["nix", "flake", "init", "-t", fp.any()] fp.register(cmd) - args = argparse.Namespace(folder="./my-clan") - admin.create(args) + cli = Cli() + cli.run(["admin", "--folder", "./my-clan", "create"]) assert fp.call_count(cmd) == 1 diff --git a/pkgs/clan-cli/tests/test_import_sops_cli.py b/pkgs/clan-cli/tests/test_import_sops_cli.py index 73a6a1349..8c9cebbdf 100644 --- a/pkgs/clan-cli/tests/test_import_sops_cli.py +++ b/pkgs/clan-cli/tests/test_import_sops_cli.py @@ -2,8 +2,8 @@ from pathlib import Path from typing import TYPE_CHECKING import pytest +from cli import Cli from environment import mock_env -from secret_cli import SecretCli if TYPE_CHECKING: from age_keys import KeyPair @@ -15,19 +15,20 @@ def test_import_sops( capsys: pytest.CaptureFixture, age_keys: list["KeyPair"], ) -> None: - cli = SecretCli() + cli = Cli() with mock_env(SOPS_AGE_KEY=age_keys[1].privkey): - cli.run(["machines", "add", "machine1", age_keys[0].pubkey]) - cli.run(["users", "add", "user1", age_keys[1].pubkey]) - cli.run(["users", "add", "user2", age_keys[2].pubkey]) - cli.run(["groups", "add-user", "group1", "user1"]) - cli.run(["groups", "add-user", "group1", "user2"]) + cli.run(["secrets", "machines", "add", "machine1", age_keys[0].pubkey]) + cli.run(["secrets", "users", "add", "user1", age_keys[1].pubkey]) + cli.run(["secrets", "users", "add", "user2", age_keys[2].pubkey]) + cli.run(["secrets", "groups", "add-user", "group1", "user1"]) + cli.run(["secrets", "groups", "add-user", "group1", "user2"]) # To edit: # SOPS_AGE_KEY=AGE-SECRET-KEY-1U5ENXZQAY62NC78Y2WC0SEGRRMAEEKH79EYY5TH4GPFWJKEAY0USZ6X7YQ sops --age age14tva0txcrl0zes05x7gkx56qd6wd9q3nwecjac74xxzz4l47r44sv3fz62 ./data/secrets.yaml cli.run( [ + "secrets", "import-sops", "--group", "group1", @@ -37,10 +38,10 @@ def test_import_sops( ] ) capsys.readouterr() - cli.run(["users", "list"]) + cli.run(["secrets", "users", "list"]) users = sorted(capsys.readouterr().out.rstrip().split()) assert users == ["user1", "user2"] capsys.readouterr() - cli.run(["get", "secret-key"]) + cli.run(["secrets", "get", "secret-key"]) assert capsys.readouterr().out == "secret-value" diff --git a/pkgs/clan-cli/tests/test_secrets_cli.py b/pkgs/clan-cli/tests/test_secrets_cli.py index 1d5ec3dae..fd2bbefb2 100644 --- a/pkgs/clan-cli/tests/test_secrets_cli.py +++ b/pkgs/clan-cli/tests/test_secrets_cli.py @@ -3,8 +3,8 @@ from pathlib import Path from typing import TYPE_CHECKING import pytest +from cli import Cli from environment import mock_env -from secret_cli import SecretCli from clan_cli.errors import ClanError @@ -18,16 +18,17 @@ def _test_identities( capsys: pytest.CaptureFixture, age_keys: list["KeyPair"], ) -> None: - cli = SecretCli() + cli = Cli() sops_folder = clan_flake / "sops" - cli.run([what, "add", "foo", age_keys[0].pubkey]) + cli.run(["secrets", what, "add", "foo", age_keys[0].pubkey]) assert (sops_folder / what / "foo" / "key.json").exists() with pytest.raises(ClanError): - cli.run([what, "add", "foo", age_keys[0].pubkey]) + cli.run(["secrets", what, "add", "foo", age_keys[0].pubkey]) cli.run( [ + "secrets", what, "add", "-f", @@ -37,18 +38,18 @@ def _test_identities( ) capsys.readouterr() # empty the buffer - cli.run([what, "list"]) + cli.run(["secrets", what, "list"]) out = capsys.readouterr() # empty the buffer assert "foo" in out.out - cli.run([what, "remove", "foo"]) + cli.run(["secrets", what, "remove", "foo"]) assert not (sops_folder / what / "foo" / "key.json").exists() with pytest.raises(ClanError): # already removed - cli.run([what, "remove", "foo"]) + cli.run(["secrets", what, "remove", "foo"]) capsys.readouterr() - cli.run([what, "list"]) + cli.run(["secrets", what, "list"]) out = capsys.readouterr() assert "foo" not in out.out @@ -68,32 +69,32 @@ def test_machines( def test_groups( clan_flake: Path, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] ) -> None: - cli = SecretCli() + cli = Cli() capsys.readouterr() # empty the buffer - cli.run(["groups", "list"]) + cli.run(["secrets", "groups", "list"]) assert capsys.readouterr().out == "" with pytest.raises(ClanError): # machine does not exist yet - cli.run(["groups", "add-machine", "group1", "machine1"]) + cli.run(["secrets", "groups", "add-machine", "group1", "machine1"]) with pytest.raises(ClanError): # user does not exist yet - cli.run(["groups", "add-user", "groupb1", "user1"]) - cli.run(["machines", "add", "machine1", age_keys[0].pubkey]) - cli.run(["groups", "add-machine", "group1", "machine1"]) + cli.run(["secrets", "groups", "add-user", "groupb1", "user1"]) + cli.run(["secrets", "machines", "add", "machine1", age_keys[0].pubkey]) + cli.run(["secrets", "groups", "add-machine", "group1", "machine1"]) # Should this fail? - cli.run(["groups", "add-machine", "group1", "machine1"]) + cli.run(["secrets", "groups", "add-machine", "group1", "machine1"]) - cli.run(["users", "add", "user1", age_keys[0].pubkey]) - cli.run(["groups", "add-user", "group1", "user1"]) + cli.run(["secrets", "users", "add", "user1", age_keys[0].pubkey]) + cli.run(["secrets", "groups", "add-user", "group1", "user1"]) capsys.readouterr() # empty the buffer - cli.run(["groups", "list"]) + cli.run(["secrets", "groups", "list"]) out = capsys.readouterr().out assert "user1" in out assert "machine1" in out - cli.run(["groups", "remove-user", "group1", "user1"]) - cli.run(["groups", "remove-machine", "group1", "machine1"]) + cli.run(["secrets", "groups", "remove-user", "group1", "user1"]) + cli.run(["secrets", "groups", "remove-machine", "group1", "machine1"]) groups = os.listdir(clan_flake / "sops" / "groups") assert len(groups) == 0 @@ -101,65 +102,65 @@ def test_groups( def test_secrets( clan_flake: Path, capsys: pytest.CaptureFixture, age_keys: list["KeyPair"] ) -> None: - cli = SecretCli() + cli = Cli() capsys.readouterr() # empty the buffer - cli.run(["list"]) + cli.run(["secrets", "list"]) assert capsys.readouterr().out == "" with mock_env( SOPS_NIX_SECRET="foo", SOPS_AGE_KEY_FILE=str(clan_flake / ".." / "age.key") ): with pytest.raises(ClanError): # does not exist yet - cli.run(["get", "nonexisting"]) - cli.run(["set", "key"]) + cli.run(["secrets", "get", "nonexisting"]) + cli.run(["secrets", "set", "key"]) capsys.readouterr() - cli.run(["get", "key"]) + cli.run(["secrets", "get", "key"]) assert capsys.readouterr().out == "foo" capsys.readouterr() - cli.run(["users", "list"]) + cli.run(["secrets", "users", "list"]) users = capsys.readouterr().out.rstrip().split("\n") assert len(users) == 1, f"users: {users}" owner = users[0] capsys.readouterr() # empty the buffer - cli.run(["list"]) + cli.run(["secrets", "list"]) assert capsys.readouterr().out == "key\n" - cli.run(["machines", "add", "machine1", age_keys[0].pubkey]) - cli.run(["machines", "add-secret", "machine1", "key"]) + cli.run(["secrets", "machines", "add", "machine1", age_keys[0].pubkey]) + cli.run(["secrets", "machines", "add-secret", "machine1", "key"]) with mock_env(SOPS_AGE_KEY=age_keys[0].privkey, SOPS_AGE_KEY_FILE=""): capsys.readouterr() - cli.run(["get", "key"]) + cli.run(["secrets", "get", "key"]) assert capsys.readouterr().out == "foo" - cli.run(["machines", "remove-secret", "machine1", "key"]) + cli.run(["secrets", "machines", "remove-secret", "machine1", "key"]) - cli.run(["users", "add", "user1", age_keys[1].pubkey]) - cli.run(["users", "add-secret", "user1", "key"]) + cli.run(["secrets", "users", "add", "user1", age_keys[1].pubkey]) + cli.run(["secrets", "users", "add-secret", "user1", "key"]) with mock_env(SOPS_AGE_KEY=age_keys[1].privkey, SOPS_AGE_KEY_FILE=""): capsys.readouterr() - cli.run(["get", "key"]) + cli.run(["secrets", "get", "key"]) assert capsys.readouterr().out == "foo" - cli.run(["users", "remove-secret", "user1", "key"]) + cli.run(["secrets", "users", "remove-secret", "user1", "key"]) with pytest.raises(ClanError): # does not exist yet - cli.run(["groups", "add-secret", "admin-group", "key"]) - cli.run(["groups", "add-user", "admin-group", "user1"]) - cli.run(["groups", "add-user", "admin-group", owner]) - cli.run(["groups", "add-secret", "admin-group", "key"]) + cli.run(["secrets", "groups", "add-secret", "admin-group", "key"]) + cli.run(["secrets", "groups", "add-user", "admin-group", "user1"]) + cli.run(["secrets", "groups", "add-user", "admin-group", owner]) + cli.run(["secrets", "groups", "add-secret", "admin-group", "key"]) capsys.readouterr() # empty the buffer - cli.run(["set", "--group", "admin-group", "key2"]) + cli.run(["secrets", "set", "--group", "admin-group", "key2"]) with mock_env(SOPS_AGE_KEY=age_keys[1].privkey, SOPS_AGE_KEY_FILE=""): capsys.readouterr() - cli.run(["get", "key"]) + cli.run(["secrets", "get", "key"]) assert capsys.readouterr().out == "foo" - cli.run(["groups", "remove-secret", "admin-group", "key"]) + cli.run(["secrets", "groups", "remove-secret", "admin-group", "key"]) - cli.run(["remove", "key"]) - cli.run(["remove", "key2"]) + cli.run(["secrets", "remove", "key"]) + cli.run(["secrets", "remove", "key2"]) capsys.readouterr() # empty the buffer - cli.run(["list"]) + cli.run(["secrets", "list"]) assert capsys.readouterr().out == ""