chore: scrub issue/PR cookies from gateway + network nix modules and gateway_nginx.rs

This commit is contained in:
atlas 2026-05-31 23:08:07 +02:00 committed by mara
commit d45b2f0293
3 changed files with 30 additions and 35 deletions

View file

@ -10,7 +10,7 @@
//! switch` needed when agents start, stop, or flip `useUnixSocket`. //! switch` needed when agents start, stop, or flip `useUnixSocket`.
//! (A path unit inside the container was tried first but `IN_MOVED_TO` //! (A path unit inside the container was tried first but `IN_MOVED_TO`
//! from the atomic rename does not cross the nspawn mount-namespace //! from the atomic rename does not cross the nspawn mount-namespace
//! boundary — see #889 for the failure analysis.) //! boundary — see `docs/gateway.md` for the failure analysis.)
//! //!
//! Upstream selection mirrors `agent_sockets::build_map`: an agent //! Upstream selection mirrors `agent_sockets::build_map`: an agent
//! gets a UDS upstream when its `.bound` marker exists (harness has //! gets a UDS upstream when its `.bound` marker exists (harness has
@ -40,8 +40,7 @@ const HOST_CONF_PATH: &str = "/var/lib/hyperhive/gateway/agents.conf";
/// (not the whole parent dir) at `/run/hive-state/` so nginx inside /// (not the whole parent dir) at `/run/hive-state/` so nginx inside
/// can read it at `/run/hive-state/agents.conf`. Subdirectory scoping /// can read it at `/run/hive-state/agents.conf`. Subdirectory scoping
/// avoids exposing the rest of `/var/lib/hyperhive/` (which may contain /// avoids exposing the rest of `/var/lib/hyperhive/` (which may contain
/// forge tokens or other credentials) to the gateway container (argus 🟡 /// forge tokens or other credentials) to the gateway container.
/// on #872).
#[must_use] #[must_use]
pub fn host_conf_path() -> PathBuf { pub fn host_conf_path() -> PathBuf {
PathBuf::from(HOST_CONF_PATH) PathBuf::from(HOST_CONF_PATH)
@ -119,7 +118,7 @@ fn render(names: &[String]) -> String {
/// inside the container watching the bind-mounted file: `IN_MOVED_TO` /// inside the container watching the bind-mounted file: `IN_MOVED_TO`
/// (fired by the atomic rename) does not reliably propagate across the /// (fired by the atomic rename) does not reliably propagate across the
/// nspawn mount-namespace boundary, so the path-unit approach was /// nspawn mount-namespace boundary, so the path-unit approach was
/// silently broken after #872 merged (#889). /// silently broken (see `docs/gateway.md` for the failure analysis).
/// ///
/// The `systemd-run` call is best-effort — a failed reload is logged /// The `systemd-run` call is best-effort — a failed reload is logged
/// but not fatal. nginx will pick up the new include on its next /// but not fatal. nginx will pick up the new include on its next

View file

@ -11,8 +11,8 @@ let
forgeCfg = config.services.hyperhive.forge; forgeCfg = config.services.hyperhive.forge;
networkCfg = config.services.hyperhive.network; networkCfg = config.services.hyperhive.network;
# Static error pages for `/agent/<name>/` mishaps (#755). Mara's # Static error pages for `/agent/<name>/` mishaps.
# call: useful pages instead of nginx's default 404/502 for routes # Useful pages of nginx's default 404/502 for routes
# we've already special-cased. See `docs/gateway.md::Per-agent # we've already special-cased. See `docs/gateway.md::Per-agent
# error pages` for the design rationale + page-vs-status semantics. # error pages` for the design rationale + page-vs-status semantics.
agentErrorPagesDir = pkgs.runCommand "hyperhive-agent-error-pages" { } '' agentErrorPagesDir = pkgs.runCommand "hyperhive-agent-error-pages" { } ''
@ -127,8 +127,8 @@ in
default = false; default = false;
example = true; example = true;
description = '' description = ''
Open `port` in the host firewall. Off by default (#651, Open `port` in the host firewall. Off by default (secure-by-default).
secure-by-default). Flip to `true` to expose the gateway to Flip to `true` to expose the gateway to
the operator's browser / external clients required for any the operator's browser / external clients required for any
out-of-host reach, since the agents themselves talk to out-of-host reach, since the agents themselves talk to
hive-c0re via the per-agent unix sockets and don't need the hive-c0re via the per-agent unix sockets and don't need the
@ -136,11 +136,9 @@ in
proxy (e.g. caddy / traefik on the host) that handles TLS proxy (e.g. caddy / traefik on the host) that handles TLS
termination + forwards to `port`. termination + forwards to `port`.
**Breaking change as of #651**: this used to default to **Note**: this used to default to `true`. Add
`true`. If you relied on the old default for external reach `services.hyperhive.gateway.openFirewall = true;` to your host
(the common case the gateway is the operator's primary config if external reach stopped working after a recent upgrade.
entry point), add `services.hyperhive.gateway.openFirewall = true;`
to your host config before rebuilding.
''; '';
}; };
@ -171,7 +169,7 @@ in
FluffyChat + several other Matrix clients) hardcodes FluffyChat + several other Matrix clients) hardcodes
`https://<host>/.well-known/matrix/client` for homeserver `https://<host>/.well-known/matrix/client` for homeserver
discovery and refuses to fall back to plain http without discovery and refuses to fall back to plain http without
TLS the browser client just won't connect (#837). TLS the browser client just won't connect.
Self-signed means browsers will show a "not secure" warning Self-signed means browsers will show a "not secure" warning
on first visit; the operator clicks through once per on first visit; the operator clicks through once per
@ -216,7 +214,7 @@ in
# Ensure bind-mount sources exist at host boot before the gateway # Ensure bind-mount sources exist at host boot before the gateway
# container's first start. nspawn would auto-create missing dirs # container's first start. nspawn would auto-create missing dirs
# (argus 🟡 on #829), but tmpfiles rules make the intent explicit # tmpfiles rules make the intent explicit
# and cover the fresh-boot window before c0re has run. # and cover the fresh-boot window before c0re has run.
# #
# /run/hive-agent — per-agent UDS socket dir, written by c0re's # /run/hive-agent — per-agent UDS socket dir, written by c0re's
@ -241,7 +239,7 @@ in
# layer that matters. # layer that matters.
privateNetwork = false; privateNetwork = false;
# Bind-mount the per-agent socket dir so nginx inside the gateway # Bind-mount the per-agent socket dir so nginx inside the gateway
# container can `connect(2)` to the UDS upstreams (#784 step 3). # container can `connect(2)` to the UDS upstreams.
# Read-only (we just connect; harness writes the socket inside # Read-only (we just connect; harness writes the socket inside
# the agent's own container). Host-side dir is pre-created by a # the agent's own container). Host-side dir is pre-created by a
# tmpfiles rule so nspawn always finds a source at boot. # tmpfiles rule so nspawn always finds a source at boot.
@ -304,7 +302,7 @@ in
# spec compliance) — 443 elides the port. Otherwise fall back # spec compliance) — 443 elides the port. Otherwise fall back
# to the plain-http listen with the bare port. See # to the plain-http listen with the bare port. See
# `docs/gateway.md` ("Self-signed TLS"). Shared at this scope # `docs/gateway.md` ("Self-signed TLS"). Shared at this scope
# (was inlined twice, argus 🟡 on #848). # Shared to avoid repetition.
publicScheme = if cfg.selfSignedTls then "https" else "http"; publicScheme = if cfg.selfSignedTls then "https" else "http";
publicPort = if cfg.selfSignedTls then cfg.httpsPort else cfg.port; publicPort = if cfg.selfSignedTls then cfg.httpsPort else cfg.port;
publicPortDefault = if cfg.selfSignedTls then 443 else 80; publicPortDefault = if cfg.selfSignedTls then 443 else 80;
@ -393,16 +391,16 @@ in
# via `systemd-run --machine=hive-gateway nginx -s reload` # via `systemd-run --machine=hive-gateway nginx -s reload`
# after each agents.conf write. A path unit watching the # after each agents.conf write. A path unit watching the
# bind-mounted file inside the container was tried first # bind-mounted file inside the container was tried first
# (in #872) but IN_MOVED_TO from an atomic rename on the host # (A path unit inside the container was tried but IN_MOVED_TO from an atomic rename on the host
# does not propagate across the nspawn mount-namespace boundary, # does not propagate across the nspawn mount-namespace boundary,
# so the watcher never fired (#889). Host-side trigger is the # does not cross the mount-namespace boundary. Host-side trigger is the
# correct approach. # correct approach.
services.nginx = { services.nginx = {
enable = true; enable = true;
recommendedProxySettings = true; recommendedProxySettings = true;
recommendedOptimisation = true; recommendedOptimisation = true;
# Accept-header SPA fallback (#686 / #729): navigations # Accept-header SPA fallback: navigations
# (`Accept: text/html,...`) fall to index.html, asset # (`Accept: text/html,...`) fall to index.html, asset
# fetches (Accept *anything else*) fall to a sentinel # fetches (Accept *anything else*) fall to a sentinel
# nonexistent path → `try_files` returns 404. Pattern # nonexistent path → `try_files` returns 404. Pattern
@ -418,7 +416,7 @@ in
listen = vhostListen; listen = vhostListen;
locations = locations =
# `<hive>/matrix/*` → 301 → `matrix.<hive>/$1` # `<hive>/matrix/*` → 301 → `matrix.<hive>/$1`
# (fluffychat moved to sub-domain root in #772; this # (fluffychat moved to sub-domain root; this
# keeps bookmarks + deep-links working during the # keeps bookmarks + deep-links working during the
# transition). See `docs/gateway.md` for the vhost # transition). See `docs/gateway.md` for the vhost
# map. # map.
@ -471,7 +469,7 @@ in
} }
) )
// //
# `/agent/` catch-all (#755): hits when an operator # `/agent/` catch-all: hits when an operator
# requests `/agent/<unknown>/...`. Without this the # requests `/agent/<unknown>/...`. Without this the
# request falls through to `/` (c0re dashboard) and # request falls through to `/` (c0re dashboard) and
# returns 404 with no useful context. Custom 404 # returns 404 with no useful context. Custom 404
@ -537,7 +535,7 @@ in
}; };
} }
// //
# Forge sub-domain vhost (#749 / #754). `server_name = # Forge sub-domain vhost. `server_name =
# forge.domain`, proxies all `/` → forgejo. Tuned for # forge.domain`, proxies all `/` → forgejo. Tuned for
# git: `client_max_body_size 1G`, `proxy_read_timeout 1h` # git: `client_max_body_size 1G`, `proxy_read_timeout 1h`
# (multi-GB clones). SSH stays direct on `forge.sshPort`. # (multi-GB clones). SSH stays direct on `forge.sshPort`.
@ -558,10 +556,10 @@ in
}; };
} }
// //
# Matrix sub-domain vhost (#747 / #764). `server_name = # Matrix sub-domain vhost. `server_name =
# matrixCfg.gatewayHost`. `/_matrix/*` → tuwunel (CORS *, # matrixCfg.gatewayHost`. `/_matrix/*` → tuwunel (CORS *,
# 50M body cap, 1h long-poll timeout). `/` serves # 50M body cap, 1h long-poll timeout). `/` serves
# fluffychat (#772) or 404 if GUI off. nginx # fluffychat or 404 if GUI off. nginx
# longer-prefix-wins puts `/_matrix/` ahead of `/`. # longer-prefix-wins puts `/_matrix/` ahead of `/`.
# See `docs/gateway.md`. # See `docs/gateway.md`.
lib.optionalAttrs (matrixCfg.enable && matrixCfg.gatewayHost != null) { lib.optionalAttrs (matrixCfg.enable && matrixCfg.gatewayHost != null) {
@ -594,7 +592,7 @@ in
// lib.optionalAttrs (hyperhiveDomain != null) { // lib.optionalAttrs (hyperhiveDomain != null) {
# FluffyChat boot-config pre-fill so the client's # FluffyChat boot-config pre-fill so the client's
# `.well-known/matrix/client` lookup hits the # `.well-known/matrix/client` lookup hits the
# right delegation endpoint (#736). # right delegation endpoint.
"= /config.json" = { "= /config.json" = {
extraConfig = '' extraConfig = ''
default_type application/json; default_type application/json;
@ -612,8 +610,8 @@ in
}; };
}; };
# Hive-internal DNS resolver (#805 v1). Co-located in the # Hive-internal DNS resolver, co-located in the
# gateway container per mara's call (#805:10957) — single # gateway container — single
# front-door for both DNS and HTTP, saves a sibling # front-door for both DNS and HTTP, saves a sibling
# container. Listens on the bridge interface from # container. Listens on the bridge interface from
# `services.hyperhive.network`; authoritative for the hive # `services.hyperhive.network`; authoritative for the hive
@ -651,7 +649,7 @@ in
# common case where `forge.domain` / # common case where `forge.domain` /
# `matrix.gatewayHost` are sub-domains of # `matrix.gatewayHost` are sub-domains of
# `hyperhive.domain` — dnsmasq's `/<domain>/` rule # `hyperhive.domain` — dnsmasq's `/<domain>/` rule
# already matches sub-domains (argus 🟡 on #845). # already matches sub-domains.
# Kept explicit because operators can override either # Kept explicit because operators can override either
# to a cross-domain hostname (e.g. # to a cross-domain hostname (e.g.
# `forge.domain = "git.example.com"`); listing them # `forge.domain = "git.example.com"`); listing them

View file

@ -7,12 +7,10 @@ let
cfg = config.services.hyperhive.network; cfg = config.services.hyperhive.network;
in in
{ {
# Hive-internal network — host-side bridge + per-agent DNS resolver # Hive-internal network — host-side bridge + per-agent DNS resolver.
# (#805, prereq for #14 netns isolation). Containers stay on shared # Containers stay on shared host netns at v1; this module stands the
# host netns at v1 — this module just stands the bridge + resolver # bridge + resolver up so the endpoint is in place before network
# up so the endpoint is in place before #14 flips containers to # isolation flips containers to private netns. Full design: docs/network.md.
# private netns (mara on #805: "we need it before #14 so nothing
# breaks when we switch over"). Full design: docs/network.md.
options.services.hyperhive.network = { options.services.hyperhive.network = {
enable = lib.mkOption { enable = lib.mkOption {