Commit graph

1,527 commits

Author SHA1 Message Date
damocles
d31a723daf feat(#550): add depends_on to queue entries for explicit dep tracking 2026-06-04 17:39:31 +02:00
atlas
1fa398e99e fix: use correct tuwunel admin room command prefix for reset-password 2026-06-04 16:43:53 +02:00
atlas
85de83bd49 fix: use correct tuwunel admin room command prefix for make-user-admin
tuwunel requires '!admin users <cmd>' — bare 'make-user-admin @user:server'
is not recognised. Update command string and doc comments.
2026-06-04 16:35:59 +02:00
atlas
0f505d5c95 fix: increase admin-room poll timeout from 5s to 15s
tuwunel can take longer than 5 seconds to process admin-room commands
during startup when the homeserver is under load. Bump both the poll
count (5→15) and the timeout message strings to match.
2026-06-04 16:28:47 +02:00
atlas
e06d3e3a8b refactor: extract admin_room_send_and_poll helper — deduplicate poll loop 2026-06-04 16:28:47 +02:00
atlas
2252eac650 fix: replace Synapse admin API in promote_user_to_admin with admin-room command 2026-06-04 16:26:59 +02:00
atlas
74253a9f71 fix: increase admin-room poll timeout from 5s to 15s
tuwunel can take longer than 5 seconds to process admin-room commands
during startup when the homeserver is under load. Bump poll count 5→15
and update timeout message strings to match.
2026-06-04 16:26:04 +02:00
atlas
0a3a956d28 fix: add /var/lib/hyperhive to hive-priv ReadWritePaths
WriteAgentForgeToken and WriteAgentMatrixToken write agent state files
under /var/lib/hyperhive/agents/<name>/state/. The hive-priv service
has ProtectSystem=strict which makes all of /var read-only by default,
but /var/lib/hyperhive was missing from ReadWritePaths, causing EROFS
on every token write.

Closes #1274.
2026-06-04 15:35:46 +02:00
damocles
c2d023ba86 fix(#1269): add requires+after hive-c0re.socket to service unit 2026-06-04 15:16:39 +02:00
atlas
a56badd004 fix: remove Synapse admin API path — use admin-room reset exclusively (tuwunel only) 2026-06-04 15:16:22 +02:00
atlas
97a78cc5d6 fix: address argus review on matrix admin-room reset — ascii lowercase, tighter markers, unit tests 2026-06-04 15:16:22 +02:00
atlas
b2913bc656 fix: admin-room fallback for matrix password reset when Synapse API absent
tuwunel 1.6.x does not implement the Synapse admin REST API.
reset_user_password() now falls back to the Matrix admin room
(#admins:<server>) when PUT /_synapse/admin/v2/users returns 404:

1. Discover admin room ID via #admins:<server> alias
2. Get current messages end-token (pagination anchor)
3. Send 'reset-password @<localpart>:<server>' as @hive admin user
4. Poll for bot response up to 5 x 1s; extract password from message
5. Persist the new password and return it

The function signature changes from Result<()> to Result<String> so the
caller can use the effective password (which may be server-generated on
the admin-room path) for subsequent login calls.

Closes #1267.
2026-06-04 15:16:22 +02:00
atlas
7e229889a6 fix: address argus review on ensure_claude_dir — narrow to EPERM, fix doc comment 2026-06-04 15:03:12 +02:00
atlas
e553e40577 fix: soft-fail chmod in ensure_claude_dir when dir is agent-owned
hive-agent-user-migrate chowns the bind-mounted claude dir to the agent
user on every container boot. After that, hive-core (a different user)
cannot chmod it — set_permissions fails with EPERM, which was propagated
as an error and caused the rebuild to fail entirely.

Fix: make the chmod best-effort. Newly created dirs (owned by hive-core)
get the 0755 mode set immediately; after the agent-migration chown the
mode is preserved so claude_has_session works correctly. Subsequent calls
that hit the EPERM path just log at DEBUG and continue.
2026-06-04 14:48:08 +02:00
damocles
911dc5227b fix(#1263): repeat security headers in locations with their own add_header 2026-06-04 14:35:18 +02:00
damocles
681a86bce9 fix: address argus review on #1260 — drop stale HIVE_ROLE and mcp::Flavor refs from CLAUDE.md 2026-06-04 14:31:44 +02:00
damocles
41eb3f806c refactor: remove hyperhive.role option — there is only one role: agent 2026-06-04 14:31:44 +02:00
damocles
d35408a18d docs: remove stale role field from AgentMeta in conventions.md 2026-06-04 14:30:27 +02:00
atlas
7022cd3826 fix: split WriteAgentStateFile into WriteAgentForgeToken + WriteAgentMatrixToken
Addresses mara's review: each credential type gets its own PrivRequest
variant, making the exact priv surface visible in the wire protocol.
No runtime filename dispatch — the operation name is the gate.

- WriteAgentForgeToken { agent_name, token } → state/forge-token
- WriteAgentMatrixToken { agent_name, token } → state/matrix-token
- priv_client: two typed fns (write_agent_forge_token, write_agent_matrix_token)
- forge.rs: split mint_and_persist_token into mint_and_persist_agent_token
  (priv) + mint_and_persist_core_token (direct write); drop dead token_path fn
- matrix.rs: call write_agent_matrix_token directly
2026-06-04 14:30:01 +02:00
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