Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/hive-matrix-service.nix
atlas 16ccdb55fe nix: finish the "moved to" comment sweep
State where `enable` and the matrix name pins are now rather than where
they moved from: swarm-grafana-service, swarm-nats-service,
hive-matrix-service (and the bao-controller fixture comment quoting it),
plus the same-shaped history in agent-modules/otel, checks and
docs/default. Comments and option-description text only; no script
string changes. Refs #3902
2026-10-05 09:59:02 +02:00

208 lines
9.5 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 matrix homeserver as every hive sees it: the name it mints ids
# under, the ports and URLs it is reached on, its encryption policy and the
# OIDC client id it is registered under, identical on every host. What the
# host running it decides, and the container itself, are in ./hive-matrix.nix.
{
lib,
config,
...
}:
let
cfg = config.services.hyperhive.swarm.matrix;
swarmDomain = config.services.hyperhive.swarm.domain;
in
{
options.services.hyperhive.swarm.matrix = {
serverName = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "chat.example.org";
description = ''
Matrix `server_name` — the host part of every user ID
(`@argus:<server_name>`) and room ID minted on this
homeserver. CRITICAL: must be stable from day one because
it's embedded irrevocably in the identifiers.
Defaults to `services.hyperhive.swarm.domain` (the bare swarm
domain), because **a swarm runs one homeserver** — tying its
identity to a single hive's domain would make relocating the
container between hives look like a different homeserver.
Combined with the `.well-known/matrix/{client,server}` routes
the gateway serves at that domain, clients auto-discover the
actual matrix endpoint without needing a subdomain. Override
here only if you need a different server_name shape (e.g.
`chat.example.org` for a bespoke hostname).
**Changing this cannot be undone by rebuilding.** The default
is the swarm domain, so a homeserver that minted ids under
another value (`matrix.''${services.hyperhive.domain}` or the
bare hive domain) must pin that value, e.g.
```nix
services.hyperhive.swarm.matrix.serverName =
config.services.hyperhive.domain; # or "matrix.''${…domain}"
```
before rebuilding. Adopting a new `server_name` does not rename
the old users and rooms — it strands them, because their ids
still name a homeserver that no longer answers.
'';
};
httpPort = lib.mkOption {
type = lib.types.port;
default = 8008;
description = ''
TCP port tuwunel serves the matrix client-server API on.
Default 8008 is the matrix-spec well-known port. Sits
outside hyperhive's claimed ranges (dashboard 7000, every
agent in 8100..8999 via FNV-1a hash). Federation listens on
`federationPort` separately.
'';
};
apiUrl = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = if cfg.gatewayHost == null then null else "https://${cfg.gatewayHost}";
defaultText = lib.literalExpression ''
if services.hyperhive.swarm.matrix.gatewayHost == null then null
else "https://''${services.hyperhive.swarm.matrix.gatewayHost}"
'';
example = "https://matrix.example.com";
description = ''
Client-server API base URL **hive-c0re itself** uses to
provision matrix (register agent users, create the hive space
and chat room, invite members). Distinct from the agent-facing
`hyperhive.matrix.url`, which is the gateway vhost handed to
each agent's `hive-matrix-daemon`.
Defaults to `https://` on the homeserver's gateway vhost
(`gatewayHost`), the same name on every hive whichever host runs
tuwunel, and `null` when there is no vhost. hive-c0re logs in
with the hive's matrix sender token over this URL, so it crosses
the network whenever hive-c0re is not on the homeserver's host:
an `http://` value sends that token in cleartext. hive-c0re
verifies the gateway's certificate against the hive trust bundle
(system CAs plus the swarm and services roots).
`null` means hive-c0re has no homeserver to provision against
and matrix provisioning no-ops. There is deliberately no
fallback compiled into the daemon: an address baked into the
binary is one that builds fine and then talks to the wrong
machine.
'';
};
gatewayHost = lib.mkOption {
type = lib.types.nullOr lib.types.str;
# `chat.` under the SWARM domain — both halves change: a swarm runs
# one homeserver, and the label follows the service rather than the
# protocol.
#
# 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 "chat.invalid" else "chat.${swarmDomain}";
defaultText = lib.literalExpression ''"chat.''${services.hyperhive.swarm.domain}"'';
example = "matrix.example.com";
description = ''
Public hostname for the matrix homeserver behind the gateway.
Defaults to `chat.''${services.hyperhive.swarm.domain}` — the
swarm's domain, because a swarm runs **one** homeserver. Set to
`null` to skip the gateway vhost (tuwunel stays direct on
`httpPort`). See `docs/networking/gateway.md` for the vhost map + matrix
discovery flow, and the federation port-8448 caveat at the
bottom of that doc.
⚠️ **`gatewayHost` and `serverName` are different things, and
they carry very different costs.** `gatewayHost` is the API
listener hostname (where nginx proxies `/_matrix/*`) and is
free to change: it is a routing detail clients rediscover
through `.well-known`. `serverName` is the matrix-identifier
domain embedded **irrevocably** in every user and room id —
adopting a new one is a different homeserver, not a rename.
Both defaults sit under the swarm domain, but only this
one is safe to change on a running deployment.
To use the per-hive name `matrix.''${services.hyperhive.domain}`
instead, pin it here.
'';
};
allowEncryption = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Server-side switch for matrix end-to-end encryption — sets
tuwunel's `allow_encryption`. Off by default: on the hive-internal
homeserver the operator already controls the transport, so server
E2EE adds key-management overhead (cross-signing, device
verification, undecryptable-message recovery) without a clear
threat-model win for the common single-hive case. Turn on when
agents join encrypted rooms on external / federated homeservers,
or when the operator wants message contents opaque to the
homeserver admin. Independent of the agent matrix client, which
always supports decryption so it can read encrypted rooms it is
invited to regardless of this flag; this option only governs
whether THIS homeserver permits room encryption.
'';
};
# This homeserver always delegates login to the swarm's authelia, as
# an OIDC relying party — matrix SSO (`m.login.sso`), offered
# alongside password login. No toggle: a homeserver in a swarm is a
# client of that swarm's identity provider.
#
# ⚠️ Not to be confused with tuwunel's `oidc_*` settings, which point
# the other way: those make this homeserver an *authorization server*
# for matrix clients. This family makes it a *client* of an external
# identity provider. The two share the protocol's name and answer
# opposite questions.
#
# This **adds** a way in. Password login keeps working: an identity
# provider that can take the homeserver offline when it hiccups is a
# worse homeserver than one with two ways in — which is also what
# makes always-on safe. Making authelia the *only* path is a
# separate, reversible switch (tuwunel's `login_with_password`),
# deliberately not folded in here.
#
# ⚠️ Matrix SSO lives **inside** the homeserver, never behind a
# forward-auth proxy: the client-server API is spoken by non-browser
# clients holding matrix access tokens — every agent's own
# `hive-matrix-daemon` — plus federation, and a proxy in front of
# `/_matrix/` breaks all of it.
sso = {
clientId = lib.mkOption {
type = lib.types.str;
default = "tuwunel";
description = ''
OAuth2 client id this homeserver identifies itself with. The host
running authelia registers it, whichever host runs the homeserver.
The homeserver's host reads the secret it pairs with out of the
swarm secret store, into
`services.hyperhive.deploy.matrix.sso.clientSecretFile`.
'';
};
redirectUri = lib.mkOption {
type = lib.types.nullOr lib.types.str;
readOnly = true;
default =
if cfg.gatewayHost == null then
null
else
"https://${cfg.gatewayHost}/_matrix/client/unstable/login/sso/callback/${cfg.sso.clientId}";
defaultText = lib.literalExpression ''"https://''${services.hyperhive.swarm.matrix.gatewayHost}/_matrix/client/unstable/login/sso/callback/''${services.hyperhive.swarm.matrix.sso.clientId}"'';
description = ''
SSO callback authelia sends the browser back to, and the URI it
matches **exactly**. Format-locked by tuwunel: the callback host
must point directly at the homeserver, and the path is fixed.
Read-only: the homeserver's config and its authelia client entry
both read it from here. `null` when `gatewayHost` is, because the
homeserver then has no name a browser can reach.
'';
};
};
};
}