fix(void): build the xbps release from the tag, not an attached sdist (#37)
Every release is built from its tag alone by packaging/void/build-release.sh, shared by the tag workflow and local dry runs. Signs in a network-less container with the key mounted read-only and publishes to the tag release and the rolling latest release.
This commit was merged in pull request #37.
This commit is contained in:
+60
-53
@@ -40,19 +40,21 @@ publish succeeds.
|
||||
### Void xbps repository (required for a Void release)
|
||||
|
||||
The signed Void repository is released by `.gitea/workflows/xbps-release.yml`
|
||||
on the fork's Gitea host, not by `release.yml`. Set it up once:
|
||||
on the fork's Gitea host, not by `release.yml`. The whole release is one script,
|
||||
`packaging/void/build-release.sh`, which the workflow and a local dry run both
|
||||
call. Set it up once:
|
||||
|
||||
| what | value |
|
||||
|---|---|
|
||||
| Secret | `XBPS_SIGNING_KEY`: the PEM-encoded RSA 4096 repository private key (Gitea repository settings, Actions, Secrets) |
|
||||
| Public key | `packaging/void/repository-key.plist`, committed, fingerprint `fa:d1:00:32:ce:b1:b9:fd:73:05:05:76:75:54:37:25` |
|
||||
| Runner | `bongbetic-ci` with podman (the workflow installs it with apt when absent). Never Docker |
|
||||
| Runner | `bongbetic-ci`, a host job with podman (rootless, with user namespaces), python3.11, uv 0.12/0.13 and tmpfs `/dev/shm`. Requirements: `packaging/void/README.md`, "Runner requirements". Never Docker |
|
||||
| Token | the job token must be allowed to create releases and upload release assets |
|
||||
|
||||
Without the secret the workflow fails and publishes nothing; it never signs
|
||||
with a different key either, because the fingerprint of the key that signed
|
||||
must equal the one above. The private key is never committed; only the public
|
||||
`.plist` is. Key generation and the check that a private key matches the
|
||||
with a different key either: the release path refuses any key whose public half
|
||||
is not `repository-key.plist`. The private key is never committed; only the
|
||||
public `.plist` is. Key generation and the check that a private key matches the
|
||||
committed public key are in `packaging/void/README.md`.
|
||||
|
||||
## Quick Release Checklist
|
||||
@@ -72,7 +74,7 @@ Use this checklist for every release:
|
||||
- [ ] `docs/INSTALL.md` - Verify install examples use `main/install.sh` (not version-pinned raw URLs)
|
||||
- [ ] `docs/UPDATE.md` - Add "What's New" section for new version
|
||||
- [ ] `SECURITY.md` - Update supported versions table
|
||||
- [ ] `packaging/void/srcpkgs/` - After the tag, bump template `version`/`checksum` to the new release as a pull request (never direct to `main`)
|
||||
- [ ] `packaging/void/srcpkgs/voculinux/template` - set `version` (the xbps spelling, the hyphen removed) and `_tag` to this release, in the same release PR as `version.py`. The tag gate refuses a tag whose template names another release. The checksum is recorded after the release (section 3.5)
|
||||
|
||||
### Website
|
||||
- [ ] `web/src/app/page.tsx` - Update `softwareVersion` in schema
|
||||
@@ -329,26 +331,32 @@ Update the supported versions table:
|
||||
| < 0.4 | :x: |
|
||||
```
|
||||
|
||||
#### 3.5 Update Void templates (pull request)
|
||||
#### 3.5 Void template: version in the release PR, checksum after the tag (pull request)
|
||||
|
||||
After the tag is cut, the Void templates in `packaging/void/srcpkgs/` must
|
||||
point at the new release: bump `version` in the `voculinux` template (and
|
||||
any template whose upstream moved) and refresh every pinned `checksum`
|
||||
(`sha256` sums of the release sdist and distfiles). The `voculinux` template
|
||||
builds the fork's release asset `voculinux-X.Y.Z.tar.gz`; its `checksum` is
|
||||
the sha256 of that exact downloaded asset, never a value copied from
|
||||
upstream, and stays `PENDING_FORK_RELEASE_SHA256` (which fails closed in
|
||||
`xbps-src`) until the asset exists. Land the bump as a **pull request**
|
||||
through the normal test, lint, and type gates, never as a direct or bot
|
||||
commit to `main`, and never hand-edited onto the release itself (see
|
||||
`just verify-release`). `tests/test_void_app_template.py` fails if the
|
||||
template version or checksum drifts from `src/vocalinux/version.py` and the
|
||||
published sdist.
|
||||
The Void template `packaging/void/srcpkgs/voculinux/template` names one release.
|
||||
It has two parts, handled at two times, and both go through a normal pull request:
|
||||
|
||||
Nothing automates this: the xbps workflow never commits or pushes. The
|
||||
signed repository a tag publishes is built from the templates as committed
|
||||
at that tag, so a bump merged after tag `vX.Y.Z` first ships with the next
|
||||
tag push.
|
||||
- **Version and tag: in the release pull request**, with `version.py`. Set
|
||||
`version` to the xbps spelling of `__version__` (the hyphen removed:
|
||||
`0.19.0-beta` becomes `0.19.0beta`) and `_tag` to the tag (`v0.19.0-beta`).
|
||||
`build-release.sh check-tag` refuses any tag whose template names another
|
||||
release, so a stale template stops the tag, before any build.
|
||||
- **Checksum: after the tag, in a pull request.** The release build replaces
|
||||
`checksum=` in its build tree only, with the sha256 of the sdist it builds, and
|
||||
prints `checksum=<sha256>` in the workflow log and in the release notes
|
||||
(`sdist sha256:`). Copy that value into the template in a pull request through
|
||||
the normal test, lint and type gates. Never commit it directly to `main`, and
|
||||
never hand-edit a release asset.
|
||||
|
||||
The committed template carries a 64-zero placeholder for `checksum=` until that
|
||||
first pull request lands. The placeholder is never a real digest and is never
|
||||
published: every release build replaces it. `tests/test_void_app_template.py`
|
||||
fails if the template's version or `_tag` drifts from `src/vocalinux/version.py`.
|
||||
|
||||
The release build never commits or pushes. Its signed repository is built from
|
||||
the templates as committed at the tag, so a checksum pull request merged after
|
||||
tag `vX.Y.Z` is recorded for the next release, and the next tag builds with it
|
||||
(the build tree always takes the digest of the sdist it builds).
|
||||
|
||||
### Step 4: Update Website
|
||||
|
||||
@@ -541,32 +549,30 @@ Pushing the tag to `origin` (the fork's Gitea repository) also starts
|
||||
`.gitea/workflows/xbps-release.yml`. Pushing a tag is a human act and is
|
||||
approved each time: the workflow has no schedule and no manual trigger.
|
||||
|
||||
1. **Tag equals version.** The tag must be exactly `v` plus `__version__` in
|
||||
`src/vocalinux/version.py`. Any other tag, including one that merely
|
||||
contains the version, exits 1 and publishes nothing.
|
||||
2. **Signing key required.** An empty `XBPS_SIGNING_KEY` exits 1 before any
|
||||
container runs. The key is written to a 0600 temp file, passed to
|
||||
`packaging/void/repo.sh`, and removed by a step that always runs.
|
||||
3. **Build and sign.** `repo.sh` is the only path that builds or signs: the
|
||||
pinned Void glibc container under podman, every template in smoke-gate
|
||||
order, the full `x86_64` index, every package and the metadata signed.
|
||||
4. **Verify.** Packages, signatures, repodata, `FINGERPRINT` and the client
|
||||
key must all be present, nothing but glibc `x86_64` data may be present,
|
||||
every package must be signed, and the signing fingerprint must be the
|
||||
pinned one. A partial or unsigned repository never attaches.
|
||||
5. **Publish.** The complete signed set attaches to the tag's release on
|
||||
Gitea and replaces the assets of the rolling `latest` release, which the
|
||||
client registration URL
|
||||
1. **Tag gate.** `build-release.sh check-tag`: the tag must be exactly `v` plus
|
||||
`__version__`, and the committed template must name that release. Any other
|
||||
tag exits 1 and publishes nothing.
|
||||
2. **Key gate.** The `XBPS_SIGNING_KEY` secret must be non-empty. It is written
|
||||
with noclobber to a `0600` file on tmpfs and removed by a final step that
|
||||
always runs.
|
||||
3. **Runner check.** podman, python3.11, uv 0.12/0.13, openssl, git and curl
|
||||
must be on the runner, or the job names what is missing and stops.
|
||||
4. **Release.** `build-release.sh release` builds the canonical sdist from the
|
||||
tag, builds every template in the pinned Void glibc container
|
||||
without the key, signs the repository in a second container with no network,
|
||||
and installs `voculinux` from that repository in a clean image without the key.
|
||||
A local dry run is `just void-release vX.Y.Z` with `XBPS_SIGNING_KEY_FILE`
|
||||
set: the same script, the same containers, nothing published.
|
||||
5. **Publish.** The staged set (sdist, packages, signatures, `x86_64-repodata`,
|
||||
`FINGERPRINT`, the client `.plist`) attaches to the tag's release on Gitea and
|
||||
replaces the assets of the rolling `latest` release, which the client
|
||||
registration URL
|
||||
(`https://git.bongbetic.com/xavierk/voculinux/releases/download/latest`)
|
||||
serves. Push tags in version order: pushing an older tag refreshes
|
||||
`latest` with the older repository.
|
||||
serves. Push tags in version order: pushing an older tag refreshes `latest`
|
||||
with the older repository.
|
||||
|
||||
The workflow never commits or pushes to any branch and never bumps a
|
||||
template; that is the pull request in section 3.5. The `voculinux` template
|
||||
fetches the fork's `vX.Y.Z` release asset, so that asset must exist and its
|
||||
checksum must be in the template before the build can pass. A tag whose
|
||||
templates still carry the pending checksum fails at the build step, by
|
||||
design.
|
||||
Nothing in this run is built or uploaded by hand, and the workflow never commits
|
||||
or pushes to any branch. The post-release checksum pull request is section 3.5.
|
||||
|
||||
### Step 9: Post-Release Tasks
|
||||
|
||||
@@ -588,11 +594,12 @@ design.
|
||||
matches the line for that wheel in `SHA256SUMS`
|
||||
- [ ] Verify website was deployed (check voculinux.com)
|
||||
- [ ] Verify the Gitea xbps run succeeded, and that both the tag release and
|
||||
`latest` carry the full signed set (`*.x86_64.xbps`, `*.sig2`,
|
||||
`x86_64-repodata`, `FINGERPRINT`, the `.plist`) and that the fingerprint
|
||||
matches the one in `README.md`
|
||||
- [ ] Open the Void template bump pull request (section 3.5); never commit
|
||||
it directly to `main`
|
||||
`latest` carry the full signed set (`sdist/voculinux-*.tar.gz`,
|
||||
`*.x86_64.xbps`, `*.sig2`, `x86_64-repodata`, `FINGERPRINT`, the `.plist`),
|
||||
that the fingerprint matches the one in `README.md`, and that the sdist
|
||||
sha256 in the release notes matches the `checksum=` line the run printed
|
||||
- [ ] Open the Void checksum pull request (section 3.5) with that `checksum=`
|
||||
value; never commit it directly to `main`
|
||||
- [ ] If the Flatpak remote is configured, verify it picked up the tag:
|
||||
`flatpak remote-info vocahq com.voculinux.Voculinux` (docs/FLATPAK_REMOTE.md)
|
||||
- [ ] Announce on social media/communities
|
||||
|
||||
Reference in New Issue
Block a user