Commit graph

1,983 commits

Author SHA1 Message Date
iris
b70209836e hive-sh4re: lift TaskFile + TaskStatus from hive-bash-mcp
Move the bash-task on-disk schema (TaskFile + TaskStatus) into hive-sh4re,
the shared wire-types crate, and re-export them from hive-bash-mcp::protocol
so existing in-crate imports keep compiling. This gives hive-ag3nt's agent
web UI a canonical type to deserialize when reading the bash-tasks dir for a
running-tasks panel, instead of a parallel struct that would silently drift
from the daemon's persisted format. Both crates already depend on hive-sh4re,
so no new dependency edges.
2026-06-21 13:28:37 +02:00
atlas
5336be7813 hivectl: wireguard mesh setup verbs (#1756)
One-time-setup convenience for the inter-hive WireGuard mesh
(services.hyperhive.swarm) so nobody has to remember the wg dance:

- hivectl wg init [--address X] — generate (if absent) the hive's
  private key at /etc/wireguard/hive.key (0400, never clobbered),
  derive + print the public key, and print the swarm.wireguard nix
  snippet to enable the mesh.
- hivectl wg peer <domain> --pubkey --address [--endpoint] — print the
  swarm.peers.<domain> nix snippet to add a remote hive.
- hivectl wg status — wrap wg show wg-hive.

Hybrid model per the design: the verb owns the imperative state (the
key file), the operator pastes the printed nix into host config (kept
in git) — nothing mutates declarative config behind their back.
hivectl-only (root host ops, like the gateway htpasswd verbs); no
priv/wire/c0re changes.

flake: wrap hivectl with wireguard-tools on PATH so wg resolves even
before the mesh config (which would otherwise pull it in) exists —
wg init is the first setup step. Add clippy.toml doc-valid-idents for
the WireGuard proper noun. Regenerate hivectl-cli.md.
2026-06-19 14:37:50 +02:00
atlas
c7612dcf2b hivectl: shell completions verb + ship zsh/bash/fish completions (#1764)
Add a 'hivectl completions <shell>' subcommand (clap_complete) that
prints a completion script for bash/zsh/fish/elvish/powershell, generated
from hivectl's own clap command tree so it never drifts from the real
verbs/flags. The package build installs the bash/zsh/fish scripts via
installShellFiles, so an operator gets working completion automatically
once hivectl is on their profile with shell completion enabled.

Regenerated docs/tools/hivectl-cli.md for the new verb.
2026-06-19 13:47:44 +02:00
damocles
f5003fd1bb hive-matrix-mcp: remove planted marker from send_redact comment, fix concurrent-delivery wording 2026-06-19 13:46:50 +02:00
atlas
eb103a5660 btrfs subvols: scrub tracker tags from comments; harden subvol chown
- Replace the #-number tracker references in code comments with prose
  (tracker-tag lint; hive convention is prose in source).
- ensure_agent_subvolume now treats a chown failure on the freshly
  created subvolume as fatal: it rolls the subvolume back (deletes it)
  and returns an error, instead of warning and leaving a root-owned
  subvol that hive-c0re can't write into (which would also make the
  c0re-side exists-check skip the retry, wedging the agent).
2026-06-19 13:46:39 +02:00
atlas
1f602d5fda hive-c0re: back agent state dirs with btrfs subvolumes
Progressive enhancement: a brand-new agent's state root under
/var/lib/hyperhive/agents is created as a btrfs subvolume when the host
filesystem is btrfs, otherwise it falls back to a plain directory. No
existing agent is auto-migrated — the new path only fires when the root
does not yet exist, so plain-dir agents are left untouched until an
explicit opt-in upgrade.

Two new privileged ops (subvolume create/delete are root-only):
EnsureAgentSubvolume statfs-gates on btrfs, creates the subvolume, and
chowns it to the hive-core user so the normal state/claude/harness
mkdirs succeed inside it; DeleteAgentSubvolume btrfs-subvolume-deletes
the root iff it is actually a subvolume. hive-c0re calls Ensure before
the per-agent dirs are created (spawn/rebuild/InitConfig) and Delete on
the purge path only — destroy keeps the subvolume for revival, matching
plain-dir semantics. btrfs-progs added to the hive-priv unit PATH.

Per-subvolume usage accounting + optional quota is a separate
follow-up.
2026-06-19 13:46:39 +02:00
iris
309cdc7546 docs(dashboard): graceful-stop CLI path is live too (#1790)
#1790 landed hivectl --graceful (enqueues the same GracefulStop as the
dashboard POST). Flip the dashboard.md note from 'CLI flag is still a no-op'
to noting both paths behave identically. hivectl-cli.md is regenerated by
#1790's clap doc-comment, so no edit needed there.
2026-06-19 12:57:31 +02:00
atlas
5da1ef4963 hivectl: trim --graceful doc to 'applies to agents only'
Drop the enumeration of what the flag does not apply to, per operator
review on the sibling graceful-stop change. Regenerate the CLI doc so
the markdown-docs self-diff check stays in sync.
2026-06-19 12:30:25 +02:00
atlas
31a4947aff hivectl: add hive-wide restart verb (stop then start)
`hivectl restart [scope]` cycles the scoped containers — composes the
existing stop + start daemon ops client-side (reusing the merged Stop/Start
wire ops + global --socket), so no new wire/c0re surface. Same scope model
as stop/start (--agents/--agent/--ci/--forge/--gateway/--matrix), and
--graceful on the stop half. If the stop phase reports a failure the start
phase is skipped so a half-stopped hive isn't blindly started over.
Regenerated docs/tools/hivectl-cli.md.
2026-06-19 12:29:17 +02:00
atlas
52ea715d60 docs: document the build + local-check workflow in conventions
Devshell-only builds (no global toolchain), nix fmt as the
authoritative formatter, and the full-flake-check gates the devshell
misses — notably the hivectl-docs regen after any hivectl verb/flag
change. Pulled out of the hive-wide knowledge repo, which keeps only
the portable kernel.
2026-06-19 12:23:01 +02:00
damocles
1b81ad423e hive-c0re: wire hivectl --graceful to enqueue GracefulStop 2026-06-19 12:10:23 +02:00
iris
cba02fc47e dashboard: label graceful-stop queue entries 'stopping…' on agent cards
#1785 routes a graceful stop through the rebuild queue as a GracefulStop
entry (wire kind 'graceful_stop'). The SW4RM container-row badge renderer
didn't recognise that kind, so an in-flight graceful stop fell through to
the generic 'rebuilding' / 'rebuild queued' label. Add the case so the card
shows 'stopping…' (running) / 'stop queued' (queued), giving the graceful
stop the same live card progress as a rebuild. Doc the badge kind too.
2026-06-19 12:01:44 +02:00
iris
2dda2f3c74 docs(dashboard): graceful stop is live — backend enqueues GracefulStop transient
#1785 landed the real backend: POST /kill/<name>?graceful=1 enqueues a
GracefulStop rebuild-queue transient (one stop-checkpoint turn to flush
state, 3-min timeout falls back to hard stop). Update the dashboard doc note
which still said the backend treated graceful the same as a hard stop. Also
note hivectl --graceful remains a no-op pending a separate gating change.
2026-06-19 12:01:03 +02:00
atlas
ae1bdd084a hivectl: make --socket a global flag instead of per-verb
The host admin socket path was duplicated on every daemon-assisted verb
(agents restart/restart-all, stop, start). Hoist it to a single global arg
on the top-level Cli (`--socket`, default DEFAULT_HOST_SOCKET, accepted
before or after the subcommand) and thread cli.socket through dispatch.
Verbs that don't talk to the daemon ignore it. Pure CLI-ergonomics change;
no wire/behaviour change. Regenerated docs/tools/hivectl-cli.md.
2026-06-19 11:56:09 +02:00
damocles
03ea5d601b hive-c0re: graceful agent stop — quiesce harness, flush state, then stop 2026-06-19 11:50:59 +02:00
iris
bf65345b83 docs(dashboard): document themed dialog system + graceful-stop checkbox
The dashboard now routes all confirms/prompts/error notices through the
in-app themed dialog system (modal.js: themedConfirm / themedPrompt /
themedToast) instead of native browser chrome, and the stop action carries
a 'stop gracefully' checkbox that POSTs /kill/<name>?graceful=1. Document
both in the web-ui reference, with the note that the backend quiesce is
still being implemented so the graceful flag currently behaves as a hard
stop.
2026-06-19 08:59:13 +02:00
damocles
3d15fcb409 hive-bash-mcp: kill is fire-and-forget; retry with force to escalate; must_use (review) 2026-06-19 08:33:40 +02:00
damocles
fc0ff10aee hive-bash-mcp: escalate sigint→sigkill on graceful kill + document panics (review) 2026-06-19 08:33:40 +02:00
damocles
b16629801b hive-bash-mcp: add kill tool to stop a running or pending bash task 2026-06-19 08:33:40 +02:00
atlas
e1b7f7cbec docs: regenerate hivectl-cli.md for the new stop/start verbs
The hivectl-docs flake check regenerates docs/tools/hivectl-cli.md from the
clap command tree and asserts it's committed up to date. Adding the stop/start
verbs changed the CLI, so the doc was stale and the check failed. Regenerate it.
2026-06-19 08:16:18 +02:00
atlas
0df9e40940 hivectl: collapse infra allowlist + restart/control ops onto SIBLING_CONTAINERS
Per review: RESTARTABLE_INFRA_CONTAINERS and the new CONTROLLABLE_INFRA_CONTAINERS
were near-identical subsets of SIBLING_CONTAINERS. Drop both and validate infra
lifecycle ops against SIBLING_CONTAINERS directly (all four infra containers;
hive-c0re is never in it, so it can't stop itself). This also makes hive-matrix
restartable, including via an infra_admin agent's restart tool.

Collapse the two priv ops too: RestartInfraContainer is gone; ControlInfraContainer
{ action } is the single op (restart = action: Restart). priv_client's
restart_infra_container is now a thin wrapper over control_infra_container.
2026-06-19 08:16:18 +02:00
atlas
c673dce73d hivectl: resolve stop/start scope to names at the c0re entry point
Per review: c0re expands the LifecycleScope to explicit container-name
lists (scoped_agents / scoped_infra) in the dispatch arm, then hands those
lists to handle_stop / handle_start. The 'all agents' flag no longer flows
past the resolution boundary, so downstream consumers (incl. the future
graceful-stop queue) always operate on concrete names. CLI --agents flag
unchanged.
2026-06-19 08:16:18 +02:00
atlas
465dd2d433 hivectl: note that stop --graceful is not yet effective
Until the per-agent quiesce lands, --graceful falls through to a hard
stop. Help-text the limitation so an operator passing the flag isn't
misled into thinking the agent quiesced.
2026-06-19 08:16:18 +02:00
atlas
fbb48ed3ce hivectl: add hive-wide start/stop verbs
`hivectl stop` brings the whole hive down in one operator action — all
sub-agents plus the ci/forge/gateway/matrix infra containers — and
`hivectl start` brings it back up. Scope flags (--agents, --agent <name>,
--ci, --forge, --gateway, --matrix) narrow the set; a bare invocation
targets everything. hive-c0re never stops itself.

- hive-sh4re: HostRequest::{Stop,Start} + LifecycleScope wire type;
  priv_proto InfraAction + ControlInfraContainer + the
  CONTROLLABLE_INFRA_CONTAINERS allowlist (adds hive-matrix, excludes
  hive-c0re).
- hive-priv: control_infra_container handler (systemctl <verb>
  container@<name>, allowlist-validated root-side).
- hive-c0re: handle_stop / handle_start fan out agents via lifecycle and
  infra via hive-priv; per-target failures are aggregated. Infra
  systemctl routes through hive-priv (the privsep boundary).
- The --graceful flag is threaded through Stop now; the per-agent quiesce
  itself lands with the graceful-agent-stop work.
2026-06-19 08:16:18 +02:00
iris
5b99eb1f8f dashboard: keep bulk/M0V3 partial-failure toasts until dismissed
The bulk-stop / M0V3 failure summaries list which agents failed; as
auto-dismissing toasts an operator could miss a partial failure after
navigating away. Make just those two summaries sticky (duration 0,
click-to-dismiss); transient single-action errors keep auto-dismiss.
2026-06-19 02:10:18 +02:00
iris
7c2de690ec dashboard: theme all remaining dialogs (replace native confirm/alert/prompt)
Follow-up to the themed-modal component: route every remaining native
browser dialog through modal.js so nothing falls back to the OS chrome.

- modal.js: add themedPrompt (input dialog) + themedToast (non-blocking
  transient notification, info/error/ok) alongside openDialog/themedConfirm.
- Migrate call sites: bindAsyncForms confirm/prompt/alerts (common.js),
  the answer-validation alert (call.js), the M0V3 reparent confirm + action
  toasts (tabs.js), and the schedule form/cancel/fire confirms + validation
  and error alerts (schedules.js).
- UX: blocking modal for confirms/prompts; non-blocking toast for transient
  errors + validation. Destructive confirms keep the danger styling.
- CSS for the toast stack + prompt input.

common.js <-> modal.js is a safe deferred import cycle (usage is call-time
only); esbuild bundles it clean.
2026-06-19 02:10:18 +02:00
damocles
ff3317eb20 hive-bash-mcp: invoke bash via /usr/bin/env (review) 2026-06-19 02:06:13 +02:00
damocles
2d97401fc0 hive-bash-mcp: run tasks under bash instead of sh 2026-06-19 02:06:13 +02:00
atlas
5a06d1156b hive-forge: add repo-labels verb to list a repo's full label set
`labels <number>` only lists an issue/PR's labels; there was no way to
list the project-wide label set, which triage/labelling needs to discover
valid names. Add `repo-labels [pattern]` hitting GET /repos/{owner}/{repo}/labels
(paginated), with optional name-substring filter. Default prints one label
per line (name + tab-separated description when set); --json emits the full
label objects.
2026-06-19 01:45:08 +02:00
iris
a45b56f658 dashboard(modal): label the dialog via aria-labelledby for a11y
Give the themed dialog an accessible name (role=dialog requires one):
label it by its title when present, else by its message, via
aria-labelledby on the box. Addresses an a11y review note on the
stop-confirm modal.
2026-06-19 01:24:54 +02:00
damocles
69682a6afa bound /api/state container rescan so introspection survives a saturated build backend 2026-06-19 01:20:56 +02:00
iris
0407e7da62 dashboard: extract themed dialog into a reusable modal.js component
Move the themed dialog out of common.js into its own modal.js module: a
general openDialog(title/message/content/buttons) primitive with themedConfirm
as a thin cancel/confirm wrapper on top. tabs.js imports it from there. No
behaviour change to the stop-confirm flow; the dialog is now a standalone
reusable component other surfaces can open.
2026-06-19 00:25:22 +02:00
iris
03b10d22cd dashboard(swarm): themed stop confirm modal with graceful checkbox
Replace the browser-native confirm() on the agent ST0P actions (per-agent
menu + bulk) with an in-theme modal (themedConfirm in common.js), carrying a
'stop gracefully' checkbox. Checked sends POST /kill/<name>?graceful=1 (the
quiesce path); unchecked is today's immediate hard stop, unchanged. The modal
also covers the other destructive menu actions (restart / rebuild / destroy /
purge) so they no longer fall back to the OS dialog.
2026-06-19 00:20:05 +02:00
damocles
9a6306540b fix agent disk usage reading container-internal state path on the host 2026-06-18 14:01:22 +02:00
damocles
68b0894f5b add list_accounts daemon op to hive-matrix-mcp 2026-06-18 14:00:44 +02:00
atlas
2efd95d0f5 nix(ci): pin the runner readiness gate to --store daemon
A bare `nix store ping` run as root with the daemon socket absent
resolves to a local store (root writes /nix/store directly) and pings
successfully, so the gate could false-pass at cold boot: nix-daemon.socket
carries ConditionPathIsReadWrite=/nix/var/nix/daemon-socket and is
condition-skipped until /nix/var goes read-write. systemd service units
don't source the profile that sets NIX_REMOTE=daemon, so auto-store
fallback to local is the real environment here.

Pin --store daemon so the readiness poll verifies the actual daemon
socket and the gate honours its wait-for-daemon contract instead of
passing against a local fallback while the daemon is still down.
2026-06-18 13:02:21 +02:00
iris
74196ac582 dashboard(swarm): wrap agent status to two lines, always show set-time
The agent self-reported status rendered on one line with
white-space:nowrap + text-overflow:ellipsis. Because the "(set N ago)"
stamp trailed the text in the same clipped flow, a long status clipped
the set-time away entirely. Wrap the icon + message in a .status-msg
span clamped to two lines and make the age a non-shrinking flex sibling,
so the message wraps to two lines (then ellipsizes) and the set-time is
always shown.
2026-06-18 13:02:11 +02:00
iris
6a7c0bcad8 docs(web-ui): matrix-accounts picker reads state.containers
The M4TR1X ACC0UNTS section said the agent picker is populated from
`state.agents`, which never existed on /api/state — the same stale
field the code read. Sync the doc to the live roster field.
2026-06-18 13:02:02 +02:00
iris
d8d589ccb2 dashboard(matrix-accounts): populate agent picker from state containers
The agent dropdown read a non-existent `agents` field on /api/state, so
it always rendered empty ("— no agents —"). The endpoint exposes the
live roster under `containers` (each entry an object with `.name`).
Read that instead; the existing string-or-object map keeps it robust.
2026-06-18 13:02:02 +02:00
atlas
3b8e77c1c1 nix(gateway): factor the self-signed condition into a shared option
Per review: the `tls.certDir == null && !tls.acme.enable` derivation was
duplicated in hive-gateway, hive-tls, and hive-ci. Expose it once as a
read-only internal option `services.hyperhive.gateway.useSelfSigned` (the
gateway module's single source of truth) and have hive-tls and hive-ci
consume it instead of re-deriving.

Eval-proven: gateway.useSelfSigned is true on the self-signed default /
false with tls.certDir, and the hive-tls (HIVE_TLS_CA_PATH) + hive-ci
(NODE_EXTRA_CA_CERTS) wiring derives correctly from it.
2026-06-18 01:03:55 +02:00
atlas
9f03cf31ba nix(ci): trust the hive CA in the runner's Node actions (self-signed TLS)
With self-signed TLS the gateway/forge serve a hive-CA-signed leaf and
forgejo's ROOT_URL is https://forge.<domain>. The CI runner's Node-based
actions (e.g. upload-artifact) POST to the ROOT_URL-derived artifact
endpoint and fail with "unable to verify the first certificate": Node uses
its own bundled CA bundle, not the system store, so it rejects the
self-signed chain. checkout etc. are fine — they hit the localhost http
registration URL.

Bind-mount the public hive CA cert (only ca.pem — never the hive-tls state
dir, which holds the CA + leaf private keys) into the hive-ci container and
set NODE_EXTRA_CA_CERTS on the runner service so every Node action trusts
it, hive-wide. Order container@hive-ci after the host hive-tls-ca service so
the cert exists before the bind-mount is set up. All gated on self-signed
mode; with an operator cert / ACME the public CA already validates and the
mount + env var are absent.

Eval-proven: self-signed → /run/hive-ca/ca.pem bind-mount (from
/var/lib/hive-tls/ca.pem), NODE_EXTRA_CA_CERTS=/run/hive-ca/ca.pem, and
container@hive-ci ordered after hive-tls-ca.service; certDir → all absent.
2026-06-18 00:17:53 +02:00
iris
1bc26429f2 dashboard(home): harden matrix-rain fade-trail colour parsing
Follow-up to the matrix-rain backdrop (merged): address argus's review nit
on the fadeColor construction. It string-rewrote `rgb(...)`→`rgba(...)`,
which silently fills the trail solid if getComputedStyle ever returns a
non-`rgb(r, g, b)` form. Extract r,g,b numerically and build the rgba
explicitly so the trail always fades regardless of the returned format
(same rgb fallback end-to-end). CSS/JS-only, home page.
2026-06-17 21:59:12 +02:00
iris
31001d52e8 dashboard(home): matrix-rain backdrop on the H0M3 page
Adds the falling-glyph "digital rain" effect the operator asked for as a
dimmed background on the home hub.

- index.html: a decorative full-viewport <canvas id="matrix-rain">
  (aria-hidden, pointer-events:none) as the first body child.
- home.css: fixes it behind the content (z-index:-1, inset:0) at low
  opacity (0.16) so the menu tiles stay legible — the "dimmed bg".
- home.js: startMatrixRain() drives the classic stepped digital rain.
  Glyph + fade-trail colours are RESOLVED FROM THE STYLIX PALETTE at
  runtime (--green glyphs, --bg trail; resolved via a probe element
  since getComputedStyle returns custom props unresolved), so a theme
  swap re-colours it rather than hardcoding matrix-green. Stepped via a
  55ms interval, paused while the tab is hidden, and skipped entirely
  under prefers-reduced-motion.

CSS/JS only, home page only.
2026-06-17 21:46:25 +02:00
atlas
58cc720173 nix(ci): gate the actions runner on nix-daemon readiness
After a hive-ci restart the act_runner re-registers and immediately claims
any queued jobs, which can beat the in-container nix daemon coming up: its
nix-daemon.socket carries ConditionPathIsReadWrite=/nix/var/nix/daemon-socket
and is skipped until /nix/var is read-write, so the first nix-dependent
build dispatches into a cold daemon and hangs/retries (observed: a 55m48s
nix flake check vs the normal ~30s — a build-offload stall, not a code
failure; a non-nix step on the same runner passed in 1s, masking it).

Ordering the runner after/wants nix-daemon.socket does not help — a
condition-skipped unit satisfies systemd ordering immediately. Instead add
a blocking ExecStartPre that polls until the daemon actually answers
(nix store ping), placed with mkBefore so it runs ahead of the upstream
module's runner-registration ExecStartPre. The runner therefore cannot
register or claim jobs until nix is usable. Topology-agnostic (works
whether the daemon is in-container or a shared host socket); ~180s ceiling
then the unit fails cleanly rather than claiming jobs into a dead daemon.

Eval-proven: gitea-runner-hive's ExecStartPre is
[wait-nix-daemon, gitea-register-runner-hive] in that order.
2026-06-17 21:17:35 +02:00
atlas
1a3f82a459 nix(gateway): self-signed TLS as the implicit default, deprecate the toggle
Make self-signed TLS the gateway's default whenever no external TLS source
is configured, and deprecate the explicit selfSignedTls toggle. Self-signed
is now derived as `tls.certDir == null && !tls.acme.enable`, so an operator
selects a TLS mode by setting tls.certDir or tls.acme — or neither, for the
self-signed default. There is no http-only mode: matrix discovery hardcodes
https, so the gateway always terminates TLS.

The selfSignedTls option is kept as a deprecated no-op (warns when set to
false) so existing configs still eval. The two selfSignedTls mutual-
exclusion assertions and the HSTS-requires-TLS assertion are dropped — they
are impossible or vacuous now that self-signed is the floor. The hive-tls
module and the forge ROOT_URL scheme consume the derived value: the gateway
always terminates TLS, so behind the gateway the forge is always advertised
over https.

Updates docs/gateway.md (TLS-modes table, self-signed section, the removed
http-only section, firewall + discovery notes). Eval-proven: default →
self-signed (hive CA active, https ROOT_URL); tls.certDir → CA inactive;
selfSignedTls=false → deprecation warning fires.
2026-06-17 21:14:05 +02:00
atlas
0b4c2419f5 ci: retrigger after prior run timed out at 55m (runner recovery window) 2026-06-17 21:09:16 +02:00
atlas
1e39a6c12b feat(forge): trust the system CA store in the hive-forge client
Enable reqwest's rustls-tls-native-roots feature for hive-forge so its
HTTP client validates against the OS/system CA store (rustls-native-certs)
in addition to the bundled webpki roots. Once the hive CA is embedded into
agent system trust stores (via the meta flake's security.pki.certificateFiles
wiring), hive-forge validates the gateway's self-signed leaf with no extra
env plumbing.

Additive: the bundled webpki roots stay enabled, so public CAs still
validate; the native store adds the hive CA. On NixOS the system store
already includes the Mozilla bundle, so the effective trust set is a
superset. Cargo unifies features across the build, so native-root loading
is enabled for every reqwest client — harmless, since it only widens the
root set.

Final piece of the self-signed agent-trust chain (host CA + gateway leaf,
then CA embedded into agent flakes, now the forge client honouring it).
2026-06-17 21:09:16 +02:00
iris
9b54eff5d1 dashboard(html): fix stale P3RM1SS10NS pane comment after the save-all change
The save-all change updated the visible copy + the JS but left this HTML
pane comment describing the old per-row "POSTs to the respective /{agent}
endpoint" flow. Correct it to the page-level save-all → POST /api/permissions
batch (caps + groups coalesce into one rebuild per agent). Comment-only.
2026-06-17 20:14:09 +02:00
atlas
4f3f6522d2 feat(tls): embed hive CA into agent flakes for self-signed trust
Wire agents to trust the gateway's self-signed leaf at build time. When
the gateway runs self-signed TLS, hive-tls sets HIVE_TLS_CA_PATH in
hive-c0re's service env pointing at the host hive CA cert. The meta flake
renderer reads it and, when present, writes the public CA cert next to
flake.nix as hive-ca.pem and emits security.pki.certificateFiles so every
agent's system trust store includes the hive CA.

Build-time embedding (rather than a runtime bind-mount + bundle service)
keeps trust robust: the CA travels with the flake source, lands in the
standard NixOS trust store, and needs no per-process SSL_CERT_FILE
plumbing. Only the public CA certificate is embedded; the CA private key
never leaves the host. The cert is re-embedded and re-committed on CA
rotation even when the flake is otherwise byte-identical; when self-signed
TLS is off the embedded cert is dropped so the flake stays buildable.

Covers OpenSSL-based tools (git, curl) directly. A follow-up switches the
hive-forge reqwest client to native roots so it picks up the same store.
2026-06-17 19:42:15 +02:00
damocles
9f9c1167ae hive-forge: add pr-commits verb (PR commit list, survives rebase-rewritten shas) 2026-06-17 19:25:01 +02:00