diff --git a/.github/workflows/create-release.yaml b/.github/workflows/create-release.yaml index b597a404..cc51a221 100644 --- a/.github/workflows/create-release.yaml +++ b/.github/workflows/create-release.yaml @@ -156,6 +156,17 @@ jobs: ./utils/render_catalog.sh done + - name: Validate updated catalog sources + env: + FBC_DIR: ${{ github.event.inputs.fbc_dir }} + VERSIONS: ${{ github.event.inputs.ocp_versions }} + run: | + IFS=',' read -ra versions <<< "${VERSIONS}" + for version in "${versions[@]}"; do + version="${version//[[:space:]]/}" + ./utils/validate_fbc_graph_sync.sh "${version}/${FBC_DIR}" + done + - name: Stage catalog changes run: git add . diff --git a/.github/workflows/sync-catalog.yaml b/.github/workflows/sync-catalog.yaml index bafd8015..b3a290eb 100644 --- a/.github/workflows/sync-catalog.yaml +++ b/.github/workflows/sync-catalog.yaml @@ -65,8 +65,7 @@ jobs: yq eval -i 'del(.entries[] | select(.schema == "io.openshift.operators.lifecycles.v1alpha1"))' $OCP_VERSION/$PACKAGE_NAME/graph.yaml FBC_DIR=$PACKAGE_NAME CATALOG_FILE="$OCP_VERSION/$PACKAGE_NAME/catalog/$PACKAGE_NAME/catalog.json" ./utils/render_catalog.sh - echo "Validating ${{ matrix.ocp_version }}/$PACKAGE_NAME/catalog/$PACKAGE_NAME" - opm validate ${{ matrix.ocp_version }}/$PACKAGE_NAME/catalog/$PACKAGE_NAME/ + ./utils/validate_fbc_graph_sync.sh "${OCP_VERSION}/${PACKAGE_NAME}" done # FIX 1: Tar the output to preserve directory structure - name: Compress Artifacts diff --git a/.github/workflows/validate-fbc-catalogs.yaml b/.github/workflows/validate-fbc-catalogs.yaml new file mode 100644 index 00000000..11ac1424 --- /dev/null +++ b/.github/workflows/validate-fbc-catalogs.yaml @@ -0,0 +1,41 @@ +name: FBC source validation + +on: + pull_request: + push: + branches: + - main + - 'release-*' + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: fbc-source-validation-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: Validate changed FBC catalogs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Install OPM + uses: ./.github/actions/install-opm + + - name: Validate catalog sources + env: + BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" || -z "${BASE_SHA}" ]]; then + ./utils/validate_changed_fbc_catalogs.sh --all + else + ./utils/validate_changed_fbc_catalogs.sh "${BASE_SHA}" "${HEAD_SHA}" + fi diff --git a/README.md b/README.md index 941e77c3..b44fe0e0 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,8 @@ Releases in this repository follow a snapshot-based workflow. First, candidate r ## Validating a Catalog Locally -Run the same graph and catalog validation used by the FBC builder pipeline by -passing the catalog context to the validation script: +Run the same graph and catalog validation used by repository CI by passing the +catalog context to the validation script: ```bash ./utils/validate_fbc_graph_sync.sh v4.20/rhtas-operator @@ -35,3 +35,14 @@ passing the catalog context to the validation script: The script requires `opm` and `jq`. It validates both the committed catalog and its synchronization with `graph.yaml`. + +GitHub Actions runs the `Validate changed FBC catalogs` check for every pull +request and for every commit pushed to `main` or a `release-*` branch. Changes +to validation tooling cause all catalogs to be checked; otherwise only changed +catalog contexts are validated. + +The release-creation and nightly synchronization workflows run this validation +before creating their signed commits. This prevents invalid automated catalog +content from being pushed and triggering a Konflux snapshot. A Release CR must +only reference a snapshot whose source commit has a successful `Validate changed +FBC catalogs` check. diff --git a/utils/validate_changed_fbc_catalogs.sh b/utils/validate_changed_fbc_catalogs.sh new file mode 100755 index 00000000..f0f2d786 --- /dev/null +++ b/utils/validate_changed_fbc_catalogs.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd "${script_dir}/.." && pwd)" +cd "${repo_root}" + +usage() { + echo "Usage: $0 --all | [head-revision]" >&2 +} + +all_contexts() { + find . -mindepth 3 -maxdepth 3 -type f -name graph.yaml -path './v*/*/graph.yaml' \ + | sed -e 's#^\./##' -e 's#/graph.yaml$##' \ + | sort -u +} + +if [[ $# -eq 1 && "$1" == "--all" ]]; then + mapfile -t contexts < <(all_contexts) +elif [[ $# -ge 1 && $# -le 2 ]]; then + base_revision="$1" + head_revision="${2:-HEAD}" + + if ! git cat-file -e "${head_revision}^{commit}" 2>/dev/null; then + echo "Head revision ${head_revision} does not resolve to a commit." >&2 + exit 2 + fi + + if [[ "${base_revision}" =~ ^0+$ ]] || ! git cat-file -e "${base_revision}^{commit}" 2>/dev/null; then + echo "Base revision is unavailable; validating all catalogs." + mapfile -t contexts < <(all_contexts) + else + changed_files="$( + git diff --name-status --find-renames --find-copies --diff-filter=ACDMRT \ + "${base_revision}" "${head_revision}" \ + | awk -F '\t' ' + $1 ~ /^[RC]/ { + print $2 + print $3 + next + } + { + print $2 + } + ' + )" + + if grep -Eq '^utils/|^\.github/actions/install-opm/action\.yaml$|^\.github/workflows/(create-release|sync-catalog|validate-fbc-catalogs)\.yaml$' \ + <<< "${changed_files}"; then + echo "Validation tooling changed; validating all catalogs." + mapfile -t contexts < <(all_contexts) + else + mapfile -t contexts < <( + awk -F/ ' + $1 ~ /^v[0-9]+\.[0-9]+$/ && + NF >= 3 && + ($3 == "graph.yaml" || $3 == "catalog") { + print $1 "/" $2 + } + ' <<< "${changed_files}" | sort -u + ) + fi + fi +else + usage + exit 2 +fi + +if [[ ${#contexts[@]} -eq 0 ]]; then + echo "No changed FBC catalogs require validation." + exit 0 +fi + +echo "Catalog contexts to validate:" +printf ' %s\n' "${contexts[@]}" + +failed=0 +for context in "${contexts[@]}"; do + if [[ ! -d "${context}" ]]; then + echo "Catalog context ${context} was removed; skipping." + continue + fi + + if ! "${script_dir}/validate_fbc_graph_sync.sh" "${context}"; then + failed=1 + fi +done + +exit "${failed}"