Network Access

Allow just the hosts a task needs, for example a Python package index:

caretz --network-allow pypi.org \
      --network-allow files.pythonhosted.org \
      -p "add requests to the project and run the tests"

Commands reach these hosts through a filtering proxy that Caretz sets up through the standard HTTP_PROXY variables, so pip, npm, go, and curl work unchanged. Other common forms:

caretz --network-allow '*.example.com:443'
caretz --network-allow '*:443'
caretz --network-allow 'tcp://git.example.com:22'

When a command hits a blocked host in an interactive session, Caretz asks whether to allow it, so you rarely need to predict the list up front.

Git and SSH

git clone, fetch, and push to SSH remotes go through the proxy automatically; approve tcp://github.com:22 when asked. For plain ssh, route it through the same helper:

ssh -o "ProxyCommand=$CARETZ_SSH_PROXY_COMMAND" user@host

Without it, ssh fails with Operation not permitted instead of asking for approval.

Local Servers and Unrestricted Network

Local dev servers and integration tests need loopback:

caretz --allow-loopback -p "start the API server and run the integration tests"

The built-in coding profile already turns this on. When a tool cannot use a proxy at all (non-HTTP protocols, some database clients), drop network isolation while keeping the filesystem sandbox:

caretz --unrestricted-network

--unrestricted-network does not create the isolated Linux network namespace. Commands share the host’s network namespace and so can still reach abstract Unix sockets, which no file mask can hide.

Linux session commands can use services inside their private loopback namespace. On macOS, --allow-loopback permits TCP listeners and direct loopback connections. Without it, proxy-aware clients can still request approval for an exact localhost host:port; direct localhost connections remain denied. Caretz does not set NO_PROXY on macOS.

Allowlist Syntax

An HTTP entry is HOST, HOST:PORT, or *:PORT. A TCP entry is tcp://HOST:PORT or tcp://*:PORT; its explicit port is required. Matching is case-insensitive and an exact host rule does not include subdomains. A leading *. matches subdomains but not the base domain. When a port is omitted from a host rule it matches any port; the proxy uses 80 and 443 as the defaults for HTTP and HTTPS requests. An any-host rule always requires a port, so bare * is rejected.

*:80 and *:443 also include loopback, private, link-local, and metadata addresses on their configured ports. Because the proxy supports HTTPS CONNECT, an any-host rule permits tunnels to any destination on that port; prefer named hosts when the required destinations are known.

How the Proxy Works

Linux starts each restricted command in a separate network namespace. macOS uses a sandbox-exec network policy. With no allowlist, neither platform can connect to the host or internet.

sandboxed command -> 127.0.0.1:18080 -> private Unix socket
                  -> host/port allowlist check -> destination

For an allowlisted Linux run, Caretz creates private Unix sockets outside the sandbox and bridges them from fixed HTTP and SOCKS loopback ports inside the network namespace. On macOS, Caretz binds dynamic loopback ports and permits only those exact endpoints in the generated profile. The upper- and lower-case HTTP_PROXY, HTTPS_PROXY, and ALL_PROXY variables point to the restricted HTTP proxy, so HTTP clients keep working without SOCKS support. CARETZ_SOCKS_PROXY points to a separate SOCKS5 proxy that resolves destination names on the trusted host. SOCKS connections require an explicit tcp://HOST:PORT or tcp://*:PORT allowlist entry; ordinary entries remain scoped to HTTP and HTTP CONNECT.

The proxy accepts absolute HTTP requests and HTTPS CONNECT tunnels only. A blocked host receives 403 Forbidden. This is destination gating, not TLS inspection: after an allowed CONNECT, encrypted traffic passes through the tunnel. Programs must honor the proxy environment variables; arbitrary TCP or UDP protocols remain unavailable in the isolated namespace. Restricted runners keep this proxy endpoint available even when the configured allowlist is empty so an approved command can receive temporary network access. The empty policy forwards no destinations, and temporary grants are removed after the command finishes.