From 7a52620161b5de376befdafee7af2fe9cc37b591 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 16:44:59 +0100 Subject: [PATCH 01/36] Add dummy EasyConfig --- .../test_software_layer_scripts_commit.yml | 87 +++++++++++++++++++ bot/commit_sha | 1 + .../eessi-2025.06-eb-5.1.2-001-system.yml | 1 + 3 files changed, 89 insertions(+) create mode 100644 .github/workflows/test_software_layer_scripts_commit.yml create mode 100644 bot/commit_sha diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml new file mode 100644 index 0000000000..f957cdbb02 --- /dev/null +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -0,0 +1,87 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +# This workflow verifies that the software-layer-scripts commit used in bot/commit_sha is +# a merge-commit for a merge into the default branch of software-layer-scripts. +# This guarantees that everything that is associated with that commit was approved by a reviewer +# (and deployed, if needed) +name: Verify software-layer-scripts commit +on: + push: + branches: [ "main" ] + pull_request: + workflow_dispatch: +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + check_software_layer_scripts_commit: + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 # We only need the current revision to read bot/commit_sha + - name: Checkout software-layer-scripts (full history) + uses: actions/checkout@v4 + with: + repository: EESSI/software-layer-scripts + path: upstream-scripts + fetch-depth: 0 # full history → required for ancestry checks + + - name: Read commit SHA + id: read_sha + run: | + SHA=$(cat bot/commit_sha | tr -d '[:space:]') + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Found SHA: $SHA" + + - name: Verify SHA exists in software‑layer‑scripts + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then + echo "Commit $SHA not found in software‑layer‑scripts." + exit 1 + fi + echo "Commit $SHA exists in software‑layer‑scripts." + + - name: Check that SHA is merged into the default branch + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + # Make sure we have the latest refs for the default branch + git remote set-head origin -a + git fetch origin main --depth=0 + + # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main + if git merge-base --is-ancestor "$SHA" origin/main; then + echo "Commit $SHA is merged into origin/main." + else + echo "Commit $SHA is NOT merged into origin/main." + exit 1 + fi + + - name: Verify commit is signed by GitHub’s web‑flow key + working-directory: upstream-scripts + env: + GIT_TRACE: 1 # extra debug output if something goes wrong + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + # Import the public key that GitHub uses for UI‑generated merges + echo "Importing GitHub web‑flow GPG key…" + curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg + gpg --import web-flow.gpg + # (optional) show the fingerprint for debugging + echo "Fingerprint of the web-flow GPG key:" + gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + + # Verify the commit’s GPG signature + echo "Verifying the signature of commit $SHA…" + if git verify-commit "$SHA"; then + echo "Commit $SHA is signed and the signature validates with the web‑flow key." + echo "All verification steps succeeded." + else + echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + exit 1 + fi diff --git a/bot/commit_sha b/bot/commit_sha new file mode 100644 index 0000000000..8712e74038 --- /dev/null +++ b/bot/commit_sha @@ -0,0 +1 @@ +f5c45bf7810eb83d2f13e7d94260772cbe5b484d diff --git a/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml b/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml index 7e2449f9c0..0cda8545d2 100644 --- a/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml +++ b/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml @@ -8,3 +8,4 @@ easyconfigs: options: # see https://github.com/easybuilders/easybuild-easyconfigs/pull/24974 from-commit: 775394fc355a53422ef7dfffdc72e88c2de8f703 + - cowsay-3.04.eb From 12c2bc7010ddd72cdf802ae510a960dd9794d60a Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 17:20:13 +0100 Subject: [PATCH 02/36] Update bot/build.sh file to checkout commit_sha from software-layer-scripts --- bot/build.sh | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bot/build.sh b/bot/build.sh index 2884db8de4..dc962d8a9d 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -3,7 +3,19 @@ # give up as soon as any error occurs set -e -git clone https://github.com/EESSI/software-layer-scripts +TOPDIR=$(dirname $(realpath $0)) + +# Clone a the commit from software-layer-script that corresponds to `bot/commit_sha` +commit_sha=$(cat ${TOPDIR}/commit_sha) + +# Get a shallow clone first +git clone --depth 1 --filter=blob:none --no-checkout https://github.com/EESSI/software-layer-scripts + +# Fetch the relevant commit & check it out +cd software-layer-scripts +git fetch --depth=1 origin ${commit_sha} +git checkout --detach ${commit_sha} +cd .. # symlink everything, except for: # - common files like LICENSE and README.md From dd37ed9a1e828dd83cb4eca4203382ff44526ab4 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 17:26:43 +0100 Subject: [PATCH 03/36] Fix indent --- .../test_software_layer_scripts_commit.yml | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml index f957cdbb02..13e1ea5a53 100644 --- a/.github/workflows/test_software_layer_scripts_commit.yml +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -15,73 +15,73 @@ jobs: check_software_layer_scripts_commit: runs-on: ubuntu-24.04 steps: - - name: Check out software-layer repository (shallow) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 1 # We only need the current revision to read bot/commit_sha - - name: Checkout software-layer-scripts (full history) - uses: actions/checkout@v4 - with: - repository: EESSI/software-layer-scripts - path: upstream-scripts - fetch-depth: 0 # full history → required for ancestry checks + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 # We only need the current revision to read bot/commit_sha + - name: Checkout software-layer-scripts (full history) + uses: actions/checkout@v4 + with: + repository: EESSI/software-layer-scripts + path: upstream-scripts + fetch-depth: 0 # full history → required for ancestry checks - - name: Read commit SHA - id: read_sha - run: | - SHA=$(cat bot/commit_sha | tr -d '[:space:]') - echo "sha=$SHA" >> $GITHUB_OUTPUT - echo "Found SHA: $SHA" + - name: Read commit SHA + id: read_sha + run: | + SHA=$(cat bot/commit_sha | tr -d '[:space:]') + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Found SHA: $SHA" - - name: Verify SHA exists in software‑layer‑scripts - working-directory: upstream-scripts - run: | - SHA="${{ steps.read_sha.outputs.sha }}" - - if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then - echo "Commit $SHA not found in software‑layer‑scripts." - exit 1 - fi - echo "Commit $SHA exists in software‑layer‑scripts." + - name: Verify SHA exists in software‑layer‑scripts + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" - - name: Check that SHA is merged into the default branch - working-directory: upstream-scripts - run: | - SHA="${{ steps.read_sha.outputs.sha }}" - - # Make sure we have the latest refs for the default branch - git remote set-head origin -a - git fetch origin main --depth=0 - - # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main - if git merge-base --is-ancestor "$SHA" origin/main; then - echo "Commit $SHA is merged into origin/main." - else - echo "Commit $SHA is NOT merged into origin/main." - exit 1 - fi + if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then + echo "Commit $SHA not found in software‑layer‑scripts." + exit 1 + fi + echo "Commit $SHA exists in software‑layer‑scripts." - - name: Verify commit is signed by GitHub’s web‑flow key + - name: Check that SHA is merged into the default branch working-directory: upstream-scripts - env: - GIT_TRACE: 1 # extra debug output if something goes wrong run: | SHA="${{ steps.read_sha.outputs.sha }}" - # Import the public key that GitHub uses for UI‑generated merges - echo "Importing GitHub web‑flow GPG key…" - curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg - gpg --import web-flow.gpg - # (optional) show the fingerprint for debugging - echo "Fingerprint of the web-flow GPG key:" - gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + # Make sure we have the latest refs for the default branch + git remote set-head origin -a + git fetch origin main --depth=0 - # Verify the commit’s GPG signature - echo "Verifying the signature of commit $SHA…" - if git verify-commit "$SHA"; then - echo "Commit $SHA is signed and the signature validates with the web‑flow key." - echo "All verification steps succeeded." + # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main + if git merge-base --is-ancestor "$SHA" origin/main; then + echo "Commit $SHA is merged into origin/main." else - echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + echo "Commit $SHA is NOT merged into origin/main." exit 1 fi + + - name: Verify commit is signed by GitHub’s web‑flow key + working-directory: upstream-scripts + env: + GIT_TRACE: 1 # extra debug output if something goes wrong + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + # Import the public key that GitHub uses for UI‑generated merges + echo "Importing GitHub web‑flow GPG key…" + curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg + gpg --import web-flow.gpg + # (optional) show the fingerprint for debugging + echo "Fingerprint of the web-flow GPG key:" + gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + + # Verify the commit’s GPG signature + echo "Verifying the signature of commit $SHA…" + if git verify-commit "$SHA"; then + echo "Commit $SHA is signed and the signature validates with the web‑flow key." + echo "All verification steps succeeded." + else + echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + exit 1 + fi From 219bef94d327248fa2414a1ce2e944ec44dfde43 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 17:33:33 +0100 Subject: [PATCH 04/36] Fix indent again --- .../test_software_layer_scripts_commit.yml | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml index 13e1ea5a53..edffee9e71 100644 --- a/.github/workflows/test_software_layer_scripts_commit.yml +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -15,73 +15,73 @@ jobs: check_software_layer_scripts_commit: runs-on: ubuntu-24.04 steps: - - name: Check out software-layer repository (shallow) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 1 # We only need the current revision to read bot/commit_sha - - name: Checkout software-layer-scripts (full history) - uses: actions/checkout@v4 - with: - repository: EESSI/software-layer-scripts - path: upstream-scripts - fetch-depth: 0 # full history → required for ancestry checks + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 # We only need the current revision to read bot/commit_sha + - name: Checkout software-layer-scripts (full history) + uses: actions/checkout@v4 + with: + repository: EESSI/software-layer-scripts + path: upstream-scripts + fetch-depth: 0 # full history → required for ancestry checks - - name: Read commit SHA - id: read_sha - run: | - SHA=$(cat bot/commit_sha | tr -d '[:space:]') - echo "sha=$SHA" >> $GITHUB_OUTPUT - echo "Found SHA: $SHA" + - name: Read commit SHA + id: read_sha + run: | + SHA=$(cat bot/commit_sha | tr -d '[:space:]') + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Found SHA: $SHA" - - name: Verify SHA exists in software‑layer‑scripts - working-directory: upstream-scripts - run: | - SHA="${{ steps.read_sha.outputs.sha }}" + - name: Verify SHA exists in software‑layer‑scripts + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" - if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then - echo "Commit $SHA not found in software‑layer‑scripts." - exit 1 - fi - echo "Commit $SHA exists in software‑layer‑scripts." + if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then + echo "Commit $SHA not found in software‑layer‑scripts." + exit 1 + fi + echo "Commit $SHA exists in software‑layer‑scripts." - - name: Check that SHA is merged into the default branch - working-directory: upstream-scripts - run: | - SHA="${{ steps.read_sha.outputs.sha }}" + - name: Check that SHA is merged into the default branch + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" - # Make sure we have the latest refs for the default branch - git remote set-head origin -a - git fetch origin main --depth=0 + # Make sure we have the latest refs for the default branch + git remote set-head origin -a + git fetch origin main --depth=0 - # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main - if git merge-base --is-ancestor "$SHA" origin/main; then - echo "Commit $SHA is merged into origin/main." - else - echo "Commit $SHA is NOT merged into origin/main." - exit 1 - fi + # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main + if git merge-base --is-ancestor "$SHA" origin/main; then + echo "Commit $SHA is merged into origin/main." + else + echo "Commit $SHA is NOT merged into origin/main." + exit 1 + fi - - name: Verify commit is signed by GitHub’s web‑flow key - working-directory: upstream-scripts - env: - GIT_TRACE: 1 # extra debug output if something goes wrong - run: | - SHA="${{ steps.read_sha.outputs.sha }}" + - name: Verify commit is signed by GitHub’s web‑flow key + working-directory: upstream-scripts + env: + GIT_TRACE: 1 # extra debug output if something goes wrong + run: | + SHA="${{ steps.read_sha.outputs.sha }}" - # Import the public key that GitHub uses for UI‑generated merges - echo "Importing GitHub web‑flow GPG key…" - curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg - gpg --import web-flow.gpg - # (optional) show the fingerprint for debugging - echo "Fingerprint of the web-flow GPG key:" - gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + # Import the public key that GitHub uses for UI‑generated merges + echo "Importing GitHub web‑flow GPG key…" + curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg + gpg --import web-flow.gpg + # (optional) show the fingerprint for debugging + echo "Fingerprint of the web-flow GPG key:" + gpg --list-keys --fingerprint | grep -i "web-flow" -A1 - # Verify the commit’s GPG signature - echo "Verifying the signature of commit $SHA…" - if git verify-commit "$SHA"; then - echo "Commit $SHA is signed and the signature validates with the web‑flow key." - echo "All verification steps succeeded." - else - echo "Commit $SHA is either unsigned or not signed by the web‑flow key." - exit 1 - fi + # Verify the commit’s GPG signature + echo "Verifying the signature of commit $SHA…" + if git verify-commit "$SHA"; then + echo "Commit $SHA is signed and the signature validates with the web‑flow key." + echo "All verification steps succeeded." + else + echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + exit 1 + fi From 218e75fd3b8993257df6e0ffcc2deb584d9011d8 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 17:44:00 +0100 Subject: [PATCH 05/36] Get rid of two unnecessary, and wrong commands --- .github/workflows/test_software_layer_scripts_commit.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml index edffee9e71..510d1aa098 100644 --- a/.github/workflows/test_software_layer_scripts_commit.yml +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -49,10 +49,6 @@ jobs: run: | SHA="${{ steps.read_sha.outputs.sha }}" - # Make sure we have the latest refs for the default branch - git remote set-head origin -a - git fetch origin main --depth=0 - # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main if git merge-base --is-ancestor "$SHA" origin/main; then echo "Commit $SHA is merged into origin/main." From b8355bb69615a25864cff9b3e1a286b945f10001 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 17:49:36 +0100 Subject: [PATCH 06/36] Check that changing the commit_sha to an _unmerged_ commit creates a failure --- bot/commit_sha | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commit_sha b/bot/commit_sha index 8712e74038..764609c31f 100644 --- a/bot/commit_sha +++ b/bot/commit_sha @@ -1 +1 @@ -f5c45bf7810eb83d2f13e7d94260772cbe5b484d +c0a3ff09a3a38737af5a922fdf581aa7b2dd6c88 From f9d1b7d1fc718c846a4f61455f0e738b002cddba Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 18:40:36 +0100 Subject: [PATCH 07/36] Checkout the required github --- .github/workflows/test_software_layer_scripts_commit.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml index 510d1aa098..c47f2ef0a0 100644 --- a/.github/workflows/test_software_layer_scripts_commit.yml +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -38,6 +38,10 @@ jobs: run: | SHA="${{ steps.read_sha.outputs.sha }}" + echo "Checking out commit ${SHA} from software-layer-scripts" + git fetch --depth=1 origin ${SHA} + git checkout --detach ${SHA} + if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then echo "Commit $SHA not found in software‑layer‑scripts." exit 1 From 2cd6082e626c2ee6f4f4b3c51da0bc0e252b6e95 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 13 Jan 2026 18:41:04 +0100 Subject: [PATCH 08/36] Add comment --- .github/workflows/test_software_layer_scripts_commit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts_commit.yml index c47f2ef0a0..b2130c95a5 100644 --- a/.github/workflows/test_software_layer_scripts_commit.yml +++ b/.github/workflows/test_software_layer_scripts_commit.yml @@ -42,6 +42,7 @@ jobs: git fetch --depth=1 origin ${SHA} git checkout --detach ${SHA} + # Validate that this object is _actually_ a commit if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then echo "Commit $SHA not found in software‑layer‑scripts." exit 1 From 6d954c43e664f07d91488c77b1c381b81abde20a Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Wed, 14 Jan 2026 16:26:58 +0100 Subject: [PATCH 09/36] Replace commit_sha by an actual signed merge commit to prove that the CI then passes --- bot/commit_sha | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commit_sha b/bot/commit_sha index 764609c31f..8712e74038 100644 --- a/bot/commit_sha +++ b/bot/commit_sha @@ -1 +1 @@ -c0a3ff09a3a38737af5a922fdf581aa7b2dd6c88 +f5c45bf7810eb83d2f13e7d94260772cbe5b484d From 36f7541a75cdbadcfafeed433f7ef6aadf0359bc Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:09:44 +0100 Subject: [PATCH 10/36] Test that the bot/build.sh script is unchanged --- .../workflows/test_unchanged_bot_build.yml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/test_unchanged_bot_build.yml diff --git a/.github/workflows/test_unchanged_bot_build.yml b/.github/workflows/test_unchanged_bot_build.yml new file mode 100644 index 0000000000..4594e3e8fe --- /dev/null +++ b/.github/workflows/test_unchanged_bot_build.yml @@ -0,0 +1,46 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +# This workflow verifies that bot/build.sh was unchanged, as a change could mean a security risk +# (e.g. if a PR clones an fork of software-layer-scripts instead, anything could happen) +# If the bot/build.sh _actually_ needs updating, then the reference checksum for that file needs to +# be updated as well - and that stands out to a reviewer, making it harder to do without a reviewer +# noticiing. +name: Verify bot/build.sh was unchanged +on: + push: + branches: [ "main" ] + pull_request: + workflow_dispatch: +permissions: + contents: read # to fetch code (actions/checkout) +env: + # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh + EXPECTED_CHECKSUM: "9d33368cac2e38e10147eeb0aafc321651ebaa5912387ecef97683570906773a" +jobs: + check_software_layer_scripts_commit: + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 # We only need the current revision to read bot/commit_sha + + - name: Compute bot/build.sh checksum and verify it + run: | + # Print clear error if file doesn't exist at all + if [[ ! -f bot/build.sh ]]; then + echo "ERROR: File bot/build.sh not found!" + exit 1 + fi + + # Compute checksum + COMPUTED_CHECKSUM=$(sha256sum bot/build.sh | awk '{print $1}') + echo "Computed checksum: $COMPUTED_CHECKSUM" + echo "Reference checksum: $EXPECTED_CHECKSUM" + + # Compare checksums + if [["$COMPUTED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]]; then + echo "ERROR: Checksum mismatch! The file bot/build.sh has been modified." + exit 1 + else + echo "Checksum for bot/build.sh matches the reference value" + fi From f1fdcca4f48676bc7dff844811403d8ac5a4c090 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:12:19 +0100 Subject: [PATCH 11/36] Try to see if CI now fails, as intended --- bot/build.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bot/build.sh b/bot/build.sh index dc962d8a9d..e315998806 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -31,3 +31,5 @@ done # call out to bot/build.sh script from software-layer-scripts software-layer-scripts/bot/build.sh + +# INSERT BOGUS COMMENT From c4b1f9aea1ff9b8aa3c1ef97d79280860b2867d5 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:15:36 +0100 Subject: [PATCH 12/36] Correct missing space in bash logic - see if the workflow now fails (it should) --- .github/workflows/test_unchanged_bot_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_unchanged_bot_build.yml b/.github/workflows/test_unchanged_bot_build.yml index 4594e3e8fe..5905b7ee8f 100644 --- a/.github/workflows/test_unchanged_bot_build.yml +++ b/.github/workflows/test_unchanged_bot_build.yml @@ -38,7 +38,7 @@ jobs: echo "Reference checksum: $EXPECTED_CHECKSUM" # Compare checksums - if [["$COMPUTED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]]; then + if [[ "$COMPUTED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]]; then echo "ERROR: Checksum mismatch! The file bot/build.sh has been modified." exit 1 else From 0494884e3a333db43941d97ec1f3ab95391d78eb Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:17:18 +0100 Subject: [PATCH 13/36] Undo dummy change to see if CI passes again --- bot/build.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/bot/build.sh b/bot/build.sh index e315998806..dc962d8a9d 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -31,5 +31,3 @@ done # call out to bot/build.sh script from software-layer-scripts software-layer-scripts/bot/build.sh - -# INSERT BOGUS COMMENT From 1530fca86ed0b612f05dcb0c9f3ce02b9965c299 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:22:04 +0100 Subject: [PATCH 14/36] Rename the CI --- .github/workflows/test_unchanged_bot_build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_unchanged_bot_build.yml b/.github/workflows/test_unchanged_bot_build.yml index 5905b7ee8f..171e65f042 100644 --- a/.github/workflows/test_unchanged_bot_build.yml +++ b/.github/workflows/test_unchanged_bot_build.yml @@ -16,7 +16,7 @@ env: # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh EXPECTED_CHECKSUM: "9d33368cac2e38e10147eeb0aafc321651ebaa5912387ecef97683570906773a" jobs: - check_software_layer_scripts_commit: + check_bot_build_checksum: runs-on: ubuntu-24.04 steps: - name: Check out software-layer repository (shallow) From cc187336e70b892f80fe469b3e7c050f2757e497 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:30:05 +0100 Subject: [PATCH 15/36] Merge into a single workflow file --- ...it.yml => test_software_layer_scripts.yml} | 0 .../workflows/test_unchanged_bot_build.yml | 46 ------------------- 2 files changed, 46 deletions(-) rename .github/workflows/{test_software_layer_scripts_commit.yml => test_software_layer_scripts.yml} (100%) delete mode 100644 .github/workflows/test_unchanged_bot_build.yml diff --git a/.github/workflows/test_software_layer_scripts_commit.yml b/.github/workflows/test_software_layer_scripts.yml similarity index 100% rename from .github/workflows/test_software_layer_scripts_commit.yml rename to .github/workflows/test_software_layer_scripts.yml diff --git a/.github/workflows/test_unchanged_bot_build.yml b/.github/workflows/test_unchanged_bot_build.yml deleted file mode 100644 index 171e65f042..0000000000 --- a/.github/workflows/test_unchanged_bot_build.yml +++ /dev/null @@ -1,46 +0,0 @@ -# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions -# This workflow verifies that bot/build.sh was unchanged, as a change could mean a security risk -# (e.g. if a PR clones an fork of software-layer-scripts instead, anything could happen) -# If the bot/build.sh _actually_ needs updating, then the reference checksum for that file needs to -# be updated as well - and that stands out to a reviewer, making it harder to do without a reviewer -# noticiing. -name: Verify bot/build.sh was unchanged -on: - push: - branches: [ "main" ] - pull_request: - workflow_dispatch: -permissions: - contents: read # to fetch code (actions/checkout) -env: - # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh - EXPECTED_CHECKSUM: "9d33368cac2e38e10147eeb0aafc321651ebaa5912387ecef97683570906773a" -jobs: - check_bot_build_checksum: - runs-on: ubuntu-24.04 - steps: - - name: Check out software-layer repository (shallow) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 1 # We only need the current revision to read bot/commit_sha - - - name: Compute bot/build.sh checksum and verify it - run: | - # Print clear error if file doesn't exist at all - if [[ ! -f bot/build.sh ]]; then - echo "ERROR: File bot/build.sh not found!" - exit 1 - fi - - # Compute checksum - COMPUTED_CHECKSUM=$(sha256sum bot/build.sh | awk '{print $1}') - echo "Computed checksum: $COMPUTED_CHECKSUM" - echo "Reference checksum: $EXPECTED_CHECKSUM" - - # Compare checksums - if [[ "$COMPUTED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]]; then - echo "ERROR: Checksum mismatch! The file bot/build.sh has been modified." - exit 1 - else - echo "Checksum for bot/build.sh matches the reference value" - fi From 77167ac9121dc04281d0fda77d96ae437d31d11a Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:44:09 +0100 Subject: [PATCH 16/36] See if the bot/build.sh checksum test runs this way... --- .../workflows/test_software_layer_scripts.yml | 167 +++++++++++------- 1 file changed, 103 insertions(+), 64 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index b2130c95a5..829f250f7e 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -1,9 +1,16 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions -# This workflow verifies that the software-layer-scripts commit used in bot/commit_sha is -# a merge-commit for a merge into the default branch of software-layer-scripts. -# This guarantees that everything that is associated with that commit was approved by a reviewer -# (and deployed, if needed) -name: Verify software-layer-scripts commit +# +# This workflow verifies that the correct version of software-layer-scripts is used. +# +# First, check_bot_build_checksums checks if the bot/build.sh code that clones software-layer-scripts is untouched, +# as this normally shouldn't change (a change could mean a contributor is trying to inject something +# malicious). Having this CI means that a change in bot/build.sh should at least be accompanied by +# a change in this CI, making it stand out to reviewers and increasing the likelihood of this being caught. +# +# Second, check-software_layer_scripts_commit checks if the commit used in bot/commit_sha is a merge-commit for a +# merge into the default branch of software-layer-scripts. This guarantees that everything that is associated with +# that commit was approved by a reviewer (and deployed, if needed) +name: Verify software-layer-scripts on: push: branches: [ "main" ] @@ -12,77 +19,109 @@ on: permissions: contents: read # to fetch code (actions/checkout) jobs: - check_software_layer_scripts_commit: + check_bot_build_checksum: runs-on: ubuntu-24.04 steps: - name: Check out software-layer repository (shallow) uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 1 # We only need the current revision to read bot/commit_sha - - name: Checkout software-layer-scripts (full history) - uses: actions/checkout@v4 - with: - repository: EESSI/software-layer-scripts - path: upstream-scripts - fetch-depth: 0 # full history → required for ancestry checks - - - name: Read commit SHA - id: read_sha - run: | - SHA=$(cat bot/commit_sha | tr -d '[:space:]') - echo "sha=$SHA" >> $GITHUB_OUTPUT - echo "Found SHA: $SHA" - - - name: Verify SHA exists in software‑layer‑scripts - working-directory: upstream-scripts - run: | - SHA="${{ steps.read_sha.outputs.sha }}" - - echo "Checking out commit ${SHA} from software-layer-scripts" - git fetch --depth=1 origin ${SHA} - git checkout --detach ${SHA} - - # Validate that this object is _actually_ a commit - if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then - echo "Commit $SHA not found in software‑layer‑scripts." - exit 1 - fi - echo "Commit $SHA exists in software‑layer‑scripts." - - name: Check that SHA is merged into the default branch - working-directory: upstream-scripts + - name: Compute bot/build.sh checksum and verify it run: | - SHA="${{ steps.read_sha.outputs.sha }}" - - # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main - if git merge-base --is-ancestor "$SHA" origin/main; then - echo "Commit $SHA is merged into origin/main." - else - echo "Commit $SHA is NOT merged into origin/main." + # Print clear error if file doesn't exist at all + if [[ ! -f bot/build.sh ]]; then + echo "ERROR: File bot/build.sh not found!" exit 1 fi - - name: Verify commit is signed by GitHub’s web‑flow key - working-directory: upstream-scripts - env: - GIT_TRACE: 1 # extra debug output if something goes wrong - run: | - SHA="${{ steps.read_sha.outputs.sha }}" + # Reference checksum + # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh + EXPECTED_CHECKSUM="9d33368cac2e38e10147eeb0aafc321651ebaa5912387ecef97683570906773a" - # Import the public key that GitHub uses for UI‑generated merges - echo "Importing GitHub web‑flow GPG key…" - curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg - gpg --import web-flow.gpg - # (optional) show the fingerprint for debugging - echo "Fingerprint of the web-flow GPG key:" - gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + # Compute checksum + COMPUTED_CHECKSUM=$(sha256sum bot/build.sh | awk '{print $1}') + echo "Computed checksum: $COMPUTED_CHECKSUM" + echo "Reference checksum: $EXPECTED_CHECKSUM" - # Verify the commit’s GPG signature - echo "Verifying the signature of commit $SHA…" - if git verify-commit "$SHA"; then - echo "Commit $SHA is signed and the signature validates with the web‑flow key." - echo "All verification steps succeeded." - else - echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + # Compare checksums + if [[ "$COMPUTED_CHECKSUM" != "$EXPECTED_CHECKSUM" ]]; then + echo "ERROR: Checksum mismatch! The file bot/build.sh has been modified." exit 1 + else + echo "Checksum for bot/build.sh matches the reference value" fi +# check_software_layer_scripts_commit: +# runs-on: ubuntu-24.04 +# steps: +# - name: Check out software-layer repository (shallow) +# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 +# with: +# fetch-depth: 1 # We only need the current revision to read bot/commit_sha +# - name: Checkout software-layer-scripts (full history) +# uses: actions/checkout@v4 +# with: +# repository: EESSI/software-layer-scripts +# path: upstream-scripts +# fetch-depth: 0 # full history → required for ancestry checks +# +# - name: Read commit SHA +# id: read_sha +# run: | +# SHA=$(cat bot/commit_sha | tr -d '[:space:]') +# echo "sha=$SHA" >> $GITHUB_OUTPUT +# echo "Found SHA: $SHA" +# +# - name: Verify SHA exists in software‑layer‑scripts +# working-directory: upstream-scripts +# run: | +# SHA="${{ steps.read_sha.outputs.sha }}" +# +# echo "Checking out commit ${SHA} from software-layer-scripts" +# git fetch --depth=1 origin ${SHA} +# git checkout --detach ${SHA} +# +# # Validate that this object is _actually_ a commit +# if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then +# echo "Commit $SHA not found in software‑layer‑scripts." +# exit 1 +# fi +# echo "Commit $SHA exists in software‑layer‑scripts." +# +# - name: Check that SHA is merged into the default branch +# working-directory: upstream-scripts +# run: | +# SHA="${{ steps.read_sha.outputs.sha }}" +# +# # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main +# if git merge-base --is-ancestor "$SHA" origin/main; then +# echo "Commit $SHA is merged into origin/main." +# else +# echo "Commit $SHA is NOT merged into origin/main." +# exit 1 +# fi +# +# - name: Verify commit is signed by GitHub’s web‑flow key +# working-directory: upstream-scripts +# env: +# GIT_TRACE: 1 # extra debug output if something goes wrong +# run: | +# SHA="${{ steps.read_sha.outputs.sha }}" +# +# # Import the public key that GitHub uses for UI‑generated merges +# echo "Importing GitHub web‑flow GPG key…" +# curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg +# gpg --import web-flow.gpg +# # (optional) show the fingerprint for debugging +# echo "Fingerprint of the web-flow GPG key:" +# gpg --list-keys --fingerprint | grep -i "web-flow" -A1 +# +# # Verify the commit’s GPG signature +# echo "Verifying the signature of commit $SHA…" +# if git verify-commit "$SHA"; then +# echo "Commit $SHA is signed and the signature validates with the web‑flow key." +# echo "All verification steps succeeded." +# else +# echo "Commit $SHA is either unsigned or not signed by the web‑flow key." +# exit 1 +# fi From bce9bbc441c22aaf3eefaf4996df8285d649cb0b Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:45:02 +0100 Subject: [PATCH 17/36] See if the bot/build.sh checksum test still runs after uncommenting --- .../workflows/test_software_layer_scripts.yml | 148 +++++++++--------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index 829f250f7e..6d62a892fe 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -51,77 +51,77 @@ jobs: else echo "Checksum for bot/build.sh matches the reference value" fi -# check_software_layer_scripts_commit: -# runs-on: ubuntu-24.04 -# steps: -# - name: Check out software-layer repository (shallow) -# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 -# with: -# fetch-depth: 1 # We only need the current revision to read bot/commit_sha -# - name: Checkout software-layer-scripts (full history) -# uses: actions/checkout@v4 -# with: -# repository: EESSI/software-layer-scripts -# path: upstream-scripts -# fetch-depth: 0 # full history → required for ancestry checks -# -# - name: Read commit SHA -# id: read_sha -# run: | -# SHA=$(cat bot/commit_sha | tr -d '[:space:]') -# echo "sha=$SHA" >> $GITHUB_OUTPUT -# echo "Found SHA: $SHA" -# -# - name: Verify SHA exists in software‑layer‑scripts -# working-directory: upstream-scripts -# run: | -# SHA="${{ steps.read_sha.outputs.sha }}" -# -# echo "Checking out commit ${SHA} from software-layer-scripts" -# git fetch --depth=1 origin ${SHA} -# git checkout --detach ${SHA} -# -# # Validate that this object is _actually_ a commit -# if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then -# echo "Commit $SHA not found in software‑layer‑scripts." -# exit 1 -# fi -# echo "Commit $SHA exists in software‑layer‑scripts." -# -# - name: Check that SHA is merged into the default branch -# working-directory: upstream-scripts -# run: | -# SHA="${{ steps.read_sha.outputs.sha }}" -# -# # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main -# if git merge-base --is-ancestor "$SHA" origin/main; then -# echo "Commit $SHA is merged into origin/main." -# else -# echo "Commit $SHA is NOT merged into origin/main." -# exit 1 -# fi -# -# - name: Verify commit is signed by GitHub’s web‑flow key -# working-directory: upstream-scripts -# env: -# GIT_TRACE: 1 # extra debug output if something goes wrong -# run: | -# SHA="${{ steps.read_sha.outputs.sha }}" -# -# # Import the public key that GitHub uses for UI‑generated merges -# echo "Importing GitHub web‑flow GPG key…" -# curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg -# gpg --import web-flow.gpg -# # (optional) show the fingerprint for debugging -# echo "Fingerprint of the web-flow GPG key:" -# gpg --list-keys --fingerprint | grep -i "web-flow" -A1 -# -# # Verify the commit’s GPG signature -# echo "Verifying the signature of commit $SHA…" -# if git verify-commit "$SHA"; then -# echo "Commit $SHA is signed and the signature validates with the web‑flow key." -# echo "All verification steps succeeded." -# else -# echo "Commit $SHA is either unsigned or not signed by the web‑flow key." -# exit 1 -# fi + check_software_layer_scripts_commit: + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 # We only need the current revision to read bot/commit_sha + - name: Checkout software-layer-scripts (full history) + uses: actions/checkout@v4 + with: + repository: EESSI/software-layer-scripts + path: upstream-scripts + fetch-depth: 0 # full history → required for ancestry checks + + - name: Read commit SHA + id: read_sha + run: | + SHA=$(cat bot/commit_sha | tr -d '[:space:]') + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Found SHA: $SHA" + + - name: Verify SHA exists in software‑layer‑scripts + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + echo "Checking out commit ${SHA} from software-layer-scripts" + git fetch --depth=1 origin ${SHA} + git checkout --detach ${SHA} + + # Validate that this object is _actually_ a commit + if ! git cat-file -e "${SHA}^{commit}" 2>/dev/null; then + echo "Commit $SHA not found in software‑layer‑scripts." + exit 1 + fi + echo "Commit $SHA exists in software‑layer‑scripts." + + - name: Check that SHA is merged into the default branch + working-directory: upstream-scripts + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + # git merge‑base --is‑ancestor returns 0 if $SHA is an ancestor of origin/main + if git merge-base --is-ancestor "$SHA" origin/main; then + echo "Commit $SHA is merged into origin/main." + else + echo "Commit $SHA is NOT merged into origin/main." + exit 1 + fi + + - name: Verify commit is signed by GitHub’s web‑flow key + working-directory: upstream-scripts + env: + GIT_TRACE: 1 # extra debug output if something goes wrong + run: | + SHA="${{ steps.read_sha.outputs.sha }}" + + # Import the public key that GitHub uses for UI‑generated merges + echo "Importing GitHub web‑flow GPG key…" + curl -sSfL https://github.com/web-flow.gpg | gpg --dearmor > web-flow.gpg + gpg --import web-flow.gpg + # (optional) show the fingerprint for debugging + echo "Fingerprint of the web-flow GPG key:" + gpg --list-keys --fingerprint | grep -i "web-flow" -A1 + + # Verify the commit’s GPG signature + echo "Verifying the signature of commit $SHA…" + if git verify-commit "$SHA"; then + echo "Commit $SHA is signed and the signature validates with the web‑flow key." + echo "All verification steps succeeded." + else + echo "Commit $SHA is either unsigned or not signed by the web‑flow key." + exit 1 + fi From bee1d296ce80f8ba3a8ae3e94cc304cac09f2879 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:49:08 +0100 Subject: [PATCH 18/36] Change sha checksum to see if this causes CI to fail (as expected) --- bot/commit_sha | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/commit_sha b/bot/commit_sha index 8712e74038..764609c31f 100644 --- a/bot/commit_sha +++ b/bot/commit_sha @@ -1 +1 @@ -f5c45bf7810eb83d2f13e7d94260772cbe5b484d +c0a3ff09a3a38737af5a922fdf581aa7b2dd6c88 From 2c752d213596987ff56cb2e49834bf63e935c758 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:52:25 +0100 Subject: [PATCH 19/36] Change SHA to an actual merge commit and change bot/build.sh to see if this causes the associated CI job to fail --- bot/build.sh | 2 ++ bot/commit_sha | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bot/build.sh b/bot/build.sh index dc962d8a9d..1c49c31726 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -31,3 +31,5 @@ done # call out to bot/build.sh script from software-layer-scripts software-layer-scripts/bot/build.sh + +# BOGUS COMMENT TO TEST CI diff --git a/bot/commit_sha b/bot/commit_sha index 764609c31f..8712e74038 100644 --- a/bot/commit_sha +++ b/bot/commit_sha @@ -1 +1 @@ -c0a3ff09a3a38737af5a922fdf581aa7b2dd6c88 +f5c45bf7810eb83d2f13e7d94260772cbe5b484d From 6d2714e3230fd31e08e13eb8b601d96734029d9b Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 19 Jan 2026 15:54:25 +0100 Subject: [PATCH 20/36] Change bot/build.sh back to the intended content so that all CI should pass again --- bot/build.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/bot/build.sh b/bot/build.sh index 1c49c31726..dc962d8a9d 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -31,5 +31,3 @@ done # call out to bot/build.sh script from software-layer-scripts software-layer-scripts/bot/build.sh - -# BOGUS COMMENT TO TEST CI From 47c4771b8fd50f6282c8a4df6febb840e0f61480 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 4 Aug 2026 18:10:35 +0200 Subject: [PATCH 21/36] Change commit_sha filename, and correspondingly change the checksum for the bot/build.sh that gets checked in CI --- .github/workflows/test_software_layer_scripts.yml | 2 +- bot/build.sh | 4 ++-- bot/{commit_sha => software_layer_scripts_commit} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename bot/{commit_sha => software_layer_scripts_commit} (100%) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index 6d62a892fe..cb82b17612 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -37,7 +37,7 @@ jobs: # Reference checksum # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh - EXPECTED_CHECKSUM="9d33368cac2e38e10147eeb0aafc321651ebaa5912387ecef97683570906773a" + EXPECTED_CHECKSUM="94df53fe4af9c4f28f5c3dc16bf1377e2ba5c7c0df65699d50984b538a1eeab1" # Compute checksum COMPUTED_CHECKSUM=$(sha256sum bot/build.sh | awk '{print $1}') diff --git a/bot/build.sh b/bot/build.sh index dc962d8a9d..01f3be57af 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -5,8 +5,8 @@ set -e TOPDIR=$(dirname $(realpath $0)) -# Clone a the commit from software-layer-script that corresponds to `bot/commit_sha` -commit_sha=$(cat ${TOPDIR}/commit_sha) +# Clone a the commit from software-layer-script that corresponds to `bot/software_layer_scripts_commit` +commit_sha=$(cat ${TOPDIR}/software_layer_scripts_commit) # Get a shallow clone first git clone --depth 1 --filter=blob:none --no-checkout https://github.com/EESSI/software-layer-scripts diff --git a/bot/commit_sha b/bot/software_layer_scripts_commit similarity index 100% rename from bot/commit_sha rename to bot/software_layer_scripts_commit From 482a907b7a9c874fba293c883da5fdeb38971371 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 4 Aug 2026 18:12:32 +0200 Subject: [PATCH 22/36] Process review comments from Kenneth --- .github/workflows/test_software_layer_scripts.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index cb82b17612..940c7b520c 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -59,10 +59,10 @@ jobs: with: fetch-depth: 1 # We only need the current revision to read bot/commit_sha - name: Checkout software-layer-scripts (full history) - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: repository: EESSI/software-layer-scripts - path: upstream-scripts + path: EESSI-software-layer-scripts fetch-depth: 0 # full history → required for ancestry checks - name: Read commit SHA @@ -73,7 +73,7 @@ jobs: echo "Found SHA: $SHA" - name: Verify SHA exists in software‑layer‑scripts - working-directory: upstream-scripts + working-directory: EESSI-software-layer-scripts run: | SHA="${{ steps.read_sha.outputs.sha }}" @@ -89,7 +89,7 @@ jobs: echo "Commit $SHA exists in software‑layer‑scripts." - name: Check that SHA is merged into the default branch - working-directory: upstream-scripts + working-directory: EESSI-software-layer-scripts run: | SHA="${{ steps.read_sha.outputs.sha }}" @@ -102,7 +102,7 @@ jobs: fi - name: Verify commit is signed by GitHub’s web‑flow key - working-directory: upstream-scripts + working-directory: EESSI-software-layer-scripts env: GIT_TRACE: 1 # extra debug output if something goes wrong run: | From ca5e9a2a4a38282c2bc09078c029761cf91e316e Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 4 Aug 2026 18:21:38 +0200 Subject: [PATCH 23/36] Use the current tip of main --- bot/software_layer_scripts_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/software_layer_scripts_commit b/bot/software_layer_scripts_commit index 8712e74038..c3c5d1c249 100644 --- a/bot/software_layer_scripts_commit +++ b/bot/software_layer_scripts_commit @@ -1 +1 @@ -f5c45bf7810eb83d2f13e7d94260772cbe5b484d +62b8e332fb041a9ba598dbed3ed781a3416407c0 From 46df2eff4b6d8515cdc39477903d2336029945ac Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Tue, 4 Aug 2026 18:21:55 +0200 Subject: [PATCH 24/36] Fix filename that contians the software layer scripts commit sha --- .github/workflows/test_software_layer_scripts.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index 940c7b520c..c422bfc0da 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -7,7 +7,7 @@ # malicious). Having this CI means that a change in bot/build.sh should at least be accompanied by # a change in this CI, making it stand out to reviewers and increasing the likelihood of this being caught. # -# Second, check-software_layer_scripts_commit checks if the commit used in bot/commit_sha is a merge-commit for a +# Second, check-software_layer_scripts_commit checks if the commit used in bot/software_layer_scripts_commit is a merge-commit for a # merge into the default branch of software-layer-scripts. This guarantees that everything that is associated with # that commit was approved by a reviewer (and deployed, if needed) name: Verify software-layer-scripts @@ -25,7 +25,7 @@ jobs: - name: Check out software-layer repository (shallow) uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - fetch-depth: 1 # We only need the current revision to read bot/commit_sha + fetch-depth: 1 # We only need the current revision to read bot/software_layer_scripts_commit - name: Compute bot/build.sh checksum and verify it run: | @@ -57,7 +57,7 @@ jobs: - name: Check out software-layer repository (shallow) uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: - fetch-depth: 1 # We only need the current revision to read bot/commit_sha + fetch-depth: 1 # We only need the current revision to read bot/software_layer_scripts_commit - name: Checkout software-layer-scripts (full history) uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: @@ -68,7 +68,7 @@ jobs: - name: Read commit SHA id: read_sha run: | - SHA=$(cat bot/commit_sha | tr -d '[:space:]') + SHA=$(cat bot/software_layer_scripts_commit | tr -d '[:space:]') echo "sha=$SHA" >> $GITHUB_OUTPUT echo "Found SHA: $SHA" From 94ae63e480c3aa2510bd1744079568d7be9cd590 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Wed, 5 Aug 2026 16:55:39 +0200 Subject: [PATCH 25/36] Add github action to check the bot/software_layer_scripts_commit sha against the latest commit on EESSI/software-layer-scripts's main branch, to see if it points to the latest commit --- .../check_software_layer_scripts_commit.yml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/check_software_layer_scripts_commit.yml diff --git a/.github/workflows/check_software_layer_scripts_commit.yml b/.github/workflows/check_software_layer_scripts_commit.yml new file mode 100644 index 0000000000..46fa3a25f2 --- /dev/null +++ b/.github/workflows/check_software_layer_scripts_commit.yml @@ -0,0 +1,61 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +# +# This workflow checks if the commit SHA in bot/software_layer_scripts_commit +# matches the latest commit on the main branch of EESSI/software-layer-scripts. +# It only runs when the 'bot:deploy' label is present on the PR. The reason is that +# before deployment, we typically want to keep using a fixed version of EESSI/software-layer-scripts +# so that we don't (unintentionally) change build behavior half-way through a PR. +# However, after deploy, we want the `bot/software_layer_script_commit to be updated +# so that on software-layer/main this always refers to as recent a commit SHA +# from EESSI/software-layer-scripts as possible +name: Check software-layer-scripts commit is up to date +on: + pull_request: + types: [opened, synchronize, reopened, labeled] +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + check_latest_commit: + if: > + ( + contains(github.event.pull_request.labels.*.name, 'bot:deploy') + || contains(github.event.pull_request.labels.*.name, 'force-ci-checks') + ) + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 + + - name: Read commit SHA from bot/software_layer_scripts_commit + id: read_sha + run: | + if [[ ! -f bot/software_layer_scripts_commit ]]; then + echo "ERROR: bot/software_layer_scripts_commit not found!" + exit 1 + fi + SHA=$(cat bot/software_layer_scripts_commit | tr -d '[:space:]') + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Found SHA: $SHA" + + - name: Get latest commit on main of EESSI/software-layer-scripts + id: latest_sha + env: + GH_TOKEN: ${{ github.token }} + run: | + SHA=$(gh api repos/EESSI/software-layer-scripts/commits/main --jq .sha) + echo "sha=$SHA" >> $GITHUB_OUTPUT + echo "Latest commit on main: $SHA" + + - name: Compare SHAs + run: | + if [[ "${{ steps.read_sha.outputs.sha }}" == "${{ steps.latest_sha.outputs.sha }}" ]]; then + echo "OK: bot/software_layer_scripts_commit matches the latest commit on main." + else + echo "ERROR: bot/software_layer_scripts_commit does not match the latest commit on main of EESSI/software-layer-scripts." + echo "Stored commit: ${{ steps.read_sha.outputs.sha }}" + echo "Latest commit: ${{ steps.latest_sha.outputs.sha }}" + echo "Please update bot/software_layer_scripts_commit to ${{ steps.latest_sha.outputs.sha }} and push the change." + exit 1 + fi From 6f2f4325ec7fdd357e769bb97bfc95ea3947d77a Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Wed, 5 Aug 2026 17:08:55 +0200 Subject: [PATCH 26/36] Change to an older merge commit to test if CI then fails --- bot/software_layer_scripts_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/software_layer_scripts_commit b/bot/software_layer_scripts_commit index c3c5d1c249..4e265aba0e 100644 --- a/bot/software_layer_scripts_commit +++ b/bot/software_layer_scripts_commit @@ -1 +1 @@ -62b8e332fb041a9ba598dbed3ed781a3416407c0 +83169938a52e22849226308cf3010e496f267430 From 690e4448fc9ffae83b9620a48a3449bb8ea543dc Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Wed, 5 Aug 2026 17:12:30 +0200 Subject: [PATCH 27/36] Try an unmerged commit --- bot/software_layer_scripts_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/software_layer_scripts_commit b/bot/software_layer_scripts_commit index 4e265aba0e..f81bd2b100 100644 --- a/bot/software_layer_scripts_commit +++ b/bot/software_layer_scripts_commit @@ -1 +1 @@ -83169938a52e22849226308cf3010e496f267430 +89e670f2336a610827ef899ecad520af78b0a848 From d1f62e71b7ef58ce3a909bcb07ac1ba2a21af179 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Thu, 6 Aug 2026 00:58:43 +0200 Subject: [PATCH 28/36] Add CI check that checks if all tarballs are available, i.e. for all supported CPU targets for that EESSI version. If there is a checksum, it'll verify that all checksums are the same for all tarballs --- .github/workflows/check_build_status.yml | 32 ++++ .github/workflows/scripts/check_builds.py | 220 ++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 .github/workflows/check_build_status.yml create mode 100644 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/check_build_status.yml b/.github/workflows/check_build_status.yml new file mode 100644 index 0000000000..65c13440bc --- /dev/null +++ b/.github/workflows/check_build_status.yml @@ -0,0 +1,32 @@ +# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions +# +# This workflow checks the bot's status table (posted in PR comments) to verify +# that all supported CPU targets have been successfully built before deployment. +name: Check bot build status +on: + issue_comment: + types: [created, edited] +permissions: + contents: read # to fetch code (actions/checkout) +jobs: + check_builds: + if: > + github.event.issue.pull_request && + contains(github.event.comment.body, 'This is the status of all the `bot: build` commands:') + runs-on: ubuntu-24.04 + steps: + - name: Check out software-layer repository (shallow) + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 1 + - name: Check bot build status + # We pass the comment body via env variable instead of a command-line argument + # because the body contains special characters (pipes |, backticks, newlines, etc.) + # that would need complex quoting/escaping in bash. Passing via env is safer + # and preserves the content exactly as-is. The Python script reads both + # PR_NUMBER and COMMENT_BODY from the environment. + env: + PR_NUMBER: ${{ github.event.issue.number }} + COMMENT_BODY: ${{ github.event.comment.body }} + run: | + python3 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/scripts/check_builds.py b/.github/workflows/scripts/check_builds.py new file mode 100644 index 0000000000..3a73505702 --- /dev/null +++ b/.github/workflows/scripts/check_builds.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 +# Check that all supported CPU targets have been successfully built, based on +# the bot's status table in the PR comment. +# +# Usage: check_builds.py +# Reads PR_NUMBER and COMMENT_BODY from environment variables. +# No API calls required — the triggering comment body is already available. +# +# Exit codes: +# 0: Success (all supported targets have successful builds, or mapping is empty) +# 1: Failure (missing/failed builds, or commit SHA inconsistency) + +import datetime +import os +import sys +import re + + +# ============================================================================ +# TODO: FILL IN THE SUPPORTED CPU TARGETS PER REPO +# ============================================================================ +# This mapping defines which CPU targets (values of the 'for' column) must be +# successfully built for each repository (value of the 'repo' column). +# The values below are a placeholder — please fill in the actual supported +# targets for your repositories. +# +# Example structure: +# SUPPORTED_TARGETS = { +# "eessi.io-2025.06-software": [ +# "x86_64/amd/zen2", +# "x86_64/amd/zen3", +# "x86_64/amd/zen4", +# "x86_64/intel/haswell", +# # ... add all supported targets for this repo ... +# ], +# "eessi.io-2023.06-software": [ +# # ... supported targets for 2023.06 ... +# ], +# } +# ============================================================================ +SUPPORTED_TARGETS = { + # Placeholder — fill in your supported targets here + # "eessi.io-2025.06-software": ["x86_64/amd/zen2"], +} + + +def parse_date(date_str): + """ + Parse a date string like 'Aug 04 18:11:14 UTC 2026' into a datetime object. + Returns None if parsing fails. + """ + try: + return datetime.datetime.strptime(date_str, "%b %d %X %Z %Y") + except ValueError: + return None + + +def parse_markdown_table(body): + """ + Parse the bot's status table from the comment body. + Returns a list of dicts, one per row, with column names as keys. + Uses header-driven parsing (column names from the header row) so it + tolerates extra/missing columns like 'commit SHA'. + """ + marker = "This is the status of all the `bot: build` commands:" + if marker not in body: + return None + + # Find the table: start from the marker line, look for header row + lines = body.splitlines() + header_idx = None + for i, line in enumerate(lines): + if line.startswith("|on|"): + header_idx = i + break + + if header_idx is None: + return None + + # Parse header row + header_line = lines[header_idx] + # Split by | and strip whitespace, remove empty first/last from leading/trailing | + columns = [c.strip() for c in header_line.strip("|").split("|")] + + # Find separator row (line of dashes) + separator_idx = header_idx + 1 + while separator_idx < len(lines) and not lines[separator_idx].startswith("|"): + separator_idx += 1 + if separator_idx >= len(lines): + return None + + # Parse data rows + rows = [] + for line in lines[separator_idx + 1:]: + if not line.startswith("|"): + continue + cells = [c.strip() for c in line.strip("|").split("|")] + if len(cells) != len(columns): + continue + row = dict(zip(columns, cells)) + # Strip backticks from 'on' and 'for' values + for key in ["on", "for"]: + if key in row: + row[key] = row[key].strip("`") + rows.append(row) + + return rows + + +def dedup_by_for_repo(rows): + """ + Deduplicate rows by (for, repo) pair, keeping only the last build + (by date) for each pair. + Returns a dict: (for, repo) -> row + """ + latest = {} + for row in rows: + key = (row.get("for"), row.get("repo")) + if key == (None, None) or key[0] is None: + continue + date_str = row.get("date", "") + date = parse_date(date_str) + if date is None: + # Treat as oldest if date can't be parsed + date = datetime.datetime.min + if key not in latest or date > latest[key][0]: + latest[key] = (date, row) + return {k: v[1] for k, v in latest.items()} + + +def main(): + pr_number = os.environ.get("PR_NUMBER") + comment_body = os.environ.get("COMMENT_BODY") + + if not pr_number or not comment_body: + print("ERROR: PR_NUMBER and COMMENT_BODY must be set in environment") + sys.exit(1) + + # Parse the table + rows = parse_markdown_table(comment_body) + if rows is None: + print("ERROR: Could not find status table in comment") + sys.exit(1) + + if not rows: + print("ERROR: Status table is empty") + sys.exit(1) + + # Deduplicate by (for, repo) + deduped = dedup_by_for_repo(rows) + if not deduped: + print("ERROR: No valid builds found in table") + sys.exit(1) + + # Determine which repos are present in both table and mapping + table_repos = set(row.get("repo") for row in deduped.values() if row.get("repo")) + mapping_repos = set(SUPPORTED_TARGETS.keys()) + repos_to_check = table_repos & mapping_repos + + # Warn if repos in table are missing from mapping + for repo in table_repos - mapping_repos: + print(f"WARNING: Repo '{repo}' found in table but not in SUPPORTED_TARGETS mapping; skipping checks for this repo") + + # Check commit SHA consistency across all deduplicated builds (if column present) + commit_shas = set() + for row in deduped.values(): + sha = row.get("commit SHA") + if sha: + commit_shas.add(sha) + + if len(commit_shas) > 1: + print("ERROR: Commit SHA inconsistency detected across builds") + for sha in commit_shas: + matching_rows = [r for r in deduped.values() if r.get("commit SHA") == sha] + targets = [r.get("for") for r in matching_rows] + print(f" SHA {sha}: targets {targets}") + print("All builds must reference the same commit SHA.") + sys.exit(1) + + # Verify each supported target for each repo + failed = False + for repo in repos_to_check: + supported = SUPPORTED_TARGETS[repo] + print(f"\nChecking repo: {repo}") + builds_for_repo = {k: v for k, v in deduped.items() if v.get("repo") == repo} + + for target in supported: + key = (target, repo) + row = deduped.get(key) + if row is None: + print(f" FAIL: Target '{target}' not found in builds for {repo}") + failed = True + continue + + status = row.get("status", "").strip() + result = row.get("result", "") + if status != "finished" or "SUCCESS" not in result: + print(f" FAIL: Target '{target}' is not SUCCESS/finished") + print(f" status={status}, result={result}") + if row.get("url"): + print(f" URL: {row['url']}") + failed = True + else: + print(f" OK: Target '{target}' built successfully") + + # Check if mapping is empty + if not mapping_repos: + print("\nWARNING: SUPPORTED_TARGETS mapping is empty — no checks performed.") + print("Please populate SUPPORTED_TARGETS in check_builds.py with your supported targets.") + + if failed: + print("\nERROR: Build verification failed. Please fix the above issues.") + sys.exit(1) + + print("\nSUCCESS: All supported targets have been successfully built.") + sys.exit(0) + + +if __name__ == "__main__": + main() From 3b7008f45e042ac0f8468c2addb37da3c354f8ff Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 10 Aug 2026 17:49:52 +0200 Subject: [PATCH 29/36] Remove functionality to check 'bot:build last_status' output, we'll implement this in a seperate PR https://github.com/EESSI/software-layer/pull/1564 --- .github/workflows/check_build_status.yml | 32 ---- .github/workflows/scripts/check_builds.py | 220 ---------------------- 2 files changed, 252 deletions(-) delete mode 100644 .github/workflows/check_build_status.yml delete mode 100644 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/check_build_status.yml b/.github/workflows/check_build_status.yml deleted file mode 100644 index 65c13440bc..0000000000 --- a/.github/workflows/check_build_status.yml +++ /dev/null @@ -1,32 +0,0 @@ -# documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions -# -# This workflow checks the bot's status table (posted in PR comments) to verify -# that all supported CPU targets have been successfully built before deployment. -name: Check bot build status -on: - issue_comment: - types: [created, edited] -permissions: - contents: read # to fetch code (actions/checkout) -jobs: - check_builds: - if: > - github.event.issue.pull_request && - contains(github.event.comment.body, 'This is the status of all the `bot: build` commands:') - runs-on: ubuntu-24.04 - steps: - - name: Check out software-layer repository (shallow) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - fetch-depth: 1 - - name: Check bot build status - # We pass the comment body via env variable instead of a command-line argument - # because the body contains special characters (pipes |, backticks, newlines, etc.) - # that would need complex quoting/escaping in bash. Passing via env is safer - # and preserves the content exactly as-is. The Python script reads both - # PR_NUMBER and COMMENT_BODY from the environment. - env: - PR_NUMBER: ${{ github.event.issue.number }} - COMMENT_BODY: ${{ github.event.comment.body }} - run: | - python3 .github/workflows/scripts/check_builds.py diff --git a/.github/workflows/scripts/check_builds.py b/.github/workflows/scripts/check_builds.py deleted file mode 100644 index 3a73505702..0000000000 --- a/.github/workflows/scripts/check_builds.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env python3 -# Check that all supported CPU targets have been successfully built, based on -# the bot's status table in the PR comment. -# -# Usage: check_builds.py -# Reads PR_NUMBER and COMMENT_BODY from environment variables. -# No API calls required — the triggering comment body is already available. -# -# Exit codes: -# 0: Success (all supported targets have successful builds, or mapping is empty) -# 1: Failure (missing/failed builds, or commit SHA inconsistency) - -import datetime -import os -import sys -import re - - -# ============================================================================ -# TODO: FILL IN THE SUPPORTED CPU TARGETS PER REPO -# ============================================================================ -# This mapping defines which CPU targets (values of the 'for' column) must be -# successfully built for each repository (value of the 'repo' column). -# The values below are a placeholder — please fill in the actual supported -# targets for your repositories. -# -# Example structure: -# SUPPORTED_TARGETS = { -# "eessi.io-2025.06-software": [ -# "x86_64/amd/zen2", -# "x86_64/amd/zen3", -# "x86_64/amd/zen4", -# "x86_64/intel/haswell", -# # ... add all supported targets for this repo ... -# ], -# "eessi.io-2023.06-software": [ -# # ... supported targets for 2023.06 ... -# ], -# } -# ============================================================================ -SUPPORTED_TARGETS = { - # Placeholder — fill in your supported targets here - # "eessi.io-2025.06-software": ["x86_64/amd/zen2"], -} - - -def parse_date(date_str): - """ - Parse a date string like 'Aug 04 18:11:14 UTC 2026' into a datetime object. - Returns None if parsing fails. - """ - try: - return datetime.datetime.strptime(date_str, "%b %d %X %Z %Y") - except ValueError: - return None - - -def parse_markdown_table(body): - """ - Parse the bot's status table from the comment body. - Returns a list of dicts, one per row, with column names as keys. - Uses header-driven parsing (column names from the header row) so it - tolerates extra/missing columns like 'commit SHA'. - """ - marker = "This is the status of all the `bot: build` commands:" - if marker not in body: - return None - - # Find the table: start from the marker line, look for header row - lines = body.splitlines() - header_idx = None - for i, line in enumerate(lines): - if line.startswith("|on|"): - header_idx = i - break - - if header_idx is None: - return None - - # Parse header row - header_line = lines[header_idx] - # Split by | and strip whitespace, remove empty first/last from leading/trailing | - columns = [c.strip() for c in header_line.strip("|").split("|")] - - # Find separator row (line of dashes) - separator_idx = header_idx + 1 - while separator_idx < len(lines) and not lines[separator_idx].startswith("|"): - separator_idx += 1 - if separator_idx >= len(lines): - return None - - # Parse data rows - rows = [] - for line in lines[separator_idx + 1:]: - if not line.startswith("|"): - continue - cells = [c.strip() for c in line.strip("|").split("|")] - if len(cells) != len(columns): - continue - row = dict(zip(columns, cells)) - # Strip backticks from 'on' and 'for' values - for key in ["on", "for"]: - if key in row: - row[key] = row[key].strip("`") - rows.append(row) - - return rows - - -def dedup_by_for_repo(rows): - """ - Deduplicate rows by (for, repo) pair, keeping only the last build - (by date) for each pair. - Returns a dict: (for, repo) -> row - """ - latest = {} - for row in rows: - key = (row.get("for"), row.get("repo")) - if key == (None, None) or key[0] is None: - continue - date_str = row.get("date", "") - date = parse_date(date_str) - if date is None: - # Treat as oldest if date can't be parsed - date = datetime.datetime.min - if key not in latest or date > latest[key][0]: - latest[key] = (date, row) - return {k: v[1] for k, v in latest.items()} - - -def main(): - pr_number = os.environ.get("PR_NUMBER") - comment_body = os.environ.get("COMMENT_BODY") - - if not pr_number or not comment_body: - print("ERROR: PR_NUMBER and COMMENT_BODY must be set in environment") - sys.exit(1) - - # Parse the table - rows = parse_markdown_table(comment_body) - if rows is None: - print("ERROR: Could not find status table in comment") - sys.exit(1) - - if not rows: - print("ERROR: Status table is empty") - sys.exit(1) - - # Deduplicate by (for, repo) - deduped = dedup_by_for_repo(rows) - if not deduped: - print("ERROR: No valid builds found in table") - sys.exit(1) - - # Determine which repos are present in both table and mapping - table_repos = set(row.get("repo") for row in deduped.values() if row.get("repo")) - mapping_repos = set(SUPPORTED_TARGETS.keys()) - repos_to_check = table_repos & mapping_repos - - # Warn if repos in table are missing from mapping - for repo in table_repos - mapping_repos: - print(f"WARNING: Repo '{repo}' found in table but not in SUPPORTED_TARGETS mapping; skipping checks for this repo") - - # Check commit SHA consistency across all deduplicated builds (if column present) - commit_shas = set() - for row in deduped.values(): - sha = row.get("commit SHA") - if sha: - commit_shas.add(sha) - - if len(commit_shas) > 1: - print("ERROR: Commit SHA inconsistency detected across builds") - for sha in commit_shas: - matching_rows = [r for r in deduped.values() if r.get("commit SHA") == sha] - targets = [r.get("for") for r in matching_rows] - print(f" SHA {sha}: targets {targets}") - print("All builds must reference the same commit SHA.") - sys.exit(1) - - # Verify each supported target for each repo - failed = False - for repo in repos_to_check: - supported = SUPPORTED_TARGETS[repo] - print(f"\nChecking repo: {repo}") - builds_for_repo = {k: v for k, v in deduped.items() if v.get("repo") == repo} - - for target in supported: - key = (target, repo) - row = deduped.get(key) - if row is None: - print(f" FAIL: Target '{target}' not found in builds for {repo}") - failed = True - continue - - status = row.get("status", "").strip() - result = row.get("result", "") - if status != "finished" or "SUCCESS" not in result: - print(f" FAIL: Target '{target}' is not SUCCESS/finished") - print(f" status={status}, result={result}") - if row.get("url"): - print(f" URL: {row['url']}") - failed = True - else: - print(f" OK: Target '{target}' built successfully") - - # Check if mapping is empty - if not mapping_repos: - print("\nWARNING: SUPPORTED_TARGETS mapping is empty — no checks performed.") - print("Please populate SUPPORTED_TARGETS in check_builds.py with your supported targets.") - - if failed: - print("\nERROR: Build verification failed. Please fix the above issues.") - sys.exit(1) - - print("\nSUCCESS: All supported targets have been successfully built.") - sys.exit(0) - - -if __name__ == "__main__": - main() From 981cb97f830ad91af91eea52b8f13ef0401b5038 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 10 Aug 2026 18:03:54 +0200 Subject: [PATCH 30/36] Run CI only if hte bot/software_layer_scripts_commit has been changed. We don't want to bother contributors who don't know about this file that they have to update stuff - for that we will create a seperate GH Action to automtically create PRs that update this. With this CI, we only ensure that contributors that DO change the commit, ensure that we don't merge an older commit into our software-layer/main branch (even if they built from an older one, which is totally fine) --- .github/workflows/check_software_layer_scripts_commit.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/check_software_layer_scripts_commit.yml b/.github/workflows/check_software_layer_scripts_commit.yml index 46fa3a25f2..9e37c759c2 100644 --- a/.github/workflows/check_software_layer_scripts_commit.yml +++ b/.github/workflows/check_software_layer_scripts_commit.yml @@ -12,6 +12,8 @@ name: Check software-layer-scripts commit is up to date on: pull_request: types: [opened, synchronize, reopened, labeled] + paths: + - 'bot/software_layer_scripts_commit' permissions: contents: read # to fetch code (actions/checkout) jobs: From 1041e4232125c0b063ed2afd4584c2ff44ce33f5 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 10 Aug 2026 18:09:02 +0200 Subject: [PATCH 31/36] Made the description of this CI more extensive, so we know why we did things this way --- .../check_software_layer_scripts_commit.yml | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/check_software_layer_scripts_commit.yml b/.github/workflows/check_software_layer_scripts_commit.yml index 9e37c759c2..a345205ce6 100644 --- a/.github/workflows/check_software_layer_scripts_commit.yml +++ b/.github/workflows/check_software_layer_scripts_commit.yml @@ -1,13 +1,20 @@ # documentation: https://help.github.com/en/articles/workflow-syntax-for-github-actions # +# Our goal is to ensure that the bot/software_layer_scripts_commit in software-layer/main always +# points to the latest software-layer-scripts/main. +# # This workflow checks if the commit SHA in bot/software_layer_scripts_commit # matches the latest commit on the main branch of EESSI/software-layer-scripts. -# It only runs when the 'bot:deploy' label is present on the PR. The reason is that -# before deployment, we typically want to keep using a fixed version of EESSI/software-layer-scripts -# so that we don't (unintentionally) change build behavior half-way through a PR. -# However, after deploy, we want the `bot/software_layer_script_commit to be updated -# so that on software-layer/main this always refers to as recent a commit SHA -# from EESSI/software-layer-scripts as possible +# It only runs when the 'bot:deploy' label is present on the PR AND if the bot/software_layer_scripts_commit +# has been changed. This ensures that: +# - Contributors that don't know about bot/software_layer_scripts_commit (i.e.: haven't updated it) don't get +# a CI that complains about the version not being the latest. That's fine, we will update that file in other PRs +# and if users don't change the file in their PR, there's no risk of overwriting with an older version +# - Contributors that have changed bot/software_layer_scripts_commit can build with a fixed version (commit) +# of EESSI/software-layer-scripts, ensuring that builds for all targets are done in a coherent manner. +# After all builds are deployed, the CI is run, checking that this is the latest commit. If not, contributors +# will have to update that before merging. This ensures that mergin their PR does not cause software-layer/main's +# bot/software_layer_scripts_commit to start pointing to an _older_ commit. name: Check software-layer-scripts commit is up to date on: pull_request: From a0a6a061c70334e81a5994e22326305f48499fca Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Mon, 10 Aug 2026 18:10:26 +0200 Subject: [PATCH 32/36] Undo adding cowsay - that was only there to be able to test this PR --- .../2025.06/eessi-2025.06-eb-5.1.2-001-system.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml b/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml index 0cda8545d2..7e2449f9c0 100644 --- a/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml +++ b/easystacks/software.eessi.io/2025.06/eessi-2025.06-eb-5.1.2-001-system.yml @@ -8,4 +8,3 @@ easyconfigs: options: # see https://github.com/easybuilders/easybuild-easyconfigs/pull/24974 from-commit: 775394fc355a53422ef7dfffdc72e88c2de8f703 - - cowsay-3.04.eb From 88611d18ea4cc674cd435a30b3a61a677b8e0129 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen <33718780+casparvl@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:45:24 +0200 Subject: [PATCH 33/36] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bob Dröge --- .github/workflows/check_software_layer_scripts_commit.yml | 2 +- .github/workflows/test_software_layer_scripts.yml | 3 +-- bot/build.sh | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/check_software_layer_scripts_commit.yml b/.github/workflows/check_software_layer_scripts_commit.yml index a345205ce6..367ff718e4 100644 --- a/.github/workflows/check_software_layer_scripts_commit.yml +++ b/.github/workflows/check_software_layer_scripts_commit.yml @@ -13,7 +13,7 @@ # - Contributors that have changed bot/software_layer_scripts_commit can build with a fixed version (commit) # of EESSI/software-layer-scripts, ensuring that builds for all targets are done in a coherent manner. # After all builds are deployed, the CI is run, checking that this is the latest commit. If not, contributors -# will have to update that before merging. This ensures that mergin their PR does not cause software-layer/main's +# will have to update that before merging. This ensures that merging their PR does not cause software-layer/main's # bot/software_layer_scripts_commit to start pointing to an _older_ commit. name: Check software-layer-scripts commit is up to date on: diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index c422bfc0da..dd69df7d3e 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -3,8 +3,7 @@ # This workflow verifies that the correct version of software-layer-scripts is used. # # First, check_bot_build_checksums checks if the bot/build.sh code that clones software-layer-scripts is untouched, -# as this normally shouldn't change (a change could mean a contributor is trying to inject something -# malicious). Having this CI means that a change in bot/build.sh should at least be accompanied by +# as this normally shouldn't change, so let's be really cautious here. Having this CI means that a change in bot/build.sh should at least be accompanied by # a change in this CI, making it stand out to reviewers and increasing the likelihood of this being caught. # # Second, check-software_layer_scripts_commit checks if the commit used in bot/software_layer_scripts_commit is a merge-commit for a diff --git a/bot/build.sh b/bot/build.sh index 01f3be57af..ab16402ced 100755 --- a/bot/build.sh +++ b/bot/build.sh @@ -5,7 +5,7 @@ set -e TOPDIR=$(dirname $(realpath $0)) -# Clone a the commit from software-layer-script that corresponds to `bot/software_layer_scripts_commit` +# Clone the commit from software-layer-scripts that corresponds to `bot/software_layer_scripts_commit` commit_sha=$(cat ${TOPDIR}/software_layer_scripts_commit) # Get a shallow clone first From 0ef5d063df87884173f6438b4a8e546506813113 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen Date: Wed, 12 Aug 2026 22:58:15 +0200 Subject: [PATCH 34/36] Update software_layer_scripts_commit --- bot/software_layer_scripts_commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/software_layer_scripts_commit b/bot/software_layer_scripts_commit index f81bd2b100..32078be5ff 100644 --- a/bot/software_layer_scripts_commit +++ b/bot/software_layer_scripts_commit @@ -1 +1 @@ -89e670f2336a610827ef899ecad520af78b0a848 +fa69734b990cc0db74ac32e037680cb9c154056d From d38aa1e040c278e48cca5200b74c18bbb2b65995 Mon Sep 17 00:00:00 2001 From: Caspar van Leeuwen <33718780+casparvl@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:12:50 +0200 Subject: [PATCH 35/36] Apply suggestion from @casparvl --- .github/workflows/check_software_layer_scripts_commit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_software_layer_scripts_commit.yml b/.github/workflows/check_software_layer_scripts_commit.yml index 367ff718e4..78f0aea11b 100644 --- a/.github/workflows/check_software_layer_scripts_commit.yml +++ b/.github/workflows/check_software_layer_scripts_commit.yml @@ -28,7 +28,7 @@ jobs: if: > ( contains(github.event.pull_request.labels.*.name, 'bot:deploy') - || contains(github.event.pull_request.labels.*.name, 'force-ci-checks') + || contains(github.event.pull_request.labels.*.name, 'force-sw-layer-commit-ci') ) runs-on: ubuntu-24.04 steps: From 19de61caa878173c5ced9fcae534e40f78babcb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bob=20Dr=C3=B6ge?= Date: Thu, 20 Aug 2026 12:45:45 +0200 Subject: [PATCH 36/36] Update expected checksum after comment was changed --- .github/workflows/test_software_layer_scripts.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_software_layer_scripts.yml b/.github/workflows/test_software_layer_scripts.yml index dd69df7d3e..0ce4fa2aac 100644 --- a/.github/workflows/test_software_layer_scripts.yml +++ b/.github/workflows/test_software_layer_scripts.yml @@ -36,7 +36,7 @@ jobs: # Reference checksum # UPDATE THIS CHECKSUM IF AND ONLY IF WE ACTUALLY WANT TO CHANGE bot/build.sh - EXPECTED_CHECKSUM="94df53fe4af9c4f28f5c3dc16bf1377e2ba5c7c0df65699d50984b538a1eeab1" + EXPECTED_CHECKSUM="622e0b4d39543aaf70ee912edd0660c3746d7a1ecb176e0d41df598155e50e21" # Compute checksum COMPUTED_CHECKSUM=$(sha256sum bot/build.sh | awk '{print $1}')