From 9780463e6a8b2fe5016d5564d14e5b1c2c9910ff Mon Sep 17 00:00:00 2001 From: Louis Opter Date: Mon, 10 Mar 2025 22:13:02 +0000 Subject: [PATCH] clan-cli: add an integration test for `clan machines delete` This tests the changes made to that command to clean-up vars and secrets when a machine is deleted. --- pkgs/clan-cli/tests/test_machines_cli.py | 86 +++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/pkgs/clan-cli/tests/test_machines_cli.py b/pkgs/clan-cli/tests/test_machines_cli.py index 9b31e5438..9e5977c1d 100644 --- a/pkgs/clan-cli/tests/test_machines_cli.py +++ b/pkgs/clan-cli/tests/test_machines_cli.py @@ -1,13 +1,15 @@ +import fixtures_flakes import pytest +from age_keys import SopsSetup, assert_secrets_file_recipients from clan_cli.inventory import load_inventory_json -from fixtures_flakes import FlakeForTest +from clan_cli.secrets.folders import sops_machines_folder from helpers import cli from stdout import CaptureOutput @pytest.mark.impure def test_machine_subcommands( - test_flake_with_core: FlakeForTest, + test_flake_with_core: fixtures_flakes.FlakeForTest, capture_output: CaptureOutput, ) -> None: cli.run( @@ -47,3 +49,83 @@ def test_machine_subcommands( assert "machine1" not in output.out assert "vm1" in output.out assert "vm2" in output.out + + +# louis(2025-03-09): +# +# The `with_core` mark is cargo-culted from +# `test_generate_public_and_secret_vars` which +# I used as a starting point: +@pytest.mark.with_core +def test_machine_delete( + monkeypatch: pytest.MonkeyPatch, + flake: fixtures_flakes.ClanFlake, + sops_setup: SopsSetup, +) -> None: + # create the admin user and set its key: + sops_setup.init(flake.path) + + # admin_key, machine_key, machine2_key = age_keys + admin_key, machine_key, machine2_key = sops_setup.keys + + # create a couple machines with their keys + for name, key in (("my-machine", machine_key), ("my-machine2", machine2_key)): + cli.run(["machines", "create", f"--flake={flake.path}", name]) + add_machine_key = [ + "secrets", + "machines", + "add", + f"--flake={flake.path}", + name, + key.pubkey, + ] + cli.run(add_machine_key) + + # create a secret shared by both machines + shared_secret_name = "shared_secret" + with monkeypatch.context(): + monkeypatch.setenv("SOPS_NIX_SECRET", "secret_value") + set_shared_secret = [ + "secrets", + "set", + f"--flake={flake.path}", + "--machine=my-machine", + "--machine=my-machine2", + shared_secret_name, + ] + cli.run(set_shared_secret) + + my_machine_sops_folder = sops_machines_folder(flake.path) / "my-machine" + assert my_machine_sops_folder.is_dir(), ( + "A sops folder for `my-machine` should have been created with its public key" + ) + + # define some vars generator for `my-machine`: + config = flake.machines["my-machine"] + config["nixpkgs"]["hostPlatform"] = "x86_64-linux" + my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] + my_generator["files"]["my_value"]["secret"] = False + my_generator["files"]["my_secret"]["secret"] = True + my_generator["script"] = ( + "echo -n public > $out/my_value;" + "echo -n secret > $out/my_secret;" + "echo -n non-default > $out/value_with_default" + ) + flake.refresh() # saves "my_generator" + monkeypatch.chdir(flake.path) + + cli.run(["vars", "generate", "--flake", str(flake.path), "my-machine"]) + my_machine_vars_store = flake.path / "vars/per-machine" / "my-machine" + assert my_machine_vars_store.is_dir(), ( + "A vars directory should have been created for `my-machine`" + ) + + cli.run(["machines", "delete", "--flake", str(flake.path), "my-machine"]) + assert not my_machine_vars_store.exists(), ( + "The vars directory for `my-machine` should have been deleted" + ) + assert not my_machine_sops_folder.exists(), ( + "The sops folder holding the public key for `my-machine` should have been deleted" + ) + expected_recipients = [admin_key, machine2_key] + assert_secrets_file_recipients(flake.path, shared_secret_name, expected_recipients)