fix: a release job uses only the key it is given, never the runner's own
CI / checks (push) Failing after 2m13s
CI / package and container gate (push) Skipped

Measured on a throwaway Gitea: with the key secret unset, Preview's
publish job would have fallen back to the runner machine's own ssh
configuration — on the development VM, the production publish key — and
published a throwaway 9.9.9 to the real server. It was cancelled before
it ran. And with the key set, the job wrote over the runner account's own
~/.ssh/config and known_hosts.

Now, under Actions, a job without RELEASE_SSH_KEY stops; with it, the key,
its known_hosts and an ssh configuration live in the job's own directory
and every ssh and rsync goes through `ssh -F` (RELEASE_SSH_CONFIG in
release-lib), which reads nothing else. The key is deleted when the job
ends. By hand, nothing changes. Also records the end-to-end measurements
of Release 1 and of Preview's gate job in docs/releasing.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-09-29 20:24:50 -05:00
co-authored by Claude Opus 5.5
parent 22f25854aa
commit 14291fde37
5 changed files with 103 additions and 19 deletions
+15 -2
View File
@@ -362,6 +362,13 @@ Gitea 1.27.2 with act_runner 0.6.1:
**Anyone with write access can publish**, by writing a workflow that uses the
key. Give write access accordingly.
The release scripts never use a runner's own ssh keys: under Actions the
key comes only from the secret, is written to the job's own directory with
its own `known_hosts` and an ssh configuration used with `ssh -F` (which
ignores `~/.ssh/config`), and is deleted when the job ends. A job without
the secret stops. **Never put a runner on a machine that holds the publish
key by hand** — the development VM does — in case that rule is ever broken.
So: the key lives only in Gitea's secret store, never on a runner's disk,
where an approved fork job could read it. The `ekklesia-release` runner runs
each job in a fresh container (`ekklesia-release:docker://node:22-trixie`,
@@ -495,7 +502,13 @@ runs), on the development VM, 2026-09-29:
| Question | Answer |
| --- | --- |
| Do all five workflows parse, and plan only on their own events? | Yes: CI on push and pull_request; the release workflows only on a manual run |
| Does the CI checks job pass on a real runner? | Yes: 30 of 30, and its logs upload as an artifact |
| Does the CI checks job pass on a real runner? | Yes: all 31 checks, and their logs upload as an artifact |
| Does CI's package job build, and run the gate in its CI mode? | Yes: built, the tree unchanged, fresh install and both upgrades passed, the report marked `mode ci` |
| Does **Release 1 - build** work end to end? | Yes, at a throwaway version 9.9.9 against what canary (0.2.6.6) and stable (0.2.6.4) really serve: built from the commit with the tree unchanged, full gate passed, pre-release `v9.9.9` tagged at exactly that commit with the package, SHA256SUMS, build-info.json, gate report and check summary |
| Is a second build of the same version refused? | Yes: "v9.9.9 already has a Gitea release; a version is built once" |
| Does Preview's gate job work? | Yes: it downloaded the release's file, proved it against the sha256 given and SHA256SUMS, passed the full gate, attached a uniquely named report, recorded it, and handed its name to the publish job |
| If the key secret is missing, what would the publish job use? | **This machine's own ssh configuration** — on the development VM, the production publish key: a throwaway 9.9.9 would have gone to the real server. The job was cancelled before it ran, and since then a job under Actions without the key refuses, and one with it uses only its own configuration (`ssh -F`), never the runner's |
| Does a failing check stop a release build? | Yes: an undocumented workflow left in the tree failed `test-workflows`, and nothing was built |
| Can the automatic token create a release, attach an asset, edit the notes? | Yes |
| Does `tools/gitea-release` refuse different bytes under a published name, on real Gitea? | Yes |
| Do `github.event.inputs.X` and `inputs.X` both work? | Yes |
@@ -507,6 +520,6 @@ runs), on the development VM, 2026-09-29:
| Approved, does it get secrets? | No. It gets variables, a token, and any runner it names |
Not measured, because it needs the real update server's key in a real
runner: the publish and promote jobs end to end. Their scripts are the ones
runner: Preview's publish job and Stable's promote job end to end. Their scripts are the ones
used by hand since 0.2.6, and `tests/test-release-ci.sh` runs them against a
stand-in server and a stand-in Gitea.