Watch
0
0
Fork
You've already forked hyperhive
0

dashboard: remove the state-file endpoint, the file_refs path scan and the unused marked and dompurify deps

This commit is contained in:
iris 2026-10-22 00:02:43 +02:00 • committed by mara
commit 6d080ea28b
11 changed files with 12 additions and 419 deletions

View file

@ -339,8 +339,7 @@ Under `/var/lib/hyperhive/agents/<name>/`:
`work/` doesn't walk up into `state/AGENTS.md` and load the agent's
own identity. Survives `destroy`/recreate, gone on `--purge`. Counted
in the per-agent disk metric (`measure_agent_disk`) together with
`state/` and the container rootfs. The dashboard doesn't serve it:
the state-file endpoint reads `state/` only.
`state/` and the container rootfs. The dashboard doesn't serve it.
### Cross-agent access to state

View file

@ -2,8 +2,8 @@
## Agent trust model
The sections below document specific mechanisms (the state-file endpoint,
nixbld isolation, privilege separation). This section frames the model they
The sections below document specific mechanisms (nixbld isolation,
privilege separation). This section frames the model they
serve: **what hyperhive defends, what it deliberately doesn't, and where the
operator is accepting risk.** It's the reference for "is it safe to give an
agent capability X?."
@ -20,9 +20,8 @@ default**. Isolating credentials _from the agent itself_ is therefore **not a
goal**: an agent can read its own tokens, its own `/home/<name>/.claude`, and
run arbitrary commands as root inside its container. (The narrow exception is
_cross-tenant_ leakage — for example the unsandboxed-nix-build `0600` token policy
below stops a build's nixbld user reading the agent's own forge token, and the
state-file endpoint stops one agent proxying another's files. Those harden the
boundary; they don't sandbox the agent from itself.)
below stops a build's nixbld user reading the agent's own forge token. That hardens
the boundary; it doesn't sandbox the agent from itself.)
<!-- vale write-good.Passive = YES -->
@ -162,45 +161,10 @@ into an agent's config, that agent has exactly that reach, with no hyperhive
layer narrowing it. Scope external tokens tightly at the source (the external
provider) before handing them over.
## State-file endpoint security model
## Agent-supplied names in paths
`GET /api/state-file?path=<p>` serves files from agent state dirs and
the shared space to authenticated dashboard users (browser, operator).
It accepts two allow-listed root prefixes and rejects all other paths
before touching the filesystem:
- `/var/lib/hyperhive/agents/<n>/state/` — per-agent durable notes
(canonical host form or the in-container view `/agents/<n>/state/`)
- `/var/lib/hyperhive/shared/` — shared docs (`/shared/` in-container)
`/state/...` without an agent prefix is explicitly _not_ accepted — it's
ambiguous from the host's perspective.
Defense-in-depth layers (in order):
1. **Allow-list prefix check** — rejects without touching the filesystem
if the path doesn't match either root.
2. **No symlinks below the matched root** — each path component is
checked with `symlink_metadata` before canonicalize. A sub-agent
that plants `ln -s /other/secret /agents/me/state/peek` can't proxy
another agent's file through this endpoint (canonicalize would
happily resolve the symlink to a still-within-allow-list path).
3. **Canonicalize as belt-and-braces** — resolves `..`/`.` traversal
and rejects if the result escapes the roots.
4. **`state/` subdir constraint** — under `AGENTS_ROOT`, the second
path component must be `state/`. Applied, proposed git repos and
config dirs are off-limits.
5. **World-readable check** — file must have `mode & 0o004` set.
A `0600` file inside `state/` would otherwise be accessible to any
operator with dashboard access.
`scan_validated_paths` (broker-message ingest, linkifier) uses the same
`resolve_state_path` helper so security rules stay in sync — the
dashboard renders anchors only for tokens that passed the same checks the
read endpoint enforces.
The same invariant holds wherever an agent-supplied name reaches a filesystem
path: the agent socket's `GetAgentMeta` takes `name` as a serde-validated
Wherever an agent-supplied name reaches a filesystem path, hyperhive validates
it first. The agent socket's `GetAgentMeta` takes `name` as a serde-validated
`hive_types::Ident` (or falls back to `Ident::parse` for the "self" case)
before building `agent_notes_dir(name)`, so a `..` component can't traverse.

View file

@ -555,23 +555,6 @@ below — some endpoints aren't in it yet.
stdout+stderr as `text/plain`. Used by the `↓ raw` / `↓ download
raw` links in the build tabs. Works on both finished and in-progress
build logs.
- `GET /static/marked.js` serves the vendored `marked` bundle used
for markdown previews.
- `GET /api/state-file?path=<host-or-container-path>` — bounded
text read of a file under the per-agent `state/` subtree or
the shared `/var/lib/hyperhive/shared/`. Accepts the
container-view forms (`/agents/<n>/state/...`, `/shared/...`)
and the host form. Canonicalises + verifies the path stays
inside the allow-list, refuses anything but a regular file,
refuses `/agents/<n>/claude` / `config` subtrees, truncates
bodies at 1 MiB. No dashboard page calls it since the flow page
stopped existing.
The broker forwarder still detects path tokens **server-side at
broker-message ingest**: it calls `scan_validated_paths(body)` —
same allow-list helper the read endpoint uses — and attaches
the verified file tokens to the event as `file_refs: Vec<String>`.
No dashboard page reads that list either.
- `GET /api/reminders` — list pending reminders for the
dashboard's queued-reminders panel.
- `GET /api/stats-hive?window=<1h|4h|24h|3d|7d|30d|all>` — hive-wide