From f6afe4e46d8fded6d48be8eaccd8e6f971acad39 Mon Sep 17 00:00:00 2001 From: ReenigneArcher <42013603+ReenigneArcher@users.noreply.github.com> Date: Fri, 4 Sep 2026 23:38:42 -0400 Subject: [PATCH] fix(cloudsmith-backfill): bypass rpmrebuild setarch for cross-arch RPMs Add cross-architecture handling in `prepareRpm` to avoid unsupported `setarch` execution during RPM repacks. The script now detects when a bypass is needed, injects a shim `setarch`, writes an `rpmrc` build compatibility override, and passes an explicit `--target` to `rpmrebuild` while preserving deterministic timestamps. Tests were updated to cover the new bypass decision logic and generated compatibility config. --- .github/scripts/cloudsmith-backfill.mjs | 65 ++++++++++++++++++--- .github/workflows/__cloudsmith-backfill.yml | 4 +- .github/workflows/__social-post.yml | 2 +- tests/cloudsmith-backfill.test.mjs | 13 +++++ 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/.github/scripts/cloudsmith-backfill.mjs b/.github/scripts/cloudsmith-backfill.mjs index 0a378f41..cf38ccd8 100644 --- a/.github/scripts/cloudsmith-backfill.mjs +++ b/.github/scripts/cloudsmith-backfill.mjs @@ -40,6 +40,33 @@ function packageNames(repository) { return {deb, rpm: repository}; } +/** + * Determine whether rpmrebuild would attempt an unsupported setarch call. + * + * rpmrebuild uses setarch when the package and runner architectures differ, + * even though rebuilding an existing payload does not execute target binaries. + * + * @param {string} hostArchitecture Runner architecture. + * @param {string} packageArchitecture RPM architecture. + * @returns {boolean} Whether to bypass rpmrebuild's setarch invocation. + */ +export function requiresSetarchBypass(hostArchitecture, packageArchitecture) { + return packageArchitecture !== hostArchitecture + && packageArchitecture !== 'noarch' + && packageArchitecture !== '(none)'; +} + +/** + * Create the temporary RPM build compatibility declaration for a cross-architecture repack. + * + * @param {string} hostArchitecture Runner architecture. + * @param {string} packageArchitecture RPM architecture. + * @returns {string} rpmrc contents. + */ +export function rpmBuildCompatibility(hostArchitecture, packageArchitecture) { + return `buildarch_compat: ${hostArchitecture}: ${packageArchitecture} ${hostArchitecture} noarch\n`; +} + /** * Return a tag without Sunshine's leading v. * @@ -283,6 +310,7 @@ function queryDeb(filename) { function queryRpm(filename) { const output = command('rpm', [ '-qp', + '--nosignature', '--qf', '%{NAME}\u001f%{VERSION}\u001f%{RELEASE}\u001f%{ARCH}', filename, @@ -397,24 +425,47 @@ export async function prepareRpm({source, destinationDirectory, release, target, const rebuildDirectory = `${source}.rpmrebuild`; mkdirSync(rebuildDirectory, {recursive: true}); try { + const rebuildEnvironment = { + ...process.env, + SOURCE_DATE_EPOCH: String(Math.floor(Date.parse(release.published_at) / 1000)), + }; + const hostArchitecture = command('uname', ['-m']); + if (requiresSetarchBypass(hostArchitecture, original.architecture)) { + const toolDirectory = path.join(rebuildDirectory, 'bin'); + const setarch = path.join(toolDirectory, 'setarch'); + mkdirSync(toolDirectory, {recursive: true}); + writeFileSync(setarch, '#!/bin/sh\nshift\nexec "$@"\n'); + chmodSync(setarch, 0o755); + rebuildEnvironment.PATH = `${toolDirectory}${path.delimiter}${process.env.PATH}`; + + const rpmConfigurationHome = path.join(rebuildDirectory, 'rpm-config'); + const rpmConfigurationDirectory = path.join(rpmConfigurationHome, 'rpm'); + mkdirSync(rpmConfigurationDirectory, {recursive: true}); + writeFileSync( + path.join(rpmConfigurationDirectory, 'rpmrc'), + rpmBuildCompatibility(hostArchitecture, original.architecture), + ); + rebuildEnvironment.XDG_CONFIG_HOME = rpmConfigurationHome; + } const filter = [ 'sed', `-e "s/^Name:.*/Name: ${desired.name}/"`, `-e "s/^Version:.*/Version: ${desired.version}/"`, `-e "s/^Release:.*/Release: ${desired.release}/"`, ].join(' '); - command('rpmrebuild', [ + const rpmrebuildArguments = [ '--package', '--batch', '--notest-install', `--directory=${rebuildDirectory}`, `--change-spec-preamble=${filter}`, - source, - ], { - env: { - ...process.env, - SOURCE_DATE_EPOCH: String(Math.floor(Date.parse(release.published_at) / 1000)), - }, + ]; + if (requiresSetarchBypass(hostArchitecture, original.architecture)) { + rpmrebuildArguments.push(`--additional=--target ${original.architecture}`); + } + rpmrebuildArguments.push(source); + command('rpmrebuild', rpmrebuildArguments, { + env: rebuildEnvironment, stdio: 'inherit', }); const rebuiltFiles = findFiles( diff --git a/.github/workflows/__cloudsmith-backfill.yml b/.github/workflows/__cloudsmith-backfill.yml index 391e26d9..db8167aa 100644 --- a/.github/workflows/__cloudsmith-backfill.yml +++ b/.github/workflows/__cloudsmith-backfill.yml @@ -72,7 +72,7 @@ jobs: }); - name: Upload distro-specific packages - uses: LizardByte/actions/actions/cloudsmith_upload@f697f5b43d7787eca2cef681d314a2093cfa15e3 # master + uses: LizardByte/actions/actions/cloudsmith_upload@188c8ccad593e0f68bcf6aacb6bf84f10359d26f # v2026.905.43751 with: api_key: ${{ secrets.CLOUDSMITH_API_KEY }} dry_run: ${{ !inputs.publish }} @@ -82,7 +82,7 @@ jobs: package_path: artifacts/cloudsmith/detected repository: stable republish: ${{ inputs.republish }} - skip_unsupported: false + skip_unsupported: true wait_for_sync: false - name: Upload distro-neutral RPMs diff --git a/.github/workflows/__social-post.yml b/.github/workflows/__social-post.yml index d21ee0f2..72f6ddb8 100644 --- a/.github/workflows/__social-post.yml +++ b/.github/workflows/__social-post.yml @@ -102,7 +102,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Post to X through Buffer - uses: LizardByte/actions/actions/buffer_post@def4fdac92797d03bb6d02d7c24ddfa5e7d83825 + uses: LizardByte/actions/actions/buffer_post@188c8ccad593e0f68bcf6aacb6bf84f10359d26f # v2026.905.43751 with: api_key: ${{ secrets.BUFFER_API_KEY }} channel_id: ${{ vars.BUFFER_X_CHANNEL_ID }} diff --git a/tests/cloudsmith-backfill.test.mjs b/tests/cloudsmith-backfill.test.mjs index b67a9de4..9a9e311c 100644 --- a/tests/cloudsmith-backfill.test.mjs +++ b/tests/cloudsmith-backfill.test.mjs @@ -8,6 +8,8 @@ import { classifyRpm, debianVersion, replaceDebControlFields, + requiresSetarchBypass, + rpmBuildCompatibility, selectStableReleases, versionFromTag, } from '../.github/scripts/cloudsmith-backfill.mjs'; @@ -119,3 +121,14 @@ test('replaceDebControlFields corrects package identity and version only', () => /missing Version/, ); }); + +test('setarch is bypassed only for cross-architecture RPM rebuilds', () => { + assert.equal(requiresSetarchBypass('x86_64', 'aarch64'), true); + assert.equal(requiresSetarchBypass('x86_64', 'x86_64'), false); + assert.equal(requiresSetarchBypass('x86_64', 'noarch'), false); + assert.equal(requiresSetarchBypass('x86_64', '(none)'), false); + assert.equal( + rpmBuildCompatibility('x86_64', 'aarch64'), + 'buildarch_compat: x86_64: aarch64 x86_64 noarch\n', + ); +});