# crit (https://crit.md): agents run `crit` to open their diff/plan for review # in the browser and block until it is finished. Each review session is its # own daemon on its own port, reachable over retiolum as # http://.r:, and publicly as https://.review.lassul.us # through neoprism (configs/crit-proxy.nix) and the router nginx below. # # SECURITY: crit has no authentication, and comments left in a review are fed # to the agent as instructions. Whoever can reach a daemon can steer an agent # running here, so the ports are only open on retiolum. On the public side the # random 10-char hostname (~51 bits, fresh per review, only on a wildcard cert # so it never shows up in CT logs) is the only protection. Only members of # group crit can register a route (via /run/crit-routes.sock), and the # ids are generated by the root service, callers cannot choose them. { self, config, pkgs, ... }: let firstPort = 7700; lastPort = 7719; # router nginx, neoprism proxies *.review.lassul.us here routerPort = 7720; domain = "review.lassul.us"; # one file per port, " ", written by crit-routes-register (root) routesDir = "/var/lib/crit-routes"; mapDir = "/run/crit-routes"; socket = "/run/crit-routes.sock"; crit-unwrapped = self.inputs.llm-agents.packages.${pkgs.system}.crit; # crit binds 127.0.0.1 on a random port by default. Bind all interfaces on a # free port from the firewalled range instead and advertise the public URL. # Only the invocation that starts a daemon binds the port; reconnecting to a # running session uses the port and URL recorded in ~/.crit/sessions. crit = pkgs.symlinkJoin { name = "crit"; paths = [ (pkgs.writeShellScriptBin "crit" '' if [ -z "''${CRIT_PORT:-}" ]; then for p in $(${pkgs.coreutils}/bin/seq ${toString firstPort} ${toString lastPort}); do if [ -z "$(${pkgs.iproute2}/bin/ss -Htln "sport = :$p")" ]; then export CRIT_PORT=$p # Fresh unguessable hostname per daemon, picked by the root # service. Replacing the port's route kills the link of # whichever review used the port before. id=$(printf '%s\n' "$p" | ${pkgs.socat}/bin/socat -t 10 - UNIX-CONNECT:${socket} 2>/dev/null) if [[ $id =~ ^[a-z0-9]{10}$ ]]; then export CRIT_PUBLIC_URL="''${CRIT_PUBLIC_URL:-https://$id.${domain}}" else echo "crit: cannot register at ${socket} (not in group crit?), no public URL" >&2 fi break fi done fi if [ -n "''${CRIT_PORT:-}" ]; then echo "crit: retiolum: http://${config.networking.hostName}.r:$CRIT_PORT" >&2 export CRIT_PUBLIC_URL="''${CRIT_PUBLIC_URL:-http://${config.networking.hostName}.r:$CRIT_PORT}" else echo "crit: ports ${toString firstPort}-${toString lastPort} all busy, using a random port (not reachable over retiolum)" >&2 fi export CRIT_HOST="''${CRIT_HOST:-0.0.0.0}" export CRIT_ALLOW_UNAUTHENTICATED_NETWORK=1 exec ${crit-unwrapped}/bin/crit "$@" '') crit-unwrapped ]; }; # Only well-formed routes make it into the nginx config. crit-routes-map = pkgs.writeShellApplication { name = "crit-routes-map"; runtimeInputs = [ pkgs.coreutils ]; text = '' routes=$1 out=$2 mkdir -p "$(dirname "$out")" tmp=$(mktemp "$out.XXXXXX") for f in "$routes"/*; do [ -f "$f" ] || continue id=''' port=''' read -r id port _ <"$f" || [ -n "$id" ] || continue if [[ $id =~ ^[a-z0-9]{10}$ && $port =~ ^[0-9]{4}$ ]] && ((port >= ${toString firstPort} && port <= ${toString lastPort})); then printf '%s.${domain} %s;\n' "$id" "$port" fi done >"$tmp" chmod 644 "$tmp" mv -f "$tmp" "$out" ''; }; # One connection of crit-routes.socket: reads a port, gives it a fresh # route and answers with the route's id. crit-routes-register = pkgs.writeShellApplication { name = "crit-routes-register"; runtimeInputs = [ pkgs.coreutils pkgs.util-linux crit-routes-map ]; text = '' routes=$1 map=$2 port=''' read -r -t 5 port || true if ! [[ $port =~ ^[0-9]{4}$ ]] || ((port < ${toString firstPort} || port > ${toString lastPort})); then echo "crit-routes-register: invalid port" >&2 exit 1 fi # tr dies of SIGPIPE once head has its 10 chars id=$(LC_ALL=C tr -dc a-z0-9 "$routes/.$port.tmp" mv -f "$routes/.$port.tmp" "$routes/$port" crit-routes-map "$routes" "$map" systemctl try-reload-or-restart nginx.service echo "$id" ''; }; in { environment.systemPackages = [ crit ]; users.groups.crit.members = [ config.users.users.mainUser.name "hermes" ]; # root-only; tmpfiles also tightens the group-writable dir of before systemd.tmpfiles.rules = [ "d ${routesDir} 0700 root root -" ]; # A unix socket rather than a writable dir: connecting works for agents # under ProtectSystem=strict. The group controls who may register. systemd.sockets.crit-routes = { wantedBy = [ "sockets.target" ]; socketConfig = { ListenStream = socket; SocketUser = "root"; SocketGroup = "crit"; SocketMode = "0660"; Accept = true; }; }; systemd.services."crit-routes@" = { description = "Register a crit review hostname"; serviceConfig = { ExecStart = "${pkgs.lib.getExe crit-routes-register} ${routesDir} ${mapDir}/routes.map"; StandardInput = "socket"; StandardOutput = "socket"; StandardError = "journal"; }; }; # map from the routes of before the reboot, so nginx starts with one systemd.services.crit-routes-map = { description = "Generate the nginx map of crit review hostnames"; wantedBy = [ "multi-user.target" ]; before = [ "nginx.service" ]; serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.lib.getExe crit-routes-map} ${routesDir} ${mapDir}/routes.map"; }; }; # Routes .review.lassul.us to the daemon's port. A daemon that has gone # away gives 502, unknown ids 404. services.nginx = { enable = true; # the glob tolerates a missing file before crit-routes ran appendHttpConfig = '' map $host $crit_port { default ""; include ${mapDir}/*.map; } ''; virtualHosts.crit-routes = { listen = [ { addr = "0.0.0.0"; port = routerPort; } { addr = "[::]"; port = routerPort; } ]; extraConfig = '' if ($crit_port = "") { return 404; } ''; # the UI follows the review over SSE locations."/" = { recommendedProxySettings = true; proxyPass = "http://127.0.0.1:$crit_port"; extraConfig = '' proxy_buffering off; proxy_read_timeout 1h; ''; }; }; }; networking.firewall.interfaces.retiolum.allowedTCPPorts = [ routerPort ]; networking.firewall.interfaces.retiolum.allowedTCPPortRanges = [ { from = firstPort; to = lastPort; } ]; }