Prose-only sweep of every remaining claim that nginx or dnsmasq lives in a container: the port comment (root in a container -> root on the host), upstreamHost's netns rationale, the ACME state dir, the store path reachability note, the vhost tree header, dnsmasq's resolv.conf paragraph (there is no copy and no path unit watching it any more), the two hive-network bridge comments, and swarm-controller's socket access-control note, which described a bind-mount that no longer exists. No behaviour change; all of it was describing a mechanism that was deleted.
219 lines
10 KiB
Nix
219 lines
10 KiB
Nix
# Environment of the hive-c0re daemon unit — a plain function file
|
|
# (not a module) returning the env attrset, imported by ./default.nix.
|
|
# Everything meta.rs forwards into agent containers or reads for the
|
|
# meta-flake render is assembled here.
|
|
{
|
|
lib,
|
|
config,
|
|
pkgs,
|
|
}:
|
|
let
|
|
cfg = config.services.hyperhive.c0re;
|
|
in
|
|
{
|
|
# nix (the prebuild `nix build`, flake-check, and meta eval) writes
|
|
# its fetcher/eval cache under $HOME/.cache. As a system user
|
|
# hive-core has no home, so HOME defaults to the unwritable
|
|
# /var/empty and Lix fails to initialise its cache. Point HOME at
|
|
# the writable StateDirectory.
|
|
HOME = "/var/lib/hyperhive";
|
|
HYPERHIVE_GIT = "${pkgs.git}/bin/git";
|
|
# Never let git block on an interactive credential prompt. hive-core is a
|
|
# TTY-less system user, so a prompt (e.g. the forge credential helper
|
|
# returns nothing because the forge isn't reachable yet on cold boot)
|
|
# would hang forever — this is what froze the whole daemon during startup
|
|
# migration's `nix flake lock` of the forge-hosted config inputs. With
|
|
# this set, git fails fast instead of prompting. Paired with the git http
|
|
# low-speed abort in `safeDirGitconfig` (bounds a stalled transfer) and
|
|
# the 120s migration shellout timeout in migrate.rs.
|
|
GIT_TERMINAL_PROMPT = "0";
|
|
# No HIVE_STATIC_DIR: the gateway static-serves the dashboard dist
|
|
# (see the hive-gateway module); this router is API-only.
|
|
# Path to the base agent frontend dist. hive-c0re's
|
|
# gateway_nginx.rs uses this to generate split location
|
|
# blocks in agents.conf — static HTML/CSS/JS served from the
|
|
# nix store directly; dynamic API paths still proxied to the
|
|
# agent daemon. nginx runs on the host, which is where this
|
|
# store path already is, so it is reachable as written.
|
|
HIVE_AGENT_FRONTEND_DIR = "${cfg.servedFrontend}/agent";
|
|
# Path to the static runtime asset tree (branding + claude
|
|
# prompts). `hive_sh4re::assets::*` reads paths underneath.
|
|
# `forge/users.rs` reads the core avatar PNG from here on startup.
|
|
HIVE_ASSETS_DIR = "${cfg.assets}/share/hyperhive";
|
|
# `agent-configs` org avatar PNG — independently overridable via
|
|
# `orgAvatarPng` without replacing the whole `assets` package.
|
|
# Falls back to the bundled PNG under HIVE_ASSETS_DIR when unset.
|
|
# Read by `forge::users::config_org_avatar_png_path`.
|
|
HIVE_ORG_AVATAR_PNG =
|
|
if cfg.orgAvatarPng != null then
|
|
"${cfg.orgAvatarPng}"
|
|
else
|
|
"${cfg.assets}/share/hyperhive/branding/agent-configs.png";
|
|
# Whether this hive runs ruthless — no root/manager agent at all
|
|
# (`auto_update::ensure_root_agent`). Default false = root
|
|
# auto-managed; true makes the sweep a no-op.
|
|
HYPERHIVE_RUTHLESS = lib.boolToString config.services.hyperhive.ruthless;
|
|
}
|
|
// {
|
|
# Identity env vars threaded into c0re's own service env and
|
|
# forwarded by meta.rs into every sub-agent's harness env —
|
|
# full chain in docs/conventions.md::Hive identity. `domain` is
|
|
# required (asserted in hive-network.nix), so it's always set.
|
|
HYPERHIVE_HIVE_DOMAIN = config.services.hyperhive.domain;
|
|
}
|
|
// lib.optionalAttrs (config.services.hyperhive.hiveName != null) {
|
|
HYPERHIVE_HIVE_NAME = config.services.hyperhive.hiveName;
|
|
}
|
|
// lib.optionalAttrs (config.services.hyperhive.swarm.name != null) {
|
|
HYPERHIVE_SWARM_NAME = config.services.hyperhive.swarm.name;
|
|
}
|
|
// lib.optionalAttrs (!config.services.hyperhive.github.enable) {
|
|
# GitHub integration is on by default; only signal the OFF override to
|
|
# meta.rs, which then injects `hyperhive.github.enable = false` into
|
|
# every agent. See services.hyperhive.github.enable.
|
|
HYPERHIVE_GITHUB_DISABLED = "1";
|
|
}
|
|
// lib.optionalAttrs config.services.hyperhive.otel.enable (
|
|
# Hive-wide OTEL config -> read by meta.rs::otel_config and
|
|
# injected as build-time `hyperhive.otel.*` into every agent.
|
|
# Endpoint presence is the enable signal on the meta side; the
|
|
# optional fields are only emitted when set so absent values
|
|
# don't render no-op env lines.
|
|
let
|
|
otel = config.services.hyperhive.otel;
|
|
in
|
|
{
|
|
HYPERHIVE_OTEL_ENDPOINT = otel.endpoint;
|
|
HYPERHIVE_OTEL_PROTOCOL = otel.protocol;
|
|
}
|
|
// lib.optionalAttrs (otel.extraResourceAttributes != "") {
|
|
HYPERHIVE_OTEL_EXTRA_RESOURCE_ATTRIBUTES = otel.extraResourceAttributes;
|
|
}
|
|
// lib.optionalAttrs (otel.headersCredential != null) {
|
|
HYPERHIVE_OTEL_HEADERS_CREDENTIAL = otel.headersCredential;
|
|
}
|
|
// lib.optionalAttrs (otel.metricIntervalMs != null) {
|
|
HYPERHIVE_OTEL_METRIC_INTERVAL_MS = toString otel.metricIntervalMs;
|
|
}
|
|
// lib.optionalAttrs otel.debug {
|
|
HYPERHIVE_OTEL_DEBUG = "1";
|
|
}
|
|
)
|
|
// {
|
|
# In-cluster forge URL — the gateway vhost (`forge.<domain>`), which
|
|
# nginx proxies to forgejo. Used both for internal API calls in
|
|
# hive-c0re (forge/mod.rs `forge_http_base()`) and forwarded to
|
|
# 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.swarm.forge.domain}";
|
|
}
|
|
//
|
|
lib.optionalAttrs
|
|
(
|
|
config.services.hyperhive.swarm.matrix.enable
|
|
&& config.services.hyperhive.swarm.matrix.gatewayHost != null
|
|
)
|
|
{
|
|
# In-cluster matrix homeserver URL for each agent's
|
|
# hive-matrix-daemon — the gateway vhost (`matrix.<domain>`).
|
|
# Forwarded to agents by meta.rs alongside HIVE_FORGE_URL; shares the
|
|
# same env-forwarding ordering caveat (value baked at
|
|
# config-generation time).
|
|
#
|
|
# A domain-less config forwards nothing rather than falling back to
|
|
# loopback. The old fallback read as harmless because hive-c0re shares
|
|
# the host netns — but the value it produced was handed to *agents*,
|
|
# which do not, so `127.0.0.1` there names the agent itself. An absent
|
|
# forward leaves `hyperhive.matrix.url` null and the daemon no-ops;
|
|
# that is the honest answer when the hive has no matrix vhost to point
|
|
# at.
|
|
HIVE_MATRIX_URL = "http://${config.services.hyperhive.swarm.matrix.gatewayHost}";
|
|
}
|
|
// lib.optionalAttrs (config.services.hyperhive.swarm.matrix.apiUrl != null) {
|
|
# Client-server API base hive-c0re uses to provision matrix (register
|
|
# agent users, create the hive space + chat room, invite members).
|
|
# Supplied by `services.hyperhive.swarm.matrix.apiUrl`, which the matrix
|
|
# module fills in with its own loopback listener when it is the thing
|
|
# running tuwunel — and which the operator sets by hand when the
|
|
# homeserver lives on another machine.
|
|
#
|
|
# NOT the agent-facing HIVE_MATRIX_URL above: that one is the gateway
|
|
# vhost, and it is absent whenever there is no vhost. Reusing it here
|
|
# would silently stop provisioning on a hive that runs matrix without
|
|
# one.
|
|
HIVE_MATRIX_API_URL = config.services.hyperhive.swarm.matrix.apiUrl;
|
|
}
|
|
// lib.optionalAttrs config.services.hyperhive.swarm.matrix.gui.enable {
|
|
# Availability flags read by the dashboard's `/api/state`.
|
|
# Matrix GUI lives entirely on the gateway nginx (matrix tab
|
|
# only shows when both flags are on). Gateway routing detail:
|
|
# docs/gateway.md::Vhost map.
|
|
HIVE_MATRIX_GUI_ENABLED = "1";
|
|
}
|
|
// {
|
|
# The gateway always runs, so the dashboard always builds
|
|
# same-origin `/agent/<name>/` links (never the direct
|
|
# `<host>:<port>` TCP fallback). Kept as an env flag so the
|
|
# dashboard doesn't need to learn the gateway is unconditional.
|
|
HIVE_GATEWAY_ENABLED = "1";
|
|
}
|
|
// 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.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.swarm.forge.publicUrl;
|
|
}
|
|
//
|
|
lib.optionalAttrs
|
|
(
|
|
config.services.hyperhive.swarm.matrix.gui.enable
|
|
&& config.services.hyperhive.swarm.matrix.gatewayHost != null
|
|
)
|
|
{
|
|
# Browser-facing matrix GUI (fluffychat) URL — the gateway
|
|
# vhost (`matrix.<domain>`). Surfaced via the daemon's `Urls`
|
|
# request for `hivectl open matrix`. Absent when the GUI is off
|
|
# or no gatewayHost is set (no browser-reachable matrix vhost).
|
|
HIVE_MATRIX_PUBLIC_URL = "https://${config.services.hyperhive.swarm.matrix.gatewayHost}/";
|
|
}
|
|
// lib.optionalAttrs (config.services.hyperhive.swarm.snapshotStore.address != null) {
|
|
# `host:port` of the swarm's single snapshot store, for pushing agent
|
|
# snapshots (hive-c0re::snapshot_push). One per swarm, not one per
|
|
# peer — the receiver keys destinations by agent so a migrating agent
|
|
# keeps one incremental chain. Absent when no store is configured, and
|
|
# a push then fails naming the option rather than guessing.
|
|
HYPERHIVE_SNAPSHOT_STORE =
|
|
let
|
|
s = config.services.hyperhive.swarm.snapshotStore;
|
|
in
|
|
"${s.address}:${toString s.port}";
|
|
}
|
|
// lib.optionalAttrs (config.services.hyperhive.swarm.peerHives != { }) {
|
|
# Peer hives serialised as a JSON array of {domain, cert_fingerprint,
|
|
# wireguard_address?} objects. Consumed by hive-agent::identity::peers()
|
|
# + the dashboard's peer_hives StateSnapshot field (P33RS tab).
|
|
# `cert_fingerprint` is null for CA-trusted hives; `wireguard_address`
|
|
# is omitted when not part of the mesh.
|
|
#
|
|
# Reads `peerHives` — `swarm.hives` minus this hive — so the "not me"
|
|
# filter is the one derived in ../swarm.nix rather than a fifth copy.
|
|
HYPERHIVE_PEERS = builtins.toJSON (
|
|
lib.mapAttrsToList (
|
|
_name: p:
|
|
{
|
|
inherit (p) domain;
|
|
cert_fingerprint = p.certFingerprint;
|
|
}
|
|
// lib.optionalAttrs (p.wireguardAddress != null) {
|
|
wireguard_address = p.wireguardAddress;
|
|
}
|
|
) config.services.hyperhive.swarm.peerHives
|
|
);
|
|
}
|