diff --git a/flake.nix b/flake.nix index 7b43844..6f5b7af 100644 --- a/flake.nix +++ b/flake.nix @@ -111,6 +111,7 @@ // (vm_test "audiobookshelf" ./test/vm/audiobookshelf.nix) // (vm_test "authelia" ./test/vm/authelia.nix) // (vm_test "grocy" ./test/vm/grocy.nix) + // (vm_test "home-assistant" ./test/vm/home-assistant.nix) // (vm_test "jellyfin" ./test/vm/jellyfin.nix) // (vm_test "ldap" ./test/vm/ldap.nix) // (vm_test "lib" ./test/vm/lib.nix) diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix index 4593469..5b5424b 100644 --- a/modules/services/home-assistant.nix +++ b/modules/services/home-assistant.nix @@ -294,12 +294,12 @@ in in '' if ! -f ${file}; then - mkdir -p ${storage} && cp ${onboarding} ${file} + mkdir -p ''$(dirname ${file}) && cp ${onboarding} ${file} fi '' + shblib.replaceSecrets { userConfig = cfg.config; resultPath = "${config.services.home-assistant.configDir}/secrets.yaml"; - generator = name: value: lib.generators.toYAML {} value; + generator = shblib.replaceSecretsGeneratorAdapter (lib.generators.toYAML {}); }); systemd.tmpfiles.rules = [ diff --git a/test/vm/home-assistant.nix b/test/vm/home-assistant.nix new file mode 100644 index 0000000..1d265c3 --- /dev/null +++ b/test/vm/home-assistant.nix @@ -0,0 +1,216 @@ +{ pkgs, lib, ... }: +let + pkgs' = pkgs; + + subdomain = "ha"; + domain = "example.com"; + fqdn = "${subdomain}.${domain}"; + + # TODO: Test login + commonTestScript = { nodes, ... }: + let + hasSSL = !(isNull nodes.server.shb.home-assistant.ssl); + proto_fqdn = if hasSSL then "https://${fqdn}" else "http://${fqdn}"; + in + '' + import json + import os + import pathlib + + start_all() + server.wait_for_unit("home-assistant.service") + server.wait_for_unit("nginx.service") + server.wait_for_open_port(8123) + + if ${if hasSSL then "True" else "False"}: + server.copy_from_vm("/etc/ssl/certs/ca-certificates.crt") + client.succeed("rm -r /etc/ssl/certs") + client.copy_from_host(str(pathlib.Path(os.environ.get("out", os.getcwd())) / "ca-certificates.crt"), "/etc/ssl/certs/ca-certificates.crt") + + def curl(target, format, endpoint, succeed=True): + return json.loads(target.succeed( + "curl --fail-with-body --silent --show-error --output /dev/null --location" + + " --connect-to ${fqdn}:443:server:443" + + " --connect-to ${fqdn}:80:server:80" + + f" --write-out '{format}'" + + " " + endpoint + )) + + with subtest("access"): + response = curl(client, """{"code":%{response_code}}""", "${proto_fqdn}") + + if response['code'] != 200: + raise Exception(f"Code is {response['code']}") + ''; + + base = { config, ... }: { + imports = [ + (pkgs'.path + "/nixos/modules/profiles/headless.nix") + (pkgs'.path + "/nixos/modules/profiles/qemu-guest.nix") + { + options = { + shb.backup = lib.mkOption { type = lib.types.anything; }; + }; + } + ../../modules/blocks/nginx.nix + ../../modules/blocks/postgresql.nix + ../../modules/blocks/ssl.nix + ../../modules/services/home-assistant.nix + ]; + + # Nginx port. + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + shb.certs = { + cas.selfsigned.myca = { + name = "My CA"; + }; + certs.selfsigned = { + n = { + ca = config.shb.certs.cas.selfsigned.myca; + domain = "*.${domain}"; + group = "nginx"; + }; + }; + }; + + systemd.services.nginx.after = [ config.shb.certs.certs.selfsigned.n.systemdService ]; + systemd.services.nginx.requires = [ config.shb.certs.certs.selfsigned.n.systemdService ]; + }; + + basic = { config, ... }: { + shb.home-assistant = { + enable = true; + inherit subdomain domain; + ssl = config.shb.certs.certs.selfsigned.n; + + config = { + name = "Tiserbox"; + country = "My Country"; + latitude = "01.0000000000"; + longitude.source = pkgs.writeText "longitude" "01.0000000000"; + time_zone = "America/Los_Angeles"; + unit_system = "metric"; + }; + }; + }; + + ldap = { config, ... }: { + imports = [ + ../../modules/blocks/ldap.nix + ]; + + shb.ldap = { + enable = true; + inherit domain; + subdomain = "ldap"; + ldapPort = 3890; + webUIListenPort = 17170; + dcdomain = "dc=example,dc=com"; + ldapUserPasswordFile = pkgs.writeText "ldapUserPassword" "ldapUserPassword"; + jwtSecretFile = pkgs.writeText "jwtSecret" "jwtSecret"; + }; + + networking.hosts = { + "127.0.0.1" = [ "${config.shb.ldap.subdomain}.${domain}" ]; + }; + + shb.home-assistant = { + ldap = { + enable = true; + host = "127.0.0.1"; + port = config.shb.ldap.webUIListenPort; + userGroup = "homeassistant_user"; + }; + }; + }; + + # Not yet supported + # + # sso = { config, ... }: { + # imports = [ + # ../../modules/blocks/authelia.nix + # ]; + # + # shb.authelia = { + # enable = true; + # inherit domain; + # subdomain = "auth"; + # ssl = config.shb.certs.certs.selfsigned.n; + # + # ldapEndpoint = "ldap://127.0.0.1:${builtins.toString config.shb.ldap.ldapPort}"; + # dcdomain = config.shb.ldap.dcdomain; + # + # secrets = { + # jwtSecretFile = pkgs.writeText "jwtSecret" "jwtSecret"; + # ldapAdminPasswordFile = pkgs.writeText "ldapUserPassword" "ldapUserPassword"; + # sessionSecretFile = pkgs.writeText "sessionSecret" "sessionSecret"; + # storageEncryptionKeyFile = pkgs.writeText "storageEncryptionKey" "storageEncryptionKey"; + # identityProvidersOIDCHMACSecretFile = pkgs.writeText "identityProvidersOIDCHMACSecret" "identityProvidersOIDCHMACSecret"; + # identityProvidersOIDCIssuerPrivateKeyFile = (pkgs.runCommand "gen-private-key" {} '' + # mkdir $out + # ${pkgs.openssl}/bin/openssl genrsa -out $out/private.pem 4096 + # '') + "/private.pem"; + # }; + # }; + # + # networking.hosts = { + # "127.0.0.1" = [ "${config.shb.authelia.subdomain}.${domain}" ]; + # }; + # }; +in +{ + basic = pkgs.testers.runNixOSTest { + name = "vaultwarden_basic"; + + nodes.server = lib.mkMerge [ + base + basic + { + options = { + shb.authelia = lib.mkOption { type = lib.types.anything; }; + }; + } + ]; + + nodes.client = {}; + + testScript = commonTestScript; + }; + + ldap = pkgs.testers.runNixOSTest { + name = "vaultwarden_ldap"; + + nodes.server = lib.mkMerge [ + base + basic + ldap + { + options = { + shb.authelia = lib.mkOption { type = lib.types.anything; }; + }; + } + ]; + + nodes.client = {}; + + testScript = commonTestScript; + }; + + # Not yet supported + # + # sso = pkgs.testers.runNixOSTest { + # name = "vaultwarden_sso"; + # + # nodes.server = lib.mkMerge [ + # base + # basic + # ldap + # sso + # ]; + # + # nodes.client = {}; + # + # testScript = commonTestScript; + # }; +}