# Tunnel and lanes ## Tunnel A userspace WireGuard tunnel (gVisor netstack) scoped so this machine can reach **only its own host**. No TUN device is created and `run` does not need root. The tunnel is dialled from this machine. Inside it, the bastion accepts on exactly three addresses, all under the `inference` capability family: a forward to a local ollama (port 11434), a forward to an OpenAI-compatible server when one is configured (port 18080), and a forward to a local PII sterilizer when one is configured. Nothing else listens. ## Git lane A loopback HTTP proxy plus a `git-credential` helper, so your local `git` reaches `git.privatae.ai` through your host. The forge answers platform addresses only, so this lane is the way in. `privatae-bastion git-setup` prints the three config lines: the proxy, a reset of the credential-helper chain for that URL (so no other helper caches your token on this machine), and the helper itself. ## Worker lanes Outbound-only reverse relays to the host: egress, management, harness, and session. The management lane runs a **fixed-argv allowlist**. Ops that touch your files are dedicated Go handlers with no shell. Of those file handlers, the one that runs a program is text extraction: it invokes a local tool named in a fixed table (`pdftotext`, `ffprobe`, and the like) from a fixed argv template, and the caller supplies only the tool's name and the document. ## Session lane An interactive terminal that runs on this machine and streams to the host over the same reverse WebSocket the other lanes use. No inbound port, no SSH server. It is your own act in your Terminal app, and needs no standing grant from the host (0.39.0): on a machine anchored to a host, `session:open` takes your approval from your device or this console, bound to that one session; on a local machine the pairing's caps are the authorization. A grant the host still presents is verified as before, and a deny in it refuses. `session:open` runs as an unprivileged user when the daemon is root. `session:root` runs as root only when the daemon is root **and** you approved that specific session here with the enrolled second factor. Every session is logged locally (output only) and recorded in the pairing's audit file. Not available on Windows. **Root commands (0.49.0).** The anchor host can also run one command at a time as root, with no terminal and no approval per command, once you have granted it here: ```sh sudo -H privatae-bastion root-exec grant --host --for 30d # asks for the code enrolled here privatae-bastion root-exec [--host ] # what is granted, until when privatae-bastion root-exec revoke [--host ] # take it back ``` The grant names one host (the anchor; a member pairing never gets it) and this machine, ends at the time you chose, and is written only by that command with the code; nothing the host sends can create, widen or extend it. Each command runs as `/bin/sh -c` in its own process group, with a deadline (10 minutes unless the host asks for less or more, never more than 8 hours) and with stdout and stderr returned up to a size cap (256 KiB each unless the host asks, at most 4 MiB); a cut output keeps its start and its end and says how many bytes were dropped. At the deadline the whole group gets SIGTERM, then SIGKILL 2 seconds later, so a child that ignores SIGTERM goes too. The bastion must run as root, the `session` family switched off here stops it, and a quarantined pairing runs nothing. These are checked again every 2 seconds while a command runs: a revoke, the grant's expiry, the switch or a quarantine stops a command already running, and its answer says why. Every command is written whole, with its output (up to 64 MiB), to the context store's `sessions/.log`, and recorded at start and stop in the audit file with its sha256, exit and byte counts; a refused, malformed or failed one gets an audit row too. Not available on Windows. The bastion also records where each root command connects. On Linux the command starts in a cgroup of its own, and an nftables table the bastion creates for that command records every connection the command and its children open; the table only records (it never allows or drops anything) and is removed when the command ends, or at the next start if the bastion died mid-command. Destinations outside the platform's own hosts are returned to the host as `untrusted_connections`, and the host then treats that output as untrusted and ends root for the turn. List the platform's own hosts in `platform_hosts.json` in the bastion's config folder: ```json {"hosts": ["2001:db8::/32", "203.0.113.0/24", "git.example.org"]} ``` With no list, every connection that leaves this machine counts as outside; loopback never does. A command whose connections could not be watched is reported as if it had connected out. What it cannot see: connections another program makes on the command's behalf, such as dockerd pulling an image for `docker build`, or a service `systemctl` starts. A root command can also leave its cgroup or delete the table on purpose; a missing table reads as "not watched", but a command that leaves its cgroup is not detected.