fix(release): retain XBPS key through publication

The optional XBPS publisher signs repository metadata after package signing. Remove the runner key only after publication and release asset upload.
This commit is contained in:
xavierk
2026-09-29 04:06:45 +05:30
parent a5b84f7566
commit 3f2dd6a5a1
3 changed files with 26 additions and 6 deletions
+4 -1
View File
@@ -159,7 +159,6 @@ jobs:
gpg --batch --yes --delete-secret-keys "${FINGERPRINT}" gpg --batch --yes --delete-secret-keys "${FINGERPRINT}"
gpg --batch --yes --delete-keys "${FINGERPRINT}" gpg --batch --yes --delete-keys "${FINGERPRINT}"
fi fi
rm -f ~/.ssh/id_xbps
- name: Determine version - name: Determine version
id: version id: version
@@ -345,3 +344,7 @@ jobs:
"https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases/${RELEASE_ID}/assets" "https://git.bongbetic.com/api/v1/repos/xavierk/Fenris/releases/${RELEASE_ID}/assets"
fi fi
done done
- name: Remove XBPS signing key
if: always()
run: rm -f ~/.ssh/id_xbps
+21 -5
View File
@@ -58,6 +58,20 @@ gpg --batch --yes --delete-keys packaging@bongbetic.com
The committed `fenris-packaging.asc` must contain the real public key (replace The committed `fenris-packaging.asc` must contain the real public key (replace
the placeholder comments). the placeholder comments).
## XBPS signing key
XBPS uses a separate RSA 3072 key. Its private half is stored as the Gitea
repository Actions secret `XBPS_SIGNING_KEY`. The corresponding public key is
published at
`https://git.bongbetic.com/xavierk/Fenris-xbps/raw/branch/stable/keys/fenris-xbps-signing.pub`,
with fingerprint `SHA256:AvPMRlKMikPg75u0iKr8AUkxlfU/Ad4k/S4o2M9W4/w`.
The secret must match that public key.
The release workflow writes the key to `~/.ssh/id_xbps` to sign the XBPS
package. A requested XBPS publication also uses the key to sign repository
metadata. A final `always()` cleanup removes the runner copy after publication
and release asset upload, including when an earlier step fails.
## Per-release signing flow ## Per-release signing flow
Each tagged release performs: **import → verify → sign → delete** on the Each tagged release performs: **import → verify → sign → delete** on the
@@ -76,14 +90,16 @@ git push origin v<version>
The release workflow imports `GPG_PRIVATE_KEY`, checks it against The release workflow imports `GPG_PRIVATE_KEY`, checks it against
`packaging/keys/fenris-packaging.asc`, builds packages, signs the RPM and `packaging/keys/fenris-packaging.asc`, builds packages, signs the RPM and
clearsigned checksum manifest, validates both, and publishes the release. clearsigned checksum manifest, validates both, and publishes the release. The
XBPS publication is separate and requires its signing key and host acceptance. workflow imports `XBPS_SIGNING_KEY` separately and signs the XBPS package.
XBPS publication is optional and also signs repository metadata; it requires
host acceptance and explicit selection during workflow dispatch.
### Step 3: Verify runner cleanup ### Step 3: Verify runner cleanup
The workflow's `always()` cleanup removes the imported key from the runner's The workflow's `always()` cleanup removes the GPG key from the runner's keyring
keyring, including after a failed job. Confirm no packaging secret key remains and deletes `~/.ssh/id_xbps`, including after a failed job. Confirm no signing
on the runner after the release job. key remains on the runner after the release job.
The Gitea Actions secret remains the approved signing source. Do not copy it to The Gitea Actions secret remains the approved signing source. Do not copy it to
the runner or repository outside the workflow. the runner or repository outside the workflow.
+1
View File
@@ -45,6 +45,7 @@
- **deb: unsigned.** apt never verifies payload signatures; trust = instance-signed `InRelease` (signed-by keyring) + TLS + Acquire-By-Hash. Manual-download integrity is covered by SHA256SUMS. - **deb: unsigned.** apt never verifies payload signatures; trust = instance-signed `InRelease` (signed-by keyring) + TLS + Acquire-By-Hash. Manual-download integrity is covered by SHA256SUMS.
- **SHA256SUMS: clearsigned** with the packaging key — the trust anchor for manually downloaded release assets, independent of TLS. - **SHA256SUMS: clearsigned** with the packaging key — the trust anchor for manually downloaded release assets, independent of TLS.
- **Packaging key:** single dedicated key, RSA 3072, UID `Fenris Packaging <packaging@bongbetic.com>`, 2-year expiry, no master/subkey hierarchy. The private key is stored as the repository Actions secret `GPG_PRIVATE_KEY`. The release workflow imports it on the self-hosted runner, verifies it against the in-repo public key, signs the RPM and SHA256SUMS, then deletes the runner's keyring copy in an `always()` cleanup step. The full ceremony is documented in `docs/install/signing-key-ceremony.md`. - **Packaging key:** single dedicated key, RSA 3072, UID `Fenris Packaging <packaging@bongbetic.com>`, 2-year expiry, no master/subkey hierarchy. The private key is stored as the repository Actions secret `GPG_PRIVATE_KEY`. The release workflow imports it on the self-hosted runner, verifies it against the in-repo public key, signs the RPM and SHA256SUMS, then deletes the runner's keyring copy in an `always()` cleanup step. The full ceremony is documented in `docs/install/signing-key-ceremony.md`.
- **XBPS key:** separate RSA 3072 key stored as the repository Actions secret `XBPS_SIGNING_KEY`; its public key and fingerprint are published in `Fenris-xbps`. The release workflow uses it for the XBPS package and, when publication is explicitly requested, the repository index. A final `always()` cleanup deletes its runner copy after publication and release asset upload.
- **Public key publication:** in-repo `packaging/keys/fenris-packaging.asc` (raw URL doubles as the `.repo` gpgkey target), release notes, docs page. No keyservers — TOFU-over-TLS. - **Public key publication:** in-repo `packaging/keys/fenris-packaging.asc` (raw URL doubles as the `.repo` gpgkey target), release notes, docs page. No keyservers — TOFU-over-TLS.
- **Rotation (outline):** new key published alongside old; rpm signed with the new key; `fenris.repo` gpgkey lists both URLs (dnf accepts multiple); old key dropped after one release cycle. Procedure details stay in map fog. - **Rotation (outline):** new key published alongside old; rpm signed with the new key; `fenris.repo` gpgkey lists both URLs (dnf accepts multiple); old key dropped after one release cycle. Procedure details stay in map fog.