diff --git a/flake.nix b/flake.nix index 3409529..9e7be65 100644 --- a/flake.nix +++ b/flake.nix @@ -135,6 +135,8 @@ // (vm_test "postgresql" ./test/blocks/postgresql.nix) // (vm_test "restic" ./test/blocks/restic.nix) // (vm_test "ssl" ./test/blocks/ssl.nix) + + // (vm_test "contracts-secret" ./test/contracts/secret.nix) )); } ) // { diff --git a/modules/blocks/hardcodedsecret.nix b/modules/blocks/hardcodedsecret.nix index 6e62cef..4a174d0 100644 --- a/modules/blocks/hardcodedsecret.nix +++ b/modules/blocks/hardcodedsecret.nix @@ -10,6 +10,19 @@ in { options.shb.hardcodedsecret = mkOption { default = {}; + description = '' + Hardcoded secrets. These should only be used in tests. + ''; + example = lib.literalExpression '' + { + mySecret = { + user = "me"; + mode = "0400"; + restartUnits = [ "myservice.service" ]; + content = "My Secrets"; + }; + } + ''; type = attrsOf (submodule ({ name, ... }: { options = { mode = mkOption { diff --git a/modules/contracts/default.nix b/modules/contracts/default.nix index 7fb8cdb..c19f509 100644 --- a/modules/contracts/default.nix +++ b/modules/contracts/default.nix @@ -1,7 +1,10 @@ -{ lib }: +{ pkgs, lib }: { backup = import ./backup.nix { inherit lib; }; mount = import ./mount.nix { inherit lib; }; secret = import ./secret.nix { inherit lib; }; ssl = import ./ssl.nix { inherit lib; }; + test = { + secret = import ./secret/test.nix { inherit pkgs lib; }; + }; } diff --git a/modules/contracts/secret/test.nix b/modules/contracts/secret/test.nix new file mode 100644 index 0000000..046b8d7 --- /dev/null +++ b/modules/contracts/secret/test.nix @@ -0,0 +1,64 @@ +{ pkgs, lib, ... }: +let + pkgs' = pkgs; + + testLib = pkgs.callPackage ../../../test/common.nix {}; + + inherit (lib) getAttrFromPath setAttrByPath; + inherit (lib) mkIf; +in + { name, + configRoot, + createContent, # config to create a secret with value "secretA". + modules ? [], + owner ? "root", + group ? "root", + mode ? "0400", + restartUnits ? [ "myunit.service" ], + }: pkgs.testers.runNixOSTest { + name = "secret_${name}_${owner}_${group}_${mode}"; + + nodes.machine = { config, ... }: { + imports = ( testLib.baseImports pkgs' ) ++ modules; + config = lib.mkMerge [ + (setAttrByPath configRoot { + A = { + inherit owner group mode restartUnits; + } // createContent; + }) + (mkIf (owner != "root") { + users.users.${owner}.isNormalUser = true; + }) + (mkIf (group != "root") { + users.groups.${group} = {}; + }) + ]; + }; + + testScript = { nodes, ... }: + let + cfg = (getAttrFromPath configRoot nodes.machine)."A"; + in + '' + owner = machine.succeed("stat -c '%U' ${cfg.path}").strip() + print(f"Got owner {owner}") + if owner != "${owner}": + raise Exception(f"Owner should be '${owner}' but got '{owner}'") + + group = machine.succeed("stat -c '%G' ${cfg.path}").strip() + print(f"Got group {group}") + if group != "${group}": + raise Exception(f"Group should be '${group}' but got '{group}'") + + mode = str(int(machine.succeed("stat -c '%a' ${cfg.path}").strip())) + print(f"Got mode {mode}") + wantedMode = str(int("${mode}")) + if mode != wantedMode: + raise Exception(f"Mode should be '{wantedMode}' but got '{mode}'") + + content = machine.succeed("cat ${cfg.path}").strip() + print(f"Got content {content}") + if content != "secretA": + raise Exception(f"Content should be 'secretA' but got '{content}'") + ''; +} diff --git a/test/contracts/secret.nix b/test/contracts/secret.nix new file mode 100644 index 0000000..d029100 --- /dev/null +++ b/test/contracts/secret.nix @@ -0,0 +1,35 @@ +{ pkgs, ... }: +let + contracts = pkgs.callPackage ../../modules/contracts {}; +in +{ + hardcoded_root_root = contracts.test.secret { + name = "hardcoded"; + modules = [ ../../modules/blocks/hardcodedsecret.nix ]; + configRoot = [ "shb" "hardcodedsecret" ]; + createContent = { + content = "secretA"; + }; + }; + + hardcoded_user_group = contracts.test.secret { + name = "hardcoded"; + modules = [ ../../modules/blocks/hardcodedsecret.nix ]; + configRoot = [ "shb" "hardcodedsecret" ]; + createContent = { + content = "secretA"; + }; + owner = "user"; + group = "group"; + mode = "640"; + }; + + # TODO: how to do this? + # sops = contracts.test.secret { + # name = "sops"; + # configRoot = cfg: name: cfg.sops.secrets.${name}; + # createContent = content: { + # sopsFile = ./secret/sops.yaml; + # }; + # }; +} diff --git a/test/contracts/secret/sops.yaml b/test/contracts/secret/sops.yaml new file mode 100644 index 0000000..e69de29