Commit graph

1,508 commits

Author SHA1 Message Date
atlas
89092caba4 fix: restrict WriteAgentStateFile to explicit filename allowlist
Addresses mara's security review: replace validate_state_filename (which
accepted any non-traversal filename) with a tight allowlist containing
only the two known credential filenames: forge-token and matrix-token.

Also addresses argus review feedback:
- drop issue tag from priv_proto.rs doc comment
- add comment explaining the path-detection heuristic in forge.rs
- add note about create_dir_all uid=0 edge case in write_agent_state_file
2026-06-04 14:30:01 +02:00
atlas
eb51362d50 fix: route forge/matrix token writes through hive-priv
hive-c0re runs as the unprivileged hive-core user (privsep from #702)
and cannot write to agent-owned state directories. forge-token and
matrix-token writes were failing with EACCES on every startup sweep.

Add WriteAgentStateFile to PrivRequest: hive-priv (root) writes the
file 0600 and chowns it to the agent user so the agent can read it.

- hive-sh4re: add AGENT_STATE_ROOT constant + WriteAgentStateFile variant
- hive-priv: validate agent name + filename (no traversal), write via root
- priv_client: add write_agent_state_file helper
- forge: mint_and_persist_token routes agent paths through priv
- matrix: ensure_user_for routes matrix-token through priv

Closes #1257
2026-06-04 14:30:01 +02:00
damocles
be8d8e48bf docs(bash): document wait_seconds param on run + status 2026-06-04 13:51:39 +02:00
damocles
60628fbb13 docs(tools/bash): fix incorrect execution tool group claims 2026-06-04 13:51:39 +02:00
damocles
9c1c4f62fb fix: add approval kind to cancel_loose_end docs; drop stale role comment in mcp.rs; fix system.md approval-cancel description 2026-06-04 13:51:39 +02:00
damocles
78a00d1258 docs(#1251): split MCP tool docs into docs/tools/ sub-mds by feature 2026-06-04 13:51:39 +02:00
atlas
5ec1306c7b feat(gateway): assert hsts.enable requires TLS
Addresses mara's review: add a NixOS assertion that rejects
hsts.enable = true when no TLS mode is configured. HSTS over
plain HTTP is silently ignored by browsers; the assertion turns
a silent misconfiguration into a build-time error.
2026-06-04 13:50:22 +02:00
atlas
5264ef7d5e feat(gateway): add gateway.hsts.enable option, disabled by default
HSTS was unconditionally tied to hasTls. This is risky: enabling it on a
deployment that later loses TLS locks browsers out until max-age expires.

Add three options under services.hyperhive.gateway.hsts:
  enable          — bool, default false
  maxAge          — seconds, default 31536000 (1 year)
  includeSubDomains — bool, default true

HSTS header is now only emitted when hsts.enable = true.
2026-06-04 13:50:22 +02:00
atlas
18941848dc feat(gateway): add security headers to all vhosts
X-Frame-Options, X-Content-Type-Options, Referrer-Policy at server
scope on _, forge, and matrix vhosts. HSTS added when TLS is active.

nginx inheritance rule: locations with their own add_header (CORS API
endpoints like /.well-known/matrix/client, /_matrix/) are unaffected —
they already carry the headers they need. HTML-serving and proxy
locations pick the security headers up automatically.
2026-06-04 13:50:22 +02:00
damocles
5fdc3ffdbf fix: remove issue ref from comment, use forge::FORGE_HTTP in knowledge.rs 2026-06-04 12:31:25 +02:00
atlas
bc0087830f fix: chmod claude dir 0755 so hive-core can list session files
claude_has_session() calls read_dir() on the agent's claude/ dir to
detect a valid session. The dir was 0700 (create-only path), so
hive-core (a different unix user) got EACCES → read_dir returns Err
→ has_session returns false → every agent shows 'needs login' in the
dashboard even when working.

Fix: ensure_claude_dir now always sets 0755. The credential files
inside (e.g. .credentials.json) are 0600, so the secrets stay private
regardless of the containing directory's mode. Existing 0700 dirs are
corrected on the next spawn/rebuild cycle that calls ensure_claude_dir.
2026-06-04 12:15:32 +02:00
damocles
cccb055245 docs: remove stale conflict marker from turn-loop.md 2026-06-04 12:15:03 +02:00
damocles
e58ead4329 fix: address argus+mara review on #1243 — stale docs, MANAGER_DEFAULT refs, ruth migration 2026-06-04 12:15:03 +02:00
damocles
f56b272a23 remove Role::Manager + ManagerSurface + Flavor::Manager — there is only one role: agent 2026-06-04 12:15:03 +02:00
damocles
186ee430b5 docs: comment std::process::exit(0) intent in M_UNKNOWN_TOKEN recovery 2026-06-04 12:12:20 +02:00
damocles
92ed989f8c refactor: move M_UNKNOWN_TOKEN recovery into client::build_and_restore 2026-06-04 12:12:20 +02:00
damocles
7010d06c34 fix: warn on failed sdk state dir removal in M_UNKNOWN_TOKEN recovery 2026-06-04 12:12:20 +02:00
damocles
78db47b00b fix: auto-create knowledge webhook + periodic pull fallback
hive-c0re now auto-creates the Forgejo push webhook for
internal/knowledge at startup (ensure_webhook). this is what was
missing — the webhook endpoint existed but was never registered in
forgejo, so merging iris's PR didn't trigger a pull.

also adds a periodic hourly pull as a fallback (and an immediate pull
at startup to reconcile commits that landed while c0re was offline).

fixes #1244.
2026-06-04 12:12:20 +02:00
damocles
1c5936febb fix: recover from M_UNKNOWN_TOKEN in hive-matrix-daemon
when the homeserver rejects the token (stale session after state wipe or
expiry), the daemon now deletes the token file + matrix-sdk state dir
and exits cleanly instead of crash-looping.

hive-c0re's matrix::ensure_all sweep now runs periodically every 30
minutes (in addition to startup) so deleted token files get
re-provisioned without requiring a hive-c0re restart. the systemd.paths
watcher on the token file path then restarts the daemon with a fresh
token.
2026-06-04 12:12:20 +02:00
atlas
cb314f77b9 refactor: extract sync_gateway_nginx fn from ReloadGatewayNginx arm
Per argus review on PR #1247: move the ~50-line inline match arm into
its own async fn sync_gateway_nginx() -> Result<(String, String)>.
Match arm becomes a one-liner.

Also add a tracing::warn when the ActiveState query exits non-zero
(gateway container down) so the cause is visible in the log.
2026-06-04 11:12:06 +02:00
atlas
c7ea495bf9 docs(priv_proto): update ReloadGatewayNginx comment — state-aware dispatch
The implementation now queries ActiveState and dispatches reload/
reset-start/start rather than blindly calling systemd-run nginx -s reload.
Clarify that machine-bus transport requires root.
2026-06-04 09:53:05 +02:00
atlas
6fab0d7f1a docs: update gateway.md — nginx reload goes through hive-priv
Reflect the fix from the companion Rust change: the nginx reload/start
is now routed through hive-priv (root) instead of calling
systemd-run --machine= directly from unprivileged hive-c0re.
Document the state-aware dispatch (active→reload, failed→reset+start,
other→start).
2026-06-04 09:51:49 +02:00
atlas
1d062d1e3e fix: route gateway nginx control through hive-priv
systemctl --machine=hive-gateway requires root (machine-bus transport
enters the container namespace). hive-c0re is unprivileged, so every
call to nginx_active_state() and gateway_systemctl() silently failed
with exit 1, causing a continuous 30s retry loop without ever
syncing nginx.

Fix:
- Move state-aware nginx logic into hive-priv ReloadGatewayNginx:
  check ActiveState, then reload/reset-start/start accordingly.
  hive-priv already runs as root and has machine-bus rights.
- Remove nginx_active_state() and gateway_systemctl() from
  gateway_nginx.rs (they were always running unprivileged, always
  failing silently).
- Make write(), reload_if_pending(), reload_gateway_nginx() async so
  they can call the async priv_client without a blocking bridge.
- Update callers in agent_sockets::spawn_poll and meta::sync_agents
  to await the now-async functions.

The priv_client::reload_gateway_nginx() call and PrivRequest::ReloadGatewayNginx
wire type already existed — the gateway_nginx module was just not using them.
2026-06-04 09:48:56 +02:00
damocles
7cf7f043ad drop ManagerServer type alias and serve_manager_stdio — no manager agent 2026-06-04 00:20:17 +02:00
damocles
7261992fda remove flavor from AgentServer — dumb dispatcher, tool groups gate access 2026-06-04 00:20:17 +02:00
damocles
3c5abd3c85 rename HiveServer -> AgentServer per mara's feedback 2026-06-04 00:20:17 +02:00
damocles
c634dab2a6 refactor: unify AgentServer + ManagerServer into HiveServer {socket, flavor} 2026-06-04 00:20:17 +02:00
lexis
1698372572 docs: bash_run timeout now fully optional, no default
PR #1223 removed the default 180s timeout. timeout_secs is now fully
optional: pass a value for a deadline, or omit for no timeout (natural exit).
2026-06-04 00:03:55 +02:00
damocles
84383568b2 fix: true atomic bulk topology -- apply_set_parent + single write, add # Errors docs 2026-06-03 23:24:55 +02:00
damocles
7ec0a36d7a fix(#1218): bulk topology move uses one git commit via new set-parent-bulk endpoint 2026-06-03 23:24:55 +02:00
atlas
644519f358 fix: skip matrix avatar upload when icon unchanged
matrix-avatar-sync ran on every boot (RemainAfterExit=false + path
trigger), uploading a fresh PNG each time. Every upload mints a new
mxc:// URI, which triggers a profile state event in every joined room
— resulting in timeline spam even when the avatar hasn't changed.

Fix: before uploading, compute sha256sum of /etc/hyperhive/icon.svg
and compare against the last-synced hash stored in
$HYPERHIVE_STATE_DIR/matrix-avatar-icon-hash. Skip the upload if the
hash matches. Write the hash after a successful avatar_url PUT so
subsequent boots are no-ops until the icon file changes.

Hash file lives in the agent's state dir — survives restart, cleared
on purge (so purge + re-provision gets a fresh upload). Delete to force
re-upload manually.

Closes #1231
2026-06-03 23:24:21 +02:00
damocles
d3239fef35 fix(#1233): subscription --watch uses PUT, GET handles 404 as not-watching 2026-06-03 23:23:51 +02:00
atlas
34bc4c0b06 fix: route forge_admin through hive-priv; auto-recover matrix passwords
forge_admin() spawned nixos-container run hive-forge directly from the
hive-core process. nixos-container run uses nsenter to enter the container
namespaces, which requires root. hive-core is unprivileged, so every call
failed with: nsenter: stat of /proc/<pid>/ns/user failed: Permission denied

Fix: add RunForgeAdmin { args } to PrivRequest. hive-priv (root) handles
it by spawning nixos-container run hive-forge -- runuser -u forgejo --
forgejo --work-path /var/lib/forgejo admin <args>. forge_admin() now calls
priv_client::run_forge_admin().

matrix: ensure_user_for hit M_USER_IN_USE then failed when the stored
password file was missing (state dirs wiped but homeserver kept accounts).
Previously required manual hivectl matrix reset-password <name>.

Fix: add auto_reset_password() — calls the admin API (PUT
/_synapse/admin/v2/users/@<name>:<server> with the hive admin token) to
set a new random password, then proceeds with login. Falls back to the
existing manual-recovery error if the admin token is unavailable.

Closes #1234
2026-06-03 23:21:45 +02:00
damocles
3830b13b03 fix(#1178): add list_containers to ToolGroup::Lifecycle tools slice 2026-06-03 23:08:31 +02:00
damocles
94c2d651c0 feat(#1178): add list_containers tool to AgentServer (topology-scoped to descendants) 2026-06-03 23:08:31 +02:00
damocles
1353fbaf17 docs: add list_containers to agent lifecycle tools in turn-loop.md 2026-06-03 23:05:33 +02:00
lexis
e5bcd16daf docs: turn-loop.md agent lifecycle + config request tools (follow-up to #1226) 2026-06-03 22:55:50 +02:00
damocles
3fa31a414f feat(#791): add request_init_config + request_apply_commit to AgentServer (topology-scoped) 2026-06-03 22:52:52 +02:00
atlas
dacd83f278 fix: wait for forge-core-token in prefetch instead of bailing early
On first boot (or after a wipe) hive-c0re writes forge-core-token only
after the forge container starts and the admin is provisioned. This
lags hive-c0re.service becoming active. The previous code bailed
immediately with TOKEN=placeholder if the token file was absent,
causing the runner to fail registration with 'token not found'.

Fix: merge both waits (core-token file appearance + forge API ready)
into a single 60s retry loop. The early-bail path is removed; the
script only exits cleanly if .runner is valid (writes placeholder)
or a fresh registration token is obtained.

When .runner exists but core-token is absent after 60s, we keep the
existing credentials (safe — the runner holds valid creds; next boot
will validate properly).

Closes #1224 (which tracks #1221).
2026-06-03 22:50:01 +02:00
damocles
280ae23c0c fix(#1220): remove default 180s timeout from bash run — no timeout unless explicitly set 2026-06-03 22:35:51 +02:00
atlas
4fbe9e4927 feat: surface pending matrix invites in get_loose_ends
Write mcp-loose-ends/matrix.json on invite arrival (before wake) and
after join_room clears an invite. The harness scans mcp-loose-ends/
generically in get_loose_ends, so pending invites are visible there
without any harness-side changes.

- paths: add mcp_loose_ends_dir() (mirrors hive-bash-mcp pattern)
- handlers: add refresh_invite_loose_ends() — atomic tmp+rename write
- handlers: join_room calls refresh after successful join to clear entry
- timeline: install_invite_handler refreshes loose-ends before wake
2026-06-03 22:33:58 +02:00
atlas
06b4745d76 fix: wake agent on matrix invite instead of auto-accepting 2026-06-03 22:33:58 +02:00
atlas
c5b35fb5fa feat: auto-accept matrix room invites in hive-matrix-daemon 2026-06-03 22:33:58 +02:00
atlas
9209094397 fix: move core-token out of hive-ci container (host-side prefetch service) 2026-06-03 22:18:53 +02:00
damocles
2722e1548c feat(#1178): add kill + update tools to AgentServer (topology-scoped) 2026-06-03 22:18:03 +02:00
damocles
29c7f64bd3 refactor(#1202): introduce HiveEnv + AgentPaths to reduce arg repetition 2026-06-03 22:09:08 +02:00
atlas
e7785b4948 docs: add # Errors doc to ensure_hive_space 2026-06-03 22:01:37 +02:00
atlas
60582c0be4 feat: create hive Matrix Space on boot and invite all agents 2026-06-03 21:56:13 +02:00
atlas
d726a0d875 docs: clarify nix eval is not fully sandboxed (IFD, fetchGit can reach network) 2026-06-03 21:52:59 +02:00
atlas
e92cfe7e1a docs: add security warning for unsandboxed CI builds and trusted-contributor scope 2026-06-03 21:52:59 +02:00