Commit 905ce58
committed
fix(egress): align proxy.yaml with iron-proxy v0.39 actual schema +
propagate handler exit codes
Live testing the full wizard against the real v0.39.0 binary
(downloaded + extracted via our own install_iron_proxy()) surfaced
three real bugs that the unit tests couldn't catch:
1. `proxy.http_listens` (plural) — NOT a field in v0.39's config struct.
Our code emitted both `http_listen` (string) and `http_listens`
(list) believing v0.39 accepts both forms. The binary actually
rejects with "field http_listens not found in type config.Proxy"
at YAML unmarshal time, so the daemon fails to start. Confirmed
via strings(1) audit of the v0.39 binary — only `http_listen` is
tagged.
2. `log.audit_path` — NOT a field in v0.39's config.Log struct. Same
class of error: "field audit_path not found in type config.Log".
Per-request audit-log records are not separable from server-level
logs at this binary version.
3. `metrics.listen` defaults to ":9090" — which is the SAME port as
our default `tunnel_port: 9090`. Result: every operator who runs
`hermes egress setup` followed by `hermes egress start` gets
"bind: address already in use" because the proxy listener and the
metrics listener fight for port 9090. We now explicitly pin
`metrics.listen: 127.0.0.1:0` to give it an ephemeral loopback
port that can never collide with tunnel_port regardless of what
operator sets.
Plus a fourth bug — pre-existing but surfaced by the egress live
test — that affects every Hermes subcommand:
4. `hermes_cli/main.py` calls `args.func(args)` at the bottom of
main() but discards the return value. Every subcommand handler
that returns a non-zero exit code (cmd_start refusing because
`fail_on_uncovered_providers=true`, cmd_setup refusing because
--from-bitwarden but BWS unreachable, etc.) was silently exiting 0.
Fix: capture the handler's return value and `sys.exit(rc)` when
it's a non-zero int. Other subcommands' contracts unchanged
because they either return 0/None or don't return at all.
Validation:
- 188/188 in test_iron_proxy.py + test_iron_proxy_cli.py +
test_config.py pass post-fix.
- 5333/5337 in tests/hermes_cli/ pass; the 4 unrelated failures
(test_managed_installs.py + test_update_hangup_protection.py)
are pre-existing on main, not touched by this PR.
- Manual wizard run end-to-end with the v0.39.0 binary in an
isolated HERMES_HOME:
* `egress install` — downloads + SHA-256 verifies + extracts
* `egress setup` — generates CA, mints tokens, writes
proxy.yaml that the binary now accepts (no http_listens,
no audit_path, metrics pinned to 127.0.0.1:0)
* `egress start` — daemon binds 127.0.0.1:9090, listens=yes
* `egress status` — shows pid + listening + mappings
* `egress stop` — clean shutdown, pidfile + nonce removed
* Idempotent re-start returns the running pid without spawning
* curl through the proxy with the openrouter token gets
forwarded; an attacker host gets HTTP 403 (allowlist works);
169.254.169.254 gets HTTP 403 (deny CIDR works)
* Refuse-start paths exit 1 with actionable messages:
- `fail_on_uncovered_providers=true` + ANTHROPIC_API_KEY set
- `credential_source=bitwarden` + BWS_ACCESS_TOKEN unset
* `--rotate-tokens` confirmation gate fires via pty:
typing 'cancel' aborts; typing 'rotate' proceeds and
creates a mappings.json.rotated-<timestamp> backup
Test updates:
- `test_default_bind_is_loopback_not_zero_zero` — asserts the
singular `http_listen` is loopback AND asserts `http_listens`
(plural) is NOT in the rendered yaml.
- `test_default_bind_uses_loopback_on_linux` — replaces
`test_default_bind_includes_docker_bridge_on_linux`. v0.39
only supports one bind per daemon process, so the docker bridge
augmentation is dropped from the rendered config; sandboxes
reach the daemon via host.docker.internal -> host-gateway
mapping, so loopback-only is functional.
- `test_metrics_listener_pinned_to_loopback_ephemeral` — new
regression test asserting `metrics.listen == "127.0.0.1:0"`.
- `test_audit_log_kwarg_does_not_inject_audit_path_v039` —
replaces `test_audit_log_path_lands_in_yaml`. audit_log kwarg
is still accepted for forward compatibility but does NOT emit
log.audit_path until upstream supports it.1 parent ec108c6 commit 905ce58
3 files changed
Lines changed: 100 additions & 33 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
851 | 851 | | |
852 | 852 | | |
853 | 853 | | |
854 | | - | |
855 | | - | |
856 | | - | |
857 | | - | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
858 | 862 | | |
859 | 863 | | |
860 | 864 | | |
861 | 865 | | |
862 | | - | |
863 | | - | |
864 | | - | |
865 | | - | |
866 | | - | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
867 | 880 | | |
868 | 881 | | |
869 | 882 | | |
| |||
878 | 891 | | |
879 | 892 | | |
880 | 893 | | |
881 | | - | |
882 | | - | |
883 | | - | |
884 | | - | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
885 | 898 | | |
886 | | - | |
887 | 899 | | |
888 | 900 | | |
889 | 901 | | |
| |||
896 | 908 | | |
897 | 909 | | |
898 | 910 | | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
899 | 923 | | |
900 | 924 | | |
901 | 925 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14001 | 14001 | | |
14002 | 14002 | | |
14003 | 14003 | | |
14004 | | - | |
| 14004 | + | |
| 14005 | + | |
| 14006 | + | |
| 14007 | + | |
| 14008 | + | |
14005 | 14009 | | |
14006 | | - | |
| 14010 | + | |
| 14011 | + | |
| 14012 | + | |
14007 | 14013 | | |
14008 | 14014 | | |
14009 | 14015 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
216 | | - | |
217 | | - | |
| 216 | + | |
218 | 217 | | |
219 | 218 | | |
220 | 219 | | |
| |||
224 | 223 | | |
225 | 224 | | |
226 | 225 | | |
227 | | - | |
228 | 226 | | |
229 | | - | |
230 | 227 | | |
231 | | - | |
232 | | - | |
233 | | - | |
234 | | - | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
235 | 238 | | |
236 | 239 | | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
241 | 248 | | |
242 | 249 | | |
243 | 250 | | |
| |||
247 | 254 | | |
248 | 255 | | |
249 | 256 | | |
250 | | - | |
251 | | - | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
252 | 276 | | |
253 | 277 | | |
254 | 278 | | |
255 | | - | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
256 | 282 | | |
257 | 283 | | |
258 | 284 | | |
259 | | - | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
260 | 292 | | |
261 | 293 | | |
262 | 294 | | |
263 | 295 | | |
264 | 296 | | |
265 | 297 | | |
266 | | - | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
267 | 304 | | |
268 | 305 | | |
269 | 306 | | |
| |||
0 commit comments