From 42fed74357765ee0b21e36f4b62004cf16a61cef Mon Sep 17 00:00:00 2001 From: davrad Date: Fri, 24 Jul 2026 18:45:42 +0200 Subject: [PATCH 1/9] ci: add image scanning step --- .github/workflows/pr-checks.yaml | 52 ++++++++++++++ .scripts/image-version.sh | 112 +++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100755 .scripts/image-version.sh diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index f96ef6b..e036895 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -322,3 +322,55 @@ jobs: name: terraform-validation-${{ matrix.target }}-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} path: ${{ env.REPORT_DIR }}/terraform + + extract-images: + needs: run-kubara-init-and-generate + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - name: Checkout CI scripts + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + sparse-checkout: | + .scripts + .github + + - name: Download generated kubara artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + name: kubara-generated-files-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} + + - name: Verify Helm + run: helm version --short + + - name: Extract container images + run: | + mkdir -p reports + IMAGE_OUTPUT_FILE="$PWD/reports/images.txt" + HELM_CHART_VERSION_FILE="$PWD/reports/chart.txt" + .scripts/image-version.sh + + - name: Write image summary + if: always() + run: | + [[ -f reports/images.txt ]] || exit 0 + echo "### Container Images" >> "$GITHUB_STEP_SUMMARY" + while read -r img; do + echo "- $img" >> "$GITHUB_STEP_SUMMARY" + done < reports/images.txt + [[ -f reports/chart.txt]] || exit 0 + echo "### Helm Chart Image Versions" >> "$GITHUB_STEP_SUMMARY" + while read -r img; do + echo "- $img" >> "$GITHUB_STEP_SUMMARY" + done < reports/chart.txt + + - name: Upload image list + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + if: always() + with: + name: container-images-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} + retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} + path: reports/images.txt + diff --git a/.scripts/image-version.sh b/.scripts/image-version.sh new file mode 100755 index 0000000..4651208 --- /dev/null +++ b/.scripts/image-version.sh @@ -0,0 +1,112 @@ +#!/usr/bin/env bash + + +# pipefail that pipes break +set -euo pipefail + +export PATH="$HOME/.local/bin/:$PATH" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +MANAGED="${MANAGED:-${PWD}/platform-components/helm}" +CONFIG_FILE="${CONFIG_FILE:-config.yaml}" + +[[ -f "$CONFIG_FILE" ]] || { echo "::error::Missing $CONFIG_FILE — run 'kubara generate' first (or cd into its output)"; exit 1; } + +CLUSTER_NAME="$(yq -r '.clusters[0].name' "$CONFIG_FILE")" +CONFIGS="${CONFIGS:-platform-configs/${CLUSTER_NAME}/helm}" +IMAGE_OUTPUT_FILE="${IMAGE_OUTPUT_FILE:-}" +HELM_IMAGE_OUTPUT_FILE="${HELM_IMAGE_OUTPUT_FILE:-}" + +[[ -d "$MANAGED" ]] || { echo "::error::Missing $MANAGED — run 'kubara generate' first"; exit 1; } +command -v helm >/dev/null 2>&1 || { echo "::error::helm not found on PATH"; exit 1; } +command -v yq >/dev/null 2>&1 || { echo "::error::yq not found on PATH"; exit 1; } + +KUBE_VERSION=$(yq -r '.clusters[0].terraform.kubernetesVersion' "$CONFIG_FILE") + +PROMETHEUS_STATUS="$(yq -r '.clusters[0].services."kube-prometheus-stack".status // "disabled"' "$CONFIG_FILE")" + +# helm template flags advertise the monitoring API only when +# kube-prometheus-stack is enabled, since some charts (eg. traefik) render +# ServiceMonitors guarded by a `fail` on monitoring.coreos.com/v1. +HELM_TEMPLATE_ARGS=(--kube-version "$KUBE_VERSION" --include-crds) +if [[ "$PROMETHEUS_STATUS" == enabled ]]; then + HELM_TEMPLATE_ARGS+=(--api-versions "monitoring.coreos.com/v1") +fi + + +echo "Rendering charts from $MANAGED (kube-version=$KUBE_VERSION)" >&2 + + +render_dir="$(mktemp -d)"; trap 'rm -rf "$render_dir"' EXIT +FAILED=() + +for chart_path in "$MANAGED"/*/; do + chart=$(basename "$chart_path") + [[ -f "$chart_path/Chart.yaml" ]] || continue + + # Don't render library charts + [[ "$(yq '.type // "application"' "$chart_path/Chart.yaml")" == library ]] && continue + + echo "Updating dependency for ${chart_path}" >&2 + + if ! dep_out=$(helm dependency update "$chart_path" 2>&1 >/dev/null ); then + echo "::error::helm dependency update failed for '$chart_path'"; echo "$dep_out" >&2 + FAILED+=("$chart:dependency-update"); continue + fi + + values_file="$CONFIGS/$chart/values.generated.yaml" + base_values=(); [[ -f "$values_file" ]] && base_values=(-f "$values_file") + + if ! helm template "${HELM_TEMPLATE_ARGS[@]}" \ + "$chart" "$chart_path" "${base_values[@]}" \ + > "$render_dir/$chart.yaml" 2> "$render_dir/$chart.err"; then + echo "::error::helm template for for '$chart':" + sed 's/^/ /' "$render_dir/$chart.err" >&2 + FAILED+=("$chart:template"); continue + fi +done + +# Note! This script does capture normal, init and sidecar containers, but by design +# misses out on runtime-injected images (e.g through webhooks, Kyverno etc.) +# and images refs passed via environment, this does not represent an exhaustive list of images +# captured +IMAGES="$( + cat "$render_dir"/*.yaml | + grep -E '^[[:space:]]*image:' || true | + sed -E "s/^[[:space:]]*image:[[:space:]]*//; s/[\"']//g" | + grep -vE '[*!]' | # drop kyverno wildcard/negation entries + grep -vE '^[[:space:]]*$' | + sort -u +)" + +echo "Done Rendering!" + +[[ -n "$IMAGES" ]] || { echo "::warning::No image references found"; exit 0; } + +if ((${#FAILED[@]})); then + echo "::warning:: Errors during templating: " + for err in "${FAILED[@]}"; do + echo "- $err" + done + exit 1 +fi + +if [[ -n "$IMAGE_OUTPUT_FILE" ]]; then + echo "$IMAGES" > "$IMAGE_OUTPUT_FILE" + echo "::notice::Image list written to $IMAGE_OUTPUT_FILE" +fi + +echo "$IMAGES" + +### Helm dependency part +echo "Extracting Helm Dependencies" +HELM_CHART_VERSIONS="$(find "$MANAGED" -name Chart.yaml -exec yq '.dependencies[] | select(.name != "template-library") | .name + ": " + .version' {} \;)" +echo "$HELM_CHART_VERSIONS" + +[[ -n "$HELM_CHART_VERSIONS" ]] || { echo "::warning::No helm image references found"; exit 0; } + + +if [[ -n "$HELM_IMAGE_OUTPUT_FILE" ]]; then + echo "$HELM_CHART_VERSIONS" > "$HELM_IMAGE_OUTPUT_FILE" + echo "::notice:: Helm Image list written to $HELM_IMAGE_OUTPUT_FILE" +fi From d3b3f747df3c4782e156e47a4b5fb9e4892b3f10 Mon Sep 17 00:00:00 2001 From: davrad Date: Fri, 24 Jul 2026 18:52:21 +0200 Subject: [PATCH 2/9] fix: remove ci dependency --- .github/workflows/action.yaml | 90 ++++++++++++++++++++++++++++++++ .github/workflows/pr-checks.yaml | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/action.yaml diff --git a/.github/workflows/action.yaml b/.github/workflows/action.yaml new file mode 100644 index 0000000..2b63b90 --- /dev/null +++ b/.github/workflows/action.yaml @@ -0,0 +1,90 @@ +--- +name: Generate platform +description: Renders a kubara platform from the working-tree catalogs. + +inputs: + kubara: + description: Path to the kubara binary. + required: true + kubara-scripts: + description: Path to the kubara repository's .scripts directory. + required: true + work-dir: + description: Directory to generate into. + required: true + provider: + description: Terraform provider. + default: stackit + kubernetes-type: + description: Kubernetes flavour. + default: ske + dns-name: + default: kubara-tst.stackit.run + project-id: + default: 00000000-0000-0000-0000-000000000000 + velero-s3-url: + default: https://object.storage.eu01.onstackit.cloud + +runs: + using: composite + steps: + - name: Generate platform + shell: bash + env: + HOME: ${{ runner.temp }}/kubara-home + KUBARA: ${{ inputs.kubara }} + SCRIPTS: ${{ inputs.kubara-scripts }} + WORK_DIR: ${{ inputs.work-dir }} + KUBARA_PROJECT_NAME: kubara + KUBARA_PROJECT_STAGE: tst + KUBARA_DOCKERCONFIG_BASE64: "000000" + KUBARA_ARGOCD_WIZARD_ACCOUNT_PASSWORD: "000000" + KUBARA_ARGOCD_HELM_REPO_USERNAME: git + KUBARA_ARGOCD_HELM_REPO_PASSWORD: "000000" + KUBARA_ARGOCD_HELM_REPO_URL: https://kubara.io/kubara.git + KUBARA_ARGOCD_GIT_HTTPS_URL: https://kubara.io/kubara.git + KUBARA_ARGOCD_GIT_PAT_OR_PASSWORD: "000000" + KUBARA_ARGOCD_GIT_USERNAME: git + KUBARA_CLUSTER_TYPE: hub + KUBARA_SSO_ORG: Kubara + KUBARA_SSO_TEAM: Test + KUBARA_KUBERNETES_VERSION: 1.35.0 + KUBARA_TERRAFORM_PROVIDER: ${{ inputs.provider }} + KUBARA_KUBERNETES_TYPE: ${{ inputs.kubernetes-type }} + KUBARA_DNS_NAME: ${{ inputs.dns-name }} + KUBARA_STACKIT_PROJECT_ID: ${{ inputs.project-id }} + KUBARA_VELERO_S3_URL: ${{ inputs.velero-s3-url }} + run: | + set -euo pipefail + bootstrap="${GITHUB_WORKSPACE}/bootstrap" + general="${GITHUB_WORKSPACE}/general" + mkdir -p "$WORK_DIR" + + # Cache the working-tree catalogs locally so `init` resolves them + # without reaching for the published versions. + for catalog in bootstrap general; do + (cd "$catalog" && "$KUBARA" catalog package "oci://ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/") + done + + "$KUBARA" --work-dir "$WORK_DIR" init --prep + "$SCRIPTS/kubara-env-update.sh" "$WORK_DIR/.env" + "$KUBARA" --work-dir "$WORK_DIR" --catalog "$general" --catalog-overwrite init + "$SCRIPTS/kubara-config-update.sh" "$WORK_DIR/config.yaml" + + # `init` writes the CLI's pinned catalog refs (…/general:1.1.0) into + # config.yaml. Left alone, `generate` would render the PUBLISHED catalog + # instead of this working tree — silently wrong on any version bump. + BOOTSTRAP="$bootstrap" GENERAL="$general" yq eval ' + .bootstrapCatalog = strenv(BOOTSTRAP) | + .clusters[].catalogs = [strenv(GENERAL)] + ' -i "$WORK_DIR/config.yaml" + + yq eval ' + .clusters[0].services[].status = "enabled" | + .clusters[0].services.metallb.config.publicLoadBalancerIPs = "192.0.2.10" | + .clusters[0].services.metallb.config.loadBalancerAddressPool = ["192.0.2.10-192.0.2.20"] | + .clusters[0].services.velero.config.backupStorage.bucketName = "kubara-ci-velero" | + .clusters[0].services.velero.config.backupStorage.s3Url = strenv(KUBARA_VELERO_S3_URL) + ' -i "$WORK_DIR/config.yaml" + + "$KUBARA" --work-dir "$WORK_DIR" generate diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index e036895..da8310a 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -360,7 +360,7 @@ jobs: while read -r img; do echo "- $img" >> "$GITHUB_STEP_SUMMARY" done < reports/images.txt - [[ -f reports/chart.txt]] || exit 0 + [[ -f reports/chart.txt ]] || exit 0 echo "### Helm Chart Image Versions" >> "$GITHUB_STEP_SUMMARY" while read -r img; do echo "- $img" >> "$GITHUB_STEP_SUMMARY" From e00a0e4f6d9c40aad31b2bed754b860e2b577e1a Mon Sep 17 00:00:00 2001 From: davrad Date: Fri, 24 Jul 2026 19:58:37 +0200 Subject: [PATCH 3/9] ci: use kubara binary --- .github/workflows/pr-checks.yaml | 15 +++++++-------- .scripts/image-version.sh | 10 +++++----- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index da8310a..002b143 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -87,13 +87,11 @@ jobs: KUBARA_KUBERNETES_TYPE: ${{ matrix.kubernetes_type }} KUBARA_KUBERNETES_VERSION: 1.35.0 steps: - - name: Checkout catalogs - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - # Needed in both acquisition modes: the job below runs kubara's helper - # scripts (.ci/kubara/.scripts/*.sh) regardless of how the CLI is obtained. - - name: Checkout kubara - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Setup Go + uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: repository: kubara-io/kubara ref: ${{ env.KUBARA_REF }} @@ -346,10 +344,11 @@ jobs: run: helm version --short - name: Extract container images + env: + IMAGE_OUTPUT_FILE: ${{ github.workspace }}/reports/image.txt + HELM_CHART_VERSION_FILE: ${{ github.workspace }}/reports/chart.txt" run: | mkdir -p reports - IMAGE_OUTPUT_FILE="$PWD/reports/images.txt" - HELM_CHART_VERSION_FILE="$PWD/reports/chart.txt" .scripts/image-version.sh - name: Write image summary diff --git a/.scripts/image-version.sh b/.scripts/image-version.sh index 4651208..f918b8b 100755 --- a/.scripts/image-version.sh +++ b/.scripts/image-version.sh @@ -15,7 +15,7 @@ CONFIG_FILE="${CONFIG_FILE:-config.yaml}" CLUSTER_NAME="$(yq -r '.clusters[0].name' "$CONFIG_FILE")" CONFIGS="${CONFIGS:-platform-configs/${CLUSTER_NAME}/helm}" IMAGE_OUTPUT_FILE="${IMAGE_OUTPUT_FILE:-}" -HELM_IMAGE_OUTPUT_FILE="${HELM_IMAGE_OUTPUT_FILE:-}" +HELM_CHART_VERSION_FILE="${HELM_CHART_VERSION_FILE:-}" [[ -d "$MANAGED" ]] || { echo "::error::Missing $MANAGED — run 'kubara generate' first"; exit 1; } command -v helm >/dev/null 2>&1 || { echo "::error::helm not found on PATH"; exit 1; } @@ -72,7 +72,7 @@ done # captured IMAGES="$( cat "$render_dir"/*.yaml | - grep -E '^[[:space:]]*image:' || true | + { grep -E '^[[:space:]]*image:' || true; } | sed -E "s/^[[:space:]]*image:[[:space:]]*//; s/[\"']//g" | grep -vE '[*!]' | # drop kyverno wildcard/negation entries grep -vE '^[[:space:]]*$' | @@ -106,7 +106,7 @@ echo "$HELM_CHART_VERSIONS" [[ -n "$HELM_CHART_VERSIONS" ]] || { echo "::warning::No helm image references found"; exit 0; } -if [[ -n "$HELM_IMAGE_OUTPUT_FILE" ]]; then - echo "$HELM_CHART_VERSIONS" > "$HELM_IMAGE_OUTPUT_FILE" - echo "::notice:: Helm Image list written to $HELM_IMAGE_OUTPUT_FILE" +if [[ -n "$HELM_CHART_VERSION_FILE" ]]; then + echo "$HELM_CHART_VERSIONS" > "$HELM_CHART_VERSION_FILE" + echo "::notice:: Helm Image list written to $HELM_CHART_VERSION_FILE" fi From b92b0d68b82954b45bf0ecaf9c61e6c1060c6db1 Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 00:42:08 +0200 Subject: [PATCH 4/9] ci: update image scanning for publishing steps --- .github/workflows/pr-checks.yaml | 25 +++++++++++++++---------- .scripts/image-version.sh | 6 ++++-- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index 002b143..e19f0fb 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -87,11 +87,11 @@ jobs: KUBARA_KUBERNETES_TYPE: ${{ matrix.kubernetes_type }} KUBARA_KUBERNETES_VERSION: 1.35.0 steps: - - name: Checkout - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Checkout catalogs + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - name: Setup Go - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 + - name: Checkout kubara + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: kubara-io/kubara ref: ${{ env.KUBARA_REF }} @@ -322,8 +322,12 @@ jobs: path: ${{ env.REPORT_DIR }}/terraform extract-images: - needs: run-kubara-init-and-generate + needs: integration-generate runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + target: [stackit-ske] defaults: run: shell: bash @@ -338,15 +342,16 @@ jobs: - name: Download generated kubara artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: - name: kubara-generated-files-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} + name: kubara-generated-${{ matrix.target }}-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} - name: Verify Helm run: helm version --short - name: Extract container images env: - IMAGE_OUTPUT_FILE: ${{ github.workspace }}/reports/image.txt - HELM_CHART_VERSION_FILE: ${{ github.workspace }}/reports/chart.txt" + IMAGE_OUTPUT_FILE: ${{ github.workspace }}/reports/images.txt + HELM_CHART_VERSION_FILE: ${{ github.workspace }}/reports/chart.txt + run: | mkdir -p reports .scripts/image-version.sh @@ -369,7 +374,7 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 if: always() with: - name: container-images-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} + name: container-images-${{ matrix.target }}-${{ github.run_attempt }}-${{ github.sha }}-${{ github.run_number }} retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} - path: reports/images.txt + path: reports/ diff --git a/.scripts/image-version.sh b/.scripts/image-version.sh index f918b8b..e19337d 100755 --- a/.scripts/image-version.sh +++ b/.scripts/image-version.sh @@ -71,6 +71,7 @@ done # and images refs passed via environment, this does not represent an exhaustive list of images # captured IMAGES="$( + shopt -s nullglob # prevents failing if nothing's matched cat "$render_dir"/*.yaml | { grep -E '^[[:space:]]*image:' || true; } | sed -E "s/^[[:space:]]*image:[[:space:]]*//; s/[\"']//g" | @@ -81,16 +82,17 @@ IMAGES="$( echo "Done Rendering!" -[[ -n "$IMAGES" ]] || { echo "::warning::No image references found"; exit 0; } +# errors during templating are listed, but not critical for extraction if ((${#FAILED[@]})); then echo "::warning:: Errors during templating: " for err in "${FAILED[@]}"; do echo "- $err" done - exit 1 fi +[[ -n "$IMAGES" ]] || { echo "::warning::No image references found"; exit 0; } + if [[ -n "$IMAGE_OUTPUT_FILE" ]]; then echo "$IMAGES" > "$IMAGE_OUTPUT_FILE" echo "::notice::Image list written to $IMAGE_OUTPUT_FILE" From dbcdd15b1d774c6d5e294695b19ab0e2c252e376 Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 11:12:20 +0200 Subject: [PATCH 5/9] ci: publish images alongside catalog --- .../generate-platform}/action.yaml | 0 .github/workflows/publish-catalog.yaml | 125 ++++++++++++++++++ .scripts/image-version.sh | 12 +- 3 files changed, 131 insertions(+), 6 deletions(-) rename .github/{workflows => actions/generate-platform}/action.yaml (100%) diff --git a/.github/workflows/action.yaml b/.github/actions/generate-platform/action.yaml similarity index 100% rename from .github/workflows/action.yaml rename to .github/actions/generate-platform/action.yaml diff --git a/.github/workflows/publish-catalog.yaml b/.github/workflows/publish-catalog.yaml index c7a3d92..de881df 100644 --- a/.github/workflows/publish-catalog.yaml +++ b/.github/workflows/publish-catalog.yaml @@ -17,11 +17,20 @@ concurrency: env: # renovate: datasource=github-releases depName=kubara-io/kubara KUBARA_REF: "v0.13.0" + OUTPUT_GENERATED_DIR: ${{ github.workspace }}/output-generated + # setup-oras requires version without "v" in "vX.X.X" + # renovate: datasource=github-releases depName=oras-project/oras extractVersion=^v(?.*)$ + ORAS_VERSION: "1.3.1" + REPORT_DIR: ${{ github.workspace }}/reports + ARTIFACT_RETENTION_DAYS: "15" jobs: publish: name: Publish catalog runs-on: ubuntu-latest + outputs: + catalog: ${{ steps.release.outputs.catalog }} + version: ${{ steps.release.outputs.version }} steps: - name: Checkout catalogs uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 @@ -108,3 +117,119 @@ jobs: "${RUNNER_TEMP}/kubara" catalog package \ "oci://ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/" "${RUNNER_TEMP}/kubara" catalog push "$CATALOG_REF" + + extract-images: + name: Extract container images + needs: publish + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + defaults: + run: + shell: bash + steps: + - name: Checkout catalogs + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Checkout kubara + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: kubara-io/kubara + ref: ${{ env.KUBARA_REF }} + path: .ci/kubara + + - name: Install kubara release + env: + KUBARA_VERSION: ${{ env.KUBARA_REF }} + run: | + set -euo pipefail + version="${KUBARA_VERSION#v}" + archive="kubara_${version}_linux_amd64.tar.gz" + checksums="kubara_${version}_checksums.txt" + base_url="https://github.com/kubara-io/kubara/releases/download/${KUBARA_VERSION}" + temp_dir="$(mktemp -d)" + trap 'rm -rf "$temp_dir"' EXIT + curl -fsSL "$base_url/$archive" -o "$temp_dir/$archive" + curl -fsSL "$base_url/$checksums" -o "$temp_dir/$checksums" + checksum="$(awk -v file="$archive" '$2 == file {print $1}' "$temp_dir/$checksums")" + [[ -n "$checksum" ]] + echo "$checksum $temp_dir/$archive" | sha256sum -c - + tar xzf "$temp_dir/$archive" -C "$RUNNER_TEMP" kubara + chmod +x "$RUNNER_TEMP/kubara" + + - name: Install oras + uses: oras-project/setup-oras@1d808f7d7f6995cc68b7bf507bfe5c5446e1dc9d # v2.0.1 + with: + version: ${{ env.ORAS_VERSION }} + + + - name: Generate platform + uses: ./.github/actions/generate-platform + with: + kubara: ${{ runner.temp }}/kubara + kubara-scripts: ${{ github.workspace }}/.ci/kubara/.scripts + work-dir: ${{ env.OUTPUT_GENERATED_DIR }} + + - name: Extract container images + working-directory: ${{ env.OUTPUT_GENERATED_DIR }} + env: + IMAGE_OUTPUT_FILE: ${{ env.REPORT_DIR }}/images.txt + HELM_CHART_VERSION_FILE: ${{ env.REPORT_DIR }}/chart.txt + run: | + mkdir -p "$REPORT_DIR" + "${GITHUB_WORKSPACE}/.scripts/image-version.sh" + + - name: Write image summary + if: always() + run: | + [[ -f "$REPORT_DIR/images.txt" ]] || exit 0 + echo "### Container Images" >> "$GITHUB_STEP_SUMMARY" + while read -r img; do + echo "- $img" >> "$GITHUB_STEP_SUMMARY" + done < "$REPORT_DIR/images.txt" + [[ -f "$REPORT_DIR/chart.txt" ]] || exit 0 + echo "### Helm Chart Image Versions" >> "$GITHUB_STEP_SUMMARY" + while read -r img; do + echo "- $img" >> "$GITHUB_STEP_SUMMARY" + done < "$REPORT_DIR/chart.txt" + + - name: Push image lists alongside catalog + env: + GHCR_TOKEN: ${{ github.token }} + CATALOG: ${{ needs.publish.outputs.catalog }} + VERSION: ${{ needs.publish.outputs.version }} + run: | + set -euo pipefail + cd "$REPORT_DIR" + + files=() + for report in images chart; do + if [[ -f "${report}.txt" ]]; then + files+=("${report}.txt:text/plain") + fi + done + if ((${#files[@]} == 0)); then + echo "::error::No image reports produced; nothing to push" + exit 1 + fi + + endpoint="ghcr.io/%{GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}" + printf '%s\n' "$GHCR_TOKEN" | + oras login ghcr.io --username "$GITHUB_ACTOR" --password-stdin + + oras attach "$endpoint" \ + --artifact-type application/vnd.kubara.catalog.images.v1+text \ + "${files[@]}" + + echo "::notice::Attached image list to $endpoint" + + + + - name: Upload image list + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + if: always() + with: + name: container-images-${{ github.ref_name }}-${{ github.run_attempt }} + retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }} + path: ${{ env.REPORT_DIR }}/ diff --git a/.scripts/image-version.sh b/.scripts/image-version.sh index e19337d..02b3979 100755 --- a/.scripts/image-version.sh +++ b/.scripts/image-version.sh @@ -91,12 +91,6 @@ if ((${#FAILED[@]})); then done fi -[[ -n "$IMAGES" ]] || { echo "::warning::No image references found"; exit 0; } - -if [[ -n "$IMAGE_OUTPUT_FILE" ]]; then - echo "$IMAGES" > "$IMAGE_OUTPUT_FILE" - echo "::notice::Image list written to $IMAGE_OUTPUT_FILE" -fi echo "$IMAGES" @@ -105,8 +99,14 @@ echo "Extracting Helm Dependencies" HELM_CHART_VERSIONS="$(find "$MANAGED" -name Chart.yaml -exec yq '.dependencies[] | select(.name != "template-library") | .name + ": " + .version' {} \;)" echo "$HELM_CHART_VERSIONS" +# If either no images are found nor chart versions exit +[[ -n "$IMAGES" ]] || { echo "::warning::No image references found"; exit 0; } [[ -n "$HELM_CHART_VERSIONS" ]] || { echo "::warning::No helm image references found"; exit 0; } +if [[ -n "$IMAGE_OUTPUT_FILE" ]]; then + echo "$IMAGES" > "$IMAGE_OUTPUT_FILE" + echo "::notice::Image list written to $IMAGE_OUTPUT_FILE" +fi if [[ -n "$HELM_CHART_VERSION_FILE" ]]; then echo "$HELM_CHART_VERSIONS" > "$HELM_CHART_VERSION_FILE" From 512d10af5d0ffadec3eb315c2363e388bc969747 Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 12:51:59 +0200 Subject: [PATCH 6/9] ci: change typo --- .github/workflows/publish-catalog.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-catalog.yaml b/.github/workflows/publish-catalog.yaml index de881df..adc41a7 100644 --- a/.github/workflows/publish-catalog.yaml +++ b/.github/workflows/publish-catalog.yaml @@ -214,7 +214,8 @@ jobs: exit 1 fi - endpoint="ghcr.io/%{GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}" + endpoint="ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}:${VERSION}" + printf '%s\n' "$GHCR_TOKEN" | oras login ghcr.io --username "$GITHUB_ACTOR" --password-stdin From 298b999bd11863e69696714b9d986c38266ddeca Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 14:08:47 +0200 Subject: [PATCH 7/9] fix: use correct endpoint --- .github/workflows/publish-catalog.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-catalog.yaml b/.github/workflows/publish-catalog.yaml index adc41a7..578e73a 100644 --- a/.github/workflows/publish-catalog.yaml +++ b/.github/workflows/publish-catalog.yaml @@ -214,12 +214,13 @@ jobs: exit 1 fi - endpoint="ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}:${VERSION}" + endpoint="ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}-images:${VERSION}" + printf '%s\n' "$GHCR_TOKEN" | oras login ghcr.io --username "$GITHUB_ACTOR" --password-stdin - oras attach "$endpoint" \ + oras push "$endpoint" \ --artifact-type application/vnd.kubara.catalog.images.v1+text \ "${files[@]}" From 6319698d6393955377649a756c3c39ae24ee0b3a Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 14:39:08 +0200 Subject: [PATCH 8/9] fix: disable rbacPrometheus for correct rendering --- general/platform-components/helm/metallb/CHANGELOG.md | 4 ++++ general/platform-components/helm/metallb/Chart.yaml | 2 +- general/platform-components/helm/metallb/values.yaml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/general/platform-components/helm/metallb/CHANGELOG.md b/general/platform-components/helm/metallb/CHANGELOG.md index 8df8f48..9213f4a 100644 --- a/general/platform-components/helm/metallb/CHANGELOG.md +++ b/general/platform-components/helm/metallb/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.2.1] - 2026-08-05 +### Fixed +- Disable `prometheus.rbacPrometheus` as permissions are already present in a seperate ClusterRole and it prevents rendering of the helm charts + ## [0.2.0] - 2026-07-10 ### Changed - Bump template-library dependency to 0.2.0 diff --git a/general/platform-components/helm/metallb/Chart.yaml b/general/platform-components/helm/metallb/Chart.yaml index 853022e..4ac2aed 100644 --- a/general/platform-components/helm/metallb/Chart.yaml +++ b/general/platform-components/helm/metallb/Chart.yaml @@ -3,7 +3,7 @@ apiVersion: v2 name: metallb description: Umbrella Chart for metalb type: application -version: 0.2.0 +version: 0.2.1 dependencies: - name: template-library repository: file://../template-library diff --git a/general/platform-components/helm/metallb/values.yaml b/general/platform-components/helm/metallb/values.yaml index f60606a..983282e 100644 --- a/general/platform-components/helm/metallb/values.yaml +++ b/general/platform-components/helm/metallb/values.yaml @@ -36,6 +36,10 @@ metallb: limits: memory: 100Mi prometheus: + # kube-prometheus-stack binds prometheus to a ClusterRole with the appopriate permissions already + # Setting it to true which is the default would not enable something new here + # Re-enable (and set serviceAccount/namespace) only if Prometheus loses cluster discover e.g metallb showing zero targets + rbacPrometheus: false serviceMonitor: enabled: true frr-k8s: From 951b850a77d6890c238595a997fa6a77b85972f0 Mon Sep 17 00:00:00 2001 From: davrad Date: Wed, 5 Aug 2026 16:42:14 +0200 Subject: [PATCH 9/9] ci: add latest tag for images.txt --- .github/workflows/publish-catalog.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/publish-catalog.yaml b/.github/workflows/publish-catalog.yaml index 578e73a..3e63dbf 100644 --- a/.github/workflows/publish-catalog.yaml +++ b/.github/workflows/publish-catalog.yaml @@ -214,8 +214,7 @@ jobs: exit 1 fi - endpoint="ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}-images:${VERSION}" - + endpoint="ghcr.io/${GITHUB_REPOSITORY_OWNER}/catalogs/${CATALOG}-images:${VERSION},latest" printf '%s\n' "$GHCR_TOKEN" | oras login ghcr.io --username "$GITHUB_ACTOR" --password-stdin