docs: fix 329 Microsoft.Contractions hits with proper safety checks

Apply contraction fixes across ~40 doc files (setup, integrations, lifecycle,
networking, scheduler, swarm, tools, trust-boundary, UI, etc.). Skipped 14 hits:
- 10 where words appear in ALL CAPS for deliberate emphasis (is NOT, do NOT, etc.)
- 4 where text could not be safely located due to markdown formatting or column position

Applied via systematic scan with checks for fenced code blocks, inline code spans,
and intentional caps. Preserves sentence-initial capitalization throughout.
This commit is contained in:
iris 2026-09-07 14:28:23 +02:00 committed by mara
commit 78021ce982
38 changed files with 320 additions and 320 deletions

View file

@ -4,14 +4,14 @@
The sections below document specific mechanisms (the state-file endpoint,
nixbld isolation, privilege separation). This section frames the model they
serve: **what hyperhive defends, what it deliberately does not, and where the
operator is accepting risk.** It is the reference for "is it safe to give an
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?".
### The trust boundary is the container, not credential storage
An agent is **trusted code running inside its own nspawn container**. The
boundary that matters is the container: a sub-agent cannot see the host
boundary that matters is the container: a sub-agent can't see the host
netns, another agent's container, or another agent's state dir. Within its
own container the agent is privileged — it has **passwordless `sudo` by
default**. Isolating credentials _from the agent itself_ is therefore **not a
@ -20,10 +20,10 @@ run arbitrary commands as root inside its container. (The narrow exception is
_cross-tenant_ leakage — e.g. 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 do not sandbox the agent from itself.)
boundary; they don't sandbox the agent from itself.)
The corollary: **don't reason about security as "can the agent be stopped from
touching its credentials". Reason about it as "what is the blast radius if this
touching its credentials". Reason about it as "what's the blast radius if this
agent does the worst possible thing with everything it can reach".**
### Scoped tokens bound the blast radius
@ -31,7 +31,7 @@ agent does the worst possible thing with everything it can reach".**
Each agent gets its own scoped credentials, never shared:
- **forge token** → that agent's Forgejo account only (its own repos +
collaborator grants; cannot act as another agent or as `core`).
collaborator grants; can't act as another agent or as `core`).
- **matrix token** → that agent's matrix account only.
So a compromised/confused agent's reach on the forge or matrix is bounded by
@ -66,7 +66,7 @@ checkpoints**, not about sandboxing the agent from its own tools:
merges restricted to the operators team + a required operators-team approval
(`apply_operator_branch_protection` / the config-repo equivalent) — and an
agent (a write collaborator, not a repo admin) can neither change those
settings nor merge its own PR. It is **not** set up for external VCS (GitHub
settings nor merge its own PR. it's **not** set up for external VCS (GitHub
etc.), though — there, operator-merge is process + accepted risk, not a
technical control.
- **Approvals** — config changes, schedule additions, and other
@ -107,7 +107,7 @@ before touching the filesystem:
(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 is
`/state/...` without an agent prefix is explicitly _not_ accepted — it's
ambiguous from the host's perspective.
Defense-in-depth layers (in order):
@ -145,7 +145,7 @@ before building `agent_notes_dir(name)`, so a `..` component can't traverse.
Agent containers bind-mount the host's `nix-daemon` socket. The host daemon may
have `sandbox-fallback = false` (strict NixOS defaults), which causes `nix build`
inside nspawn containers to fail — containers lack kernel user namespaces, so nix
cannot set up its build sandbox. the agent modules set `sandbox-fallback = true`
can't set up its build sandbox. the agent modules set `sandbox-fallback = true`
so that builds fall back to unsandboxed execution rather than failing outright.
### Threat model
@ -156,22 +156,22 @@ any file in the container that the nixbld user can read.
The blast radius also has a **network** dimension. hive-ci runs its unsandboxed
builds of untrusted PR code in its own private netns behind the hive bridge: a
build reaches the forge only through the gateway and cannot reach host-loopback
build reaches the forge only through the gateway and can't reach host-loopback
services — including the core dashboard at `127.0.0.1:<dashboard_port>`, which
has no application-layer auth of its own (see [`docs/scheduler/ci.md`](../scheduler/ci.md)). The `0600`
token policy bounds file reads; network isolation bounds network reach.
**What is NOT exposed**:
**what's NOT exposed**:
- `/home/<name>/.claude/` — mode `0700`, owned by the per-agent
user `<name>`. nixbld users cannot read it.
user `<name>`. nixbld users can't read it.
- `$HYPERHIVE_STATE_DIR/forge-token` (= `/agents/<name>/state/forge-token`)
— written at mode `0600` and chowned to the per-agent uid:gid (see
`hive-c0re/src/forge/mod.rs`'s module doc for exactly where). nixbld users
cannot read it.
can't read it.
**Policy**: all credential files written to agent state directories MUST be mode
`0600` or stricter. Do not create world-readable secret files in agent state dirs.
`0600` or stricter. don't create world-readable secret files in agent state dirs.
### Long-term fix
@ -185,14 +185,14 @@ bind-mount compatibility with user namespace UID mapping and is tracked as a TOD
### Background
`hive-c0re` runs as the unprivileged system user `hive-core`
(`/var/lib/hyperhive` owned by `hive-core:hive-core`). It cannot
(`/var/lib/hyperhive` owned by `hive-core:hive-core`). It can't
directly invoke `nixos-container`, `journalctl -M`, or act on a system
unit (`systemctl reload nginx`) — those require root. `hive-priv` fills
this gap.
⚠️ **`ReloadGatewayNginx` acts on a host unit, so nothing implicitly
scopes it.** Its containment is the unit name hard-coded in `hive-priv`:
a caller cannot name the unit, so the verb cannot be steered at another
a caller can't name the unit, so the verb can't be steered at another
service. **A privileged verb needs something bounding what it can act
on; when that isn't a namespace, it has to be a constant the caller
can't supply.**
@ -228,12 +228,12 @@ known operations; there is no arbitrary command pass-through:
allowlist before any operation: only names matching the agent-name
convention (char-validated) or the known sibling service containers
(`hive-forge`, `hive-matrix`, `hive-ci`) are accepted. `hive-gateway` is
a host unit, not a container, so it is not in this list — see
a host unit, not a container, so it's not in this list — see
`ReloadGatewayNginx` above for how its access is scoped instead.
Arbitrary container names are rejected.
**Socket-activated** — systemd starts `hive-priv` on the first
incoming connection (`LISTEN_FDS=1`); it is not running between calls.
incoming connection (`LISTEN_FDS=1`); it's not running between calls.
The `ProtectSystem=strict` + `ReadWritePaths` sandbox limits filesystem
writes to only the paths `hive-priv` legitimately needs.