| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- name: 'Provenance / SBOM / Sign'
- description: 'Creates SBOM & provenance files and signs the image'
- inputs:
- image-name:
- description: "name of the image"
- required: true
- default: ''
- image-tag:
- description: "image tag"
- required: true
- default: ""
- runs:
- using: "composite"
- steps:
- - name: Install cosign
- # https://github.com/sigstore/cosign-installer/releases/tag/v4.0.0
- uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
- with:
- cosign-release: 'v3.0.2'
- - name: Install Syft
- # https://github.com/anchore/sbom-action/releases/tag/v0.22.2
- uses: anchore/sbom-action/download-syft@28d71544de8eaf1b958d335707167c5f783590ad # v0.22.2
- with:
- syft-version: v1.41.2
- - name: Check Cosign install
- shell: bash
- run: cosign version
- - name: Login to ghcr.io
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ github.token }}
- - name: Setup Go
- uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
- with:
- go-version-file: go.mod
- - name: Set up crane
- shell: bash
- run: go install github.com/google/go-containerregistry/cmd/crane@v0.11.0
- - name: Get docker image tag
- id: container_info
- shell: bash
- env:
- IMAGE_NAME: ${{ inputs.image-name }}
- IMAGE_TAG: ${{ inputs.image-tag }}
- run: |
- echo "::group::Crane digest lookup"
- echo "Looking up digest for ${IMAGE_NAME}:${IMAGE_TAG}"
- DIGEST=$(crane digest ${IMAGE_NAME}:${IMAGE_TAG})
- echo "Found digest: ${DIGEST}"
- echo "digest=${DIGEST}" >> $GITHUB_OUTPUT
- echo "::endgroup::"
- - name: Sign image
- shell: bash
- env:
- IMAGE_NAME: ${{ inputs.image-name }}
- CONTAINER_DIGEST: ${{ steps.container_info.outputs.digest }}
- GITHUB_TRIGGERING_ACTOR: ${{ github.triggering_actor }}
- run: |
- echo "::group::Cosign sign"
- echo "Signing ${IMAGE_NAME}@${CONTAINER_DIGEST}"
- cosign sign --yes --new-bundle-format=false --use-signing-config=false -a GITHUB_ACTOR=${GITHUB_TRIGGERING_ACTOR} "${IMAGE_NAME}@${CONTAINER_DIGEST}"
- echo "::endgroup::"
- - name: Attach SBOM to image
- shell: bash
- id: sbom
- env:
- IMAGE_NAME: ${{ inputs.image-name }}
- IMAGE_TAG: ${{ inputs.image-tag }}
- CONTAINER_DIGEST: ${{ steps.container_info.outputs.digest }}
- run: |
- echo "::group::Image SBOM generation"
- # Image SBOM (OS + application libs contained in the image)
- echo "Generating image SBOM for ${IMAGE_NAME}@${CONTAINER_DIGEST}"
- syft "${IMAGE_NAME}@${CONTAINER_DIGEST}" -o spdx-json=sbom.${IMAGE_TAG}.spdx.json
- ORIGINAL_IMAGE_SBOM_SIZE="$(wc -c < sbom.${IMAGE_TAG}.spdx.json)"
- echo "Original image SBOM size: ${ORIGINAL_IMAGE_SBOM_SIZE} bytes"
- MAX_SBOM_SIZE_BYTES=10000000
- echo "Deduplicating image SPDX package nodes and relationships"
- bash ./hack/dedupe-spdx-gomod.sh \
- --input sbom.${IMAGE_TAG}.spdx.json \
- --output sbom.${IMAGE_TAG}.dedup.spdx.json
- DEDUP_IMAGE_SBOM_SIZE="$(wc -c < sbom.${IMAGE_TAG}.dedup.spdx.json)"
- echo "Deduplicated image SBOM size: ${DEDUP_IMAGE_SBOM_SIZE} bytes"
- if [[ "${DEDUP_IMAGE_SBOM_SIZE}" -gt "${MAX_SBOM_SIZE_BYTES}" ]]; then
- echo "Deduped image SBOM still above ${MAX_SBOM_SIZE_BYTES} bytes, dropping file ownership data"
- bash ./hack/dedupe-spdx-gomod.sh \
- --input sbom.${IMAGE_TAG}.spdx.json \
- --output sbom.${IMAGE_TAG}.dedup.spdx.json \
- --drop-file-ownership
- DEDUP_IMAGE_SBOM_SIZE="$(wc -c < sbom.${IMAGE_TAG}.dedup.spdx.json)"
- echo "Ownership-pruned deduplicated image SBOM size: ${DEDUP_IMAGE_SBOM_SIZE} bytes"
- fi
- if [[ "${DEDUP_IMAGE_SBOM_SIZE}" -gt "${MAX_SBOM_SIZE_BYTES}" ]]; then
- echo "Image SBOM predicate is still too large (${DEDUP_IMAGE_SBOM_SIZE} bytes)."
- echo "Refusing attestation to avoid Rekor submission retries/failure."
- exit 1
- fi
- echo "::endgroup::"
- echo "::group::Attest image SBOM"
- cosign attest --yes --new-bundle-format=false --use-signing-config=false --predicate sbom.${IMAGE_TAG}.dedup.spdx.json --type spdx "${IMAGE_NAME}@${CONTAINER_DIGEST}"
- echo "::endgroup::"
- echo "::group::Verify image SBOM attestation"
- echo "Using certificate-identity-regexp: https://github.com/$GITHUB_REPOSITORY/.*"
- cosign verify-attestation --type spdx ${IMAGE_NAME}@${CONTAINER_DIGEST} \
- --certificate-identity-regexp "https://github.com/$GITHUB_REPOSITORY/.*" \
- --certificate-oidc-issuer https://token.actions.githubusercontent.com | jq '.payload |= @base64d | .payload | fromjson'
- echo "::endgroup::"
- echo "::group::Go modules SBOM generation"
- # Go modules SBOM (dependencies from the source tree)
- # Requires repository to be checked out before this composite action runs.
- syft dir:. -o spdx-json=sbom.gomod.${IMAGE_TAG}.spdx.json
- ORIGINAL_GOMOD_SBOM_SIZE="$(wc -c < sbom.gomod.${IMAGE_TAG}.spdx.json)"
- echo "Original Go modules SBOM size: ${ORIGINAL_GOMOD_SBOM_SIZE} bytes"
- echo "Deduplicating Go modules SPDX package nodes and relationships"
- bash ./hack/dedupe-spdx-gomod.sh \
- --input sbom.gomod.${IMAGE_TAG}.spdx.json \
- --output sbom.gomod.${IMAGE_TAG}.dedup.spdx.json
- DEDUP_GOMOD_SBOM_SIZE="$(wc -c < sbom.gomod.${IMAGE_TAG}.dedup.spdx.json)"
- echo "Deduplicated Go modules SBOM size: ${DEDUP_GOMOD_SBOM_SIZE} bytes"
- # Rekor requests can fail when predicates are too large. If the deduped
- # SBOM is still big, drop file ownership-heavy data and re-check size.
- if [[ "${DEDUP_GOMOD_SBOM_SIZE}" -gt "${MAX_SBOM_SIZE_BYTES}" ]]; then
- echo "Deduped SBOM still above ${MAX_SBOM_SIZE_BYTES} bytes, dropping file ownership data"
- bash ./hack/dedupe-spdx-gomod.sh \
- --input sbom.gomod.${IMAGE_TAG}.spdx.json \
- --output sbom.gomod.${IMAGE_TAG}.dedup.spdx.json \
- --drop-file-ownership
- DEDUP_GOMOD_SBOM_SIZE="$(wc -c < sbom.gomod.${IMAGE_TAG}.dedup.spdx.json)"
- echo "Ownership-pruned deduplicated Go modules SBOM size: ${DEDUP_GOMOD_SBOM_SIZE} bytes"
- fi
- if [[ "${DEDUP_GOMOD_SBOM_SIZE}" -gt "${MAX_SBOM_SIZE_BYTES}" ]]; then
- echo "Go modules SBOM predicate is still too large (${DEDUP_GOMOD_SBOM_SIZE} bytes)."
- echo "Refusing attestation to avoid Rekor submission retries/failure."
- exit 1
- fi
- echo "::endgroup::"
- echo "::group::Attest Go modules SBOM"
- cosign attest --yes --new-bundle-format=false --use-signing-config=false --predicate sbom.gomod.${IMAGE_TAG}.dedup.spdx.json --type spdx "${IMAGE_NAME}@${CONTAINER_DIGEST}"
- echo "::endgroup::"
- echo "::group::Verify Go modules SBOM attestation"
- cosign verify-attestation --type spdx ${IMAGE_NAME}@${CONTAINER_DIGEST} \
- --certificate-identity-regexp "https://github.com/$GITHUB_REPOSITORY/.*" \
- --certificate-oidc-issuer https://token.actions.githubusercontent.com | jq ' .payload |= @base64d | .payload | fromjson | .subject'
- echo "::endgroup::"
- - name: Generate provenance
- shell: bash
- env:
- IMAGE_NAME: ${{ inputs.image-name }}
- IMAGE_TAG: ${{ inputs.image-tag }}
- CONTAINER_DIGEST: ${{ steps.container_info.outputs.digest }}
- run: |
- echo "::group::Generate provenance"
- ./hack/generate-provenance.sh \
- --repository "${IMAGE_NAME}" \
- --digest "${CONTAINER_DIGEST}" \
- --tags "${IMAGE_TAG}" \
- --output-path "provenance.${IMAGE_TAG}.intoto.jsonl"
- echo "::endgroup::"
- - name: Attach provenance
- shell: bash
- id: provenance
- env:
- IMAGE_NAME: ${{ inputs.image-name }}
- IMAGE_TAG: ${{ inputs.image-tag }}
- CONTAINER_DIGEST: ${{ steps.container_info.outputs.digest }}
- run: |
- echo "::group::Prepare provenance predicate"
- jq '.predicate' provenance.${IMAGE_TAG}.intoto.jsonl > provenance-predicate.att
- echo "::endgroup::"
- echo "::group::Attest provenance"
- cosign attest --yes --new-bundle-format=false --use-signing-config=false --predicate provenance-predicate.att --type slsaprovenance "${IMAGE_NAME}@${CONTAINER_DIGEST}"
- echo "::endgroup::"
- echo "::group::Verify provenance attestation"
- cosign verify-attestation --type slsaprovenance ${IMAGE_NAME}@${CONTAINER_DIGEST} \
- --certificate-identity-regexp "https://github.com/$GITHUB_REPOSITORY/.*" \
- --certificate-oidc-issuer https://token.actions.githubusercontent.com
- echo "::endgroup::"
|