name: PR Check

on: [ pull_request, merge_group ]

# When a new revision is pushed to a PR, cancel all in-progress CI runs for that
# PR. See https://docs.github.com/en/actions/using-jobs/using-concurrency
concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

permissions:
  contents: read
  security-events: write

jobs:
  # Check what types of changes this PR contains
  check-changes:
    name: Check what files changed
    runs-on: ubuntu-24.04
    outputs:
      go: ${{ steps.changes.outputs.go }}
      wasm: ${{ steps.changes.outputs.wasm }}
      docs: ${{ steps.changes.outputs.docs }}
      rego: ${{ steps.changes.outputs.rego }}
      yaml: ${{ steps.changes.outputs.yaml }}
      proto: ${{ steps.changes.outputs.proto }}
    steps:
    - name: Check out repository code
      # Shallow checkout for a faster clone; merge_group fetches the base below.
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Download OPA
      uses: open-policy-agent/setup-opa@b2b258e089860efaadaaf71bf6e3aecb4a3eeff1 # v2.4.0
      with:
        version: latest

    - name: Check for file changes
      id: changes
      run: | # zizmor: ignore[template-injection] These SHAs are generated by GitHub, not user-controlled.
        set -e

        # Default to running all checks
        echo "go=true" >> $GITHUB_OUTPUT
        echo "wasm=true" >> $GITHUB_OUTPUT
        echo "docs=true" >> $GITHUB_OUTPUT
        echo "rego=true" >> $GITHUB_OUTPUT
        echo "yaml=true" >> $GITHUB_OUTPUT
        echo "proto=true" >> $GITHUB_OUTPUT

        # Get changed files: use git diff for merge_group, PR API for pull_request
        if [ -n "${{ github.event.merge_group.base_sha }}" ]; then
          # Fetch just the base commit; shallow checkout above omits it.
          git fetch --no-tags --depth=1 origin "${{ github.event.merge_group.base_sha }}"
          git diff --name-only "${{ github.event.merge_group.base_sha }}" "${{ github.event.merge_group.head_sha }}" \
            | jq -R '{filename: .}' | jq -s '.' > changed_files.json
        elif ! curl -s -o changed_files.json -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
          "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files"; then
          echo "Error: Failed to fetch changed files from GitHub API"
          echo "Defaulting to running all checks (go=true, wasm=true, docs=true, rego=true, yaml=true, proto=true)"
          exit 0
        fi

        if [ ! -s changed_files.json ]; then
          echo "Warning: No changed files found"
          echo "Defaulting to running all checks (go=true, wasm=true, docs=true, rego=true, yaml=true, proto=true)"
          exit 0
        fi

        echo "Changed files:"
        jq -r '.[].filename' changed_files.json

        opa eval \
          --data build/policy/pr-check/pr_check.rego \
          --input changed_files.json \
          --format pretty \
          'data.policy["pr-check"].changes' > changes.json

        echo "Final outputs:"
        jq -r '
          ["go","wasm","docs","rego","yaml","proto"][] as $k |
          "\($k)=\(.[$k] // false)"
        ' changes.json | tee -a "$GITHUB_OUTPUT" | sed 's/^/  /'

  # All jobs essentially re-create the `ci-release-test` make target, but are split
  # up for parallel runners for faster PR feedback and a nicer UX.
  generate:
    name: Generate Code
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Generate
      run: make clean generate

    - name: Upload generated artifacts
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      with:
        name: generated
        path: |
          internal/compiler/wasm/opa
          capabilities.json

  go-build:
    name: Go Build (${{ matrix.os }}${{ matrix.arch && format(' {0}', matrix.arch) || '' }}${{ matrix.go_tags }})
    runs-on: ${{ matrix.run }}
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    strategy:
      fail-fast: false
      matrix:
        include:
        - os: linux
          run: ubuntu-24.04
          targets: ci-go-ci-build-linux ci-go-ci-build-linux-static
          arch: amd64
        - os: linux
          run: ubuntu-24.04
          targets: ci-go-ci-build-linux ci-go-ci-build-linux-static
          arch: arm64
        - os: windows
          run: ubuntu-24.04
          targets: ci-build-windows
          arch: amd64
        - os: darwin
          run: macos-15-intel
          targets: ci-build-darwin
          arch: amd64
        - os: darwin
          run: macos-15
          targets: ci-build-darwin ci-build-darwin-arm64-static
          arch: arm64
        - # NB(sr): We're only building this to see that it still builds.
          #         The resulting binary is not used in any other way.
          os: linux
          run: ubuntu-24.04
          targets: ci-build-linux-static
          go_tags: GO_TAGS="-tags=opa_no_oci"
          arch: arm64
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Go
      uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
      with:
        go-version-file: .go-version
      if: matrix.os != 'linux'
    - uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0
      with:
        install: true
        cache: true
        mise_toml: |
          [tools]
          zig = "0.16.0"
      if: matrix.os == 'windows'

    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated

    - name: Build
      run: make ${{ matrix.go_tags }} ${{ matrix.targets }}
      env:
        GOARCH: ${{ matrix.arch }}
      timeout-minutes: 30

    - name: Upload binaries - No Go tags
      uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
      if: ${{ matrix.go_tags == '' }}
      with:
        name: binaries-${{ matrix.os }}-${{ matrix.arch }}
        path: _release

  go-test:
    name: Go Test (${{ matrix.os }})
    runs-on: ${{ matrix.run }}
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    strategy:
      fail-fast: false
      matrix:
        include:
        - os: linux
          run: ubuntu-24.04
        - os: darwin
          run: macos-15
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Go
      uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
      with:
        go-version-file: .go-version

    - name: Install Node
      # docs/.nvmrc is the source of truth for the Node version across the repo.
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version-file: docs/.nvmrc

    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated

    - name: Unit Test Golang
      run: make test-coverage
      timeout-minutes: 30

    - name: E2E Test Golang
      run: make e2e

  go-lint:
    name: Go Lint
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Golang Style and Lint Check
      run: make check
      timeout-minutes: 30

  yaml-lint:
    name: YAML Lint
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.yaml == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: YAML Style and Lint Check
      run: make check-yaml-tests
      timeout-minutes: 30
      env:
        YAML_LINT_FORMAT: github

  proto-check:
    name: Proto Lint and Breaking
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.proto == 'true' }}
    steps:
      - name: Check out code
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false

      - name: Install buf
        uses: bufbuild/buf-setup-action@a47c93e0b1648d5651a065437926377d060baa99 # v1.50.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

      - name: buf lint
        run: buf lint

      - name: buf breaking against base
        # Bootstrap PR has no buf.yaml on the comparison ref — skip then.
        env:
          BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
        run: |
          set -euo pipefail
          if [ -n "${BASE_SHA:-}" ]; then
            git fetch --no-tags --depth=1 origin "$BASE_SHA"
            ref="$BASE_SHA"
          else
            git fetch --no-tags --depth=1 origin main
            ref="$(git rev-parse FETCH_HEAD)"
          fi
          if git show "${ref}:buf.yaml" >/dev/null 2>&1; then
            buf breaking --against ".git#ref=${ref}"
          else
            echo "Comparison ref ${ref} has no buf.yaml — bootstrap PR, skipping breaking-change check."
          fi

  gh-actions-lint:
    name: Github Actions Lint
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.yaml == 'true' }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          persist-credentials: false

      - name: Run zizmor
        uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7

  wasm:
    name: WASM
    runs-on: ubuntu-24.04
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.wasm == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated

    - name: Build and Test Wasm
      run: make ci-wasm
      timeout-minutes: 15

    - name: Build and Test Wasm SDK
      run: make ci-go-wasm-sdk-e2e-test
      timeout-minutes: 30
      env:
        DOCKER_RUNNING: 0

  check-generated:
    name: Check Generated
    runs-on: ubuntu-24.04
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated

    - name: Check Working Copy
      run: make ci-check-working-copy
      timeout-minutes: 15
      env:
        DOCKER_RUNNING: 0

  race-detector:
    name: Go Race Detector
    runs-on: ubuntu-24.04
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated

    - name: Test with Race Detector
      run: make ci-go-race-detector
      env:
        DOCKER_RUNNING: 0

  smoke-test-docker-images:
    name: docker image smoke test
    runs-on: ubuntu-24.04
    needs: [go-build, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Set up QEMU
      uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0
      with:
        platforms: arm64

    - name: Download release binaries
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        pattern: binaries-*
        merge-multiple: true
        path: _release

    - name: Test amd64 images
      run: make ci-image-smoke-test

    - name: Test arm64 images
      run: make ci-image-smoke-test
      env:
        GOARCH: arm64

  # Note(philipc): We only run the amd64 targets for windows/linux
  smoke-test-binaries:
    runs-on: ${{ matrix.run }}
    needs: [go-build, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    strategy:
      matrix:
        include:
        - os: linux
          run: ubuntu-24.04
          exec: opa_linux_amd64
          arch: amd64
        - os: linux
          run: ubuntu-24.04
          exec: opa_linux_amd64_static
          arch: amd64
          wasm: disabled
        - os: darwin
          run: macos-15-intel
          exec: opa_darwin_amd64
          arch: amd64
        - os: darwin
          run: macos-15
          exec: opa_darwin_arm64_static
          arch: arm64
          wasm: disabled
        - os: windows
          run: windows-latest
          exec: opa_windows_amd64.exe
          arch: amd64

    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Go
      uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
      with:
        go-version: stable

    - name: Download release binaries
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: binaries-${{ matrix.os }}-${{ matrix.arch }}
        path: _release

    - name: Prep tests
      run: cd build/tools && go install tool

    - name: CLI E2E tests
      run: |
        matches=($BINARY_PATH_GLOB) # expand glob
        export OPA="$(pwd)/${matches[0]}"
        chmod +x "$OPA"
        find . -type f -name '*.txtar' -path '*/script/*' -print0 \
          | xargs -0 -I{} testscript -e OPA {}
      shell: bash
      env:
        BINARY_PATH_GLOB: _release/*/${{ matrix.exec }}

    - name: wasm smoke test
      run: _release/*/${{ matrix.exec }} eval --target wasm 'time.now_ns()'
      shell: bash
      if: matrix.wasm != 'disabled'

  go-version-build:
    name: Go compat build/test
    needs: [generate, check-changes]
    if: ${{ needs.check-changes.outputs.go == 'true' }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-24.04, macos-15]
        version: ["1.25.7"]
    steps:
    - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false
    - name: Download generated artifacts
      uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
      with:
        name: generated
    - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
      with:
        go-version: ${{ matrix.version }}
    - run: make build
      env:
        DOCKER_RUNNING: 0
    - run: make go-test
      env:
        DOCKER_RUNNING: 0

  # Run PR metadata against Rego policies
  rego-check-pr:
    name: Rego PR checks
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.rego == 'true' }}
    steps:
    - name: Checkout code
      # Shallow checkout for a faster clone; merge_group fetches the base below.
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Download OPA
      uses: open-policy-agent/setup-opa@b2b258e089860efaadaaf71bf6e3aecb4a3eeff1 # v2.4.0
      with:
        version: edge

    - name: Test policies
      run: opa test --schema build/policy/schema --bundle build/policy

    - name: Test embedded Rego policies
      run: ./build/run-rego-tests.sh

    - name: Run file policy checks on changed files
      run: |
        if [ -n "${{ github.event.merge_group.base_sha }}" ]; then
          # Fetch just the base commit; shallow checkout above omits it.
          git fetch --no-tags --depth=1 origin "${{ github.event.merge_group.base_sha }}"
          git diff --name-only "${{ github.event.merge_group.base_sha }}" "${{ github.event.merge_group.head_sha }}" \
            | jq -R '{filename: .}' | jq -s '.' > files.json
        else
          curl --silent --fail --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' -o files.json \
            https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files
        fi

        opa eval --bundle build/policy --format values --input files.json  --fail-defined 'data.files.deny[message]'
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    - name: Download Regal
      uses: open-policy-agent/setup-regal@761188c3b435761fa254beca508a44875619648f # v2.0.0
      with:
        version: latest

    - name: Run Regal lint
      # Current configuration ensures anything but build/policy is ignored. While this could point Regal only at that
      # directory, this will serve as a reminder when more Rego policies are added, as they should be linted by default.
      run: regal lint --format github .

  docs-build:
    name: Build Docs
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Node
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version-file: docs/.nvmrc
        cache: npm
        cache-dependency-path: docs/package-lock.json

    - name: Build docs
      run: make docs-ci docs-build

  docs-fmt-check:
    name: Docs Format Check
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Node
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version-file: docs/.nvmrc
        cache: npm
        cache-dependency-path: docs/package-lock.json

    - name: Check docs formatting
      run: make docs-ci docs-fmt-check

  docs-lint-check:
    name: Docs Lint Check
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Node
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version-file: docs/.nvmrc
        cache: npm
        cache-dependency-path: docs/package-lock.json

    - name: Lint docs
      run: make docs-ci docs-lint-check

  docs-markdownlint-check:
    name: Docs Markdownlint Check
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Node
      uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
      with:
        node-version-file: docs/.nvmrc
        cache: npm
        cache-dependency-path: docs/package-lock.json

    - name: Check markdown linting
      run: make docs-ci docs-markdownlint-check

  docs-gen-check:
    name: Docs Gen Check
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Build OPA
      uses: ./.github/actions/build-opa

    - name: Check generated docs are up to date
      run: make docs-gen-check

  docs-spell-check:
    name: Docs Spell Check
    runs-on: ubuntu-24.04
    needs: check-changes
    if: ${{ needs.check-changes.outputs.docs == 'true' }}
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false

    - name: Install Vale
      run: |
        wget -O vale.tar.gz https://github.com/errata-ai/vale/releases/download/v3.13.0/vale_3.13.0_Linux_64-bit.tar.gz
        sudo tar xzf vale.tar.gz -C /usr/local/bin vale
        rm vale.tar.gz
        vale --version

    - name: Run Vale spell check
      run: make docs-spell-check

  benchmarks:
    name: Benchmarks
    needs: check-changes
    if: github.event_name == 'merge_group' && needs.check-changes.outputs.go == 'true'
    uses: ./.github/workflows/run-benchmarks.yaml
    with:
      publish: false

  test-ocp-with-opa:
    needs: check-changes
    if: github.event_name == 'merge_group' && needs.check-changes.outputs.go == 'true'
    uses: ./.github/workflows/test-ocp-with-opa.yaml

  test-regal-with-opa:
    needs: check-changes
    if: github.event_name == 'merge_group' && needs.check-changes.outputs.go == 'true'
    uses: ./.github/workflows/test-regal-with-opa.yaml

  # This job is required to complete before merging, and is set as a branch
  # protection rule:
  # https://github.com/open-policy-agent/opa/settings/branch_protection_rules
  pr-check-summary:
    name: PR Check Summary
    runs-on: ubuntu-24.04
    needs: [
      check-changes,
      generate,
      go-build,
      go-test,
      go-lint,
      yaml-lint,
      gh-actions-lint,
      proto-check,
      wasm,
      check-generated,
      race-detector,
      smoke-test-docker-images,
      smoke-test-binaries,
      go-version-build,
      rego-check-pr,
      docs-build,
      docs-fmt-check,
      docs-lint-check,
      docs-markdownlint-check,
      docs-gen-check,
      docs-spell-check,
      benchmarks,
      test-ocp-with-opa,
      test-regal-with-opa,
    ]
    if: always()
    steps:
    - name: Check out code
      uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
      with:
        persist-credentials: false
    - name: Download OPA
      uses: open-policy-agent/setup-opa@b2b258e089860efaadaaf71bf6e3aecb4a3eeff1 # v2.4.0
      with:
        version: edge
    - name: Check job results
      run: | # zizmor: ignore[template-injection] The 'needs' var is controlled by us.
        # Create the input file with all job results
        echo '${{ toJSON(needs) }}' > input.json

        # Find failed or cancelled jobs using OPA
        opa eval -d .github/workflows/pull-request.yaml \
        --input=input.json \
        '{job|some _, job in data.jobs["pr-check-summary"].needs} & {job | input[job].result in {"failure", "cancelled"}}' \
        --format=raw > failed_jobs.json

        # Check for failures and display a nice message
        if [ "$(cat failed_jobs.json)" != "[]" ]; then
          echo "The following required jobs did not complete successfully:"
          jq -r '.[]' failed_jobs.json | sed 's/^/- /'
          exit 1
        fi

        echo "All jobs completed successfully or were skipped"
