From 6e3f2b1ce27ca9a61edb52a41bb776f82e334d86 Mon Sep 17 00:00:00 2001 From: lassulus Date: Fri, 29 Sep 2023 18:31:05 +0200 Subject: [PATCH] tests: add test_secrets_password_store --- pkgs/clan-cli/default.nix | 1 + pkgs/clan-cli/tests/test_flake.py | 9 +++ .../test_flake_with_core_and_pass/.clan-flake | 0 .../test_flake_with_core_and_pass/flake.nix | 37 +++++++++++ .../tests/test_secrets_password_store.py | 62 +++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 pkgs/clan-cli/tests/test_flake_with_core_and_pass/.clan-flake create mode 100644 pkgs/clan-cli/tests/test_flake_with_core_and_pass/flake.nix create mode 100644 pkgs/clan-cli/tests/test_secrets_password_store.py diff --git a/pkgs/clan-cli/default.nix b/pkgs/clan-cli/default.nix index 89fea0545..ac588160d 100644 --- a/pkgs/clan-cli/default.nix +++ b/pkgs/clan-cli/default.nix @@ -45,6 +45,7 @@ let pytest-parallel openssh git + gnupg stdenv.cc ]; diff --git a/pkgs/clan-cli/tests/test_flake.py b/pkgs/clan-cli/tests/test_flake.py index c4debf11e..b27c3bc24 100644 --- a/pkgs/clan-cli/tests/test_flake.py +++ b/pkgs/clan-cli/tests/test_flake.py @@ -48,3 +48,12 @@ def test_flake_with_core(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]: "clan-core flake not found. This test requires the clan-core flake to be present" ) yield from create_flake(monkeypatch, "test_flake_with_core", CLAN_CORE) + + +@pytest.fixture +def test_flake_with_core_and_pass(monkeypatch: pytest.MonkeyPatch) -> Iterator[Path]: + if not (CLAN_CORE / "flake.nix").exists(): + raise Exception( + "clan-core flake not found. This test requires the clan-core flake to be present" + ) + yield from create_flake(monkeypatch, "test_flake_with_core_and_pass", CLAN_CORE) diff --git a/pkgs/clan-cli/tests/test_flake_with_core_and_pass/.clan-flake b/pkgs/clan-cli/tests/test_flake_with_core_and_pass/.clan-flake new file mode 100644 index 000000000..e69de29bb diff --git a/pkgs/clan-cli/tests/test_flake_with_core_and_pass/flake.nix b/pkgs/clan-cli/tests/test_flake_with_core_and_pass/flake.nix new file mode 100644 index 000000000..8bd24afc7 --- /dev/null +++ b/pkgs/clan-cli/tests/test_flake_with_core_and_pass/flake.nix @@ -0,0 +1,37 @@ +{ + # Use this path to our repo root e.g. for UI test + # inputs.clan-core.url = "../../../../."; + + # this placeholder is replaced by the path to nixpkgs + inputs.clan-core.url = "__CLAN_CORE__"; + + outputs = { self, clan-core }: + let + clan = clan-core.lib.buildClan { + directory = self; + machines = { + vm1 = { lib, ... }: { + clan.networking.deploymentAddress = "__CLAN_DEPLOYMENT_ADDRESS__"; + system.stateVersion = lib.version; + clanCore.secretStore = "password-store"; + clanCore.secretsUploadDirectory = lib.mkForce "__CLAN_SOPS_KEY_DIR__/secrets"; + + clan.networking.zerotier.controller.enable = true; + + systemd.services.shutdown-after-boot = { + enable = true; + wantedBy = [ "multi-user.target" ]; + after = [ "multi-user.target" ]; + script = '' + #!/usr/bin/env bash + shutdown -h now + ''; + }; + }; + }; + }; + in + { + inherit (clan) nixosConfigurations clanInternals; + }; +} diff --git a/pkgs/clan-cli/tests/test_secrets_password_store.py b/pkgs/clan-cli/tests/test_secrets_password_store.py new file mode 100644 index 000000000..e6c769ff5 --- /dev/null +++ b/pkgs/clan-cli/tests/test_secrets_password_store.py @@ -0,0 +1,62 @@ +import subprocess +from pathlib import Path + +import pytest +from cli import Cli + +from clan_cli.machines.facts import machine_get_fact +from clan_cli.nix import nix_shell +from clan_cli.ssh import HostGroup + + +@pytest.mark.impure +def test_upload_secret( + monkeypatch: pytest.MonkeyPatch, + test_flake_with_core_and_pass: Path, + temporary_dir: Path, + host_group: HostGroup, +) -> None: + monkeypatch.chdir(test_flake_with_core_and_pass) + gnupghome = temporary_dir / "gpg" + gnupghome.mkdir() + monkeypatch.setenv("GNUPGHOME", str(gnupghome)) + monkeypatch.setenv("PASSWORD_STORE_DIR", str(temporary_dir / "pass")) + gpg_key_spec = temporary_dir / "gpg_key_spec" + gpg_key_spec.write_text( + """ + Key-Type: 1 + Key-Length: 1024 + Name-Real: Root Superuser + Name-Email: test@local + Expire-Date: 0 + %no-protection + """ + ) + cli = Cli() + subprocess.run( + nix_shell(["gnupg"], ["gpg", "--batch", "--gen-key", str(gpg_key_spec)]), + check=True, + ) + subprocess.run(nix_shell(["pass"], ["pass", "init", "test@local"]), check=True) + cli.run(["secrets", "generate", "vm1"]) + network_id = machine_get_fact("vm1", "zerotier-network-id") + assert len(network_id) == 16 + identity_secret = ( + temporary_dir / "pass" / "machines" / "vm1" / "zerotier-identity-secret.gpg" + ) + secret1_mtime = identity_secret.lstat().st_mtime_ns + + # test idempotency + cli.run(["secrets", "generate", "vm1"]) + assert identity_secret.lstat().st_mtime_ns == secret1_mtime + + flake = test_flake_with_core_and_pass.joinpath("flake.nix") + host = host_group.hosts[0] + addr = f"{host.user}@{host.host}:{host.port}?StrictHostKeyChecking=no&UserKnownHostsFile=/dev/null&IdentityFile={host.key}" + new_text = flake.read_text().replace("__CLAN_DEPLOYMENT_ADDRESS__", addr) + flake.write_text(new_text) + cli.run(["secrets", "upload", "vm1"]) + zerotier_identity_secret = ( + test_flake_with_core_and_pass / "secrets" / "zerotier-identity-secret" + ) + assert zerotier_identity_secret.exists()