mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-10-20 04:21:58 +00:00
docs(egress): align user + dev docs with iron-proxy v0.39 actual behavior
The previous docs round (906b1da57) described the integration the way we wanted it to work — `http_listens` plural with a docker bridge bind, dedicated `audit.log` for per-request JSON records. Live testing against the real v0.39.0 binary in [905ce58a1] surfaced that neither field exists in v0.39's config schema, and the docs were making promises the daemon couldn't keep. This commit walks every claim in the docs back to what the binary actually does today, while keeping the upgrade path explicit so the docs stay coherent when the pinned `_IRON_PROXY_VERSION` bumps: website/docs/user-guide/egress/iron-proxy.md - Bind policy section: rewritten. Was "loopback + docker bridge IP on Linux"; now "loopback only" with an explicit explanation that v0.39 only supports one bind per daemon and that host.docker.internal -> host-gateway mapping is what sandboxes use to reach the loopback bind. - Bind policy section adds a note on the metrics-port pin that the previous round of docs didn't even mention. - State directory layout table: `audit.log` description rewritten to acknowledge it's a pre-created sentinel for future binary versions, NOT something the v0.39 daemon writes to. - New section "Logging on iron-proxy v0.39" replaces the old "Audit log vs daemon log" section. Explicitly tells operators the daemon log is the single source of truth for both audiences on v0.39, with the upgrade path called out. - Data-flow diagram step 7: rewritten to send per-request records to `iron-proxy.log` on v0.39 with cross-link to the new logging section. - Diagram caption updated. - Security-model "allowlisted-host exfiltration" line: "audit log captures" -> "daemon log captures". - Security-model "LAN peer leak" line: removed the docker-bridge claim. - Troubleshooting section's per-request-inspection recipes: rewritten to use `iron-proxy.log` and explain when the split stream will land. - Limitations list gets a new bullet calling out the single-bind + combined-log v0.39 constraints + the auto-upgrade posture. website/docs/developer-guide/egress-internals.md - Bind policy invariant: documents the singular `http_listen` v0.39 schema constraint + dead-code-until-upgrade status of the bridge-bind path. - New "Metrics port collision" invariant documenting why `metrics.listen: 127.0.0.1:0` is non-negotiable. - Audit log fail-loud invariant adds the v0.39 schema constraint note + the new `test_audit_log_kwarg_does_not_inject_audit_path_v039` regression test. - "Subscribing to per-request audit events" section updated to send watchers at `iron-proxy.log` for v0.39 with the upgrade pivot called out. website/docs/reference/cli-commands.md - Diagnostic shortcut for tailing the audit log: `tail audit.log | jq` -> `tail iron-proxy.log | jq` with the v0.39 note inline. Build verification: - `npx docusaurus build` succeeds across all three locales (en + zh-Hans + ko). - New `#logging-on-iron-proxy-v039` anchor lands in the rendered HTML and the in-page cross-references resolve. - No new broken anchors introduced (pre-existing warnings on unrelated zh-Hans pages are unchanged). - No leftover stale `#audit-log-vs-daemon-log` or `#http_listens` references anywhere on the egress pages.
This commit is contained in:
parent
905ce58a12
commit
bde66ef37a
3 changed files with 48 additions and 31 deletions
|
|
@ -169,11 +169,19 @@ Regression: `test_subprocess_env_strips_unrelated_secrets`, `test_subprocess_env
|
|||
|
||||
### Bind policy
|
||||
|
||||
`_default_http_listen` returns loopback + (Linux only) the docker bridge IP. Never `0.0.0.0`, never `:PORT` (INADDR_ANY).
|
||||
`_default_http_listen` returns loopback (and, on Linux, the docker bridge IP as a *second list entry the rendered yaml currently discards* — see below). Never `0.0.0.0`, never `:PORT` (INADDR_ANY).
|
||||
|
||||
`_detect_docker_bridge_ip` validates via `ipaddress.IPv4Address` and rejects `is_unspecified` / `is_loopback` / `is_multicast` / `is_reserved` / `is_link_local` / `is_global`. A hostile `ip` shim on PATH cannot inject `0.0.0.0`.
|
||||
|
||||
Regression: `test_default_bind_is_loopback_not_zero_zero`, `test_detect_docker_bridge_ip_rejects_dangerous` (parametrized over 8 attack inputs).
|
||||
**v0.39 schema constraint:** the binary's `config.Proxy` struct has only a singular `http_listen` string field — there is no `http_listens` (plural) list, despite earlier comments in this module claiming otherwise. `build_proxy_config` emits only the first entry of `_default_http_listen`'s result; the second-bind path is dead code today. When the pinned `_IRON_PROXY_VERSION` is bumped to one that supports the plural form, re-enable the list-emit in `build_proxy_config` and the docker-bridge bind becomes live without further changes.
|
||||
|
||||
Regression: `test_default_bind_is_loopback_not_zero_zero` (asserts loopback bind AND that `http_listens` is NOT in the rendered yaml), `test_default_bind_uses_loopback_on_linux`, `test_detect_docker_bridge_ip_rejects_dangerous` (parametrized over 8 attack inputs).
|
||||
|
||||
### Metrics port collision
|
||||
|
||||
`metrics.listen` defaults to `:9090` in iron-proxy v0.39 — the SAME port as Hermes's default `tunnel_port: 9090`. `build_proxy_config` MUST explicitly pin `metrics.listen: 127.0.0.1:0` so the metrics binding gets an ephemeral loopback port that can never collide with the proxy listener regardless of operator-chosen `tunnel_port`.
|
||||
|
||||
Regression: `test_metrics_listener_pinned_to_loopback_ephemeral`.
|
||||
|
||||
### Default deny CIDRs
|
||||
|
||||
|
|
@ -185,7 +193,9 @@ Regression: `test_default_deny_cidrs_present_when_unspecified`, `test_default_de
|
|||
|
||||
`ensure_audit_log` raises `RuntimeError` on any `OSError`. Swallowing the failure would let the daemon create the file under the default umask, defeating the privacy promise. `cmd_setup` catches the RuntimeError and surfaces a clear error to the operator.
|
||||
|
||||
Regression: `test_ensure_audit_log_raises_on_immutable_parent`.
|
||||
**v0.39 schema constraint:** `log.audit_path` is NOT a field in iron-proxy v0.39's `config.Log` struct, so `build_proxy_config` accepts the `audit_log` kwarg but does NOT emit it into the rendered yaml. Per-request records on v0.39 land in `iron-proxy.log` alongside daemon-level events. The `audit.log` file is still pre-created at `0o600` with `O_NOFOLLOW` so the privacy contract holds when the pinned version is bumped to one that supports the separate stream.
|
||||
|
||||
Regression: `test_ensure_audit_log_raises_on_immutable_parent`, `test_audit_log_kwarg_does_not_inject_audit_path_v039`.
|
||||
|
||||
### Bitwarden mode fail-loud
|
||||
|
||||
|
|
@ -268,7 +278,7 @@ The Docker implementation is ~150 lines; expect similar volume for Modal / Dayto
|
|||
|
||||
### Subscribing to per-request audit events
|
||||
|
||||
iron-proxy writes line-delimited JSON to `~/.hermes/proxy/audit.log`. A plugin / external watcher can tail the file and react to allowlist denials, secret swaps, or upstream errors. The schema is documented at [docs.iron.sh/audit](https://docs.iron.sh/audit) (link).
|
||||
iron-proxy writes line-delimited JSON to `~/.hermes/proxy/iron-proxy.log` on the currently pinned v0.39 (daemon + per-request records combined; see "Logging on iron-proxy v0.39" in the user guide). A plugin / external watcher can tail that file and react to allowlist denials, secret swaps, or upstream errors. When the pinned version is bumped to one that supports `log.audit_path`, the per-request stream moves to `audit.log` and watchers wired to that path go live without operator action. The schema is documented at [docs.iron.sh/audit](https://docs.iron.sh/audit) (link).
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue