Skip to content

Commit

Permalink
feat: attest release archives
Browse files Browse the repository at this point in the history
  • Loading branch information
kormide committed Mar 6, 2025
1 parent d816305 commit 65603f5
Showing 1 changed file with 79 additions and 15 deletions.
94 changes: 79 additions & 15 deletions .github/workflows/release_ruleset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,47 @@
# See example usage in https://github.com/bazel-contrib/rules-template/blob/main/.github/workflows/release.yaml
#
# By default this workflows calls `.github/workflows/release_prep.sh` as the command to prepare
# the release. This can be customized with the `release_prep_command` attribute. Release notes are
# expected to be outputted to stdout from the release prep command.
# the release. This can be customized with the `release_prep_command` attribute. See documentation
# for the `release_prep_command` property below for inputs and outputs of the script.
#
# This workflow uses https://github.com/bazel-contrib/setup-bazel to prepare the cache folders.
# Caching may be disabled by setting `mount_bazel_caches` to false.
#
# The workflow requires the following permissions to be set on the invoking job:
#
# permissions:
# contents: write # Needed for uploading release files


on:
# Make this workflow reusable, see
# https://github.blog/2022-02-10-using-reusable-workflows-github-actions
workflow_call:
inputs:
release_files:
required: true
description: |
Newline-delimited globs of paths to assets to upload for release.
See https://github.com/softprops/action-gh-release#inputs
type: string
release_prep_command:
default: .github/workflows/release_prep.sh
description: |
Command to run to prepare the release and generate release notes.
Release notes are expected to be outputted to stdout.
The script will be provided with the following env vars:
ARTIFACTS_DIR: Path to a pre-created directory where all artifacts to be
uploaded to the GitHub release must be placed.
RELEASE_NOTES: Path to a pre-created file where release notes content should
be written.
The following arguments are passed to the script:
<tag_or_ref> The tag supplied as an input to this workflows, or ${{ github.ref_name }}.
The script must output a JSON blob with paths to release archives. The path can
be absolute or relative to the ARTIFACTS_DIR. For example:
{
"release_archives": ["my-ruleset-vX.Y.Z.tar.gz"]
}
type: string
bazel_test_command:
default: "bazel test //..."
Expand Down Expand Up @@ -55,31 +74,76 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ inputs.tag_name }}
path: this

- uses: bazel-contrib/setup-bazel@0.8.0
- uses: bazel-contrib/setup-bazel@0.14.0
with:
module-root: this
disk-cache: ${{ inputs.mount_bazel_caches }}
external-cache: ${{ inputs.mount_bazel_caches }}
repository-cache: ${{ inputs.mount_bazel_caches }}

- name: Test
working-directory: this
run: ${{ inputs.bazel_test_command }} --disk_cache=~/.cache/bazel-disk-cache --repository_cache=~/.cache/bazel-repository-cache

- name: Build release artifacts and prepare release notes
- name: Release preparation
id: release_prep
working-directory: this
run: |
if [ ! -f "${{ inputs.release_prep_command }}" ]; then
echo "ERROR: create a ${{ inputs.release_prep_command }} release prep script or configure a different release prep command with the release_prep_command attribute"
exit 1
fi
${{ inputs.release_prep_command }} ${{ inputs.tag_name || github.ref_name }} > release_notes.txt
export ARTIFACTS_DIR=$(mktemp --directory)
export RELEASE_NOTES=$(mktemp)
OUTPUT=$(${{ inputs.release_prep_command }} ${{ inputs.tag_name || github.ref_name }} | jq --compact-output .)
echo "Release prep output:"
echo "${OUTPUT}"
# Parse the the release archives, making the paths absolute
# Store a comma-delimited list which is the format required by the `subject-path`
# input in actions/attest-build-provenance.
RELEASE_ARCHIVES=$(echo "${OUTPUT}" | jq --raw-output --arg artifactsDir "${ARTIFACTS_DIR}/" '.release_archives[] |= sub("^(?<path>[^/].*)";"\($artifactsDir)\(.path)") | .release_archives[]' | tr '\n' ',' | sed '$s/,$//')
echo "artifacts_dir=$ARTIFACTS_DIR" >> $GITHUB_OUTPUT
echo "release_notes=$RELEASE_NOTES" >> $GITHUB_OUTPUT
echo "release_archives=$RELEASE_ARCHIVES" >> $GITHUB_OUTPUT
# The actions/attest-build-provenance action can only produce a single attestation with multiple
# subjects, rather than an attestation per subject, which we want. Create a single attestation
# with all release archives, then copy the same attestation to multiple files below.
- name: Attest release archive(s) provenance
id: attest_release_archive
uses: actions/attest-build-provenance@v2
with:
subject-path: ${{ steps.release_prep.outputs.release_archives }}

- name: Write release archive(s) attestation into intoto.jsonl
id: write_release_archive_attestation
run: |
ATTESTATIONS_DIR=$(mktemp --directory)
RELEASE_ARCHIVES="${{ steps.release_prep.outputs.release_archives }}"
SPACE_DELIMITED="${RELEASE_ARCHIVES//,/ }"
for ARCHIVE in $SPACE_DELIMITED; do
echo "${ARCHIVE}"
ATTESTATION_FILE="$(basename "${ARCHIVE}").intoto.jsonl"
echo "Writing attestation to ${ATTESTATION_FILE}"
cat ${{ steps.attest_release_archive.outputs.bundle-path }} | jq --compact-output > "${ATTESTATIONS_DIR}/${ATTESTATION_FILE}"
done
echo "release_archive_attestations_dir=${ATTESTATIONS_DIR}" >> $GITHUB_OUTPUT
- name: Release
uses: softprops/action-gh-release@v1
with:
prerelease: ${{ inputs.prerelease }}
# Use GH feature to populate the changelog automatically
generate_release_notes: true
body_path: release_notes.txt
body_path: ${{ steps.release_prep.outputs.release_notes }}
fail_on_unmatched_files: true
files: ${{ inputs.release_files }}
tag_name: ${{ inputs.tag_name }}
files: |
${{ steps.release_prep.outputs.artifacts_dir }}/*
${{ steps.write_release_archive_attestation.outputs.release_archive_attestations_dir }}/*
tag_name: ${{ inputs.tag_name }}

0 comments on commit 65603f5

Please sign in to comment.