Sign the automated version bump commit in CI
CI / Coding Standards (pull_request) Successful in 23s
CI / Tests (PHP 8.5) (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 35s
CI / Static Analysis (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / No Debug Code (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
CI / Coding Standards (pull_request) Successful in 23s
CI / Tests (PHP 8.5) (pull_request) Successful in 27s
CI / Tests (PHP 8.2) (pull_request) Successful in 35s
CI / Static Analysis (pull_request) Successful in 39s
CI / Tests (PHP 8.3) (pull_request) Successful in 40s
CI / Tests (PHP 8.1) (pull_request) Successful in 49s
CI / No Debug Code (pull_request) Successful in 35s
CI / Build Plugin Zip (pull_request) Skipped
main now requires signed commits, and Gitea refuses to merge a pull request carrying an unsigned one, so the post-release bump PR could not be merged without disabling the protection first. The runner now signs that commit with a dedicated release-bot SSH key held as an organisation Actions secret, trusted by the instance through [repository.signing] TRUSTED_SSH_KEYS. The key Gitea signs merge commits with lives on the server and no runner can reach it. The step fails fast when the secret is missing, unparseable or passphrase protected, and the commit is re-read before pushing so an unsigned one is caught here rather than days later at merge time. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -149,6 +149,50 @@ jobs:
|
||||
{ print }
|
||||
' CHANGELOG.md > CHANGELOG.md.tmp && mv CHANGELOG.md.tmp CHANGELOG.md
|
||||
|
||||
# main requires signed commits, and Gitea refuses to merge a pull request
|
||||
# that carries an unsigned one. The key Gitea signs merge commits with
|
||||
# lives on the server and is not reachable from a runner, so the bump
|
||||
# commit is signed here with a dedicated release-bot key that the instance
|
||||
# trusts via TRUSTED_SSH_KEYS. Generating that key, trusting it and storing
|
||||
# the secret is documented in docs/ci.md.
|
||||
- name: Configure signing as Release Bot
|
||||
env:
|
||||
SIGNING_KEY: ${{ secrets.RELEASE_BOT_SIGNING_KEY }}
|
||||
run: |
|
||||
if [ -z "${SIGNING_KEY}" ]; then
|
||||
echo "RELEASE_BOT_SIGNING_KEY is not set - the bump commit would be unsigned and unmergeable." >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! command -v ssh-keygen > /dev/null; then
|
||||
echo "ssh-keygen is missing from the runner image; git cannot make SSH signatures without it." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The secret holds an OpenSSH private key ("-----BEGIN OPENSSH PRIVATE
|
||||
# KEY-----"). git signs by shelling out to ssh-keygen, which wants that
|
||||
# key on disk next to the .pub it is pointed at, readable only by us,
|
||||
# and rejects it unless the final newline survived the round trip.
|
||||
keydir="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/release-bot-signing"
|
||||
install -m 700 -d "${keydir}"
|
||||
printf '%s\n' "${SIGNING_KEY}" | tr -d '\r' > "${keydir}/key"
|
||||
chmod 600 "${keydir}/key"
|
||||
# Doubles as a format check: a truncated or re-wrapped key fails here,
|
||||
# with a clearer cause than "gpg failed to sign the data" later on.
|
||||
if ! ssh-keygen -y -f "${keydir}/key" < /dev/null > "${keydir}/key.pub"; then
|
||||
echo "RELEASE_BOT_SIGNING_KEY is not a usable OpenSSH private key (passphrase-protected, truncated, or re-wrapped on paste)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# No Gitea account backs this address; TRUSTED_SSH_KEYS verifies the
|
||||
# signature without an account lookup, so it is a label, not an identity.
|
||||
git config user.name 'Release Bot'
|
||||
git config user.email '[email protected]'
|
||||
# Named gpg.format for historical reasons; "ssh" is what switches git
|
||||
# over to signing with the SSH key above rather than a GPG key.
|
||||
git config gpg.format ssh
|
||||
git config user.signingkey "${keydir}/key.pub"
|
||||
git config commit.gpgsign true
|
||||
|
||||
- name: Open pull request
|
||||
env:
|
||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -157,10 +201,14 @@ jobs:
|
||||
branch="release/bump-${next}"
|
||||
api="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}"
|
||||
|
||||
git config user.name 'Release Bot'
|
||||
git config user.email '[email protected]'
|
||||
git checkout -b "${branch}"
|
||||
git commit -am "Bump version to ${next} and open changelog section"
|
||||
# A commit that came out unsigned would otherwise go unnoticed until
|
||||
# someone tried to merge the PR, so fail here instead.
|
||||
if ! git cat-file commit HEAD | grep -q '^gpgsig'; then
|
||||
echo "Bump commit is unsigned; refusing to push it." >&2
|
||||
exit 1
|
||||
fi
|
||||
git push origin "${branch}"
|
||||
|
||||
curl -fsS -X POST "${api}/pulls" \
|
||||
|
||||
Reference in New Issue
Block a user