hermes-agent/tools/environments
Bartok9 45da4b2363
fix(egress): address maxpetrusenko P1/P2 review — fail-closed secrets, NODE_OPTIONS conflict, GPG verify, threat-model scope
Follow-up to the #30179 security review (maxpetrusenko). P0s 1-3 are being
handled separately (kuangmi-bit); this covers the three P1s + the P2.

P1 #4 — secrets replace rules now emit `require: true`. Verified
replaceConfig.Require EXISTS in the pinned iron-proxy v0.39.0 secrets
transform (KnownFields(true) strict decode would otherwise reject it) and is
enforced in TransformRequest: a request to an allowlisted upstream that
arrives WITHOUT the proxy token in a matched location is rejected
(ActionReject) rather than forwarded with whatever credential it carried.
Closes the leak where a real provider key sent directly to an allowed host
passed the proxy boundary.

P1 #5 — NODE_OPTIONS append-merge now resolves CA-mode conflicts. A
docker_env `--use-bundled-ca` would previously survive alongside the
egress-required `--use-openssl-ca`, leaving Node's trust behavior dependent
on option order. Egress flag now wins deterministically (conflicting CA-mode
flags stripped + warning); unrelated operator tuning preserved.

P1 #6 — install now GPG-verifies the release. checksums.txt is verified
against checksums.txt.asc using the bundled public-key.asc in an ephemeral
keyring. Best-effort: degrades with a warning when gpg/sig assets are
unavailable (SHA-256 still enforced); a PRESENT-but-invalid signature is a
tamper signal and hard-fails the install.

P2 #7 — threat-model wording scoped to the 'configured trusted proxy
boundary' across the module docstring, config.py, and the egress docs, with
a new security-model bullet on CA-key / endpoint-integrity loss (MITRE
T1588.004 AiTM).

Tests: +2 NODE_OPTIONS conflict/preserve, +5 GPG verify (skip/missing/bad/
good/install-abort), +1 require assertion. iron_proxy 94 + docker 74 green; ruff clean.
2026-06-25 11:00:10 -07:00
..
__init__.py remove Vercel AI Gateway and Vercel Sandbox (#33067) 2026-05-27 00:43:32 -07:00
base.py fix(tools): don't compound-rewrite spawn_via_env background wrappers 2026-06-01 00:05:10 +05:30
daytona.py fix(daytona): migrate legacy-sandbox lookup to cursor-based list() (#24587) 2026-05-12 16:31:46 -07:00
docker.py fix(egress): address maxpetrusenko P1/P2 review — fail-closed secrets, NODE_OPTIONS conflict, GPG verify, threat-model scope 2026-06-25 11:00:10 -07:00
file_sync.py fix(ssh): handle WinError 1314 symlink failure with shutil.copy2 fallback 2026-06-04 18:06:21 -07:00
local.py fix: make profile subprocess HOME policy explicit 2026-06-14 03:20:21 -07:00
managed_modal.py feat(environments): unified spawn-per-call execution layer 2026-04-08 17:23:15 -07:00
modal.py fix(async): close unscheduled coroutines in all threadsafe bridges (#26584) 2026-05-15 14:00:01 -07:00
modal_utils.py fix(tools): don't compound-rewrite spawn_via_env background wrappers 2026-06-01 00:05:10 +05:30
singularity.py fix: prevent TUI gateway stdin EOF crash across all TUI-context subprocess calls 2026-06-08 22:46:57 -07:00
ssh.py fix(tui): preserve remote cwd for ssh sessions 2026-06-06 18:40:43 -07:00