-
Notifications
You must be signed in to change notification settings - Fork 40
CNF-23203: Pin container image versions and add automated update workflow #1196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| # Searches backwards through GitHub releases to find the newest release | ||
| # where all specified container images have been published. | ||
| # | ||
| # Usage: find-latest-image.sh <github_repo> <image1> [image2 ...] | ||
| # github_repo: GitHub repo in "owner/name" format | ||
| # image1..N: Full image references without tags (e.g., ghcr.io/org/name) | ||
| # | ||
| # Options (via environment variables): | ||
| # SEMVER_ONLY=true Skip non-semver tags (default: false) | ||
| # FALLBACK_TAG=<tag> Tag to return if no release has published images (default: exits 1) | ||
| # | ||
| # Outputs the matched tag to stdout. All logging goes to stderr. | ||
|
|
||
| GITHUB_REPO="$1" | ||
| shift | ||
| IMAGES=("$@") | ||
|
|
||
| if [ ${#IMAGES[@]} -eq 0 ]; then | ||
| echo "Usage: find-latest-image.sh <github_repo> <image1> [image2 ...]" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| SEMVER_ONLY="${SEMVER_ONLY:-false}" | ||
| FALLBACK_TAG="${FALLBACK_TAG:-}" | ||
|
|
||
| RELEASES=$(curl -sf --retry 3 --retry-delay 5 \ | ||
| "https://api.github.com/repos/${GITHUB_REPO}/releases?per_page=20" \ | ||
| | jq -r '.[].tag_name') | ||
|
|
||
| for RELEASE_TAG in $RELEASES; do | ||
| if [ "$SEMVER_ONLY" = "true" ]; then | ||
| if ! echo "$RELEASE_TAG" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+'; then | ||
| echo "Skipping non-semver tag: $RELEASE_TAG" >&2 | ||
| continue | ||
| fi | ||
| fi | ||
|
|
||
| echo "Checking images for ${GITHUB_REPO} release ${RELEASE_TAG}..." >&2 | ||
| ALL_FOUND=true | ||
| for IMAGE in "${IMAGES[@]}"; do | ||
| if ! skopeo inspect --override-arch amd64 --override-os linux \ | ||
| "docker://${IMAGE}:${RELEASE_TAG}" > /dev/null 2>&1; then | ||
| ALL_FOUND=false | ||
| break | ||
| fi | ||
| done | ||
|
|
||
| if [ "$ALL_FOUND" = "true" ]; then | ||
| echo "Found images for ${GITHUB_REPO} release ${RELEASE_TAG}" >&2 | ||
| echo "$RELEASE_TAG" | ||
| exit 0 | ||
| else | ||
| echo "Images not found for ${RELEASE_TAG}, trying next..." >&2 | ||
| fi | ||
| done | ||
|
|
||
| if [ -n "$FALLBACK_TAG" ]; then | ||
| echo "No versioned images found, using fallback: ${FALLBACK_TAG}" >&2 | ||
| echo "$FALLBACK_TAG" | ||
| exit 0 | ||
| fi | ||
|
|
||
| echo "No release with published images found for ${GITHUB_REPO}" >&2 | ||
| exit 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| name: Update image versions | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '17 6 * * *' | ||
| workflow_dispatch: {} | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| env: | ||
| REGISTRY: ghcr.io/complianceascode | ||
| IMAGES_FILE: pkg/utils/images.go | ||
|
|
||
| jobs: | ||
| update-images: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Install skopeo | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y skopeo | ||
|
|
||
| - name: Get latest compliance-operator release with published images | ||
| id: co-release | ||
| run: | | ||
| CO_TAG=$(SEMVER_ONLY=true .github/scripts/find-latest-image.sh \ | ||
| ComplianceAsCode/compliance-operator \ | ||
| "$REGISTRY/compliance-operator" \ | ||
| "$REGISTRY/openscap-ocp") | ||
| echo "tag=$CO_TAG" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Get latest k8scontent revision | ||
| id: k8scontent-release | ||
| run: | | ||
| K8S_TAG=$(skopeo inspect --override-arch amd64 --override-os linux \ | ||
| "docker://$REGISTRY/k8scontent:latest" \ | ||
| | jq -r '.Labels["org.opencontainers.image.revision"]') | ||
|
|
||
| if [ -z "$K8S_TAG" ] || [ "$K8S_TAG" = "null" ]; then | ||
| echo "Failed to get k8scontent revision from :latest" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Verifying k8scontent:${K8S_TAG} exists..." | ||
| skopeo inspect --override-arch amd64 --override-os linux \ | ||
| "docker://$REGISTRY/k8scontent:${K8S_TAG}" > /dev/null | ||
|
|
||
| echo "tag=$K8S_TAG" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Check for version changes | ||
| id: check | ||
| run: | | ||
| CO_TAG="${{ steps.co-release.outputs.tag }}" | ||
| K8S_TAG="${{ steps.k8scontent-release.outputs.tag }}" | ||
|
|
||
| OPENSCAP_CUR=$(grep 'openscap-ocp:' "$IMAGES_FILE" | sed 's/.*openscap-ocp:\([^"]*\).*/\1/') | ||
| OPERATOR_CUR=$(grep 'compliance-operator:' "$IMAGES_FILE" | sed 's/.*compliance-operator:\([^"]*\).*/\1/') | ||
| K8S_CUR=$(grep 'k8scontent:' "$IMAGES_FILE" | sed 's/.*k8scontent:\([^"]*\).*/\1/') | ||
|
|
||
| echo "Current: openscap-ocp=$OPENSCAP_CUR compliance-operator=$OPERATOR_CUR k8scontent=$K8S_CUR" | ||
| echo "Resolved: openscap-ocp=$CO_TAG compliance-operator=$CO_TAG k8scontent=$K8S_TAG" | ||
|
|
||
| echo "openscap=$OPENSCAP_CUR" >> "$GITHUB_OUTPUT" | ||
| echo "operator=$OPERATOR_CUR" >> "$GITHUB_OUTPUT" | ||
| echo "k8scontent=$K8S_CUR" >> "$GITHUB_OUTPUT" | ||
|
|
||
| CHANGED="false" | ||
| if [ "$CO_TAG" != "$OPENSCAP_CUR" ] || [ "$CO_TAG" != "$OPERATOR_CUR" ] || [ "$K8S_TAG" != "$K8S_CUR" ]; then | ||
| CHANGED="true" | ||
| fi | ||
| echo "changed=$CHANGED" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Update image versions | ||
| if: steps.check.outputs.changed == 'true' | ||
| run: | | ||
| CO_TAG="${{ steps.co-release.outputs.tag }}" | ||
| K8S_TAG="${{ steps.k8scontent-release.outputs.tag }}" | ||
|
|
||
| sed -i 's|openscap-ocp:[^"]*|openscap-ocp:'"${CO_TAG}"'|' "$IMAGES_FILE" | ||
| sed -i 's|compliance-operator:[^"]*|compliance-operator:'"${CO_TAG}"'|' "$IMAGES_FILE" | ||
| sed -i 's|k8scontent:[^"]*|k8scontent:'"${K8S_TAG}"'|' "$IMAGES_FILE" | ||
|
|
||
| echo "Updated $IMAGES_FILE:" | ||
| grep -A2 'componentDefaults' "$IMAGES_FILE" | tail -5 | ||
|
|
||
| - name: Create pull request | ||
| if: steps.check.outputs.changed == 'true' | ||
| uses: peter-evans/create-pull-request@v7 | ||
| with: | ||
| commit-message: | | ||
| Update container image versions | ||
|
|
||
| openscap-ocp: ${{ steps.check.outputs.openscap }} -> ${{ steps.co-release.outputs.tag }} | ||
| compliance-operator: ${{ steps.check.outputs.operator }} -> ${{ steps.co-release.outputs.tag }} | ||
| k8scontent: ${{ steps.check.outputs.k8scontent }} -> ${{ steps.k8scontent-release.outputs.tag }} | ||
| title: "Update container image versions" | ||
| body: | | ||
| Automated update of pinned container image versions in `pkg/utils/images.go`. | ||
|
|
||
| | Image | Previous | New | | ||
| |-------|----------|-----| | ||
| | openscap-ocp | `${{ steps.check.outputs.openscap }}` | `${{ steps.co-release.outputs.tag }}` | | ||
| | compliance-operator | `${{ steps.check.outputs.operator }}` | `${{ steps.co-release.outputs.tag }}` | | ||
| | k8scontent | `${{ steps.check.outputs.k8scontent }}` | `${{ steps.k8scontent-release.outputs.tag }}` | | ||
| branch: automated/update-image-versions | ||
| delete-branch: true |
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14,9 +14,9 @@ var componentDefaults = []struct { | |||||||||||
| defaultImage string | ||||||||||||
| envVar string | ||||||||||||
| }{ | ||||||||||||
| {"ghcr.io/complianceascode/openscap-ocp:latest", "RELATED_IMAGE_OPENSCAP"}, | ||||||||||||
| {"ghcr.io/complianceascode/compliance-operator:latest", "RELATED_IMAGE_OPERATOR"}, | ||||||||||||
| {"ghcr.io/complianceascode/k8scontent:latest", "RELATED_IMAGE_PROFILE"}, | ||||||||||||
| {"ghcr.io/complianceascode/openscap-ocp:v1.7.0", "RELATED_IMAGE_OPENSCAP"}, | ||||||||||||
| {"ghcr.io/complianceascode/compliance-operator:v1.7.0", "RELATED_IMAGE_OPERATOR"}, | ||||||||||||
| {"ghcr.io/complianceascode/k8scontent:b01ffe68cc1320ee472408798bc56d83cfbfb1f7", "RELATED_IMAGE_PROFILE"}, | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should transition these images to use what we build from Konflux on every PR and merge. compliance-operator/bundle-hack/update_csv.go Lines 17 to 20 in c23fc6a
I think it makes sense to keep using a moving tag like In the pipeline we set the moving tag to be the name of the branch, so in this case it would be:
https://github.com/ComplianceAsCode/content/blob/f8760a00e700af1b78b9ff18f9bc07b178dd7a59/.tekton/compliance-operator-content-dev-push.yaml#L551
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We still need to do upstream release of CO 1.9.0, on |
||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| // GetComponentImage returns a full image pull spec for a given component | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this kind of doing what Konflux does already?
See for example:
We still need to setup some guidelines for auto-merge when these bumps pass all tests.