From de67002c94a798c931ca051ca39b132f1f061290 Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 31 May 2026 13:29:22 +0200 Subject: [PATCH] =?UTF-8?q?nix/hive-forge:=20reject=20subdomain=3D""=20wit?= =?UTF-8?q?h=20assertion=20(argus=20#754=20v2=20=F0=9F=9F=A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit argus on PR #754 v2 review: > `subdomain = ""` edge case: when `cfg.subdomain = ""`, the > `localHostsEntry` appends ".${domain}" (invalid hostname; bare > domain is already covered) and the virtualHosts key becomes > ".${domain}" (nginx treats this as a wildcard catch-all, not a > bare-domain server block). docs call this "advanced: collides > with dashboard server block" — the actual nginx behavior is > more surprising than that. Fix: reject `""` at assertion time rather than ship the surprising behaviour. Bare-domain landing is what the dashboard already serves; there's no use case for `""` that null doesn't already cover. Updated option description + dropped the now-dead branch from the `subdomain` let-binding. Verified: `services.hyperhive.forge.subdomain = ""` triggers the new assertion at toplevel build with a clear message pointing at `null` as the right opt-out. Default + `null` paths still build clean. --- nix/modules/hive-forge.nix | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/nix/modules/hive-forge.nix b/nix/modules/hive-forge.nix index 9a2b0c18..9be03593 100644 --- a/nix/modules/hive-forge.nix +++ b/nix/modules/hive-forge.nix @@ -12,9 +12,10 @@ let # Sub-domain forgejo lives at when served behind the gateway (#749, # mara verdict at issue:9609 — sub-domain over sub-path). Defaults # to `forge.`; set to `null` to opt out of subdomain - # routing (forge stays direct on `cfg.httpPort`). + # routing (forge stays direct on `cfg.httpPort`). Empty string is + # rejected at assertion time. subdomain = - if cfg.subdomain == null then null else if cfg.subdomain == "" then hyperhiveDomain else "${cfg.subdomain}.${hyperhiveDomain}"; + if cfg.subdomain == null then null else "${cfg.subdomain}.${hyperhiveDomain}"; # ROOT_URL forgejo advertises in clone links + outbound URLs. When # served behind the gateway (#749), use the sub-domain so generated @@ -124,8 +125,11 @@ in Defaults to `"forge"` (→ `forge.''${hyperhive.domain}`). Set to `null` to opt out — forge stays direct on `httpPort`, - no gateway vhost. Set to the empty string `""` for a bare-domain - landing (advanced: collides with the dashboard server block). + no gateway vhost. Empty-string `""` is rejected (would render + `.''${hyperhive.domain}` — nginx treats that as a wildcard + catch-all, not a bare-domain server block, so the behaviour + is surprising; bare-domain landing is what the dashboard + already serves anyway). Requires `services.hyperhive.domain` to be set. Requires `services.hyperhive.gateway.enable = true` for the vhost to @@ -207,6 +211,21 @@ in out of sub-domain routing. ''; } + { + # `subdomain = ""` would render `.` as both the + # nginx server_name (treated as wildcard catch-all, surprising) + # and the /etc/hosts entry (invalid hostname). argus 🟡 on + # #754 v2 — fail loud here rather than ship the surprising + # behaviour. + assertion = cfg.subdomain != ""; + message = '' + services.hyperhive.forge.subdomain = "" is rejected: the + rendered sub-domain "." is invalid (nginx + treats it as a wildcard catch-all, /etc/hosts rejects it). + Use `null` to opt out of sub-domain routing entirely, or + set a non-empty label like "forge" or "git". + ''; + } ]; containers.hive-forge = {