Commit graph hyperhive/docs/security.md
Author SHA1 Message Date
iris
1277f5d4ca docs(security): fix stale forge.rs path, GetAgentMeta validator, hive-priv table 2026-08-15 12:45:22 +02:00
iris
58459bbbb3 docs(security): drop origin-story framing, point to module doc instead of internals 2026-08-15 12:45:22 +02:00
atlas
98d895cf9e docs(gateway): describe what is, not what changed
Per review: docs represent current state. Every "used to" / "no longer"
clause this branch introduced is gone — including the History section in
network.md, which was a whole subsection about a sync mechanism that
doesn't exist.

Where the removed clause was carrying a real constraint, the constraint
stays and is stated in the present tense instead of as a delta: nothing
narrows what the gateway's nginx can reach except the directory
permissions in front of a socket, and nothing bounds `ReloadGatewayNginx`
except the hard-coded unit name. Those read as rules now rather than as
the story of how they came to be rules.
2026-08-11 18:09:51 +02:00
atlas
07852cabc1 feat(3088): move the gateway's nginx + dnsmasq onto the host
The gateway's nginx + dnsmasq no longer run in their own nspawn container.
`nix/host-modules/hive-gateway/default.nix` loses the
`containers.hive-gateway` wrapper and everything that existed only to punch
holes in it: `privateNetwork = false`, `CAP_NET_ADMIN`, five bind mounts,
its own `stateVersion`, `networking.firewall.enable = false`,
`networking.resolvconf.enable = false`, and the `hive-gateway-resolv`
path+service pair. 465 -> 303 lines.

The container never bought isolation here. It shared the host netns by
necessity — nginx binds the host's :80/:443, dnsmasq answers on the bridge —
so each of those settings was undoing a boundary the gateway could not
afford in the first place.

Four things made it more than a deletion, none of them visible in the nix
diff:

- The self-signed cert service also imports the hive CA leaf, so removing it
  with the container would have left nginx naming a missing cert file, which
  it refuses to load at all.
- The nginx reload is a hive-priv verb. It still needs root, but no longer
  for the reason its doc gave, and `--machine=` was both transport and
  scope — so the unit name is now hard-coded in the helper as the
  containment.
- The lifecycle verb named a container that stops existing.
- `journalctl -M hive-gateway` had no machine to enter.

Per the operator's ruling, the operator verb keeps working and agents lose
it. `InfraContainer` answered three questions that used to share an answer;
it now splits into `name()` (identity), `target()` (Container vs HostUnit),
`service_unit()` (the systemd unit), and `agent_restartable()`, which the
MCP restart path checks before the capability so the refusal cannot read as
"ask for infra_admin". `SIBLING_CONTAINERS` drops the gateway — it gates the
requests that name a container as a string — while `FromStr` still accepts
it, because that answers what a name is, not who may act on it. The
dashboard's gateway journal reads host journald filtered to `nginx.service`.

Prose was corrected where it only named a location, and re-argued where the
container was doing security work: a `0666` per-agent socket was safe
because only the gateway container had the directory bind-mounted. There is
no mount now, so the directory permissions are the whole of the access
control — the constraint holds, its mechanism doesn't.

Gate: nix fmt / clippy --all-targets -D warnings / cargo test all clean (710
tests); hivectl-cli.md regenerated from the clap tree. The nix eval was run
in both TLS shapes at this commit: every delta in the rendered
virtualHosts is one of the three intended path moves, dnsmasq settings are
byte-identical, and the absence probe flips true -> false with bindMounts
emptied.
2026-08-11 18:01:03 +02:00
atlas
3fc1588e83 fix: declare the agent socket dir's owner in tmpfiles, not by chown after
/run/hive-agent/<name> was 0777 root root in steady state, not just during
first spawn. A directory without the sticky bit lets any user unlink files
in it, and the gateway container has all of /run/hive-agent bind-mounted
in, so anything that could reach the path could delete an agent's
agent.sock, bind its own, and receive that agent's todos from hive-c0re.

Two mechanisms were writing the dir and undoing each other: the tmpfiles.d
entry wrote 0777 root root, then hive-c0re round-tripped through hive-priv's
ChownSocketDir to narrow it. `d` re-asserts mode and owner on every apply
and the file is regenerated on any agent's spawn or destroy, so every such
event reset every agent's dir back to world-writable.

SyncAgentTmpfiles now carries each agent's container uid/gid and the entry
declares the answer: 0751 <uid> <gid>. Three principals need the dir and no
two share a group -- the harness binds its sockets (owner rwx), hive-c0re
dials agent.sock and the gateway's nginx dials web.sock (both only need
traverse, and both sockets are already 0666).

Deletes ChownSocketDir and ChmodSocketDir, both priv_client wrappers, the
either/or in host_config with its two swallowed warn!s, and the now-dead
socket_dir_path -- two verbs off the privileged helper's surface and one
round-trip off every agent spawn.

Also makes the two tmpfiles rules for /run/hive-agent itself agree: the
gateway module said hive-core, the generated file said root, and which won
depended on the order systemd read them in.
2026-08-04 01:00:48 +02:00
atlas
f28a1e33d3 docs(#2754): document the container weights in coordinator/security/persistence
The PR added CPUWeight=/IOWeight= to the drop-in but left the prose
docs describing a two-setting file. Covers the cap-vs-share
distinction, the hive-wide-only scope (no resource-limits.json
override), and the iocost/BFQ caveat that makes IOWeight= inert on
most hosts.
2026-07-27 11:01:36 +02:00
müde
4a48ce5024 refactor: nix/host-modules + nix/agent-modules layout, update doc paths 2026-07-13 22:05:49 +02:00
sock
6c95933775 docs(security): ci netns, knowledge .git tmpfs, matrix id/secret split
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.
2026-07-10 19:17:17 +02:00
atlas
8406a45275 feat(#1997): add prettier markdown formatter to treefmt
- .prettierrc: proseWrap=preserve (no prose reflow)
- .prettierignore: exclude hivectl-cli.md (auto-generated) + 11 docs
  with multi-line list-item continuations prettier would strip to col 0
  (CommonMark limitation in prettier's list handling)
- format 16 markdown files: cosmetic only (*→_, table alignment,
  heading normalisation) — verified no broken continuations, idempotent
2026-07-02 23:33:11 +02:00
atlas
8e366c8a10 docs(security): operator-merge IS enforced on the internal forge
Per mara (verified in forge.rs): agents have max_repo_creation=0, so every
internal-forge repo is core-created with branch protection on by default
(merge restricted to operators team + required operators-team approval via
apply_operator_branch_protection / the config-repo equivalent), and agents
(write collaborators, not admins) can't change it or self-merge. So it's
technically enforced there, not just convention — only external VCS (GitHub)
is unprotected. Corrects my prior over-correction.
2026-06-26 17:19:35 +02:00
atlas
524b1de98c docs(security): correct the operator-merge bullet (mara review)
Per mara: branch protection isn't a blanket enforced check, and it's not
set up for external VCS (GitHub). Reframe the bullet as the operator-merge
*convention* — technically enforced only on the core-managed config repos,
and explicitly NOT wired up for GitHub/external VCS (process + accepted
risk there, not a control).
2026-06-26 17:19:35 +02:00
atlas
9daed8acc1 docs(security): restore the State-file endpoint heading
The trust-model insert accidentally consumed the
'## State-file endpoint security model' heading, leaving that section
floating under the new one. Re-add the heading and collapse the extra
blank lines (argus review).
2026-06-26 17:19:35 +02:00
atlas
cf581d14b8 docs(security): document the agent trust model
Add an 'Agent trust model' framing section at the top of docs/security.md
covering the conceptual model the existing mechanism-level sections serve:

- trust boundary = the container, not credential storage (agents have
  passwordless sudo by default; isolating creds from the agent itself is
  not a goal — cross-tenant leakage is)
- scoped per-agent forge/matrix tokens bound the blast radius
- threat model: prompt injection -> confused deputy (untrusted input is
  the adversary; the agent + its tools are trusted)
- branch protection (agents push, operator merges) as the human-in-loop
  checkpoint, incl. external VCS
- capability = accepted risk ('don't grant what you can't afford to lose')
- no auto-sandboxing of external tokens (operator-accepted scope)

Emerged from the 2026-06-24 security discussion. Updates the CLAUDE.md
pointer for findability.
2026-06-26 17:19:35 +02:00
iris
80c33f5108 docs(security): drop redundant bootstrap-container allowlist entry
The hive-priv container allowlist's explicit MANAGER_NAME allow is
redundant — the bootstrap container's name passes the generic
agent-name char validation anyway. Describe the allowlist as just the
agent-name convention + the sibling service containers.
2026-06-23 14:48:10 +02:00
iris
ec5c7d49c4 docs: reframe stale 'the manager' as the root/bootstrap container (infra + web-ui)
Port-range, network-isolation, state-dir, web-UI-port, priv allowlist,
and rebuild-source mentions now refer to the root/bootstrap container
rather than 'the manager' — no structural manager exists (root-ness is
topological). Real artifact names (the manager.nix template toplevel,
/run/hyperhive/manager/mcp.sock) are left as-is.
2026-06-23 14:48:10 +02:00
iris
09e2ad326c fix: update PrivRequest table to match actual hive-sh4re::priv_proto variants
Replace stale AddBindMount/RemoveBindMount/SetNetworkIsolation/ReloadGateway
entries with the actual current variants from hive-sh4re/src/priv_proto.rs:

- WriteNspawnFlags (replaces AddBindMount/RemoveBindMount/SetNetworkIsolation)
- WriteResourceLimits (new)
- RemoveServiceDropin (new)
- DaemonReload (new)
- ChownSocketDir / ChmodSocketDir (new)
- RunForgeAdmin (new)
- RestartMatrixDaemon (new)
- ReloadGatewayNginx (renamed from ReloadGateway)
2026-06-05 18:40:44 +02:00
iris
28df69286d docs(security): document hive-priv privilege separation model 2026-06-05 18:40:44 +02:00
damocles
42fe3965de docs: move dashboard.rs security + bind rationale to docs (#715) 2026-06-01 11:38:42 +02:00
iris
5ca96b8c85 docs: scrub self-ref cookies across 5 files (#719 batch 2)
All five files scrubbed to 0 issue-ref cookies. Most refs were
'(closes #NNN)' style attribution after closed work landed.

- docs/turn-loop.md: 6 → 0 (#598 unified binary, #419 auth-fail,
  #542 mtime resumption, #519 role markers, #442 spawn path,
  #474/#478 partial edit)
- docs/approvals.md: 5 → 0 (#317 flake validation, #250 withdraw,
  #441 rebuild-queue dispatch, #753 manager port hash, #425
  crash-watch grace)
- docs/terminal-rendering.md: 2 → 0 (#666 ask-operator inline)
- docs/conventions.md: 3 → 0 (#753 port hash, #692 parent
  sentinel, #486 reparenting)
- docs/security.md: 4 → 0 (#240 + #658 ×2 + #673/#678 attribution)

Combined with PR #810 (docs/web-ui.md 14→0), this PR closes the
small / medium files. Remaining: agent-hierarchy.md (13),
gotchas.md (13), persistence.md (13). gateway.md is atlas's lane.
2026-05-31 15:39:09 +02:00
damocles
fcb5fae345 docs: catch up post-#658/#604/#660 + add operator hivectl section (#124) 2026-05-31 10:13:33 +02:00
damocles
6ca72074c4 docs: move sandbox threat model to docs/security.md, add code reference 2026-05-22 12:28:04 +02:00