From 4679314556a81b8f101d3011c731e7fb8e08617c Mon Sep 17 00:00:00 2001 From: Feng Ruohang Date: Thu, 6 Aug 2026 21:02:15 +0800 Subject: [PATCH] build(packages): unify the rpm and deb release segment as 1PGSTY The rpm carried a bare -1 release while the deb carried none. Both now ship the PGDG-style 1PGSTY segment: silo-VER-1PGSTY.arch.rpm and silo_VER-1PGSTY_arch.deb, with nfpm rendering it as the RPM Release tag and the Debian revision respectively. The apk stays bare because Alpine pkgrel admits only -r. sign-release-rpms.sh declares the value once as expected_release; package-release.sh names artifacts from its own PKG_RELEASE copy, and test-release.yml evals the signing script's value and asserts both the download names and the packaged RPM Release/DEB Version against it, so the copies cannot drift apart silently. Co-Authored-By: Claude Fable 5 --- .github/workflows/test-release.yml | 91 +++++++++++++++--------------- buildscripts/package-release.sh | 18 ++++-- buildscripts/sign-release-rpms.sh | 7 ++- 3 files changed, 63 insertions(+), 53 deletions(-) diff --git a/.github/workflows/test-release.yml b/.github/workflows/test-release.yml index c3b397220..b10da1102 100644 --- a/.github/workflows/test-release.yml +++ b/.github/workflows/test-release.yml @@ -131,14 +131,37 @@ jobs: set -euo pipefail cd dist/packages + # The signing script asserts these same values, but it runs on the + # maintainer's machine after the release workflow has already built + # and uploaded. Take its expectations as the single source of truth + # so nfpm.yml and the signing script cannot drift apart without + # failing here first, while a fix is still cheap. + # + # This grep is deliberately limited to the eight identity variables, + # all of which are single-line. That is what makes the eval safe: + # should one ever become multi-line, the grep captures an + # unterminated quote and the eval aborts on a syntax error under + # set -e rather than quietly binding an empty value and comparing + # against nothing. expected_payload is multi-line by design and must + # stay out of this set for the same reason. + eval "$(grep -E '^expected_(release|vendor|packager|url|summary|description|license|group)=' \ + ../../buildscripts/sign-release-rpms.sh)" + for value in "${expected_release}" "${expected_vendor}" "${expected_packager}" \ + "${expected_url}" "${expected_summary}" "${expected_description}" \ + "${expected_license}" "${expected_group}"; do + test -n "${value}" + done + # These are the public download names; a drift here breaks every - # script that fetches packages by URL. + # script that fetches packages by URL. RPM and DEB carry the PGSTY + # release segment; APK cannot (Alpine pkgrel admits only -r), + # so it stays bare. package-release.sh builds the same three shapes. expected=( - "silo-${PKG_VERSION}-1.aarch64.rpm" - "silo-${PKG_VERSION}-1.x86_64.rpm" + "silo-${PKG_VERSION}-${expected_release}.aarch64.rpm" + "silo-${PKG_VERSION}-${expected_release}.x86_64.rpm" + "silo_${PKG_VERSION}-${expected_release}_amd64.deb" + "silo_${PKG_VERSION}-${expected_release}_arm64.deb" "silo_${PKG_VERSION}_aarch64.apk" - "silo_${PKG_VERSION}_amd64.deb" - "silo_${PKG_VERSION}_arm64.deb" "silo_${PKG_VERSION}_x86_64.apk" ) @@ -150,34 +173,14 @@ jobs: test "$(find . -maxdepth 1 -type f \( -name '*.rpm' -o -name '*.deb' -o -name '*.apk' \) | wc -l)" -eq 6 - # The signing script asserts these same values, but it runs on the - # maintainer's machine after the release workflow has already built - # and uploaded. Take its expectations as the single source of truth - # so nfpm.yml and the signing script cannot drift apart without - # failing here first, while a fix is still cheap. - # - # This grep is deliberately limited to the seven identity variables, - # all of which are single-line. That is what makes the eval safe: - # should one ever become multi-line, the grep captures an - # unterminated quote and the eval aborts on a syntax error under - # set -e rather than quietly binding an empty value and comparing - # against nothing. expected_payload is multi-line by design and must - # stay out of this set for the same reason. - eval "$(grep -E '^expected_(vendor|packager|url|summary|description|license|group)=' \ - ../../buildscripts/sign-release-rpms.sh)" - for value in "${expected_vendor}" "${expected_packager}" "${expected_url}" \ - "${expected_summary}" "${expected_description}" \ - "${expected_license}" "${expected_group}"; do - test -n "${value}" - done - service_sha="$(sha256sum ../../silo.service | awk '{print $1}')" defaults_sha="$(sha256sum ../../silo.env | awk '{print $1}')" sysusers_sha="$(sha256sum ../../silo.sysusers | awk '{print $1}')" license_sha="$(sha256sum ../../LICENSE | awk '{print $1}')" notice_sha="$(sha256sum ../../NOTICE | awk '{print $1}')" - rpm_file="silo-${PKG_VERSION}-1.x86_64.rpm" + rpm_file="silo-${PKG_VERSION}-${expected_release}.x86_64.rpm" + test "$(rpm -qp --queryformat '%{RELEASE}' "${rpm_file}")" = "${expected_release}" test "$(rpm -qp --queryformat '%{VENDOR}' "${rpm_file}")" = "${expected_vendor}" test "$(rpm -qp --queryformat '%{PACKAGER}' "${rpm_file}")" = "${expected_packager}" test "$(rpm -qp --queryformat '%{URL}' "${rpm_file}")" = "${expected_url}" @@ -212,9 +215,9 @@ jobs: exit 1 fi - deb_file="silo_${PKG_VERSION}_amd64.deb" + deb_file="silo_${PKG_VERSION}-${expected_release}_amd64.deb" test "$(dpkg-deb --field "${deb_file}" Maintainer)" = "${expected_packager}" - test "$(dpkg-deb --field "${deb_file}" Version)" = "${PKG_VERSION}" + test "$(dpkg-deb --field "${deb_file}" Version)" = "${PKG_VERSION}-${expected_release}" test "$(dpkg-deb --field "${deb_file}" License)" = "${expected_license}" test "$(dpkg-deb --field "${deb_file}" Section)" = "utils" test "$(dpkg-deb --field "${deb_file}" Homepage)" = "${expected_url}" @@ -259,8 +262,8 @@ jobs: apk_arch=aarch64 fi - test "$(rpm -qp --queryformat '%{ARCH}' "silo-${PKG_VERSION}-1.${rpm_arch}.rpm")" = "${rpm_arch}" - test "$(dpkg-deb --field "silo_${PKG_VERSION}_${deb_arch}.deb" Architecture)" = "${deb_arch}" + test "$(rpm -qp --queryformat '%{ARCH}' "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm")" = "${rpm_arch}" + test "$(dpkg-deb --field "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" Architecture)" = "${deb_arch}" grep -Fx "arch = ${apk_arch}" <<< "$(tar -xOzf "silo_${PKG_VERSION}_${apk_arch}.apk" .PKGINFO)" # Accepted weakness: this takes the first match, unsorted, where @@ -278,25 +281,25 @@ jobs: # rpm's own digests instead -- -K checks the payload against the # header, and FILEDIGESTS is the sha256 rpm itself verifies on # install. - rpm -K "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" + rpm -K "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" rpm_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/usr/bin/silo" { print $2 }')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/usr/bin/silo" { print $2 }')" rpm_service_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/usr/lib/systemd/system/silo.service" { print $2 }')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/usr/lib/systemd/system/silo.service" { print $2 }')" rpm_defaults_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/etc/default/silo" { print $2 }')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/etc/default/silo" { print $2 }')" rpm_sysusers_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/usr/lib/sysusers.d/silo.conf" { print $2 }')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/usr/lib/sysusers.d/silo.conf" { print $2 }')" rpm_license_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/usr/share/doc/silo/LICENSE" { print $2 }')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/usr/share/doc/silo/LICENSE" { print $2 }')" rpm_notice_sha="$(rpm -qp --queryformat '[%{FILENAMES} %{FILEDIGESTS}\n]' \ - "silo-${PKG_VERSION}-1.${rpm_arch}.rpm" | awk '$1 == "/usr/share/doc/silo/NOTICE" { print $2 }')" - deb_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/bin/silo | sha256sum | awk '{print $1}')" - deb_service_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/lib/systemd/system/silo.service | sha256sum | awk '{print $1}')" - deb_defaults_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./etc/default/silo | sha256sum | awk '{print $1}')" - deb_sysusers_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/lib/sysusers.d/silo.conf | sha256sum | awk '{print $1}')" - deb_license_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/share/doc/silo/LICENSE | sha256sum | awk '{print $1}')" - deb_notice_sha="$(ar p "silo_${PKG_VERSION}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/share/doc/silo/NOTICE | sha256sum | awk '{print $1}')" + "silo-${PKG_VERSION}-${expected_release}.${rpm_arch}.rpm" | awk '$1 == "/usr/share/doc/silo/NOTICE" { print $2 }')" + deb_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/bin/silo | sha256sum | awk '{print $1}')" + deb_service_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/lib/systemd/system/silo.service | sha256sum | awk '{print $1}')" + deb_defaults_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./etc/default/silo | sha256sum | awk '{print $1}')" + deb_sysusers_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/lib/sysusers.d/silo.conf | sha256sum | awk '{print $1}')" + deb_license_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/share/doc/silo/LICENSE | sha256sum | awk '{print $1}')" + deb_notice_sha="$(ar p "silo_${PKG_VERSION}-${expected_release}_${deb_arch}.deb" data.tar.gz | tar -xzOf - ./usr/share/doc/silo/NOTICE | sha256sum | awk '{print $1}')" apk_sha="$(tar -xzOf "silo_${PKG_VERSION}_${apk_arch}.apk" usr/bin/silo | sha256sum | awk '{print $1}')" apk_service_sha="$(tar -xzOf "silo_${PKG_VERSION}_${apk_arch}.apk" usr/lib/systemd/system/silo.service | sha256sum | awk '{print $1}')" apk_defaults_sha="$(tar -xzOf "silo_${PKG_VERSION}_${apk_arch}.apk" etc/default/silo | sha256sum | awk '{print $1}')" diff --git a/buildscripts/package-release.sh b/buildscripts/package-release.sh index bb128df78..bb7e68587 100755 --- a/buildscripts/package-release.sh +++ b/buildscripts/package-release.sh @@ -20,6 +20,10 @@ if ! [[ "${PKG_VERSION}" =~ ^[0-9]{14}\.0\.0$ ]]; then exit 1 fi +# The PGSTY release segment, PGDG-style. sign-release-rpms.sh declares the +# same value as expected_release, and test-release.yml asserts the two agree. +PKG_RELEASE="1PGSTY" + if ! command -v nfpm >/dev/null 2>&1; then echo "nfpm is required" >&2 exit 1 @@ -122,19 +126,21 @@ build_arch() { source="$(find_binary "${goarch}")" - # These names are the public download names and must not drift; RPM carries a - # release number, DEB and APK do not, matching what pkger produced. - rpm_file="${packages_dir}/silo-${PKG_VERSION}-1.${rpm_arch}.rpm" - deb_file="${packages_dir}/silo_${PKG_VERSION}_${deb_arch}.deb" + # These names are the public download names and must not drift; RPM and DEB + # carry the PGSTY release number (nfpm renders it as the RPM Release tag and + # as the Debian revision after a dash). APK stays bare: Alpine pkgrel only + # admits -r, so a lettered release cannot ride along there. + rpm_file="${packages_dir}/silo-${PKG_VERSION}-${PKG_RELEASE}.${rpm_arch}.rpm" + deb_file="${packages_dir}/silo_${PKG_VERSION}-${PKG_RELEASE}_${deb_arch}.deb" apk_file="${packages_dir}/silo_${PKG_VERSION}_${apk_arch}.apk" ( cd "${repo_dir}" export NFPM_UNIT="${unit_file}" NFPM_DEFAULTS="${defaults_file}" NFPM_SYSUSERS="${sysusers_file}" \ NFPM_LICENSE="${license_file}" NFPM_NOTICE="${notice_file}" - PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE=1 NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" \ + PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE="${PKG_RELEASE}" NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" \ nfpm package --config "${nfpm_config}" --packager rpm --target "${rpm_file}" - PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" \ + PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE="${PKG_RELEASE}" NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" \ nfpm package --config "${nfpm_config}" --packager deb --target "${deb_file}" PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" \ nfpm package --config "${nfpm_config}" --packager apk --target "${apk_file}" diff --git a/buildscripts/sign-release-rpms.sh b/buildscripts/sign-release-rpms.sh index 32816626d..830ee9595 100755 --- a/buildscripts/sign-release-rpms.sh +++ b/buildscripts/sign-release-rpms.sh @@ -7,6 +7,7 @@ set -euo pipefail # other way round would only surface here, on the maintainer's machine, after # the build has already run and uploaded. expected_fingerprint="9592A7BC7A682E7333376E09E7935D8DB9BD8B20" +expected_release="1PGSTY" expected_vendor="PGSTY" expected_packager="Ruohang Feng (@Vonng) " expected_url="https://silo.pgsty.com" @@ -126,8 +127,8 @@ mkdir -p "${unsigned_dir}" "${signed_dir}" chmod 700 "${work_dir}" "${unsigned_dir}" "${signed_dir}" rpm_files=( - "silo-${package_version}-1.x86_64.rpm" - "silo-${package_version}-1.aarch64.rpm" + "silo-${package_version}-${expected_release}.x86_64.rpm" + "silo-${package_version}-${expected_release}.aarch64.rpm" ) download_patterns=() @@ -209,7 +210,7 @@ for rpm_file in "${rpm_files[@]}"; do assert_rpm_tag "${container_rpm}" NAME silo assert_rpm_tag "${container_rpm}" VERSION "${package_version}" - assert_rpm_tag "${container_rpm}" RELEASE 1 + assert_rpm_tag "${container_rpm}" RELEASE "${expected_release}" assert_rpm_tag "${container_rpm}" ARCH "${expected_arch}" assert_rpm_tag "${container_rpm}" VENDOR "${expected_vendor}" assert_rpm_tag "${container_rpm}" PACKAGER "${expected_packager}"