Publish Container Images #1677
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Publish Container Images | |
# This workflow uses actions that are not certified by GitHub. | |
# They are provided by a third-party and are governed by | |
# separate terms of service, privacy policy, and support | |
# documentation. | |
on: | |
schedule: | |
- cron: "43 9 * * *" | |
push: | |
branches: [main] | |
# Publish semver tags as releases. | |
tags: ["v*.*.*"] | |
env: | |
REGISTRY: ghcr.io | |
GHCR_IMAGE: ghcr.io/${{ github.repository }} | |
GCP_IMAGE: us-docker.pkg.dev/mondoohq/release/mondoo-operator | |
RELEASE: ${{ github.ref_name }} | |
jobs: | |
debug-event: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Print workflow actor | |
run: echo "${{ toJSON(github.actor) }}" | |
- name: Print workflow event | |
run: jq '.' $GITHUB_EVENT_PATH | |
build-operator: | |
name: Build operator binaries | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
# This is used to complete the identity challenge | |
# with sigstore/fulcio when running outside of PRs. | |
id-token: write | |
strategy: | |
matrix: | |
os: [linux] | |
arch: [amd64, arm64, arm] | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
- name: Import environment variables from file | |
run: cat ".github/env" >> $GITHUB_ENV | |
- uses: actions/setup-go@v5 | |
with: | |
go-version: "${{ env.golang-version }}" | |
cache: true | |
# Install the cosign tool except on PR | |
# https://github.com/sigstore/cosign-installer | |
- name: Install cosign | |
uses: sigstore/cosign-installer@v3 | |
# Login against a Docker registry except on PR | |
# https://github.com/docker/login-action | |
- name: Log into registry ${{ env.REGISTRY }} | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Authenticate with Google Cloud | |
uses: "google-github-actions/auth@v2" | |
with: | |
credentials_json: "${{ secrets.GCP_ARTIFACT_REGISTRY_SA }}" | |
- name: "Set up Cloud SDK" | |
uses: "google-github-actions/setup-gcloud@v2" | |
- name: Docker Login (GCR) | |
run: | | |
gcloud auth configure-docker us-docker.pkg.dev | |
# Extract metadata (tags, labels) for Docker | |
# https://github.com/docker/metadata-action | |
- name: Extract Docker metadata | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.GHCR_IMAGE }} | |
${{ env.GCP_IMAGE }} | |
tags: | | |
type=schedule,pattern=main | |
type=ref,event=branch | |
type=ref,event=tag | |
type=ref,event=pr | |
flavor: | | |
suffix=-${{ matrix.arch }},onlatest=true | |
# Extract metadata (tags, labels) for Docker | |
# https://github.com/docker/metadata-action | |
- name: Extract Docker metadata (without suffixes) | |
id: meta_clean | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.GHCR_IMAGE }} | |
${{ env.GCP_IMAGE }} | |
tags: | | |
type=schedule,pattern=main | |
type=ref,event=branch | |
type=ref,event=tag | |
type=ref,event=pr | |
- name: Build binaries | |
run: VERSION=${{ steps.meta_clean.outputs.version }} TARGET_OS=${{ matrix.os }} TARGET_ARCH=${{ matrix.arch }} make build | |
# Build and push Docker image with Buildx | |
# https://github.com/docker/build-push-action | |
- name: Build and push operator image | |
id: build-and-push-operator | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
platforms: ${{ matrix.os }}/${{ matrix.arch }} | |
push: true | |
labels: ${{ steps.meta.outputs.labels }} | |
tags: ${{ steps.meta.outputs.tags }} | |
- name: Scan Image | |
uses: mondoohq/actions/docker-image@main | |
env: | |
MONDOO_CONFIG_BASE64: ${{ secrets.MONDOO_CLIENT }} | |
with: | |
image: ${{ env.GHCR_IMAGE }}@${{ steps.build-and-push-operator.outputs.digest }} | |
# Sign the resulting Docker image digest except on PRs. | |
# This will only write to the public Rekor transparency log when the Docker | |
# repository is public to avoid leaking data. If you would like to publish | |
# transparency data even for private images, pass --force to cosign below. | |
# https://github.com/sigstore/cosign | |
- name: Sign the published Docker image | |
# This step uses the identity token to provision an ephemeral certificate | |
# against the sigstore community Fulcio instance. | |
run: cosign sign -y ${{ env.GHCR_IMAGE }}@${{ steps.build-and-push-operator.outputs.digest }} | |
push-virtual-tag: | |
name: Push multi-platform virtual tag | |
runs-on: ubuntu-latest | |
needs: | |
- build-operator | |
permissions: | |
contents: read | |
packages: write | |
# This is used to complete the identity challenge | |
# with sigstore/fulcio when running outside of PRs. | |
id-token: write | |
steps: | |
- name: Checkout repository | |
uses: actions/checkout@v4 | |
# Install the cosign tool except on PR | |
# https://github.com/sigstore/cosign-installer | |
- name: Install cosign | |
uses: sigstore/cosign-installer@v3 | |
# Login against a Docker registry except on PR | |
# https://github.com/docker/login-action | |
- name: Log into registry ${{ env.REGISTRY }} | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Authenticate with Google Cloud | |
uses: "google-github-actions/auth@v2" | |
with: | |
credentials_json: "${{ secrets.GCP_ARTIFACT_REGISTRY_SA }}" | |
- name: "Set up Cloud SDK" | |
uses: "google-github-actions/setup-gcloud@v2" | |
- name: Docker Login (GCR) | |
run: | | |
gcloud auth configure-docker us-docker.pkg.dev | |
# Extract metadata (tags, labels) for Docker | |
# https://github.com/docker/metadata-action | |
- name: Extract Docker metadata | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: | | |
${{ env.GHCR_IMAGE }} | |
${{ env.GCP_IMAGE }} | |
- name: Push multi-platform virtual tag and sign | |
run: bash scripts/push-virtual-tag.sh | |
env: | |
TAGS: ${{ steps.meta.outputs.tags }} | |
CPU_ARCHS: amd64 arm64 arm | |
build-bundle: | |
if: startsWith(github.ref, 'refs/tags/v') | |
needs: | |
- push-virtual-tag | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
# This is used to complete the identity challenge | |
# with sigstore/fulcio when running outside of PRs. | |
id-token: write | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Import environment variables from file | |
run: cat ".github/env" >> $GITHUB_ENV | |
- name: Install Go | |
uses: actions/setup-go@v5 | |
with: | |
go-version: "${{ env.golang-version }}" | |
# Install the cosign tool except on PR | |
# https://github.com/sigstore/cosign-installer | |
- name: Install cosign | |
uses: sigstore/cosign-installer@v3 | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
with: | |
image: tonistiigi/binfmt:latest | |
platforms: amd64,arm | |
# Workaround: https://github.com/docker/build-push-action/issues/461 | |
- name: Setup Docker buildx | |
uses: docker/setup-buildx-action@v3 | |
# Login against a Docker registry except on PR | |
# https://github.com/docker/login-action | |
- name: Log into registry ${{ env.REGISTRY }} | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Make bundle | |
id: make-bundle | |
run: | | |
export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) | |
export OS=$(uname | awk '{print tolower($0)}') | |
export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/${{ env.operator-sdk-version }} | |
curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH} | |
gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E | |
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt | |
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc | |
gpg -u "Operator SDK (release) <cncf-operator-sdk@cncf.io>" --verify checksums.txt.asc | |
grep operator-sdk_${OS}_${ARCH} checksums.txt | sha256sum -c - | |
chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk | |
make bundle IMG='${{ env.GHCR_IMAGE }}:${{ env.RELEASE }}' VERSION='${{ env.RELEASE }}' | |
# Extract metadata (tags, labels) for Docker | |
# https://github.com/docker/metadata-action | |
- name: Extract Docker metadata | |
id: meta-bundle | |
uses: docker/metadata-action@v5 | |
with: | |
images: "${{ env.GHCR_IMAGE }}-bundle" | |
# Build and push Docker image bundle with Buildx | |
- name: Build and push bundle image | |
id: build-and-push-bundle | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
file: bundle.Dockerfile | |
platforms: linux/amd64,linux/arm/v7,linux/arm64 | |
push: true | |
labels: ${{ steps.meta-bundle.outputs.labels }} | |
tags: ${{ steps.meta-bundle.outputs.tags }} | |
# Sign the resulting Docker image digest except on PRs. | |
# This will only write to the public Rekor transparency log when the Docker | |
# repository is public to avoid leaking data. If you would like to publish | |
# transparency data even for private images, pass --force to cosign below. | |
# https://github.com/sigstore/cosign | |
- name: Sign the published Docker image | |
# This step uses the identity token to provision an ephemeral certificate | |
# against the sigstore community Fulcio instance. | |
run: cosign sign -y ${{ env.GHCR_IMAGE }}-bundle@${{ steps.build-and-push-bundle.outputs.digest }} | |
# run olm e2e tests | |
run-olm-e2e: | |
name: OLM integration tests | |
if: startsWith(github.ref, 'refs/tags/v') | |
needs: | |
- build-bundle | |
runs-on: ubuntu-latest | |
strategy: | |
fail-fast: false | |
matrix: | |
k8s-version: [v1.28.9, v1.29.4, v1.30.0] | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 # fetch is needed for "git tag --list" in the Makefile | |
- name: Import environment variables from file | |
run: cat ".github/env" >> $GITHUB_ENV | |
- name: Install Go | |
uses: actions/setup-go@v5 | |
with: | |
go-version: "${{ env.golang-version }}" | |
- name: Start minikube | |
uses: medyagh/setup-minikube@master | |
with: | |
memory: 4000m | |
kubernetes-version: ${{ matrix.k8s-version }} | |
- name: Install operator-sdk | |
id: operator-sdk | |
run: | | |
export ARCH=$(case $(uname -m) in x86_64) echo -n amd64 ;; aarch64) echo -n arm64 ;; *) echo -n $(uname -m) ;; esac) | |
export OS=$(uname | awk '{print tolower($0)}') | |
export OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/${{ env.operator-sdk-version }} | |
curl -LO ${OPERATOR_SDK_DL_URL}/operator-sdk_${OS}_${ARCH} | |
gpg --keyserver keyserver.ubuntu.com --recv-keys 052996E2A20B5C7E | |
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt | |
curl -LO ${OPERATOR_SDK_DL_URL}/checksums.txt.asc | |
gpg -u "Operator SDK (release) <cncf-operator-sdk@cncf.io>" --verify checksums.txt.asc | |
grep operator-sdk_${OS}_${ARCH} checksums.txt | sha256sum -c - | |
chmod +x operator-sdk_${OS}_${ARCH} && sudo mv operator-sdk_${OS}_${ARCH} /usr/local/bin/operator-sdk | |
# Now that dependencies are cached the tests start almost immediately after minikube has started | |
# this makes tests fail occasionally. This sleep gives the runner some time to become more stable | |
# before the test execution starts. | |
- name: Wait a bit for the runner to become more stable | |
run: kubectl -n kube-system wait --for=condition=Ready pods --all --timeout=60s | |
- name: Install Mondoo operator using OLM | |
run: | | |
operator-sdk olm install | |
kubectl -n olm wait --for=condition=Ready pods --all --timeout=60s | |
kubectl create ns mondoo-operator | |
operator-sdk run bundle ghcr.io/${{ github.repository }}-bundle:${{ github.ref_name }} --namespace mondoo-operator --timeout 3m0s | |
- name: Gather running pods | |
if: failure() | |
run: | | |
kubectl get pods -A | |
mkdir -p tests/integration/_output | |
kubectl get pods -n mondoo-operator -o yaml >> tests/integration/_output/mondoo-pods.log | |
kubectl logs -n olm deployment/olm-operator >> tests/integration/_output/olm-operator-pods.log | |
- name: Extract Docker metadata | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.GHCR_IMAGE }} | |
- name: Run integration tests | |
env: | |
MONDOO_API_TOKEN: ${{ secrets.MONDOO_TEST_ORG_TOKEN }} | |
run: EXTERNAL_INSTALLATION=1 VERSION=${{ steps.meta.outputs.version }} make test/integration/ci | |
- name: Clean up | |
run: | | |
operator-sdk cleanup mondoo-operator --namespace mondoo-operator | |
operator-sdk olm uninstall | |
- uses: actions/upload-artifact@v4 # upload test results | |
if: success() || failure() # run this step even if previous step failed | |
with: # upload a combined archive with unit and integration test results | |
name: test-results-olm-${{ matrix.k8s-version }} | |
path: integration-tests-olm-${{ matrix.k8s-version }}.xml | |
- name: Upload test logs artifact | |
uses: actions/upload-artifact@v4 | |
if: failure() | |
with: | |
name: olm-test-logs-${{ matrix.k8s-version }} | |
path: /home/runner/work/mondoo-operator/mondoo-operator/tests/integration/_output/ | |
# publish kubectl manifests | |
run-release-manifests: | |
if: startsWith(github.ref, 'refs/tags/v') | |
uses: ./.github/workflows/release-manifests.yaml | |
needs: | |
- push-virtual-tag | |
# this should ensure the manifest is tagged latest, which is required for the install automation | |
- release-helm | |
# publish helm chart after the release of container images is complete | |
# run-helm-tests: | |
# name: Run helm integration tests | |
# if: startsWith(github.ref, 'refs/tags/v') | |
# needs: | |
# - push-virtual-tag | |
# runs-on: ubuntu-latest | |
# permissions: | |
# contents: read | |
# checks: write | |
# statuses: write | |
# strategy: | |
# fail-fast: false | |
# matrix: | |
# k8s-version: [v1.26.12, v1.27.9, v1.28.5, v1.29.0] | |
# steps: | |
# - name: Checkout | |
# uses: actions/checkout@v4 | |
# with: | |
# fetch-depth: 0 | |
# - name: Import environment variables from file | |
# run: cat ".github/env" >> $GITHUB_ENV | |
# - name: Install Go | |
# uses: actions/setup-go@v5 | |
# with: | |
# go-version: "${{ env.golang-version }}" | |
# - name: Start minikube | |
# uses: medyagh/setup-minikube@master | |
# with: | |
# memory: 4000m | |
# kubernetes-version: ${{ matrix.k8s-version }} | |
# - name: Install Helm | |
# uses: azure/setup-helm@v4 | |
# with: | |
# token: ${{ secrets.GITHUB_TOKEN }} | |
# id: install | |
# - name: Extract Docker metadata | |
# id: meta | |
# uses: docker/metadata-action@v5 | |
# with: | |
# images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
# - name: Install Mondoo Operator Helm chart | |
# run: helm install mondoo-operator charts/mondoo-operator -n mondoo-operator --create-namespace --wait | |
# # Now that dependencies are cached the tests start almost immediately after minikube has started | |
# # this makes tests fail occasionally. This sleep gives the runner some time to become more stable | |
# # before the test execution starts. | |
# - name: Wait a bit for the runner to become more stable | |
# run: kubectl -n kube-system wait --for=condition=Ready pods --all --timeout=60s | |
# - name: Run integration tests | |
# env: | |
# MONDOO_API_TOKEN: ${{ secrets.MONDOO_TEST_ORG_TOKEN }} | |
# run: EXTERNAL_INSTALLATION=1 VERSION=${{ steps.meta.outputs.version }} make test/integration/ci | |
# - uses: actions/upload-artifact@v4 # upload test results | |
# if: success() || failure() # run this step even if previous step failed | |
# with: # upload a combined archive with unit and integration test results | |
# name: test-results-helm-${{ matrix.k8s-version }} | |
# path: integration-tests-helm-${{ matrix.k8s-version }}.xml | |
# - name: Upload test logs artifact | |
# uses: actions/upload-artifact@v4 | |
# if: failure() | |
# with: | |
# name: helm-test-logs-${{ matrix.k8s-version }} | |
# path: /home/runner/work/mondoo-operator/mondoo-operator/tests/integration/_output/ | |
report-tests: | |
name: Report test results | |
runs-on: ubuntu-latest | |
needs: | |
- run-olm-e2e | |
#- run-helm-tests | |
permissions: | |
actions: read # Required to read the artifact | |
contents: read # Required to read the source | |
checks: write # Required to write the results | |
pull-requests: write # Required to write comments | |
steps: | |
- name: Download test results | |
uses: actions/download-artifact@v4 | |
with: | |
pattern: test-results-* | |
merge-multiple: true | |
- name: Publish Test Results | |
uses: EnricoMi/publish-unit-test-result-action@v2 | |
with: | |
commit: ${{ github.event.workflow_run.head_sha }} | |
event_file: ${{ github.event_path }} | |
event_name: ${{ github.event.workflow_run.event }} | |
files: "*.xml" | |
release-helm: | |
name: Release helm chart | |
needs: | |
- push-virtual-tag | |
runs-on: ubuntu-latest | |
permissions: | |
contents: write | |
steps: | |
- name: Checkout | |
uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 | |
- name: Configure Git | |
run: | | |
git config user.name "$GITHUB_ACTOR" | |
git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | |
- name: Install Helm | |
uses: azure/setup-helm@v4 | |
with: | |
token: ${{ secrets.GITHUB_TOKEN }} | |
id: install | |
- name: Run chart-releaser | |
# switch back to helm/chart-releaser-action when #60 is fixed | |
# https://github.com/helm/chart-releaser-action/issues/60 | |
uses: luisico/chart-releaser-action@on-tags | |
env: | |
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" |