From 7051cc12d91215143320647cd70cdc50266c271a Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Thu, 9 Oct 2025 09:49:23 -0700 Subject: [PATCH] feat: update bazel central registry publish workflow (#23465) Includes pre-built protoc integrity hashes in the release artifact, in a new file `bazel/private/prebuilt_tool_integrity.bzl` tested on my fork of protobuf: https://github.com/alexeagle/protobuf/releases/tag/v0.1000.10 Next steps: - create toolchain definitions that fetch the prebuilt protoc from github releases - change logic in Bazel setup to use the prebuilt toolchain when desired - create a token from @protobuf-team-bot account and add to GHA secrets so the pull request to BCR opens Closes #23465 COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/23465 from protocolbuffers:alexeagle/bazel-protoc-prebuilt 05314db0266344eae85815380297b31943cbf0d2 PiperOrigin-RevId: 817227717 --- .bcr/source.template.json | 2 +- .gitattributes | 4 ++ .github/workflows/publish_to_bcr.yaml | 36 ++++++++++++++ .github/workflows/release_bazel_module.yaml | 33 +++++++++++++ .github/workflows/release_prep.sh | 53 +++++++++++++++++++++ bazel/private/prebuilt_tool_integrity.bzl | 20 ++++++++ 6 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/publish_to_bcr.yaml create mode 100644 .github/workflows/release_bazel_module.yaml create mode 100755 .github/workflows/release_prep.sh create mode 100644 bazel/private/prebuilt_tool_integrity.bzl diff --git a/.bcr/source.template.json b/.bcr/source.template.json index ce4bbcce0f..d25b0666cc 100644 --- a/.bcr/source.template.json +++ b/.bcr/source.template.json @@ -1,5 +1,5 @@ { "integrity": "**leave this alone**", "strip_prefix": "{REPO}-{VERSION}", - "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/{REPO}-{VERSION}.zip" + "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/{REPO}-{VERSION}.tar.gz" } diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..99fc84c066 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Configuration for 'git archive' +# see https://git-scm.com/docs/git-archive/2.40.0#ATTRIBUTES +# Don't include compatibility folder in the distribution artifact, just to reduce size +compatibility/ export-ignore \ No newline at end of file diff --git a/.github/workflows/publish_to_bcr.yaml b/.github/workflows/publish_to_bcr.yaml new file mode 100644 index 0000000000..d20dc19e0b --- /dev/null +++ b/.github/workflows/publish_to_bcr.yaml @@ -0,0 +1,36 @@ +# Publish new releases to Bazel Central Registry. +name: Publish to BCR +on: + # Run the publish workflow after a successful release + # Will be triggered from the release.yaml workflow + workflow_call: + inputs: + tag_name: + required: true + type: string + secrets: + # This token should be owned by https://github.com/protobuf-team-bot + BCR_PUBLISH_TOKEN: + required: true + # In case of problems, let release engineers retry by manually dispatching + # the workflow from the GitHub UI + workflow_dispatch: + inputs: + tag_name: + description: git tag being released + required: true + type: string +jobs: + publish: + uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v1.0.0 + with: + tag_name: ${{ inputs.tag_name }} + # GitHub repository which is a fork of the upstream where the Pull Request will be opened. + registry_fork: protocolbuffers/bazel-central-registry + permissions: + attestations: write + contents: write + id-token: write + secrets: + # Necessary to push to the BCR fork, and to open a pull request against a registry + publish_token: ${{ secrets.BCR_PUBLISH_TOKEN }} diff --git a/.github/workflows/release_bazel_module.yaml b/.github/workflows/release_bazel_module.yaml new file mode 100644 index 0000000000..86e88896be --- /dev/null +++ b/.github/workflows/release_bazel_module.yaml @@ -0,0 +1,33 @@ +# Prepare a release specifically for Bazel users, including a pre-built protoc. +name: Bazel Release +on: + # Can be triggered from the GitHub Actions ui, using the "Run workflow" button on + # https://github.com/protocolbuffers/protobuf/actions/workflows/release_bazel_module.yaml + # TODO: consider automating the trigger from a new release being created + workflow_dispatch: + inputs: + tag_name: + description: git tag that has the protoc release artifact + required: true + type: string +permissions: + id-token: write + attestations: write + contents: write +jobs: + release: + uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v7.2.3 + with: + release_files: protobuf-*.tar.gz + prerelease: false + tag_name: ${{ inputs.tag_name }} + # The release was already created by Google-internal mechanism, + # so there aren't any useful assertions to make here. + bazel_test_command: 'true' + publish: + needs: release + uses: ./.github/workflows/publish_to_bcr.yaml + with: + tag_name: ${{ inputs.tag_name }} + secrets: + BCR_PUBLISH_TOKEN: ${{ secrets.BCR_PUBLISH_TOKEN }} diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh new file mode 100755 index 0000000000..5f2ea54b1b --- /dev/null +++ b/.github/workflows/release_prep.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# NB: this file must be named release_prep.sh because the attestation generation doesn't trust user control. +# see https://github.com/bazel-contrib/.github/blob/v7.2.3/.github/workflows/release_ruleset.yaml#L33-L45 +set -o errexit -o nounset -o pipefail + +# Argument provided by reusable workflow caller, see +# https://github.com/bazel-contrib/.github/blob/v7.2.3/.github/workflows/release_ruleset.yaml#L104 +TAG=$1 +PREFIX="protobuf-${TAG:1}" +ARCHIVE="$PREFIX.tar.gz" +ARCHIVE_TMP=$(mktemp) +INTEGRITY_FILE=${PREFIX}/bazel/private/prebuilt_tool_integrity.bzl + +# NB: configuration for 'git archive' is in /.gitattributes +git archive --format=tar --prefix=${PREFIX}/ ${TAG} > $ARCHIVE_TMP +############ +# Patch up the archive to have integrity hashes for built binaries that we downloaded in the GHA workflow. +# Now that we've run `git archive` we are free to pollute the working directory. + +# Delete the placeholder file +tar --file $ARCHIVE_TMP --delete $INTEGRITY_FILE + +# Use jq to translate GitHub Releases json into a Starlark object +filter_releases=$(cat <<'EOF' +# Read the file assets already present on the release +reduce .assets[] as $a ( + # Start with an empty dictionary, and for each asset, add + {}; . + { + # The format required in starlark, i.e. "release-name": "deadbeef123" + ($a.name): ($a.digest | sub("^sha256:"; "")) + } +) +EOF +) + +mkdir -p ${PREFIX}/bazel/private +cat >${INTEGRITY_FILE} < $ARCHIVE +SHA=$(shasum -a 256 $ARCHIVE | awk '{print $1}') diff --git a/bazel/private/prebuilt_tool_integrity.bzl b/bazel/private/prebuilt_tool_integrity.bzl new file mode 100644 index 0000000000..029aa8a033 --- /dev/null +++ b/bazel/private/prebuilt_tool_integrity.bzl @@ -0,0 +1,20 @@ +"""Release binary integrity hashes. + +This file contents are entirely replaced during release publishing, by .github/workflows/release_prep.sh +so that the integrity of the prebuilt tools is included in the release artifact. + +The checked in content is only here to allow load() statements in the sources to resolve. +""" + +# Create a mapping for every tool name to the hash of /dev/null +NULLSHA = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" +RELEASED_BINARY_INTEGRITY = { + "-".join([ + "protoc", + os, + arch, + ]): NULLSHA + for [os, arch] in { + "linux": ["aarch_64", "x86_64"], + } +}