diff --git a/checks/rabbi-gerzi-domains.nix b/checks/rabbi-gerzi-domains.nix new file mode 100644 index 0000000..27c9e62 --- /dev/null +++ b/checks/rabbi-gerzi-domains.nix @@ -0,0 +1,77 @@ +{ + config, + lib, + pkgs, +}: + +let + frontendConfig = config.services.rabbi-gerzi.frontend; + backendConfig = config.services.rabbi-gerzi.backend; + frontendVirtualHost = config.services.nginx.virtualHosts.${frontendConfig.hostName}; + backendVirtualHost = config.services.nginx.virtualHosts.${backendConfig.hostName}; + redirectVirtualHost = lib.attrByPath [ + "www.rabbigerzi.com" + ] { } config.services.nginx.virtualHosts; + + assertions = [ + { + assertion = frontendConfig.hostName == "rabbigerzi.com"; + message = "Rabbi Gerzi frontend does not use the production domain"; + } + { + assertion = frontendConfig.apiBaseUrl == "https://api.rabbigerzi.com"; + message = "Rabbi Gerzi frontend does not use the production API"; + } + { + assertion = frontendConfig.redirectHostNames == [ "www.rabbigerzi.com" ]; + message = "Rabbi Gerzi frontend redirect hosts are not configured"; + } + { + assertion = backendConfig.hostName == "api.rabbigerzi.com"; + message = "Rabbi Gerzi backend does not use the production API domain"; + } + { + assertion = + backendConfig.corsAllowedOrigins == [ + "https://rabbigerzi.com" + "https://rabbigerzi.yisroelbaum.com" + ]; + message = "Rabbi Gerzi CORS origins do not cover production and staging"; + } + { + assertion = builtins.elem "rabbigerzi.yisroelbaum.com" frontendVirtualHost.serverAliases; + message = "Rabbi Gerzi frontend staging alias is missing"; + } + { + assertion = builtins.elem "rabbigerziapi.yisroelbaum.com" backendVirtualHost.serverAliases; + message = "Rabbi Gerzi backend staging alias is missing"; + } + { + assertion = redirectVirtualHost.globalRedirect or null == "rabbigerzi.com"; + message = "Rabbi Gerzi www host does not redirect to the apex"; + } + { + assertion = redirectVirtualHost.forceSSL or false; + message = "Rabbi Gerzi www redirect does not force HTTPS"; + } + { + assertion = redirectVirtualHost.enableACME or false; + message = "Rabbi Gerzi www redirect does not enable ACME"; + } + ]; + + failedAssertions = lib.filter (assertion: !assertion.assertion) assertions; +in +pkgs.runCommand "rabbi-gerzi-production-domains" + { + failures = lib.concatMapStringsSep "\n" (assertion: assertion.message) failedAssertions; + preferLocalBuild = true; + } + '' + if [ -n "$failures" ]; then + printf '%s\n' "$failures" >&2 + exit 1 + fi + + touch $out + '' diff --git a/flake.nix b/flake.nix index 1c9a84d..fc821ec 100644 --- a/flake.nix +++ b/flake.nix @@ -59,6 +59,11 @@ } ]; }; + checks."${system}".rabbi-gerzi-domains = import ./checks/rabbi-gerzi-domains.nix { + config = self.nixosConfigurations.nixos.config; + inherit (nixpkgs) lib; + pkgs = nixpkgs.legacyPackages.${system}; + }; devShells."${system}".default = let pkgs = import nixpkgs { inherit system; }; diff --git a/rabbi-gerzi.nix b/rabbi-gerzi.nix index 8da51b0..70fd980 100644 --- a/rabbi-gerzi.nix +++ b/rabbi-gerzi.nix @@ -10,18 +10,25 @@ borgPrivateKey = config.sops.secrets."borg-private-key".path; }; frontend = { - hostName = "rabbigerzi.yisroelbaum.com"; + hostName = "rabbigerzi.com"; + redirectHostNames = [ "www.rabbigerzi.com" ]; nginx = { forceSSL = true; enableACME = true; + serverAliases = [ "rabbigerzi.yisroelbaum.com" ]; }; }; backend = { - hostName = "rabbigerziapi.yisroelbaum.com"; + hostName = "api.rabbigerzi.com"; environmentFile = config.sops.secrets."rabbi-gerzi-env".path; + corsAllowedOrigins = [ + "https://rabbigerzi.com" + "https://rabbigerzi.yisroelbaum.com" + ]; nginx = { forceSSL = true; enableACME = true; + serverAliases = [ "rabbigerziapi.yisroelbaum.com" ]; }; }; };