nix: split hive-matrix into service and deploy-mode files
`swarm.matrix` (what the homeserver is to every hive: server name, ports, API URL, gateway host, encryption policy, OIDC client id) moves to nix/host-modules/hive-matrix-service.nix. Everything else -- the `imports` block with its two renames and the removed `sso.enable`, the `deploy.matrix` options, the whole `config` block including `containers.hive-matrix`, and every other let binding -- stays in nix/host-modules/hive-matrix.nix, which default.nix now imports alongside the new file. The `swarm.matrix` block reads three let bindings, and the `config` block reads all three too: `cfg` (`apiUrl` defaults from `cfg.httpPort`), `swarmDomain` (`gatewayHost`'s default) and `deployCfg` (`apiUrl` reads `deployCfg.matrix.enable`). All three are option reads, so each file binds them from `config.services.hyperhive.*`. Nothing is duplicated. A pure move: option paths, option definitions and config are unchanged apart from the comment above `deploy.matrix`, which now names the file `swarm.matrix` lives in. Refs #3742
This commit is contained in:
parent
4181d33cad
commit
a539dceab1
3 changed files with 195 additions and 179 deletions
|
|
@ -20,6 +20,7 @@
|
|||
./hive-ci.nix
|
||||
./hive-forge
|
||||
./hive-gateway
|
||||
./hive-matrix-service.nix
|
||||
./hive-matrix.nix
|
||||
./hive-network.nix
|
||||
./hive-priv.nix
|
||||
|
|
|
|||
191
nix/host-modules/hive-matrix-service.nix
Normal file
191
nix/host-modules/hive-matrix-service.nix
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
# 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;
|
||||
deployCfg = config.services.hyperhive.deploy;
|
||||
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).
|
||||
|
||||
**Breaking change, and the one on this page that cannot be
|
||||
undone by rebuilding.** This default has now moved twice — from
|
||||
`matrix.''${services.hyperhive.domain}`, then to the bare hive
|
||||
domain, and now to the swarm domain. Every existing homeserver
|
||||
must pin whichever value it already minted ids under, 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 deployCfg.matrix.enable then "http://127.0.0.1:${toString cfg.httpPort}" else null;
|
||||
defaultText = lib.literalExpression ''
|
||||
if services.hyperhive.deploy.matrix.enable
|
||||
then "http://127.0.0.1:''${toString services.hyperhive.swarm.matrix.httpPort}"
|
||||
else null
|
||||
'';
|
||||
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 the loopback listener **only when this module is the
|
||||
thing running tuwunel** — in that case the address is not a
|
||||
guess, it is where this module just put the container. Set it
|
||||
explicitly (with `enable = false`) when the homeserver runs on
|
||||
another machine; "everything on one host" is a special case of
|
||||
the full deployment, not the assumption.
|
||||
|
||||
`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 now sit under the swarm domain, but only this
|
||||
one is safe to move on a running deployment.
|
||||
|
||||
A deployment that was running before this moved keeps its
|
||||
current name by pinning
|
||||
`matrix.''${services.hyperhive.domain}` here — exactly what the
|
||||
old default rendered.
|
||||
'';
|
||||
};
|
||||
|
||||
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. Must
|
||||
match the `id` of the corresponding entry in
|
||||
`services.hyperhive.swarm.authelia.oidc.clients`.
|
||||
|
||||
The secret it pairs with is a host path, so it lives at
|
||||
`services.hyperhive.deploy.matrix.sso.clientSecretFile`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -406,185 +406,9 @@ 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).
|
||||
|
||||
**Breaking change, and the one on this page that cannot be
|
||||
undone by rebuilding.** This default has now moved twice — from
|
||||
`matrix.''${services.hyperhive.domain}`, then to the bare hive
|
||||
domain, and now to the swarm domain. Every existing homeserver
|
||||
must pin whichever value it already minted ids under, 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 deployCfg.matrix.enable then "http://127.0.0.1:${toString cfg.httpPort}" else null;
|
||||
defaultText = lib.literalExpression ''
|
||||
if services.hyperhive.deploy.matrix.enable
|
||||
then "http://127.0.0.1:''${toString services.hyperhive.swarm.matrix.httpPort}"
|
||||
else null
|
||||
'';
|
||||
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 the loopback listener **only when this module is the
|
||||
thing running tuwunel** — in that case the address is not a
|
||||
guess, it is where this module just put the container. Set it
|
||||
explicitly (with `enable = false`) when the homeserver runs on
|
||||
another machine; "everything on one host" is a special case of
|
||||
the full deployment, not the assumption.
|
||||
|
||||
`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 now sit under the swarm domain, but only this
|
||||
one is safe to move on a running deployment.
|
||||
|
||||
A deployment that was running before this moved keeps its
|
||||
current name by pinning
|
||||
`matrix.''${services.hyperhive.domain}` here — exactly what the
|
||||
old default rendered.
|
||||
'';
|
||||
};
|
||||
|
||||
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. Must
|
||||
match the `id` of the corresponding entry in
|
||||
`services.hyperhive.swarm.authelia.oidc.clients`.
|
||||
|
||||
The secret it pairs with is a host path, so it lives at
|
||||
`services.hyperhive.deploy.matrix.sso.clientSecretFile`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# What stays above is what the homeserver IS from any hive's point of view:
|
||||
# the name it answers to, the ports and URLs it is reached on, and the client
|
||||
# id it is registered under. What lives here is what the host running it
|
||||
# `swarm.matrix`, in ./hive-matrix-service.nix, is what the homeserver IS from
|
||||
# any hive's point of view: the name it answers to, the ports and URLs it is
|
||||
# reached on, and the client id it is registered under. What lives here is what the host running it
|
||||
# decides — which build it runs, whether it is exposed, which peers it trusts,
|
||||
# how large a request it accepts, and where its host-local secrets sit. Same rule as
|
||||
# ./swarm-victorialogs.nix; `enable` already lives in ./deploy.nix, which also
|
||||
|
|
|
|||
Loading…
Reference in a new issue