From 3bd7cee5b7e4e4678efa87d58200a4facb04ff2e Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Wed, 16 Sep 2026 14:44:14 +0300 Subject: [PATCH] Publish and sign a source tarball with each release Package maintainers, Gentoo among them, build from source and had nothing signed to verify against: the source archive GitHub generates for a tag is neither signed nor guaranteed to stay byte-identical. Add release-tarball.yml. It builds 3proxy-.tar.gz with git archive from the release tag, signs the tarball and SHA256SUMS-src with the release key, attests build provenance and uploads all four files to the release. Also drop the SECURITY.md line about Authenticode signing, left over from the removal of self-signed Windows binaries. Closes #1270 Co-Authored-By: Claude Opus 5 --- .github/workflows/release-tarball.yml | 85 +++++++++++++++++++++++++++ SECURITY.md | 18 ++++-- 2 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/release-tarball.yml diff --git a/.github/workflows/release-tarball.yml b/.github/workflows/release-tarball.yml new file mode 100644 index 0000000..1c5154d --- /dev/null +++ b/.github/workflows/release-tarball.yml @@ -0,0 +1,85 @@ +name: Release source tarball + +on: + release: + types: [published] + workflow_dispatch: + +permissions: + contents: read + +jobs: + tarball: + permissions: + contents: write + id-token: write + attestations: write + name: "source tarball" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - name: env + run: | + if [ -f RELEASE ]; then + RELEASE=$(tr -d ' \t\r\n' < RELEASE) + else + RELEASE=$(tr -d ' \t\r\n' < DEVEL) + fi + echo "RELEASE=$RELEASE" >> $GITHUB_ENV + + - name: Create tarball + run: | + # git archive is reproducible from the tag: anyone can regenerate the + # tarball and compare it against the published checksum. + git archive --format=tar.gz -9 \ + --prefix="3proxy-${{ env.RELEASE }}/" \ + -o "3proxy-${{ env.RELEASE }}.tar.gz" HEAD + tar tzf "3proxy-${{ env.RELEASE }}.tar.gz" >/dev/null + ls -l *.tar.gz + + - name: Get artifact + uses: actions/upload-artifact@v7 + with: + name: "3proxy-${{ env.RELEASE }}-src" + path: "*.tar.gz" + + - name: Import signing key + if: github.event_name == 'release' + env: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + run: | + if [ -z "$GPG_PRIVATE_KEY" ]; then echo "GPG_PRIVATE_KEY is not set"; exit 1; fi + mkdir -p ~/.gnupg && chmod 700 ~/.gnupg + printf 'allow-loopback-pinentry\n' > ~/.gnupg/gpg-agent.conf + gpgconf --kill gpg-agent || true + printf '%s' "$GPG_PRIVATE_KEY" | gpg --batch --import + KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec:/{print $5; exit}') + echo "GPG_KEYID=$KEYID" >> $GITHUB_ENV + + - name: Checksums and detached signatures + if: github.event_name == 'release' + env: + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: | + sha256sum *.tar.gz > SHA256SUMS-src + for f in *.tar.gz SHA256SUMS-src; do + gpg --batch --yes --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" \ + -u "$GPG_KEYID" --armor --detach-sign "$f" + done + sha256sum -c SHA256SUMS-src + gpg --verify SHA256SUMS-src.asc SHA256SUMS-src + + - name: Attest build provenance + if: github.event_name == 'release' + uses: actions/attest-build-provenance@v4 + with: + subject-path: | + *.tar.gz + + - name: Upload to release + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.event.release.tag_name }} + run: gh release upload "$TAG" *.tar.gz *.tar.gz.asc SHA256SUMS-src SHA256SUMS-src.asc diff --git a/SECURITY.md b/SECURITY.md index 92e1c1b..0283f8c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,8 +15,8 @@ For High/Critical patched version is released within 2 weeks ## Verifying downloads -Release binaries are published with SHA256 checksums, an OpenPGP signature and -a GitHub build provenance attestation. +Release binaries and the source tarball are published with SHA256 checksums, an +OpenPGP signature and a GitHub build provenance attestation. The release signing key is `3proxy-release-key.asc` in the root of this repository, an RSA-4096 key: @@ -40,6 +40,18 @@ gpg --verify SHA256SUMS-x86_64.asc SHA256SUMS-x86_64 sha256sum -c SHA256SUMS-x86_64 ``` +The source tarball published with each release is signed as well: + +``` +gpg --verify SHA256SUMS-src.asc SHA256SUMS-src +sha256sum -c SHA256SUMS-src +gpg --verify 3proxy-0.9.9.tar.gz.asc 3proxy-0.9.9.tar.gz +``` + +Prefer it over the `Source code (tar.gz)` link GitHub generates automatically: +only the published tarball is signed. It is produced with `git archive` from +the release tag, so it can be regenerated and compared byte for byte. + RPM packages are signed, the signature is checked by rpm itself: ``` @@ -60,5 +72,3 @@ verified with the GitHub CLI: gh attestation verify 3proxy-0.9.9.x86_64.rpm --owner 3proxy gh attestation verify oci://docker.io/3proxy/3proxy:lts --owner 3proxy ``` - -Windows binaries are Authenticode signed in addition to the above.