diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index 12f96e3b..6c7b9536 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -196,6 +196,28 @@ in ''; }; + webhookAllowedHosts = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ + "ci.example.com" + "hooks.example.org" + ]; + description = '' + Extra hosts to add to forgejo's webhook SSRF allow-list + (`[webhook] ALLOWED_HOST_LIST`). The hive gateway host + (`services.hyperhive.domain`) is ALWAYS included — the config-PR + and knowledge webhooks target it, and it resolves to a private + gateway IP that forgejo's default guard would otherwise deny. + Add entries here to additionally allow webhooks from project + repos to other hosts (a user's own CI, external services, etc.). + + Entries are forgejo hostmatcher patterns: hostnames, globs, + IPs/CIDRs, or the builtins `loopback` / `private` / `external` + / `*`. + ''; + }; + openFirewall = lib.mkOption { type = lib.types.bool; default = false; @@ -423,10 +445,13 @@ in # private (RFC-1918) gateway IP. Forgejo's webhook SSRF guard # denies private hosts by default, so the config-PR + knowledge # webhooks never actually deliver — only the 5-min poll fallback - # catches config PRs. Allow the gateway host explicitly; scoping - # to the single hostname keeps the SSRF surface tighter than the - # broad `private` builtin. - webhook.ALLOWED_HOST_LIST = hyperhiveDomain; + # catches config PRs. The gateway host is always allowed (scoping + # to that one hostname keeps the SSRF surface tighter than the + # broad `private` builtin); operators extend the list via + # `forge.webhookAllowedHosts` for webhooks on their own repos. + webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," ( + [ hyperhiveDomain ] ++ cfg.webhookAllowedHosts + ); log.LEVEL = "Warn"; ui = { DEFAULT_THEME = "catppuccin-vibec0re";