Commit 9467ed29d6

9467ed29d693e590e8e037c8858eeb793f21f029

parent: 9809a86bfc

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-28 07:31 UTC

runner egress: remove the rule when it blocks the runner's poll

Ref #260

Layout: unified · split

deploy/gitbay-runner-egress.nft +4 −3
@@ -20,9 +20,10 @@
2020# 127.0.0.1:22 the forge over loopback, for the runner. Builds do
2121# not reach loopback at all: the runner starts them
2222# with pasta's gateway mapping off (--no-map-gw).
23# loopback :53 the host's resolver, which pasta forwards a
24# build's DNS to when the host's nameserver is a
25# loopback address.
23# loopback :53 the host's resolver, for when the host's nameserver
24# is a loopback address. That pasta forwards a
25# build's DNS there is to be confirmed from inside a
26# build by runbook R3, not assumed.
2627# public 22/80/443 the forge, as anyone on the internet reaches it.
2728# Everything else is rejected: the admin sshd on 2222 on every address,
2829# and any service bound to loopback. -isolation none builds run as the
deploy/gitbay-runner-egress.service +4 −1
@@ -10,6 +10,9 @@
1010# Reload re-reads the file and replaces the table in one transaction; it
1111# does not restart the runner, which a restart of this unit would
1212# (Requires= propagates restarts). `make deploy-runner` reloads.
13#
14# Stop uses destroy, which succeeds when the table is already gone (a
15# flush ruleset removes it); delete would fail and leave the unit failed.
1316[Unit]
1417Description=Host egress rule for CI builds
1518After=nftables.service ufw.service
@@ -20,7 +23,7 @@ Type=oneshot
2023RemainAfterExit=yes
2124ExecStart=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft
2225ExecReload=/usr/sbin/nft -f /etc/gitbay-runner/egress.nft
23ExecStop=/usr/sbin/nft delete table inet gitbay_runner
26ExecStop=/usr/sbin/nft destroy table inet gitbay_runner
2427
2528[Install]
2629WantedBy=multi-user.target
deploy/runner-egress-check.sh +14 −7
@@ -14,17 +14,24 @@ RUNNER_USER="${RUNNER_USER:-ci-runner}"
1414public=$(hostname -I | awk '{print $1}')
1515
1616probe() {
17 su -s /bin/bash "$RUNNER_USER" -c "timeout 5 bash -c 'exec 3<>/dev/tcp/$1/$2'" 2>/dev/null
17 su -s /bin/bash "$RUNNER_USER" -c "timeout 5 bash -c 'exec 3<>/dev/tcp/$1/$2'" </dev/null 2>/dev/null
1818}
1919
2020nft list table inet gitbay_runner >/dev/null
2121
22for dest in 127.0.0.1:22 "$public:22"; do
23 if ! probe "${dest%:*}" "${dest##*:}"; then
24 echo "$RUNNER_USER cannot reach $dest: the egress rule would stop the runner" >&2
25 exit 1
26 fi
27done
22# The runner polls 127.0.0.1:22. If the rule blocks that, the running
23# runner is already cut off, so remove the table: CI keeps polling as it
24# did before the deploy, and the exit still stops make before the restart.
25if ! probe 127.0.0.1 22; then
26 nft destroy table inet gitbay_runner
27 echo "$RUNNER_USER cannot reach 127.0.0.1:22 with the egress rule loaded;" >&2
28 echo "removed table inet gitbay_runner so the runner keeps polling. Fix the rule and deploy again." >&2
29 exit 1
30fi
31if ! probe "$public" 22; then
32 echo "$RUNNER_USER cannot reach $public:22: builds would not reach the forge" >&2
33 exit 1
34fi
2835for dest in 127.0.0.1:2222 "$public:2222"; do
2936 if probe "${dest%:*}" "${dest##*:}"; then
3037 echo "$RUNNER_USER reaches $dest: the egress rule is not in force" >&2