parent
0fc77df1a9
commit
8e09f8360a
47 changed files with 98 additions and 1026 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
||||||
"name": "hyperhive",
|
"name": "hyperhive",
|
||||||
"description": "hyperhive-authored Claude Code plugins, shipped hive-wide via the default hyperhive.claudeMarketplaces/claudePlugins nix options (nix/agent-modules/claude-settings.nix). Built as a nix store path and added with `claude plugin marketplace add <path>` - no forge repo or git remote needed. Add a new plugins/<name>/ subtree + one entry below to ship another.",
|
"description": "hyperhive-authored Claude Code plugins, shipped hive-wide via the default services.hyperhive.agent.claudeMarketplaces/claudePlugins nix options (nix/agent-modules/claude-settings.nix). Built as a nix store path and added with `claude plugin marketplace add <path>` - no forge repo or git remote needed. Add a new plugins/<name>/ subtree + one entry below to ship another.",
|
||||||
"owner": {
|
"owner": {
|
||||||
"name": "hyperhive"
|
"name": "hyperhive"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -403,8 +403,8 @@ daemon's socket, so the host that runs the controller is the host that
|
||||||
can serve the UI. A hive that merely _uses_ a swarm has nothing to serve.
|
can serve the UI. A hive that merely _uses_ a swarm has nothing to serve.
|
||||||
|
|
||||||
The UI build is `deploy.swarm-controller.ui.package` (defaulted from this
|
The UI build is `deploy.swarm-controller.ui.package` (defaulted from this
|
||||||
flake's `swarm-ui` package). The older `deploy.swarm-ui.package` and
|
flake's `swarm-ui` package). The older `deploy.swarm-ui.package` still works
|
||||||
`swarm.ui.package` still work and warn at evaluation.
|
and warns at evaluation.
|
||||||
|
|
||||||
The UI answers on `services.hyperhive.swarm.domain` and nothing else. It
|
The UI answers on `services.hyperhive.swarm.domain` and nothing else. It
|
||||||
shares that name with the swarm-controller it fronts — one service to a
|
shares that name with the swarm-controller it fronts — one service to a
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
// resolved from @hive/shared)
|
// resolved from @hive/shared)
|
||||||
//
|
//
|
||||||
// The in-container Rust binary mounts `dist/` (with per-agent
|
// The in-container Rust binary mounts `dist/` (with per-agent
|
||||||
// `hyperhive.frontend.extraFiles` layered on top) as a
|
// `services.hyperhive.agent.frontend.extraFiles` layered on top) as a
|
||||||
// `tower_http::ServeDir` fallback; the layout above keeps every URL
|
// `tower_http::ServeDir` fallback; the layout above keeps every URL
|
||||||
// the HTML references reachable without rewriting paths.
|
// the HTML references reachable without rewriting paths.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "@hive/agent",
|
"name": "@hive/agent",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "hive-ag3nt per-container web UI. Bundled by esbuild into a static dist; served by the in-container Rust binary at runtime via tower_http::ServeDir. Per-agent additions are layered on top via the hyperhive.frontend.extraFiles nix option.",
|
"description": "hive-ag3nt per-container web UI. Bundled by esbuild into a static dist; served by the in-container Rust binary at runtime via tower_http::ServeDir. Per-agent additions are layered on top via the services.hyperhive.agent.frontend.extraFiles nix option.",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node ./build.mjs",
|
"build": "node ./build.mjs",
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
import { useEffect, useRef } from "preact/hooks";
|
import { useEffect, useRef } from "preact/hooks";
|
||||||
import type { ComponentChildren } from "preact";
|
import type { ComponentChildren } from "preact";
|
||||||
|
|
||||||
// Icon 404s when the agent has no `hyperhive.icon` override (no
|
// Icon 404s when the agent has no `services.hyperhive.agent.icon` override (no
|
||||||
// bundled server-side default any more — see
|
// bundled server-side default any more — see
|
||||||
// `hive_agent::web_ui::screen::serve_icon`). Ports app.js's
|
// `hive_agent::web_ui::screen::serve_icon`). Ports app.js's
|
||||||
// `bindHeaderIconFallback` exactly: fire-and-forget load, swap to
|
// `bindHeaderIconFallback` exactly: fire-and-forget load, swap to
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// (`@hive/shared/icons.js`'s `LinkIcon` — an emoji glyph can't match a
|
// (`@hive/shared/icons.js`'s `LinkIcon` — an emoji glyph can't match a
|
||||||
// neighbouring icon's size/weight on any platform, see that file's
|
// neighbouring icon's size/weight on any platform, see that file's
|
||||||
// comment) in the pills cluster that opens a popover listing
|
// comment) in the pills cluster that opens a popover listing
|
||||||
// stats/screen/forge/config + any `hyperhive.dashboardLinks` extras,
|
// stats/screen/forge/config + any `services.hyperhive.agent.dashboardLinks` extras,
|
||||||
// sourced from the backend's `agent_links()` (the single source of
|
// sourced from the backend's `agent_links()` (the single source of
|
||||||
// truth — same list also feeds the dashboard card's icon strip) — plus
|
// truth — same list also feeds the dashboard card's icon strip) — plus
|
||||||
// a `🧭 dashboard` back-link.
|
// a `🧭 dashboard` back-link.
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ export interface AgentState {
|
||||||
|
|
||||||
// Mirrors `hive_agent::web_ui::state::AgentLink` — one meta-nav entry
|
// Mirrors `hive_agent::web_ui::state::AgentLink` — one meta-nav entry
|
||||||
// in the agent page header (stats/screen/forge/config + any
|
// in the agent page header (stats/screen/forge/config + any
|
||||||
// `hyperhive.dashboardLinks` extras). `agent_links()` on the backend
|
// `services.hyperhive.agent.dashboardLinks` extras). `agent_links()` on the backend
|
||||||
// is the single source of truth for what links an agent exposes; see
|
// is the single source of truth for what links an agent exposes; see
|
||||||
// docs/web-ui/agent.md::Header for the kind → URL resolution table.
|
// docs/web-ui/agent.md::Header for the kind → URL resolution table.
|
||||||
export interface AgentLink {
|
export interface AgentLink {
|
||||||
|
|
|
||||||
|
|
@ -663,7 +663,7 @@ export function renderContainers(s) {
|
||||||
// `docs/web-ui/dashboard.md::Container row` + `docs/networking/gateway.md::Vhost map`.
|
// `docs/web-ui/dashboard.md::Container row` + `docs/networking/gateway.md::Vhost map`.
|
||||||
const gatewayLinks = !!(s && s.gateway_enabled);
|
const gatewayLinks = !!(s && s.gateway_enabled);
|
||||||
// Forge public URL: state.forge_public_url (set by the NixOS module
|
// Forge public URL: state.forge_public_url (set by the NixOS module
|
||||||
// from services.hyperhive.forge.publicUrl) or null — never guessed
|
// from services.hyperhive.swarm.forge.publicUrl) or null — never guessed
|
||||||
// from "<hostname>:3000". `null` propagates down to
|
// from "<hostname>:3000". `null` propagates down to
|
||||||
// buildContainerLi/buildAgentMenu, which already hide forge links
|
// buildContainerLi/buildAgentMenu, which already hide forge links
|
||||||
// rather than emit a possibly-wrong one.
|
// rather than emit a possibly-wrong one.
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ export function LinkMatrixAccountForm({
|
||||||
pattern={ACCOUNT_PATTERN}
|
pattern={ACCOUNT_PATTERN}
|
||||||
title="1-63 chars: letters, digits, underscore, hyphen"
|
title="1-63 chars: letters, digits, underscore, hyphen"
|
||||||
// Not "primary" — that reads as naming the hive-provided default
|
// Not "primary" — that reads as naming the hive-provided default
|
||||||
// account (`main`, reserved: see `hyperhive.matrixAccounts`'s own
|
// account (`main`, reserved: see `services.hyperhive.agent.matrixAccounts`'s own
|
||||||
// module doc), which this route can neither create nor touch.
|
// module doc), which this route can neither create nor touch.
|
||||||
// Picking a name with no relationship to that default avoids the
|
// Picking a name with no relationship to that default avoids the
|
||||||
// misread entirely, rather than requiring a reader to already know
|
// misread entirely, rather than requiring a reader to already know
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ or their own daemon instead of living here.
|
||||||
in-agent socket the `hive-agent` harness serves.
|
in-agent socket the `hive-agent` harness serves.
|
||||||
- **`client.rs`** — socket client to the hyperhive broker.
|
- **`client.rs`** — socket client to the hyperhive broker.
|
||||||
- **`send_allow.rs`** — enforces the per-agent
|
- **`send_allow.rs`** — enforces the per-agent
|
||||||
`hyperhive.allowedRecipients` allow-list on `send`.
|
`services.hyperhive.agent.allowedRecipients` allow-list on `send`.
|
||||||
- **`paths.rs`** — socket + state path resolution shared with the
|
- **`paths.rs`** — socket + state path resolution shared with the
|
||||||
harness's own `paths.rs` conventions.
|
harness's own `paths.rs` conventions.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ You are hyperhive agent `{label}` (qualified: `{qualified_label}`){hive_identity
|
||||||
Tools (hyperhive surface). Full signature + behavior for each comes from the tool's own MCP description (you already received it via the MCP tool schema) — this is just the map of what exists and which ones are gated, so you know where to look:
|
Tools (hyperhive surface). Full signature + behavior for each comes from the tool's own MCP description (you already received it via the MCP tool schema) — this is just the map of what exists and which ones are gated, so you know where to look:
|
||||||
|
|
||||||
- **Inbox / messaging** (always available): `mcp__hyperhive__recv`, `mcp__hyperhive__ack_until`, `mcp__hyperhive__send`, `mcp__hyperhive__get_loose_ends`, `mcp__hyperhive__cancel_loose_end`, `mcp__hyperhive__mark_todos_done`, `mcp__hyperhive__remind`, `mcp__hyperhive__set_status`, `mcp__hyperhive__get_agent_meta`. `send` reaches peers on this hive only; **reach the operator over matrix** if you have the matrix MCP tools (`mcp__matrix__send_dm` or `mcp__matrix__send_message`); without them the operator reads your `set_status` line and turn output on the dashboard, and your logs. `send(to: "operator")` is refused. One habit worth internalizing beyond the tool descriptions themselves: prefer ending the turn over repeatedly polling `recv` when idle (only turn-boundaries observe in-container todo wakes — bash-task completions, matrix unread, forge activity — and ending the turn is also your checkpoint). For a large todo backlog (`get_loose_ends` caps at 40 rows), clear reviewed ids in bulk with `mark_todos_done` rather than cancelling one at a time — there's no blind range-clear, only ids you've actually looked at.
|
- **Inbox / messaging** (always available): `mcp__hyperhive__recv`, `mcp__hyperhive__ack_until`, `mcp__hyperhive__send`, `mcp__hyperhive__get_loose_ends`, `mcp__hyperhive__cancel_loose_end`, `mcp__hyperhive__mark_todos_done`, `mcp__hyperhive__remind`, `mcp__hyperhive__set_status`, `mcp__hyperhive__get_agent_meta`. `send` reaches peers on this hive only; **reach the operator over matrix** if you have the matrix MCP tools (`mcp__matrix__send_dm` or `mcp__matrix__send_message`); without them the operator reads your `set_status` line and turn output on the dashboard, and your logs. `send(to: "operator")` is refused. One habit worth internalizing beyond the tool descriptions themselves: prefer ending the turn over repeatedly polling `recv` when idle (only turn-boundaries observe in-container todo wakes — bash-task completions, matrix unread, forge activity — and ending the turn is also your checkpoint). For a large todo backlog (`get_loose_ends` caps at 40 rows), clear reviewed ids in bulk with `mark_todos_done` rather than cancelling one at a time — there's no blind range-clear, only ids you've actually looked at.
|
||||||
- **Extra MCP tools** (some agents only): `mcp__<server>__<tool>` — agent-specific (matrix client, scraper, db connector, etc.) declared in your `agent.nix` under `hyperhive.extraMcpServers`. First-class tools, already operator-approved at deploy time.
|
- **Extra MCP tools** (some agents only): `mcp__<server>__<tool>` — agent-specific (matrix client, scraper, db connector, etc.) declared in your `agent.nix` under `services.hyperhive.agent.extraMcpServers`. First-class tools, already operator-approved at deploy time.
|
||||||
|
|
||||||
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — open a PR on your `agent-configs/<name>` repo, or contact the operator directly. Config repos live at `/agents/{label}/config/` (read-only inside your container). All changes flow through operator-approved commits.
|
Need new packages, env vars, or other NixOS config for yourself? You can't edit your own config directly — open a PR on your `agent-configs/<name>` repo, or contact the operator directly. Config repos live at `/agents/{label}/config/` (read-only inside your container). All changes flow through operator-approved commits.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,8 +169,8 @@ pub(super) struct StateSnapshot {
|
||||||
links: Vec<AgentLink>,
|
links: Vec<AgentLink>,
|
||||||
/// Public URL of the forge (e.g.
|
/// Public URL of the forge (e.g.
|
||||||
/// `"https://forge.pr1ma.darkest.space"`). Sourced from
|
/// `"https://forge.pr1ma.darkest.space"`). Sourced from
|
||||||
/// `HIVE_FORGE_PUBLIC_URL` (set from `services.hyperhive.forge.
|
/// `HIVE_FORGE_PUBLIC_URL` (set from
|
||||||
/// publicUrl`); `None` when unset. The frontend uses this to build
|
/// `services.hyperhive.swarm.forge.publicUrl`); `None` when unset. The frontend uses this to build
|
||||||
/// forge nav-strip links, and **hides** the forge link entirely
|
/// forge nav-strip links, and **hides** the forge link entirely
|
||||||
/// when absent rather than guessing `<hostname>:3000`.
|
/// when absent rather than guessing `<hostname>:3000`.
|
||||||
forge_public_url: Option<String>,
|
forge_public_url: Option<String>,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
# hive-screen-mcp
|
# hive-screen-mcp
|
||||||
|
|
||||||
A stdio MCP server that exposes screenshot, keyboard, and mouse tools to agents
|
A stdio MCP server that exposes screenshot, keyboard, and mouse tools to agents
|
||||||
running a Weston Wayland compositor (`hyperhive.gui.enable = true`).
|
running a Weston Wayland compositor (`services.hyperhive.agent.gui.enable = true`).
|
||||||
|
|
||||||
## When to use it
|
## When to use it
|
||||||
|
|
||||||
This crate is the bridge for **GUI agents** — agents that drive graphical
|
This crate is the bridge for **GUI agents** — agents that drive graphical
|
||||||
applications (browsers, desktop tools, game UIs) and need to see and interact
|
applications (browsers, desktop tools, game UIs) and need to see and interact
|
||||||
with a Weston Wayland display. If your agent does not have `hyperhive.gui.enable
|
with a Weston Wayland display. If your agent does not have `services.hyperhive.agent.gui.enable
|
||||||
= true`, none of these tools will function.
|
= true`, none of these tools will function.
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
@ -27,7 +27,7 @@ module; `HIVE_GUI_VNC_PORT` is set by the harness service (defaults to `5900`).
|
||||||
## Shape
|
## Shape
|
||||||
|
|
||||||
One binary (`hive-screen-mcp`) launched over stdio. The agent runtime wires it
|
One binary (`hive-screen-mcp`) launched over stdio. The agent runtime wires it
|
||||||
as an extra MCP server when `hyperhive.gui.enable = true`. There are no library
|
as an extra MCP server when `services.hyperhive.agent.gui.enable = true`. There are no library
|
||||||
exports — it is a self-contained binary crate.
|
exports — it is a self-contained binary crate.
|
||||||
|
|
||||||
See the crate-root `//!` docs for the full per-tool implementation notes and
|
See the crate-root `//!` docs for the full per-tool implementation notes and
|
||||||
|
|
|
||||||
|
|
@ -19,23 +19,6 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# What an `agent.nix` still setting the dropped per-agent matrix switch is
|
|
||||||
# told. Shared by the two `mkRemovedOptionModule` entries below, one per
|
|
||||||
# spelling of the path.
|
|
||||||
matrixEnableRemoved = ''
|
|
||||||
The per-agent matrix switch is gone. Matrix is enabled for an agent exactly
|
|
||||||
when it has at least one services.hyperhive.agent.matrixAccounts entry, and
|
|
||||||
the hive-internal `main` entry is declared for you whenever
|
|
||||||
services.hyperhive.agent.matrix.url is non-null.
|
|
||||||
|
|
||||||
- `enable = true` was the default: drop the line, nothing else to do.
|
|
||||||
- `enable = false`: set services.hyperhive.agent.matrix.url = null instead
|
|
||||||
(and declare no accounts of your own). That is what leaves the account set
|
|
||||||
empty, which is now what suppresses the daemon, its path watcher and the
|
|
||||||
injected extraMcpServers.matrix entry.
|
|
||||||
|
|
||||||
See docs/tools/matrix.md.
|
|
||||||
'';
|
|
||||||
hiveNameRemoved = ''
|
hiveNameRemoved = ''
|
||||||
An agent reads its hive's name at runtime from /etc/hyperhive-hive-facts,
|
An agent reads its hive's name at runtime from /etc/hyperhive-hive-facts,
|
||||||
which the hive writes into every container, so no agent build sets it.
|
which the hive writes into every container, so no agent build sets it.
|
||||||
|
|
@ -71,36 +54,12 @@ in
|
||||||
./packages.nix
|
./packages.nix
|
||||||
./queue.nix
|
./queue.nix
|
||||||
./queue-identity.nix
|
./queue-identity.nix
|
||||||
./renamed-options.nix
|
|
||||||
./user.nix
|
./user.nix
|
||||||
./screen.nix
|
./screen.nix
|
||||||
./weston-vnc.nix
|
./weston-vnc.nix
|
||||||
(lib.mkRemovedOptionModule [ "hyperhive" "web" "useUnixSocket" ] ''
|
# The hive supplies both at runtime; a definition fails the eval, naming
|
||||||
Unix socket mode is always enabled for all agents. Remove the
|
# where the value comes from.
|
||||||
setting from your agent.nix.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "hyperhive" "allowedBashPatterns" ] ''
|
|
||||||
The built-in Bash tool is fully disabled; agents use
|
|
||||||
mcp__bash__run instead. Remove the setting from your agent.nix.
|
|
||||||
'')
|
|
||||||
# The dropped per-agent matrix switch. A removal, not a silent delete,
|
|
||||||
# because the definition that *changes meaning* is `false`: left undeclared
|
|
||||||
# it would be ignored and the agent would quietly gain the matrix tools its
|
|
||||||
# operator turned off. Failing the eval with the replacement spelling is the
|
|
||||||
# only outcome that cannot do that.
|
|
||||||
#
|
|
||||||
# Both spellings, for the same reason ../host-modules/deploy.nix lists both
|
|
||||||
# of `swarm|deploy.matrix.registrationTokenFile`: an existing agent.nix may
|
|
||||||
# carry either the `hyperhive.*` path or the `services.hyperhive.agent.*`
|
|
||||||
# one, and only the one it actually carries will fire. Neither is an entry
|
|
||||||
# in ./renamed-options.nix — a rename pointing at an undeclared option
|
|
||||||
# breaks evaluation for everyone, removed or not.
|
|
||||||
(lib.mkRemovedOptionModule [ "hyperhive" "matrix" "enable" ] matrixEnableRemoved)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "agent" "matrix" "enable" ] matrixEnableRemoved)
|
|
||||||
# Both spellings, for the reason given above.
|
|
||||||
(lib.mkRemovedOptionModule [ "hyperhive" "hiveName" ] hiveNameRemoved)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "agent" "hiveName" ] hiveNameRemoved)
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "agent" "hiveName" ] hiveNameRemoved)
|
||||||
(lib.mkRemovedOptionModule [ "hyperhive" "claudeMemoryMaxBytes" ] memoryMaxBytesRemoved)
|
|
||||||
(lib.mkRemovedOptionModule [
|
(lib.mkRemovedOptionModule [
|
||||||
"services"
|
"services"
|
||||||
"hyperhive"
|
"hyperhive"
|
||||||
|
|
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
# Deprecation shims for the agent tier's top-level `hyperhive.*` spelling.
|
|
||||||
#
|
|
||||||
# Per-agent options live at `services.hyperhive.agent.<name>`, beside the host
|
|
||||||
# tier's `services.hyperhive.*`. These entries keep an `agent.nix` that still
|
|
||||||
# uses the top-level `hyperhive.<name>` spelling evaluating, with a
|
|
||||||
# deprecation warning.
|
|
||||||
#
|
|
||||||
# ⚠️ One entry per LEAF, not per namespace. A single entry for a parent path
|
|
||||||
# only covers its children when the parent is a submodule-typed option; every
|
|
||||||
# nested option here (`user`, `mcp`, `otel`, …) is a plain attrset of
|
|
||||||
# declarations instead, so each leaf needs its own line — the same reason
|
|
||||||
# `../host-modules/deploy.nix` renames the CI runner's knobs one by one.
|
|
||||||
{ lib, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "_bashEnvFragments" ]
|
|
||||||
[ "services" "hyperhive" "agent" "_bashEnvFragments" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "allowedRecipients" ]
|
|
||||||
[ "services" "hyperhive" "agent" "allowedRecipients" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "autoCompact" ]
|
|
||||||
[ "services" "hyperhive" "agent" "autoCompact" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "availableModels" ]
|
|
||||||
[ "services" "hyperhive" "agent" "availableModels" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "backendEnvironmentFile" ]
|
|
||||||
[ "services" "hyperhive" "agent" "backendEnvironmentFile" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "cargo" "shortMessages" ]
|
|
||||||
[ "services" "hyperhive" "agent" "cargo" "shortMessages" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "claudeCodePath" ]
|
|
||||||
[ "services" "hyperhive" "agent" "claudeCodePath" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "claudeMarketplaces" ]
|
|
||||||
[ "services" "hyperhive" "agent" "claudeMarketplaces" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "claudePlugins" ]
|
|
||||||
[ "services" "hyperhive" "agent" "claudePlugins" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "claudePluginsAutoUpdate" ]
|
|
||||||
[ "services" "hyperhive" "agent" "claudePluginsAutoUpdate" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "dashboardLinks" ]
|
|
||||||
[ "services" "hyperhive" "agent" "dashboardLinks" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "docs" "enable" ]
|
|
||||||
[ "services" "hyperhive" "agent" "docs" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "docs" "source" ]
|
|
||||||
[ "services" "hyperhive" "agent" "docs" "source" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "effortLevel" ]
|
|
||||||
[ "services" "hyperhive" "agent" "effortLevel" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "extraMcpServers" ]
|
|
||||||
[ "services" "hyperhive" "agent" "extraMcpServers" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "extraWebProxies" ]
|
|
||||||
[ "services" "hyperhive" "agent" "extraWebProxies" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "forge" "url" ]
|
|
||||||
[ "services" "hyperhive" "agent" "forge" "url" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "frontend" "dist" ]
|
|
||||||
[ "services" "hyperhive" "agent" "frontend" "dist" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "frontend" "extraFiles" ]
|
|
||||||
[ "services" "hyperhive" "agent" "frontend" "extraFiles" ]
|
|
||||||
)
|
|
||||||
# `frontend.mergedDist` deliberately has NO entry:
|
|
||||||
# it is `readOnly` and ./frontend.nix already defines it, and a rename
|
|
||||||
# module contributes a *definition* to its target — so a shim for it makes
|
|
||||||
# every evaluation fail with "set multiple times". Nothing could have set
|
|
||||||
# it anyway; a reader of the old path gets "option does not exist",
|
|
||||||
# which says the same thing sooner. Same reasoning as the `hostUsersFile`
|
|
||||||
# exclusion in ../host-modules/deploy.nix.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "github" "enable" ]
|
|
||||||
[ "services" "hyperhive" "agent" "github" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "gui" "enable" ]
|
|
||||||
[ "services" "hyperhive" "agent" "gui" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "gui" "vncPort" ]
|
|
||||||
[ "services" "hyperhive" "agent" "gui" "vncPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule [ "hyperhive" "icon" ] [ "services" "hyperhive" "agent" "icon" ])
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "logs" "queryUrl" ]
|
|
||||||
[ "services" "hyperhive" "agent" "logs" "queryUrl" ]
|
|
||||||
)
|
|
||||||
# `matrix.enable` is deliberately absent from this list: it has no
|
|
||||||
# replacement option, and a rename pointing at an undeclared option
|
|
||||||
# breaks evaluation for everyone. Both of its spellings are
|
|
||||||
# `mkRemovedOptionModule` in ./default.nix instead.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "matrix" "url" ]
|
|
||||||
[ "services" "hyperhive" "agent" "matrix" "url" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "matrixAccounts" ]
|
|
||||||
[ "services" "hyperhive" "agent" "matrixAccounts" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "mcp" "bashHttpPort" ]
|
|
||||||
[ "services" "hyperhive" "agent" "mcp" "bashHttpPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "mcp" "httpPort" ]
|
|
||||||
[ "services" "hyperhive" "agent" "mcp" "httpPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "mcp" "matrixHttpPort" ]
|
|
||||||
[ "services" "hyperhive" "agent" "mcp" "matrixHttpPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "mcp" "subagentHttpPort" ]
|
|
||||||
[ "services" "hyperhive" "agent" "mcp" "subagentHttpPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule [ "hyperhive" "model" ] [ "services" "hyperhive" "agent" "model" ])
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "debug" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "debug" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "enable" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "endpoint" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "endpoint" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "extraResourceAttributes" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "extraResourceAttributes" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "metricIntervalMs" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "metricIntervalMs" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "otel" "protocol" ]
|
|
||||||
[ "services" "hyperhive" "agent" "otel" "protocol" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule [ "hyperhive" "packages" ] [ "services" "hyperhive" "agent" "packages" ])
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "queue" "natsUrl" ]
|
|
||||||
[ "services" "hyperhive" "agent" "queue" "natsUrl" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "queue" "tokenEndpoint" ]
|
|
||||||
[ "services" "hyperhive" "agent" "queue" "tokenEndpoint" ]
|
|
||||||
)
|
|
||||||
# `queue.clientIdFile` / `queue.clientSecretFile` are excluded for the
|
|
||||||
# `mergedDist` reason above: both are `readOnly`, so a shim's definition
|
|
||||||
# collides with the option's own and breaks every evaluation. They are
|
|
||||||
# derived paths no agent config could have set.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "swarmName" ]
|
|
||||||
[ "services" "hyperhive" "agent" "swarmName" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "useApiKey" ]
|
|
||||||
[ "services" "hyperhive" "agent" "useApiKey" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "user" "gid" ]
|
|
||||||
[ "services" "hyperhive" "agent" "user" "gid" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "user" "name" ]
|
|
||||||
[ "services" "hyperhive" "agent" "user" "name" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "user" "passwordlessSudo" ]
|
|
||||||
[ "services" "hyperhive" "agent" "user" "passwordlessSudo" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "hyperhive" "user" "uid" ]
|
|
||||||
[ "services" "hyperhive" "agent" "user" "uid" ]
|
|
||||||
)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -212,9 +212,9 @@ let
|
||||||
grafana, the swarm controller, authelia, …).
|
grafana, the swarm controller, authelia, …).
|
||||||
- [per-agent options](agent.md) — options declared in
|
- [per-agent options](agent.md) — options declared in
|
||||||
`nix/agent-modules/`, visible from every `agent.nix`
|
`nix/agent-modules/`, visible from every `agent.nix`
|
||||||
(`hyperhive.model`, `hyperhive.allowedRecipients`,
|
(`services.hyperhive.agent.model`, `services.hyperhive.agent.allowedRecipients`,
|
||||||
`hyperhive.extraMcpServers`, `hyperhive.frontend.*`,
|
`services.hyperhive.agent.extraMcpServers`, `services.hyperhive.agent.frontend.*`,
|
||||||
`hyperhive.forge.*`, `hyperhive.matrix.*`, `hyperhive.gui.*`).
|
`services.hyperhive.agent.forge.*`, `services.hyperhive.agent.matrix.*`, `services.hyperhive.agent.gui.*`).
|
||||||
|
|
||||||
Regenerate with `nix build .#docs` (bundle), `.#docs-host`,
|
Regenerate with `nix build .#docs` (bundle), `.#docs-host`,
|
||||||
`.#docs-swarm`, `.#docs-deploy`, or `.#docs-agent`. Consumed by the
|
`.#docs-swarm`, `.#docs-deploy`, or `.#docs-agent`. Consumed by the
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@
|
||||||
./swarm.nix
|
./swarm.nix
|
||||||
./host-ca-removed.nix
|
./host-ca-removed.nix
|
||||||
./nats-callout-removed.nix
|
./nats-callout-removed.nix
|
||||||
./swarm-peers-removed.nix
|
|
||||||
./swarm-required-services.nix
|
./swarm-required-services.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,7 @@
|
||||||
#
|
#
|
||||||
# ⚠️ The renames below are deliberately in this one file rather than
|
# ⚠️ The renames below are deliberately in this one file rather than
|
||||||
# spread across the service modules, so all of them have a single home
|
# spread across the service modules, so all of them have a single home
|
||||||
# and a single file to delete when the deprecation window closes — the
|
# and a single file to delete when the deprecation window closes.
|
||||||
# shape ./swarm-peers-removed.nix already uses.
|
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
# The swarm UI's own switch, in both spellings. Accepted and ignored: a
|
# The swarm UI's own switch, in both spellings. Accepted and ignored: a
|
||||||
|
|
@ -46,7 +45,7 @@ let
|
||||||
lib.optional (value != null)
|
lib.optional (value != null)
|
||||||
"services.hyperhive.${path} no longer has any effect: swarm-ui now runs wherever swarm-controller runs. Remove this setting; services.hyperhive.deploy.swarm-controller.enable decides it.";
|
"services.hyperhive.${path} no longer has any effect: swarm-ui now runs wherever swarm-controller runs. Remove this setting; services.hyperhive.deploy.swarm-controller.enable decides it.";
|
||||||
|
|
||||||
# Shared by the two removed spellings of the status-publishing secret below.
|
# The removed status-publishing secret below.
|
||||||
statusSecretRemoved = ''
|
statusSecretRemoved = ''
|
||||||
hive-c0re reads this hive's status-publishing client secret from the
|
hive-c0re reads this hive's status-publishing client secret from the
|
||||||
swarm's secret store, under the hive's own certificate
|
swarm's secret store, under the hive's own certificate
|
||||||
|
|
@ -57,101 +56,11 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
# Same type, same meaning, new path — so a rename carries it exactly
|
|
||||||
# and existing configs keep evaluating with one warning naming both
|
|
||||||
# paths. Precedent: ./hive-forge/service.nix, ./hive-matrix.nix.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "grafana" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "grafana" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "grafana" "datasourceUrl" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "grafana" "datasourceUrl" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "grafana" "logsDatasourceUrl" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "grafana" "logsDatasourceUrl" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "grafana" "plugins" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "grafana" "plugins" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victoriametrics" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victoriametrics" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "victoriametrics" "port" ] ''
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "victoriametrics" "port" ] ''
|
||||||
VictoriaMetrics listens on a unix socket in a network namespace of its
|
VictoriaMetrics listens on a unix socket in a network namespace of its
|
||||||
own, and the gateway reaches it there, so it binds no host port. Remove
|
own, and the gateway reaches it there, so it binds no host port. Remove
|
||||||
this definition.
|
this definition.
|
||||||
'')
|
'')
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victorialogs" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victorialogs" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "controller" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "controller" "forgeTokenFile" ] ''
|
|
||||||
The controller reads its forge token from the swarm's secret store, under
|
|
||||||
its own certificate, and forgejo-swarm-controller-account in the forge's
|
|
||||||
container puts it there. Remove this definition; the file it named is
|
|
||||||
read by nothing now and can be deleted.
|
|
||||||
'')
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "controller" "authBridgeUrl" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "authBridgeUrl" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "controller" "queue" "clientSecretFile" ]
|
|
||||||
''
|
|
||||||
The controller reads its queue client secret from the swarm's secret
|
|
||||||
store, under its own certificate (deploy.swarm-controller.baoClientCertFile),
|
|
||||||
and swarm-secret-publish on the host that runs authelia puts it there.
|
|
||||||
Remove this definition; the file it named is read by nothing now and can
|
|
||||||
be deleted.
|
|
||||||
''
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "authelia" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "authelia" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "authelia" "usersFile" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "authelia" "usersFile" ]
|
|
||||||
)
|
|
||||||
# `hostClientSecretDir`, `hostUsersFile` and `grafana.socketDir`
|
|
||||||
# deliberately have NO entry here. A rename module contributes a
|
|
||||||
# *definition* to its target, and all three are `readOnly`, which refuses a
|
|
||||||
# second one — so a shim for any of them makes every evaluation fail with
|
|
||||||
# "set multiple times", naming the option's own default as the rival
|
|
||||||
# definition.
|
|
||||||
#
|
|
||||||
# The first two are derived, so nothing could ever have set them and a
|
|
||||||
# shim's only customer is a reader of the old path. `grafana.socketDir` was
|
|
||||||
# a plain settable option; only a test fixture set it in
|
|
||||||
# this tree, but a deployment outside it can have. That setter now fails
|
|
||||||
# evaluation with "option does not exist" at the old path, rather than
|
|
||||||
# being carried to the new one.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "nats" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "nats" "enable" ]
|
|
||||||
)
|
|
||||||
# `tokenEndpoint` stays under `swarm.*`: it is the swarm IdP's one
|
|
||||||
# address, identical on every hive, where this is "the queue as seen from
|
|
||||||
# here".
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "statusPublish" "natsUrl" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "hive-controller" "statusPublish" "natsUrl" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [
|
|
||||||
"services"
|
|
||||||
"hyperhive"
|
|
||||||
"swarm"
|
|
||||||
"statusPublish"
|
|
||||||
"clientSecretFile"
|
|
||||||
] statusSecretRemoved)
|
|
||||||
(lib.mkRemovedOptionModule [
|
(lib.mkRemovedOptionModule [
|
||||||
"services"
|
"services"
|
||||||
"hyperhive"
|
"hyperhive"
|
||||||
|
|
@ -160,27 +69,11 @@ in
|
||||||
"statusPublish"
|
"statusPublish"
|
||||||
"clientSecretFile"
|
"clientSecretFile"
|
||||||
] statusSecretRemoved)
|
] statusSecretRemoved)
|
||||||
# Both old spellings of "run a hive here" forward to the one switch.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "hive-controller" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "c0re" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "hive-controller" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "otel" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-otel" "enable" ]
|
|
||||||
)
|
|
||||||
# ⚠️ Not to be confused with `services.hyperhive.otel.clientSecretFile`,
|
|
||||||
# a different option on the hive tier that is not part of this table. A
|
|
||||||
# bare `clientSecretFile` matches five distinct options across the tree.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "otel" "clientSecretFile" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-otel" "clientSecretFile" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# Same type, same meaning, new path — so a rename carries it exactly
|
||||||
|
# and existing configs keep evaluating with one warning naming both
|
||||||
|
# paths.
|
||||||
|
#
|
||||||
# The runner moved from `deploy.forgejo.ci` to `deploy.ci-runner` with
|
# The runner moved from `deploy.forgejo.ci` to `deploy.ci-runner` with
|
||||||
# every option keeping its type and meaning, so the old paths forward.
|
# every option keeping its type and meaning, so the old paths forward.
|
||||||
(lib.mkRenamedOptionModule
|
(lib.mkRenamedOptionModule
|
||||||
|
|
@ -219,69 +112,6 @@ in
|
||||||
[ "services" "hyperhive" "deploy" "bao" "servicesIssuerClientKeyFile" ]
|
[ "services" "hyperhive" "deploy" "bao" "servicesIssuerClientKeyFile" ]
|
||||||
)
|
)
|
||||||
|
|
||||||
# The runner toggle sat under `swarm.forge.ci` before `deploy.forgejo.ci`.
|
|
||||||
# Both were per-host, so each forwards straight to its final path.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "ci" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "ci-runner" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "ci" "name" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "ci-runner" "name" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "ci" "concurrency" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "ci-runner" "concurrency" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "ci" "labels" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "ci-runner" "labels" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "ci" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "ci-runner" "package" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# The rest of the forge split. What stays under `swarm.forge` is what the
|
|
||||||
# forge IS from any hive's point of view — the names and ports it answers
|
|
||||||
# on, the URLs it advertises, the client id it is registered under; the
|
|
||||||
# two renamed here are what the host running it decides. Its package is
|
|
||||||
# renamed further down with the other `*.package` entries. The two removed
|
|
||||||
# here named host files that the swarm secret store now replaces.
|
|
||||||
#
|
|
||||||
# `mirrors` renames in one entry rather than one per field: it is a single
|
|
||||||
# option of a list-of-submodule type, so the rename carries its whole
|
|
||||||
# value.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "openFirewall" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "forgejo" "openFirewall" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "mirrors" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "forgejo" "mirrors" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "forge" "sso" "clientSecretFile" ] ''
|
|
||||||
The forge's OIDC client secret is fetched from the swarm secret store
|
|
||||||
(swarm-bao-forge-oidc) into a fixed runtime path. Remove this
|
|
||||||
definition.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "forge" "hostSwarmControllerTokenFile" ]
|
|
||||||
''
|
|
||||||
The forge publishes the swarm-controller's forge token to the swarm
|
|
||||||
secret store (forgejo-swarm-controller-account), and the controller
|
|
||||||
reads it there. Remove this definition; the file it named is read by
|
|
||||||
nothing now and can be deleted.
|
|
||||||
''
|
|
||||||
)
|
|
||||||
|
|
||||||
# The homeserver, split the same way. `swarm.matrix` keeps what it IS to
|
|
||||||
# every hive — the name it answers to, the URLs it is reached on, the
|
|
||||||
# client id it is registered under. These six are what the host
|
|
||||||
# running it decides; its two packages are renamed further down with
|
|
||||||
# the other `*.package` entries. ⚠️ `enable` is NOT here: its shim lives in
|
|
||||||
# ./hive-matrix.nix, so that file is the one
|
|
||||||
# to check before assuming this table is the whole matrix story.
|
|
||||||
#
|
|
||||||
# The homeserver's port and its firewall switch, removed rather than
|
# The homeserver's port and its firewall switch, removed rather than
|
||||||
# renamed: tuwunel listens on a unix socket only the gateway reaches, so
|
# renamed: tuwunel listens on a unix socket only the gateway reaches, so
|
||||||
# there is no host port to choose or open.
|
# there is no host port to choose or open.
|
||||||
|
|
@ -291,111 +121,20 @@ in
|
||||||
Remove this definition. Clients and federation peers reach it at
|
Remove this definition. Clients and federation peers reach it at
|
||||||
services.hyperhive.swarm.matrix.gatewayHost.
|
services.hyperhive.swarm.matrix.gatewayHost.
|
||||||
'')
|
'')
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "openFirewall" ] ''
|
|
||||||
The homeserver no longer listens on a host port, so there is no port
|
|
||||||
to open. Remove this definition. Reach from outside the host goes
|
|
||||||
through the gateway: services.hyperhive.gateway.openFirewall.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "openFirewall" ] ''
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "openFirewall" ] ''
|
||||||
The homeserver no longer listens on a host port, so there is no port
|
The homeserver no longer listens on a host port, so there is no port
|
||||||
to open. Remove this definition. Reach from outside the host goes
|
to open. Remove this definition. Reach from outside the host goes
|
||||||
through the gateway: services.hyperhive.gateway.openFirewall.
|
through the gateway: services.hyperhive.gateway.openFirewall.
|
||||||
'')
|
'')
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "trustedServers" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "trustedServers" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "maxRequestSize" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "maxRequestSize" ]
|
|
||||||
)
|
|
||||||
# Both spellings of the registration token, removed rather than renamed:
|
|
||||||
# the homeserver does not accept a shared registration secret at all,
|
|
||||||
# so there is no path to point a definition at. Accounts are created by
|
|
||||||
# the swarm's appservice.
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "registrationTokenFile" ] ''
|
|
||||||
The matrix registration token is gone: swarm-controller creates accounts
|
|
||||||
as the swarm's appservice instead, so there is no shared secret for
|
|
||||||
tuwunel to check. Remove this definition — nothing needs replacing.
|
|
||||||
The old token file at /var/lib/hyperhive/matrix-register-token is read by
|
|
||||||
nothing now and can be deleted. See docs/integrations/matrix.md.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "registrationTokenFile" ] ''
|
|
||||||
The matrix registration token is gone: swarm-controller creates accounts
|
|
||||||
as the swarm's appservice instead, so there is no shared secret for
|
|
||||||
tuwunel to check. Remove this definition — nothing needs replacing.
|
|
||||||
The old token file at /var/lib/hyperhive/matrix-register-token is read by
|
|
||||||
nothing now and can be deleted. See docs/integrations/matrix.md.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "gui" "enable" ] ''
|
|
||||||
The matrix web client has no on/off switch: every host that runs the
|
|
||||||
homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost,
|
|
||||||
and the swarm UI links to it. Remove this definition.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ] ''
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ] ''
|
||||||
The matrix web client has no on/off switch: every host that runs the
|
The matrix web client has no on/off switch: every host that runs the
|
||||||
homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost,
|
homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost,
|
||||||
and the swarm UI links to it. Remove this definition.
|
and the swarm UI links to it. Remove this definition.
|
||||||
'')
|
'')
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "sso" "clientSecretFile" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "sso" "clientSecretFile" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Retention is read only where the container is defined, so it is a
|
# The hive CA's lifetime and its leaves', removed rather than renamed: no
|
||||||
# decision of the host running the store rather than something the swarm
|
# hive CA is generated, and the store's per-hive role sets the gateway
|
||||||
# agrees on. The two stores keep their domain and port in `swarm.*`,
|
# leaf's lifetime.
|
||||||
# because a client hive needs those to reach them; `package` followed
|
|
||||||
# `enable` and `retentionPeriod` across in a later slice.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victoriametrics" "retentionPeriod" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victoriametrics" "retentionPeriod" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victorialogs" "retentionPeriod" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victorialogs" "retentionPeriod" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# The switch over all of the above. `allSwarmServices` says whether THIS
|
|
||||||
# host runs every service the swarm requires; those services are
|
|
||||||
# required of the SWARM, so the name is about the swarm rather than this
|
|
||||||
# host's wiring.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "enableRequiredServices" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "allSwarmServices" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# The mode above that one lives under `deploy`, not at the TOP of
|
|
||||||
# `services.hyperhive`: that namespace is everything about hyperhive, not
|
|
||||||
# the settings of a single hive. `singleHostSwarm` names what the mode
|
|
||||||
# asserts — the whole swarm runs on this host — instead of its mechanism.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "enableAllLocalDefaults" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "singleHostSwarm" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# The hive TLS state dir lives under `deploy.hive-controller` (the
|
|
||||||
# hive-c0re daemon's namespace), not at the TOP of `services.hyperhive`,
|
|
||||||
# which is everything about hyperhive rather than the settings of one hive.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "tls" "stateDir" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "hive-controller" "tls" "stateDir" ]
|
|
||||||
)
|
|
||||||
# The hive CA's lifetime and its leaves', both spellings, removed rather
|
|
||||||
# than renamed: no hive CA is generated, and the store's per-hive role
|
|
||||||
# sets the gateway leaf's lifetime.
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "tls" "caValidityDays" ] ''
|
|
||||||
No hive CA is generated any more: the gateway leaf is issued by the
|
|
||||||
secret store's pki mount, whose per-hive role sets its lifetime
|
|
||||||
(services.hyperhive.deploy.bao.servicesPkiLeafTtlHours). Remove this
|
|
||||||
definition. See docs/swarm/ca.md.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "tls" "leafValidityDays" ] ''
|
|
||||||
No hive CA is generated any more: the gateway leaf is issued by the
|
|
||||||
secret store's pki mount, whose per-hive role sets its lifetime
|
|
||||||
(services.hyperhive.deploy.bao.servicesPkiLeafTtlHours). Remove this
|
|
||||||
definition. See docs/swarm/ca.md.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule
|
(lib.mkRemovedOptionModule
|
||||||
[ "services" "hyperhive" "deploy" "hive-controller" "tls" "caValidityDays" ]
|
[ "services" "hyperhive" "deploy" "hive-controller" "tls" "caValidityDays" ]
|
||||||
''
|
''
|
||||||
|
|
@ -415,98 +154,12 @@ in
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
|
|
||||||
# The WireGuard mesh, whole. Unlike every rename above this one covers a
|
# `deploy.swarm-ui` keeps only its ignored `enable` (declared below); its
|
||||||
# namespace rather than a toggle: nothing under it is a fact another hive
|
# `package` is the controller's UI package.
|
||||||
# reads. A peer needs this host's `wireguardEndpoint` — the roster entry
|
|
||||||
# in ./swarm.nix, which stays — and nothing about the interface this host
|
|
||||||
# brings up. `listenPort` follows for the same reason and is easy to read
|
|
||||||
# the other way: it is what this host *binds*, while the port a peer
|
|
||||||
# *dials* is the one inside `wireguardEndpoint`.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "privateKeyFile" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "privateKeyFile" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "address" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "address" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "listenPort" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "listenPort" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "wireguard" "persistentKeepalive" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "wireguard" "persistentKeepalive" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Which build a service runs is a decision of the host that runs it, so
|
|
||||||
# every `*.package` follows its `enable` across. Left in separate
|
|
||||||
# namespaces they split one client's two halves, as `gui.enable` and
|
|
||||||
# `gui.package` would.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "gui" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "gui" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "grafana" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "grafana" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victorialogs" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victorialogs" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "victoriametrics" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "victoriametrics" "package" ]
|
|
||||||
)
|
|
||||||
# With these two `services.hyperhive.swarm.ui` holds nothing at all: its
|
|
||||||
# `enable` is an ignored switch (declared below) and its `package` is
|
|
||||||
# renamed here. `deploy.swarm-ui` keeps only its ignored `enable`.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "ui" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "ui" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
(lib.mkRenamedOptionModule
|
||||||
[ "services" "hyperhive" "deploy" "swarm-ui" "package" ]
|
[ "services" "hyperhive" "deploy" "swarm-ui" "package" ]
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "ui" "package" ]
|
[ "services" "hyperhive" "deploy" "swarm-controller" "ui" "package" ]
|
||||||
)
|
)
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "nats" "authPackage" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "nats" "authPackage" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "authelia" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "authelia" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "authelia" "bridgePackage" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "authelia" "bridgePackage" ]
|
|
||||||
)
|
|
||||||
# ⚠️ `swarm-controller`, not `hive-controller` — see the note in
|
|
||||||
# ./swarm-controller.nix. Both namespaces exist, so the wrong target here
|
|
||||||
# lands on a live option in hive-c0re's tree instead of failing.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "controller" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "package" ]
|
|
||||||
)
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "controller" "swarmctlPackage" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "swarmctlPackage" ]
|
|
||||||
)
|
|
||||||
# ⚠️ `deploy.forgejo`, not `deploy.forge` — the deploy-side name differs
|
|
||||||
# from the swarm-side one here, as it does for the controller and the UI.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" "package" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "forgejo" "package" ]
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
# ⚠️ Only `deploy.forgejo.enable` is declared here. The rest of
|
# ⚠️ Only `deploy.forgejo.enable` is declared here. The rest of
|
||||||
|
|
|
||||||
|
|
@ -67,13 +67,13 @@ in
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs (!config.services.hyperhive.github.enable) {
|
// lib.optionalAttrs (!config.services.hyperhive.github.enable) {
|
||||||
# GitHub integration is on by default; only signal the OFF override to
|
# GitHub integration is on by default; only signal the OFF override to
|
||||||
# meta.rs, which then injects `hyperhive.github.enable = false` into
|
# meta.rs, which then injects `services.hyperhive.agent.github.enable = false` into
|
||||||
# every agent. See services.hyperhive.github.enable.
|
# every agent. See services.hyperhive.github.enable.
|
||||||
HYPERHIVE_GITHUB_DISABLED = "1";
|
HYPERHIVE_GITHUB_DISABLED = "1";
|
||||||
}
|
}
|
||||||
// lib.optionalAttrs config.services.hyperhive.otel.enable (
|
// lib.optionalAttrs config.services.hyperhive.otel.enable (
|
||||||
# Hive-wide OTEL config -> read by meta.rs::otel_config and
|
# Hive-wide OTEL config -> read by meta.rs::otel_config and
|
||||||
# injected as build-time `hyperhive.otel.*` into every agent.
|
# injected as build-time `services.hyperhive.agent.otel.*` into every agent.
|
||||||
# Endpoint presence is the enable signal on the meta side; the
|
# Endpoint presence is the enable signal on the meta side; the
|
||||||
# optional fields are only emitted when set so absent values
|
# optional fields are only emitted when set so absent values
|
||||||
# don't render no-op env lines.
|
# don't render no-op env lines.
|
||||||
|
|
@ -172,7 +172,7 @@ in
|
||||||
# fallback reads as harmless because hive-c0re shares the host netns —
|
# fallback reads as harmless because hive-c0re shares the host netns —
|
||||||
# but the value is handed to *agents*, which do not, so `127.0.0.1`
|
# but the value is handed to *agents*, which do not, so `127.0.0.1`
|
||||||
# there names the agent itself. An absent forward leaves
|
# there names the agent itself. An absent forward leaves
|
||||||
# `hyperhive.matrix.url` null and the daemon no-ops; that is the honest
|
# `services.hyperhive.agent.matrix.url` null and the daemon no-ops; that is the honest
|
||||||
# answer when there is no matrix vhost to point at.
|
# answer when there is no matrix vhost to point at.
|
||||||
HIVE_MATRIX_URL = "http://${config.services.hyperhive.swarm.matrix.gatewayHost}";
|
HIVE_MATRIX_URL = "http://${config.services.hyperhive.swarm.matrix.gatewayHost}";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
description = ''
|
description = ''
|
||||||
URL of the narrow `docs/` source (no fragment). Inlined into the
|
URL of the narrow `docs/` source (no fragment). Inlined into the
|
||||||
generated meta `flake.nix` at `inputs.hyperhive-docs.url` and
|
generated meta `flake.nix` at `inputs.hyperhive-docs.url` and
|
||||||
threaded to each agent as `hyperhive.docs.source`, from which the
|
threaded to each agent as `services.hyperhive.agent.docs.source`, from which the
|
||||||
harness resolves `$HIVE_DOCS_DIR`. Its own store path — separate
|
harness resolves `$HIVE_DOCS_DIR`. Its own store path — separate
|
||||||
from `hyperhiveFlake` — so a doc edit only re-locks this input
|
from `hyperhiveFlake` — so a doc edit only re-locks this input
|
||||||
instead of rebuilding every agent container.
|
instead of rebuilding every agent container.
|
||||||
|
|
|
||||||
|
|
@ -30,27 +30,6 @@ let
|
||||||
effectiveRootUrl = if cfg.rootUrl != null then cfg.rootUrl else defaultRootUrl;
|
effectiveRootUrl = if cfg.rootUrl != null then cfg.rootUrl else defaultRootUrl;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Forge lives under `swarm`, beside the other swarm-global services. One
|
|
||||||
# rename for the top-level `services.hyperhive.forge` namespace: the
|
|
||||||
# subtree comes with it, so existing hives keep evaluating and get one
|
|
||||||
# warning naming both paths.
|
|
||||||
imports = [
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "forge" ]
|
|
||||||
[ "services" "hyperhive" "swarm" "forge" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "forge" "sso" "enable" ] ''
|
|
||||||
SSO is no longer optional: the forge always registers the swarm's
|
|
||||||
authelia as a login source.
|
|
||||||
|
|
||||||
Removed rather than defaulted to true so a config that turned it
|
|
||||||
OFF fails here, where the line is, instead of silently gaining a
|
|
||||||
login provider on the next rebuild. Drop the line; if it was
|
|
||||||
false, set services.hyperhive.swarm.authelia.url as the assertion
|
|
||||||
describes.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
# Every swarm needs this forge — it's the canonical store for the meta
|
# Every swarm needs this forge — it's the canonical store for the meta
|
||||||
# flake + every agent's config repo (and the `internal/*` repos) — but
|
# flake + every agent's config repo (and the `internal/*` repos) — but
|
||||||
# only one host runs it: `deploy.forgejo.enable`, in ../deploy.nix. What
|
# only one host runs it: `deploy.forgejo.enable`, in ../deploy.nix. What
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,6 @@ let
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "gateway" "selfSignedTls" ] ''
|
|
||||||
Self-signed TLS is the implicit default whenever neither
|
|
||||||
tls.certDir nor tls.acme is configured, and there is no http-only
|
|
||||||
mode. Remove the setting; configure `tls.certDir` or `tls.acme`
|
|
||||||
to override the self-signed default.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "gateway" "auth" ] ''
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "gateway" "auth" ] ''
|
||||||
The dashboard is served on services.hyperhive.swarm.dashboardDomain
|
The dashboard is served on services.hyperhive.swarm.dashboardDomain
|
||||||
behind authelia, and only accounts in authelia's `admins` group can
|
behind authelia, and only accounts in authelia's `admins` group can
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ in
|
||||||
Client-server API base URL **hive-c0re itself** uses to
|
Client-server API base URL **hive-c0re itself** uses to
|
||||||
provision matrix (register agent users, create the hive space
|
provision matrix (register agent users, create the hive space
|
||||||
and chat room, invite members). Distinct from the agent-facing
|
and chat room, invite members). Distinct from the agent-facing
|
||||||
`hyperhive.matrix.url`, which is the gateway vhost handed to
|
`services.hyperhive.agent.matrix.url`, which is the gateway vhost handed to
|
||||||
each agent's `hive-matrix-daemon`.
|
each agent's `hive-matrix-daemon`.
|
||||||
|
|
||||||
Defaults to `https://` on the homeserver's gateway vhost
|
Defaults to `https://` on the homeserver's gateway vhost
|
||||||
|
|
|
||||||
|
|
@ -281,42 +281,12 @@ in
|
||||||
# settings: docs/integrations/matrix.md. Vhost map + discovery flow + tuning
|
# settings: docs/integrations/matrix.md. Vhost map + discovery flow + tuning
|
||||||
# knobs: docs/networking/gateway.md.
|
# knobs: docs/networking/gateway.md.
|
||||||
|
|
||||||
# Matrix lives under `swarm`, beside the other swarm-global services. One
|
|
||||||
# rename for the top-level `services.hyperhive.matrix` namespace: the
|
|
||||||
# subtree comes with it, so existing hives keep evaluating and get one
|
|
||||||
# warning naming both paths.
|
|
||||||
imports = [
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "matrix" ]
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" ]
|
|
||||||
)
|
|
||||||
# "does THIS host run it" is a per-host decision, and `swarm.*` is the
|
|
||||||
# namespace every host in the swarm agrees on. What stays under
|
|
||||||
# `swarm.matrix` is the homeserver's identity as every hive sees it —
|
|
||||||
# its server name, its addresses, its federation policy.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarm" "matrix" "enable" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "matrix" "enable" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "sso" "enable" ] ''
|
|
||||||
SSO is no longer optional: a homeserver that runs at all delegates
|
|
||||||
login to the swarm's authelia.
|
|
||||||
|
|
||||||
Removed rather than defaulted to true so a config that turned it
|
|
||||||
OFF fails here, where the line is, instead of silently gaining a
|
|
||||||
login flow on the next rebuild. Drop the line; if it was false,
|
|
||||||
set services.hyperhive.deploy.matrix.sso.clientSecretFile and
|
|
||||||
services.hyperhive.swarm.authelia.url as the assertions describe.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
# `swarm.matrix`, in ./hive-matrix-service.nix, is what the homeserver IS from
|
# `swarm.matrix`, in ./hive-matrix-service.nix, is what the homeserver IS from
|
||||||
# any hive's point of view: the name it answers to, the URLs it is
|
# any hive's point of view: the name it answers to, the URLs it is
|
||||||
# reached on, and the client id it is registered under. What lives here is what the host running it
|
# reached on, and the client id it is registered under. What lives here is what the host running it
|
||||||
# decides — which build it runs, whether it is exposed, which peers it trusts,
|
# decides — which build it runs, whether it is exposed, which peers it trusts,
|
||||||
# how large a request it accepts, and where its host-local secrets sit. Same rule as
|
# how large a request it accepts, and where its host-local secrets sit. Same rule as
|
||||||
# ./swarm-victorialogs.nix; `enable` already lives in ./deploy.nix, which also
|
# ./swarm-victorialogs.nix; `enable` lives in ./deploy.nix.
|
||||||
# carries the renames.
|
|
||||||
options.services.hyperhive.deploy.matrix = {
|
options.services.hyperhive.deploy.matrix = {
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
|
|
|
||||||
|
|
@ -63,19 +63,6 @@ in
|
||||||
# Hive-internal network — the host-side bridge every container in a
|
# Hive-internal network — the host-side bridge every container in a
|
||||||
# private netns hangs off. Full design: docs/networking/network.md.
|
# private netns hangs off. Full design: docs/networking/network.md.
|
||||||
|
|
||||||
imports = [
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "network" "isolateContainers" ] ''
|
|
||||||
Network isolation is the only mode and is always on whenever
|
|
||||||
the hive runs; the shared-netns path was removed. Remove
|
|
||||||
the setting.
|
|
||||||
'')
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "network" "upstreamDns" ] ''
|
|
||||||
The hive resolver always follows the host's resolvers now
|
|
||||||
(dnsmasq runs on the host and reads its /etc/resolv.conf
|
|
||||||
directly). Configure upstream DNS on the host itself instead.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
options.services.hyperhive.network = {
|
options.services.hyperhive.network = {
|
||||||
enable = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
# a removed option fails evaluation with a message, a CA-file option naming
|
# a removed option fails evaluation with a message, a CA-file option naming
|
||||||
# one of the deleted paths fails it too, and every host deletes the files.
|
# one of the deleted paths fails it too, and every host deletes the files.
|
||||||
#
|
#
|
||||||
# Self-contained and deletable, like ./swarm-peers-removed.nix: one file to
|
# Self-contained and deletable: one file to
|
||||||
# remove when the deprecation window closes.
|
# remove when the deprecation window closes.
|
||||||
{ lib, config, ... }:
|
{ lib, config, ... }:
|
||||||
let
|
let
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,7 @@ let
|
||||||
hiveCfg = config.services.hyperhive;
|
hiveCfg = config.services.hyperhive;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# The swarm's display name lives under `swarm`, with the other
|
|
||||||
# swarm-global settings; the hive's own name and domain are top-level,
|
|
||||||
# because they describe this hive rather than the swarm it joins.
|
|
||||||
imports = [
|
imports = [
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "swarmName" ]
|
|
||||||
[ "services" "hyperhive" "swarm" "name" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "ruthless" ] ''
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "ruthless" ] ''
|
||||||
hive-c0re no longer creates ruth at boot. Remove this definition, and create
|
hive-c0re no longer creates ruth at boot. Remove this definition, and create
|
||||||
ruth from the swarm dashboard like any other agent; a ruth container that
|
ruth from the swarm dashboard like any other agent; a ruth container that
|
||||||
|
|
@ -205,11 +198,11 @@ in
|
||||||
example = false;
|
example = false;
|
||||||
description = ''
|
description = ''
|
||||||
Hive-wide switch for the per-agent GitHub integration (the `gh` CLI
|
Hive-wide switch for the per-agent GitHub integration (the `gh` CLI
|
||||||
wrapper + git credential helper, per `hyperhive.github.enable`). On by
|
wrapper + git credential helper, per `services.hyperhive.agent.github.enable`). On by
|
||||||
default: every agent gets the integration, inert until an operator links
|
default: every agent gets the integration, inert until an operator links
|
||||||
a PAT for it in the swarm UI. Set `false` to turn it off for the whole hive --- the
|
a PAT for it in the swarm UI. Set `false` to turn it off for the whole hive --- the
|
||||||
meta-flake renderer (`hive-c0re/src/meta.rs`) then injects
|
meta-flake renderer (`hive-c0re/src/meta.rs`) then injects
|
||||||
`hyperhive.github.enable = false` into every agent. Exposed to hive-c0re
|
`services.hyperhive.agent.github.enable = false` into every agent. Exposed to hive-c0re
|
||||||
as `HYPERHIVE_GITHUB_DISABLED` (set only when the integration is off).
|
as `HYPERHIVE_GITHUB_DISABLED` (set only when the integration is off).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
# Set ONCE here at host level; the meta-flake renderer
|
# Set ONCE here at host level; the meta-flake renderer
|
||||||
# (`hive-c0re/src/meta.rs::otel_config`) reads the HYPERHIVE_OTEL_* env
|
# (`hive-c0re/src/meta.rs::otel_config`) reads the HYPERHIVE_OTEL_* env
|
||||||
# exported off hive-c0re's unit (see ./hive-c0re) and injects the matching
|
# exported off hive-c0re's unit (see ./hive-c0re) and injects the matching
|
||||||
# `hyperhive.otel.*` build-time config into EVERY agent (mirroring the
|
# `services.hyperhive.agent.otel.*` build-time config into EVERY agent (mirroring the
|
||||||
# CA-cert injection), so each agent's harness exports its own Claude Code
|
# CA-cert injection), so each agent's harness exports its own Claude Code
|
||||||
# stats directly to the collector. There is no per-agent opt-in — this is
|
# stats directly to the collector. There is no per-agent opt-in — this is
|
||||||
# the single switch for the whole hive.
|
# the single switch for the whole hive.
|
||||||
|
|
|
||||||
|
|
@ -1530,14 +1530,7 @@ let
|
||||||
storeRefreshTimer = import ./lib/store-refresh-timer.nix { };
|
storeRefreshTimer = import ./lib/store-refresh-timer.nix { };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports =
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "bao" "matrixCtlHiveName" ] ''
|
|
||||||
swarm-controller is the only minter of the per-hive matrix sender token,
|
|
||||||
and this option named a write grant matrix-ctl no longer holds. Delete
|
|
||||||
this setting.
|
|
||||||
'')
|
|
||||||
]
|
|
||||||
++
|
|
||||||
map
|
map
|
||||||
(
|
(
|
||||||
option:
|
option:
|
||||||
|
|
|
||||||
|
|
@ -285,22 +285,6 @@ in
|
||||||
hostUnit = true;
|
hostUnit = true;
|
||||||
enable = deployCfg.swarm-controller.enable;
|
enable = deployCfg.swarm-controller.enable;
|
||||||
})
|
})
|
||||||
# The avatar belongs to the forge-objects pass that uploads it, which
|
|
||||||
# runs in this daemon.
|
|
||||||
(lib.mkRenamedOptionModule
|
|
||||||
[ "services" "hyperhive" "c0re" "orgAvatarPng" ]
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "configOrgAvatarPng" ]
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule
|
|
||||||
[ "services" "hyperhive" "deploy" "swarm-controller" "queue" "clientSecretFile" ]
|
|
||||||
''
|
|
||||||
The controller reads its queue client secret from the swarm's secret
|
|
||||||
store, under its own certificate (deploy.swarm-controller.baoClientCertFile),
|
|
||||||
and swarm-secret-publish on the host that runs authelia puts it there.
|
|
||||||
Remove this definition; the file it named is read by nothing now and can
|
|
||||||
be deleted.
|
|
||||||
''
|
|
||||||
)
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "swarm-controller" "forgeTokenFile" ]
|
(lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "swarm-controller" "forgeTokenFile" ]
|
||||||
''
|
''
|
||||||
The controller reads its forge token from the swarm's secret store, under
|
The controller reads its forge token from the swarm's secret store, under
|
||||||
|
|
@ -421,7 +405,7 @@ in
|
||||||
description = ''
|
description = ''
|
||||||
Quick links to swarm-wide services, surfaced by the swarm UI's
|
Quick links to swarm-wide services, surfaced by the swarm UI's
|
||||||
links menu (`GET /api/links`). Same shape and same
|
links menu (`GET /api/links`). Same shape and same
|
||||||
zero-code-change-to-extend idea as `hyperhive.dashboardLinks`
|
zero-code-change-to-extend idea as `services.hyperhive.agent.dashboardLinks`
|
||||||
(`nix/agent-modules/dashboard-links.nix`), one level up: rather
|
(`nix/agent-modules/dashboard-links.nix`), one level up: rather
|
||||||
than one fixed list, definitions merge with the list-merge idiom
|
than one fixed list, definitions merge with the list-merge idiom
|
||||||
`services.hyperhive.gateway.localNames` uses, so an operator can
|
`services.hyperhive.gateway.localNames` uses, so an operator can
|
||||||
|
|
|
||||||
|
|
@ -33,15 +33,6 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "otel" "journaldUnits" ] ''
|
|
||||||
The swarm collector no longer takes a unit allowlist: it ships the
|
|
||||||
journal of every system unit on the host and drops only user
|
|
||||||
sessions (records under a `user-<uid>.slice`). Delete the setting;
|
|
||||||
nothing replaces it.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
# `enable` is `services.hyperhive.deploy.swarm-otel.enable` — see ./deploy.nix.
|
# `enable` is `services.hyperhive.deploy.swarm-otel.enable` — see ./deploy.nix.
|
||||||
# ⚠️ That is the SWARM collector. The per-hive one keeps its own
|
# ⚠️ That is the SWARM collector. The per-hive one keeps its own
|
||||||
# `services.hyperhive.otel.enable` (./otel.nix) and is a different
|
# `services.hyperhive.otel.enable` (./otel.nix) and is a different
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
# Migration shim for `services.hyperhive.swarm.peers`, replaced by the
|
|
||||||
# `swarm.hives` directory in ./swarm.nix.
|
|
||||||
#
|
|
||||||
# ⚠️ This is not a `mkRenamedOptionModule`. `hives` is not `peers`
|
|
||||||
# under another name, it is **`peers` ∪ {self}**: the set gains a member no
|
|
||||||
# existing config has ever written down, because a host's own identity
|
|
||||||
# lives in *other* options entirely. A rename migrates a name and a
|
|
||||||
# default can re-root a meaning; neither can conjure a new member.
|
|
||||||
#
|
|
||||||
# The whole module is self-contained and deletable — one file to remove
|
|
||||||
# when the deprecation window closes, with nothing else referring to it.
|
|
||||||
#
|
|
||||||
# Deliberately a warning rather than a hard failure, with the loudness
|
|
||||||
# coming from elsewhere: a config that set only `peers` leaves `hives`
|
|
||||||
# empty, so the self-entry assertion in ./swarm.nix fails the build
|
|
||||||
# anyway. The warning is what explains it; the assertion is what stops
|
|
||||||
# it.
|
|
||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
peers = config.services.hyperhive.swarm.peers;
|
|
||||||
withCaCert = lib.attrNames (lib.filterAttrs (_: p: p ? caCert && p.caCert != null) peers);
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.hyperhive.swarm.peers = lib.mkOption {
|
|
||||||
type = lib.types.attrsOf lib.types.anything;
|
|
||||||
default = { };
|
|
||||||
visible = false;
|
|
||||||
internal = true;
|
|
||||||
description = ''
|
|
||||||
Removed — use `services.hyperhive.swarm.hives` instead, which
|
|
||||||
describes every hive in the swarm including this one. Kept only so
|
|
||||||
an existing definition produces a warning that says where to move
|
|
||||||
it, rather than an "option does not exist" error that says nothing.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
config.warnings =
|
|
||||||
lib.optional (peers != { }) ''
|
|
||||||
services.hyperhive.swarm.peers is removed and ignored. Move these
|
|
||||||
entries to services.hyperhive.swarm.hives, keyed by hive NAME
|
|
||||||
rather than domain, and add an entry for this hive itself
|
|
||||||
(services.hyperhive.hiveName) — `hives` is the swarm's full
|
|
||||||
directory, identical on every host.
|
|
||||||
|
|
||||||
services.hyperhive.swarm.hives.<name> = {
|
|
||||||
domain = "<the old attrset key>";
|
|
||||||
# wireguard* carries over unchanged
|
|
||||||
};
|
|
||||||
|
|
||||||
Still set: ${lib.concatStringsSep ", " (lib.attrNames peers)}
|
|
||||||
''
|
|
||||||
++ lib.optional (withCaCert != [ ]) ''
|
|
||||||
services.hyperhive.swarm.peers.<hive>.caCert is removed and
|
|
||||||
ignored, and has no replacement in services.hyperhive.swarm.hives.
|
|
||||||
|
|
||||||
Trust inside a swarm derives from the secret store's pki root (see
|
|
||||||
docs/swarm/ca.md): every hive chains to it, so a per-hive CA is dead
|
|
||||||
weight. What this genuinely drops is trusting a hive whose root this
|
|
||||||
swarm does NOT own — another swarm's, or one keeping its own CA.
|
|
||||||
|
|
||||||
Still set on: ${lib.concatStringsSep ", " withCaCert}
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
@ -70,18 +70,6 @@ in
|
||||||
# `services.hyperhive.deploy.swarm-controller.enable` is, because it reaches
|
# `services.hyperhive.deploy.swarm-controller.enable` is, because it reaches
|
||||||
# that daemon over its unix socket. There is no `domain` option: the UI
|
# that daemon over its unix socket. There is no `domain` option: the UI
|
||||||
# answers on the swarm apex, which the swarm already declares once.
|
# answers on the swarm apex, which the swarm already declares once.
|
||||||
imports = [
|
|
||||||
(lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "ui" "domain" ] ''
|
|
||||||
The swarm UI answers on services.hyperhive.swarm.domain and nothing
|
|
||||||
else. It shares that name with the swarm-controller it fronts — they
|
|
||||||
are one service to a reader and to a certificate — so a second option
|
|
||||||
only ever created two spellings of one address.
|
|
||||||
|
|
||||||
Removed rather than aliased: a config still setting it was pinning a
|
|
||||||
name the controller's own public URL never used, and silently keeping
|
|
||||||
the alias would preserve exactly that mismatch.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
# ⚠️ Neither `services.hyperhive.swarm.ui` nor `deploy.swarm-ui` is a
|
# ⚠️ Neither `services.hyperhive.swarm.ui` nor `deploy.swarm-ui` is a
|
||||||
# namespace for anything but the old spellings: the UI's `package` lives
|
# namespace for anything but the old spellings: the UI's `package` lives
|
||||||
|
|
|
||||||
|
|
@ -118,13 +118,6 @@ let
|
||||||
# never gets a gateway certificate.
|
# never gets a gateway certificate.
|
||||||
swarmCfg.bao.ui.domain
|
swarmCfg.bao.ui.domain
|
||||||
];
|
];
|
||||||
|
|
||||||
# Hives whose entry still carries the removed `certFingerprint`. Scanned
|
|
||||||
# here, at top level, because that is the only place an assertion about a
|
|
||||||
# submodule field can actually live — see the option's own comment.
|
|
||||||
pinnedHives = lib.attrNames (
|
|
||||||
lib.filterAttrs (_: hive: hive.certFingerprint != null) swarmCfg.hives
|
|
||||||
);
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.hyperhive.swarm.hives = lib.mkOption {
|
options.services.hyperhive.swarm.hives = lib.mkOption {
|
||||||
|
|
@ -207,33 +200,6 @@ in
|
||||||
silently excluded from `wg-hive`).
|
silently excluded from `wg-hive`).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Removed, and re-declared only so an existing definition
|
|
||||||
# produces an error that says *what happened*. Without it the
|
|
||||||
# module system says `The option ... does not exist`, which
|
|
||||||
# tells an operator nothing about why it went or what replaced
|
|
||||||
# it — and this field was set on real deployments.
|
|
||||||
#
|
|
||||||
# ⚠️ `lib.mkRemovedOptionModule` cannot do this job here, and
|
|
||||||
# neither of its two halves survives inside a submodule:
|
|
||||||
# its `apply = throw` fires only when the value is READ, and
|
|
||||||
# nothing reads this (that being the point of removing
|
|
||||||
# it); its `config.assertions` half would land on a submodule
|
|
||||||
# that declares no `assertions` option at all. It is a
|
|
||||||
# top-level tool. The assertion below is the working shape, and
|
|
||||||
# it is the same one ./swarm-peers-removed.nix uses for the
|
|
||||||
# analogous `peers.<hive>.caCert`.
|
|
||||||
certFingerprint = lib.mkOption {
|
|
||||||
type = lib.types.nullOr lib.types.str;
|
|
||||||
default = null;
|
|
||||||
visible = false;
|
|
||||||
internal = true;
|
|
||||||
description = ''
|
|
||||||
Removed. Trust inside a swarm comes from the secret store's
|
|
||||||
pki root (docs/swarm/ca.md), which replaces per-hive leaf
|
|
||||||
pinning entirely.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -388,37 +354,6 @@ in
|
||||||
Declared hives: ${lib.concatStringsSep ", " (lib.attrNames swarmCfg.hives)}
|
Declared hives: ${lib.concatStringsSep ", " (lib.attrNames swarmCfg.hives)}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# An error rather than a warning, deliberately. Re-declaring the
|
|
||||||
# removed option above is what stops "option does not exist"; on
|
|
||||||
# its own it would turn a config that sets the removed field into
|
|
||||||
# one that quietly evaluates with the setting ignored, which is a
|
|
||||||
# worse answer than an error. So this stays fatal until the field
|
|
||||||
# is gone from the config.
|
|
||||||
#
|
|
||||||
# Wording follows `lib.mkRemovedOptionModule`'s, so it reads like
|
|
||||||
# every other removal the module system reports.
|
|
||||||
assertion = pinnedHives == [ ];
|
|
||||||
message = ''
|
|
||||||
The option definition `services.hyperhive.swarm.hives.<hive>.certFingerprint'
|
|
||||||
no longer has any effect; please remove it.
|
|
||||||
|
|
||||||
Still set on: ${lib.concatStringsSep ", " pinnedHives}
|
|
||||||
|
|
||||||
It pinned a peer hive's TLS leaf for hive-c0re's own peer HTTPS
|
|
||||||
checks, and was removed along with the dashboard feature it
|
|
||||||
existed to serve — nothing else ever consumed it.
|
|
||||||
|
|
||||||
There is no replacement, and none is needed for a hive inside
|
|
||||||
this swarm: trust comes from the secret store's pki root (see
|
|
||||||
docs/swarm/ca.md), which every hive chains to, so one anchor
|
|
||||||
replaces per-hive pinning.
|
|
||||||
What that genuinely drops is trusting a hive whose root this
|
|
||||||
swarm does NOT own — another swarm's, or one keeping its own
|
|
||||||
CA. That is a cross-swarm problem and wants a mechanism
|
|
||||||
designed for it.
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
(nameGuards.mustBeIdent {
|
(nameGuards.mustBeIdent {
|
||||||
option = "services.hyperhive.swarm.hives";
|
option = "services.hyperhive.swarm.hives";
|
||||||
names = hiveNames;
|
names = hiveNames;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ let
|
||||||
m:
|
m:
|
||||||
lib.any (a: !a.assertion && lib.hasInfix "deploy.builder.enable requires" a.message) m.assertions;
|
lib.any (a: !a.assertion && lib.hasInfix "deploy.builder.enable requires" a.message) m.assertions;
|
||||||
|
|
||||||
natsHere = shared.natsOldPath;
|
natsHere = shared.natsQueueOnly;
|
||||||
|
|
||||||
autheliaHere = hive {
|
autheliaHere = hive {
|
||||||
deploy.bao.enable = true;
|
deploy.bao.enable = true;
|
||||||
|
|
|
||||||
|
|
@ -995,36 +995,6 @@ let
|
||||||
&& bare.services.dnsmasq.enable
|
&& bare.services.dnsmasq.enable
|
||||||
&& bare.networking.bridges ? hive-br0;
|
&& bare.networking.bridges ? hive-br0;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# A host config written against either old spelling still runs its hive.
|
|
||||||
# The builder's own `true` is lowered to `mkDefault false`, so only the
|
|
||||||
# forwarded definition can turn it on.
|
|
||||||
name = "the old hive toggles forward to deploy.hive-controller.enable and warn";
|
|
||||||
ok =
|
|
||||||
let
|
|
||||||
renamedFrom =
|
|
||||||
old: m:
|
|
||||||
lib.any (
|
|
||||||
w: lib.hasInfix old w && lib.hasInfix "services.hyperhive.deploy.hive-controller.enable" w
|
|
||||||
) m.warnings;
|
|
||||||
viaOld =
|
|
||||||
extra:
|
|
||||||
hive (
|
|
||||||
extra
|
|
||||||
// {
|
|
||||||
deploy.hive-controller.enable = lib.mkDefault false;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
oldEnable = viaOld { enable = true; };
|
|
||||||
oldC0re = viaOld { c0re.enable = true; };
|
|
||||||
in
|
|
||||||
oldEnable.services.hyperhive.deploy.hive-controller.enable
|
|
||||||
&& oldEnable.systemd.services ? hive-c0re
|
|
||||||
&& renamedFrom "services.hyperhive.enable" oldEnable
|
|
||||||
&& oldC0re.services.hyperhive.deploy.hive-controller.enable
|
|
||||||
&& oldC0re.systemd.services ? hive-c0re
|
|
||||||
&& renamedFrom "services.hyperhive.c0re.enable" oldC0re;
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
# Refused wherever something turns the name into an identifier, and only
|
# Refused wherever something turns the name into an identifier, and only
|
||||||
# there. The store host is the control that the refusal is not the hive's
|
# there. The store host is the control that the refusal is not the hive's
|
||||||
|
|
|
||||||
|
|
@ -82,16 +82,6 @@ let
|
||||||
deploy.hive-controller.enable = false;
|
deploy.hive-controller.enable = false;
|
||||||
deploy.forgejo.ci.enable = true;
|
deploy.forgejo.ci.enable = true;
|
||||||
};
|
};
|
||||||
# The older spelling, under the swarm-level forge options.
|
|
||||||
ciUnderSwarmForge = hive {
|
|
||||||
swarm.forge.ci.enable = true;
|
|
||||||
swarm.forge.ci.name = "older-runner";
|
|
||||||
swarm.forge.ci.concurrency = 2;
|
|
||||||
swarm.forge.ci.labels = [ "nix:host" ];
|
|
||||||
swarm.forge.ci.package = pkgs.hello;
|
|
||||||
deploy.bao.ciRunnerClientCertFile = "/etc/pki/bao-ci-runner.pem";
|
|
||||||
deploy.bao.ciRunnerClientKeyFile = "/etc/pki/bao-ci-runner-key.pem";
|
|
||||||
};
|
|
||||||
|
|
||||||
runsForge = m: m.services.hyperhive.deploy.forgejo.enable && m.containers ? hive-forge;
|
runsForge = m: m.services.hyperhive.deploy.forgejo.enable && m.containers ? hive-forge;
|
||||||
|
|
||||||
|
|
@ -299,22 +289,6 @@ let
|
||||||
&& lib.any (lib.hasInfix "services.hyperhive.deploy.forgejo.ci.enable") ciUnderForge.warnings
|
&& lib.any (lib.hasInfix "services.hyperhive.deploy.forgejo.ci.enable") ciUnderForge.warnings
|
||||||
&& !(lib.any (a: !a.assertion) ciUnderForge.assertions);
|
&& !(lib.any (a: !a.assertion) ciUnderForge.assertions);
|
||||||
}
|
}
|
||||||
{
|
|
||||||
# The control is the container: it only exists if `enable` arrived.
|
|
||||||
name = "a CI option under swarm.forge sets the same option under deploy.ci-runner";
|
|
||||||
ok =
|
|
||||||
let
|
|
||||||
r = ciUnderSwarmForge.services.hyperhive.deploy.ci-runner;
|
|
||||||
in
|
|
||||||
r.enable
|
|
||||||
&& r.name == "older-runner"
|
|
||||||
&& r.concurrency == 2
|
|
||||||
&& r.labels == [ "nix:host" ]
|
|
||||||
&& r.package == pkgs.hello
|
|
||||||
&& ciUnderSwarmForge.containers ? swarm-ci-runner
|
|
||||||
&& lib.any (lib.hasInfix "services.hyperhive.swarm.forge.ci.enable") ciUnderSwarmForge.warnings
|
|
||||||
&& !(lib.any (a: !a.assertion) ciUnderSwarmForge.assertions);
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
# The rename carries `enable` but not the identity: an old config with
|
# The rename carries `enable` but not the identity: an old config with
|
||||||
# only the old name is refused, and the message says what to set. The
|
# only the old name is refused, and the message says what to set. The
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,12 @@ let
|
||||||
runGroup
|
runGroup
|
||||||
;
|
;
|
||||||
|
|
||||||
grafanaOldPath = hive {
|
grafanaHere = hive {
|
||||||
deploy.grafana.enable = true;
|
deploy.grafana.enable = true;
|
||||||
swarm.grafana.datasourceUrl = "http://127.0.0.1:19999";
|
deploy.grafana.datasourceUrl = "http://127.0.0.1:19999";
|
||||||
swarm.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
|
deploy.grafana.logsDatasourceUrl = "http://127.0.0.1:19998";
|
||||||
swarm.grafana.plugins = [ ];
|
deploy.grafana.plugins = [ ];
|
||||||
swarm.grafana.package = pkgs.emptyDirectory;
|
deploy.grafana.package = pkgs.emptyDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
# A host that tries to move the socket directory; reading the option throws.
|
# A host that tries to move the socket directory; reading the option throws.
|
||||||
|
|
@ -120,7 +120,7 @@ let
|
||||||
ok =
|
ok =
|
||||||
!(builtins.tryEval grafanaSocketDirSet.services.hyperhive.deploy.grafana.socketDir).success
|
!(builtins.tryEval grafanaSocketDirSet.services.hyperhive.deploy.grafana.socketDir).success
|
||||||
&&
|
&&
|
||||||
grafanaOldPath.services.nginx.virtualHosts.${grafanaOldPath.services.hyperhive.swarm.grafana.domain}.locations."= /metrics".proxyPass
|
grafanaHere.services.nginx.virtualHosts.${grafanaHere.services.hyperhive.swarm.grafana.domain}.locations."= /metrics".proxyPass
|
||||||
== "http://unix:/run/swarm-grafana/grafana.sock:/metrics";
|
== "http://unix:/run/swarm-grafana/grafana.sock:/metrics";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -132,8 +132,8 @@ let
|
||||||
name = "grafana's published vhost serves /metrics only behind the collector's auth subrequest";
|
name = "grafana's published vhost serves /metrics only behind the collector's auth subrequest";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
g = grafanaOldPath.services.hyperhive.swarm.grafana;
|
g = grafanaHere.services.hyperhive.swarm.grafana;
|
||||||
locs = grafanaOldPath.services.nginx.virtualHosts.${g.domain}.locations;
|
locs = grafanaHere.services.nginx.virtualHosts.${g.domain}.locations;
|
||||||
checksOf = l: lib.filter (lib.hasPrefix "auth_request") (lib.splitString "\n" l.extraConfig);
|
checksOf = l: lib.filter (lib.hasPrefix "auth_request") (lib.splitString "\n" l.extraConfig);
|
||||||
authz = locs."= /__grafana_metrics_authz";
|
authz = locs."= /__grafana_metrics_authz";
|
||||||
in
|
in
|
||||||
|
|
@ -143,7 +143,7 @@ let
|
||||||
&& !(lib.hasInfix "error_page" locs."= /metrics".extraConfig)
|
&& !(lib.hasInfix "error_page" locs."= /metrics".extraConfig)
|
||||||
&& authz.proxyPass == "https://auth.t.local/api/authz/auth-request"
|
&& authz.proxyPass == "https://auth.t.local/api/authz/auth-request"
|
||||||
&& lib.hasInfix "internal;" authz.extraConfig
|
&& lib.hasInfix "internal;" authz.extraConfig
|
||||||
&& !(grafanaOldPath.services.nginx.virtualHosts ? "grafana-metrics")
|
&& !(grafanaHere.services.nginx.virtualHosts ? "grafana-metrics")
|
||||||
&& lib.hasPrefix "http://unix:" locs."/".proxyPass;
|
&& lib.hasPrefix "http://unix:" locs."/".proxyPass;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -152,8 +152,7 @@ let
|
||||||
# this host". Its vhost is on the public gateway, so a password box there
|
# this host". Its vhost is on the public gateway, so a password box there
|
||||||
# is a way in whatever the topology.
|
# is a way in whatever the topology.
|
||||||
name = "grafana disables its local login form even where authelia is not on this host";
|
name = "grafana disables its local login form even where authelia is not on this host";
|
||||||
ok =
|
ok = grafanaHere.containers.swarm-grafana.config.services.grafana.settings.auth.disable_login_form;
|
||||||
grafanaOldPath.containers.swarm-grafana.config.services.grafana.settings.auth.disable_login_form;
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
# The absence class this whole file is for, and the reported defect in one
|
# The absence class this whole file is for, and the reported defect in one
|
||||||
|
|
@ -445,7 +444,7 @@ let
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
sources =
|
sources =
|
||||||
grafanaOldPath.containers.swarm-grafana.config.services.grafana.provision.datasources.settings.datasources;
|
grafanaHere.containers.swarm-grafana.config.services.grafana.provision.datasources.settings.datasources;
|
||||||
logs = lib.head (lib.filter (d: d.uid == "swarm-victorialogs") sources);
|
logs = lib.head (lib.filter (d: d.uid == "swarm-victorialogs") sources);
|
||||||
rules = logs.jsonData.logLevelRules or [ ];
|
rules = logs.jsonData.logLevelRules or [ ];
|
||||||
# `overwrite_text` makes the stored text the OpenTelemetry short name
|
# `overwrite_text` makes the stored text the OpenTelemetry short name
|
||||||
|
|
@ -473,7 +472,7 @@ let
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
groups =
|
groups =
|
||||||
grafanaOldPath.containers.swarm-grafana.config.services.grafana.provision.alerting.rules.settings.groups;
|
grafanaHere.containers.swarm-grafana.config.services.grafana.provision.alerting.rules.settings.groups;
|
||||||
rules = lib.concatMap (g: g.rules) groups;
|
rules = lib.concatMap (g: g.rules) groups;
|
||||||
rule = lib.findFirst (r: r.uid == "hh-agent-turn-failed") null rules;
|
rule = lib.findFirst (r: r.uid == "hh-agent-turn-failed") null rules;
|
||||||
expr = (lib.head rule.data).model.expr;
|
expr = (lib.head rule.data).model.expr;
|
||||||
|
|
@ -517,9 +516,8 @@ let
|
||||||
name = "grafana's vhost is rendered with the gateway's listen set, TLS and security headers";
|
name = "grafana's vhost is rendered with the gateway's listen set, TLS and security headers";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
gw = grafanaOldPath.services.hyperhive.gateway;
|
gw = grafanaHere.services.hyperhive.gateway;
|
||||||
v =
|
v = grafanaHere.services.nginx.virtualHosts.${grafanaHere.services.hyperhive.swarm.grafana.domain};
|
||||||
grafanaOldPath.services.nginx.virtualHosts.${grafanaOldPath.services.hyperhive.swarm.grafana.domain};
|
|
||||||
# nginx's `listen` entries come back with defaults filled in
|
# nginx's `listen` entries come back with defaults filled in
|
||||||
# (`extraParameters`, `proxyProtocol`), so compare the fields set.
|
# (`extraParameters`, `proxyProtocol`), so compare the fields set.
|
||||||
listenOf = map (l: {
|
listenOf = map (l: {
|
||||||
|
|
|
||||||
|
|
@ -103,13 +103,7 @@ let
|
||||||
];
|
];
|
||||||
}).config;
|
}).config;
|
||||||
|
|
||||||
# Note `hyperhive`, not `services.hyperhive`: the agent tier's options moved
|
agent = extra: agentWith { services.hyperhive.agent = extra; };
|
||||||
# under `services.hyperhive.agent`, and ../agent-modules/renamed-options.nix
|
|
||||||
# keeps the top-level spelling reaching them. ⚠️ That shim covers the
|
|
||||||
# options that existed when the tier moved and nothing since, so a fixture
|
|
||||||
# for an option added afterwards has to go through [`agentWith`] and name
|
|
||||||
# the real path.
|
|
||||||
agent = extra: agentWith { hyperhive = extra; };
|
|
||||||
|
|
||||||
baoNames = machine: machine.services.hyperhive.gateway.localNames;
|
baoNames = machine: machine.services.hyperhive.gateway.localNames;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,25 +22,18 @@ let
|
||||||
runGroup
|
runGroup
|
||||||
;
|
;
|
||||||
|
|
||||||
# The queue's two old `swarm.nats` paths that still rename; dropping either
|
# No store identity, which the first case below relies on.
|
||||||
# shim fails the eval. No store identity, which the first case below relies on.
|
natsQueueOnly = shared.natsQueueOnly;
|
||||||
natsOldPath = shared.natsOldPath;
|
|
||||||
|
|
||||||
# Seventh split slice, plus slice 10's two authelia packages. Of slice 7's
|
# The IdP and the queue on one host. A reader of authelia's host paths has to
|
||||||
# movers only `usersFile` has a rename entry — the other two are `readOnly`,
|
# follow the `deploy` namespace; seven of those reads go through an alias a
|
||||||
# and a rename module contributes a definition, which a read-only option
|
# path-shaped grep cannot see.
|
||||||
# refuses; see ./host-modules/deploy.nix. `package` and `bridgePackage` are
|
autheliaAndNats = hive {
|
||||||
# ordinary options, so they do carry one. The two arms
|
|
||||||
# below have different jobs. `usersFile` tests the rename; the nats one tests
|
|
||||||
# that a reader pointed at the `deploy` namespace still renders the derived
|
|
||||||
# path — seven of those reads go through an alias a path-shaped grep
|
|
||||||
# cannot see.
|
|
||||||
autheliaOldPath = hive {
|
|
||||||
deploy.authelia.enable = true;
|
deploy.authelia.enable = true;
|
||||||
deploy.nats.enable = true;
|
deploy.nats.enable = true;
|
||||||
swarm.authelia.usersFile = "/var/lib/test-authelia/users.yml";
|
deploy.authelia.usersFile = "/var/lib/test-authelia/users.yml";
|
||||||
swarm.authelia.package = pkgs.emptyDirectory;
|
deploy.authelia.package = pkgs.emptyDirectory;
|
||||||
swarm.authelia.bridgePackage = pkgs.emptyDirectory;
|
deploy.authelia.bridgePackage = pkgs.emptyDirectory;
|
||||||
# Renders the publisher, which reads the host client-secret dir.
|
# Renders the publisher, which reads the host client-secret dir.
|
||||||
deploy.swarm-secret-publisher.baoClientCertFile = "/etc/pki/publisher.pem";
|
deploy.swarm-secret-publisher.baoClientCertFile = "/etc/pki/publisher.pem";
|
||||||
deploy.swarm-secret-publisher.baoClientKeyFile = "/etc/pki/publisher-key.pem";
|
deploy.swarm-secret-publisher.baoClientKeyFile = "/etc/pki/publisher-key.pem";
|
||||||
|
|
@ -297,9 +290,9 @@ let
|
||||||
{
|
{
|
||||||
name = "authelia and nats declare no scrape target on a host with no collector";
|
name = "authelia and nats declare no scrape target on a host with no collector";
|
||||||
ok =
|
ok =
|
||||||
!(autheliaOldPath.services.hyperhive.deploy.swarm-otel.enable)
|
!(autheliaAndNats.services.hyperhive.deploy.swarm-otel.enable)
|
||||||
&& !(autheliaOldPath.services.hyperhive.swarm.otel.scrapeTargets ? authelia)
|
&& !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? authelia)
|
||||||
&& !(autheliaOldPath.services.hyperhive.swarm.otel.scrapeTargets ? nats);
|
&& !(autheliaAndNats.services.hyperhive.swarm.otel.scrapeTargets ? nats);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
# The xkey and the responder's OIDC client secret are read only from
|
# The xkey and the responder's OIDC client secret are read only from
|
||||||
|
|
@ -308,7 +301,7 @@ let
|
||||||
# minted one.
|
# minted one.
|
||||||
name = "a queue with no responder store identity is refused at eval, one with a leaf is not";
|
name = "a queue with no responder store identity is refused at eval, one with a leaf is not";
|
||||||
ok =
|
ok =
|
||||||
refusedWithoutIdentity natsOldPath
|
refusedWithoutIdentity natsQueueOnly
|
||||||
&& !(refusedWithoutIdentity natsWithStoreIdentity)
|
&& !(refusedWithoutIdentity natsWithStoreIdentity)
|
||||||
&& !(refusedWithoutIdentity natsOnStoreHost);
|
&& !(refusedWithoutIdentity natsOnStoreHost);
|
||||||
}
|
}
|
||||||
|
|
@ -327,10 +320,10 @@ let
|
||||||
# this key would still evaluate cleanly — the only reader that would
|
# this key would still evaluate cleanly — the only reader that would
|
||||||
# notice is a publisher whose row exceeds upstream's much smaller
|
# notice is a publisher whose row exceeds upstream's much smaller
|
||||||
# default, and by then it is a dropped row, not an eval failure.
|
# default, and by then it is a dropped row, not an eval failure.
|
||||||
# Piggybacks on the pre-rename nats fixture above, which already
|
# Piggybacks on the queue-only fixture above, which already
|
||||||
# renders this container's full config.
|
# renders this container's full config.
|
||||||
name = "the queue's payload ceiling is set, not inherited from the server's default";
|
name = "the queue's payload ceiling is set, not inherited from the server's default";
|
||||||
ok = natsOldPath.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608;
|
ok = natsQueueOnly.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
# What keeps a callout request inside one principal: the responder is
|
# What keeps a callout request inside one principal: the responder is
|
||||||
|
|
@ -351,7 +344,7 @@ let
|
||||||
&& !(settings ? system_account)
|
&& !(settings ? system_account)
|
||||||
)
|
)
|
||||||
[
|
[
|
||||||
natsOldPath
|
natsQueueOnly
|
||||||
natsOnStoreHost
|
natsOnStoreHost
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +368,7 @@ let
|
||||||
&& !(c.services.nats.settings.authorization.auth_callout ? xkey)
|
&& !(c.services.nats.settings.authorization.auth_callout ? xkey)
|
||||||
)
|
)
|
||||||
[
|
[
|
||||||
natsOldPath
|
natsQueueOnly
|
||||||
natsOnStoreHost
|
natsOnStoreHost
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -384,7 +377,7 @@ let
|
||||||
# responder with it: the responder requires the server, so a server that
|
# responder with it: the responder requires the server, so a server that
|
||||||
# failed to start left the responder inactive rather than failed.
|
# failed to start left the responder inactive rather than failed.
|
||||||
name = "starting the queue's server starts its responder";
|
name = "starting the queue's server starts its responder";
|
||||||
ok = lib.elem "nats.service" (responderOf natsOldPath).wantedBy;
|
ok = lib.elem "nats.service" (responderOf natsQueueOnly).wantedBy;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
# The keys are created before anything needs them, by the responder's
|
# The keys are created before anything needs them, by the responder's
|
||||||
|
|
@ -480,7 +473,7 @@ let
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
exec =
|
exec =
|
||||||
natsOldPath.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
|
natsQueueOnly.containers.swarm-nats.config.systemd.services.swarm-nats-auth.serviceConfig.ExecStart;
|
||||||
in
|
in
|
||||||
!(lib.hasInfix "--agent-publish-subject " exec);
|
!(lib.hasInfix "--agent-publish-subject " exec);
|
||||||
}
|
}
|
||||||
|
|
@ -491,7 +484,7 @@ let
|
||||||
name = "the responder grants a verified agent its own hive-free subjects";
|
name = "the responder grants a verified agent its own hive-free subjects";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
exec = (responderOf natsOldPath).serviceConfig.ExecStart;
|
exec = (responderOf natsQueueOnly).serviceConfig.ExecStart;
|
||||||
in
|
in
|
||||||
lib.hasInfix "--agent-token-publish-subject '$$SWARM.term.{agent}'" exec
|
lib.hasInfix "--agent-token-publish-subject '$$SWARM.term.{agent}'" exec
|
||||||
&& lib.hasInfix "--agent-token-publish-subject '$$SWARM.agent-state.{agent}'" exec
|
&& lib.hasInfix "--agent-token-publish-subject '$$SWARM.agent-state.{agent}'" exec
|
||||||
|
|
@ -503,7 +496,7 @@ let
|
||||||
name = "the responder grants a verified agent its own icon key";
|
name = "the responder grants a verified agent its own icon key";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
exec = (responderOf natsOldPath).serviceConfig.ExecStart;
|
exec = (responderOf natsQueueOnly).serviceConfig.ExecStart;
|
||||||
in
|
in
|
||||||
lib.hasInfix "--agent-token-publish-subject '$$KV.agent-icons.{agent}'" exec;
|
lib.hasInfix "--agent-token-publish-subject '$$KV.agent-icons.{agent}'" exec;
|
||||||
}
|
}
|
||||||
|
|
@ -514,7 +507,7 @@ let
|
||||||
name = "a verified agent's grant is exactly its own subjects, and its JetStream API subjects read its own schedule, inference and permissions keys";
|
name = "a verified agent's grant is exactly its own subjects, and its JetStream API subjects read its own schedule, inference and permissions keys";
|
||||||
ok =
|
ok =
|
||||||
let
|
let
|
||||||
args = lib.splitString " " (responderOf natsOldPath).serviceConfig.ExecStart;
|
args = lib.splitString " " (responderOf natsQueueOnly).serviceConfig.ExecStart;
|
||||||
granted = lib.concatLists (
|
granted = lib.concatLists (
|
||||||
lib.imap0 (
|
lib.imap0 (
|
||||||
i: a:
|
i: a:
|
||||||
|
|
@ -685,7 +678,7 @@ let
|
||||||
# through an `autheliaCfg` alias, where a path-shaped grep does not see it.
|
# through an `autheliaCfg` alias, where a path-shaped grep does not see it.
|
||||||
name = "a consumer of authelia's host client-secret dir renders it from the deploy namespace";
|
name = "a consumer of authelia's host client-secret dir renders it from the deploy namespace";
|
||||||
ok =
|
ok =
|
||||||
autheliaOldPath.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
|
autheliaAndNats.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
|
||||||
== "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients";
|
== "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -55,11 +55,10 @@ in
|
||||||
# shape that hives elsewhere join.
|
# shape that hives elsewhere join.
|
||||||
swarmServicesWithController = hiveWithController { deploy.allSwarmServices = true; };
|
swarmServicesWithController = hiveWithController { deploy.allSwarmServices = true; };
|
||||||
|
|
||||||
# The queue's two old `swarm.nats` paths that still rename, `enable` and
|
# The queue with no store identity.
|
||||||
# `authPackage`, with no store identity.
|
natsQueueOnly = hive {
|
||||||
natsOldPath = hive {
|
deploy.nats.enable = true;
|
||||||
swarm.nats.enable = true;
|
deploy.nats.authPackage = pkgs.emptyDirectory;
|
||||||
swarm.nats.authPackage = pkgs.emptyDirectory;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
controllerAlone = hive { deploy.swarm-controller.enable = true; };
|
controllerAlone = hive { deploy.swarm-controller.enable = true; };
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,6 @@ let
|
||||||
# authelia somewhere else, the credential delivered by hand. Whether this
|
# authelia somewhere else, the credential delivered by hand. Whether this
|
||||||
# collector authenticates must follow the credential, never another
|
# collector authenticates must follow the credential, never another
|
||||||
# service's placement.
|
# service's placement.
|
||||||
#
|
|
||||||
# The `swarm.otel.clientSecretFile` below is the PRE-RENAME path. It predates
|
|
||||||
# the split and is deliberately left spelled that way: it makes this fixture
|
|
||||||
# the old-path case for that option too, so dropping its rename entry fails
|
|
||||||
# the eval here rather than only in a real operator's config.
|
|
||||||
otelRemoteAuthelia = hive {
|
otelRemoteAuthelia = hive {
|
||||||
deploy.swarm-otel.enable = true;
|
deploy.swarm-otel.enable = true;
|
||||||
deploy.authelia.enable = false;
|
deploy.authelia.enable = false;
|
||||||
|
|
@ -74,7 +69,7 @@ let
|
||||||
# `token_url`, so a hive with a secret and no URL has a credential it can
|
# `token_url`, so a hive with a secret and no URL has a credential it can
|
||||||
# present nowhere.
|
# present nowhere.
|
||||||
swarm.authelia.url = "https://auth.example.invalid";
|
swarm.authelia.url = "https://auth.example.invalid";
|
||||||
swarm.otel.clientSecretFile = "/var/lib/swarm-otel-oidc/by-hand.secret";
|
deploy.swarm-otel.clientSecretFile = "/var/lib/swarm-otel-oidc/by-hand.secret";
|
||||||
};
|
};
|
||||||
|
|
||||||
# A collector whose ONLY scrape work is published: loopback targets forced
|
# A collector whose ONLY scrape work is published: loopback targets forced
|
||||||
|
|
@ -148,10 +143,8 @@ let
|
||||||
{
|
{
|
||||||
# The collector's half of the same split, and a different arm from the
|
# The collector's half of the same split, and a different arm from the
|
||||||
# authenticator case below: this one reads the PATH the unit loads, so a
|
# authenticator case below: this one reads the PATH the unit loads, so a
|
||||||
# reader left on a source that is non-null but wrong still fails. The
|
# reader left on a source that is non-null but wrong still fails.
|
||||||
# fixture spells the option its pre-rename way, so it covers the rename
|
name = "a by-hand otel secret path is the one the collector loads as a credential";
|
||||||
# entry at the same time.
|
|
||||||
name = "a config written against the pre-rename otel secret path still loads it as a credential";
|
|
||||||
ok =
|
ok =
|
||||||
lib.any (c: lib.hasInfix "/var/lib/swarm-otel-oidc/by-hand.secret" c)
|
lib.any (c: lib.hasInfix "/var/lib/swarm-otel-oidc/by-hand.secret" c)
|
||||||
otelRemoteAuthelia.containers.swarm-otel.config.systemd.services.opentelemetry-collector.serviceConfig.LoadCredential;
|
otelRemoteAuthelia.containers.swarm-otel.config.systemd.services.opentelemetry-collector.serviceConfig.LoadCredential;
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ let
|
||||||
deploy.forgejo.enable = true;
|
deploy.forgejo.enable = true;
|
||||||
deploy.forgejo.mirrors = [ aMirror ];
|
deploy.forgejo.mirrors = [ aMirror ];
|
||||||
deploy.forgejo.actionsFromSelf = false;
|
deploy.forgejo.actionsFromSelf = false;
|
||||||
c0re.orgAvatarPng = "/etc/marker-avatar.png";
|
deploy.swarm-controller.configOrgAvatarPng = "/etc/marker-avatar.png";
|
||||||
};
|
};
|
||||||
mirrorsNoController = hive {
|
mirrorsNoController = hive {
|
||||||
deploy.forgejo.enable = true;
|
deploy.forgejo.enable = true;
|
||||||
|
|
@ -796,7 +796,7 @@ let
|
||||||
&& lib.elem "actions/checkout" (map (m: m.dest) (mirrorsOf forgeWithController));
|
&& lib.elem "actions/checkout" (map (m: m.dest) (mirrorsOf forgeWithController));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "the old c0re org-avatar option lands on the controller's unit";
|
name = "the org avatar lands on the controller's unit, not hive-c0re's";
|
||||||
ok =
|
ok =
|
||||||
controllerWithMirrors.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_CONFIG_ORG_AVATAR_PNG
|
controllerWithMirrors.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_CONFIG_ORG_AVATAR_PNG
|
||||||
== "/etc/marker-avatar.png"
|
== "/etc/marker-avatar.png"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# hyperhive-authored Claude Code plugin marketplace (source tree at
|
# hyperhive-authored Claude Code plugin marketplace (source tree at
|
||||||
# ../../claude-plugins), shipped as a standalone derivation and spliced
|
# ../../claude-plugins), shipped as a standalone derivation and spliced
|
||||||
# into the *default* `hyperhive.claudeMarketplaces`/`claudePlugins` lists
|
# into the *default* `services.hyperhive.agent.claudeMarketplaces`/`claudePlugins` lists
|
||||||
# (nix/agent-modules/claude-settings.nix) as a local marketplace source.
|
# (nix/agent-modules/claude-settings.nix) as a local marketplace source.
|
||||||
# `claude plugin marketplace add` accepts a plain filesystem path (verified:
|
# `claude plugin marketplace add` accepts a plain filesystem path (verified:
|
||||||
# `claude plugin marketplace add --help` → "Add a marketplace from a URL,
|
# `claude plugin marketplace add --help` → "Add a marketplace from a URL,
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,7 @@ in
|
||||||
assets = pkgs.callPackage ./assets.nix { };
|
assets = pkgs.callPackage ./assets.nix { };
|
||||||
# hyperhive-authored Claude Code plugin marketplace (source tree at
|
# hyperhive-authored Claude Code plugin marketplace (source tree at
|
||||||
# ../../claude-plugins) — a local-path marketplace spliced into the
|
# ../../claude-plugins) — a local-path marketplace spliced into the
|
||||||
# default `hyperhive.claudeMarketplaces`/`claudePlugins` lists. See
|
# default `services.hyperhive.agent.claudeMarketplaces`/`claudePlugins` lists. See
|
||||||
# ./claude-plugins.nix for the "why a store path, not a repo" rationale.
|
# ./claude-plugins.nix for the "why a store path, not a repo" rationale.
|
||||||
claude-plugins = pkgs.callPackage ./claude-plugins.nix { };
|
claude-plugins = pkgs.callPackage ./claude-plugins.nix { };
|
||||||
# The repo docs/ markdown tree as a standalone derivation —
|
# The repo docs/ markdown tree as a standalone derivation —
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
# static/{tabs,flow,stats,stream-worker}.js{,.map}
|
# static/{tabs,flow,stats,stream-worker}.js{,.map}
|
||||||
# static/{colors,theme,common,dashboard,flow,stats}.css
|
# static/{colors,theme,common,dashboard,flow,stats}.css
|
||||||
# $out/agent/ the per-agent default UI (layered with
|
# $out/agent/ the per-agent default UI (layered with
|
||||||
# hyperhive.frontend.extraFiles at activation time)
|
# services.hyperhive.agent.frontend.extraFiles at activation time)
|
||||||
# index.html stats.html screen.html
|
# index.html stats.html screen.html
|
||||||
# static/{app,stats}.js{,.map}
|
# static/{app,stats}.js{,.map}
|
||||||
# static/{colors,theme,agent}.css
|
# static/{colors,theme,agent}.css
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
# frontend/, prompts/, flake.lock. docs/ is deliberately dropped:
|
# frontend/, prompts/, flake.lock. docs/ is deliberately dropped:
|
||||||
# it is shipped to agent containers as its OWN narrow meta-flake
|
# it is shipped to agent containers as its OWN narrow meta-flake
|
||||||
# input (`hyperhiveDocsSource`, below), threaded through hive-c0re
|
# input (`hyperhiveDocsSource`, below), threaded through hive-c0re
|
||||||
# → the meta flake → `hyperhive.docs.source`. Keeping docs/ out of
|
# → the meta flake → `services.hyperhive.agent.docs.source`. Keeping docs/ out of
|
||||||
# THIS source means a doc edit only re-hashes the docs input (a
|
# THIS source means a doc edit only re-hashes the docs input (a
|
||||||
# cheap re-link), not the whole flake source (which would rebuild
|
# cheap re-link), not the whole flake source (which would rebuild
|
||||||
# every agent container). The `reference-docs` build from `../docs`
|
# every agent container). The `reference-docs` build from `../docs`
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
# path moves ONLY on doc edits, decoupled from `hyperhiveFlakeSource`.
|
# path moves ONLY on doc edits, decoupled from `hyperhiveFlakeSource`.
|
||||||
# hive-c0re threads this to the meta flake as the `hyperhive-docs`
|
# hive-c0re threads this to the meta flake as the `hyperhive-docs`
|
||||||
# input (same pattern as the `hyperhive` input); the harness resolves
|
# input (same pattern as the `hyperhive` input); the harness resolves
|
||||||
# `$HIVE_DOCS_DIR` from it via `hyperhive.docs.source`. Evaluated
|
# `$HIVE_DOCS_DIR` from it via `services.hyperhive.agent.docs.source`. Evaluated
|
||||||
# here on the host where docs/ exists — it cannot be derived from
|
# here on the host where docs/ exists — it cannot be derived from
|
||||||
# inside the docs-stripped `hyperhiveFlakeSource`.
|
# inside the docs-stripped `hyperhiveFlakeSource`.
|
||||||
hyperhiveDocsSource = lib.cleanSourceWith {
|
hyperhiveDocsSource = lib.cleanSourceWith {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue