Compare commits

...
Author SHA1 Message Date
atlas
0d23896dbb fix(nix): the rename lives with the module that declares the options
mara: "remove the extra deprecatios file, less comments". The alias now
sits in hive-forge/default.nix next to the options it renames, and the
comment is three lines instead of eighteen.

Better than tidier: there is no shared file for the sibling migrations
to queue behind. Matrix's rename goes in hive-matrix.nix, authelia's in
its own module, and none of them touch each other. hive-ci.nix declares
swarm.forge.ci.* from a different module and stays covered, because the
rename is on the namespace rather than on the declaring file.

Re-ran the check both ways this time, per argus on the last round: old
paths set and new paths read back 3999 / 7, and a config that only uses
the new paths produces no warnings at all.
2026-08-05 03:44:53 +02:00
atlas
f7beea3a6f fix(nix): rename the forge attrset, not fifteen leaves
mara on the PR: "why deprecate individual keys instead of the whole
attrset? there is no hyperhive.forge anymore after the move". Right, and
mkRenamedOptionModule takes the namespace path directly - the subtree
comes with it, nested ci.* included.

Fifteen explicit renames collapse to one. The list was also a
liability: an option added under swarm.forge later would have needed
remembering here to get an alias, so it could silently fall behind the
options it mirrors.

Re-ran both evals against the new form. Values still map (httpPort 3999,
ci.concurrency 7 through the old paths) and the warning still fires; it
now names the attrset rather than the leaf, which also means one warning
per hive instead of one per option an operator had set.
2026-08-05 03:44:53 +02:00
atlas
38c222fadd feat(nix): move the forge host options under services.hyperhive.swarm
Forgejo is a swarm-global service, so its operator-facing host options
move to services.hyperhive.swarm.forge (and .swarm.forge.ci) as the
first of the namespace consolidation.

Existing hive configs keep evaluating: swarm-renames.nix maps every
moved leaf with mkRenamedOptionModule, which also emits a deprecation
warning naming both the old and new path, so an operator is told what to
rename rather than discovering it from a failed eval.

The per-agent hyperhive.forge.url does NOT move. It is a client pointer
at whatever forge an agent talks to - it shares a word with the service
and nothing else, and the two are already documented as separate option
surfaces.

Verified by evaluating the host module, since no Rust gate evaluates
nix: setting the old paths and reading the new ones yields the values
(httpPort 3999, ci.concurrency 7), and config.warnings carries the
rename notice.
2026-08-05 03:44:53 +02:00
6 changed files with 35 additions and 24 deletions

View file

@ -153,7 +153,8 @@ let
- [host options](host.md) options exposed by
`hyperhive.nixosModules.default` to operator host configurations
(`services.hyperhive.{enable,domain,c0re,forge,matrix,gateway}.*`).
(`services.hyperhive.{enable,domain,c0re,gateway}.*`,
`services.hyperhive.swarm.{forge,matrix}.*`).
- [per-agent options](agent.md) options declared in
`nix/agent-modules/`, visible from every `agent.nix`
(`hyperhive.model`, `hyperhive.allowedRecipients`,

View file

@ -31,7 +31,7 @@ let
safeDirGitconfig = pkgs.writeText "hyperhive-safe-gitconfig" ''
[safe]
directory = *
[credential "http://${config.services.hyperhive.forge.domain}"]
[credential "http://${config.services.hyperhive.swarm.forge.domain}"]
helper = hive-forge
username = core
[http]

View file

@ -98,7 +98,7 @@ in
# agents via meta.rs for their forge-notify client. The forge is
# mandatory, so this is unconditional (the whole env block is already
# gated on hyperhive being enabled). See `docs/gateway.md::HIVE_FORGE_URL`.
HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}";
HIVE_FORGE_URL = "http://${config.services.hyperhive.swarm.forge.domain}";
}
//
lib.optionalAttrs
@ -147,17 +147,17 @@ in
# dashboard doesn't need to learn the gateway is unconditional.
HIVE_GATEWAY_ENABLED = "1";
}
// lib.optionalAttrs (config.services.hyperhive.forge.publicUrl != null) {
// lib.optionalAttrs (config.services.hyperhive.swarm.forge.publicUrl != null) {
# Public URL of the forge, for the dashboard to build browser-facing
# forge links from instead of guessing `<hostname>:3000` (which
# breaks the moment the operator's browser hostname isn't the forge
# host, e.g. through the gateway or a reverse proxy). Sourced from
# `services.hyperhive.forge.publicUrl`, which itself defaults to the
# `services.hyperhive.swarm.forge.publicUrl`, which itself defaults to the
# gateway vhost URL when `behindGateway = true` and `null` otherwise
# — see that option's doc for the "hide, don't guess" rationale.
# Absent here whenever `publicUrl` is `null`; the dashboard hides
# forge links rather than emitting one it can't justify.
HIVE_FORGE_PUBLIC_URL = config.services.hyperhive.forge.publicUrl;
HIVE_FORGE_PUBLIC_URL = config.services.hyperhive.swarm.forge.publicUrl;
}
//
lib.optionalAttrs

View file

@ -5,8 +5,8 @@
...
}:
let
cfg = config.services.hyperhive.forge.ci;
forgeCfg = config.services.hyperhive.forge;
cfg = config.services.hyperhive.swarm.forge.ci;
forgeCfg = config.services.hyperhive.swarm.forge;
gatewayCfg = config.services.hyperhive.gateway;
networkCfg = config.services.hyperhive.network;
tlsCfg = config.services.hyperhive.tls;
@ -52,14 +52,14 @@ in
# nspawn containers can't create the user-namespaces that nix sandboxing
# requires. See docs/gotchas.md.
options.services.hyperhive.forge.ci = {
options.services.hyperhive.swarm.forge.ci = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = ''
Run a Forgejo Actions runner in a `hive-ci` nixos-container.
Grouped under `services.hyperhive.forge` because the runner is
Grouped under `services.hyperhive.swarm.forge` because the runner is
tightly coupled to the forge instance it registers against.
Disabled by default; the internal forge it registers against is
always present (mandatory), so enabling this is all that's needed.
@ -142,8 +142,8 @@ in
{
assertion = forgeCfg.behindGateway;
message = ''
services.hyperhive.forge.ci.enable requires
services.hyperhive.forge.behindGateway = true.
services.hyperhive.swarm.forge.ci.enable requires
services.hyperhive.swarm.forge.behindGateway = true.
The CI container runs with a private network namespace and
reaches the forge through the gateway vhost on the bridge IP.
Set behindGateway = true (it defaults to true alongside

View file

@ -5,7 +5,7 @@
...
}:
let
cfg = config.services.hyperhive.forge;
cfg = config.services.hyperhive.swarm.forge;
gatewayCfg = config.services.hyperhive.gateway;
hyperhiveDomain = config.services.hyperhive.domain;
tlsCfg = config.services.hyperhive.tls;
@ -53,7 +53,7 @@ let
# blip otherwise reds every `actions/checkout@vN` fetch from
# data.forgejo.org). Auto-append a pull-mirror of it and point
# forgejo's DEFAULT_ACTIONS_URL at this instance so `uses:` resolves local.
ciEnabled = config.services.hyperhive.forge.ci.enable;
ciEnabled = config.services.hyperhive.swarm.forge.ci.enable;
actionCheckoutMirror = {
upstream = "https://github.com/actions/checkout";
dest = "actions/checkout";
@ -82,11 +82,21 @@ in
# (base URL), the same shape as the GitHub PAT / matrix extra-account
# flows. See `hive-c0re/src/dashboard/extra_forges.rs`.
# Forge moved under `swarm` when the swarm-global services were
# consolidated. One rename for the 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" ]
)
];
# 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`).
options.services.hyperhive.forge = {
options.services.hyperhive.swarm.forge = {
httpPort = lib.mkOption {
type = lib.types.port;
default = 3000;
@ -244,7 +254,7 @@ in
**Breaking change**: this used to default to `true`. If you
relied on the old default for external reach, add
`services.hyperhive.forge.openFirewall = true;` to your host
`services.hyperhive.swarm.forge.openFirewall = true;` to your host
config before rebuilding.
'';
};
@ -283,7 +293,7 @@ in
so a host-resolver blip leaves a *stale* mirror, never a hard
failure on whatever reads it.
When `services.hyperhive.forge.ci.enable` is set, an
When `services.hyperhive.swarm.forge.ci.enable` is set, an
`actions/checkout` mirror is auto-appended to this list and
forgejo's `DEFAULT_ACTIONS_URL` is pointed at this instance, so CI
`uses: actions/checkout@vN` steps resolve entirely on loopback with
@ -298,7 +308,7 @@ in
{
assertion = cfg.rootUrl == null || lib.hasSuffix "/" cfg.rootUrl;
message = ''
services.hyperhive.forge.rootUrl must end with "/". forgejo's
services.hyperhive.swarm.forge.rootUrl must end with "/". forgejo's
ROOT_URL contract requires a trailing slash for correct
relative-link generation; without it forgejo emits URLs like
`https://forge.example.com.user.id` instead of
@ -313,7 +323,7 @@ in
# loud.
assertion = cfg.domain != "";
message = ''
services.hyperhive.forge.domain = "" is rejected. The
services.hyperhive.swarm.forge.domain = "" is rejected. The
rendered URLs would be invalid (nginx wildcard catch-all
for an empty server_name, /etc/hosts rejects empty entries).
Either leave at default (auto-derives to
@ -326,7 +336,7 @@ in
# splits on the single slash to create the org + repo.
assertion = lib.all (m: lib.length (lib.splitString "/" m.dest) == 2) effectiveMirrors;
message = ''
Every services.hyperhive.forge.mirrors[].dest must be exactly
Every services.hyperhive.swarm.forge.mirrors[].dest must be exactly
"<owner>/<repo>" (one slash). Got: ${lib.concatMapStringsSep ", " (m: m.dest) effectiveMirrors}
'';
}
@ -344,7 +354,7 @@ in
])
) effectiveMirrors;
message = ''
services.hyperhive.forge.mirrors[].dest must not place a mirror
services.hyperhive.swarm.forge.mirrors[].dest must not place a mirror
in a hive-c0re-managed org (config / shared / agents / core)
those are provisioned by hive-c0re and a mirror there would
collide. Use a dedicated org (e.g. "actions/checkout").

View file

@ -16,7 +16,7 @@ let
cfg = config.services.hyperhive.gateway;
hyperhiveDomain = config.services.hyperhive.domain;
matrixCfg = config.services.hyperhive.matrix;
forgeCfg = config.services.hyperhive.forge;
forgeCfg = config.services.hyperhive.swarm.forge;
networkCfg = config.services.hyperhive.network;
# Dashboard SPA dist, static-served by nginx. Read in OUTER scope so
@ -411,8 +411,8 @@ in
networking.hosts = lib.mkIf cfg.localHostsEntry {
"127.0.0.1" = lib.unique (
[ hyperhiveDomain ]
++ lib.optional (config.services.hyperhive.forge.behindGateway or false
) config.services.hyperhive.forge.domain
++ lib.optional (config.services.hyperhive.swarm.forge.behindGateway or false
) config.services.hyperhive.swarm.forge.domain
++ lib.optional (matrixCfg.enable && matrixCfg.gatewayHost != null) matrixCfg.gatewayHost
);
};