//! In-process HTTP/HTTPS proxy that enforces a hostname allowlist.
//!
//! Spawned per terminal command from the parent process. The sandbox is
//! configured to permit network only to this proxy's port; everything the
//! sandboxed command tries to reach the network for has to come through here.
//!
//! The proxy:
//!
//! - Speaks HTTP CONNECT for HTTPS tunnels and HTTP forward proxying for
//!   plain HTTP. Other protocols cannot reach it (the seatbelt rule limits
//!   the sandboxed process to this one TCP destination, and this proxy only
//!   speaks HTTP).
//! - Checks the destination hostname against an allowlist of exact hostnames
//!   and leading-`*.` subdomain wildcards. Unless the allowlist allows any
//!   host, IP-literal targets are denied, and hostnames whose DNS resolves
//!   only into loopback / private / link-local space are denied too
//!   (DNS-rebinding protection — the proxy runs outside the sandbox, so it
//!   must not reopen the local network the Seatbelt rule closed off).
//! - Pins each TCP connection to the destination approved for its first
//!   request: directly (to the vetted resolved addresses) or via a CONNECT
//!   tunnel through an optional upstream HTTP proxy from the parent's
//!   environment (`HTTPS_PROXY` / `HTTP_PROXY`), honoring `NO_PROXY`. Plain
//!   HTTP is also tunneled when chaining, so keep-alive requests after the
//!   first can never be routed to a different host by the upstream.
//! - Reports per-connection events (allowed, denied, completed) over an
//!   mpsc supplied by the caller.
//!
//! ## Trust assumptions
//!
//! The proxy's sole client is model-driven code running inside the sandbox —
//! exactly the party the sandbox distrusts — and the proxy itself runs inside
//! the editor process. It therefore caps request header sizes and concurrent
//! connections, and bounds connect/handshake waits with timeouts, so a
//! malicious command can't exhaust the editor's memory, threads, or file
//! descriptors through it. Bandwidth is deliberately not capped; the
//! command's lifetime bounds it.
//!
//! ## "No proxy here" principle
//!
//! The agent and tools running inside the sandbox should not need to know
//! that a proxy is in front of them. The only response code the proxy
//! synthesizes itself is `511 Network Authentication Required`, used solely
//! for policy denials (with `Via:` and `Proxy-Status:` headers and a
//! plain-text body explaining the policy decision). Other failure modes
//! (upstream connection failure, malformed input from the client, etc.) are
//! handled by silently closing the connection — same behavior the client
//! would see from a direct network failure, no proxy fingerprint.

mod allowlist;
mod pinned_host;
mod proxy;

pub use allowlist::{Allowlist, HostPattern, HostPatternError};
pub use pinned_host::{PinnedHost, PinnedHostError, is_forbidden_ip};
pub use proxy::{
    DenyReason, ProxyConfig, ProxyEvent, ProxyHandle, RequestMethod, RequestOutcome, UpstreamProxy,
};
