refactor(ci): move the xbps job out of the GitHub release workflow

The signed repository is now published by the tag-triggered Gitea workflow,
so release.yml drops the build-xbps job, its place in the checksum job's
needs list, the xbps-repo artifact pattern, and the checksum lines for
files that no longer arrive. The release notes point at the Gitea release
instead of promising attached repository files.

The policy tests now assert the new shape: release.yml carries no xbps
job, and the Gitea workflow is the one place that runs repo.sh.
This commit is contained in:
2026-11-06 18:26:14 +05:30
parent 227c3cc1a3
commit ba6462ccf8
3 changed files with 74 additions and 188 deletions
+9 -111
View File
@@ -290,19 +290,12 @@ jobs:
refresh from the Store. amd64 only.
### Void Linux (glibc x86_64, signed xbps repo)
Also attached below: the signed repository files (`*.x86_64.xbps`
with signatures, `x86_64-repodata`, and the client key
`FINGERPRINT` plus the fingerprint-named `.plist`). This is a
third-party repository published by this project, not upstream
Void Linux:
```bash
# as root (the files come from this release's assets):
cp <fingerprint>.plist /var/db/xbps/keys/
echo 'repository=https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/' > /etc/xbps.d/voculinux.conf
sudo xbps-install -Sy voculinux
```
Answer `Y` at the fingerprint prompt only after checking it
matches the attached `FINGERPRINT` file.
Not attached here. The signed xbps repository is published by the
tag-triggered Gitea workflow `.gitea/workflows/xbps-release.yml` to
the release named `latest` on the project's Gitea host. It is a
third-party repository published by this project, not upstream Void
Linux. The registration lines and the key fingerprint to pin are in
the Void Linux section of the README.
### Verifying what you downloaded
`SHA256SUMS` covers every file here and is attached once the aarch64 AppImage,
@@ -804,7 +797,7 @@ jobs:
# missing one looks like the tampered one.
publish-checksums:
name: Checksums and Provenance
needs: [build-and-release, build-appimage-arm64, build-native, build-native-arm64, build-flatpak-amd64, build-flatpak-arm64, attach-flatpak, attach-snap, build-xbps]
needs: [build-and-release, build-appimage-arm64, build-native, build-native-arm64, build-flatpak-amd64, build-flatpak-arm64, attach-flatpak, attach-snap]
runs-on: ubuntu-latest
# An attach-job failure must not skip checksums: this job hashes the build
# artifacts, which exist regardless of whether an upload to the release
@@ -820,7 +813,7 @@ jobs:
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
# Verification-only artifacts must never enter the release manifest.
pattern: '@(python-dist|appimage-*|native-*|flatpak-*|snap-amd64|xbps-repo)'
pattern: '@(python-dist|appimage-*|native-*|flatpak-*|snap-amd64)'
merge-multiple: true
path: dist
@@ -831,9 +824,6 @@ jobs:
for pat in '*.whl' '*.tar.gz' '*.AppImage' '*.deb' '*.rpm' '*.flatpak' '*.snap'; do
compgen -G "$pat" > /dev/null || { echo "missing artifact: $pat"; exit 1; }
done
for pat in 'repo/*.x86_64.xbps' 'repo/*.sig2' 'repo/*-repodata*' 'keys/FINGERPRINT' 'keys/*.plist'; do
compgen -G "$pat" > /dev/null || { echo "missing artifact: $pat"; exit 1; }
done
test "$(compgen -G '*.AppImage' | wc -l)" -eq 2
test "$(compgen -G '*.deb' | wc -l)" -eq 2
test "$(compgen -G '*.rpm' | wc -l)" -eq 2
@@ -845,12 +835,8 @@ jobs:
set -euo pipefail
ls -la
# Bare names, so `sha256sum -c` works in whatever directory the user
# downloaded the release into. The xbps repo files hash from their
# own directories for the same reason: the release attaches them
# flat, and RSA signatures stay the primary trust root.
# downloaded the release into.
sha256sum -- *.whl *.tar.gz *.AppImage *.deb *.rpm *.flatpak *.snap | tee SHA256SUMS
(cd repo && sha256sum -- *.x86_64.xbps *.sig2 *-repodata*) >> SHA256SUMS
(cd keys && sha256sum -- FINGERPRINT *.plist) >> SHA256SUMS
# Attesting from the manifest rather than a second glob: the file we
# publish and the set we attest cannot drift apart.
@@ -1043,94 +1029,6 @@ jobs:
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: 'Release ${{ github.ref_name }}'
# The signed Void xbps repository (ticket #29): every template builds in
# smoke-gate order in the pinned Void container via podman, the full
# repository index is signed with the RSA4096 repository key, and the
# packages, signatures, repodata, and client key land on this release.
# XBPS_SIGNING_KEY is required — an unsigned repository can never
# publish, so a missing key fails the job instead of skipping it (unlike
# the opt-in Flatpak remote and AUR publishes). The voculinux template
# builds the canonical release sdist, so this waits for build-and-release,
# and the tag must match src/vocalinux/version.py or the job aborts.
build-xbps:
name: Build signed xbps repository
needs: build-and-release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Verify tag matches the version source of truth
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/v}"
PACKAGE_VERSION=$(grep -oP '__version__\s*=\s*"\K[^"]+' src/vocalinux/version.py)
echo "Tag version: $TAG"
echo "Package version: $PACKAGE_VERSION"
if [[ "$PACKAGE_VERSION" != *"$TAG"* ]] && [[ "$TAG" != *"$PACKAGE_VERSION"* ]]; then
echo "::error::Tag v$TAG does not match src/vocalinux/version.py ($PACKAGE_VERSION); refusing to ship the signed repo"
exit 1
fi
# Fail-closed: no key, no repo, no publish — never a silent skip.
- name: Require the repository signing key
env:
XBPS_SIGNING_KEY: ${{ secrets.XBPS_SIGNING_KEY }}
run: |
if [ -z "$XBPS_SIGNING_KEY" ]; then
echo "::error::XBPS_SIGNING_KEY is unset; refusing to publish an unsigned repository (packaging/void/README.md)"
exit 1
fi
- name: Install podman
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends podman
- name: Build and sign the repository
env:
XBPS_SIGNING_KEY: ${{ secrets.XBPS_SIGNING_KEY }}
run: |
set -euo pipefail
printf '%s' "$XBPS_SIGNING_KEY" > /tmp/xbps-sign-key.pem
chmod 600 /tmp/xbps-sign-key.pem
XBPS_SIGNING_KEY_FILE=/tmp/xbps-sign-key.pem bash packaging/void/repo.sh
rm -f /tmp/xbps-sign-key.pem
ls -la publish/xbps/repo publish/xbps/keys
- name: Upload the signed repository
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: xbps-repo
path: |
publish/xbps/repo/*
publish/xbps/keys/*
if-no-files-found: error
retention-days: 7
- name: Attach the signed repository to the release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
cd publish/xbps
# Full signed repo or nothing: binary packages (*.x86_64.xbps)
# with their signatures, the signed repository metadata
# (*-repodata), and the client key files (FINGERPRINT plus the
# fingerprint-named .plist). Each class is required below, so a
# partial repo can never attach.
compgen -G 'repo/*.x86_64.xbps' > /dev/null || { echo "missing packages"; exit 1; }
compgen -G 'repo/*.sig2' > /dev/null || { echo "missing signatures"; exit 1; }
compgen -G 'repo/*-repodata*' > /dev/null || { echo "missing repodata"; exit 1; }
compgen -G 'keys/FINGERPRINT' > /dev/null || { echo "missing FINGERPRINT"; exit 1; }
compgen -G 'keys/*.plist' > /dev/null || { echo "missing client key"; exit 1; }
gh release upload "${{ github.ref_name }}" \
repo/*.x86_64.xbps repo/*.sig2 repo/*-repodata* keys/FINGERPRINT keys/*.plist \
--repo ${{ github.repository }} \
--clobber
# GitHub Release first, Store second. A super-privileged plug can still
# queue a human review and refuse edge/candidate; the .snap still
# has to land on the tag for sideload. grade: stable allows candidate; do