Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 0 additions & 83 deletions .github/actions/build/attest-artifact/action.yml

This file was deleted.

19 changes: 5 additions & 14 deletions .github/actions/build/publish-helm-chart/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ inputs:
registryPassword:
description: "Container registry password"
required: true
attestDryRun:
description: "Run attestation in dry-run mode (log only, no real attestation)"
required: false
default: "false"
outputs:
image:
description: "Full OCI image reference with digest (e.g. quay.io/strimzi-helm/chart@sha256:abc)"
value: ${{ steps.helm-push.outputs.image }}

runs:
using: "composite"
Expand All @@ -55,13 +55,4 @@ runs:
echo "$PUSH_OUTPUT"
DIGEST=$(echo "$PUSH_OUTPUT" | grep "Digest:" | awk '{print $2}')
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"

- name: Attest Helm chart
if: ${{ github.event_name != 'pull_request' }}
uses: ./.github/actions/build/attest-artifact
with:
mode: oci
subjectPrefix: ${{ inputs.containerRegistry }}/${{ inputs.containerOrg }}
imageName: ${{ inputs.helmChartName }}
subjectDigest: ${{ steps.helm-push.outputs.digest }}
dryRun: ${{ inputs.attestDryRun }}
echo "image=${{ inputs.containerRegistry }}/${{ inputs.containerOrg }}/${{ inputs.helmChartName }}@${DIGEST}" >> "$GITHUB_OUTPUT"
7 changes: 5 additions & 2 deletions .github/actions/build/push-containers/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ inputs:

outputs:
images:
description: "JSON array of {name, digest} for multi-image attestation via attest-containers.yml"
description: "JSON array of {name, digest, sbom} for multi-image attestation via reusable-attest.yml"
value: ${{ steps.discover-images.outputs.images }}
sbomsArtifact:
description: "Name of the uploaded SBOMs artifact"
value: SBOMs-${{ inputs.artifactSuffix }}-${{ inputs.containerTag }}.tar.gz

runs:
using: "composite"
Expand Down Expand Up @@ -146,7 +149,7 @@ runs:
for sbom_file in $(find ./sbom -name "*.json" -type f | sort); do
relative="${sbom_file#./sbom/}"
after_org="${relative#*${{ inputs.containerRegistry }}/${{ inputs.containerOrg }}/}"
name=$(echo "$after_org" | cut -d'/' -f1)
name="${{ inputs.containerRegistry }}/${{ inputs.containerOrg }}/${after_org%%/*}"
digest=$(basename "$sbom_file" .json)
images=$(echo "$images" | jq -c --arg n "$name" --arg d "$digest" --arg s "$relative" \
'. + [{"name": $n, "digest": $d, "sbom": $s}]')
Expand Down
45 changes: 1 addition & 44 deletions .github/actions/build/release-artifacts/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ inputs:
artifactSuffix:
description: "Suffix of archive with images"
required: true
attestDryRun:
description: "Run attestation in dry-run mode (log only, no real attestation)"
required: false
default: "false"

runs:
using: "composite"
steps:
Expand All @@ -31,51 +26,13 @@ runs:
RELEASE_VERSION: ${{ inputs.releaseVersion }}
MVN_ARGS: '-B -DskipTests'

# Find release archives using case-insensitive search (Maven may change case, e.g. rc1 -> RC1)
- name: Find release archives for attestation
id: find-archives
shell: bash
run: |
FILES=$(find . -type f \( -iname "*${{ inputs.releaseVersion }}*.tar.gz" -o \
-iname "*${{ inputs.releaseVersion }}*.zip" -o \
-iname "*${{ inputs.releaseVersion }}*.tgz" \))
if [ -n "$FILES" ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
{
echo "files<<EOF"
echo "$FILES"
echo "EOF"
} >> "$GITHUB_OUTPUT"
echo "Found $(echo "$FILES" | wc -l | tr -d ' ') release archive(s) for attestation"
else
echo "found=false" >> "$GITHUB_OUTPUT"
echo "No release archives found for attestation"
fi

# Creates attestation for release artifacts
- name: Attest release archives
if: ${{ github.event_name != 'pull_request' && steps.find-archives.outputs.found == 'true' }}
id: attest
uses: ./.github/actions/build/attest-artifact
with:
mode: blob
subjectPath: ${{ steps.find-archives.outputs.files }}
dryRun: ${{ inputs.attestDryRun }}

# Copy attestation provenance file in .intoto.jsonl format to add it into release tarball
- name: Copy attestation bundle
if: ${{ github.event_name != 'pull_request' && steps.find-archives.outputs.found == 'true' && inputs.attestDryRun != 'true' }}
shell: bash
run: cp "${{ steps.attest.outputs.bundlePath }}" "./release-${{ inputs.releaseVersion }}.intoto.jsonl"

- name: Create release tarball
shell: bash
run: |
find . -type f \( -iname "*${{ inputs.releaseVersion }}*.tar.gz" -o \
-iname "*${{ inputs.releaseVersion }}*.zip" -o \
-iname "*${{ inputs.releaseVersion }}*.tgz" -o \
-iname "*${{ inputs.releaseVersion }}*.yaml" -o \
-iname "*.intoto.jsonl" \) \
-iname "*${{ inputs.releaseVersion }}*.yaml" \) \
-exec tar -rvf release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar {} \;

- name: Upload release artifacts
Expand Down
180 changes: 180 additions & 0 deletions .github/workflows/reusable-attest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
name: Attestation

on:
workflow_call:
inputs:
containerImages:
description: "JSON array of {name, digest} from push-containers"
required: false
type: string
default: "[]"
artifactSuffix:
description: "Suffix for the release artifact name (e.g. kafka-bridge)"
required: false
type: string
default: ""
releaseVersion:
description: "Release version for finding archives in the release tar"
required: false
type: string
default: ""
helmChartName:
description: "Helm chart name (used for conditional logic, skip when empty or 'none')"
required: false
type: string
default: ""
helmChartImage:
description: "Full OCI reference with digest (e.g. quay.io/strimzi-helm/chart@sha256:abc123)"
required: false
type: string
default: ""
sbomsArtifact:
description: "Name of the SBOMs artifact from push-containers (e.g. SBOMs-kafka-bridge-latest.tar.gz)"
required: false
type: string
default: ""

permissions:
contents: read
id-token: write
attestations: write

jobs:
attest-release:
name: Attest Release Archives
if: ${{ inputs.releaseVersion != '' && inputs.releaseVersion != 'none' }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Download release artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar

- name: Extract release tar
shell: bash
run: |
mkdir -p release-workdir
tar -xf release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar -C release-workdir

- name: Download SBOMs artifact
if: ${{ inputs.sbomsArtifact != '' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.sbomsArtifact }}

- name: Copy SBOMs into release workdir
if: ${{ inputs.sbomsArtifact != '' }}
shell: bash
run: cp sbom.tar.gz release-workdir/

- name: Find release archives
id: find-archives
shell: bash
run: |
FILES=$(find release-workdir -type f \( -iname "*${{ inputs.releaseVersion }}*.tar.gz" -o \
-iname "*${{ inputs.releaseVersion }}*.zip" -o \
-iname "*${{ inputs.releaseVersion }}*.tgz" \))
if [ -n "$FILES" ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
{
echo "files<<EOF"
echo "$FILES"
echo "EOF"
} >> "$GITHUB_OUTPUT"
echo "Found $(echo "$FILES" | wc -l | tr -d ' ') release archive(s) for attestation"
else
echo "found=false" >> "$GITHUB_OUTPUT"
echo "No release archives found for attestation"
fi

- name: Attest release archives
if: ${{ steps.find-archives.outputs.found == 'true' }}
id: attest
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
with:
subject-path: ${{ steps.find-archives.outputs.files }}

- name: Add attestation bundle and SBOMs to release tar
if: ${{ steps.find-archives.outputs.found == 'true' }}
shell: bash
run: |
cp "${{ steps.attest.outputs.bundle-path }}" "release-workdir/release-${{ inputs.releaseVersion }}.intoto.jsonl"
rm release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar
TARBALL="../release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar"
cd release-workdir
find . -type f \( -iname "*${{ inputs.releaseVersion }}*.tar.gz" -o \
-iname "*${{ inputs.releaseVersion }}*.zip" -o \
-iname "*${{ inputs.releaseVersion }}*.tgz" -o \
-iname "*${{ inputs.releaseVersion }}*.yaml" -o \
-iname "*.intoto.jsonl" -o \
-name "sbom.tar.gz" \) \
-exec tar -rvf "${TARBALL}" {} \;

if ! tar -tf "${TARBALL}" | grep -q 'intoto.jsonl'; then
echo "::error::Attestation bundle missing from rebuilt release tar"
exit 1
fi

- name: Re-upload release artifact with attestation
if: ${{ steps.find-archives.outputs.found == 'true' }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar
path: release-${{ inputs.artifactSuffix }}-${{ inputs.releaseVersion }}.tar
overwrite: true
retention-days: 30

attest-helm:
name: Attest Helm Chart
if: ${{ inputs.helmChartName != '' && inputs.helmChartName != 'none' && inputs.helmChartImage != '' }}
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Parse Helm chart image reference
id: parse
shell: bash
run: |
IMAGE="${{ inputs.helmChartImage }}"
echo "subject-name=${IMAGE%%@*}" >> "$GITHUB_OUTPUT"
echo "subject-digest=${IMAGE##*@}" >> "$GITHUB_OUTPUT"

- name: Attest Helm chart
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
with:
subject-name: ${{ steps.parse.outputs.subject-name }}
subject-digest: ${{ steps.parse.outputs.subject-digest }}

attest-containers:
name: Attest Container Image
if: ${{ inputs.containerImages != '[]' && inputs.containerImages != '' }}
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
image: ${{ fromJSON(inputs.containerImages) }}
steps:
- name: Attest container image - ${{ matrix.image.name }}
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
with:
subject-name: ${{ matrix.image.name }}
subject-digest: ${{ matrix.image.digest }}

- name: Download SBOMs artifact
if: ${{ inputs.sbomsArtifact != '' && matrix.image.sbom != '' }}
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ inputs.sbomsArtifact }}

- name: Extract SBOMs
if: ${{ inputs.sbomsArtifact != '' && matrix.image.sbom != '' }}
shell: bash
run: tar -xzf sbom.tar.gz

- name: Attest SBOM - ${{ matrix.image.sbom }}
if: ${{ inputs.sbomsArtifact != '' && matrix.image.sbom != '' }}
uses: actions/attest@f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6 # v4.2.0
with:
subject-name: ${{ matrix.image.name }}
subject-digest: ${{ matrix.image.digest }}
sbom-path: ${{ matrix.image.sbom }}
Loading
Loading