forked from
lass.pds.lassul.us/superconfig
This repository has no description
7.5 kB
214 lines
1# crit (https://crit.md): agents run `crit` to open their diff/plan for review
2# in the browser and block until it is finished. Each review session is its
3# own daemon on its own port, reachable over retiolum as
4# http://<host>.r:<port>, and publicly as https://<id>.review.lassul.us
5# through neoprism (configs/crit-proxy.nix) and the router nginx below.
6#
7# SECURITY: crit has no authentication, and comments left in a review are fed
8# to the agent as instructions. Whoever can reach a daemon can steer an agent
9# running here, so the ports are only open on retiolum. On the public side the
10# random 10-char hostname (~51 bits, fresh per review, only on a wildcard cert
11# so it never shows up in CT logs) is the only protection. Only members of
12# group crit can register a route (via /run/crit-routes.sock), and the
13# ids are generated by the root service, callers cannot choose them.
14{
15 self,
16 config,
17 pkgs,
18 ...
19}:
20let
21 firstPort = 7700;
22 lastPort = 7719;
23 # router nginx, neoprism proxies *.review.lassul.us here
24 routerPort = 7720;
25 domain = "review.lassul.us";
26 # one file per port, "<id> <port>", written by crit-routes-register (root)
27 routesDir = "/var/lib/crit-routes";
28 mapDir = "/run/crit-routes";
29 socket = "/run/crit-routes.sock";
30 crit-unwrapped = self.inputs.llm-agents.packages.${pkgs.system}.crit;
31
32 # crit binds 127.0.0.1 on a random port by default. Bind all interfaces on a
33 # free port from the firewalled range instead and advertise the public URL.
34 # Only the invocation that starts a daemon binds the port; reconnecting to a
35 # running session uses the port and URL recorded in ~/.crit/sessions.
36 crit = pkgs.symlinkJoin {
37 name = "crit";
38 paths = [
39 (pkgs.writeShellScriptBin "crit" ''
40 if [ -z "''${CRIT_PORT:-}" ]; then
41 for p in $(${pkgs.coreutils}/bin/seq ${toString firstPort} ${toString lastPort}); do
42 if [ -z "$(${pkgs.iproute2}/bin/ss -Htln "sport = :$p")" ]; then
43 export CRIT_PORT=$p
44 # Fresh unguessable hostname per daemon, picked by the root
45 # service. Replacing the port's route kills the link of
46 # whichever review used the port before.
47 id=$(printf '%s\n' "$p" | ${pkgs.socat}/bin/socat -t 10 - UNIX-CONNECT:${socket} 2>/dev/null)
48 if [[ $id =~ ^[a-z0-9]{10}$ ]]; then
49 export CRIT_PUBLIC_URL="''${CRIT_PUBLIC_URL:-https://$id.${domain}}"
50 else
51 echo "crit: cannot register at ${socket} (not in group crit?), no public URL" >&2
52 fi
53 break
54 fi
55 done
56 fi
57 if [ -n "''${CRIT_PORT:-}" ]; then
58 echo "crit: retiolum: http://${config.networking.hostName}.r:$CRIT_PORT" >&2
59 export CRIT_PUBLIC_URL="''${CRIT_PUBLIC_URL:-http://${config.networking.hostName}.r:$CRIT_PORT}"
60 else
61 echo "crit: ports ${toString firstPort}-${toString lastPort} all busy, using a random port (not reachable over retiolum)" >&2
62 fi
63 export CRIT_HOST="''${CRIT_HOST:-0.0.0.0}"
64 export CRIT_ALLOW_UNAUTHENTICATED_NETWORK=1
65 exec ${crit-unwrapped}/bin/crit "$@"
66 '')
67 crit-unwrapped
68 ];
69 };
70
71 # Only well-formed routes make it into the nginx config.
72 crit-routes-map = pkgs.writeShellApplication {
73 name = "crit-routes-map";
74 runtimeInputs = [ pkgs.coreutils ];
75 text = ''
76 routes=$1
77 out=$2
78 mkdir -p "$(dirname "$out")"
79 tmp=$(mktemp "$out.XXXXXX")
80 for f in "$routes"/*; do
81 [ -f "$f" ] || continue
82 id=''' port='''
83 read -r id port _ <"$f" || [ -n "$id" ] || continue
84 if [[ $id =~ ^[a-z0-9]{10}$ && $port =~ ^[0-9]{4}$ ]] &&
85 ((port >= ${toString firstPort} && port <= ${toString lastPort})); then
86 printf '%s.${domain} %s;\n' "$id" "$port"
87 fi
88 done >"$tmp"
89 chmod 644 "$tmp"
90 mv -f "$tmp" "$out"
91 '';
92 };
93
94 # One connection of crit-routes.socket: reads a port, gives it a fresh
95 # route and answers with the route's id.
96 crit-routes-register = pkgs.writeShellApplication {
97 name = "crit-routes-register";
98 runtimeInputs = [
99 pkgs.coreutils
100 pkgs.util-linux
101 crit-routes-map
102 ];
103 text = ''
104 routes=$1
105 map=$2
106 port='''
107 read -r -t 5 port || true
108 if ! [[ $port =~ ^[0-9]{4}$ ]] || ((port < ${toString firstPort} || port > ${toString lastPort})); then
109 echo "crit-routes-register: invalid port" >&2
110 exit 1
111 fi
112 # tr dies of SIGPIPE once head has its 10 chars
113 id=$(LC_ALL=C tr -dc a-z0-9 </dev/urandom | head -c 10) || true
114 [[ $id =~ ^[a-z0-9]{10}$ ]]
115 # concurrent registrations must not lose each other's map update
116 exec 9<"$routes"
117 flock 9
118 printf '%s %s\n' "$id" "$port" >"$routes/.$port.tmp"
119 mv -f "$routes/.$port.tmp" "$routes/$port"
120 crit-routes-map "$routes" "$map"
121 systemctl try-reload-or-restart nginx.service
122 echo "$id"
123 '';
124 };
125in
126{
127 environment.systemPackages = [ crit ];
128
129 users.groups.crit.members = [
130 config.users.users.mainUser.name
131 "hermes"
132 ];
133 # root-only; tmpfiles also tightens the group-writable dir of before
134 systemd.tmpfiles.rules = [ "d ${routesDir} 0700 root root -" ];
135
136 # A unix socket rather than a writable dir: connecting works for agents
137 # under ProtectSystem=strict. The group controls who may register.
138 systemd.sockets.crit-routes = {
139 wantedBy = [ "sockets.target" ];
140 socketConfig = {
141 ListenStream = socket;
142 SocketUser = "root";
143 SocketGroup = "crit";
144 SocketMode = "0660";
145 Accept = true;
146 };
147 };
148 systemd.services."crit-routes@" = {
149 description = "Register a crit review hostname";
150 serviceConfig = {
151 ExecStart = "${pkgs.lib.getExe crit-routes-register} ${routesDir} ${mapDir}/routes.map";
152 StandardInput = "socket";
153 StandardOutput = "socket";
154 StandardError = "journal";
155 };
156 };
157 # map from the routes of before the reboot, so nginx starts with one
158 systemd.services.crit-routes-map = {
159 description = "Generate the nginx map of crit review hostnames";
160 wantedBy = [ "multi-user.target" ];
161 before = [ "nginx.service" ];
162 serviceConfig = {
163 Type = "oneshot";
164 ExecStart = "${pkgs.lib.getExe crit-routes-map} ${routesDir} ${mapDir}/routes.map";
165 };
166 };
167
168 # Routes <id>.review.lassul.us to the daemon's port. A daemon that has gone
169 # away gives 502, unknown ids 404.
170 services.nginx = {
171 enable = true;
172 # the glob tolerates a missing file before crit-routes ran
173 appendHttpConfig = ''
174 map $host $crit_port {
175 default "";
176 include ${mapDir}/*.map;
177 }
178 '';
179 virtualHosts.crit-routes = {
180 listen = [
181 {
182 addr = "0.0.0.0";
183 port = routerPort;
184 }
185 {
186 addr = "[::]";
187 port = routerPort;
188 }
189 ];
190 extraConfig = ''
191 if ($crit_port = "") {
192 return 404;
193 }
194 '';
195 # the UI follows the review over SSE
196 locations."/" = {
197 recommendedProxySettings = true;
198 proxyPass = "http://127.0.0.1:$crit_port";
199 extraConfig = ''
200 proxy_buffering off;
201 proxy_read_timeout 1h;
202 '';
203 };
204 };
205 };
206
207 networking.firewall.interfaces.retiolum.allowedTCPPorts = [ routerPort ];
208 networking.firewall.interfaces.retiolum.allowedTCPPortRanges = [
209 {
210 from = firstPort;
211 to = lastPort;
212 }
213 ];
214}