Skip to content

chore(deps): update nginxinc/nginx-unprivileged:1.27.4-alpine-slim do… #259

chore(deps): update nginxinc/nginx-unprivileged:1.27.4-alpine-slim do…

chore(deps): update nginxinc/nginx-unprivileged:1.27.4-alpine-slim do… #259

name: container-build
# Based on:
# https://docs.docker.com/build/ci/github-actions/multi-platform/
# https://github.com/named-data/actions/blob/9cc5e94a08ae58ac033821e11fd44947d0f5f9bc/.github/workflows/docker-image.yml
on:
workflow_dispatch:
inputs:
# keep-sorted start
container_image_sign:
description: "SBOM + Sign the container image"
type: boolean
required: false
default: false
container_image_vulnerability_scan:
description: "Scan the container image for vulnerabilities"
type: boolean
required: false
default: true
container_registry_push:
description: "Push the container image to the registry"
type: boolean
required: false
default: false
# keep-sorted end
workflow_call:
inputs:
# keep-sorted start
container_image_sign:
type: boolean
required: true
container_registry_push:
type: boolean
required: true
release_tag:
type: string
required: true
# keep-sorted end
push:
branches-ignore:
- renovate/*
paths:
- Dockerfile
schedule:
- cron: 1 1 1 * *
permissions:
actions: read
# Use concurrency to prevent running when ghcr-cleanup is running
concurrency:
group: container-build
defaults:
run:
shell: bash -euxo pipefail {0}
env:
# keep-sorted start
container_image_authors: [email protected]
container_image_authors_name: Petr Ruzicka
container_image_category: security
container_image_dockerfile_location: Dockerfile
container_image_logo_url: https://raw.githubusercontent.com/MISP/intelligence-icons/513abc840b7ac92e4f8a4a7ecab2964007bf25f5/svg/threat_actor.svg
container_image_platforms: linux/amd64,linux/arm64
container_image_repository_url: https://quay.io/repository/petr_ruzicka/${{ github.event.repository.name }}?tab=tags
container_image_vendor: MyCompany
container_registries: |
# keep-sorted start
- registry: docker.io
image_name: docker.io/peru/${{ github.event.repository.name }}
username: ${{ secrets.dockerhub_container_registry_user }}
password: ${{ secrets.dockerhub_container_registry_password }}
- registry: ghcr.io
image_name: ghcr.io/${{ github.repository }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- registry: quay.io
image_name: quay.io/petr_ruzicka/${{ github.event.repository.name }}
username: ${{ secrets.quay_container_registry_user }}
password: ${{ secrets.quay_container_registry_password }}
# keep-sorted end
# Push the container image to the registry when triggered by a scheduled execution or a push to the default branch
container_registry_push_image: ${{ github.event_name == 'schedule' || inputs.container_registry_push || (github.ref_name == github.event.repository.default_branch && github.event_name == 'push') }}
# keep-sorted end
jobs:
# Workaround (GitHub Actions: Use variables in matrix definition?): https://stackoverflow.com/questions/74072206/github-actions-use-variables-in-matrix-definition
container-build-push-matrix-platform:
runs-on: ubuntu-latest
outputs:
matrix_platform_json: ${{ steps.matrix-platform.outputs.MATRIX_PLATFORM_JSON }}
steps:
- name: Parse container_image_platforms for Matrix Platform
id: matrix-platform
env:
CONTAINER_IMAGE_PLATFORMS: ${{ env.container_image_platforms }}
run: |
echo "MATRIX_PLATFORM_JSON=$(jq -cR 'split(",")' <<< "${CONTAINER_IMAGE_PLATFORMS}")" | tee -a "${GITHUB_OUTPUT}"
container-build-push:
name: ${{ matrix.platform }} - build
runs-on: ${{ contains(matrix.platform, 'arm') && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
needs: container-build-push-matrix-platform
outputs:
container_image_platform_digest: ${{ steps.docker-build-push.outputs.digest }}
strategy:
matrix:
platform: ${{ fromJSON(needs.container-build-push-matrix-platform.outputs.matrix_platform_json) }}
permissions:
contents: read
id-token: write # for creating OIDC tokens for signing
packages: write # for uploading attestations
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set variables
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
CONTAINER_IMAGE_DOCKERFILE_LOCATION: ${{ env.container_image_dockerfile_location }}
run: |
# Create list of image names for docker/metadata-action ("images" parameter)
# Create list of image locations for docker/metadata-action ("labels" [io.artifacthub.package.alternative-locations] parameter)
DOCKER_IMAGE_NAMES="$(yq '[.[].image_name] | join(",") | downcase' <<< "${CONTAINER_REGISTRIES}")"
echo "DOCKER_IMAGE_NAMES=${DOCKER_IMAGE_NAMES}" | tee -a "${GITHUB_ENV}"
# Create list of topics for io.artifacthub.package.keywords
echo '${{ toJSON(github.event.repository.topics) }}' | jq -r '. | join(",") | "GITHUB_REPOSITORY_TOPICS=\(.)"' | tee -a "${GITHUB_ENV}"
# Get the directory where the Dockerfile is located
echo "CONTAINER_IMAGE_DOCKER_BUILD_DIRECTORY=$(dirname "${CONTAINER_IMAGE_DOCKERFILE_LOCATION}")" | tee -a "${GITHUB_ENV}"
# Replace "/" by "-" in platform variable to be used in "Export digest"
echo "PLATFORM=$(echo "${{ matrix.platform }}" | tr '/' '-')" | tee -a "${GITHUB_ENV}"
- name: Login to container registries
if: ${{ env.container_registry_push_image == 'true' }}
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
# Login to all registries
readarray CONTAINER_REGISTRIES_ARRAY < <(yq e -o=j -I=0 '.[]' <<< "${CONTAINER_REGISTRIES}")
for CONTAINER_REGISTRY in "${CONTAINER_REGISTRIES_ARRAY[@]}"; do
REGISTRY="$(jq -r '.registry' <<< "${CONTAINER_REGISTRY}")"
USERNAME="$(jq -r '.username' <<< "${CONTAINER_REGISTRY}")"
PASSWORD="$(jq -r '.password' <<< "${CONTAINER_REGISTRY}")"
docker login "${REGISTRY}" --username "${USERNAME}" --password-stdin <<< "${PASSWORD}"
done
- name: Set up QEMU
if: ${{ !contains(matrix.platform, 'amd64') && !contains(matrix.platform, 'arm') }}
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3.4.0
with:
platforms: ${{ matrix.platform }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
- name: Build temporary container image
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
id: docker-build-push-temporary
env:
DOCKER_BUILD_SUMMARY: false
with:
file: ${{ env.container_image_dockerfile_location }}
context: ${{ env.CONTAINER_IMAGE_DOCKER_BUILD_DIRECTORY }}
platforms: ${{ matrix.platform }}
load: true
tags: temporary_container-${{ github.run_id }}:latest
- name: Grype [table] - scan container image
uses: anchore/scan-action@7c05671ae9be166aeb155bad2d7df9121823df32 # v6.1.0
with:
fail-build: ${{ inputs.container_image_vulnerability_scan }}
image: temporary_container-${{ github.run_id }}:latest
only-fixed: true
output-format: table
severity-cutoff: high
# Write to multiple output files (like syft): https://github.com/anchore/grype/issues/648
- name: Grype [sarif] - scan container image
uses: anchore/scan-action@7c05671ae9be166aeb155bad2d7df9121823df32 # v6.1.0
if: ${{ env.container_registry_push_image == 'true' }}
id: grype-scan
with:
fail-build: false
image: temporary_container-${{ github.run_id }}:latest
only-fixed: true
output-format: sarif
severity-cutoff: high
- name: Docker metadata
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
if: ${{ env.container_registry_push_image == 'true' }}
id: docker_meta
with:
labels: |
## Replace deprecated NGINX maintainer: https://docs.docker.com/reference/dockerfile/#maintainer-deprecated (crane config nginxinc/nginx-unprivileged | jq '.config.Labels')
maintainer=${{ env.container_image_authors }}
## Container images repositories: https://artifacthub.io/docs/topics/repositories/container-images/
# keep-sorted start sticky_comments=no
# org.opencontainers.image.created - it is there by default
# org.opencontainers.image.description - it is there by default (repository description)
# org.opencontainers.image.source - it is there by default
# org.opencontainers.image.title - it is there by default
# org.opencontainers.image.url - it is there by default
# org.opencontainers.image.version - it is there by default
io.artifacthub.package.alternative-locations=${{ env.DOCKER_IMAGE_NAMES }}
io.artifacthub.package.category=${{ env.container_image_category }}
io.artifacthub.package.keywords=${{ env.GITHUB_REPOSITORY_TOPICS }}
io.artifacthub.package.license=${{ github.event.repository.license.spdx_id }}
io.artifacthub.package.logo-url=${{ env.container_image_logo_url || 'https://raw.githubusercontent.com/kubernetes/community/487f994c013ea61d92cf9a341af7620037abbce3/icons/svg/resources/unlabeled/pod.svg' }}
io.artifacthub.package.maintainers=[{"name":"${{ env.container_image_authors_name }}","email":"${{ env.container_image_authors }}"}]
io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ github.repository }}/${{ github.sha }}/README.md
org.opencontainers.image.documentation=${{ github.event.repository.html_url }}/blob/${{ github.sha }}/README.md
org.opencontainers.image.vendor=${{ env.container_image_vendor }}
# keep-sorted end
## The OpenContainers Annotations Spec: https://specs.opencontainers.org/image-spec/annotations/?v=v1.0.1#pre-defined-annotation-keys
# keep-sorted start sticky_comments=no
# org.opencontainers.image.created - it is there by default
# org.opencontainers.image.description - it is there by default (repository description)
# org.opencontainers.image.documentation - already set
# org.opencontainers.image.licenses - it is there by default
# org.opencontainers.image.revision - it is there by default
# org.opencontainers.image.source - it is there by default
# org.opencontainers.image.title - it is there by default
# org.opencontainers.image.url - it is there by default
# org.opencontainers.image.vendor - already set
# org.opencontainers.image.version - it is there by default
org.opencontainers.image.authors=${{ env.container_image_authors }}
org.opencontainers.image.ref.name=${{ github.ref_name }}
# keep-sorted end
## Label Schema Convention: https://github.com/badouralix/dockerfiles/blob/c91181b356f92574f26d0499ee3d2be2cacd0952/LABELS.md
# keep-sorted start sticky_comments=no
com.github.actions.event_name=${{ github.event_name }}
com.github.actions.job=${{ github.job }}
com.github.actions.run_id=${{ github.run_id }}
com.github.actions.run_url=${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
# keep-sorted end
- name: Push image to container registries
uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
if: ${{ env.container_registry_push_image == 'true' }}
id: docker-build-push
env:
DOCKER_BUILD_RECORD_UPLOAD: false
with:
file: ${{ env.container_image_dockerfile_location }}
context: ${{ env.CONTAINER_IMAGE_DOCKER_BUILD_DIRECTORY }}
platforms: ${{ matrix.platform }}
provenance: false
outputs: type=image,"name=${{ env.DOCKER_IMAGE_NAMES }}",push-by-digest=true,name-canonical=true,push=true
annotations: ${{ steps.docker_meta.outputs.labels }}
labels: ${{ steps.docker_meta.outputs.labels }}
- name: Install cosign
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0
if: ${{ env.container_registry_push_image == 'true' && inputs.container_image_sign }}
- name: Install Syft
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
if: ${{ env.container_registry_push_image == 'true' && inputs.container_image_sign }}
- name: Sign + create SBOM
if: ${{ env.container_registry_push_image == 'true' && inputs.container_image_sign }}
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
DIGEST: ${{ steps.docker-build-push.outputs.digest }}
PLATFORM: ${{ matrix.platform }}
run: |
while read -r CONTAINER_REGISTRY_IMAGE_NAME; do
syft attest --output cyclonedx-json --platform "${PLATFORM}" "${CONTAINER_REGISTRY_IMAGE_NAME}@${DIGEST}"
done <<< "$(yq '.[].image_name | downcase' <<< "${CONTAINER_REGISTRIES}")"
- name: Export digest
if: ${{ env.container_registry_push_image == 'true' }}
working-directory: ${{ runner.temp }}
env:
DIGEST: ${{ steps.docker-build-push.outputs.digest }}
PLATFORM: ${{ matrix.platform }}
run: |
mkdir digests
touch "digests/${DIGEST#sha256:}"
- name: Upload digest
if: ${{ env.container_registry_push_image == 'true' }}
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
with:
name: digests-${{ env.PLATFORM }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
- name: Publish SARIF to github code scanning
if: ${{ env.container_registry_push_image == 'true' && steps.grype-scan.outputs.sarif != '' && github.ref_name == github.event.repository.default_branch }}
uses: github/codeql-action/upload-sarif@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0 # v3.28.9
with:
sarif_file: ${{ steps.grype-scan.outputs.sarif }}
- name: Remove docker credentials
if: ${{ always() && env.container_registry_push_image == 'true' }}
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
while read -r CONTAINER_REGISTRY; do
docker logout "${CONTAINER_REGISTRY}"
done <<< "$(yq '.[].registry' <<< "${CONTAINER_REGISTRIES}")"
container-build-push-merge:
name: Merge container images and generate sbom and signature
runs-on: ubuntu-latest
needs: container-build-push
if: ${{ needs.container-build-push.outputs.container_image_platform_digest != '' }}
permissions:
id-token: write # for creating OIDC tokens for signing
packages: write # for uploading attestations
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
outputs:
container_image_digest: ${{ steps.sign-sbom.outputs.CONTAINER_IMAGE_DIGEST }}
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
- name: Download digests
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
id: download
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true
- name: Login to container registries
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
# Login to all registries
readarray CONTAINER_REGISTRIES_ARRAY < <(yq e -o=j -I=0 '.[]' <<< "${CONTAINER_REGISTRIES}")
for CONTAINER_REGISTRY in "${CONTAINER_REGISTRIES_ARRAY[@]}"; do
REGISTRY="$(jq -r '.registry' <<< "${CONTAINER_REGISTRY}")"
USERNAME="$(jq -r '.username' <<< "${CONTAINER_REGISTRY}")"
PASSWORD="$(jq -r '.password' <<< "${CONTAINER_REGISTRY}")"
docker login "${REGISTRY}" --username "${USERNAME}" --password-stdin <<< "${PASSWORD}"
done
- name: Set variables
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
# Create list of image names for docker/metadata-action ("images" parameter)
CONTAINER_REGISTRY_IMAGE_NAMES=$(yq ".[].image_name | downcase" <<< "${CONTAINER_REGISTRIES}" )
echo "CONTAINER_REGISTRY_IMAGE_NAMES<<EOF"$'\n'"${CONTAINER_REGISTRY_IMAGE_NAMES}"$'\n'EOF | tee -a "${GITHUB_ENV}"
- name: Docker metadata
uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
id: docker_meta
env:
# https://github.com/docker/docs/issues/18835
DOCKER_METADATA_ANNOTATIONS_LEVELS: index
with:
images: |
${{ env.CONTAINER_REGISTRY_IMAGE_NAMES }}
tags: |
# Whever the pipeline runs form "main" - use "latest" container tag
type=raw,value=latest,enable={{is_default_branch}}
# When the pipeline is not executed form 'main' branch use "br-<mybranch>" tag
type=ref,prefix=br-,event=branch,enable=${{ github.ref_name != github.event.repository.default_branch }}
# Create "1.1.1", "1.1", "1" tags when called from release-please workflow (inputs.release_tag is "1.1.1")
type=semver,pattern={{version}},value=${{ inputs.release_tag }},enable=${{ inputs.release_tag != '' }}
type=semver,pattern={{major}}.{{minor}},value=${{ inputs.release_tag }},enable=${{ inputs.release_tag != '' }}
type=semver,pattern={{major}},value=${{ inputs.release_tag }},enable=${{ !startsWith(inputs.release_tag, '0.') }}
flavor: |
latest=false
- name: Install cosign
uses: sigstore/cosign-installer@c56c2d3e59e4281cc41dea2217323ba5694b171e # v3.8.0
if: ${{ inputs.container_image_sign }}
- name: Install Syft
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
if: ${{ inputs.container_image_sign }}
- name: Create and push multi-platform image index
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
working-directory: ${{ steps.download.outputs.download-path }}
run: |
while read -r CONTAINER_REGISTRY_IMAGE_NAME; do
readarray -t ANNOTATIONS < <(jq -r '.annotations[] | ("--annotation", .)' <<< "${DOCKER_METADATA_OUTPUT_JSON}")
readarray -t TAGS < <(jq -r --arg CONTAINER_REGISTRY_IMAGE_NAME "${CONTAINER_REGISTRY_IMAGE_NAME}" '.tags[] | select(contains($CONTAINER_REGISTRY_IMAGE_NAME)) | ("--tag", .)' <<< "${DOCKER_METADATA_OUTPUT_JSON}")
readarray -t SOURCES < <(printf "${CONTAINER_REGISTRY_IMAGE_NAME}@sha256:%s\n" *)
docker buildx imagetools create "${ANNOTATIONS[@]}" "${TAGS[@]}" "${SOURCES[@]}"
done <<< "$(yq '.[].image_name | downcase' <<< "${CONTAINER_REGISTRIES}")"
- name: Sign + create SBOM
if: ${{ inputs.container_image_sign }}
id: sign-sbom
env:
DOCKER_METADATA_TAG_0: ${{ fromJSON(steps.docker_meta.outputs.json).tags[0] }}
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
# Get the digest of the image from fist container registry (due to: https://github.com/docker/buildx/issues/2407)
CONTAINER_IMAGE_DIGEST="$(docker buildx imagetools inspect "${DOCKER_METADATA_TAG_0}" --format "{{json .Manifest.Digest}}" | jq -r)"
echo "CONTAINER_IMAGE_DIGEST=${CONTAINER_IMAGE_DIGEST}" | tee -a "${GITHUB_OUTPUT}"
while read -r CONTAINER_REGISTRY_IMAGE_NAME; do
cosign sign --recursive --yes "${CONTAINER_REGISTRY_IMAGE_NAME}@${CONTAINER_IMAGE_DIGEST}"
# Syft doesn't support recursive attestation yet - this is only for index manifest
syft attest --output cyclonedx-json "${CONTAINER_REGISTRY_IMAGE_NAME}@${CONTAINER_IMAGE_DIGEST}"
done <<< "$(yq '.[].image_name | downcase' <<< "${CONTAINER_REGISTRIES}")"
- name: Remove docker credentials
if: ${{ always() }}
env:
CONTAINER_REGISTRIES: ${{ env.container_registries }}
run: |
while read -r CONTAINER_REGISTRY; do
docker logout "${CONTAINER_REGISTRY}"
done <<< "$(yq '.[].registry' <<< "${CONTAINER_REGISTRIES}")"
provenance:
name: ${{ matrix.registry }} - provenance
needs: container-build-push-merge
if: ${{ inputs.container_image_sign || inputs.release_tag != '' }}
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
strategy:
# NOTE: These are the reasons why I need to repeat the whole container_registries section again :-(
# GH env variables can not be used in matrix: https://stackoverflow.com/questions/74072206/github-actions-use-variables-in-matrix-definition
# Secrets can not be used in matrix: https://github.com/orgs/community/discussions/26302
# GH Reusable Workflow can not be run as step: https://stackoverflow.com/questions/75733616/github-actions-how-to-call-a-reusable-workflow-as-a-step
matrix:
include:
# keep-sorted start
- registry: docker.io
image_name: docker.io/peru/${{ github.event.repository.name }}
username: peru
password: dockerhub_container_registry_password
- registry: ghcr.io
image_name: ghcr.io/${{ github.repository }}
username: ${{ github.actor }}
password: GITHUB_TOKEN
- registry: quay.io
image_name: quay.io/petr_ruzicka/${{ github.event.repository.name }}
username: petr_ruzicka+github_actions_access
password: quay_container_registry_password
# keep-sorted end
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
with:
image: ${{ matrix.image_name }}
digest: ${{ needs.container-build-push-merge.outputs.container_image_digest }}
registry-username: ${{ matrix.username }}
secrets:
registry-password: ${{ secrets[matrix.password] }}
verify-signatures-provenance-sbom:
name: verify signatures and provenance
needs: [container-build-push-merge, provenance]
runs-on: ubuntu-latest
if: ${{ inputs.container_image_sign || inputs.release_tag != '' }}
steps:
- name: Verify signatures, provenance and SBOM
env:
CONTAINER_IMAGE_PLATFORMS: ${{ env.container_image_platforms }}
CONTAINER_REGISTRIES: ${{ env.container_registries }}
COSIGN_CERTIFICATE_IDENTITY_REGEXP: ${{ github.event.repository.html_url }}/.github/workflows
COSIGN_CERTIFICATE_OIDC_ISSUER: https://token.actions.githubusercontent.com
COSIGN_ATTESTATION_TYPE: https://cyclonedx.org/bom
TRIVY_DISABLE_VEX_NOTICE: true
CONTAINER_IMAGE_DIGEST: ${{ needs.container-build-push-merge.outputs.container_image_digest }}
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
brew install cosign grype regclient slsa-verifier
while read -r CONTAINER_REGISTRY_IMAGE_NAME; do
CONTAINER_REGISTRY_IMAGE="${CONTAINER_REGISTRY_IMAGE_NAME}@${CONTAINER_IMAGE_DIGEST}"
echo "*** ${CONTAINER_REGISTRY_IMAGE_NAME}"
# # Example from Chainguard
# # https://images.chainguard.dev/directory/image/go/provenance
# CONTAINER_REGISTRY_IMAGE_NAME="cgr.dev/chainguard/go"
# CONTAINER_IMAGE_DIGEST=$(regctl image digest "cgr.dev/chainguard/go:latest")
# CONTAINER_REGISTRY_IMAGE="cgr.dev/chainguard/go@${CONTAINER_IMAGE_DIGEST}"
# COSIGN_CERTIFICATE_IDENTITY_REGEXP="https://github.com/chainguard-images/images/"
# COSIGN_CERTIFICATE_OIDC_ISSUER="https://token.actions.githubusercontent.com"
# COSIGN_ATTESTATION_TYPE="https://spdx.dev/Document"
# CONTAINER_IMAGE_PLATFORMS="linux/amd64,linux/arm64"
# CONTAINER_REGISTRY_IMAGE_NAME="c8n.io/ruzickap-github/malware-cryptominer-container-test"
# CONTAINER_IMAGE_DIGEST=$(regctl image digest "c8n.io/ruzickap-github/malware-cryptominer-container-test:latest")
# CONTAINER_REGISTRY_IMAGE="c8n.io/ruzickap-github/malware-cryptominer-container-test@${CONTAINER_IMAGE_DIGEST}"
# COSIGN_CERTIFICATE_IDENTITY_REGEXP="https://github.com/ruzickap/gha-test/.github/workflows"
# COSIGN_CERTIFICATE_OIDC_ISSUER="https://token.actions.githubusercontent.com"
# COSIGN_ATTESTATION_TYPE="https://cyclonedx.org/bom"
# CONTAINER_IMAGE_PLATFORMS="linux/amd64,linux/arm64"
#####################################
# Cosign
#####################################
# Verify the manifest list is signed
cosign verify \
--certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
--certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
"${CONTAINER_REGISTRY_IMAGE}" | jq --color-output
# Verify if every platfrom image manifest is signed
while read -r MANIFEST_DIGESTS; do
cosign verify \
--certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
--certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
"${CONTAINER_REGISTRY_IMAGE_NAME}@${MANIFEST_DIGESTS}" | jq --color-output
done <<< "$(regctl manifest get "${CONTAINER_REGISTRY_IMAGE}" --format '{{jsonPretty .}}' | jq -r '.manifests[].digest')"
#####################################
# SBOM
#####################################
cosign verify-attestation --type="${COSIGN_ATTESTATION_TYPE}" \
--certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
--certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
"${CONTAINER_REGISTRY_IMAGE}" | jq --color-output '.payload |= .[:2000] + "...<rest_is_removed>..."' --color-output
cosign verify-attestation --type="${COSIGN_ATTESTATION_TYPE}" \
--certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
--certificate-identity-regexp="${COSIGN_CERTIFICATE_IDENTITY_REGEXP}" \
"${CONTAINER_REGISTRY_IMAGE}" | jq '.payload | @base64d | fromjson | .predicate' | grype
for PLATFORM in ${CONTAINER_IMAGE_PLATFORMS//,/ }; do
cosign download attestation --platform="${PLATFORM}" --predicate-type="${COSIGN_ATTESTATION_TYPE}" \
"${CONTAINER_REGISTRY_IMAGE}" | jq -r .payload | base64 -d | jq .predicate | grype --add-cpes-if-none
done
#####################################
# SLSA Provenance
#####################################
cosign verify-attestation --type="slsaprovenance" \
--certificate-oidc-issuer="${COSIGN_CERTIFICATE_OIDC_ISSUER}" \
--certificate-identity-regexp='^https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@refs/tags/v[0-9]+.[0-9]+.[0-9]+$' \
"${CONTAINER_REGISTRY_IMAGE}" | jq --color-output
slsa-verifier verify-image --print-provenance --source-uri "github.com/${GITHUB_REPOSITORY}" \
"${CONTAINER_REGISTRY_IMAGE}" | jq --color-output
#####################################
# Container Registry Manifests
#####################################
cosign tree "${CONTAINER_REGISTRY_IMAGE}"
cosign download attestation "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output '.payload |= .[:2000] + "...<rest_is_removed>..."'
# Note: "regctl manifest get" should contain "Annotations"
regctl manifest get "${CONTAINER_REGISTRY_IMAGE}"
regctl manifest get "${CONTAINER_REGISTRY_IMAGE/@*/}:${CONTAINER_IMAGE_DIGEST/:/-}.att"
for PLATFORM in ${CONTAINER_IMAGE_PLATFORMS//,/ }; do
regctl image config --platform="${PLATFORM}" "${CONTAINER_REGISTRY_IMAGE}" | jq --color-output
done
done <<< "$(yq '.[].image_name | downcase' <<< "${CONTAINER_REGISTRIES}")"