nix: run the forge on one host per swarm (deploy.forgejo.enable)
Every hive with hyperhive enabled ran its own hive-forge container, and its gateway answered forge.<swarm> with its own bridge IP, so on a multi-host swarm each hive talked to its own forge. deploy.forgejo.enable defaults to false and allSwarmServices sets it with mkDefault, like authelia and bao; singleHostSwarm gets it through that. The forge's OIDC client moves to a glue module gated on authelia, so a split authelia/forge swarm still registers it. CI now requires the forge on the same host, and the controller's forgeTokenFile defaults to null where the forge is not. Closes #4705 Refs #3782
This commit is contained in:
parent
21c17772b8
commit
978164dc53
15 changed files with 346 additions and 84 deletions
|
|
@ -105,8 +105,9 @@ let
|
|||
in
|
||||
{
|
||||
# Private Forgejo in a `hive-forge` nixos-container, shared host
|
||||
# netns. Agents reach it at `forge.<domain>` via the gateway. State
|
||||
# at `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives
|
||||
# netns, on the one host with `deploy.forgejo.enable`. Agents reach it
|
||||
# at `forge.<domain>` via the gateway. State at
|
||||
# `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives
|
||||
# restart. See `docs/networking/gateway.md::hive-forge container shape`.
|
||||
|
||||
# External Forgejo/Gitea/Codeberg-compatible forges (beyond the mandatory
|
||||
|
|
@ -138,10 +139,10 @@ in
|
|||
'')
|
||||
];
|
||||
|
||||
# The internal forge is mandatory — it's the canonical store for the
|
||||
# meta flake + every agent's config repo (and the `internal/*` repos),
|
||||
# so there is no enable/disable toggle. It deploys whenever hyperhive
|
||||
# itself is enabled (`services.hyperhive.enable`).
|
||||
# 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;
|
||||
|
|
@ -252,8 +253,8 @@ in
|
|||
};
|
||||
|
||||
# The swarm's authelia is always registered as an OpenID Connect
|
||||
# login source here — there is no toggle, for the same reason the
|
||||
# forge itself has none.
|
||||
# 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
|
||||
|
|
@ -270,6 +271,29 @@ 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
|
||||
{option}`services.hyperhive.deploy.forgejo.behindGateway` and
|
||||
the gateway's `httpsPort`, which are per-host. An authelia host
|
||||
that is not the forge's host renders the forge's callback only
|
||||
if the two agree on them; 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` — see the block below.
|
||||
};
|
||||
|
|
@ -435,7 +459,7 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.services.hyperhive.enable {
|
||||
config = lib.mkIf (config.services.hyperhive.enable && deployCfg.forgejo.enable) {
|
||||
# Same principle as the vhost below — this service's own surface lives
|
||||
# with the service. The SSO source is named alongside forgejo because
|
||||
# its failure mode is a login that silently falls back, not an error.
|
||||
|
|
@ -1194,20 +1218,10 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
# One declaration, two readers. The forge knows its own callback URL;
|
||||
# making the operator restate it in authelia's client list would be a
|
||||
# second source of truth for a string whose mismatch is a silent
|
||||
# rejected login.
|
||||
services.hyperhive.swarm.authelia.oidc.clients = lib.mkIf ssoLocal [
|
||||
{
|
||||
id = cfg.sso.clientId;
|
||||
description = "HyperHive forge";
|
||||
redirectUris = [ ssoRedirectUri ];
|
||||
}
|
||||
];
|
||||
|
||||
# Same case, same reasoning: this host minted the secret, so it can
|
||||
# say where the forge will find it.
|
||||
# The client this login source authenticates as is registered by
|
||||
# ../glue-forge-oidc-client.nix, wherever authelia runs. When authelia
|
||||
# is here too, this host minted the secret, so it can say where the
|
||||
# forge will find it.
|
||||
services.hyperhive.deploy.forgejo.sso.clientSecretFile = lib.mkIf ssoLocal (
|
||||
lib.mkDefault forgeSecretPath
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue