fix agent-logs unit dropdown mismatch, add other hive daemons

Dashboard AGENT log tab sent unit=hive-ag3nt.service (the crate/dir
name) but the actual systemd unit is hive-agent.service, so every
fetch 400'd against the backend allow-list. Fixed the dropdown value
and, per the same issue's request, added the other per-agent daemons
(hive-mcp-http, hive-bash-daemon, hive-matrix-daemon) as selectable
units, plus hive-priv.service on the SYSTEM tab's host-daemon list.
Extended both backend allow-lists (post_journal / post_journal_host)
to match, and fixed a stale systemd.services.hive-ag3nt doc reference
in agent-hierarchy.md that had the same crate/unit-name confusion.
This commit is contained in:
iris 2026-07-15 20:30:23 +02:00 committed by mara
commit a73216e8be
4 changed files with 21 additions and 9 deletions

View file

@ -216,7 +216,7 @@ nspawn agent. Open questions, not yet wired:
One harness serve binary (`hive-agent`, with its `hive-agent-mcp` /
`hive-agent-wake` siblings), one shared `nix/agent-modules/` tree, one
service unit (`systemd.services.hive-ag3nt`) for all agents. There
service unit (`systemd.services.hive-agent`) for all agents. There
is no longer a separate manager service name or role distinction in
the harness — privilege differences live server-side in the broker
socket (which tool groups and manager-surface calls each agent

View file

@ -734,7 +734,9 @@ routing is hash-based (`#agent`, `#system`, `#audit`); default is
**AGENT sub-tab** — per-container journald viewer. Two selects: agent
name (populated from `GET /api/state`) and unit filter
(`hive-ag3nt.service` / `(full machine journal)`). Fetches
(`hive-agent.service` / `hive-mcp-http.service` /
`hive-bash-daemon.service` / `hive-matrix-daemon.service` /
`(full machine journal)`). Fetches
`GET /api/journal/{name}?unit=<unit>&lines=500` on selection change
or `↻ refresh`. Output rendered as a `<pre>` block. A `?agent=<name>`
and/or `?unit=<svc>` URL param pre-selects the agent + unit on page
@ -743,9 +745,9 @@ deep-link directly to a specific agent's journal. A "fetched N ago"
chip appears after the `↻ refresh` button following each successful
fetch and ticks every 30 s.
**SYSTEM sub-tab** — host-side service logs. Unit selector (currently
only `hive-c0re.service`). Fetches
`GET /api/journal-host?unit=hive-c0re.service&lines=500` on activation
**SYSTEM sub-tab** — host-side service logs. Unit selector
(`hive-c0re.service` / `hive-priv.service`). Fetches
`GET /api/journal-host?unit=<unit>&lines=500` on activation
and on `↻ refresh`. Rendered as a `<pre>` block. A "fetched N ago"
chip ticks every 30 s. Available to the operator unconditionally (not
capability-gated — the endpoint lives on the hive-c0re dashboard,

View file

@ -45,7 +45,10 @@
<div class="logs-toolbar">
<select id="agent-select" class="journal-unit"></select>
<select id="agent-unit-select" class="journal-unit">
<option value="hive-ag3nt.service">hive-ag3nt.service</option>
<option value="hive-agent.service">hive-agent.service</option>
<option value="hive-mcp-http.service">hive-mcp-http.service</option>
<option value="hive-bash-daemon.service">hive-bash-daemon.service</option>
<option value="hive-matrix-daemon.service">hive-matrix-daemon.service</option>
<option value="">(full machine journal)</option>
</select>
<button type="button" class="btn btn-restart" id="agent-refresh">↻ refresh</button>
@ -61,6 +64,7 @@
<div class="logs-toolbar">
<select id="system-unit-select" class="journal-unit">
<option value="hive-c0re.service">hive-c0re.service</option>
<option value="hive-priv.service">hive-priv.service</option>
</select>
<button type="button" class="btn btn-restart" id="system-refresh">↻ refresh</button>
<span id="system-fetch-ts" class="meta logs-fetch-ts" hidden></span>

View file

@ -57,8 +57,14 @@ pub(super) async fn get_journal(
let lines = q.lines.unwrap_or(500).min(5000);
let unit = match q.unit.as_deref().filter(|s| !s.is_empty()) {
Some(u) => {
// accept hive-agent[.service] — anything else refused.
let allowed = ["hive-agent.service"];
// accept any of the per-container hive daemons [.service] —
// anything else refused.
let allowed = [
"hive-agent.service",
"hive-mcp-http.service",
"hive-bash-daemon.service",
"hive-matrix-daemon.service",
];
let unit = if u.ends_with(".service") {
u.to_owned()
} else {
@ -115,7 +121,7 @@ pub(super) async fn get_journal_host(
axum::extract::Query(q): axum::extract::Query<JournalHostQuery>,
) -> Result<Response, ProblemDetails> {
let lines = q.lines.unwrap_or(500).min(5000);
let allowed = ["hive-c0re.service"];
let allowed = ["hive-c0re.service", "hive-priv.service"];
let mut cmd = tokio::process::Command::new("journalctl");
cmd.args(["--no-pager", "--output=short-iso", "--lines"])
.arg(lines.to_string());