hive-ci: run the runner credential precondition with full privileges
The token file is 0600 root-owned and the precondition ran as the unit's dynamic gitea-runner user, so it could not read it -- and it did not fail closed. `[ -s ]` succeeds on a stat alone, grep then died with EACCES, and `! grep` turned that error into true, so the gate exited 0 on a file it had never read. It has reported 'a real token is present' without looking for its entire existence, which is why the runner kept retrying instead of holding still and saying why. Prefix the step with + so it runs with full privileges. This grants the runner nothing new: tokenFile becomes EnvironmentFile=, which systemd already reads as root before dropping privileges, so the payload never passes through an unprivileged reader either way -- the + only lets the gate observe what systemd observes. Also assert readability separately and loudly, rather than folding it into the placeholder test: an unreadable file and a real token produced the same verdict, so 'I could not look' was indistinguishable from 'I looked and it is fine'.
This commit is contained in:
parent
39a0a313dc
commit
4152000a3b
1 changed files with 25 additions and 2 deletions
|
|
@ -380,17 +380,40 @@ in
|
|||
# (bound socket above), which is up before the container — nix's
|
||||
# own connect retries cover any brief window. `mkBefore` runs this
|
||||
# ahead of any upstream pre-steps.
|
||||
#
|
||||
# The `+` prefix runs this step with FULL PRIVILEGES instead of as
|
||||
# the unit's (dynamic) `gitea-runner` user. The token file is 0600
|
||||
# root-owned, so an unprivileged check cannot read it — and it did
|
||||
# not fail closed: `[ -s ]` succeeds on a stat alone, `grep` then
|
||||
# died with EACCES, and `! grep` turned that error into `true`, so
|
||||
# the gate exited 0 on an unreadable file. It reported "a real token
|
||||
# is present" without ever having looked, for its entire existence.
|
||||
#
|
||||
# This grants the runner nothing new: `tokenFile` above becomes
|
||||
# `EnvironmentFile=`, which systemd already reads AS ROOT before
|
||||
# dropping privileges, so the payload never passes through an
|
||||
# unprivileged reader either way. The `+` only lets the gate observe
|
||||
# what systemd observes.
|
||||
serviceConfig.ExecStartPre = lib.mkBefore [
|
||||
(pkgs.writeShellScript "hive-ci-runner-precond" ''
|
||||
"+${pkgs.writeShellScript "hive-ci-runner-precond" ''
|
||||
RUNNER=/var/lib/gitea-runner/hive/.runner
|
||||
TOKEN_FILE=/run/hive-ci/runner-token
|
||||
if [ -f "$RUNNER" ]; then exit 0; fi
|
||||
# Readability is asserted SEPARATELY and fails loudly. Folding
|
||||
# it into the test below is what hid the bug: an unreadable file
|
||||
# and a file holding a real token produced the same verdict, so
|
||||
# "I could not look" was indistinguishable from "I looked and it
|
||||
# is fine".
|
||||
if [ -e "$TOKEN_FILE" ] && [ ! -r "$TOKEN_FILE" ]; then
|
||||
echo "hive-ci runner: $TOKEN_FILE exists but is unreadable by this step; the credential gate cannot run" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ -s "$TOKEN_FILE" ] && ! ${pkgs.gnugrep}/bin/grep -q '^TOKEN=placeholder$' "$TOKEN_FILE"; then
|
||||
exit 0
|
||||
fi
|
||||
echo "hive-ci runner: not registered and no real token yet; waiting for hive-c0re to register" >&2
|
||||
exit 1
|
||||
'')
|
||||
''}"
|
||||
];
|
||||
# Registration is out of band: hive-c0re explicitly restarts this
|
||||
# unit once it writes the real token, which is the primary path. As
|
||||
|
|
|
|||
Loading…
Reference in a new issue