feat(#1867): make the internal forge mandatory (remove forge.enable)
The internal forge is the canonical store for the meta flake, every agent's config repo, and the internal/* repos, so it can no longer be optional. Remove the services.hyperhive.forge.enable toggle: - hive-forge.nix: drop the `enable` option; the forge config now deploys gated on `services.hyperhive.enable` (it ships with hyperhive). - hive-c0re.nix: HIVE_FORGE_URL env unconditional; forge-public-URL gate drops the enable check (keeps behindGateway). - hive-gateway.nix: local /etc/hosts forge entry keyed on behindGateway. - hive-ci.nix: drop the now-moot `forge.ci.enable requires forge.enable` assertion (forge is always present); reword the option doc. - nix/docs/default.nix: drop the `forge.enable = mkForce false` stub (option gone); the options-doc eval stays light via hyperhive.enable. - hive-c0re forge.rs / hivectl.rs: reword 'forge.enable = true' error text to 'wait for hive-c0re to start the container' (the runtime token-absent path is unchanged — it's a bootstrap-timing check, not the opt-out). - docs/approvals.md, docs/ci.md: drop stale forge.enable references. Migration: configs that set `services.hyperhive.forge.enable = false` must drop the line — the forge is now mandatory. Prereq/companion to #1838 (PR-based config flow, which assumes the forge is always present).
This commit is contained in:
parent
c091d8a4b5
commit
2b4e928afe
9 changed files with 37 additions and 58 deletions
|
|
@ -358,10 +358,9 @@ queue but skip the approval row plumbing.
|
||||||
|
|
||||||
### Forge mirror
|
### Forge mirror
|
||||||
|
|
||||||
When the bundled `hive-forge` container is running — on by
|
The bundled `hive-forge` container is mandatory (it deploys with
|
||||||
default, `hyperhive.forge.enable` — hive-c0re mirrors every
|
hyperhive), and hive-c0re mirrors every agent's applied repo into a
|
||||||
agent's applied repo into a private `agent-configs` Forgejo
|
private `agent-configs` Forgejo org. `forge::push_config(<name>)` pushes `applied/main` plus
|
||||||
org. `forge::push_config(<name>)` pushes `applied/main` plus
|
|
||||||
every tag to `agent-configs/<name>` after each ref mutation:
|
every tag to `agent-configs/<name>` after each ref mutation:
|
||||||
the spawn that seeds `deployed/0`, every `request_apply_commit`
|
the spawn that seeds `deployed/0`, every `request_apply_commit`
|
||||||
(which plants `proposal/<id>`), every approve / deny, and a
|
(which plants `proposal/<id>`), every approve / deny, and a
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ The `hive-ci` module runs a Forgejo Actions runner in a `hive-ci` nixos-containe
|
||||||
Set `services.hyperhive.forge.ci.enable = true` in the host NixOS config. That's it — no manual token provisioning.
|
Set `services.hyperhive.forge.ci.enable = true` in the host NixOS config. That's it — no manual token provisioning.
|
||||||
|
|
||||||
**Requirements:**
|
**Requirements:**
|
||||||
- `services.hyperhive.forge.enable = true` must also be set (the runner registers against hive-forge).
|
- The internal forge is always present (mandatory), so the runner always has a hive-forge instance to register against — nothing extra to enable.
|
||||||
- Optional: tune `services.hyperhive.forge.ci.name` (runner name in forge admin panel), `concurrency` (parallel job capacity), `labels` (workflow targeting), `jobTimeout` (per-job wall-clock cap, default `"1h"`, Go duration string e.g. `"3h"` — a job that exceeds it is killed so a hung or runaway build can't hold the runner's single slot indefinitely).
|
- Optional: tune `services.hyperhive.forge.ci.name` (runner name in forge admin panel), `concurrency` (parallel job capacity), `labels` (workflow targeting), `jobTimeout` (per-job wall-clock cap, default `"1h"`, Go duration string e.g. `"3h"` — a job that exceeds it is killed so a hung or runaway build can't hold the runner's single slot indefinitely).
|
||||||
|
|
||||||
## Container design
|
## Container design
|
||||||
|
|
|
||||||
|
|
@ -1019,7 +1019,7 @@ fn choom(name: &str, fresh: bool) -> Result<()> {
|
||||||
async fn forge_create_user(name: &str, password: Option<&str>, password_stdin: bool) -> Result<()> {
|
async fn forge_create_user(name: &str, password: Option<&str>, password_stdin: bool) -> Result<()> {
|
||||||
if !hive_c0re::forge::is_present().await {
|
if !hive_c0re::forge::is_present().await {
|
||||||
bail!(
|
bail!(
|
||||||
"hive-forge container not running — start it (services.hyperhive.forge.enable = true) before provisioning forge users"
|
"hive-forge container not running — wait for hive-c0re to start it before provisioning forge users"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let user_password = resolve_password(password, password_stdin)?;
|
let user_password = resolve_password(password, password_stdin)?;
|
||||||
|
|
|
||||||
|
|
@ -407,7 +407,7 @@ pub async fn ensure_user_for(name: &str) -> Result<()> {
|
||||||
pub async fn provision_user_token(name: &str, password: Option<&str>) -> Result<String> {
|
pub async fn provision_user_token(name: &str, password: Option<&str>) -> Result<String> {
|
||||||
if !is_present().await {
|
if !is_present().await {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"hive-forge container not running — start it (services.hyperhive.forge.enable = true) before provisioning forge users"
|
"hive-forge container not running — wait for hive-c0re to start it before provisioning forge users"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ensure_user_exists(name, false, password).await?;
|
ensure_user_exists(name, false, password).await?;
|
||||||
|
|
@ -661,7 +661,7 @@ pub fn core_token() -> Option<String> {
|
||||||
|
|
||||||
/// Push `dir` (the meta repo) to `core/meta` on the local forge.
|
/// Push `dir` (the meta repo) to `core/meta` on the local forge.
|
||||||
/// Best-effort: returns Err which callers log + ignore. No-op when
|
/// Best-effort: returns Err which callers log + ignore. No-op when
|
||||||
/// the core token isn't present (forge not enabled).
|
/// the core token isn't present yet (forge container not provisioned).
|
||||||
pub async fn push_meta(dir: &Path) -> Result<()> {
|
pub async fn push_meta(dir: &Path) -> Result<()> {
|
||||||
let Some(token) = core_token() else {
|
let Some(token) = core_token() else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ let
|
||||||
boot.loader.grub.enable = false;
|
boot.loader.grub.enable = false;
|
||||||
system.stateVersion = "25.11";
|
system.stateVersion = "25.11";
|
||||||
services.hyperhive.enable = lib.mkForce false;
|
services.hyperhive.enable = lib.mkForce false;
|
||||||
services.hyperhive.forge.enable = lib.mkForce false;
|
|
||||||
services.hyperhive.matrix.enable = lib.mkForce false;
|
services.hyperhive.matrix.enable = lib.mkForce false;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -109,11 +109,11 @@ let
|
||||||
if stylixThemeColors != null then themedFrontend stylixThemeColors else cfg.frontend;
|
if stylixThemeColors != null then themedFrontend stylixThemeColors else cfg.frontend;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# The forge is part of the standard install — hive-c0re mirrors
|
# The forge is mandatory — hive-c0re mirrors every agent's applied
|
||||||
# every agent's applied config repo into it. On by default; opt out
|
# config repo into it and it's the canonical store for the meta flake
|
||||||
# with `services.hyperhive.forge.enable = false`. hive-matrix is
|
# + `internal/*` repos, so there's no enable toggle; it deploys with
|
||||||
# opt-in (off by default) and asserts that `services.hyperhive.domain`
|
# hyperhive itself. hive-matrix is opt-in (off by default) and asserts
|
||||||
# is set before it can be enabled.
|
# that `services.hyperhive.domain` is set before it can be enabled.
|
||||||
imports = [
|
imports = [
|
||||||
./hive-ci.nix
|
./hive-ci.nix
|
||||||
./hive-forge.nix
|
./hive-forge.nix
|
||||||
|
|
@ -790,10 +790,11 @@ in
|
||||||
// lib.optionalAttrs (config.services.hyperhive.swarmName != null) {
|
// lib.optionalAttrs (config.services.hyperhive.swarmName != null) {
|
||||||
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName;
|
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarmName;
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs config.services.hyperhive.forge.enable {
|
// {
|
||||||
# In-cluster forge URL — the gateway vhost (`forge.<domain>`), which
|
# In-cluster forge URL — the gateway vhost (`forge.<domain>`), which
|
||||||
# nginx proxies to forgejo. Set directly: this env only exists when
|
# nginx proxies to forgejo. The forge is mandatory, so this is
|
||||||
# hyperhive is enabled. See `docs/gateway.md::HIVE_FORGE_URL`.
|
# 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.forge.domain}";
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs config.services.hyperhive.matrix.enable {
|
// lib.optionalAttrs config.services.hyperhive.matrix.enable {
|
||||||
|
|
@ -823,10 +824,7 @@ in
|
||||||
# dashboard doesn't need to learn the gateway is unconditional.
|
# dashboard doesn't need to learn the gateway is unconditional.
|
||||||
HIVE_GATEWAY_ENABLED = "1";
|
HIVE_GATEWAY_ENABLED = "1";
|
||||||
}
|
}
|
||||||
//
|
// lib.optionalAttrs config.services.hyperhive.forge.behindGateway {
|
||||||
lib.optionalAttrs
|
|
||||||
(config.services.hyperhive.forge.enable && config.services.hyperhive.forge.behindGateway)
|
|
||||||
{
|
|
||||||
# Public URL of the forge vhost served by hive-gateway. The
|
# Public URL of the forge vhost served by hive-gateway. The
|
||||||
# dashboard uses this to build browser-facing forge links
|
# dashboard uses this to build browser-facing forge links
|
||||||
# instead of hardcoding `<hostname>:3000`, which breaks when
|
# instead of hardcoding `<hostname>:3000`, which breaks when
|
||||||
|
|
|
||||||
|
|
@ -193,8 +193,8 @@ in
|
||||||
Run a Forgejo Actions runner in a `hive-ci` nixos-container.
|
Run a Forgejo Actions runner in a `hive-ci` nixos-container.
|
||||||
Grouped under `services.hyperhive.forge` because the runner is
|
Grouped under `services.hyperhive.forge` because the runner is
|
||||||
tightly coupled to the forge instance it registers against.
|
tightly coupled to the forge instance it registers against.
|
||||||
Disabled by default; `services.hyperhive.forge.enable = true` is
|
Disabled by default; the internal forge it registers against is
|
||||||
a prerequisite (enforced by assertion).
|
always present (mandatory), so enabling this is all that's needed.
|
||||||
|
|
||||||
On first start the container auto-registers against hive-forge using
|
On first start the container auto-registers against hive-forge using
|
||||||
hive-c0re's admin token — no manual token provisioning needed.
|
hive-c0re's admin token — no manual token provisioning needed.
|
||||||
|
|
@ -265,16 +265,9 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
assertions = [
|
# No forge-presence assertion needed: the internal forge is mandatory
|
||||||
{
|
# (deploys with hyperhive), so the runner always has an instance to
|
||||||
assertion = forgeCfg.enable;
|
# register against.
|
||||||
message = ''
|
|
||||||
services.hyperhive.forge.ci.enable = true requires
|
|
||||||
services.hyperhive.forge.enable = true — the runner registers
|
|
||||||
against the hive-forge Forgejo instance.
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
# Create /run/hive-ci/ on the host and seed runner-token with a
|
# Create /run/hive-ci/ on the host and seed runner-token with a
|
||||||
# placeholder. hive-ci-prefetch.service overwrites it with the real
|
# placeholder. hive-ci-prefetch.service overwrites it with the real
|
||||||
|
|
|
||||||
|
|
@ -41,19 +41,11 @@ in
|
||||||
# `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives
|
# `/var/lib/nixos-containers/hive-forge/var/lib/forgejo/` survives
|
||||||
# restart. See `docs/gateway.md::hive-forge container shape`.
|
# restart. See `docs/gateway.md::hive-forge container shape`.
|
||||||
|
|
||||||
|
# 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.forge = {
|
||||||
enable = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Run hive-forge — a private Forgejo (in a nixos-container) for
|
|
||||||
hyperhive agents. On by default: hive-c0re mirrors every
|
|
||||||
agent's applied config repo into the forge's `agent-configs`
|
|
||||||
org, so the forge is part of the standard install. Set
|
|
||||||
`services.hyperhive.forge.enable = false` to opt out.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
httpPort = lib.mkOption {
|
httpPort = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
default = 3000;
|
default = 3000;
|
||||||
|
|
@ -192,7 +184,7 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf config.services.hyperhive.enable {
|
||||||
assertions = [
|
assertions = [
|
||||||
{
|
{
|
||||||
assertion = cfg.rootUrl == null || lib.hasSuffix "/" cfg.rootUrl;
|
assertion = cfg.rootUrl == null || lib.hasSuffix "/" cfg.rootUrl;
|
||||||
|
|
|
||||||
|
|
@ -1019,9 +1019,7 @@ in
|
||||||
networking.hosts = lib.mkIf (cfg.localHostsEntry && hyperhiveDomain != null) {
|
networking.hosts = lib.mkIf (cfg.localHostsEntry && hyperhiveDomain != null) {
|
||||||
"127.0.0.1" = lib.unique (
|
"127.0.0.1" = lib.unique (
|
||||||
[ hyperhiveDomain ]
|
[ hyperhiveDomain ]
|
||||||
++ lib.optional (
|
++ lib.optional (config.services.hyperhive.forge.behindGateway or false
|
||||||
(config.services.hyperhive.forge.enable or false)
|
|
||||||
&& (config.services.hyperhive.forge.behindGateway or false)
|
|
||||||
) config.services.hyperhive.forge.domain
|
) config.services.hyperhive.forge.domain
|
||||||
++ lib.optional (matrixCfg.enable && matrixCfg.gatewayHost != null) matrixCfg.gatewayHost
|
++ lib.optional (matrixCfg.enable && matrixCfg.gatewayHost != null) matrixCfg.gatewayHost
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue