From 6a918267480fabbdb062be7473ba6f72e5a76f65 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 08:29:45 +0000 Subject: [PATCH 1/4] ci(actions): relock actions.lock remotely with gh-actions-lock Both red checks on main share one root cause: .github/workflows/actions.lock drifted. - Dependabot (#34) bumped lean-action to v1.6.1 and codeql-action to v4.38.2 but left the lock on v1.6.0 / v4.38.0, so CI ends in startup_failure. dependabot-core still gates lock rewriting behind its github_actions_lockfile experiment, so every Actions bump repeats this. - The lock held cicd-suite@main at 5a10b72, before cicd-suite #32 fixed the Required Files Gate that kills estate-audit here (grep -v | wc -l under -e -o pipefail on a comment-only CODEOWNERS). New .github/workflows/actions-lock.yml runs the official extension (github/gh-actions-lock, pinned v0.2.0) with --relock on GitHub's runners: - triggers on every push to main that changes a workflow (a merged Dependabot bump is relocked within minutes), weekly, and on dispatch; - is scoped to the workflows the lock already tracks plus itself, so the estate's canonical secret-scanner caller is never rewritten; - refuses any run that would change more than actions.lock; - opens or updates a lockfile-only PR. It has no `uses:`, so it runs even when the lock is stale. It falls back to GITHUB_TOKEN; an ACTIONS_LOCK_TOKEN secret lets CI run on the PR it opens. Merging this triggers the first relock (push to main touching a workflow). Checks: actionlint 1.7.7 with shellcheck clean. Rung: none (CI housekeeping; rung 3 stays OPEN) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX --- .github/workflows/actions-lock.yml | 113 +++++++++++++++++++++++++++++ STATE.adoc | 20 +++++ 2 files changed, 133 insertions(+) create mode 100644 .github/workflows/actions-lock.yml diff --git a/.github/workflows/actions-lock.yml b/.github/workflows/actions-lock.yml new file mode 100644 index 0000000..64237f8 --- /dev/null +++ b/.github/workflows/actions-lock.yml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: MPL-2.0 +name: Actions lock + +# Keeps .github/workflows/actions.lock in step with the workflows, remotely. +# +# Why this exists. A workflow listed in actions.lock runs only the commits the +# lock records. When a `uses:` ref changes and the lock does not, that workflow +# ends in startup_failure with no check run at all. Dependabot bumps `uses:` +# refs but does not yet rewrite the lock (dependabot-core gates that behind its +# `github_actions_lockfile` experiment), so every Actions bump broke CI here: +# #34 moved lean-action to v1.6.1 and codeql-action to v4.38.2 while the lock +# still named v1.6.0 / v4.38.0. Branch pins also go stale: the lock held +# cicd-suite@main at 5a10b72, before cicd-suite #32 fixed the gate that fails +# estate-audit on this repo. +# +# What it does. Runs the official extension (github/gh-actions-lock, pinned +# below) with --relock, which records new refs and advances branch pins to +# upstream HEAD, then opens a PR that changes ONLY actions.lock. A run that +# wants to touch any workflow file is refused (same assert as #25). +# +# When. On every push to main that changes a workflow (so a merged Dependabot +# bump is relocked within minutes), weekly (so branch pins track latest), and +# on demand. +# +# ⚠ NO `uses:` ANYWHERE, DELIBERATELY (see labels.yml): this workflow must run +# precisely when the lock is stale, so it depends on no action. +# +# Token. Falls back to GITHUB_TOKEN. Add a repository secret +# ACTIONS_LOCK_TOKEN (fine-grained: Contents, Pull requests and Workflows +# read/write on this repo) if GitHub refuses a GITHUB_TOKEN write under +# .github/workflows/, and so that CI runs on the PR it opens (PRs opened with +# GITHUB_TOKEN do not trigger workflows). + +on: + push: + branches: [main] + paths: + - '.github/workflows/*.yml' + - '.github/workflows/*.yaml' + schedule: + - cron: "41 6 * * 1" # weekly, after Dependabot's Monday run + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: actions-lock + cancel-in-progress: false + +jobs: + relock: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + env: + GH_ACTIONS_LOCK_VERSION: v0.2.0 + GH_TOKEN: ${{ secrets.ACTIONS_LOCK_TOKEN || secrets.GITHUB_TOKEN }} + BASE: main + BRANCH: ci/relock-actions + steps: + - name: Relock and open a lockfile-only PR + run: | + set -euo pipefail + gh extension install github/gh-actions-lock --pin "$GH_ACTIONS_LOCK_VERSION" + gh auth setup-git + gh repo clone "$GITHUB_REPOSITORY" repo -- --quiet --depth 1 --branch "$BASE" + cd repo + + # Scope: the workflows the lock already tracks, plus this one (it has + # no `uses:`, so it is recorded as []). Untracked workflows, e.g. the + # estate's canonical secret-scanner caller, are left alone: onboarding + # one may rewrite its SHA ref, and those stay a reviewed, manual step. + # A scoped run never prunes out-of-scope entries. + mapfile -t scope < <( + { sed -n "/^workflows:/,/^dependencies:/s/^ '\(\.github\/workflows\/[^']*\)':.*$/\1/p" \ + .github/workflows/actions.lock + echo .github/workflows/actions-lock.yml + } | sort -u | while read -r p; do [ -f "$p" ] && echo "$p"; done) + printf 'relocking: %s\n' "${scope[@]}" + + gh actions-lock --relock --no-narrow --no-migrate-local-actions --no-interactive "${scope[@]}" + + changed=$(git status --porcelain | awk '{print $2}') + if [ -z "$changed" ]; then + echo "actions.lock is current; nothing to do." + exit 0 + fi + if [ "$changed" != ".github/workflows/actions.lock" ]; then + echo "::error::The relock wanted to change more than actions.lock. Refusing; handle by hand:" + git status --porcelain + exit 1 + fi + git --no-pager diff --stat + + git switch --quiet -c "$BRANCH" + git -c user.name='github-actions[bot]' \ + -c user.email='41898583+github-actions[bot]@users.noreply.github.com' \ + commit --quiet -am "chore(actions): relock actions.lock" \ + -m "Regenerated by .github/workflows/actions-lock.yml with github/gh-actions-lock $GH_ACTIONS_LOCK_VERSION (--relock --no-narrow --no-migrate-local-actions). Only actions.lock changes; every workflow file is byte-identical." + if ! git push --quiet --force origin "$BRANCH"; then + echo "::error::Push refused. If GitHub rejected a GITHUB_TOKEN write under .github/workflows/, add the ACTIONS_LOCK_TOKEN secret described at the top of this workflow." + exit 1 + fi + + body="Regenerated by \`actions-lock.yml\` (run $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) with \`github/gh-actions-lock $GH_ACTIONS_LOCK_VERSION --relock\`. Only \`.github/workflows/actions.lock\` changes." + if [ -n "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then + echo "Updated the open relock PR." + else + gh pr create --base "$BASE" --head "$BRANCH" \ + --title "chore(actions): relock actions.lock" --body "$body" + fi diff --git a/STATE.adoc b/STATE.adoc index 00ff2d0..de0174b 100644 --- a/STATE.adoc +++ b/STATE.adoc @@ -1,5 +1,25 @@ = STATE — cross-session log +== 2026-10-14 — CI: actions.lock relocked remotely (not a rung) + +* One root cause behind both red checks: `.github/workflows/actions.lock` + drifted. + - Dependabot (#34) bumped `lean-action` → v1.6.1 and `codeql-action` → + v4.38.2 but left the lock on v1.6.0 / v4.38.0, so `CI` ends in + `startup_failure`. dependabot-core still gates lock rewriting behind its + `github_actions_lockfile` experiment. + - The lock held `cicd-suite@main` at `5a10b72`, before cicd-suite #32 fixed + the Required Files Gate (`grep -v | wc -l` under `-e -o pipefail` on a + comment-only CODEOWNERS). That is why `estate-audit` fails. The bug is + already fixed upstream, so nothing needs filing. +* `.github/workflows/actions-lock.yml` (new, no `uses:`) runs + `github/gh-actions-lock v0.2.0 --relock` remotely. It triggers on pushes to + main that change a workflow, weekly, and on dispatch. It is scoped to the + workflows the lock already tracks plus itself, and opens a PR only when + `actions.lock` alone changes. +* Gates: actionlint 1.7.7 (with shellcheck) clean. The run itself can only + be exercised on GitHub, because this sandbox cannot reach the GitHub API. + == 2026-10-14 — toolchain v4.34.0 → v4.34.1 (patch; review finding on #36) * CodeRabbit flagged #36 (Major, security): v4.34.1 is the patched From 1a623fb6203f2bce6116d1783c5be19519072406 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 08:38:49 +0000 Subject: [PATCH 2/4] ci(actions): onboard every uses-free workflow; one AUTOMATION_TOKEN Scope is now the tracked workflows plus every workflow with no `uses:` (recorded as [], nothing to rewrite), so the uses-free track-*.yml workflows that follow are locked without hand edits. Untracked workflows with refs (secret-scanner) are still left alone. The optional secret is renamed AUTOMATION_TOKEN so one fine-grained token (Contents, Issues, Pull requests, Workflows) serves all the automation. actionlint 1.7.7 with shellcheck clean. Rung: none (CI housekeeping) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX --- .github/workflows/actions-lock.yml | 23 +++++++++++++---------- STATE.adoc | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/actions-lock.yml b/.github/workflows/actions-lock.yml index 64237f8..a49f8f8 100644 --- a/.github/workflows/actions-lock.yml +++ b/.github/workflows/actions-lock.yml @@ -26,10 +26,10 @@ name: Actions lock # precisely when the lock is stale, so it depends on no action. # # Token. Falls back to GITHUB_TOKEN. Add a repository secret -# ACTIONS_LOCK_TOKEN (fine-grained: Contents, Pull requests and Workflows +# AUTOMATION_TOKEN (fine-grained: Contents, Issues, Pull requests and Workflows # read/write on this repo) if GitHub refuses a GITHUB_TOKEN write under # .github/workflows/, and so that CI runs on the PR it opens (PRs opened with -# GITHUB_TOKEN do not trigger workflows). +# GITHUB_TOKEN do not trigger workflows). The track-*.yml workflows share it. on: push: @@ -56,7 +56,7 @@ jobs: pull-requests: write env: GH_ACTIONS_LOCK_VERSION: v0.2.0 - GH_TOKEN: ${{ secrets.ACTIONS_LOCK_TOKEN || secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }} BASE: main BRANCH: ci/relock-actions steps: @@ -68,15 +68,18 @@ jobs: gh repo clone "$GITHUB_REPOSITORY" repo -- --quiet --depth 1 --branch "$BASE" cd repo - # Scope: the workflows the lock already tracks, plus this one (it has - # no `uses:`, so it is recorded as []). Untracked workflows, e.g. the - # estate's canonical secret-scanner caller, are left alone: onboarding - # one may rewrite its SHA ref, and those stay a reviewed, manual step. - # A scoped run never prunes out-of-scope entries. + # Scope: the workflows the lock already tracks, plus every workflow + # with no `uses:` (recorded as [], nothing to rewrite). An untracked + # workflow WITH refs, e.g. the estate's canonical secret-scanner + # caller, is left alone: onboarding it may rewrite its SHA ref, so + # that stays a reviewed, manual step. A scoped run never prunes + # out-of-scope entries. mapfile -t scope < <( { sed -n "/^workflows:/,/^dependencies:/s/^ '\(\.github\/workflows\/[^']*\)':.*$/\1/p" \ .github/workflows/actions.lock - echo .github/workflows/actions-lock.yml + for f in .github/workflows/*.yml .github/workflows/*.yaml; do + [ -f "$f" ] && ! grep -qE '^[[:space:]]*(-[[:space:]]+)?uses:' "$f" && echo "$f" + done } | sort -u | while read -r p; do [ -f "$p" ] && echo "$p"; done) printf 'relocking: %s\n' "${scope[@]}" @@ -100,7 +103,7 @@ jobs: commit --quiet -am "chore(actions): relock actions.lock" \ -m "Regenerated by .github/workflows/actions-lock.yml with github/gh-actions-lock $GH_ACTIONS_LOCK_VERSION (--relock --no-narrow --no-migrate-local-actions). Only actions.lock changes; every workflow file is byte-identical." if ! git push --quiet --force origin "$BRANCH"; then - echo "::error::Push refused. If GitHub rejected a GITHUB_TOKEN write under .github/workflows/, add the ACTIONS_LOCK_TOKEN secret described at the top of this workflow." + echo "::error::Push refused. If GitHub rejected a GITHUB_TOKEN write under .github/workflows/, add the AUTOMATION_TOKEN secret described at the top of this workflow." exit 1 fi diff --git a/STATE.adoc b/STATE.adoc index de0174b..3dbd601 100644 --- a/STATE.adoc +++ b/STATE.adoc @@ -15,7 +15,7 @@ * `.github/workflows/actions-lock.yml` (new, no `uses:`) runs `github/gh-actions-lock v0.2.0 --relock` remotely. It triggers on pushes to main that change a workflow, weekly, and on dispatch. It is scoped to the - workflows the lock already tracks plus itself, and opens a PR only when + workflows the lock already tracks plus every workflow with no `uses:`, and opens a PR only when `actions.lock` alone changes. * Gates: actionlint 1.7.7 (with shellcheck) clean. The run itself can only be exercised on GitHub, because this sandbox cannot reach the GitHub API. From 37bf88e2cb9e49b6563caca49f0d5ca8c32e63c9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 09:06:51 +0000 Subject: [PATCH 3/4] ci(estate-audit): port #44, call cicd-suite's reusable audit Ports the workflow and lock changes of hyperpolymath/marches#44 so that this PR's estate-audit check runs the fixed audit instead of the frozen 26-step copy. #44 is green on all five component checks against cicd-suite b9d4f24 (hyperpolymath/cicd-suite#50). The ported files are byte-identical to #44's, so whichever merges second sees no diff for them. #44 keeps the STATE.adoc entry. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX --- .github/workflows/actions.lock | 21 ----- .github/workflows/main-estate-audit.yml | 106 +++++------------------ .github/workflows/track-estate-audit.yml | 78 +++++++++++++++++ 3 files changed, 99 insertions(+), 106 deletions(-) create mode 100644 .github/workflows/track-estate-audit.yml diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 4e6ed21..3da4783 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -11,9 +11,6 @@ workflows: - 'github/codeql-action@v4.38.0' '.github/workflows/label-triage.yml': [] '.github/workflows/labels.yml': [] - '.github/workflows/main-estate-audit.yml': - - 'actions/checkout@v7.0.1' - - 'hyperpolymath/cicd-suite@main' '.github/workflows/pages.yml': - 'actions/checkout@v7.0.1' - 'actions/deploy-pages@v5.0.1' @@ -51,24 +48,6 @@ dependencies: commit: 'sha1-b96794f015dfd88f77b49b1c93e0fa7110f94c63' owner_id: 9919 repo_id: 259445878 - 'hyperpolymath/cicd-suite@main': - ref: 'main' - commit: 'sha1-5a10b72e574ef63855fafd4568a4c178657f3294' - owner_id: 6759885 - repo_id: 1326697643 - uses: - - 'hyperpolymath/deed-ecosystem@f9d999b60cb5f383679ea19912bcdc49c944973a' - - 'hyperpolymath/k9-ecosystem@2155aa26a21758f2ba119f61bc7e0e1981c106fb' - 'hyperpolymath/deed-ecosystem@f9d999b60cb5f383679ea19912bcdc49c944973a': - ref: 'main' - commit: 'sha1-f9d999b60cb5f383679ea19912bcdc49c944973a' - owner_id: 6759885 - repo_id: 1275649586 - 'hyperpolymath/k9-ecosystem@2155aa26a21758f2ba119f61bc7e0e1981c106fb': - ref: 'main' - commit: 'sha1-2155aa26a21758f2ba119f61bc7e0e1981c106fb' - owner_id: 6759885 - repo_id: 1275650185 'leanprover/lean-action@v1.6.0': ref: 'v1.6.0' commit: 'sha1-50fcf42d2e460296f1a34b402e990d1b24f8b596' diff --git a/.github/workflows/main-estate-audit.yml b/.github/workflows/main-estate-audit.yml index 2229d94..044425c 100644 --- a/.github/workflows/main-estate-audit.yml +++ b/.github/workflows/main-estate-audit.yml @@ -1,95 +1,31 @@ -# This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 -# This workflow is managed by gh actions-lock. - name: Central Estate CI/CD Audit +# Thin caller of the estate audit, which lives in hyperpolymath/cicd-suite as +# a reusable workflow and reports five component checks: governance, +# hygiene, manifests, languages, advisory. Do not copy the audit's steps in +# here. A copy freezes this repository at whatever cicd-suite commit its +# actions.lock happened to hold, and fixes made upstream never arrive. +# +# The pin is a full SHA, advanced weekly by track-estate-audit.yml (a PR +# whose own run of this audit is the check). +# +# ⚠ DE-ONBOARDED from actions.lock, deliberately, like the secret-scanner +# caller. A reusable workflow onboarded cross-repo startup-fails with zero +# jobs under sha_pinning_required (see the header of cicd-suite's +# main-estate-audit.yml). Do not run a full-directory `gh actions-lock` that +# re-onboards this file. If one does, cicd-suite/scripts/deonboard-estate-audit.sh +# reverses it. + on: push: branches: [ "main" ] pull_request: branches: [ "main" ] +permissions: + contents: read + jobs: - estate-audit: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7.0.1 - - - name: Required Files Gate - uses: hyperpolymath/cicd-suite/actions/required-files-check@main - - - name: Code Hygiene Gate - uses: hyperpolymath/cicd-suite/actions/code-hygiene-check@main - - - name: Manifest Validation Gate - uses: hyperpolymath/cicd-suite/actions/manifest-check@main - - - name: Idris2 ABI Purity Gate - uses: hyperpolymath/cicd-suite/actions/idris2-abi-check@main - - - name: Zig UnifiedApiAdapter API Gate - uses: hyperpolymath/cicd-suite/actions/zig-unified-api-adapter-check@main - - - name: Contractile Validation Gate - uses: hyperpolymath/cicd-suite/actions/contractile-validation-check@main - - - name: Recipes Set Validation Gate - uses: hyperpolymath/cicd-suite/actions/recipes-set-check@main - - - name: Affirmation Document Gate - uses: hyperpolymath/cicd-suite/actions/affirmation-check@main - - - name: Academic Referencing Gate - uses: hyperpolymath/cicd-suite/actions/referencing-check@main - - - name: Semantic Audit Gate - uses: hyperpolymath/cicd-suite/actions/semantic-audit-check@main - - - name: SPDX License Gate - uses: hyperpolymath/cicd-suite/actions/spdx-license-check@main - - - name: Proof Runner Gate - uses: hyperpolymath/cicd-suite/actions/proof-runner-check@main - - - name: PRAT Testing Gate - uses: hyperpolymath/cicd-suite/actions/prat-check@main - - - name: Panic Attack & Pons Gate - uses: hyperpolymath/cicd-suite/actions/custom-tools-check@main - - - name: WWW & Well-Known Compliance Gate - uses: hyperpolymath/cicd-suite/actions/www-compliance-check@main - - - name: BoJ Cartridge Validation Gate - uses: hyperpolymath/cicd-suite/actions/boj-cartridge-check@main - - - name: Formatting Validation Gate - uses: hyperpolymath/cicd-suite/actions/formatting-check@main - - - name: Accreditations & Badges Gate - uses: hyperpolymath/cicd-suite/actions/badges-check@main - - - name: Metrics Extraction Gate - uses: hyperpolymath/cicd-suite/actions/metrics-check@main - - - name: Linguist & Banned Languages Gate - uses: hyperpolymath/cicd-suite/actions/linguist-check@main - - - name: Test & Benchmarks Dashboard Gate - uses: hyperpolymath/cicd-suite/actions/tests-benches-check@main - - - name: Hosting & Site Status Gate - uses: hyperpolymath/cicd-suite/actions/hosting-check@main - - - name: Git-Sea Analytics Gate - uses: hyperpolymath/cicd-suite/actions/gitsea-check@main - - - name: Trust & Humans Validation Gate - uses: hyperpolymath/cicd-suite/actions/trust-humans-check@main - - - name: Are We UnAPI Gate (Secret Scanning) - uses: hyperpolymath/cicd-suite/actions/secrets-check@main - - - name: Reasonably Good Token Validation Gate - uses: hyperpolymath/cicd-suite/actions/vaulted-tokens-check@main + estate: + uses: hyperpolymath/cicd-suite/.github/workflows/main-estate-audit.yml@b9d4f242f0f1e889a48023534d6fd3669cb83e79 # cicd-suite#50 head; re-pin to its merge commit diff --git a/.github/workflows/track-estate-audit.yml b/.github/workflows/track-estate-audit.yml new file mode 100644 index 0000000..dffe007 --- /dev/null +++ b/.github/workflows/track-estate-audit.yml @@ -0,0 +1,78 @@ +# SPDX-License-Identifier: MPL-2.0 +name: Track latest estate audit + +# Weekly: is the cicd-suite estate audit this repository calls behind +# cicd-suite's main? If so, open a PR that moves the pin in +# main-estate-audit.yml to cicd-suite HEAD. The PR's own estate-audit run is +# the check: merge it when the five components are green. Nothing reaches +# main unreviewed. +# +# ⚠ NO `uses:` ANYWHERE, DELIBERATELY: actions.lock is keyed by workflow path, +# and this must run even when the lock is stale. +# +# Token: AUTOMATION_TOKEN, a fine-grained token on this repository with +# Contents, Pull requests and Workflows set to read/write. In practice it is +# required: the bump edits a file under .github/workflows/, which +# GITHUB_TOKEN may not write, and a PR opened by GITHUB_TOKEN does not trigger +# the estate-audit run that validates it. + +on: + schedule: + - cron: "23 7 * * 1" # weekly, Monday + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: track-estate-audit + cancel-in-progress: false + +jobs: + bump: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + env: + GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }} + BRANCH: ci/track-estate-audit + CALLER: .github/workflows/main-estate-audit.yml + steps: + - name: Move the cicd-suite pin to HEAD and open a PR + run: | + set -euo pipefail + gh auth setup-git + base=$(gh repo view "$GITHUB_REPOSITORY" --json defaultBranchRef --jq .defaultBranchRef.name) + gh repo clone "$GITHUB_REPOSITORY" repo -- --quiet --depth 1 --branch "$base" + cd repo + + pinned=$(grep -oE 'cicd-suite/\.github/workflows/main-estate-audit\.yml@[0-9a-f]{40}' "$CALLER" \ + | sed 's/.*@//' | head -n 1 || true) + if [ -z "$pinned" ]; then + echo "::error::$CALLER does not call cicd-suite's reusable estate audit at a full SHA." + exit 1 + fi + head=$(git ls-remote https://github.com/hyperpolymath/cicd-suite.git HEAD | cut -f1) + echo "pinned ${pinned:0:7}, cicd-suite HEAD ${head:0:7}" + if [ "$pinned" = "$head" ]; then + echo "Already at cicd-suite HEAD." + exit 0 + fi + + sed -i "s/$pinned/$head/g" "$CALLER" + git switch --quiet -c "$BRANCH" + git -c user.name='github-actions[bot]' \ + -c user.email='41898583+github-actions[bot]@users.noreply.github.com' \ + commit --quiet -am "ci(estate-audit): track cicd-suite ${head:0:7}" + if ! git push --quiet --force origin "$BRANCH"; then + echo "::error::Push refused: writing under .github/workflows/ needs the AUTOMATION_TOKEN secret described above." + exit 1 + fi + body="Moves the estate audit to cicd-suite \`${head:0:7}\` (was \`${pinned:0:7}\`): https://github.com/hyperpolymath/cicd-suite/compare/$pinned...$head. This PR's estate-audit run is the check. Opened by \`track-estate-audit.yml\`." + if [ -n "$(gh pr list --head "$BRANCH" --state open --json number --jq '.[].number')" ]; then + gh pr edit "$BRANCH" --title "ci(estate-audit): track cicd-suite ${head:0:7}" --body "$body" + else + gh pr create --base "$base" --head "$BRANCH" \ + --title "ci(estate-audit): track cicd-suite ${head:0:7}" --body "$body" + fi From 6ae9736a1ea9651d3095128756f143bd0a4e5f58 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 14 Oct 2026 09:10:29 +0000 Subject: [PATCH 4/4] ci(estate-audit): pin cicd-suite#50 head afa28ff; bot keeps others' commits Takes hyperpolymath/cicd-suite#50's review fix to the track bot: if ci/track-estate-audit holds a commit not made by the bot, the bot leaves it alone instead of force-pushing over it. The pin moves to #50's new head; its reusable workflow is unchanged from b9d4f24. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VTeVWDEJgdYKsUNr4uhnXX --- .github/workflows/main-estate-audit.yml | 2 +- .github/workflows/track-estate-audit.yml | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main-estate-audit.yml b/.github/workflows/main-estate-audit.yml index 044425c..9880f31 100644 --- a/.github/workflows/main-estate-audit.yml +++ b/.github/workflows/main-estate-audit.yml @@ -28,4 +28,4 @@ permissions: jobs: estate: - uses: hyperpolymath/cicd-suite/.github/workflows/main-estate-audit.yml@b9d4f242f0f1e889a48023534d6fd3669cb83e79 # cicd-suite#50 head; re-pin to its merge commit + uses: hyperpolymath/cicd-suite/.github/workflows/main-estate-audit.yml@afa28ff81dc89ae7bd2304eead22917ec1733904 # cicd-suite#50 head; re-pin to its merge commit diff --git a/.github/workflows/track-estate-audit.yml b/.github/workflows/track-estate-audit.yml index dffe007..b52c28a 100644 --- a/.github/workflows/track-estate-audit.yml +++ b/.github/workflows/track-estate-audit.yml @@ -38,6 +38,7 @@ jobs: GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN || secrets.GITHUB_TOKEN }} BRANCH: ci/track-estate-audit CALLER: .github/workflows/main-estate-audit.yml + BOT_EMAIL: 41898583+github-actions[bot]@users.noreply.github.com steps: - name: Move the cicd-suite pin to HEAD and open a PR run: | @@ -60,10 +61,21 @@ jobs: exit 0 fi + # The bot branch is rebuilt from the default branch each run, which + # would discard anything else on it. If someone has pushed to it + # (say, a fix the newer audit needed), leave it for review. + if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null; then + foreign=$(gh api "repos/$GITHUB_REPOSITORY/compare/$base...$BRANCH" \ + --jq "[.commits[] | select(.commit.author.email != \"$BOT_EMAIL\")] | length") + if [ "$foreign" != 0 ]; then + echo "::warning::$BRANCH carries $foreign commit(s) not made by this workflow; leaving it alone. Merge its PR or delete the branch, then re-run." + exit 0 + fi + fi + sed -i "s/$pinned/$head/g" "$CALLER" git switch --quiet -c "$BRANCH" - git -c user.name='github-actions[bot]' \ - -c user.email='41898583+github-actions[bot]@users.noreply.github.com' \ + git -c user.name='github-actions[bot]' -c user.email="$BOT_EMAIL" \ commit --quiet -am "ci(estate-audit): track cicd-suite ${head:0:7}" if ! git push --quiet --force origin "$BRANCH"; then echo "::error::Push refused: writing under .github/workflows/ needs the AUTOMATION_TOKEN secret described above."