hive-forge: read the webhook host from the option the target is built from
`swarm.domain` is not the value swarm-controller addresses this hive with — `swarm-controller.nix` builds `SWARM_CONTROLLER_PUBLIC_URL` from `swarm.ui.domain`, which merely defaults to it and is documented as overridable. Allowing the one and being delivered the other would work until someone takes that option up, then fail as a refused delivery with nothing naming the cause. Also states why the entry is NOT gated on `deploy.swarm-ui.enable`, which is what makes the controller register the hooks at all: in a spread deployment the forge and the swarm UI are different hosts, so that per-host flag is false exactly where the allow-list entry is needed. The comment-block lint caught the prose at 35 lines; trimmed to the parts a reader cannot re-derive.
This commit is contained in:
parent
584c99ce13
commit
b9919164e4
1 changed files with 29 additions and 25 deletions
|
|
@ -9,6 +9,13 @@ let
|
||||||
gatewayCfg = config.services.hyperhive.gateway;
|
gatewayCfg = config.services.hyperhive.gateway;
|
||||||
hyperhiveDomain = config.services.hyperhive.domain;
|
hyperhiveDomain = config.services.hyperhive.domain;
|
||||||
swarmDomain = config.services.hyperhive.swarm.domain;
|
swarmDomain = config.services.hyperhive.swarm.domain;
|
||||||
|
# The host the swarm-controller's webhooks actually target. NOT
|
||||||
|
# `swarm.domain`: `swarm-controller.nix` builds `SWARM_CONTROLLER_PUBLIC_URL`
|
||||||
|
# from `swarm.ui.domain`, which merely *defaults* to the swarm domain and is
|
||||||
|
# documented as overridable. Reading the other one would be right until
|
||||||
|
# someone takes that option up, and then wrong in a way whose only symptom is
|
||||||
|
# a refused delivery.
|
||||||
|
swarmUiDomain = config.services.hyperhive.swarm.ui.domain;
|
||||||
tlsCfg = config.services.hyperhive.deploy.hive-controller.tls;
|
tlsCfg = config.services.hyperhive.deploy.hive-controller.tls;
|
||||||
networkCfg = config.services.hyperhive.network;
|
networkCfg = config.services.hyperhive.network;
|
||||||
|
|
||||||
|
|
@ -807,41 +814,38 @@ in
|
||||||
# forge.darkest.space, etc.) were failing every sync
|
# forge.darkest.space, etc.) were failing every sync
|
||||||
# attempt without this.
|
# attempt without this.
|
||||||
migrations.ALLOWED_DOMAINS = "*";
|
migrations.ALLOWED_DOMAINS = "*";
|
||||||
# `ALLOWED_HOST_LIST` is forgejo's webhook SSRF allow-list, and
|
# `ALLOWED_HOST_LIST` is forgejo's webhook SSRF allow-list: a
|
||||||
# it's a STRICT whitelist (only listed hosts deliver). Its
|
# STRICT whitelist whose `external` builtin allows public unicast
|
||||||
# default is the `external` builtin: all public unicast IPs are
|
# IPs and denies private/loopback. `external` STAYS so user-repo
|
||||||
# allowed, private/loopback denied. We must KEEP `external` so
|
# webhooks to github/slack keep working; the hyperhive hosts are
|
||||||
# user-repo webhooks to public hosts (github, slack, …) keep
|
# added on top, because their webhooks target a private (RFC-1918)
|
||||||
# working, and ADD the hive gateway host on top: the config-PR +
|
# gateway IP `external` alone denies — naming the two hosts is
|
||||||
# knowledge webhooks target `https://<hyperhive domain>/webhook/*`,
|
|
||||||
# which resolves to a private (RFC-1918) gateway IP that
|
|
||||||
# `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.
|
# tighter than the broad `private` builtin.
|
||||||
#
|
#
|
||||||
# ⚠️ The SWARM domain is on this list too, and leaving it off is
|
# TWO hosts, not one. The hive's carries the config-PR + knowledge
|
||||||
# what made every swarm-controller delivery fail. Those webhooks
|
# hooks; the swarm's carries swarm-controller's, and leaving it
|
||||||
# target `https://<swarm domain>/webhook/forge/*` — a different
|
# off denied every one of those:
|
||||||
# host from the hive's, resolving to the same private gateway IP,
|
# deny '<swarm host>(10.42.0.1:443)' — webhook can only call
|
||||||
# so `external` denies it and the hive entry does not cover it.
|
# allowed HTTP servers
|
||||||
# Measured from the sender's own log, which names both the host
|
|
||||||
# and the rule:
|
|
||||||
#
|
#
|
||||||
# deny 'constellation.darkest.space(10.42.0.1:443)'
|
# ⚠️ `swarm.ui.domain`, NOT `swarm.domain`: swarm-controller.nix
|
||||||
# webhook can only call allowed HTTP servers
|
# builds its `SWARM_CONTROLLER_PUBLIC_URL` from the former, which
|
||||||
# (check your webhook.ALLOWED_HOST_LIST setting)
|
# only *defaults* to the latter and is documented as overridable.
|
||||||
#
|
#
|
||||||
# `optional` because a hive with no swarm has no such domain, and
|
# Not gated on `deploy.swarm-ui.enable`, even though that is what
|
||||||
# `unique` because an all-local deployment can legitimately set
|
# makes the controller register the hooks: in a spread deployment
|
||||||
# both to the same string — a duplicate entry is harmless to
|
# the forge and the UI are different hosts, so that per-host flag
|
||||||
# forgejo but reads as a mistake.
|
# is false exactly where this entry is needed.
|
||||||
|
#
|
||||||
|
# `unique` because an all-local swarm legitimately serves both
|
||||||
|
# from one name.
|
||||||
webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," (
|
webhook.ALLOWED_HOST_LIST = lib.concatStringsSep "," (
|
||||||
lib.unique (
|
lib.unique (
|
||||||
[
|
[
|
||||||
"external"
|
"external"
|
||||||
hyperhiveDomain
|
hyperhiveDomain
|
||||||
]
|
]
|
||||||
++ lib.optional (swarmDomain != null) swarmDomain
|
++ lib.optional (swarmDomain != null) swarmUiDomain
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
log.LEVEL = "Warn";
|
log.LEVEL = "Warn";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue