From 584c99ce13a71fa71aa33175438e53d0c687a4ee Mon Sep 17 00:00:00 2001 From: atlas Date: Mon, 31 Aug 2026 18:15:49 +0200 Subject: [PATCH] hive-forge: allow the swarm domain through forgejo's webhook SSRF list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `webhook.ALLOWED_HOST_LIST` named `external` plus the HIVE domain. The swarm-controller's webhooks target the SWARM domain, which is a different host on the same private gateway IP — so `external` denied it and the hive entry did not cover it. Every swarm-controller delivery has been failing there. Found from the sender's log, which names the host and the rule it broke: deny 'constellation.darkest.space(10.42.0.1:443)' webhook can only call allowed HTTP servers (check your webhook.ALLOWED_HOST_LIST setting) This is the layer under the DNS fix: resolution now succeeds and reaches 10.42.0.1:443, and forgejo refuses to dial it. The two failures look identical from the receiving end — no delivery, no log line — which is why reading the sender was what separated them. `optional` because a hive with no swarm has no such domain; `unique` because an all-local deployment can legitimately set both to the same string. --- nix/host-modules/hive-forge/default.nix | 27 ++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/nix/host-modules/hive-forge/default.nix b/nix/host-modules/hive-forge/default.nix index b36cfb45..790658fa 100644 --- a/nix/host-modules/hive-forge/default.nix +++ b/nix/host-modules/hive-forge/default.nix @@ -818,7 +818,32 @@ in # `external` alone would deny (so they'd only ever be caught by # the 5-min poll fallback). Naming the single gateway host is # tighter than the broad `private` builtin. - webhook.ALLOWED_HOST_LIST = "external,${hyperhiveDomain}"; + # + # ⚠️ The SWARM domain is on this list too, and leaving it off is + # what made every swarm-controller delivery fail. Those webhooks + # target `https:///webhook/forge/*` — a different + # host from the hive's, resolving to the same private gateway IP, + # so `external` denies it and the hive entry does not cover it. + # Measured from the sender's own log, which names both the host + # and the rule: + # + # deny 'constellation.darkest.space(10.42.0.1:443)' + # webhook can only call allowed HTTP servers + # (check your webhook.ALLOWED_HOST_LIST setting) + # + # `optional` because a hive with no swarm has no such domain, and + # `unique` because an all-local deployment can legitimately set + # both to the same string — a duplicate entry is harmless to + # forgejo but reads as a mistake. + webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," ( + lib.unique ( + [ + "external" + hyperhiveDomain + ] + ++ lib.optional (swarmDomain != null) swarmDomain + ) + ); log.LEVEL = "Warn"; # Pinned explicitly rather than left to upstream's default # (currently `bleve`, a separate full-text index Forgejo