From 81a0b9c35c57e6b762a2c089bc369fb787cae5e2 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 24 Nov 2025 13:31:41 -0800 Subject: [PATCH 1/4] workflows: Factor out artifact attestation and upload into a composite action Also, switch the release-sources workflow over to use this new action. As a result of this change, the attestation file for the sources will be renamed from attestation.jsonl to $TAG-sources.jsonl. --- .github/workflows/release-sources.yml | 32 ++----- .../upload-release-artifact/action.yml | 92 +++++++++++++++++++ 2 files changed, 102 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/upload-release-artifact/action.yml diff --git a/.github/workflows/release-sources.yml b/.github/workflows/release-sources.yml index 4c47bd7575d99..41f8cf9a0eca1 100644 --- a/.github/workflows/release-sources.yml +++ b/.github/workflows/release-sources.yml @@ -79,30 +79,18 @@ jobs: run: | pip install --require-hashes -r ./llvm/utils/git/requirements.txt - - name: Check Permissions - if: github.event_name != 'pull_request' - env: - GITHUB_TOKEN: ${{ github.token }} - USER_TOKEN: ${{ secrets.RELEASE_TASKS_USER_TOKEN }} - run: | - ./llvm/utils/release/./github-upload-release.py --token "$GITHUB_TOKEN" --user ${{ github.actor }} --user-token "$USER_TOKEN" check-permissions - name: Create Tarballs run: | ./llvm/utils/release/export.sh ${{ needs.inputs.outputs.export-args }} - - name: Attest Build Provenance - if: github.event_name != 'pull_request' - id: provenance - uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 - with: - subject-path: "*.xz" - - if: github.event_name != 'pull_request' - run: | - mv ${{ steps.provenance.outputs.bundle-path }} . - - name: Create Tarball Artifacts - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 - with: - path: | - *.xz - attestation.jsonl + - name: Store Tarball Names + id: filenames + run: | + echo "filenames=*.xz" >> $GITHUB_OUTPUT + - name: Upload Artifacts + uses: ./.github/workflows/upload-release-artifact + with: + files: ${{ steps.filenames.outputs.filenames }} + attestation-name: ${{ needs.inputs.outputs.ref }}-sources + upload: false diff --git a/.github/workflows/upload-release-artifact/action.yml b/.github/workflows/upload-release-artifact/action.yml new file mode 100644 index 0000000000000..747dae8e65670 --- /dev/null +++ b/.github/workflows/upload-release-artifact/action.yml @@ -0,0 +1,92 @@ +name: Upload Release Artifact +description: >- + Upload release artifact along with an attestation. The action assumes that + the llvm-project repository has already been checked out. +inputs: + files: + description: >- + Files to be uploaded. This can contain bash wildcards. + required: true + release-version: + description: >- + The release where the artifact will be attached. + required: true + upload: + description: >- + Whether or not to upload the file and attestation to the release. If this + is set to false, then the atteastion will still be generated and attached as + an artifact to the workflow, but won't be uploaded to the release. + default: true + user-token: + description: >- + Token with premissions to read llvm teams that is used to ensure that + the person who triggred the action has permission to upload artifacts. + This is required if upload is true. + requred: false + attestation-name: + description: >- + This will be used for the artifact name that is attached to the workflow and + will be used as the basename for the attestation file which will be called + $attestation-name.jsonl. If this is not set, it will default + to the falue of `files`. + required: false + + +runs: + using: "composite" + steps: + - name: Collect Variables + id: vars + shell: bash + env: + INPUTS_ATTESTATION_NAME: ${{ inputs.attestation-name }} + INPUTS_FILES: ${{ inputs.files }} + run: | + if [ -z "$INPUTS_ATTESTATION_NAME" ]; then + name="$INPUTS_FILES" + else + name="$INPUTS_ATTESTATION_NAME" + fi + echo "attestation-name=$name" >> $GITHUB_OUTPUT + - name: Attest Build Provenance + id: provenance + uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 + with: + subject-path: ${{ inputs.files }} + + - name: Rename attestation file + shell: bash + run: | + mv ${{ steps.provenance.outputs.bundle-path }} ${{ steps.vars.outputs.attestation-name }}.jsonl + + - name: Upload Build Provenance + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: ${{ steps.vars.outputs.attestation-name }} + path: | + ${{ inputs.files }} + ${{ steps.vars.outputs.attestation-name }}.jsonl + + - name: Install Python Requirements + if: inputs.upload == 'true' + shell: bash + run: | + pip install --require-hashes -r ./llvm/utils/git/requirements.txt + + - name: Check Permissions + if: inputs.upload == 'true' + env: + GITHUB_TOKEN: ${{ github.token }} + USER_TOKEN: ${{ inputs.user-token }} + shell: bash + run: | + ./llvm/utils/release/./github-upload-release.py --token "$GITHUB_TOKEN" --user "$GITHUB_ACTOR" --user-token "$USER_TOKEN" check-permissions + - name: Upload Release + shell: bash + if: inputs.upload == 'true' + run: | + ./llvm/utils/release/github-upload-release.py \ + --token ${{ github.token }} \ + --release ${{ inputs.release-version }} \ + upload \ + --files ${{ inputs.files }} ${{ steps.vars.outputs.attestation-name}}.jsonl From 7530ab52b776683817afed4a6f7cbf821ec59fa1 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 1 Dec 2025 15:09:45 -0800 Subject: [PATCH 2/4] Disable attestion creation when uploads are disabled --- .github/workflows/upload-release-artifact/action.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/upload-release-artifact/action.yml b/.github/workflows/upload-release-artifact/action.yml index 747dae8e65670..ac014a35b2613 100644 --- a/.github/workflows/upload-release-artifact/action.yml +++ b/.github/workflows/upload-release-artifact/action.yml @@ -14,8 +14,9 @@ inputs: upload: description: >- Whether or not to upload the file and attestation to the release. If this - is set to false, then the atteastion will still be generated and attached as - an artifact to the workflow, but won't be uploaded to the release. + is set to false, then the file will be uploaded to the job as an artifact, + but no atteastion will be generated and the artifact won't be uploaded + to the release. default: true user-token: description: >- @@ -31,7 +32,6 @@ inputs: to the falue of `files`. required: false - runs: using: "composite" steps: @@ -49,12 +49,14 @@ runs: fi echo "attestation-name=$name" >> $GITHUB_OUTPUT - name: Attest Build Provenance + if: inputs.upload == 'true' id: provenance uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 with: subject-path: ${{ inputs.files }} - name: Rename attestation file + if: inputs.upload == 'true' shell: bash run: | mv ${{ steps.provenance.outputs.bundle-path }} ${{ steps.vars.outputs.attestation-name }}.jsonl @@ -65,7 +67,7 @@ runs: name: ${{ steps.vars.outputs.attestation-name }} path: | ${{ inputs.files }} - ${{ steps.vars.outputs.attestation-name }}.jsonl + ${{(inputs.upload == 'true' && format('{}.jsonl', steps.vars.outputs.attestation-name)) || '' }} - name: Install Python Requirements if: inputs.upload == 'true' From e6e54df13366f80abefa72bd2c05ad3b43a816d5 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Mon, 1 Dec 2025 15:09:45 -0800 Subject: [PATCH 3/4] Disable attestion creation when uploads are disabled --- .github/workflows/upload-release-artifact/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upload-release-artifact/action.yml b/.github/workflows/upload-release-artifact/action.yml index ac014a35b2613..af79fda02c009 100644 --- a/.github/workflows/upload-release-artifact/action.yml +++ b/.github/workflows/upload-release-artifact/action.yml @@ -67,7 +67,7 @@ runs: name: ${{ steps.vars.outputs.attestation-name }} path: | ${{ inputs.files }} - ${{(inputs.upload == 'true' && format('{}.jsonl', steps.vars.outputs.attestation-name)) || '' }} + ${{(inputs.upload == 'true' && format('{0}.jsonl', steps.vars.outputs.attestation-name)) || '' }} - name: Install Python Requirements if: inputs.upload == 'true' From 5f858fd9700c4838e0e270cd146975d077a23b55 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Tue, 2 Dec 2025 16:21:46 -0800 Subject: [PATCH 4/4] Move upload artifact out of composite action --- .github/workflows/release-sources.yml | 45 ++++++++++++--- .../upload-release-artifact/action.yml | 55 +++++++++++-------- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/.github/workflows/release-sources.yml b/.github/workflows/release-sources.yml index 41f8cf9a0eca1..3a23d105e2411 100644 --- a/.github/workflows/release-sources.yml +++ b/.github/workflows/release-sources.yml @@ -64,11 +64,11 @@ jobs: name: Package Release Sources if: github.repository_owner == 'llvm' runs-on: ubuntu-24.04 + outputs: + digest: ${{ steps.digest.outputs.digest }} + artifact-id: ${{ steps.artifact-upload.outputs.artifact-id }} needs: - inputs - permissions: - id-token: write - attestations: write steps: - name: Checkout LLVM uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 @@ -83,14 +83,43 @@ jobs: run: | ./llvm/utils/release/export.sh ${{ needs.inputs.outputs.export-args }} - - name: Store Tarball Names - id: filenames + - name: Generate sha256 digest for sources + id: digest run: | - echo "filenames=*.xz" >> $GITHUB_OUTPUT + echo "digest=$(cat *.xz | sha256sum | cut -d ' ' -f 1)" >> $GITHUB_OUTPUT + + - name: Release Sources Artifact + id: artifact-upload + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: ${{ needs.inputs.outputs.ref }}-sources + path: | + *.xz + + attest-release-sources: + name: Attest Release Sources + runs-on: ubuntu-24.04 + if: github.event_name != 'pull_request' + needs: + - inputs + - release-sources + permissions: + id-token: write + attestations: write + steps: + - name: Checkout Release Scripts + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + with: + sparse-checkout: | + .github/workflows/upload-release-artifact + llvm/utils/release/github-upload-release.py + llvm/utils/git/requirements.txt + sparse-checkout-cone-mode: false - name: Upload Artifacts uses: ./.github/workflows/upload-release-artifact with: - files: ${{ steps.filenames.outputs.filenames }} - attestation-name: ${{ needs.inputs.outputs.ref }}-sources + artifact-id: ${{ needs.release-sources.outputs.artifact-id }} + attestation-name: ${{ needs.inputs.outputs.ref }}-sources-attestation + digest: ${{ needs.release-sources.outputs.digest }} upload: false diff --git a/.github/workflows/upload-release-artifact/action.yml b/.github/workflows/upload-release-artifact/action.yml index af79fda02c009..b2adb31f269c1 100644 --- a/.github/workflows/upload-release-artifact/action.yml +++ b/.github/workflows/upload-release-artifact/action.yml @@ -3,10 +3,6 @@ description: >- Upload release artifact along with an attestation. The action assumes that the llvm-project repository has already been checked out. inputs: - files: - description: >- - Files to be uploaded. This can contain bash wildcards. - required: true release-version: description: >- The release where the artifact will be attached. @@ -31,43 +27,58 @@ inputs: $attestation-name.jsonl. If this is not set, it will default to the falue of `files`. required: false + artifact-id: + description: >- + Artifact id of the artifact with the files to upload. + required: true + digest: + description: >- + sha256 digest to verify the authenticity of the files being uploaded. + required: true runs: using: "composite" steps: - - name: Collect Variables - id: vars + - name: Download Artifact + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + id: download-artifact + with: + artifact-ids: ${{ inputs.artifact-id }} + path: downloads + + # In theory github artifacts are immutable so we could just rely on using + # the artifact-id to download it, but just to be extra safe we want to + # generated a digest for the files we are uploading so we can verify it + # when downloading. + # See also: https://irsl.medium.com/github-artifact-immutability-is-a-lie-9b6244095694 + - name: Verify Files shell: bash env: - INPUTS_ATTESTATION_NAME: ${{ inputs.attestation-name }} - INPUTS_FILES: ${{ inputs.files }} + INPUTS_DIGEST: ${{ inputs.digest }} run: | - if [ -z "$INPUTS_ATTESTATION_NAME" ]; then - name="$INPUTS_FILES" - else - name="$INPUTS_ATTESTATION_NAME" - fi - echo "attestation-name=$name" >> $GITHUB_OUTPUT + digest_file="sha256" + echo "$INPUTS_DIGEST -" > $digest_file + cat ${{ steps.download-artifact.outputs.download-path }}/* | sha256sum -c $digest_file + - name: Attest Build Provenance - if: inputs.upload == 'true' id: provenance uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 with: - subject-path: ${{ inputs.files }} + subject-path: ${{ steps.download-artifact.outputs.download-path }}/* - name: Rename attestation file - if: inputs.upload == 'true' shell: bash + env: + INPUTS_ATTESTATION_NAME: ${{ inputs.attestation-name }} run: | - mv ${{ steps.provenance.outputs.bundle-path }} ${{ steps.vars.outputs.attestation-name }}.jsonl + mv ${{ steps.provenance.outputs.bundle-path }} "$INPUTS_ATTESTATION_NAME".jsonl - name: Upload Build Provenance uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: - name: ${{ steps.vars.outputs.attestation-name }} + name: ${{ inputs.attestation-name }} path: | - ${{ inputs.files }} - ${{(inputs.upload == 'true' && format('{0}.jsonl', steps.vars.outputs.attestation-name)) || '' }} + ${{ inputs.attestation-name }}.jsonl - name: Install Python Requirements if: inputs.upload == 'true' @@ -91,4 +102,4 @@ runs: --token ${{ github.token }} \ --release ${{ inputs.release-version }} \ upload \ - --files ${{ inputs.files }} ${{ steps.vars.outputs.attestation-name}}.jsonl + --files ${{ steps.download-artifact.outputs.download-path }}/* ${{ steps.vars.outputs.attestation-name}}.jsonl