Adds openssl and jq to the runner toolchain image.
Why. The release tag gate verifies the Control Plane's signed quorum verdict — an Ed25519 DSSE envelope — by parsing it with jq and checking the signature with openssl pkeyutl -verify -rawin. Neither binary is in this image. Under set -e, both are written as cmd ... || { echo "<security message>"; exit 1; }, so "command not found" took the failure branch and the gate reported:
line 19: jq: command not found
::error::Quorum verdict for v0.0.134 is not a signed DSSE envelope — refusing.
and, after parsing moved to python3, one step later:
::error::Quorum verdict signature for v0.0.135 FAILED verification against the CP's published key — refusing.
Both verdicts were valid, signed, and verifiable throughout. The damage is not only the block: the log accuses the approval, so an investigator is sent at the Tag Request rather than at this image. That is the same failure this Dockerfile already documents for git-daemon, where a missing CGI backend surfaced as three test FAILURES.
This blocked v0.0.134 and v0.0.135 on 2026-08-31.
Verified, not assumed. Built this image locally and ran the gate's real script inside it against the live Control Plane:
OpenSSL 3.5.8 / jq-1.8.1 / Python 3.12.14
✓ v0.0.135 is TR-approved (quorum 1/1), verdict signature verified, bound to 829b1a5752cd…
The unpatched image fails the same script. openssl pkeyutl -rawin needs OpenSSL 3.0+; Alpine's openssl package is 3.5.8, so that holds.
Assumptions & Decisions
Fixing the image rather than working around it in the gate — operator-directed. A runtime apk add was tested and is impossible anyway: the job runs as uid 1000 and the pod drops all caps, exactly as the file's header comment says.
jq is added even though the gate no longer uses it (parsing moved to python3 in zegit 829b1a5). It is the reflex tool for JSON in shell steps, and its absence keeps resurfacing as a misleading failure wherever the next step reaches for it. Do not read this as a reason to revert 829b1a5: that change also made a missing parser report itself honestly instead of as "unsigned", which is worth keeping regardless.
Package list only; no base image bump, no version change.
Open question for the reviewer.push-image.sh and the header comment publish to gitea.langenoja.se/zegit-zoo/zegit-forgejo-runner, but the live deployment runs ghcr.io/zegit-zoo/zegit-forgejo-runner:12.11.1-ci5. I did not reconcile that — please build/push by whichever path is current, then bump both runner containers in flux-config. The agent has no GitHub write, so it cannot publish to ghcr.io itself.
Rollback. Revert the commit and pin the deployment back to 12.11.1-ci5.
Adds `openssl` and `jq` to the runner toolchain image.
**Why.** The release tag gate verifies the Control Plane's signed quorum verdict — an Ed25519 DSSE envelope — by parsing it with `jq` and checking the signature with `openssl pkeyutl -verify -rawin`. Neither binary is in this image. Under `set -e`, both are written as `cmd ... || { echo "<security message>"; exit 1; }`, so "command not found" took the failure branch and the gate reported:
```
line 19: jq: command not found
::error::Quorum verdict for v0.0.134 is not a signed DSSE envelope — refusing.
```
and, after parsing moved to python3, one step later:
```
::error::Quorum verdict signature for v0.0.135 FAILED verification against the CP's published key — refusing.
```
Both verdicts were valid, signed, and verifiable throughout. The damage is not only the block: the log accuses the *approval*, so an investigator is sent at the Tag Request rather than at this image. That is the same failure this Dockerfile already documents for `git-daemon`, where a missing CGI backend surfaced as three test FAILURES.
This blocked v0.0.134 and v0.0.135 on 2026-08-31.
**Verified, not assumed.** Built this image locally and ran the gate's real script inside it against the live Control Plane:
```
OpenSSL 3.5.8 / jq-1.8.1 / Python 3.12.14
✓ v0.0.135 is TR-approved (quorum 1/1), verdict signature verified, bound to 829b1a5752cd…
```
The unpatched image fails the same script. `openssl pkeyutl -rawin` needs OpenSSL 3.0+; Alpine's `openssl` package is 3.5.8, so that holds.
**Assumptions & Decisions**
- Fixing the image rather than working around it in the gate — operator-directed. A runtime `apk add` was tested and is impossible anyway: the job runs as uid 1000 and the pod drops all caps, exactly as the file's header comment says.
- `jq` is added even though the gate no longer uses it (parsing moved to python3 in zegit `829b1a5`). It is the reflex tool for JSON in shell steps, and its absence keeps resurfacing as a misleading failure wherever the next step reaches for it. Do not read this as a reason to revert `829b1a5`: that change also made a missing parser report itself honestly instead of as "unsigned", which is worth keeping regardless.
- Package list only; no base image bump, no version change.
**Open question for the reviewer.** `push-image.sh` and the header comment publish to `gitea.langenoja.se/zegit-zoo/zegit-forgejo-runner`, but the live deployment runs `ghcr.io/zegit-zoo/zegit-forgejo-runner:12.11.1-ci5`. I did not reconcile that — please build/push by whichever path is current, then bump both runner containers in flux-config. The agent has no GitHub write, so it cannot publish to ghcr.io itself.
**Rollback.** Revert the commit and pin the deployment back to `12.11.1-ci5`.
Agent-Session: c49e7dd9-2fb0-4501-8f80-264f8ef3a9b7
The release tag gate parses the Control Plane quorum verdict and verifies its
Ed25519 DSSE signature by shelling out to jq and openssl. Neither is in this
image, and both call sites read cmd ... || { echo <security message>; exit 1; },
so command-not-found took the failure branch: the gate reported a valid, signed
approval first as "not a signed DSSE envelope" and then as "signature FAILED
verification". That blocked v0.0.134 and v0.0.135 on 2026-08-31 and pointed the
investigation at the Tag Request rather than at this image — the same shape as
the git-daemon gap already documented above the package list.
Also adds both to the toolchain assertion. That check already existed and still
missed them, because it only covers what someone thought to list; the comment
now says so, and says to extend it whenever a gate grows a shell dependency.
Verified by building this image and running the gate script inside it against
the live Control Plane: openssl 3.5.8, jq 1.8.1, and the v0.0.135 verdict
verifies and binds to its commit. The unpatched image fails the same script.
agent
marked the pull request as ready for review 2026-08-31 10:57:10 +00:00
markus
merged commit d5ab7a483e into master2026-08-31 10:57:43 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Adds
opensslandjqto the runner toolchain image.Why. The release tag gate verifies the Control Plane's signed quorum verdict — an Ed25519 DSSE envelope — by parsing it with
jqand checking the signature withopenssl pkeyutl -verify -rawin. Neither binary is in this image. Underset -e, both are written ascmd ... || { echo "<security message>"; exit 1; }, so "command not found" took the failure branch and the gate reported:and, after parsing moved to python3, one step later:
Both verdicts were valid, signed, and verifiable throughout. The damage is not only the block: the log accuses the approval, so an investigator is sent at the Tag Request rather than at this image. That is the same failure this Dockerfile already documents for
git-daemon, where a missing CGI backend surfaced as three test FAILURES.This blocked v0.0.134 and v0.0.135 on 2026-08-31.
Verified, not assumed. Built this image locally and ran the gate's real script inside it against the live Control Plane:
The unpatched image fails the same script.
openssl pkeyutl -rawinneeds OpenSSL 3.0+; Alpine'sopensslpackage is 3.5.8, so that holds.Assumptions & Decisions
apk addwas tested and is impossible anyway: the job runs as uid 1000 and the pod drops all caps, exactly as the file's header comment says.jqis added even though the gate no longer uses it (parsing moved to python3 in zegit829b1a5). It is the reflex tool for JSON in shell steps, and its absence keeps resurfacing as a misleading failure wherever the next step reaches for it. Do not read this as a reason to revert829b1a5: that change also made a missing parser report itself honestly instead of as "unsigned", which is worth keeping regardless.Open question for the reviewer.
push-image.shand the header comment publish togitea.langenoja.se/zegit-zoo/zegit-forgejo-runner, but the live deployment runsghcr.io/zegit-zoo/zegit-forgejo-runner:12.11.1-ci5. I did not reconcile that — please build/push by whichever path is current, then bump both runner containers in flux-config. The agent has no GitHub write, so it cannot publish to ghcr.io itself.Rollback. Revert the commit and pin the deployment back to
12.11.1-ci5.Agent-Session: c49e7dd9-2fb0-4501-8f80-264f8ef3a9b7
The release tag gate parses the Control Plane quorum verdict and verifies its Ed25519 DSSE signature by shelling out to jq and openssl. Neither is in this image, and both call sites read cmd ... || { echo <security message>; exit 1; }, so command-not-found took the failure branch: the gate reported a valid, signed approval first as "not a signed DSSE envelope" and then as "signature FAILED verification". That blocked v0.0.134 and v0.0.135 on 2026-08-31 and pointed the investigation at the Tag Request rather than at this image — the same shape as the git-daemon gap already documented above the package list. Also adds both to the toolchain assertion. That check already existed and still missed them, because it only covers what someone thought to list; the comment now says so, and says to extend it whenever a gate grows a shell dependency. Verified by building this image and running the gate script inside it against the live Control Plane: openssl 3.5.8, jq 1.8.1, and the v0.0.135 verdict verifies and binds to its commit. The unpatched image fails the same script.