NAME
egress-demo - show the CONNECT-proxy allowlist gate
SYNOPSIS
egress-demo
DESCRIPTION
egress-demo exercises the per-invocation HTTP CONNECT proxy that cli-guard stands up for the duration of a wrapped subprocess. The child inherits HTTPS_PROXY / HTTP_PROXY pointing at a local proxy on 127.0.0.1:. The proxy logs every CONNECT, joins the rows back to the parent invocation's audit row, and either enforces a pinned allowlist or observes silently.
Two modes:
- ModeEnforce: per-binary allowlist pinned in code. Denied
CONNECTs return HTTP 403 from the proxy. The row is marked
decision=deny. Used for package-manager wrappers (brew, npm,
pip, cargo, ...) where the upstream registry set is small,
stable, and high-value.
- ModeObserve: no allowlist, every CONNECT is forwarded and
logged. Used for aws, gh, kubectl, docker, tailscale - tools
whose upstream surface is too broad to enumerate but whose
every network reach is still worth auditing.
What this gate is and is not:
- CONNECT-only. No TLS interception, no CA install, no payload
inspection. The proxy reads the host:port from the CONNECT
request line and decides accept/deny on hostname alone.
- Plaintext HTTP through the proxy is rejected with 405. Any
tool that depends on plaintext fetching is already a bug, and
we do not want to be the layer that silently downgrades it.
- Not a sandbox. A determined hostile process can resolve a host
directly, bypass the env proxy hint, or use a non-HTTP
transport. The gate stops the dumb cases (npm post-install
curls a remote shell), records the rest, and pairs with the
lockdown deny rules and audit log to make the rest expensive
to hide.
Operating model for an agent calling these commands:
- On a 403, the child saw a normal HTTP failure. Do not retry.
The upstream is unreachable by design; the right escalation is
"the allowlist does not cover <host>, here is the egress row,
operator decide". An allowlist edit is a code change, not a
runtime flag.
- Egress rows are emitted to stderr at proxy.Stop() time in
these examples for inspection. In production they fold into
the parent audit row.
Usage:
egress-demo [GLOBAL OPTIONS] [command [COMMAND OPTIONS]] [ARGUMENTS...]
COMMANDS
allowed
dial a host that is on the allowlist
denied
dial a host that is not on the allowlist
observe
log every host without enforcing