forgejo-runner install does not check the Docker Engine, and its group warning understates a fatal condition #142

Open
opened 2026-08-01 19:05:09 +00:00 by claude-bot-andresmgsl · 0 comments

Context

forgejo-runner daemon treats a missing Docker Engine as fatal — it exits 1 immediately and never connects. From @andres's ci-box, 2026-08-01:

time="2026-08-01T18:50:58Z" level=info msg="Starting runner daemon"
Error: daemon Docker Engine socket not found and docker_host config was invalid
forgejo-runner.service: Main process exited, code=exited, status=1/FAILURE
forgejo-runner.service: Scheduled restart job, restart counter is at 76.

rig installed it anyway, registered it against the instance, and said "installed and running".

Two defects

1. There is no Docker preflight. commands/forgejo-runner-install.sh checks only for the group, at :270-278, and only warns. A box with no Docker at all sails through registration.

2. The warning that does exist is wrong. :277:

no docker group on this box — jobs using docker:// labels will fail. Inside a ci-box, 'rig bootstrap ci-box' installs docker; elsewhere install it before running jobs.

"jobs using docker:// labels will fail" understates it by a category. Without Docker there are no jobs to fail — the daemon never starts, so the runner is Offline forever. An operator reading that line reasonably concludes they have a working runner that cannot run some workloads, and goes looking in the wrong place. @andres did exactly that, for thirteen minutes of crash-loop.

The warning is also about the wrong thing: group membership is a permissions detail, whereas the daemon's hard requirement is a reachable socket. A box can have the group and no Engine.

Why it should refuse, not warn

The check happens before registration, and registration consumes a token the operator minted by hand. Installing a runner that provably cannot start, after spending their token, is the same shape as #139: a secret paid into a run that could never succeed.

rig refuses rather than guessing elsewhere for exactly this reason — bootstrap on an unmet precondition, and now require_admin_bins on a PATH without /usr/sbin (#139).

Spec

Refuse before registering when the Docker Engine is not reachable.

  • Assert the socket/daemon, not just the group: docker info succeeding, or the socket existing and answering — group membership stays a separate, softer check.
  • Refuse before the registration token is read or used.
  • Name the remedy, and distinguish the two boxes: inside a ci-box tenant, rig bootstrap ci-box installs Docker; elsewhere, the operator installs it.
  • Rewrite :277 so it states the real consequence — the runner will not start — rather than implying degraded operation.
  • Keep the group check, corrected: having Docker but not the group is a genuinely different, and recoverable, state.

Tasks

  • Add the Engine preflight, before registration
  • Correct the group warning's claim
  • test/cli.sh: a box with no reachable Engine refuses, and refuses before the token prompt
  • changelog.d/<n>.md

Acceptance criteria

  • With no Docker Engine, install exits non-zero naming the remedy
  • It refuses before reading or spending a registration token — driven
  • With Docker present but the user not in the group, it still installs and warns accurately
  • With both present, behaviour is unchanged
  • bash test/cli.sh passes; CI's shellcheck -x step is clean

Test plan

  • Stub docker absent / failing and assert the refusal text and its ordering against the token prompt.
  • Must fail: delete the preflight and the refusal test goes red.
  • Stub Docker present, group absent: installs, warns, and the warning no longer claims "jobs will fail".

Dependencies

Related to #141 — that assert is why this failure was reported as success. They are separable: #141 would have lied about any startup failure; this one is the specific precondition that caused it. Same doctrine as #139.


@andres — filed, not fixed, per your instruction.

## Context `forgejo-runner daemon` treats a missing Docker Engine as **fatal** — it exits 1 immediately and never connects. From @andres's ci-box, 2026-08-01: ``` time="2026-08-01T18:50:58Z" level=info msg="Starting runner daemon" Error: daemon Docker Engine socket not found and docker_host config was invalid forgejo-runner.service: Main process exited, code=exited, status=1/FAILURE forgejo-runner.service: Scheduled restart job, restart counter is at 76. ``` rig installed it anyway, registered it against the instance, and said "installed and running". ## Two defects **1. There is no Docker preflight.** `commands/forgejo-runner-install.sh` checks only for the *group*, at `:270-278`, and only warns. A box with no Docker at all sails through registration. **2. The warning that does exist is wrong.** `:277`: > `no docker group on this box — jobs using docker:// labels will fail. Inside a ci-box, 'rig bootstrap ci-box' installs docker; elsewhere install it before running jobs.` "jobs using `docker://` labels will fail" understates it by a category. Without Docker there are no jobs to fail — the daemon never starts, so the runner is Offline forever. An operator reading that line reasonably concludes they have a working runner that cannot run *some* workloads, and goes looking in the wrong place. @andres did exactly that, for thirteen minutes of crash-loop. The warning is also about the wrong thing: group membership is a permissions detail, whereas the daemon's hard requirement is a reachable **socket**. A box can have the group and no Engine. ## Why it should refuse, not warn The check happens *before* registration, and registration consumes a token the operator minted by hand. Installing a runner that provably cannot start, after spending their token, is the same shape as #139: a secret paid into a run that could never succeed. `rig` refuses rather than guessing elsewhere for exactly this reason — `bootstrap` on an unmet precondition, and now `require_admin_bins` on a `PATH` without `/usr/sbin` (#139). ## Spec Refuse before registering when the Docker Engine is not reachable. - Assert the **socket/daemon**, not just the group: `docker info` succeeding, or the socket existing and answering — group membership stays a separate, softer check. - Refuse before the registration token is read or used. - Name the remedy, and distinguish the two boxes: inside a ci-box tenant, `rig bootstrap ci-box` installs Docker; elsewhere, the operator installs it. - Rewrite `:277` so it states the real consequence — the runner will not start — rather than implying degraded operation. - Keep the group check, corrected: having Docker but not the group is a genuinely different, and recoverable, state. ## Tasks - [ ] Add the Engine preflight, before registration - [ ] Correct the group warning's claim - [ ] `test/cli.sh`: a box with no reachable Engine refuses, and refuses **before** the token prompt - [ ] `changelog.d/<n>.md` ## Acceptance criteria - [ ] With no Docker Engine, `install` exits non-zero naming the remedy - [ ] It refuses **before** reading or spending a registration token — driven - [ ] With Docker present but the user not in the group, it still installs and warns accurately - [ ] With both present, behaviour is unchanged - [ ] `bash test/cli.sh` passes; CI's `shellcheck -x` step is clean ## Test plan - Stub `docker` absent / failing and assert the refusal text and its ordering against the token prompt. - **Must fail:** delete the preflight and the refusal test goes red. - Stub Docker present, group absent: installs, warns, and the warning no longer claims "jobs will fail". ## Dependencies Related to #141 — that assert is why this failure was reported as success. They are separable: #141 would have lied about any startup failure; this one is the specific precondition that caused it. Same doctrine as #139. --- @andres — filed, not fixed, per your instruction.
claude-bot-andresmgsl added the
bug
scope:runner
labels 2026-08-01 19:05:09 +00:00
claude-bot-andresmgsl added the
ready
label 2026-08-17 23:23:45 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/rig#142
No description provided.