fix(aur): gate source publication on attested sdists (#1020)

* fix(aur): gate source publication on attested sdists

Prepare and verify the canonical release source, build the exact PKGBUILD on Arch, and publish the gated artifact without further rewrites. Part of #701.

* fix(aur): isolate local gate and binary publication

Keep local gate distributions and diagnostics in a private workspace, preserving other build outputs and failed diagnostics. Publish vocalinux-bin after its own AppImage inputs without depending on the source gate or unrelated release jobs. Add regression coverage for both review findings.
This commit is contained in:
Sergey Silaev
2026-10-26 20:26:04 -07:00
committed by GitHub
parent aae1f4b474
commit 5687363a4a
13 changed files with 925 additions and 102 deletions
+54 -18
View File
@@ -871,9 +871,51 @@ jobs:
with:
skip-existing: true
aur-source-test:
name: Verify AUR release source (gate)
needs: [build-and-release, publish-checksums]
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
attestations: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
version: '0.13.3'
- name: Download the published sdist and checksum manifest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release download "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" \
--pattern 'vocalinux-*.tar.gz' --pattern SHA256SUMS --dir release-source
- name: Verify provenance and prepare the exact source PKGBUILD
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
uv run --python "$(command -v python)" --locked --only-group release-build \
python scripts/prepare_aur_source.py \
--sdist release-source/vocalinux-*.tar.gz --manifest release-source/SHA256SUMS \
--tag "$GITHUB_REF_NAME" --source-commit "$GITHUB_SHA" --output build/aur-source
- name: Build and install the exact source PKGBUILD on Arch
run: |
docker run --rm -v "$PWD:/repo:ro" -e AUR_SOURCE_ONLY=1 -e AUR_FETCH_SOURCE=1 \
archlinux:latest bash /repo/packaging/aur/build-test.sh
- name: Retain only the verified source PKGBUILD for publication
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: aur-source-pkgbuild
path: build/aur-source/PKGBUILD
if-no-files-found: error
retention-days: 7
publish-aur:
name: Publish to AUR
needs: build-and-release
needs: [build-and-release, aur-source-test]
runs-on: ubuntu-latest
permissions:
contents: read
@@ -891,27 +933,20 @@ jobs:
echo "configured=true" >> "$GITHUB_OUTPUT"
fi
- name: Checkout code
- name: Download the verified source PKGBUILD
if: steps.aur.outputs.configured == 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Bump PKGBUILD version
if: steps.aur.outputs.configured == 'true'
run: |
set -euo pipefail
TAG="${GITHUB_REF#refs/tags/v}"
for PKGBUILD in packaging/aur/vocalinux/PKGBUILD packaging/aur/vocalinux-bin/PKGBUILD; do
sed -i "s/^pkgver=.*/pkgver=${TAG//-/}/; s/^_tag=.*/_tag=${TAG}/; s/^pkgrel=.*/pkgrel=1/" "$PKGBUILD"
grep -E '^(pkgver|_tag|pkgrel)=' "$PKGBUILD"
done
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: aur-source-pkgbuild
path: aur-source
- name: Publish AUR package
if: steps.aur.outputs.configured == 'true'
uses: KSXGitHub/github-actions-deploy-aur@084b0d9b15415bf9cdb65d44dad1efe37a354050 # v4.2.0
with:
pkgname: vocalinux
pkgbuild: packaging/aur/vocalinux/PKGBUILD
updpkgsums: 'true'
pkgbuild: aur-source/PKGBUILD
updpkgsums: 'false'
commit_username: ${{ secrets.AUR_USERNAME }}
commit_email: ${{ secrets.AUR_EMAIL }}
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
@@ -919,11 +954,12 @@ jobs:
# Separate job: the -bin PKGBUILD pins digests of BOTH AppImages, and the
# aarch64 build attaches its asset after build-and-release returns. Waiting
# for it here keeps the source package publishing early while the binary
# package never curls a 404.
# for it here keeps the binary package from curling a 404. Do not depend on
# source publication: its Arch gate and unrelated checksum producers must
# not block ready AppImages.
publish-aur-bin:
name: Publish -bin to AUR
needs: [publish-aur, build-appimage-arm64]
needs: [build-and-release, build-appimage-arm64]
runs-on: ubuntu-latest
permissions:
contents: read
+33 -7
View File
@@ -67,6 +67,9 @@ jobs:
# the whole python matrix along.
aur:
- 'packaging/aur/**'
- 'MANIFEST.in'
- 'README.md'
- 'LICENSE'
- '.github/workflows/unified-pipeline.yml'
# Same carve-out for the .deb/.rpm gate: nfpm.yaml mirrors
# pyproject.toml's dependencies against distro package names, so a
@@ -116,6 +119,15 @@ jobs:
version: '0.13.3'
- name: Build and verify reproducible wheel
run: python scripts/build_reproducible_wheel.py --python "$(command -v python)"
- name: Share the canonical distributions with packaging gates
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: python-dist
path: |
dist/*.whl
dist/*.tar.gz
if-no-files-found: error
retention-days: 7
- name: Preserve failed wheel builds and diagnostics
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -383,21 +395,35 @@ jobs:
"${{ matrix.distro }}" \
bash /pk/boot-test.sh "/dist/$(basename "$APPIMAGE")"
# Nothing built the PKGBUILD before a tag pushed it to AUR users, which is
# how #757 shipped: Arch's setuptools 84 against our old <82 cap. The gate
# swaps the not-yet-existing tag tarball for a git archive of the checkout,
# so it answers whether *this commit* builds on Arch. Deliberately
# archlinux:latest: the AUR is a rolling channel and #757 was Arch moving
# under us.
# Build the canonical sdist produced by this commit's wheel gate. PR sources
# are explicitly unattested fixtures; release.yml verifies published sources
# before passing the same prepared PKGBUILD to this Arch gate. Deliberately
# archlinux:latest: the AUR follows Arch's current distro toolchain (#757).
aur-build-test:
name: 🏛️ Build AUR package (gate)
runs-on: ubuntu-latest
needs: changes
needs: [changes, reproducible-wheel]
if: needs.changes.outputs.python == 'true' || needs.changes.outputs.aur == 'true'
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.11'
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
with:
version: '0.13.3'
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: python-dist
path: dist
- name: Prepare the local unattested source fixture
run: |
uv run --python "$(command -v python)" --locked --only-group release-build \
python scripts/prepare_aur_source.py \
--local-unattested --sdist dist/vocalinux-*.tar.gz --output build/aur-source
- name: Build the PKGBUILD on Arch
run: |
docker run --rm \