Say sudo everywhere a command needs it
tests / runner-env (confined) (pull_request) Successful in 1m46s
tests / tests (pull_request) Successful in 1m51s
tests / compose-schema (pull_request) Successful in 1m34s
tests / runner-env (privileged) (pull_request) Successful in 1m24s

Commands offered for someone to run were inconsistent about it. install.sh's
closing output named dejima-ci-allowlist and dejima-ci-runners without sudo,
the README's operating section listed all four programs bare, the firewall
unit's own comment had sudo on one half of a line and not the other, and the
node-side checks in the Proxmox runbook were bare as well.

Every one of them needs root, and the inconsistency is worse than either
convention would be: a reader who has just been shown one command without sudo
reasonably tries the next the same way, and this tool's failure for that was -
until the previous commit - to say the configuration was missing.

Audited mechanically rather than by eye: every fenced command in the
documentation and every command offered in script output, matched against the
programs that need root. Fifteen were bare. The check is repeatable, and finds
nothing now.

The README's list also says why `show` needs root, since that is the one that
looks like it should not: all four read /etc/dejima-ci/config, which names a
token's path and is 0640 in a 0750 directory.

Not changed: commands the scripts run themselves, which are already root, and
the two lines in the runbook that are explicitly performed as root from a
console.

84 ok, 0 failed.
This commit is contained in:
Brad Anderson
2026-08-08 19:44:53 -07:00
parent 9339d03636
commit 63869c04d3
6 changed files with 28 additions and 23 deletions
+11 -6
View File
@@ -234,18 +234,23 @@ Confined-tier commands. A privileged host installs none of them, which is the
point of that tier rather than a gap in it.
```sh
dejima-ci-allowlist check # what would change, without changing it
dejima-ci-allowlist render # fetch, validate, install, reload if changed
dejima-ci-allowlist show # what is installed right now
dejima-ci-firewall # reapply the egress rules
sudo dejima-ci-allowlist check # what would change, without changing it
sudo dejima-ci-allowlist render # fetch, validate, install, reload if changed
sudo dejima-ci-allowlist show # what is installed right now
sudo dejima-ci-firewall # reapply the egress rules
```
All four need root, `show` included: every one of them reads
`/etc/dejima-ci/config`, which names a forge token's path and is `0640 root` in
a `0750 root` directory. Without `sudo` they cannot see it — and say that,
rather than reporting it as absent.
`dejima-ci-runners` is installed on both tiers, and is how the runners
themselves are changed:
```sh
dejima-ci-runners --role confined --count 5 --non-interactive # grow the pool
dejima-ci-runners --role confined # change anything else
sudo dejima-ci-runners --role confined --count 5 --non-interactive # grow the pool
sudo dejima-ci-runners --role confined # change anything else
```
Exit codes are distinguishable on purpose, because a timer's alerting has to
+1 -1
View File
@@ -152,7 +152,7 @@ preflight() {
{
printf '%s: cannot run - %d problem(s) with the configuration:\n\n' "$PROG" "${#problems[@]}"
printf ' - %s\n' "${problems[@]}"
printf '\nFix all of them, or re-run install.sh, which prompts for each.\n'
printf '\nFix all of them, or re-run `sudo ./install.sh`, which prompts for each.\n'
} >&2
# 2, not 1: `check` uses 1 for "there is a pending change", which is an
# ordinary answer rather than a fault. A caller - install.sh, or a timer's
+4 -4
View File
@@ -502,7 +502,7 @@ elif [ "$ROLE" = privileged ]; then
say " installed /usr/local/sbin/dejima-ci-runners"
say
/usr/local/sbin/dejima-ci-runners --role privileged || \
say " runner setup did not finish - re-run dejima-ci-runners --role privileged"
say " runner setup did not finish - re-run: sudo dejima-ci-runners --role privileged"
else
say
say "Running install.sh for the allowlist, resolver and job firewall..."
@@ -765,7 +765,7 @@ cat >&2 <<EOF
writes the compose project and the runner config together, so nothing has
to be kept in step by hand:
dejima-ci-runners --role $ROLE
sudo dejima-ci-runners --role $ROLE
It needs a registration token from your forge and names the exact page to
mint one on. Grant it to as few repositories as you can stand.
@@ -821,8 +821,8 @@ asking the forge, and that is what fails.
Fix the cause, then run either of these - the first re-prompts for every
setting, the second only re-renders:
$SRC/install.sh
/usr/local/sbin/dejima-ci-allowlist render
sudo $SRC/install.sh
sudo /usr/local/sbin/dejima-ci-allowlist render
Nothing needs undoing first. Both are idempotent.
EOF
+7 -7
View File
@@ -578,7 +578,7 @@ if command -v curl >/dev/null 2>&1 && [ -s "$TOKEN_FILE" ] && [ -n "$probe_repo"
say
say " Fix the entry in $REPOS_FILE - the rest of this"
say " run is unaffected, and re-running this installer or"
say " '$BIN_DIR/dejima-ci-allowlist render' picks it up." ;;
say " 'sudo $BIN_DIR/dejima-ci-allowlist render' picks it up." ;;
000) say " Could not reach $forge_api to check the token."
say " That is the network or the forge, not the token itself." ;;
*) say " The forge answered $status when checking the token against"
@@ -589,12 +589,12 @@ if command -v curl >/dev/null 2>&1 && [ -s "$TOKEN_FILE" ] && [ -n "$probe_repo"
say " containers get a resolver that answers for nothing."
say
if [ "$NONINTERACTIVE" -eq 1 ]; then
say " Continuing - fix the token and run: $BIN_DIR/dejima-ci-allowlist render"
say " Continuing - fix the token and run: sudo $BIN_DIR/dejima-ci-allowlist render"
break
fi
case "$status" in
30[1278]) say " Continuing. Fix $REPOS_FILE, then run:"
say " $BIN_DIR/dejima-ci-allowlist render"
say " sudo $BIN_DIR/dejima-ci-allowlist render"
break ;;
esac
ask retry_token "Enter a different token now? (Y/n)" "y"
@@ -776,11 +776,11 @@ if [ "${run_runners,,}" != n ] && [ "${run_runners,,}" != no ]; then
# correct, and a runner that needs a second attempt should not read as the
# allowlist having failed.
"$BIN_DIR/dejima-ci-runners" --role confined || \
say " runner setup did not finish - re-run $BIN_DIR/dejima-ci-runners --role confined"
say " runner setup did not finish - re-run: sudo $BIN_DIR/dejima-ci-runners --role confined"
else
say "Skipped. When you are ready:"
say
say " $BIN_DIR/dejima-ci-runners --role confined"
say " sudo $BIN_DIR/dejima-ci-runners --role confined"
say
say "It asks for a label and a count, takes the network and resolver from"
say "$CONFIG, and tells you which page of your forge mints"
@@ -794,7 +794,7 @@ say "from your forge's UI. dejima ships test/ci-runner.bats for exactly this."
say "If the DNS checks pass while the egress checks fail, the resolver is fine"
say "and the firewall is not:"
say
say " $BIN_DIR/dejima-ci-firewall && iptables -S DOCKER-USER"
say " sudo $BIN_DIR/dejima-ci-firewall && sudo iptables -S DOCKER-USER"
say
say "A runner using host networking is not covered by any of this: its jobs"
say "are in the host's namespace, no bridge is in front of them, and the rules"
@@ -815,7 +815,7 @@ rc=0
case "$rc" in
0) say "Up to date." ;;
1) say; say "There is a pending change, shown above. Apply it with:"
say " $BIN_DIR/dejima-ci-allowlist render" ;;
say " sudo $BIN_DIR/dejima-ci-allowlist render" ;;
*) say; say "The configuration is not usable yet - the problems are listed above."
say "Re-run this installer to fix them."; exit "$rc" ;;
esac
+2 -2
View File
@@ -246,10 +246,10 @@ nothing:
```sh
# what is actually loaded right now
iptables -S | grep "tap<vmid>i0"
sudo iptables -S | grep "tap<vmid>i0"
# what Proxmox would generate from the current config
pve-firewall compile | grep -B2 -A20 "tap<vmid>i0"
sudo pve-firewall compile | grep -B2 -A20 "tap<vmid>i0"
```
**What you are looking for.** Proxmox names the per-VM chains after the tap
+3 -3
View File
@@ -15,11 +15,11 @@
# that was never the problem.
#
# Install as /etc/systemd/system/dejima-ci-firewall.service, then:
# systemctl daemon-reload
# systemctl enable --now dejima-ci-firewall
# sudo systemctl daemon-reload
# sudo systemctl enable --now dejima-ci-firewall
#
# Verify it actually rebinds, rather than assuming:
# systemctl restart docker && sudo iptables -S DOCKER-USER
# sudo systemctl restart docker && sudo iptables -S DOCKER-USER
[Unit]
Description=dejima CI job-network egress rules