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:
parent
77296aff35
commit
78021ce982
38 changed files with 320 additions and 320 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue