From a8bc0842629a3d015532a81f1b0ae79c23a11bfa Mon Sep 17 00:00:00 2001 From: atlas Date: Tue, 18 Aug 2026 00:26:56 +0200 Subject: [PATCH] feat(#3255): expose the controller's webhook endpoint through the swarm vhost A forge webhook is a machine POST carrying an HMAC and no session cookie, so it cannot pass the authelia auth-request subrequest every other location on this vhost uses. This location deliberately omits it; the HMAC check in the controller is what guards the path. Scoped to /webhook/forge/ rather than /webhook/ so a future endpoint under the same prefix does not inherit the bypass. --- nix/host-modules/swarm-ui.nix | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/nix/host-modules/swarm-ui.nix b/nix/host-modules/swarm-ui.nix index 62096f90..9f1b08f5 100644 --- a/nix/host-modules/swarm-ui.nix +++ b/nix/host-modules/swarm-ui.nix @@ -188,6 +188,27 @@ in proxyPass = "http://unix:${controllerCfg.socketPath}:"; extraConfig = swarmAuthRequest; }; + # ⚠️ THE ONE LOCATION ON THIS VHOST WITH NO `swarmAuthRequest`, + # and that is deliberate rather than an omission. + # + # A forge webhook is a machine POST carrying an HMAC signature + # and no session cookie. An authelia auth-request subrequest + # authenticates a *browser session*; there is nothing here for it + # to check, so guarding this location would not make it safer, it + # would make it permanently unreachable. + # + # What replaces it: swarm-controller verifies the + # `X-Hub-Signature-256` HMAC over the raw body before looking at + # anything else, and answers 401 on any mismatch. That check is + # the access control for this path — see the `webhook` module. + # + # Scoped to `/webhook/forge/` rather than `/webhook/` so the + # carve-out is exactly as wide as the endpoint that justifies it: + # a future `/webhook/` does not inherit the + # bypass by living under a shared prefix. + "/webhook/forge/" = { + proxyPass = "http://unix:${controllerCfg.socketPath}:"; + }; # Swagger UI: same "nginx hosts the themed dist straight from # the store, only /api/openapi.json is dynamic" shape as the # per-hive gateway's `swaggerUiLocations`.