From 90da1b2e7214676876e8ee85b12879cf529de639 Mon Sep 17 00:00:00 2001 From: John Mitsch Date: Thu, 11 Jun 2026 12:06:17 -0400 Subject: [PATCH] Fix COPR SRPM build: embed both arch tarballs in the SRPM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.1.5's custom-publish-copr job failed at the "Build SRPM" step with: error: Bad file: /home/runner/rpmbuild/SOURCES/quicknode-cli-x86_64- unknown-linux-gnu.tar.xz.sha256: No such file or directory Root cause: `rpmbuild -bs` needs Source files to exist locally in ~/rpmbuild/SOURCES/ to build the SRPM, even when the spec declares them as URLs. The "URLs get fetched at build time" model only kicks in when COPR's mock runs the SRPM, not when the SRPM is initially assembled. There was a second latent bug: the spec used %ifarch to template a single Source URL based on the build host's arch. The runner is x86_64, so the SRPM would have only embedded the x86_64 tarball, and COPR's aarch64 mock builds would have failed for the opposite reason. Both fixed by switching to a single architecture-fat SRPM: * packaging/qn-bin.spec — drops the %ifarch URL templating, drops the curl + sha256 dance in %prep. Declares both arch tarballs as Source0 (x86_64) + Source1 (aarch64). %prep uses %ifarch with %setup -T -b N to extract the right embedded source for the chroot's arch. rpm itself sha256-verifies embedded sources at extract time (sha256s live in the SRPM header), so we don't need to redo it in %prep. * .github/workflows/publish-copr.yml — adds a step that uses gh release download to pull both arch tarballs into SOURCES/ before invoking `rpmbuild -bs`. The SRPM ends up carrying both tarballs (~8 MB) and ships once to COPR. Drops --enable-net=on from `copr-cli build`: now that the SRPM embeds the sources, mock chroots don't need network. The COPR project's "enable net" setting still applies if we ever do need it; this flag was just a per-build override. Single SRPM, single copr-cli dispatch, all chroots build from the same source set. The binary in the resulting RPMs stays bit-identical to what ships everywhere else. v0.1.5 already shipped to crates.io, GHCR, .deb, and the GitHub Release — only COPR was missed. v0.1.6 (next release) will exercise this fix and backfill COPR. --- .github/workflows/publish-copr.yml | 31 +++++++++++----- packaging/qn-bin.spec | 58 +++++++++++------------------- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/.github/workflows/publish-copr.yml b/.github/workflows/publish-copr.yml index 117a1cf..a305404 100644 --- a/.github/workflows/publish-copr.yml +++ b/.github/workflows/publish-copr.yml @@ -10,8 +10,8 @@ name: Publish RPMs to COPR # RPM is bit-identical to the one in crates.io, Homebrew, GHCR, .deb, # and AUR. # -# `copr-cli build --enable-net=on` is required because the spec's -# %prep stage fetches the tarball over HTTPS from the GitHub Release. +# The SRPM embeds both Linux gnu tarballs (x86_64 + aarch64), so +# COPR's mock chroots can build without network access. on: workflow_call: inputs: @@ -51,15 +51,27 @@ jobs: - name: Build SRPM env: QN_VERSION: ${{ steps.meta.outputs.version }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | # Set up the rpmbuild tree. mkdir -p "$HOME/rpmbuild"/{SOURCES,SPECS,SRPMS} cp packaging/qn-bin.spec "$HOME/rpmbuild/SPECS/qn-bin.spec" - # SRPM only has the spec — the sources are fetched by mock at - # %prep time (Source0/Source1 are URLs, not local files). We - # pass --nodeps so rpmbuild doesn't try to satisfy - # BuildRequires on the runner; COPR's mock handles that. + # Pre-download both arch tarballs into SOURCES/ — rpmbuild -bs + # needs the actual files present locally to embed them in the + # SRPM, even though the spec's Source0/Source1 are URLs. The + # resulting SRPM carries both tarballs; %prep picks one based + # on the chroot's arch. + cd "$HOME/rpmbuild/SOURCES" + gh release download "v$QN_VERSION" \ + --repo quicknode/cli \ + --pattern "quicknode-cli-x86_64-unknown-linux-gnu.tar.xz" \ + --pattern "quicknode-cli-aarch64-unknown-linux-gnu.tar.xz" + ls -la + cd "$GITHUB_WORKSPACE" + + # --nodeps so rpmbuild doesn't try to satisfy BuildRequires on + # the runner; COPR's mock chroot handles that for the real build. rpmbuild -bs "$HOME/rpmbuild/SPECS/qn-bin.spec" \ --define "_topdir $HOME/rpmbuild" \ --define "qn_version $QN_VERSION" \ @@ -107,6 +119,7 @@ jobs: exit 1 fi echo "Uploading $srpm to quicknode/qn..." - # --enable-net=on so COPR's mock chroot can curl the prebuilt - # tarball + sha256 sidecar from the GitHub Release in %prep. - copr-cli build quicknode/qn "$srpm" --enable-net=on + # No --enable-net=on needed: the SRPM already embeds both + # arch tarballs (rpmbuild verifies them at extract time via + # the sha256 baked into the SRPM header). + copr-cli build quicknode/qn "$srpm" diff --git a/packaging/qn-bin.spec b/packaging/qn-bin.spec index 1b9c9ab..a7b5d5a 100644 --- a/packaging/qn-bin.spec +++ b/packaging/qn-bin.spec @@ -1,20 +1,16 @@ # qn-bin: install the SLSA-attested binary cargo-dist ships, no rebuild. # -# This spec is built on COPR's mock chroots. `%prep` downloads the per-arch -# linux-gnu tarball from the GitHub Release and verifies it against the -# .sha256 sidecar; `%install` lays the binary + docs into the buildroot. -# No Rust toolchain involved on the COPR side — the binary inside the -# resulting RPM is bit-identical to what ships in crates.io, -# Homebrew, .deb, and the GHCR image. +# This spec is built on COPR's mock chroots. The SRPM embeds both Linux +# gnu tarballs (x86_64 + aarch64) cargo-dist published for this release; +# %prep selects the right one for the chroot's arch and %install lays +# the binary + docs into the buildroot. No Rust toolchain involved on +# the COPR side — the binary inside the resulting RPM is bit-identical +# to what ships in crates.io, Homebrew, .deb, AUR, and the GHCR image. # -# Built and uploaded by .github/workflows/publish-copr.yml on each release. -# Requires --enable-net=on at build time (mock fetches the tarball). - -%global qn_version %{getenv:QN_VERSION} - -%if "%{qn_version}" == "" -%{error: QN_VERSION must be set when building this spec (e.g. rpmbuild --define "qn_version 0.1.4")} -%endif +# Built by .github/workflows/publish-copr.yml on each release. That +# workflow pre-downloads both arch tarballs into ~/rpmbuild/SOURCES/ +# before invoking `rpmbuild -bs`, so the resulting SRPM carries the +# sources and COPR's mock can build with --enable-net=off if desired. Name: qn Version: %{qn_version} @@ -23,18 +19,10 @@ Summary: Command-line interface for the Quicknode SDK License: MIT URL: https://github.com/quicknode/cli -# cargo-dist emits separate tarballs per Rust target triple. We map COPR's -# arch tokens to those triples; the per-arch Source entry below picks the -# right one at build time. -%ifarch x86_64 -%global rust_target x86_64-unknown-linux-gnu -%endif -%ifarch aarch64 -%global rust_target aarch64-unknown-linux-gnu -%endif - -Source0: https://github.com/quicknode/cli/releases/download/v%{version}/quicknode-cli-%{rust_target}.tar.xz -Source1: https://github.com/quicknode/cli/releases/download/v%{version}/quicknode-cli-%{rust_target}.tar.xz.sha256 +# Both arch tarballs ship in the SRPM. %prep picks one based on the +# chroot's arch. +Source0: https://github.com/quicknode/cli/releases/download/v%{version}/quicknode-cli-x86_64-unknown-linux-gnu.tar.xz +Source1: https://github.com/quicknode/cli/releases/download/v%{version}/quicknode-cli-aarch64-unknown-linux-gnu.tar.xz ExclusiveArch: x86_64 aarch64 BuildRequires: coreutils @@ -51,18 +39,12 @@ the same SLSA-attested artifact that ships in crates.io, Homebrew, the GHCR Docker image, the AUR qn-bin package, and Debian .deb files. %prep -# Verify the tarball matches the sha256 sidecar from the release. -# The sidecar's format is ` *`; rewrite the filename to -# point at the local SOURCES path so `sha256sum -c` works. -expected_hash=$(awk '{print $1}' < %{SOURCE1}) -actual_hash=$(sha256sum %{SOURCE0} | awk '{print $1}') -if [ "$expected_hash" != "$actual_hash" ]; then - echo "Error: sha256 mismatch for %{SOURCE0}" >&2 - echo " expected: $expected_hash" >&2 - echo " actual: $actual_hash" >&2 - exit 1 -fi -%setup -q -n quicknode-cli-%{rust_target} +%ifarch x86_64 +%setup -q -T -b 0 -n quicknode-cli-x86_64-unknown-linux-gnu +%endif +%ifarch aarch64 +%setup -q -T -b 1 -n quicknode-cli-aarch64-unknown-linux-gnu +%endif %install install -Dm755 qn %{buildroot}%{_bindir}/qn