Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/hive-forge/service.nix
atlas e990e9a0be nix: finish the current-behaviour comment sweep in touched files
Rewrite the remaining narration in files the previous commit touched:
"moved"/"sat"/"was REMOVED"/"old default" comments in swarm-bao,
swarm-otel, glue-bao-tls, nats-authelia, swarm-controller, swarm-ui,
swarm-otel-service, swarm-authelia-service, the deploy.nix rename table,
hive-ci, hive-forge/service, hive-tls, hyperhive, swarm-nats, swarm.nix
and a few module-eval fixtures, so each says where a thing is or why it
is so now.

Revert the comment edits inside shell script strings in hive-tls,
swarm-nats and the forge token mint to their previous text, so those
generated units are unchanged. The only unit still changing is
swarm-bao-pki (two comment lines in its script). Refs #3902
2026-10-05 09:58:57 +02:00

195 lines
8.2 KiB
Nix
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# The swarm's forge as every hive sees it: the names and ports it answers on,
# the URLs it advertises, and the OIDC client it is registered as. What the
# host running it decides, and the container itself, are in ./default.nix.
{
lib,
config,
...
}:
let
cfg = config.services.hyperhive.swarm.forge;
gatewayCfg = config.services.hyperhive.gateway;
swarmDomain = config.services.hyperhive.swarm.domain;
# Forgejo's name for the login source. Duplicated in ./default.nix, which
# registers the source under it.
ssoSourceName = "authelia";
# Forgejo's OAuth2 callback shape. `ssoSourceName` and `effectiveRootUrl`
# must equal their copies in ./default.nix: a mismatch is a rejected login
# with no error text worth reading.
ssoRedirectUri = "${effectiveRootUrl}user/oauth2/${ssoSourceName}/callback";
# Forgejo's `ROOT_URL`, duplicated from ./default.nix, which documents its
# shape.
defaultRootUrl =
let
portSuffix = if gatewayCfg.httpsPort == 443 then "" else ":${toString gatewayCfg.httpsPort}";
in
"https://${cfg.domain}${portSuffix}/";
effectiveRootUrl = if cfg.rootUrl != null then cfg.rootUrl else defaultRootUrl;
in
{
# Forge lives under `swarm`, beside the other swarm-global services. One
# rename for the top-level `services.hyperhive.forge` namespace: the
# subtree comes with it, so existing hives keep evaluating and get one
# warning naming both paths.
imports = [
(lib.mkRenamedOptionModule
[ "services" "hyperhive" "forge" ]
[ "services" "hyperhive" "swarm" "forge" ]
)
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "forge" "sso" "enable" ] ''
SSO is no longer optional: the forge always registers the swarm's
authelia as a login source.
Removed rather than defaulted to true so a config that turned it
OFF fails here, where the line is, instead of silently gaining a
login provider on the next rebuild. Drop the line; if it was
false, set services.hyperhive.deploy.forgejo.sso.clientSecretFile and
services.hyperhive.swarm.authelia.url as the assertions describe.
'')
];
# Every swarm needs this forge — it's the canonical store for the meta
# flake + every agent's config repo (and the `internal/*` repos) — but
# only one host runs it: `deploy.forgejo.enable`, in ../deploy.nix. What
# follows is what every hive needs to reach it, wherever it runs.
options.services.hyperhive.swarm.forge = {
httpPort = lib.mkOption {
type = lib.types.port;
default = 3000;
description = ''
TCP port the forge serves HTTP on. Default 3000 sits outside
hyperhive's claimed ranges (dashboard 7000, every agent in
8100..8999 via FNV-1a hash). Change this if you already have
another forgejo bound to 3000.
'';
};
sshPort = lib.mkOption {
type = lib.types.port;
default = 2222;
description = ''
TCP port the forge's built-in SSH server listens on. Kept off
22 so it doesn't clash with the host's openssh. Agents push
with `ssh -p <sshPort> git@<domain>:<owner>/<repo>.git`.
'';
};
domain = lib.mkOption {
type = lib.types.str;
# Under the SWARM domain, not this hive's: a swarm runs one forge
# and every hive in it reaches the same host, so the name belongs
# to the swarm rather than to whichever hive happens to run it.
#
# Total on a null swarm domain so the required-domain assertion in
# hive-network.nix is the thing that fires; see the comment there.
default = if swarmDomain == null then "forge.invalid" else "forge.${swarmDomain}";
defaultText = lib.literalExpression ''"forge.''${services.hyperhive.swarm.domain}"'';
example = "git.example.com";
description = ''
Public hostname for the forge. Doubles as both the forgejo
`DOMAIN` setting (clone URLs forgejo advertises) AND the
gateway vhost server-name (sub-domain routing — see
`docs/networking/gateway.md`).
Defaults to `forge.''${services.hyperhive.swarm.domain}` — the
swarm's domain, not this hive's, because a swarm runs **one**
forge that every hive in it talks to.
⚠️ To use the per-hive name `forge.''${services.hyperhive.domain}`
instead, pin it here. Certificates follow either way: the
swarm-services sub-CA is name-constrained to the configured
names (see `./swarm-ca.nix`), not to a fixed tree.
Set to a full hostname (`git.example.com`,
`forge.internal.lan`, etc.) for a bespoke vhost shape — the
full domain goes here, no separate sub-domain-label option.
'';
};
publicUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = "https://${cfg.domain}";
defaultText = lib.literalExpression ''"https://''${domain}"'';
example = "https://forge.example.com";
description = ''
Browser-facing forge URL the dashboard uses to build clickable
forge links (the H0M3 Forge tile, per-agent-row forge links) —
sourced into every agent container + hive-c0re as
`HIVE_FORGE_PUBLIC_URL`.
Defaults to `https://''${cfg.domain}`, the gateway vhost. When
`null`, the dashboard **hides** forge links rather than
guessing one — see `docs/web-ui/dashboard.md::H0M3 page` for
the rationale (a link built from the operator's own browser
hostname + a container port is only an accident away from
wrong on any deployment that isn't plain localhost).
'';
};
rootUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "https://forge.example.com/";
description = ''
Override the auto-derived forgejo `ROOT_URL`. When `null`
(default), `ROOT_URL` is `https://''${cfg.domain}/`. The gateway
always terminates TLS (self-signed is the implicit floor when no
`gateway.tls.certDir` / ACME is set), so the forge is always
advertised over https. A non-canonical `gateway.httpsPort` is
appended as `:<port>`.
Set this only for a genuinely bespoke shape (e.g. an external
reverse proxy on a different host/path). Must end with `/` per
forgejo's `ROOT_URL` contract.
'';
};
# The swarm's authelia is always registered as an OpenID Connect
# login source here — there is no toggle: a forge without it has no
# way to log a person in through the swarm's SSO.
#
# **Additive, never exclusive.** Forgejo keeps its local password
# database and gains an extra "sign in with" button; this does not
# disable local login. Deliberate: an identity provider that can take
# the forge offline when it hiccups is a worse forge than one with
# two ways in — which is also what makes always-on safe.
sso = {
clientId = lib.mkOption {
type = lib.types.str;
default = "forgejo";
description = ''
OAuth2 client id this forge identifies itself with. Must match
the `id` of the corresponding entry in
`services.hyperhive.swarm.authelia.oidc.clients`.
'';
};
redirectUri = lib.mkOption {
type = lib.types.str;
readOnly = true;
default = ssoRedirectUri;
defaultText = lib.literalExpression ''"''${ROOT_URL}user/oauth2/authelia/callback"'';
description = ''
OAuth2 callback authelia sends the browser back to, and the URI
it matches **exactly**.
Read-only: forgejo derives it from its own `ROOT_URL` and the
login source's name, so it is a fact other modules read rather
than a knob. The glue that registers this client wherever
authelia runs reads it from here instead of restating the
format.
⚠️ With {option}`services.hyperhive.swarm.forge.rootUrl` unset,
`ROOT_URL` follows the gateway's `httpsPort`, which is
per-host. An authelia host that is not the forge's host renders
the forge's callback only if the two agree on it; set `rootUrl`
if they do not.
'';
};
# The secret half is a path on the host that runs the forge, so it
# lives under `deploy.forgejo.sso`, in ./default.nix.
};
};
}