feat: Add nginx module

Change-Id: I34fbb926c4b7eab344c1c14de4e4b5f82c6c30eb
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/785
Reviewed-by: Samuel Shuert <coded@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/lib/nginx/http/internal/lib.nginx.http.internal.assertion.spec.nix b/lib/nginx/http/internal/lib.nginx.http.internal.assertion.spec.nix
new file mode 100644
index 0000000..946ef61
--- /dev/null
+++ b/lib/nginx/http/internal/lib.nginx.http.internal.assertion.spec.nix
@@ -0,0 +1,71 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{ lib, ... }: let
+  tailscaleAuthWithRoute = {
+    "calibre.clicks.codes" = {
+      routes."/somePath" = lib.home-manager.hm.dag.entryAnywhere {
+        host = "generic";
+        port = 1024;
+        _type = "reverseProxy";
+        headers = null;
+      };
+      dnsProvider = "cloudflare";
+      service = null;
+      authWith = "tailscale";
+      enableHttp = false;
+    };
+  };
+  serviceAndRoutes = {
+    "calibre.clicks.codes" = {
+      routes."/somePath" = lib.home-manager.hm.dag.entryAnywhere {
+        host = "generic";
+        port = 1024;
+        _type = "reverseProxy";
+        headers = null;
+      };
+      dnsProvider = "cloudflare";
+      service = {
+        host = "generic";
+        port = 1024;
+        _type = "reverseProxy";
+        headers = null;
+      };
+      authWith = "tailscale";
+      enableHttp = false;
+    };
+  };
+  neitherServiceOrRoutes = {
+    "calibre.clicks.codes" = {
+      routes = null;
+      dnsProvider = "cloudflare";
+      service = null;
+      authWith = "tailscale";
+      enableHttp = false;
+    };
+  };
+in {
+  testAssertTailscaleAuthServiceOnlyFail = {
+    /* This is NOT considered a step, here we test that it passes through input */
+    expr = lib.clicks.nginx.http.internal.assertTailscaleAuthServiceOnly tailscaleAuthWithRoute;
+    expectedError = {
+      type = "ThrownError";
+      msg = "calibre.clicks.codes: You may not use tailscale auth when manually specifying `routes`. Please use `service` instead";
+    };
+  };
+  testAssertExactlyOneOServiceOrRoutesBothProvidedFail = {
+    expr = lib.clicks.nginx.http.internal.assertExactlyOneOfServiceOrRoutes serviceAndRoutes;
+    expectedError = {
+      type = "ThrownError";
+      msg = "calibre.clicks.codes: You may only provide one of `service` or `routes`";
+    };
+  };
+  testAssertExactlyOneOfServiceOrRoutesNeitherProvidedFail = {
+    expr = lib.clicks.nginx.http.internal.assertExactlyOneOfServiceOrRoutes neitherServiceOrRoutes;
+    expectedError = {
+      type = "ThrownError";
+      msg = "calibre.clicks.codes: You must provide one of `service` or `routes`";
+    };
+  };
+}