Repository navigation
fix(ci): restore the required-check producers — allow-list, actions.lock gate, K9 pedigree #5
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This workflow is managed by gh actions-lock. | |
| # SPDX-License-Identifier: MPL-2.0 | |
| # | |
| # actions-lock.yml — keep .github/workflows/actions.lock in step with the | |
| # workflows themselves. | |
| # | |
| # Why this exists: an out-of-date lockfile is not a soft failure. Every | |
| # workflow listed in actions.lock dies with `startup_failure` before a single | |
| # step runs, so it produces no check runs at all — which is how | |
| # game-server-admin#103 took out both required-check producers (`ABI Contract` | |
| # and `Cross-Platform Build & Test`) at once. Dependabot bumps action tags on a | |
| # weekly schedule and cannot run `gh actions-lock`, so without a gate here the | |
| # next group bump re-breaks the whole CI estate, silently. | |
| # | |
| # The gate has two halves: | |
| # verify — read-only (`gh actions-lock --verify`). Fails when the lockfile | |
| # and the workflows disagree, so a bump cannot merge unrelocked. | |
| # relock — runs only when verify failed. Regenerates the lockfile and | |
| # delivers it: pushed straight back to the branch on a pull | |
| # request, or opened as a PR when the target is the default branch | |
| # (main requires signed commits, so a bot cannot push there). | |
| # | |
| # A push made with GITHUB_TOKEN does not start a new workflow run, so the | |
| # relock commit cannot loop. | |
| name: Actions Lockfile | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main, master] | |
| workflow_dispatch: | |
| inputs: | |
| mode: | |
| description: 'verify = report only; relock = regenerate and deliver' | |
| required: false | |
| default: 'verify' | |
| type: choice | |
| options: | |
| - verify | |
| - relock | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: actions-lockfile-${{ github.ref }} | |
| cancel-in-progress: false | |
| env: | |
| # Bump deliberately: the lockfile format is pre-1.0 and its shape can | |
| # change between releases. | |
| ACTIONS_LOCK_EXTENSION_VERSION: v0.1.7-rc.1 | |
| jobs: | |
| verify: | |
| name: Verify actions.lock | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| outputs: | |
| # `relock` is computed in the shell, not in an `if:` expression: | |
| # `inputs.mode` is not a recognised named value outside | |
| # workflow_dispatch, and referencing it there is a start-up error. | |
| in_sync: ${{ steps.check.outputs.in_sync }} | |
| relock: ${{ steps.check.outputs.relock }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| - name: Install gh actions-lock | |
| run: | | |
| set -euo pipefail | |
| gh extension install github/gh-actions-lock --pin "$ACTIONS_LOCK_EXTENSION_VERSION" | |
| gh actions-lock --help | |
| - name: Check the lockfile matches the workflows | |
| id: check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| EVENT_NAME: ${{ github.event_name }} | |
| DISPATCH_MODE: ${{ github.event.inputs.mode }} | |
| run: | | |
| set -uo pipefail | |
| code=0 | |
| gh actions-lock --verify --no-interactive \ | |
| --json=valid,findings > actions-lock-report.json 2>actions-lock-report.err \ | |
| || code=$? | |
| echo "gh actions-lock --verify exited ${code}" | tee -a "$GITHUB_STEP_SUMMARY" | |
| if [ "$code" -eq 0 ]; then | |
| echo "in_sync=true" >> "$GITHUB_OUTPUT" | |
| # An explicit relock dispatch still wins even when the file looks | |
| # fine: it is how a maintainer refreshes pins that have moved. | |
| if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ "$DISPATCH_MODE" = "relock" ]; then | |
| echo "relock=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "relock=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "actions.lock agrees with every workflow." >> "$GITHUB_STEP_SUMMARY" | |
| exit 0 | |
| fi | |
| if [ "$code" -ne 1 ]; then | |
| # 1 = blocking findings (out of sync). Anything else is the tool | |
| # failing, not the repo: do not let the relock job paper over it. | |
| # Re-emit the tool's stderr as annotations — a bare exit code on a | |
| # runner nobody can read logs from is worse than a verbose diff. | |
| echo "in_sync=unknown" >> "$GITHUB_OUTPUT" | |
| echo "relock=false" >> "$GITHUB_OUTPUT" | |
| echo "::error::gh actions-lock --verify exited ${code} (tool failure, not a lockfile mismatch)" | |
| while IFS= read -r line; do | |
| [ -n "$line" ] && echo "::error::[gh actions-lock] ${line}" | |
| done < <(tail -n 30 actions-lock-report.err | tr -d '\r' | cut -c1-200) | |
| exit "$code" | |
| fi | |
| echo "in_sync=false" >> "$GITHUB_OUTPUT" | |
| echo "relock=true" >> "$GITHUB_OUTPUT" | |
| echo "::error::actions.lock is out of step with .github/workflows — every onboarded workflow will fail with startup_failure until it is regenerated" | |
| { | |
| echo '## actions.lock is out of sync' | |
| echo | |
| echo '```json' | |
| jq . actions-lock-report.json 2>/dev/null || cat actions-lock-report.json | |
| echo '```' | |
| echo | |
| echo 'Fix locally with `gh actions-lock`, or run this workflow in `relock` mode.' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| jq -r '.findings[]? | "::\(.severity // "error")::\(.detail // .)"' \ | |
| actions-lock-report.json 2>/dev/null || true | |
| exit 1 | |
| relock: | |
| name: Regenerate actions.lock | |
| needs: verify | |
| # Only for a genuine mismatch. `unknown` means the tool itself broke, and | |
| # committing whatever it produced would be worse than leaving the diff. | |
| if: always() && needs.verify.outputs.relock == 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Decide where the fix goes | |
| id: target | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| HEAD_REF: ${{ github.event.pull_request.head.ref }} | |
| HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} | |
| REPO: ${{ github.repository }} | |
| REF: ${{ github.ref }} | |
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$EVENT_NAME" = "pull_request" ]; then | |
| if [ "$HEAD_REPO" != "$REPO" ]; then | |
| echo "skipped=true" >> "$GITHUB_OUTPUT" | |
| echo "::warning::Fork pull request: cannot push the regenerated lockfile back to ${HEAD_REPO}. Run \`gh actions-lock\` locally." | |
| exit 0 | |
| fi | |
| echo "skipped=false" >> "$GITHUB_OUTPUT" | |
| echo "branch=${HEAD_REF}" >> "$GITHUB_OUTPUT" | |
| echo "on_default=false" >> "$GITHUB_OUTPUT" | |
| else | |
| branch="${REF#refs/heads/}" | |
| echo "skipped=false" >> "$GITHUB_OUTPUT" | |
| echo "branch=${branch}" >> "$GITHUB_OUTPUT" | |
| if [ "$branch" = "$DEFAULT_BRANCH" ]; then | |
| # main requires signed commits, so a bot commit cannot land | |
| # there: deliver the fix as a pull request instead. | |
| echo "on_default=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "on_default=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| fi | |
| - name: Checkout the branch that needs the lockfile | |
| if: steps.target.outputs.skipped == 'false' | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| ref: ${{ steps.target.outputs.branch }} | |
| - name: Install gh actions-lock | |
| if: steps.target.outputs.skipped == 'false' | |
| run: | | |
| set -euo pipefail | |
| gh extension install github/gh-actions-lock --pin "$ACTIONS_LOCK_EXTENSION_VERSION" | |
| - name: Regenerate the lockfile | |
| if: steps.target.outputs.skipped == 'false' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -uo pipefail | |
| code=0 | |
| gh actions-lock --relock --no-interactive >relock.out 2>relock.err || code=$? | |
| cat relock.out || true | |
| cat relock.err || true | |
| # A non-zero exit here does NOT mean nothing was written. The tool | |
| # writes the lockfile and then reports whatever it still objects to | |
| # (a bare SHA with no symbolic ref, say) — findings that do not | |
| # invalidate the file. Only "the file did not change" is a real | |
| # failure, and that is checked below. | |
| if [ "$code" -ne 0 ]; then | |
| echo "::warning::gh actions-lock --relock exited ${code}; the regenerated lockfile is still delivered if it changed" | |
| while IFS= read -r line; do | |
| [ -n "$line" ] && echo "::warning::[gh actions-lock] ${line}" | |
| done < <(tail -n 30 relock.err | tr -d '\r' | cut -c1-200) | |
| fi | |
| git --no-pager diff --stat -- .github/workflows/actions.lock || true | |
| - name: Push the regenerated lockfile back to the branch | |
| if: steps.target.outputs.skipped == 'false' && steps.target.outputs.on_default == 'false' | |
| run: | | |
| set -uo pipefail | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git add .github/workflows/actions.lock | |
| if git diff --cached --quiet; then | |
| echo "::notice::gh actions-lock produced no change; nothing to commit" | |
| exit 0 | |
| fi | |
| git commit -m "chore(ci): regenerate actions.lock (gh actions-lock --relock) | |
| The lockfile and the workflows had drifted apart. While they do, | |
| every onboarded workflow ends in startup_failure and produces no | |
| check runs at all. See game-server-admin#103." | |
| git push origin "HEAD:refs/heads/${{ steps.target.outputs.branch }}" | |
| echo "::notice::Regenerated actions.lock pushed to ${{ steps.target.outputs.branch }}; this pull request will re-verify on the next run." | |
| - name: Open a pull request with the regenerated lockfile | |
| if: steps.target.outputs.skipped == 'false' && steps.target.outputs.on_default == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| BASE_BRANCH: ${{ steps.target.outputs.branch }} | |
| run: | | |
| set -uo pipefail | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| branch="ci/actions-lock-relock-${GITHUB_RUN_ID}" | |
| git switch --create "$branch" | |
| git add .github/workflows/actions.lock | |
| if git diff --cached --quiet; then | |
| echo "::notice::gh actions-lock produced no change; nothing to propose" | |
| exit 0 | |
| fi | |
| git commit -m "chore(ci): regenerate actions.lock (gh actions-lock --relock) | |
| The lockfile and the workflows had drifted apart. While they do, | |
| every onboarded workflow ends in startup_failure and produces no | |
| check runs at all. See game-server-admin#103." | |
| git push --set-upstream origin "$branch" | |
| gh pr create \ | |
| --base "$BASE_BRANCH" \ | |
| --head "$branch" \ | |
| --title 'chore(ci): regenerate actions.lock' \ | |
| --body '`gh actions-lock --verify` failed on `'"$BASE_BRANCH"'` because `actions.lock` no longer matches the workflows. While they disagree, every onboarded workflow ends in `startup_failure` and produces no check runs at all. | |
| This PR is the output of `gh actions-lock --relock`. See game-server-admin#103.' |