From 7f60f9f46ebd8ba361625df973699c25d25bcf7e Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 1 Jul 2026 15:06:28 +0200 Subject: [PATCH 1/3] chore: Bump stackabletech/actions to v0.16.0 --- .github/workflows/mirror.yaml | 8 ++++---- .github/workflows/pr_pre-commit.yaml | 2 +- .github/workflows/reusable_build_image.yaml | 16 ++++++++-------- .github/workflows/ubi-rust-builder.yml | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/mirror.yaml b/.github/workflows/mirror.yaml index 77ef064e9..3a15bc401 100644 --- a/.github/workflows/mirror.yaml +++ b/.github/workflows/mirror.yaml @@ -73,7 +73,7 @@ jobs: - name: Publish Container Image on oci.stackable.tech/sdp if: inputs.destination-project == 'sdp' - uses: stackabletech/actions/publish-image@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$sdp+github-action-build @@ -84,7 +84,7 @@ jobs: - name: Publish Container Image on oci.stackable.tech/stackable if: inputs.destination-project == 'stackable' - uses: stackabletech/actions/publish-image@8a8085be0a8cec3d24ad3970e602d65be487da6a # v0.14.1 + uses: stackabletech/actions/publish-image@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$stackable+github-action-build @@ -113,7 +113,7 @@ jobs: - name: Publish and Sign Image Index Manifest to oci.stackable.tech/sdp if: inputs.destination-project == 'sdp' - uses: stackabletech/actions/publish-image-index-manifest@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$sdp+github-action-build @@ -123,7 +123,7 @@ jobs: - name: Publish and Sign Image Index Manifest to oci.stackable.tech/stackable if: inputs.destination-project == 'stackable' - uses: stackabletech/actions/publish-image-index-manifest@8a8085be0a8cec3d24ad3970e602d65be487da6a # v0.14.1 + uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$stackable+github-action-build diff --git a/.github/workflows/pr_pre-commit.yaml b/.github/workflows/pr_pre-commit.yaml index 60fbb0145..074333668 100644 --- a/.github/workflows/pr_pre-commit.yaml +++ b/.github/workflows/pr_pre-commit.yaml @@ -22,7 +22,7 @@ jobs: persist-credentials: false fetch-depth: 0 - - uses: stackabletech/actions/run-pre-commit@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + - uses: stackabletech/actions/run-pre-commit@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: python-version: ${{ env.PYTHON_VERSION }} rust: ${{ env.RUST_TOOLCHAIN_VERSION }} diff --git a/.github/workflows/reusable_build_image.yaml b/.github/workflows/reusable_build_image.yaml index 8a88d16b2..4385141ae 100644 --- a/.github/workflows/reusable_build_image.yaml +++ b/.github/workflows/reusable_build_image.yaml @@ -88,7 +88,7 @@ jobs: persist-credentials: false - id: shard - uses: stackabletech/actions/shard@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/shard@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: product-name: ${{ inputs.product-name }} outputs: @@ -115,11 +115,11 @@ jobs: persist-credentials: false - name: Free Disk Space - uses: stackabletech/actions/free-disk-space@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/free-disk-space@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 - name: Build Product Image id: build - uses: stackabletech/actions/build-product-image@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/build-product-image@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: registry-namespace: ${{ inputs.registry-namespace }} product-name: ${{ inputs.product-name }} @@ -128,7 +128,7 @@ jobs: - name: Publish Container Image on oci.stackable.tech if: inputs.publish - uses: stackabletech/actions/publish-image@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$${{ inputs.registry-namespace }}+github-action-build @@ -144,7 +144,7 @@ jobs: - name: Publish Container Image on quay.io if: inputs.publish && inputs.publish-to-quay - uses: stackabletech/actions/publish-image@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: quay.io image-registry-username: stackable+robot_${{ inputs.registry-namespace }}_github_action_build @@ -177,7 +177,7 @@ jobs: - name: Publish and Sign Image Index Manifest to oci.stackable.tech if: inputs.publish - uses: stackabletech/actions/publish-image-index-manifest@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: oci.stackable.tech image-registry-username: robot$${{ inputs.registry-namespace }}+github-action-build @@ -192,7 +192,7 @@ jobs: - name: Publish and Sign Image Index Manifest to quay.io if: inputs.publish && inputs.publish-to-quay - uses: stackabletech/actions/publish-image-index-manifest@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: image-registry-uri: quay.io image-registry-username: stackable+robot_${{ inputs.registry-namespace }}_github_action_build @@ -214,7 +214,7 @@ jobs: if: failure() || (github.run_attempt > 1 && !cancelled()) steps: - name: Send Notification - uses: stackabletech/actions/send-slack-notification@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/send-slack-notification@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: publish-manifests-result: ${{ needs.publish_manifests.result }} build-result: ${{ needs.build.result }} diff --git a/.github/workflows/ubi-rust-builder.yml b/.github/workflows/ubi-rust-builder.yml index 69393019f..677b56317 100644 --- a/.github/workflows/ubi-rust-builder.yml +++ b/.github/workflows/ubi-rust-builder.yml @@ -123,7 +123,7 @@ jobs: if: failure() || (github.run_attempt > 1 && !cancelled()) steps: - name: Send Notification - uses: stackabletech/actions/send-slack-notification@1b8db26b7406c66a7ab74e344a9e54edb2bc2690 # v0.14.3 + uses: stackabletech/actions/send-slack-notification@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: publish-manifests-result: ${{ needs.publish_manifests.result }} build-result: ${{ needs.build.result }} From 82063bcf7b0611c231f905beba6bdc12ec334c8d Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 1 Jul 2026 15:59:37 +0200 Subject: [PATCH 2/3] feat: generate SLSA provenance for product images --- .github/workflows/reusable_build_image.yaml | 115 +++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable_build_image.yaml b/.github/workflows/reusable_build_image.yaml index 4385141ae..1f3904a86 100644 --- a/.github/workflows/reusable_build_image.yaml +++ b/.github/workflows/reusable_build_image.yaml @@ -176,6 +176,7 @@ jobs: persist-credentials: false - name: Publish and Sign Image Index Manifest to oci.stackable.tech + id: publish-oci if: inputs.publish uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: @@ -191,6 +192,7 @@ jobs: image-index-manifest-tag: ${{ matrix.versions }}-stackable${{ inputs.sdp-version }} - name: Publish and Sign Image Index Manifest to quay.io + id: publish-quay if: inputs.publish && inputs.publish-to-quay uses: stackabletech/actions/publish-image-index-manifest@a8af17a19bdcc3b5da0065f76e73827ba0c072ce # v0.16.0 with: @@ -205,9 +207,120 @@ jobs: image-repository: stackable/${{ inputs.registry-namespace }}/${{ inputs.image-name || inputs.product-name }} image-index-manifest-tag: ${{ matrix.versions }}-stackable${{ inputs.sdp-version }} + # Record the pushed index manifest digest(s) for this matrix version so the + # provenance jobs can pick them up. Matrix jobs cannot expose per-version + # outputs (they overwrite each other), so we pass the digests through + # artifacts instead. + - name: Record image index digests for provenance + if: inputs.publish + shell: bash + env: + VERSION: ${{ matrix.versions }} + OCI_DIGEST: ${{ steps.publish-oci.outputs.image-index-manifest-digest }} + QUAY_DIGEST: ${{ steps.publish-quay.outputs.image-index-manifest-digest }} + run: | + set -euo pipefail + jq -n \ + --arg version "$VERSION" \ + --arg oci "$OCI_DIGEST" \ + --arg quay "$QUAY_DIGEST" \ + '{version: $version, oci_digest: $oci, quay_digest: $quay}' > digests.json + + - name: Upload provenance digests + if: inputs.publish + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: provenance-digests-${{ matrix.versions }} + path: digests.json + retention-days: 1 + + # Collect the per-version index manifest digests uploaded by publish_manifests + # and turn them into a matrix (one entry per version and registry) for the + # provenance job. This is needed because a matrix job cannot expose per-leg + # outputs directly. + collect-provenance-matrix: + name: Collect Provenance Matrix + if: inputs.publish + needs: [publish_manifests] + permissions: + contents: read + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.build-matrix.outputs.matrix }} + has-entries: ${{ steps.build-matrix.outputs.has_entries }} + steps: + - name: Download provenance digests + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: provenance-digests-* + path: artifacts + + - name: Build provenance matrix + id: build-matrix + shell: bash + env: + REGISTRY_NAMESPACE: ${{ inputs.registry-namespace }} + PRODUCT_NAME: ${{ inputs.product-name }} + IMAGE_NAME: ${{ inputs.image-name }} + run: | + set -euo pipefail + IMAGE="${IMAGE_NAME:-$PRODUCT_NAME}" + + # Build a JSON matrix include array. Each version contributes one entry + # for oci.stackable.tech and, if a quay digest was recorded, one for + # quay.io. The slsa generator attaches provenance by digest, so no tag + # is needed in the image reference. + INCLUDE=$(jq -c -s \ + --arg ns "$REGISTRY_NAMESPACE" \ + --arg img "$IMAGE" ' + [ .[] + | ( { registry: "oci.stackable.tech", + image: ("oci.stackable.tech/" + $ns + "/" + $img), + digest: .oci_digest, + username: ("robot$" + $ns + "+github-action-build") } ), + ( if (.quay_digest // "") != "" + then { registry: "quay.io", + image: ("quay.io/stackable/" + $ns + "/" + $img), + digest: .quay_digest, + username: ("stackable+robot_" + $ns + "_github_action_build") } + else empty end ) + ]' artifacts/*/digests.json) + + echo "matrix={\"include\":$INCLUDE}" | tee -a "$GITHUB_OUTPUT" + if [ "$INCLUDE" = "[]" ]; then + echo "has_entries=false" | tee -a "$GITHUB_OUTPUT" + else + echo "has_entries=true" | tee -a "$GITHUB_OUTPUT" + fi + + # Generate SLSA build provenance for every published multi-arch image index + # (one matrix entry per version and registry) and attach it to the image. The + # reusable workflow signs the provenance with keyless signing (GitHub Actions + # as the OIDC identity) and pushes the attestation next to the image. + provenance: + name: Generate Provenance (${{ matrix.image }}@${{ matrix.digest }}) + if: inputs.publish && needs.collect-provenance-matrix.outputs.has-entries == 'true' + needs: [collect-provenance-matrix] + permissions: + actions: read # detect the build workflow that generated the image + id-token: write # mint the OIDC token for keyless signing + packages: write # needed until https://github.com/slsa-framework/slsa-github-generator/issues/1257 is resolved + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.collect-provenance-matrix.outputs.matrix) }} + # MUST be referenced by a @vX.Y.Z tag (not a SHA), otherwise the reusable + # workflow cannot verify its own provenance. + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.1.0 + with: + image: ${{ matrix.image }} + digest: ${{ matrix.digest }} + registry-username: ${{ matrix.username }} + secrets: + registry-password: ${{ matrix.registry == 'quay.io' && secrets.quay-robot-secret || secrets.harbor-robot-secret }} + notify: name: Failure Notification - needs: [generate_version_dimension, build, publish_manifests] + needs: [generate_version_dimension, build, publish_manifests, collect-provenance-matrix, provenance] runs-on: ubuntu-latest # TODO (@NickLarsenNZ): Allow a condition from input so that we can always # be notified of new builds for precompiled product images. From 40776a68c404c2b5f2d120d09b60e3d1e8ab6970 Mon Sep 17 00:00:00 2001 From: dervoeti Date: Wed, 1 Jul 2026 17:26:49 +0200 Subject: [PATCH 3/3] docs: Add changelog entries for actions bump and SLSA provenance --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b93284f53..5f9f3ea1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ All notable changes to this project will be documented in this file. ### Added +- ci: Generate SLSA build provenance for published image indexes and attest it in each registry ([#1559]). + - hadoop: Add precompiled hadoop for later reuse in dependent images ([#1466], [#1474]). - nifi: Add version `2.9.0` ([#1463]). - nifi: Backport NIFI-15801 to 2.x versions ([#1481]). @@ -28,6 +30,7 @@ All notable changes to this project will be documented in this file. - airflow: Bump statsd_exporter to `0.30.0` ([#1524]). - ci: Bump `docker/login-action` from `v3.6.0` to `v4.1.0` and `stackabletech/actions` to `v0.14.3` to escape Node.js 20 deprecation ([#1507]). +- ci: Bump `stackabletech/actions` to `v0.16.0` ([#1559]). - hbase: Update `hbase-opa-authorizer` from `0.1.0` to `0.2.0` and then `0.3.0` ([#1446], [#1454]). - stackable-base: Bump `containerdebug` to `0.4.0` and `config-utils` to `0.4.0` ([#1521]). - statsd_exporter: Bump version from `0.28.0` to `0.30.0` ([#1524]). @@ -91,6 +94,7 @@ All notable changes to this project will be documented in this file. [#1549]: https://github.com/stackabletech/docker-images/pull/1549 [#1550]: https://github.com/stackabletech/docker-images/pull/1550 [#1551]: https://github.com/stackabletech/docker-images/pull/1551 +[#1559]: https://github.com/stackabletech/docker-images/pull/1559 ## [26.3.0] - 2026-03-16