The swarm-authelia module states that its users database is written by swarm-controller, but nothing ever granted the means. This adds the tool that does it. swarmctl runs as root on the controller's host and acts directly. The rootless alternative was examined and does not work: relocating the users file into a directory the controller owns only turns a write problem into a read problem, because authelia must then reach across the same boundary in the other direction. Making that read work needs either a hand-pinned gid or world-readable password hashes. The user store is two files, one authoritative: users.json is canonical, users.yml is a rendered artifact. That split is what lets the crate work without a YAML parser -- the workspace has none, and adding one costs a crates.io fetch, a lock update and a vendor hash for a schema we fully control and only ever emit. Passwords are generated by authelia rather than passed to it: argv is world-readable, so a password on a command line is readable by any local process for the lifetime of the call. The three derived facts swarmctl needs about the authelia container -- machine, unit and the host-side users path -- become readOnly options on the authelia module rather than literals repeated at the call site.
219 lines
9.9 KiB
Nix
219 lines
9.9 KiB
Nix
# All flake package outputs. Imported per system from flake.nix; the
|
|
# shared rust build wiring (cleanSrc / cargoArtifacts /
|
|
# nativeBuildInputs) comes in via `rust` (see ../rust.nix).
|
|
{
|
|
pkgs,
|
|
craneLib,
|
|
rust,
|
|
self,
|
|
nixpkgs,
|
|
}:
|
|
let
|
|
inherit (pkgs) lib;
|
|
inherit (rust) cleanSrc cargoArtifacts nativeBuildInputs;
|
|
|
|
docsAttrs = import ../docs {
|
|
inherit pkgs self;
|
|
inherit (nixpkgs) lib;
|
|
inherit (nixpkgs.lib) nixosSystem;
|
|
};
|
|
|
|
# Plain vendored Swagger UI dist (./swagger-ui-dist.nix) + the
|
|
# hyperhive-themed overlay on top (./swagger-ui-theme.nix) — bound
|
|
# here (not just inline in the attrset below) so the theme
|
|
# derivation can take the dist derivation as an explicit input.
|
|
swagger-ui-dist = pkgs.callPackage ./swagger-ui-dist.nix { };
|
|
swagger-ui-theme = pkgs.callPackage ./swagger-ui-theme.nix { inherit swagger-ui-dist; };
|
|
|
|
# Every per-binary package: name → description. The single source of
|
|
# truth for the bin list — it drives the per-bin extractor packages
|
|
# and the `default` bundle, so adding a binary is one entry here.
|
|
daemonBins = {
|
|
hive-c0re = "hyperhive host coordinator daemon";
|
|
hive-priv = "hyperhive privileged root helper";
|
|
hive-agent = "hyperhive in-container agent harness serve loop";
|
|
hive-agent-mcp = "hyperhive agent-surface MCP server";
|
|
hive-bash-daemon = "hyperhive per-agent bash-task runner daemon (serves its MCP tools directly over streamable-http)";
|
|
hive-matrix-daemon = "hyperhive per-agent matrix-sdk daemon (serves its MCP tools directly over streamable-http)";
|
|
hive-metric = "hyperhive agent-emitted custom metrics CLI";
|
|
hive-screen-mcp = "hyperhive screen MCP bridge (screenshot + input for GUI agents)";
|
|
hive-forge = "hyperhive Forgejo CLI";
|
|
hive-forge-notify = "hyperhive per-agent Forgejo notification poller daemon";
|
|
hive-github-notify = "hyperhive per-agent github.com notification poller daemon";
|
|
};
|
|
|
|
# ONE compile of the whole workspace (every bin, sharing the
|
|
# prebuilt `cargoArtifacts` dep cache). The per-bin packages below
|
|
# are cheap copy-extractors over this, so workspace lib crates
|
|
# (hive-sh4re, hive-claude, …) compile exactly once instead of once
|
|
# per bin derivation.
|
|
#
|
|
# Tests are kept in the separate `checks.cargo-test` derivation
|
|
# (carries the hyperhive-assets build input for the prompt-template
|
|
# assertions in hive-agent::prompt::tests). Keeping them out of this
|
|
# derivation means a prompt edit doesn't bust the cargo cache.
|
|
workspaceBuild = craneLib.buildPackage {
|
|
src = cleanSrc;
|
|
inherit cargoArtifacts nativeBuildInputs;
|
|
pname = "hyperhive-workspace";
|
|
version = "0.1.0";
|
|
doCheck = false;
|
|
};
|
|
|
|
# Per-bin extractor: COPIES one binary out of the workspace build.
|
|
# A copy, not a symlink — a symlink would keep the whole workspace
|
|
# output (and thus every other binary) in the consumer's runtime
|
|
# closure, defeating the point of the per-bin split. The copied
|
|
# binary's RPATH references only the libs it links, so nix's
|
|
# reference scan gives each package a narrow closure.
|
|
mkBinPackage =
|
|
bin: description:
|
|
pkgs.runCommand bin
|
|
{
|
|
meta = {
|
|
inherit description;
|
|
mainProgram = bin;
|
|
};
|
|
}
|
|
''
|
|
install -Dm755 ${workspaceBuild}/bin/${bin} $out/bin/${bin}
|
|
'';
|
|
|
|
# Operator CLI — extractor plus shell completions and the `wg`
|
|
# wrapper. Suitable for `nix profile install .#hivectl` /
|
|
# `environment.systemPackages = [ …packages.<system>.hivectl ]`
|
|
# when the operator only wants the admin CLI.
|
|
# Completions come from the binary's own `completions <shell>` verb
|
|
# (the single source of truth, so they never drift from the actual
|
|
# verbs). The wireguard-tools wrap makes `hivectl wg` subcommands
|
|
# work before `swarm.wireguard.enable` is set (wg init is the very
|
|
# first setup step). Completion generation runs before wrapProgram
|
|
# since wrapProgram renames the real binary.
|
|
hivectlPkg =
|
|
pkgs.runCommand "hivectl"
|
|
{
|
|
nativeBuildInputs = [
|
|
pkgs.installShellFiles
|
|
pkgs.makeWrapper
|
|
];
|
|
meta = {
|
|
description = "hyperhive operator CLI";
|
|
mainProgram = "hivectl";
|
|
};
|
|
}
|
|
''
|
|
install -Dm755 ${workspaceBuild}/bin/hivectl $out/bin/hivectl
|
|
installShellCompletion --cmd hivectl \
|
|
--bash <("$out/bin/hivectl" completions bash) \
|
|
--zsh <("$out/bin/hivectl" completions zsh) \
|
|
--fish <("$out/bin/hivectl" completions fish)
|
|
wrapProgram "$out/bin/hivectl" \
|
|
--prefix PATH : ${pkgs.wireguard-tools}/bin
|
|
'';
|
|
|
|
# Per-bin split packages. Agent containers depend on the individual
|
|
# bins they actually exec/PATH-need (see harness-base.nix) instead
|
|
# of the `default` bundle — that keeps `hivectl` (dials the *host*
|
|
# admin socket, unreachable from inside a container, drags in
|
|
# `wireguard-tools`) and redundant binaries out of every agent's
|
|
# closure.
|
|
binPkgs = lib.mapAttrs mkBinPackage daemonBins // {
|
|
hivectl = hivectlPkg;
|
|
};
|
|
in
|
|
{
|
|
# All workspace binaries in one derivation — a symlinkJoin over the
|
|
# per-bin packages, pure assembly with no extra compilation. The
|
|
# host module's `services.hyperhive.c0re.package` and `nix build .#`
|
|
# both land here.
|
|
default = pkgs.symlinkJoin {
|
|
name = "hyperhive";
|
|
paths = lib.attrValues binPkgs;
|
|
};
|
|
}
|
|
// binPkgs
|
|
// {
|
|
# Swarm-level controller daemon. Deliberately NOT in `daemonBins`:
|
|
# that list is the core stack — the binaries hive-c0re and the agent
|
|
# harness are made of — and it drives the `default` bundle that
|
|
# `services.hyperhive.c0re.package` points at. This daemon is a
|
|
# separate swarm-scoped service with its own module and its own
|
|
# `package` option, and one hive in a swarm runs it, so folding it
|
|
# into the core bundle would put it in every hive's closure to no end.
|
|
# Uses the same per-bin extractor, just bound on its own.
|
|
swarm-controller = mkBinPackage "swarm-controller" "hyperhive swarm-level controller daemon";
|
|
|
|
# The swarm operator's CLI, out of `daemonBins` for the same reason as
|
|
# the daemon above: it is installed by the swarm-controller module on
|
|
# the one host that runs the controller, and belongs in that hive's
|
|
# closure only. Kept a separate derivation rather than a second binary
|
|
# in the daemon's package so a hive can pin one without the other.
|
|
swarmctl = mkBinPackage "swarmctl" "hyperhive swarm-level operator CLI";
|
|
|
|
# Bundled browser assets — see ./frontend.nix. Output is
|
|
# $out/{dashboard,agent}/ which the Rust binaries serve via
|
|
# tower_http::ServeDir.
|
|
frontend = pkgs.callPackage ./frontend.nix {
|
|
branding-svg = ../../branding/hyperhive.svg;
|
|
};
|
|
# Static runtime assets the rust binaries read via
|
|
# `hive_sh4re::assets::*`: branding/* + prompts/*, plus the
|
|
# rendered agent-configs.png. Split out of the rust derivation so
|
|
# a tweak to e.g. system.md doesn't bust the cargo cache. Build
|
|
# input of the `cargo-test` check but NOT of `packages.default`,
|
|
# so the binary derivation stays cached when a prompt edit ripples
|
|
# through.
|
|
assets = pkgs.callPackage ./assets.nix { };
|
|
# hyperhive-authored Claude Code plugin marketplace (source tree at
|
|
# ../../claude-plugins) — a local-path marketplace spliced into the
|
|
# default `hyperhive.claudeMarketplaces`/`claudePlugins` lists. See
|
|
# ./claude-plugins.nix for the "why a store path, not a repo" rationale.
|
|
claude-plugins = pkgs.callPackage ./claude-plugins.nix { };
|
|
# The repo docs/ markdown tree as a standalone derivation —
|
|
# agents read it in-container (added as a claude additional
|
|
# directory) and the website repo reuses it as a flake input,
|
|
# neither of which needs the branding/prompt assets. See
|
|
# ./reference-docs.nix. (`docs` below is the auto-generated
|
|
# nix-options reference, a different artifact.)
|
|
reference-docs = pkgs.callPackage ./reference-docs.nix { };
|
|
# XDG icon set + .desktop entries for hyperhive processes.
|
|
# Narrow input: only the branding SVG, so unrelated source changes
|
|
# don't bust this derivation's cache.
|
|
xdg-icons = pkgs.callPackage ./hive-xdg-icons.nix {
|
|
hyperhiveSvg = ../../branding/hyperhive.svg;
|
|
};
|
|
# Swagger UI: plain vendored dist + the hyperhive-themed overlay —
|
|
# see ./swagger-ui-dist.nix / ./swagger-ui-theme.nix (both computed
|
|
# above, in `let`). The gateway serves `swagger-ui-theme`'s full
|
|
# tree straight from the store at /api/docs/; a theme tweak is a
|
|
# gateway config change, not a hive-c0re rebuild. `swagger-ui-dist`
|
|
# is exposed too since it's independently useful/inspectable.
|
|
inherit swagger-ui-dist swagger-ui-theme;
|
|
|
|
# Pre-built per-container system closures. Exposed as packages
|
|
# so operators can `nix build .#agent-base-toplevel` (or wire
|
|
# them into their host system closure via the
|
|
# `preBuildAgentTemplates` option on the hive-c0re module —
|
|
# see nix/host-modules/hive-c0re.nix). Speeds up the first agent
|
|
# spawn dramatically because the heavy lifting (nixpkgs +
|
|
# claude-code + hive-agent binary) is already in the store
|
|
# when the meta evaluator goes to build the container.
|
|
#
|
|
# nixosConfigurations are pinned to x86_64-linux (nixos-
|
|
# containers only run native arch), so these toplevels are
|
|
# only useful on an x86_64-linux host — flake check across
|
|
# systems still tolerates evaluating them on aarch64 because
|
|
# they're plain derivations, but `nix build` from a non-x86
|
|
# host would only succeed via a remote x86 builder.
|
|
agent-base-toplevel = self.nixosConfigurations.agent-base.config.system.build.toplevel;
|
|
ruth-toplevel = self.nixosConfigurations.ruth.config.system.build.toplevel;
|
|
|
|
# Auto-generated nix options reference for hyperhive.
|
|
# `docs` bundles host + agent pages into one tree; the split
|
|
# outputs are useful when consumers only want one surface.
|
|
# All three are pure markdown — no rust or frontend deps in
|
|
# the closure, so `nix build .#docs` is cheap.
|
|
docs = docsAttrs.bundle;
|
|
docs-host = docsAttrs.host;
|
|
docs-agent = docsAttrs.agent;
|
|
}
|