From a371627ccacccda131422fdf9c3bc8969ac3f8ef Mon Sep 17 00:00:00 2001 From: carole-lavillonniere Date: Mon, 31 Aug 2026 11:44:39 +0200 Subject: [PATCH] ci: add aggregate CI OK check so a skipped job cannot pass the gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ruleset requires the `build` check, but `build` has `needs: test`, so a failing `test` leaves `build` reporting "skipped" — and GitHub counts a skipped required check as satisfied. `test` is not itself required, so nothing blocked the merge: six Renovate PRs automerged onto a red `localstack` between Aug 22 and Aug 30. Add a `ci-ok` job depending on every other job that treats any result other than "success" as a failure. Requires a matching ruleset change to require `CI OK` in place of `build`; this commit alone does not close the hole. --- .github/workflows/build.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44a810e..9b9f1c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -71,3 +71,28 @@ jobs: files: bin/* generate_release_notes: true prerelease: ${{ inputs.prerelease || endsWith(github.ref, '-pre') || endsWith(inputs.version, '-pre') }} + + # Single aggregate check for the branch ruleset to require. + # + # `build` needs `test`, so a failing `test` leaves `build` reporting "skipped" — + # which GitHub counts as a passing required status check. That is how six + # Renovate PRs automerged onto a red `localstack` between Aug 22 and Aug 30. + # + # This job depends on every other job and treats anything other than "success" + # as a failure, so a skip can no longer masquerade as a pass. `if: always()` + # is required: without it the job would itself be skipped when an upstream job + # fails, and a required check that never reports blocks the PR as pending. + # Add new jobs to `needs` as they are introduced. + ci-ok: + name: CI OK + if: always() + needs: [test, build] + runs-on: ubuntu-latest + steps: + - name: Verify upstream jobs succeeded + env: + RESULTS: ${{ toJSON(needs) }} + run: | + echo "$RESULTS" + echo "$RESULTS" | jq -e 'to_entries | map(select(.value.result != "success")) | length == 0' > /dev/null \ + || { echo "::error::One or more upstream jobs did not succeed"; exit 1; }