[llvm] workflows: Factor out artifact attestation and upload into a composite action (PR #169621)

Tom Stellard via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 2 20:01:53 PST 2025


https://github.com/tstellar updated https://github.com/llvm/llvm-project/pull/169621

>From 81a0b9c35c57e6b762a2c089bc369fb787cae5e2 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Mon, 24 Nov 2025 13:31:41 -0800
Subject: [PATCH 1/9] 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 at 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 at 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 at 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 at 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 <tstellar at redhat.com>
Date: Mon, 1 Dec 2025 15:09:45 -0800
Subject: [PATCH 2/9] 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 at 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 <tstellar at redhat.com>
Date: Mon, 1 Dec 2025 15:09:45 -0800
Subject: [PATCH 3/9] 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 <tstellar at redhat.com>
Date: Tue, 2 Dec 2025 16:21:46 -0800
Subject: [PATCH 4/9] 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 at 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 at 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 at 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 at 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 at 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 at 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

>From 1582943dcc67ac9b44e41aeeb701e29bd5635816 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Mon, 1 Dec 2025 15:41:44 -0800
Subject: [PATCH 5/9] Debug

---
 .github/workflows/release-sources.yml | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/.github/workflows/release-sources.yml b/.github/workflows/release-sources.yml
index 3a23d105e2411..39c1a8624e2f1 100644
--- a/.github/workflows/release-sources.yml
+++ b/.github/workflows/release-sources.yml
@@ -4,6 +4,7 @@ permissions:
   contents: read
 
 on:
+  push:
   workflow_dispatch:
     inputs:
       release-version:
@@ -42,7 +43,6 @@ jobs:
   inputs:
     name: Collect Job Inputs
     if: >-
-      github.repository_owner == 'llvm' &&
       github.event.action != 'closed'
     outputs:
       ref: ${{ steps.inputs.outputs.ref }}
@@ -62,7 +62,6 @@ jobs:
 
   release-sources:
     name: Package Release Sources
-    if: github.repository_owner == 'llvm'
     runs-on: ubuntu-24.04
     outputs:
       digest: ${{ steps.digest.outputs.digest }}

>From ec63f0548075dc7d689651a1935084c10ace83c4 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Tue, 2 Dec 2025 16:28:12 -0800
Subject: [PATCH 6/9] Debug

---
 llvm/utils/release/export.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/utils/release/export.sh b/llvm/utils/release/export.sh
index 0ac392cbed7be..974343779157c 100755
--- a/llvm/utils/release/export.sh
+++ b/llvm/utils/release/export.sh
@@ -13,7 +13,7 @@
 
 set -e
 
-projects="llvm bolt clang cmake compiler-rt libcxx libcxxabi libclc clang-tools-extra polly lldb lld openmp libunwind mlir flang runtimes third-party"
+projects="llvm bolt"
 
 release=""
 rc=""

>From c25e25f5a53febb6eb98e3bbb2d3bb6ba5f011b2 Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Tue, 2 Dec 2025 16:40:00 -0800
Subject: [PATCH 7/9] debug

---
 llvm/utils/release/export.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/utils/release/export.sh b/llvm/utils/release/export.sh
index 974343779157c..557dde07efcba 100755
--- a/llvm/utils/release/export.sh
+++ b/llvm/utils/release/export.sh
@@ -13,7 +13,7 @@
 
 set -e
 
-projects="llvm bolt"
+projects="cmake bolt"
 
 release=""
 rc=""

>From eeecd335ac2f840c9021f536d80daf083929086a Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Tue, 2 Dec 2025 16:40:51 -0800
Subject: [PATCH 8/9] Debug

---
 llvm/utils/release/export.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/utils/release/export.sh b/llvm/utils/release/export.sh
index 557dde07efcba..6e92ecf7fe097 100755
--- a/llvm/utils/release/export.sh
+++ b/llvm/utils/release/export.sh
@@ -112,7 +112,7 @@ export_sources() {
     echo "$rc" > $target_dir/llvm-rc-$yyyymmdd.txt
     echo "$git_rev" > $target_dir/llvm-git-revision-$yyyymmdd.txt
     
-    git archive --prefix=llvm-project-$release$rc.src/ $tree_id . | xz -T0 >$target_dir/$(template_file llvm-project)
+    #git archive --prefix=llvm-project-$release$rc.src/ $tree_id . | xz -T0 >$target_dir/$(template_file llvm-project)
     popd
 
     if [ -z "$snapshot" ]; then

>From 4296eb18e92eae9fef169754ddc7ff426a37860a Mon Sep 17 00:00:00 2001
From: Tom Stellard <tstellar at redhat.com>
Date: Tue, 2 Dec 2025 17:00:09 -0800
Subject: [PATCH 9/9] Undo debug

---
 llvm/utils/release/export.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/utils/release/export.sh b/llvm/utils/release/export.sh
index 6e92ecf7fe097..0ac392cbed7be 100755
--- a/llvm/utils/release/export.sh
+++ b/llvm/utils/release/export.sh
@@ -13,7 +13,7 @@
 
 set -e
 
-projects="cmake bolt"
+projects="llvm bolt clang cmake compiler-rt libcxx libcxxabi libclc clang-tools-extra polly lldb lld openmp libunwind mlir flang runtimes third-party"
 
 release=""
 rc=""
@@ -112,7 +112,7 @@ export_sources() {
     echo "$rc" > $target_dir/llvm-rc-$yyyymmdd.txt
     echo "$git_rev" > $target_dir/llvm-git-revision-$yyyymmdd.txt
     
-    #git archive --prefix=llvm-project-$release$rc.src/ $tree_id . | xz -T0 >$target_dir/$(template_file llvm-project)
+    git archive --prefix=llvm-project-$release$rc.src/ $tree_id . | xz -T0 >$target_dir/$(template_file llvm-project)
     popd
 
     if [ -z "$snapshot" ]; then



More information about the llvm-commits mailing list