nix/hive-forge: reject subdomain="" with assertion (argus #754 v2 🟡)

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.
This commit is contained in:
atlas 2026-05-31 13:29:22 +02:00 committed by mara
commit de67002c94

View file

@ -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.<hive-domain>`; 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 `.<hive-domain>` 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 ".<hive-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 = {