Commit graph hyperhive/nix
Author SHA1 Message Date
müde
7ad2bb9211 refactor: replace deprecated no-op options with mkRemovedOptionModule 2026-07-13 21:58:30 +02:00
müde
43bbd64f82 refactor: drop dead http-only TLS branches (gateway is always https) 2026-07-13 21:54:30 +02:00
müde
874a900bdc refactor: split c0re module into options/theme/environment, hive-priv standalone 2026-07-13 21:50:32 +02:00
müde
281667d5a8 refactor: thread agent packages via option, drop overlay and forge-tools shim 2026-07-13 21:43:26 +02:00
müde
e7689a6804 refactor: split hive-c0re module, aggregate host stack in nix/modules 2026-07-13 21:37:47 +02:00
müde
5f9af9fc97 refactor: split hive-gateway into module dir, DHCP range into hive-network 2026-07-13 21:26:30 +02:00
müde
ecaad48fad refactor: split harness-base.nix into harness/ feature modules 2026-07-13 21:16:29 +02:00
müde
c0bd77b314 fix: select rust sources via filesets so new dirs keep the cargo cache 2026-07-13 21:16:29 +02:00
müde
3069c11c3d refactor: build workspace once, extract per-bin packages 2026-07-13 21:05:12 +02:00
müde
4f8bb6ded2 refactor: slim flake.nix into nix/ entry files 2026-07-13 20:55:43 +02:00
atlas
650224c9c6 fix(#2399): split daemon/harness/MCP bins into per-binary packages
mara: "no, do split packages for the separate daemons" — instead of
grouping all daemon/harness/MCP bins into one hyperhive-daemon
derivation, each bin (hive-c0re, hive-priv, hive-agent,
hive-agent-mcp, hive-agent-wake, hive-bash-daemon, hive-bash-mcp,
hive-matrix-daemon, hive-matrix-mcp, hive-metric) is now its own
named package + overlay output, matching the existing hivectl /
hive-forge split. harness-base.nix's ExecStart/command lines now
point at the specific pkgs.hive-* each ExecStart needs, and
environment.systemPackages only carries the two bins actually
PATH-looked-up in-container (hive-agent-wake, hive-metric) instead
of the whole bundle.
2026-07-13 19:26:58 +02:00
atlas
5c08abc1b2 fix(#2399): agent containers get daemonBins, not the full hivectl/hive-forge bundle
Agent containers pulled in `pkgs.hyperhive` (packages.default: daemonBins +
hivectlPkg + hiveForgePkg) via environment.systemPackages and every
harness ExecStart. That shipped hivectl (a host-admin CLI dialing the
host admin socket, unreachable from inside a container, wrapped with
wireguard-tools for `hivectl wg`) plus a redundant second hive-forge
copy (already provided separately via hive-forge-tools.nix) into every
single agent's closure.

Expose the existing daemonBins split as packages.<system>.daemonBins
(mara: 'there should be split nix outputs already, use those' — no new
grouping derivation) + a hyperhive-daemon overlay entry, and repoint
harness-base.nix's systemPackages entry and all agent-run ExecStarts
(hive-agent, hive-agent-mcp, hive-bash-daemon, hive-matrix-daemon) plus
the bash/matrix MCP bridge commands at it instead of the full bundle.

nix flake check: daemonBins + agent-base-toplevel + ruth-toplevel all
evaluate cleanly (docs derivation failure is a preexisting dirty-tree
issue, unrelated).
2026-07-13 19:26:58 +02:00
müde
e13a2cb33a fix(#2363): open UDP 67 on the bridge — host firewall dropped DHCP requests 2026-07-13 15:24:56 +02:00
müde
3a3f318779 fix(#2363): grant hive-gateway CAP_NET_ADMIN — dnsmasq DHCP mode requires it 2026-07-13 13:57:37 +02:00
atlas
2f8c1ec347 docs(#2363): update network.md + hive-ci.nix for full-DHCP model
- docs/network.md: LOCAL_ADDRESS is now empty (not deterministic-IP);
  containers use dhcpcd + dnsmasq DHCP pool, not hash-derived static IPs
- nix/modules/hive-ci.nix: 'service containers' → 'all containers'
  in the dnsmasq DHCP pool comment (agents also use the same pool)
2026-07-13 11:57:14 +02:00
atlas
4cdbbafc44 feat(#2363): full-DHCP for all agents — drop static agent_network_ip
All agent containers now receive their bridge IP dynamically via DHCP
from the dnsmasq pool instead of a hash-derived static address:

- nix/templates/harness-base.nix: networking.useDHCP = true
- nix/modules/hive-gateway.nix: expand DHCP pool to full usable range
  (.2 to .254 on /24) — was last-14-IPs-only
- hive-sh4re/src/priv_proto.rs: remove agent_ip from NetworkIsolation
- hive-c0re/src/lifecycle/mod.rs: drop agent_network_ip + DHCP_POOL_SIZE
- hive-c0re/src/lifecycle/host_config.rs: remove agent_network_ip call
- hive-priv/src/main.rs: LOCAL_ADDRESS= empty (DHCP assigns IP);
  HOST_ADDRESS still set so nixos-container installs default route
  before the DHCP lease arrives
- nix/dhcp-pool-size: deleted (no longer needed)

The nix/dhcp-pool-size single-source-of-truth file and all associated
Rust/Nix dual-constant plumbing are gone — there is no static map.
bridge_gateway_ip() is retained (still needed for HOST_ADDRESS).

Closes #2363
2026-07-13 11:57:14 +02:00
atlas
eb94b2aae6 docs(#2363): fix stale 'remap' comments in hive-gateway.nix
The DHCP pool exclusion is now by construction (agent_slots = usable -
dhcpPoolSize), not a secondary-hash remap. Update two comment blocks
that still referenced the old approach.
2026-07-13 11:57:14 +02:00
atlas
3068034463 refactor(#2363): single source of truth for DHCP pool size
Move the DHCP pool size constant out of the two separate definitions
(Nix literal + Rust const) into a shared data file: nix/dhcp-pool-size.

- nix/dhcp-pool-size: new file, contains '14'
- hive-gateway.nix: reads via builtins.readFile + toIntBase10
- lifecycle/mod.rs: parses via include_bytes! const block at compile time

Cargo automatically tracks include_bytes! as a file dependency so a
change to nix/dhcp-pool-size triggers recompilation without build.rs.
2026-07-13 11:57:14 +02:00
atlas
a3796890f5 feat(#2363): DHCP pool for bridge service containers
Add a DHCP pool to the gateway's dnsmasq so bridge-attached service
containers (hive-ci and future equivalents) get their addresses from
a proper DHCP server instead of a brittle static derivation.

gateway (hive-gateway.nix):
- Add IPv4 arithmetic helpers (ipToInt, intToIp, pow2) to compute the
  DHCP pool range at nix eval time from bridgeIp + bridgePrefixLength.
- Reserve the last dhcpPoolSize (14) usable host addresses as the DHCP
  pool (e.g. .241-.254 on a /24 with 10.42.0.0 network).
- Add dhcp-range and dhcp-leasefile to the dnsmasq settings block.
  The pool is active whenever services.hyperhive.network.enable is true.

hive-ci (hive-ci.nix):
- Remove the ciBridgeIp / ciBridgeOctets static derivation and the
  brittle top-of-/24 comment block.
- Switch networking.interfaces.eth0 to useDHCP = true so hive-ci gets
  its address from the gateway DHCP pool.

lifecycle (mod.rs, tests.rs):
- Add DHCP_POOL_SIZE = 14 constant (must stay in sync with
  dhcpPoolSize in hive-gateway.nix).
- Remap agents whose FNV-1a hash falls in the DHCP pool into the
  agent-only window [2, dhcp_start - 1]. Only the rare agent whose
  name hashes into the pool is affected; all others keep their IPs.
- Update and extend tests: agent range is now .2-.240 on /24;
  add agent_network_ip_never_in_dhcp_pool covering 18 agent names.
2026-07-13 11:57:14 +02:00
atlas
79a29873e3 fix(#2164): domain-URL webhooks + HMAC + config-PR polling fallback
Both webhook registrations (knowledge push + config-PR pull_request) now
use the public hive domain instead of loopback:
  https://<HYPERHIVE_HIVE_DOMAIN>/webhook/{knowledge,config-pr}

This routes deliveries through the gateway, bypassing the Forgejo SSRF
guard that blocked loopback delivery and silently broke the config-PR
merge flow since launch.

Changes:
- webhook_secret: new module — auto-generate + persist a 32-byte HMAC
  secret to STATE_ROOT/webhook-secret on first startup; verify
  X-Hub-Signature-256 on every incoming webhook POST (HMAC-SHA256).
- forge/mod.rs: ensure_config_pr_webhook now takes hive_domain +
  webhook_secret; sets secret in Forgejo hook config.
- workers/knowledge.rs: ensure_webhook same update.
- dashboard/webhook.rs: both handlers read raw Bytes first, verify HMAC,
  then parse JSON. Returns 401 on signature mismatch.
- dashboard/mod.rs: AppState carries webhook_secret; serve() takes it.
- main.rs: load/generate secret at startup; pass to registration tasks
  + dashboard; add 5-minute config-PR polling fallback task.
- forge/config_pr_poll.rs: new — scan agent-configs/* for open PRs with
  no pending MergeConfigPr approval; queue them. Idempotent.
- stores/approvals.rs: has_pending_merge_config_pr() for poll dedup.
- nix/modules/hive-gateway.nix: remove dashboardAuth from /webhook/
  location (HMAC replaces basic auth for webhook endpoints; Forgejo
  cannot send HTTP Basic credentials with webhook deliveries).
2026-07-11 23:28:16 +02:00
damocles
46007008a9 fix(#1970): bake token path into gh/git wrappers — env var didn't reach claude's bash-tool context 2026-07-11 14:12:25 +02:00
damocles
bd0e554447 fix(#1970): nested-path environment.etc."gitconfig" + mkIf — whole-set binding collided with sibling entries 2026-07-11 12:18:55 +02:00
damocles
18965ff7bd feat(#1970): host services.hyperhive.github.enable (default true) + meta.rs propagation of the off-switch 2026-07-11 12:18:55 +02:00
damocles
af9b46e80a refactor(#1970): replace githubAccount option with hyperhive.github.enable gate (default true, github.com + x-access-token) 2026-07-11 12:18:55 +02:00
damocles
5fb4b9f4b0 wip(#1970): gh wrapper + git credential helper + gated env/gitconfig for githubAccount 2026-07-11 12:18:55 +02:00
damocles
303037689e wip(#1970): add hyperhive.githubAccount nix option (single-account, nullable) 2026-07-11 12:18:55 +02:00
damocles
1ba44b77ac feat(#2112): make http-mcp the sole transport for the built-in surface 2026-07-11 00:32:51 +02:00
atlas
0fc4600d07 fix(#2332): add After=hive-tls-ca to resign service — prevent first-boot CA race
On a fresh deploy Persistent=true causes the weekly timer to fire
immediately. Without this ordering hive-tls-resign can race
hive-tls-ca before the CA key is written, failing the resign.
CA is always valid when this runs; resign is a no-op if the leaf
is still within its half-life margin.

Suggested by argus (review) + requested by mara.
2026-07-10 19:37:08 +02:00
atlas
61bd0b604d feat(#1933): weekly hive-tls-resign timer — dedicated resign service, no hive-tls-ca bounce
The parked PR (#1934) triggered re-sign by restarting hive-tls-ca
(a RemainAfterExit oneshot), which mara flagged as a hack.  This
replaces that with a dedicated hive-tls-resign.{service,timer}:

- hive-tls-ca unchanged — still handles boot-time CA generation +
  initial leaf signing; RemainAfterExit, runs before the gateway.
- hive-tls-resign.service — runs the leaf re-sign directly (openssl
  in its own PATH); does NOT touch hive-tls-ca.  Re-signs only when
  the leaf is within half its validity of expiry, so the weekly timer
  catches short-lived (30d default) leaves well before they lapse.
  Checks sha256 before/after; if the leaf rotated it propagates into
  the running gateway via systemctl -M hive-gateway (mirroring how
  hive-c0re reloads the gateway after agents.conf writes — the
  documented correct approach; an inotify path unit inside the
  container does not work across the nspawn mount-namespace boundary).
  || true on the propagation calls so a stopped gateway never fails
  the unit (its next boot imports the already-rotated leaf).
- hive-tls-resign.timer — OnCalendar=weekly, Persistent=true (fires a
  missed run on next boot so a host that was off on the scheduled day
  catches up rather than letting the leaf lapse silently).
- leafValidityDays doc updated to reflect automatic renewal.

Closes #1933.
2026-07-10 19:37:08 +02:00
sock
078ea74ba9 fix(hive-ci): static bridge IP instead of DHCP (no DHCP server on the bridge)
hive-ci is the one container on the hive bridge that used DHCP
(networking.interfaces.eth0.useDHCP = true, from #2310 / #2336). But the
bridge has no DHCP server: dnsmasq on the bridge is DNS-only and agent
containers get deterministic static IPs (lifecycle::agent_network_ip),
so the DHCP client never gets a lease and the container hangs at boot:

  A start job is running for DHCP Client (5s / 1min 31s)

Assign a static address on eth0 (top host address of the subnet) plus a
default route via the bridge gateway, and drop useDHCP. Preserves the
#2310 netns isolation (no host-loopback reach) while letting the
container boot and reach the forge through the gateway.

Refs #2310, #2336.
2026-07-10 18:38:17 +02:00
atlas
c0a49c95c1 fix(#2336): per-interface DHCP on eth0 instead of global useDHCP
nixos-containers.nix sets networking.useDHCP = false for every
container (to suppress the deprecated global DHCP warning). Setting
networking.useDHCP = true in the hive-ci inner config conflicts with
no priority differential → eval error on hosts running current main.

Fix: drop the global useDHCP = true and configure DHCP on eth0
(the inner veth interface name assigned by systemd-nspawn when
hostBridge is used). This is both conflict-free and the correct
modern NixOS practice for per-interface DHCP.
2026-07-10 14:47:32 +02:00
atlas
3f7f24dd0b fix: correct hyperhive.user.gid description — gid works independently of uid 2026-07-10 13:54:03 +02:00
atlas
0d5f7e00b6 feat(#903): expose hyperhive.user.uid + gid options for optional UID pinning 2026-07-10 13:54:03 +02:00
atlas
bd77b94518 fix(#1821): remove nix.settings.fallback from hive-ci once daemon routing confirmed
The container-level nix.settings.fallback = lib.mkForce true (added as an
interim safety net so a down remote builder degrades gracefully rather than
hard-failing CI) is rendered redundant by the host-daemon routing fix: with
NIX_REMOTE=daemon set for all systemd units in the container, every nix
build invocation routes through the host daemon, which already has its own
fallback policy. The container setting would only apply to nix invocations
that bypass the daemon entirely — a case that should not exist post-deploy.

NOTE: draft — gated on the daemon-routing change (PR that adds
NIX_REMOTE=daemon to systemd.globalEnvironment + hive-priv service env)
being deployed and confirmed working in production before merging.
2026-07-10 13:48:27 +02:00
atlas
056a442a18 fix(#2310): hive-ci private network — bridge-connected, no host-loopback reach
Give hive-ci its own network namespace (privateNetwork=true, hostBridge)
instead of sharing the host netns. This closes the path by which a
prompt-injected PR nix build could reach the unauthenticated dashboard
at 127.0.0.1:7000.

The runner now reaches the forge through the gateway:
- networking.extraHosts maps forgeCfg.domain → bridgeIp
- runner url = http://${forgeCfg.domain} (gateway port 80, addSSL=true,
  no HTTP→HTTPS redirect — HTTP is served alongside HTTPS)
- networking.useDHCP = true for the bridge-attached veth
- networking.nameservers = [bridgeIp] (dnsmasq on bridge, external fwd)

Ports 80 and 443 are already open on the bridge firewall (hive-network.nix).
The bridge→127.0.0.0/8 DROP rule (defence-in-depth) is unchanged — CI
can no longer reach 127.0.0.1:{7000 dashboard, forge httpPort, etc.}.

Requires forge.behindGateway=true (the default when hyperhive is enabled)
— asserted so misconfigured hosts get a clear build error.

Note: the host-side hive-ci-prefetch script still uses
127.0.0.1:${httpPort} directly (it runs on the host, not in the
container) — no change needed there.
2026-07-10 12:54:46 +02:00
iris
476a7a3c9f web_ui: support unix:<path> upstreams in extraWebProxies
reqwest has no UDS transport, so unix: upstreams dial the socket
directly with a raw hyper/1.1 client per request instead. http(s)://
upstreams are unaffected (still go through the existing reqwest path).

Adds hyper (client, http1), hyper-util (tokio IO adapter), and
http-body-util as direct hive-ag3nt dependencies - all three were
already present transitively via reqwest, this just uses them
directly for the new code path.
2026-07-10 12:53:09 +02:00
damocles
89ce8790ff feat(web_ui): per-path reverse-proxy via HIVE_EXTRA_WEB_PROXIES 2026-07-10 12:14:21 +02:00
atlas
6da7835ad9 fix(#2264): boot.tmp.useTmpfs = false — disk-backed /tmp for agents
Agent containers currently mount /tmp as a 3.2 GB tmpfs (RAM-backed).
Large scratch writes (nix-develop shells, cargo build dirs) eat container
RAM unnecessarily and can exhaust the tmpfs, losing in-flight work.

Set boot.tmp.useTmpfs = false so /tmp is disk-backed instead.
boot.tmp.cleanOnBoot (default true) preserves the ephemeral-per-boot
semantics — /tmp is cleared on container start, same as before.

Closes #2264. Supersedes PR #2299 (TMPDIR redirect + state/tmp).
2026-07-10 12:09:31 +02:00
iris
ccc5e631e2 web-ui: sanitize markdown HTML with DOMPurify to fix XSS
Both mdNode implementations (agent UI app.js, dashboard common.js)
assigned marked.parse() output straight to innerHTML with no
sanitizer. marked v5+ dropped its built-in sanitize option, and there
was no DOMPurify anywhere in frontend/, so markdown containing raw
HTML/script tags rendered live in the browser.

Both sinks receive untrusted input in practice: the agent UI's mdNode
renders recv tool_result bodies, assistant prose, and send/ask/answer
payloads sourced from peer agents and matrix-relayed messages (the
documented prompt-injection adversary); the dashboard's mdNode renders
agent-authored .md files served verbatim by GET /api/state-file
(the endpoint validates path, not content). Since the per-agent UI and
dashboard are same-origin behind the gateway with operator-authority
endpoints (approve/spawn/rebuild/destroy/answer-question), injected
script would run with the operator's session.

Fix: DOMPurify.sanitize() the marked.parse() output at both sinks
before assigning to innerHTML. Added dompurify as a dependency to
both the agent and dashboard npm workspaces, recomputed npmDepsHash
in nix/frontend.nix for the updated lockfile. Also corrected
docs/web-ui/shape.md, which claimed the markdown-rendering path was
XSS-safe by construction the same way the text-node-based linkify
path is — it isn't; it's safe because it's sanitized.

CSP hardening for the dashboard (no unsafe-inline) is a separate,
larger backend change (response headers in hive-c0re) and is left as
a fast-follow rather than folded into this fix.
2026-07-10 11:54:50 +02:00
atlas
9adf074504 feat(#2304): set weston VNC default resolution to 720p (1280x720)
Add [output] section to weston.ini with name=VNC-1 mode=1280x720.
The VNC backend's output is named VNC-1; the mode string sets the
compositor's framebuffer size that clients connect to.
2026-07-10 02:47:39 +02:00
atlas
031edbd41f fix(#1868): use HIVE_FORGE_URL for internal forge calls
Replace the hardcoded FORGE_HTTP const with forge_http_base() which
reads HIVE_FORGE_URL from the environment (already set unconditionally
by hive-c0re.nix to http://<forge.domain>). Add forge_git_url() helper
that inserts core:<token> credentials between scheme and authority for
git push/clone URLs.

All call sites updated:
- forge/mod.rs: api() OnceLock + new forge_git_url/forge_http_base fns
- forge/repos.rs: push_meta, push_config, ensure_meta_remote
- forge/pr_merge.rs: tokenised_repo_url delegate + test loosened
- workers/knowledge.rs: clone + push URLs
- socket_server/mod.rs: clone_url in RepoCreated response

No new env var: HIVE_FORGE_URL was already the right knob (mara).

Closes #1868. Closes #2174 (this supersedes the operators-team fix from
the closed #2218, which is re-applied in the ensure_operators_team call
that was already merged separately).
2026-07-09 00:45:13 +02:00
atlas
39af2bad5d style: nix fmt hive-xdg-icons.nix (treefmt) 2026-07-08 23:37:09 +02:00
atlas
ba5a0e1a66 fix: add hyperhiveXdgIcons stub to nix/docs eval (fixes packages.docs check) 2026-07-08 23:37:09 +02:00
atlas
64eddfd0b6 feat(#2228): add XDG icon set and .desktop entries for hyperhive processes
Adds hive-xdg-icons package (nix/packages/hive-xdg-icons.nix) that
rasterizes the branding SVG to all standard hicolor sizes (16–256px)
and installs /usr/share/pixmaps/hyperhive.png as a flat fallback.
Ships .desktop entries for hive-c0re and hive-ag3nt with NoDisplay=true
so desktop environments can match running processes to their icon without
cluttering the application launcher.

Narrow drv input: only ./branding/hyperhive.svg, so unrelated source
changes don't bust the cache.

Wired into environment.systemPackages in hive-c0re.nix (host side)
so the icons are present wherever hive-c0re is deployed.

Closes #2228
2026-07-08 23:37:09 +02:00
müde
5b062dca55 refactor(hive-ag3nt): split hive bin into hive-agent / hive-agent-mcp / hive-agent-wake 2026-07-06 23:48:05 +02:00
müde
8349e6f621 feat(dashboard): node-aware queue render + buildSlots option
each queue card now shows its DAG's node chain (per-node state, step,
build-log link), fixing 'queue jumps don't show on the dashboard'.
live-log panel keys off the running node's log. new
services.hyperhive.c0re.buildSlots option (default 1) threads the
concurrent nix-build count into serve.json.
2026-07-06 20:36:57 +02:00
atlas
23f13d9e71 chore(docs,nix): fix stale 'localhost via shared netns' claims in forge/matrix
Agents in private netns can't reach host loopback directly; they
use forge.<domain> and matrix.<domain> via the gateway. Update four
locations that still claimed direct loopback access:

- hive-forge.nix: module header + openFirewall description
- hive-matrix.nix: openFirewall description
- docs/matrix.md: container design bullet + openFirewall section
2026-07-04 22:54:38 +02:00
atlas
d7bed0052c chore(nix): fix stale 'localhost via shared netns' claim in forge openFirewall doc
Agents in private netns reach the forge at forge.<domain> via the
gateway, not via localhost directly. The conclusion (firewall only
matters for external access) is correct; the mechanism description
was stale from the pre-isolation era.
2026-07-04 22:54:38 +02:00
atlas
03e07c7d37 chore(nix): fix remaining stale shared-netns references in harness-base.nix
- Option doc: 'Default points at the in-host tuwunel (shared netns)'
  → updated to reflect that c0re forwards the gateway URL at runtime
- DNS oneshot comment: 'inert in shared-netns mode' → removed since
  isolation is always on; oneshot always runs
2026-07-04 22:54:38 +02:00
atlas
9067398e3c chore(docs,nix): remove stale shared-netns references from matrix URL docs
Agents run in private netns (always-on isolation) and can't reach
host loopback directly. hive-c0re forwards HIVE_MATRIX_URL set to
`matrix.<domain>` via the gateway. Update two places that still
referenced the removed shared-netns path.
2026-07-04 22:54:38 +02:00