A `status` or `run` call whose inline `wait_seconds` poll observes a
terminal task hands the caller the full result in that same tool
response. The completion wake fired unconditionally regardless,
producing a redundant `bash-task-<id>` inbox message for information
the agent already has.
Add a one-shot, in-memory wake-suppression registry in hive-bash-mcp's
runner: `wait_for_task` (shared by both BashRun's and BashStatus's
inline-wait paths) marks a task's wake suppressed the moment it
observes a terminal state; `run_task`'s completion handler consumes
that flag before calling `send_wake` and skips the wake if set.
In-memory only (daemon restart wipes it) — fine, since a task still
running across a restart is separately marked `interrupted` on boot
and gets its own fresh wake. Narrow best-effort race window between
the terminal write and the wake send; acceptable given this daemon's
existing best-effort delivery tolerance elsewhere.
docs/tools/bash.md updated to describe the new suppression behavior.
- docs/network.md: LOCAL_ADDRESS is now empty (not deterministic-IP);
containers use dhcpcd + dnsmasq DHCP pool, not hash-derived static IPs
- nix/modules/hive-ci.nix: 'service containers' → 'all containers'
in the dnsmasq DHCP pool comment (agents also use the same pool)
New POST /api/infra-container/{name}/{action} dashboard route (start/
stop/restart on hive-ci/hive-forge/hive-gateway/hive-matrix), reusing
the existing priv_client::control_infra_container helper the
infra_admin agent path already uses, plus an audit_log entry per
attempt. Adds infra_containers to the /api/state StateSnapshot (name +
live running status via systemctl is-active). New 1NFR4 sub-tab on the
C0R3 dashboard page: one row per infra container with a running/
stopped badge and start/stop/restart buttons, polled every 5s while
the sub-tab is open.
Part 2 of hyperhive#1970 (backend/CLI landed in PR #2378). Renames
/matrix-accounts.html -> /credentials.html and restructures it with a
sub-tab strip (MATRIX / GITHUB), reusing the shared @hive/shared/tabs.js
tab strip already used by /logs.html.
MATRIX tab carries over the existing account list + login form
unchanged. GITHUB tab adds a single-PAT provisioning form: status line
(present/absent, read from GET /api/github-account), a security-warning
banner (dedicated bot account + minimally-scoped token), a link to
generate a PAT at github.com/settings/tokens, and a paste-token form
posting to POST /api/github-account. Both tabs share one agent picker.
Updated docs/web-ui.md + docs/web-ui/dashboard.md to describe the new
page shape, and the H0M3 hub tile (index.html) to point at the renamed
page.
Per damocles review comment: conventions.md:328 (canonical group-membership
table) and agent-hierarchy.md (privilege scope table) were missing the new
tool entry. Both now match ToolGroup::Approvals slice.
MergeConfigPr approvals had a fully-implemented approve handler
(run_merge_config_pr, ff_push_to_main, mark_pr_merged) and dashboard
display, but no way to submit one. An agent with the `approvals` tool
group calling request_merge_config_pr(agent, pr_number) is the missing
piece.
What this adds:
- RequestMergeConfigPr variant in hive-sh4re AgentRequest + ToolGroup::Approvals
- submit_merge_config_pr: fetches PR head sha (the drift-gate reviewed sha),
queues a MergeConfigPr row, sets fetched_sha, emits approval_added with
pr_number so the dashboard card links to the forge PR
- handle_request_merge_config_pr: topology (require_descendant) +
tool-group (require_group(approvals)) guards before submit
- socket_server/mod.rs: dispatch arm for RequestMergeConfigPr
- hive-ag3nt MCP tool: request_merge_config_pr with full description
- docs/tools/lifecycle.md: documents the new tool + boundary table row
Unlike submit_apply_commit, no flake pre-flight at submission time (eval-
verify happens at approval time inside run_merge_config_pr, same as the
rest of the merge pipeline). Applied repo must already exist (guard added
with a clear error message pointing at request_apply_commit for first-spawn).
Security fixes landed without updating the security-model docs; bring them
current as present-tense invariants:
- security.md: matrix identities are public / cross-agent-readable via
GetAgentMeta while the token stays private; name validation extends to
GetAgentMeta; the nix-build blast radius has a network dimension (hive-ci
netns) alongside the 0600 token policy.
- boundary.md: the core dashboard /api has no app-layer auth — protection is
the gateway plus network isolation; stated as a standing invariant.
- ci.md: hive-ci runs in its own private netns behind the bridge, reaches the
forge via the gateway, and cannot reach host-loopback (dashboard/forge port).
- knowledge.md: /knowledge excludes .git via tmpfs so the core token in
.git/config isn't readable by agents.
Refs #2308, #2310, #2313.
reqwest has no UDS transport, so unix: upstreams dial the socket
directly with a raw hyper/1.1 client per request instead. http(s)://
upstreams are unaffected (still go through the existing reqwest path).
Adds hyper (client, http1), hyper-util (tokio IO adapter), and
http-body-util as direct hive-ag3nt dependencies - all three were
already present transitively via reqwest, this just uses them
directly for the new code path.
Both mdNode implementations (agent UI app.js, dashboard common.js)
assigned marked.parse() output straight to innerHTML with no
sanitizer. marked v5+ dropped its built-in sanitize option, and there
was no DOMPurify anywhere in frontend/, so markdown containing raw
HTML/script tags rendered live in the browser.
Both sinks receive untrusted input in practice: the agent UI's mdNode
renders recv tool_result bodies, assistant prose, and send/ask/answer
payloads sourced from peer agents and matrix-relayed messages (the
documented prompt-injection adversary); the dashboard's mdNode renders
agent-authored .md files served verbatim by GET /api/state-file
(the endpoint validates path, not content). Since the per-agent UI and
dashboard are same-origin behind the gateway with operator-authority
endpoints (approve/spawn/rebuild/destroy/answer-question), injected
script would run with the operator's session.
Fix: DOMPurify.sanitize() the marked.parse() output at both sinks
before assigning to innerHTML. Added dompurify as a dependency to
both the agent and dashboard npm workspaces, recomputed npmDepsHash
in nix/frontend.nix for the updated lockfile. Also corrected
docs/web-ui/shape.md, which claimed the markdown-rendering path was
XSS-safe by construction the same way the text-node-based linkify
path is — it isn't; it's safe because it's sanitized.
CSP hardening for the dashboard (no unsafe-inline) is a separate,
larger backend change (response headers in hive-c0re) and is left as
a fast-follow rather than folded into this fix.
every agent lifecycle verb on the admin socket (rebuild / restart /
restart-all / kill / stop / start) now submits job-queue DAGs and
returns their ids; hivectl polls the new HostRequest::QueueDag and
prints a live node-chain progress line per DAG (fan-out children
included), exiting non-zero on failure — --no-wait opts out. DagView
and the queue wire enums move to hive_sh4re::jobs (wire types live in
the shared crate); the last fused rebuild path (lifecycle::rebuild)
is gone. tracker: #2166
- deploy-window gate (meta::exclusive) + path-limited meta commits:
a perm/lock/topology commit can no longer sweep an ApprovalDeploy's
staged flake.lock and neuter abort_deploy (regression test included)
- cancel surfaces now buffer terminal roll-ups the scheduler drains,
so a queued approval DAG cancelled by the operator resolves its
approval instead of dangling, and cancelled power ops revert their
wanted flip to the observed state
- hivectl restart / restart-all ride the queue (lease serialization,
transient guard) and restart sets wanted=Up like the old kill+start
- exactly one Rebuilt event per rebuild DAG, emitted at terminal
- StopForUpdate pre-seeds a missing agent_power row from the pre-stop
observation so a rebuild can't strand an unknown agent offline
- history trim keeps terminal fan-out parents with live children
- audit_log back on db::open; swarm.js badge for reconcile DAGs
coordinator.md rewrites the queue section (node inventory, DAG shapes,
resources, desired-state reconciliation, boot reconcile); approvals.md
+ persistence.md + hivectl --graceful help updated to match. agent_power
lives in broker.sqlite like approvals/questions (own connection + busy
timeout) instead of a separate db file.
Per argus review: correct routing subject from 'root/manager agent' to
'submitting agent (root agent for top-level containers; approvals-group
agent for its own subtree)', and drop the deprecated 'manager' term.