hive-forge: allow the swarm domain through forgejo's webhook SSRF list

`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.
This commit is contained in:
atlas 2026-08-31 18:15:49 +02:00
commit 584c99ce13

View file

@ -818,7 +818,32 @@ in
# `external` alone would deny (so they'd only ever be caught by # `external` alone would deny (so they'd only ever be caught by
# the 5-min poll fallback). Naming the single gateway host is # the 5-min poll fallback). Naming the single gateway host is
# tighter than the broad `private` builtin. # 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://<swarm domain>/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"; log.LEVEL = "Warn";
# Pinned explicitly rather than left to upstream's default # Pinned explicitly rather than left to upstream's default
# (currently `bleve`, a separate full-text index Forgejo # (currently `bleve`, a separate full-text index Forgejo