From bd554ca39269a139e81541b02c0f41ba28da7b08 Mon Sep 17 00:00:00 2001 From: DavHau Date: Wed, 4 Sep 2024 15:40:30 +0200 Subject: [PATCH] vars: new option prompts..createFile --- nixosModules/clanCore/vars/generator.nix | 28 ++++++++++++++++++--- nixosModules/clanCore/vars/interface.nix | 16 ++++++++++++ pkgs/clan-cli/tests/test_vars.py | 31 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/nixosModules/clanCore/vars/generator.nix b/nixosModules/clanCore/vars/generator.nix index 2693a8a38..cbd50a4f0 100644 --- a/nixosModules/clanCore/vars/generator.nix +++ b/nixosModules/clanCore/vars/generator.nix @@ -4,13 +4,32 @@ pkgs, ... }: +let + inherit (lib) + attrNames + concatMapStrings + genAttrs + filterAttrs + makeBinPath + mkOptionDefault + optionalString + ; + + promptToFile = name: '' + cat "$prompts/${name}" > "$out/${name}" + ''; + + promptsToFilesScript = concatMapStrings promptToFile; + + filePromptNames = attrNames (filterAttrs (_name: prompt: prompt.createFile) config.prompts); +in { - finalScript = lib.mkOptionDefault '' + finalScript = mkOptionDefault '' set -eu -o pipefail - export PATH="${lib.makeBinPath config.runtimeInputs}:${pkgs.coreutils}/bin" + export PATH="${makeBinPath config.runtimeInputs}:${pkgs.coreutils}/bin" - ${lib.optionalString (pkgs.stdenv.hostPlatform.isLinux) '' + ${optionalString (pkgs.stdenv.hostPlatform.isLinux) '' # prepare sandbox user on platforms where this is supported mkdir -p /etc @@ -31,6 +50,9 @@ ::1 localhost EOF ''} + ${promptsToFilesScript filePromptNames} ${config.script} ''; + + files = genAttrs filePromptNames (_name: { }); } diff --git a/nixosModules/clanCore/vars/interface.nix b/nixosModules/clanCore/vars/interface.nix index bc8a70312..75d7dce62 100644 --- a/nixosModules/clanCore/vars/interface.nix +++ b/nixosModules/clanCore/vars/interface.nix @@ -120,6 +120,21 @@ in type = attrsOf ( submodule (prompt: { options = options { + createFile = { + description = '' + Whether the prompted value should be stored in a file with the same name as the prompt. + + If enabled, the behavior is equivalent to the following configuration: + ```nix + { + files..secret = true; + script = "cp $prompts/ $out/"; + } + ``` + ''; + type = bool; + default = true; + }; description = { description = '' The description of the prompted value @@ -165,6 +180,7 @@ in The script should produce the files specified in the 'files' attribute under $out. ''; type = either str path; + default = ""; }; finalScript = { description = '' diff --git a/pkgs/clan-cli/tests/test_vars.py b/pkgs/clan-cli/tests/test_vars.py index a6ca8cd9a..4d82bab5b 100644 --- a/pkgs/clan-cli/tests/test_vars.py +++ b/pkgs/clan-cli/tests/test_vars.py @@ -314,6 +314,7 @@ def test_prompt( my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] my_generator["files"]["my_value"]["secret"] = False my_generator["prompts"]["prompt1"]["description"] = "dream2nix" + my_generator["prompts"]["prompt1"]["createFile"] = False my_generator["prompts"]["prompt1"]["type"] = prompt_type my_generator["script"] = "cat $prompts/prompt1 > $out/my_value" flake = generate_flake( @@ -378,3 +379,33 @@ def test_share_flag( assert not in_repo_store.exists("shared_generator", "my_value", shared=False) assert in_repo_store.exists("unshared_generator", "my_value", shared=False) assert not in_repo_store.exists("unshared_generator", "my_value", shared=True) + + +@pytest.mark.impure +def test_prompt_create_file( + monkeypatch: pytest.MonkeyPatch, + temporary_home: Path, + sops_setup: SopsSetup, +) -> None: + """ + Test that the createFile flag in the prompt configuration works as expected + """ + config = nested_dict() + my_generator = config["clan"]["core"]["vars"]["generators"]["my_generator"] + my_generator["prompts"]["prompt1"]["createFile"] = True + my_generator["prompts"]["prompt2"]["createFile"] = False + flake = generate_flake( + temporary_home, + flake_template=CLAN_CORE / "templates" / "minimal", + machine_configs={"my_machine": config}, + ) + monkeypatch.chdir(flake.path) + sops_setup.init() + monkeypatch.setattr("sys.stdin", StringIO("input1\ninput2\n")) + cli.run(["vars", "generate", "--flake", str(flake.path), "my_machine"]) + sops_store = sops.SecretStore( + Machine(name="my_machine", flake=FlakeId(str(flake.path))) + ) + assert sops_store.exists("my_generator", "prompt1") + assert not sops_store.exists("my_generator", "prompt2") + assert sops_store.get("my_generator", "prompt1").decode() == "input1"