Skip to content

Image - nginx-prometheus-exporter - refs/heads/main #10558

Image - nginx-prometheus-exporter - refs/heads/main

Image - nginx-prometheus-exporter - refs/heads/main #10558

Workflow file for this run

name: Image
run-name: "Image - ${{ inputs.oci-image-name || github.triggering_actor }} - ${{ github.ref }}"
on:
push:
branches:
- main
tags-ignore:
- '*'
paths:
- "oci/*/image.y*ml"
- "!oci/mock*"
pull_request:
paths:
- "oci/*/image.y*ml"
- "!oci/mock*"
workflow_dispatch:
inputs:
oci-image-name:
description: "OCI image to build and test"
required: true
b64-image-trigger:
description: "(Base64 encoded) Pass the image.yaml as an argument"
required: false
type: string
upload:
description: "Upload image to GHCR"
required: true
type: boolean
default: false
external_ref_id: # (1)
description: "Optional ID for unique run detection"
required: false
type: string
default: "default-id"
workflow_call:
inputs:
oci-image-name:
description: "OCI image to build and test"
type: string
required: true
upload:
description: "Upload image to GHCR"
type: boolean
default: false
env:
VULNERABILITY_REPORT_SUFFIX: ".vulnerability-report.json"
ROCK_REPO_DIR: rock-repo
# Skopeo v1.22.2 (immutable tag; mutable digests get GC'd by quay).
SKOPEO_IMAGE: "quay.io/skopeo/stable@sha256:4a16d57b37617a04b3d643079a477a2848efe892dffcdf0ce56df4262b65f810"
jobs:
prepare-build:
runs-on: ubuntu-22.04
name: Prepare build
outputs:
build-matrix: ${{ steps.prepare-matrix.outputs.build-matrix }}
release-to: ${{ steps.prepare-matrix.outputs.release-to }}
oci-img-path: ${{ steps.validate-image.outputs.img-path }}
oci-img-name: ${{ steps.validate-image.outputs.img-name }}
steps:
- name: ${{ inputs.external_ref_id }} # (2)
if: ${{ github.event_name == 'workflow_dispatch' }}
run: echo "Started by ${INPUTS_EXTERNAL_REF_ID}" >> "$GITHUB_STEP_SUMMARY"
env:
INPUTS_EXTERNAL_REF_ID: ${{ inputs.external_ref_id }}
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Infer number of image triggers
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323
id: changed-files
if: github.event_name != 'workflow_dispatch' && github.event_name != 'workflow_call'
with:
separator: ","
dir_names: "true"
files: |
oci/*/image.y*ml
- name: Validate image from dispatch
id: validate-image
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
source src/shared/logs.sh
# check if this is coming from a workflow dispatch/call
# as checking github.event_name isn't reliable here
if [ "${INPUTS_OCI_IMAGE_NAME}" != "" ]
then
img_path="oci/${INPUTS_OCI_IMAGE_NAME}"
else
img_path="${STEPS_CHANGED_FILES_OUTPUTS_ALL_CHANGED_FILES}"
occurrences="${img_path//[^,]}"
if [ ${#occurrences} -ne 0 ]
then
log_error "can only build 1 image at a time, but trying to trigger ${img_path}"
exit 1
fi
fi
test -d "${img_path}"
echo "img-name=$(basename ${img_path})" >> "$GITHUB_OUTPUT"
echo "img-path=${img_path}" >> "$GITHUB_OUTPUT"
env:
INPUTS_OCI_IMAGE_NAME: ${{ inputs.oci-image-name }}
STEPS_CHANGED_FILES_OUTPUTS_ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
- name: Validate access to triggered image
uses: ./.github/actions/validate-actor
if: ${{ github.repository == 'canonical/oci-factory' && !github.event.pull_request.head.repo.fork }}
with:
admin-only: true
image-path: ${{ steps.validate-image.outputs.img-path }}
github-token: ${{ secrets.ROCKSBOT_TOKEN }}
- name: Use custom image trigger
if: ${{ inputs.b64-image-trigger != '' }}
run: echo ${INPUTS_B64_IMAGE_TRIGGER} | base64 -d > ${STEPS_VALIDATE_IMAGE_OUTPUTS_IMG_PATH}/image.yaml
env:
INPUTS_B64_IMAGE_TRIGGER: ${{ inputs.b64-image-trigger }}
STEPS_VALIDATE_IMAGE_OUTPUTS_IMG_PATH: ${{ steps.validate-image.outputs.img-path }}
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.x"
- run: pip install -r src/image/requirements.txt
- name: Validate and prepare builds matrix
id: prepare-matrix
env:
DATA_DIR: "revision-data"
STEPS_VALIDATE_IMAGE_OUTPUTS_IMG_PATH: ${{ steps.validate-image.outputs.img-path }}
run: |
mkdir ${{ env.DATA_DIR }}
python3 -m src.image.prepare_single_image_build_matrix \
--oci-path "${STEPS_VALIDATE_IMAGE_OUTPUTS_IMG_PATH}" \
--revision-data-dir ${DATA_DIR} \
--warn-image-eol-exceeds-base-eol
validate-matrix:
# validate matrix prepared in previous job before running Build-Rock workflow.
runs-on: ubuntu-22.04
needs: [prepare-build]
strategy:
fail-fast: true
matrix: ${{ fromJSON(needs.prepare-build.outputs.build-matrix) }}
steps:
- name: Cloning OCI Factory
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
fetch-depth: 1
persist-credentials: false
- name: Clone GitHub image repository
uses: ./.github/actions/checkout
with:
repository: ${{ matrix.source }}
ref: ${{ matrix.commit }}
submodules: "recursive"
path: ${{ env.ROCK_REPO_DIR }}
- name: Installing yq
run: sudo snap install yq --channel=v4/stable
- name: Validate image naming and base
run: |
source src/shared/logs.sh
rock_name=$(cat "${{ env.ROCK_REPO_DIR }}/${MATRIX_DIRECTORY}"/rockcraft.y*ml | yq -r .name)
folder_name="${{ env.ROCK_REPO_DIR }}/${MATRIX_PATH}"
if [[ "${folder_name}" != *"${rock_name}"* ]]
then
log_error "the OCI folder name '${folder_name}', must contain the rock's name '${rock_name}'."
exit 1
fi
env:
MATRIX_DIRECTORY: ${{ matrix.directory }}
MATRIX_PATH: ${{ matrix.path }}
build-rock:
needs: [prepare-build, validate-matrix]
strategy:
fail-fast: true
matrix: ${{ fromJSON(needs.prepare-build.outputs.build-matrix) }}
uses: ./.github/workflows/Build-Rock.yaml
with:
oci-archive-name: ${{ matrix.name }}_${{ matrix.commit }}_${{ matrix.dir_identifier }}
build-id: ${{ matrix.name }}
rock-repo: ${{ matrix.source }}
rock-repo-commit: ${{ matrix.commit }}
rockfile-directory: ${{ matrix.directory }}
lpci-fallback: true
secrets: inherit
test-rock:
needs: [prepare-build, build-rock]
# TODO: Remove tmp-cache-job when removing the job tmp-cache-job
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.prepare-build.outputs.build-matrix) }}
uses: ./.github/workflows/Test-Rock.yaml
with:
oci-archive-name: "${{ matrix.name }}_${{ matrix.commit }}_${{ matrix.dir_identifier }}"
trivyignore-path: ${{ matrix.ignored-vulnerabilities == '' && format('oci/{0}/.trivyignore', matrix.name) || '' }}
ignored-vulnerabilities: ${{ matrix.ignored-vulnerabilities }}
secrets: inherit
prepare-upload:
runs-on: self-hosted-linux-amd64-noble-private-endpoint-small
needs: [prepare-build, build-rock, test-rock]
name: Prepare upload
if: ${{ inputs.upload || (github.ref_name == 'main' && github.event_name == 'push') }}
env:
OS_AUTH_URL: ${{ secrets.SWIFT_OS_AUTH_URL_PS7 }}
OS_USERNAME: ${{ secrets.SWIFT_OS_USERNAME_PS7 }}
OS_TENANT_NAME: ${{ secrets.SWIFT_OS_TENANT_NAME_PS7 }}
OS_PASSWORD: ${{ secrets.SWIFT_OS_PASSWORD_PS7 }}
OS_STORAGE_URL: ${{ secrets.SWIFT_OS_STORAGE_URL_PS7 }}
IMAGE_NAME: ${{ needs.prepare-build.outputs.oci-img-name }}
SWIFT_CONTAINER_NAME: ${{ vars.SWIFT_CONTAINER_NAME }}
DATA_DIR: "revision-data"
outputs:
build-matrix: ${{ steps.prepare-matrix.outputs.build-matrix }}
revision-data-cache-key: ${{ steps.prepare-matrix.outputs.revision-data-cache-key }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Use custom image trigger
if: ${{ inputs.b64-image-trigger != '' }}
run: echo ${INPUTS_B64_IMAGE_TRIGGER} | base64 -d > ${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH}/image.yaml
env:
INPUTS_B64_IMAGE_TRIGGER: ${{ inputs.b64-image-trigger }}
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH: ${{ needs.prepare-build.outputs.oci-img-path }}
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.x"
- run: |
./src/uploads/requirements.sh
pip install -r src/image/requirements.txt -r src/uploads/requirements.txt
- name: Upload the lockfile for the image
id: swift-lock
run: |
./src/uploads/swift_lockfile_lock.sh \
"${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_NAME}"
env:
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_NAME: ${{ needs.prepare-build.outputs.oci-img-name }}
# Here starts the critical section, have to be executed in sequence outside of matrix.
- name: Get next revision number
id: get-next-revision
run: ./src/image/define_image_revision.sh
- name: Prepare builds matrix for upload
id: prepare-matrix
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
mkdir ${DATA_DIR}
python3 -m src.image.prepare_single_image_build_matrix \
--oci-path "${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH}" \
--revision-data-dir ${DATA_DIR} \
--next-revision "${STEPS_GET_NEXT_REVISION_OUTPUTS_REVISION}" \
--infer-image-track
echo "revision-data-cache-key=${{ github.run_id }}-${DATA_DIR}-$(date +%s)" >> "$GITHUB_OUTPUT"
env:
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH: ${{ needs.prepare-build.outputs.oci-img-path }}
STEPS_GET_NEXT_REVISION_OUTPUTS_REVISION: ${{ steps.get-next-revision.outputs.revision }}
- name: Preempt Swift slot
run: |
./src/uploads/preempt_swift_slots.sh ${{ env.DATA_DIR }}
# Here leaves the critical section.
# The lock will be removed even if the steps above fail,
# or the workflow is cancelled.
- name: Remove the lockfile for the image
# Failing to lock the swift container can mean there are multiple
# workflows trying to upload the same image at the same time.
# Therefore we should not remove the lockfile if the swift lock failed.
if: ${{ always() && steps.swift-lock.outcome != 'failure' }}
run: |
./src/uploads/swift_lockfile_unlock.sh \
"${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_NAME}"
env:
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_NAME: ${{ needs.prepare-build.outputs.oci-img-name }}
- uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7
with:
path: ${{ steps.prepare-matrix.outputs.revision-data-dir }}
key: ${{ steps.prepare-matrix.outputs.revision-data-cache-key }}
upload:
runs-on: self-hosted-linux-amd64-noble-private-endpoint-small
needs: [prepare-build, prepare-upload]
name: Upload
strategy:
fail-fast: true
matrix: ${{ fromJSON(needs.prepare-upload.outputs.build-matrix) }}
env:
OCI_ARCHIVE_NAME: ${{ matrix.name }}_${{ matrix.commit }}_${{ matrix.dir_identifier }}
UMOCI_VERSION: "v0.4.7"
UMOCI_BINARY: "umoci.amd64"
outputs:
artefacts-hashes: ${{ steps.artefacts-hashes.outputs.hashes }}
permissions:
packages: write
# Used by step "Create Git tag"
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.10"
- name: Setup environment
env:
ROCKS_DEV_LP_SSH_PRIVATE: ${{ secrets.ROCKS_DEV_LP_SSH_PRIVATE }}
ROCKS_DEV_LP_USERNAME: ${{ secrets.ROCKS_DEV_LP_USERNAME }}
CPC_BUILD_TOOLS_REPO: git.launchpad.net/~cloudware/cloudware/+git/cpc_build_tools
# CPC_BUILD_TOOLS_REPO_REF: 9b716ed8a8ba728d036b54b1bb17a8f49dbda434
run: |
./src/image/requirements.sh
./src/uploads/requirements.sh
pip install -r src/uploads/requirements.txt -r src/image/requirements.txt
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: ${{ env.OCI_ARCHIVE_NAME }}
- name: Name output artefact
id: rename-oci-archive
run: |
# Rename the OCI archive tarball
canonical_tag="${MATRIX_TRACK}_${MATRIX_REVISION}"
name="${MATRIX_NAME}_${canonical_tag}"
mv "${OCI_ARCHIVE_NAME}" "$name"
echo "name=${name}" >> "$GITHUB_OUTPUT"
echo "canonical-tag=${canonical_tag}" >> "$GITHUB_OUTPUT"
env:
MATRIX_TRACK: ${{ matrix.track }}
MATRIX_REVISION: ${{ matrix.revision }}
MATRIX_NAME: ${{ matrix.name }}
- uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7
with:
path: ${{ steps.rename-oci-archive.outputs.name }}
key: ${{ github.run_id }}-${{ steps.rename-oci-archive.outputs.name }}
- name: Install Syft
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610
with:
syft-version: "v0.75.0"
- name: Infer architectures
id: get-arches
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
source src/shared/logs.sh
arches=$(docker run --rm \
-v "$PWD:/workdir" -w /workdir \
"${SKOPEO_IMAGE}" \
inspect --raw \
"oci-archive:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}" \
| jq -r 'if has("manifests") then .manifests[].platform.architecture else "${{ runner.arch }}" end' \
| jq -nRcr '[inputs] | join(",")')
log_info "Detected architectures: ${arches}"
echo "arches=${arches}" >> "$GITHUB_OUTPUT"
env:
STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME: ${{ steps.rename-oci-archive.outputs.name }}
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c
with:
go-version: '1.24'
- name: Setup SSBOM
run: |
go install github.com/canonical/ssbom/cmd/ssbom@latest
- name: Setup umoci
uses: ./.github/actions/install-umoci
with:
umoci-version: ${{ env.UMOCI_VERSION }}
umoci-binary: ${{ env.UMOCI_BINARY }}
- name: Generate SBOMs
id: generate-sboms
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
source src/shared/logs.sh
log_info "Generating SBOMs for ${STEPS_GET_ARCHES_OUTPUTS_ARCHES}"
IFS=',' read -ra arch_list <<< "${STEPS_GET_ARCHES_OUTPUTS_ARCHES}"
for arch in "${arch_list[@]}"; do
if [[ "${arch}" == "unknown" ]]; then
continue
fi
log_info "Generate SBOM for ${arch}"
# --insecure-policy is required on private-endpoint runners.
docker run --rm \
-v "$PWD:/workdir" -w /workdir \
"${SKOPEO_IMAGE}" \
--insecure-policy --override-arch "${arch}" copy \
"oci-archive:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}" \
"oci:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_CANONICAL_TAG}" \
syft "oci-dir:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}" \
-o spdx-json \
--file "${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}.sbom_preview.spdx.json"
umoci unpack \
--keep-dirlinks --rootless \
--image "${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}:${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_CANONICAL_TAG}" \
"${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}-bundle"
if [[ -f "${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}-bundle/rootfs/var/lib/chisel/manifest.wall" ]]; then
ssbom "${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}-bundle/rootfs" \
"${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.${arch}.chiselled.sbom_preview.spdx.json"
fi
done
all_sboms_zip="${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}.sbom_preview.spdx.zip"
zip "${all_sboms_zip}" "${STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME}".*.sbom_preview.spdx.json
echo "sboms=${all_sboms_zip}" >> "$GITHUB_OUTPUT"
env:
STEPS_GET_ARCHES_OUTPUTS_ARCHES: ${{ steps.get-arches.outputs.arches }}
STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_NAME: ${{ steps.rename-oci-archive.outputs.name }}
STEPS_RENAME_OCI_ARCHIVE_OUTPUTS_CANONICAL_TAG: ${{ steps.rename-oci-archive.outputs.canonical-tag }}
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
with:
name: ${{ env.OCI_ARCHIVE_NAME }}${{ env.VULNERABILITY_REPORT_SUFFIX }}
# https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/generic/README.md
- name: Calculate artefacts hashes
id: artefacts-hashes
env:
VULN_REPORT: ${{ env.OCI_ARCHIVE_NAME }}${{ env.VULNERABILITY_REPORT_SUFFIX }}
SBOMS: ${{ steps.generate-sboms.outputs.sboms }}
OCI_IMAGE_ARCHIVE: ${{ steps.rename-oci-archive.outputs.name }}
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
echo "hashes=$(sha256sum ${VULN_REPORT} ${OCI_IMAGE_ARCHIVE} ${SBOMS} | base64 -w0)"
- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Upload SBOM
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: ${{ steps.generate-sboms.outputs.sboms }}
path: ${{ steps.generate-sboms.outputs.sboms }}
if-no-files-found: error
- name: Upload image
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: ${{ steps.rename-oci-archive.outputs.name }}
path: ${{ steps.rename-oci-archive.outputs.name }}
if-no-files-found: error
- name: Upload to GHCR
id: upload-image
uses: ./.github/actions/upload-rock
with:
artifact_name: ${{ env.OCI_ARCHIVE_NAME }}
name: ${{ github.repository_owner }}/oci-factory/${{ matrix.name }}
tags: ${{ matrix.track }}_${{ matrix.revision }}
registry: ghcr.io
skopeo-image: ${{ env.SKOPEO_IMAGE }}
password: ${{ secrets.GITHUB_TOKEN }}
username: ${{ github.actor }}
- name: Upload build metadata to Swift
env:
OS_AUTH_URL: ${{ secrets.SWIFT_OS_AUTH_URL_PS7 }}
OS_USERNAME: ${{ secrets.SWIFT_OS_USERNAME_PS7 }}
OS_TENANT_NAME: ${{ secrets.SWIFT_OS_TENANT_NAME_PS7 }}
OS_PASSWORD: ${{ secrets.SWIFT_OS_PASSWORD_PS7 }}
OS_REGION_NAME: ${{ secrets.SWIFT_OS_REGION_NAME_PS7 }}
OS_STORAGE_URL: ${{ secrets.SWIFT_OS_STORAGE_URL_PS7 }}
IMAGE_NAME: ${{ matrix.name }}
SWIFT_CONTAINER_NAME: ${{ vars.SWIFT_CONTAINER_NAME }}
MATRIX_BASE: ${{ matrix.base }}
STEPS_UPLOAD_IMAGE_OUTPUTS_DIGEST: ${{ steps.upload-image.outputs.digest }}
MATRIX_IGNORED_VULNERABILITIES: ${{ matrix.ignored-vulnerabilities }}
MATRIX_NAME: ${{ matrix.name }}
MATRIX_TRACK: ${{ matrix.track }}
MATRIX_REVISION: ${{ matrix.revision }}
STEPS_GENERATE_SBOMS_OUTPUTS_SBOMS: ${{ steps.generate-sboms.outputs.sboms }}
run: |
jq --arg base "${MATRIX_BASE}" \
--arg digest "${STEPS_UPLOAD_IMAGE_OUTPUTS_DIGEST}" \
--arg ignored_vulnerabilities "${MATRIX_IGNORED_VULNERABILITIES}" \
'. + {base: $base, digest: $digest, "ignored-vulnerabilities": $ignored_vulnerabilities}' \
<<< '${{ toJSON(matrix) }}' > build_metadata.json
./src/uploads/upload_to_swift.sh \
"${MATRIX_NAME}" \
"${MATRIX_TRACK}" \
"${MATRIX_REVISION}" \
build_metadata.json \
"${STEPS_GENERATE_SBOMS_OUTPUTS_SBOMS}" \
"${OCI_ARCHIVE_NAME}${{ env.VULNERABILITY_REPORT_SUFFIX }}"
- name: Create Git tag
uses: rickstaa/action-create-tag@a1c7777fcb2fee4f19b0f283ba888afa11678b72
with:
tag: "${{ steps.rename-oci-archive.outputs.name }}"
message: "upload(${{ matrix.name }}): Build and upload new image revision ${{ matrix.revision }}"
force_push_tag: true
github_token: ${{ secrets.GITHUB_TOKEN }}
# We need this job because we want to make the releases all in one go,
# so that we know which revisions to release, and so that we can update
# and commit the _releases.json file in a single commit, outside a matrix job
prepare-releases:
name: Prepare releases
needs: [prepare-build, prepare-upload, upload]
runs-on: ubuntu-22.04
if: ${{ needs.prepare-build.outputs.release-to != '' }}
concurrency:
group: ${{ needs.prepare-build.outputs.oci-img-path }}
cancel-in-progress: true
env:
REVISION_DATA_DIR: revision-data
steps:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.x"
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- name: Use custom image trigger
if: ${{ inputs.b64-image-trigger != '' }}
run: echo ${INPUTS_B64_IMAGE_TRIGGER} | base64 -d > ${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH}/image.yaml
env:
INPUTS_B64_IMAGE_TRIGGER: ${{ inputs.b64-image-trigger }}
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH: ${{ needs.prepare-build.outputs.oci-img-path }}
- uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7
with:
path: ${{ env.REVISION_DATA_DIR }}
key: ${{ needs.prepare-upload.outputs.revision-data-cache-key }}
fail-on-cache-miss: true
- run: pip install -r src/image/requirements.txt
- name: Merge release requests
id: merge-release-requests
env:
PYTHONUNBUFFERED: 1
NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH: ${{ needs.prepare-build.outputs.oci-img-path }}
run: |
set -e
if [[ "$RUNNER_DEBUG" == "1" ]]; then
set -x
fi
source src/shared/logs.sh
for revision_file in "${REVISION_DATA_DIR}"/*
do
revision_file="$(basename "${revision_file}")"
ret=0
jq -er .release < "${REVISION_DATA_DIR}/${revision_file}" > /dev/null || ret=1
if [ $ret -eq 1 ]
then
log_info "Revision $revision_file not marked for release"
continue
fi
log_info "Merge revision $revision_file with requested releases"
python3 -m src.image.merge_release_info \
--image-trigger "${NEEDS_PREPARE_BUILD_OUTPUTS_OCI_IMG_PATH}/image.yaml" \
--revision-data-file "${REVISION_DATA_DIR}/${revision_file}"
done
- uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7
with:
path: ${{ needs.prepare-build.outputs.oci-img-path }}/image.yaml
key: ${{ github.run_id }}-image-trigger
release:
name: Release
needs: [prepare-build, prepare-releases]
permissions:
contents: write
uses: ./.github/workflows/Release.yaml
with:
oci-image-name: "${{ needs.prepare-build.outputs.oci-img-name }}"
image-trigger-cache-key: "${{ github.run_id }}-image-trigger"
secrets: inherit
generate-provenance:
name: Generate SLSA provenance
needs: [upload]
runs-on: ubuntu-22.04
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c
id: download
with:
path: artifacts
- name: Generate provenance
uses: philips-labs/slsa-provenance-action@752766b8a3b1ebd09d599e163eeec8fa39e677aa
with:
command: generate
subcommand: files
arguments: --artifact-path ${{ steps.download.outputs.download-path }} --output-path provenance.json
# - uses: sigstore/cosign-installer@41d4f4d837df20f1ef015f6d24b78584cb492a2d
# with:
# cosign-release: 'v2.0.0'
# - name: Sign provenance file
# env:
# PRIVATE_KEY: ${{ secrets.COSIGN_PRIVATE_KEY }}
# COSIGN_PASSWORD: ${{ secrets.COSIGN_PASSWORD }}
# PUBLIC_KEY: ${{ secrets.COSIGN_PUBLIC_KEY }}
# run: |
# echo "${PRIVATE_KEY}" > cosign.key
# echo "${PUBLIC_KEY}" > cosign.pub
# cosign sign-blob --key cosign.key --output-signature provenance.json.sig provenance.json
# - name: Upload verification keys
# uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
# with:
# name: verify
# path: |
# cosign.pub
# provenance.json.sig
# if-no-files-found: error
# - name: Generate checksums
# working-directory: ${{ steps.download.outputs.download-path }}
# run: sha256sum * > SHA256SUMS || true
# - name: Upload SHA256SUMS file
# uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
# with:
# name: SHA256SUMS
# path: SHA256SUMS
# if-no-files-found: error
- name: Upload provenance file
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f
with:
name: provenance
path: provenance.json
if-no-files-found: error
# generate-provenance:
# name: Generate SLSA provenance
# needs: [upload]
# permissions:
# actions: read # Needed for detection of GitHub Actions environment.
# id-token: write # Needed for provenance signing and ID
# contents: write # Needed for release uploads
# uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@7f4fdb871876c23e455853d694197440c5a91506
# with:
# base64-subjects: "${{ needs.upload.outputs.artefacts-hashes }}"
notify:
runs-on: ubuntu-22.04
name: Notify
needs:
[prepare-build, validate-matrix, build-rock, test-rock, prepare-upload, upload, prepare-releases, release, generate-provenance]
if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) && github.event_name != 'pull_request' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
persist-credentials: false
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
with:
python-version: "3.x"
- run: pip install -r src/notifications/requirements.txt
- name: Summarize workflow failure message
id: get-summary
run: |
echo '${{ toJson(needs) }}' > jobs.json
python3 -m src.notifications.mattermost_notifier summarize jobs.json
- name: Get contacts for ${{ needs.prepare-build.outputs.oci-img-name }}
id: get-contacts
working-directory: ${{ needs.prepare-build.outputs.oci-img-path }}
run: |
mm_channels=$(yq -r '.notify | ."mattermost-channels" | join(",")' < contacts.y*ml)
echo "mattermost-channels=${mm_channels}" >> "$GITHUB_OUTPUT"
- name: Notify via Mattermost
env:
MM_BOT_TOKEN: ${{ secrets.MM_BOT_TOKEN }}
FINAL_STATUS: failure
MM_SERVER: ${{ secrets.MM_SERVER }}
URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
SUMMARY: ${{ steps.get-summary.outputs.summary }}
FOOTER: "Triggered by ${{ github.triggering_actor }}. Ref: ${{ github.ref }}. Attempts: ${{ github.run_attempt }}"
TITLE: "${{ needs.prepare-build.outputs.oci-img-name }}: failed to build->upload->release"
STEPS_GET_CONTACTS_OUTPUTS_MATTERMOST_CHANNELS: ${{ steps.get-contacts.outputs.mattermost-channels }}
run: |
for channel in $(echo ${STEPS_GET_CONTACTS_OUTPUTS_MATTERMOST_CHANNELS} | tr ',' ' ')
do
MM_CHANNEL_ID="${channel}" python3 -m src.notifications.mattermost_notifier send
done