From 77f72f6fc8a4e36bd0d9ba83e7c0e30a4a2c4790 Mon Sep 17 00:00:00 2001 From: Kazuki Yamada Date: Sat, 30 May 2026 22:35:00 +0900 Subject: [PATCH 1/3] ci(schema): Deliver schema updates via PR instead of direct push to main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intent(schema-update): the Update Schema workflow's direct push to main fails at every version bump — the branch ruleset rejects it (GH013, pull_request required) because github-actions[bot] is not in the bypass list (only the admin role is) decision(schema-update): on main (push / workflow_dispatch) open a PR via peter-evans/create-pull-request instead of pushing; keep the existing git-auto-commit-into-PR-branch behavior for pull_request events so schema changes still ride along with the PR that caused them decision(schema-token): use the existing COMMITTER_TOKEN PAT so the generated PR triggers CI and is mergeable; the create-pull-request step is gated to non-pull_request events, so the PAT is never exposed to fork-triggered runs constraint(branch-ruleset): main requires PR + 1 approving + code-owner review with no required status checks, so the schema PR is merged by the admin (bypass) — typically one click per release Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/schema-update.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/schema-update.yml b/.github/workflows/schema-update.yml index b408e100..6f41a5c7 100644 --- a/.github/workflows/schema-update.yml +++ b/.github/workflows/schema-update.yml @@ -9,6 +9,7 @@ on: permissions: contents: write + pull-requests: write jobs: generate-schema: @@ -24,9 +25,32 @@ jobs: cache: npm - run: npm ci - run: node --run website-generate-schema - - uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 + + # On pull requests, commit the regenerated schema back into the PR branch + # so the schema change rides along with the PR that caused it. + - if: github.event_name == 'pull_request' + uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 with: commit_message: 'chore(schema): auto generate schema' commit_user_name: "github-actions[bot]" commit_user_email: "github-actions[bot]@users.noreply.github.com" commit_author: "github-actions[bot] " + + # On main (e.g. after a version bump), direct pushes are blocked by the + # branch ruleset (pull_request required), so deliver the regenerated + # schema as a PR instead. COMMITTER_TOKEN is used so the PR triggers CI + # and is mergeable. + - if: github.event_name != 'pull_request' + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + token: ${{ secrets.COMMITTER_TOKEN }} + commit-message: 'chore(schema): auto generate schema' + branch: chore/schema-update + delete-branch: true + title: 'chore(schema): Update configuration JSON schema' + body: | + Automated schema update generated by the Update Schema workflow. + + Direct pushes to `main` are blocked by the branch ruleset, so the + regenerated schema is delivered as this PR instead. + author: 'github-actions[bot] ' From 19a2d68adef47dd9c92b60c6af17b555d70a04db Mon Sep 17 00:00:00 2001 From: Kazuki Yamada Date: Sat, 30 May 2026 23:40:54 +0900 Subject: [PATCH 2/3] fix(ci): Harden schema-update PR/fork/dispatch handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit decision(schema-update): check out the PR head branch only for same-repo PRs so git-auto-commit can push the regenerated schema; push/dispatch/fork all fall back to main decision(schema-update): gate the PR-branch auto-commit to same-repo PRs — fork PRs get a read-only GITHUB_TOKEN and would fail (or push to main) decision(schema-update): pin create-pull-request to `base: main` so a manual workflow_dispatch from another ref still targets main learned(gha-expressions): accessing `github.event.pull_request.head.repo.full_name` on push/dispatch (where pull_request is null) yields empty, not an error, so the `&& ... || 'main'` fallback is safe Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/schema-update.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/schema-update.yml b/.github/workflows/schema-update.yml index 6f41a5c7..ec714db1 100644 --- a/.github/workflows/schema-update.yml +++ b/.github/workflows/schema-update.yml @@ -18,6 +18,10 @@ jobs: steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: + # Same-repo PRs check out the PR head branch so the regenerated schema + # can be committed back to it; all other cases (push, dispatch, fork + # PRs) use main. + ref: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.head_ref || 'main' }} token: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: @@ -26,9 +30,10 @@ jobs: - run: npm ci - run: node --run website-generate-schema - # On pull requests, commit the regenerated schema back into the PR branch - # so the schema change rides along with the PR that caused it. - - if: github.event_name == 'pull_request' + # On same-repo pull requests, commit the regenerated schema back into the + # PR branch so the schema change rides along with the PR that caused it. + # Fork PRs are skipped — their GITHUB_TOKEN is read-only. + - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 with: commit_message: 'chore(schema): auto generate schema' @@ -44,6 +49,7 @@ jobs: uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ secrets.COMMITTER_TOKEN }} + base: main commit-message: 'chore(schema): auto generate schema' branch: chore/schema-update delete-branch: true From 4f73c6047d7991899430dc3df58a3bf5e6e0f282 Mon Sep 17 00:00:00 2001 From: Kazuki Yamada Date: Sun, 31 May 2026 00:03:01 +0900 Subject: [PATCH 3/3] fix(ci): Address schema-update review feedback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit decision(schema-update): fork PRs now check out the merge ref and fail on schema drift instead of silently checking out main — surfaces fork-authored schema changes in CI (CodeRabbit) decision(schema-update): add a concurrency group so two near-simultaneous main pushes don't race on the reused chore/schema-update branch decision(schema-token): drop the unused `pull-requests: write` permission — create-pull-request uses COMMITTER_TOKEN (PAT), not GITHUB_TOKEN, and auto-commit needs only contents:write decision(commit-message): capitalize the bot commit message to 'Auto-generate schema' per the project's Conventional Commits casing rule Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/schema-update.yml | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/workflows/schema-update.yml b/.github/workflows/schema-update.yml index ec714db1..a7f17874 100644 --- a/.github/workflows/schema-update.yml +++ b/.github/workflows/schema-update.yml @@ -9,7 +9,12 @@ on: permissions: contents: write - pull-requests: write + +concurrency: + # Serialize runs that share the reused chore/schema-update branch so two + # near-simultaneous main pushes don't race on it. + group: schema-update-${{ github.ref }} + cancel-in-progress: false jobs: generate-schema: @@ -19,9 +24,9 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # Same-repo PRs check out the PR head branch so the regenerated schema - # can be committed back to it; all other cases (push, dispatch, fork - # PRs) use main. - ref: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.head_ref || 'main' }} + # can be committed back to it. Fork PRs check out the merge ref so the + # schema is generated from the PR's code. Push / dispatch use main. + ref: ${{ github.event_name == 'pull_request' && (github.event.pull_request.head.repo.full_name == github.repository && github.head_ref || github.ref) || 'main' }} token: ${{ secrets.GITHUB_TOKEN }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: @@ -32,15 +37,25 @@ jobs: # On same-repo pull requests, commit the regenerated schema back into the # PR branch so the schema change rides along with the PR that caused it. - # Fork PRs are skipped — their GITHUB_TOKEN is read-only. - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository }} uses: stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0 with: - commit_message: 'chore(schema): auto generate schema' + commit_message: 'chore(schema): Auto-generate schema' commit_user_name: "github-actions[bot]" commit_user_email: "github-actions[bot]@users.noreply.github.com" commit_author: "github-actions[bot] " + # Fork pull requests use a read-only token and cannot be committed to, so + # fail if the schema is out of date to surface the drift instead of + # silently merging it. + - if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }} + run: | + if ! git diff --quiet; then + echo "::error::Generated schema is out of date. Run 'node --run website-generate-schema' and commit the result." + git --no-pager diff --stat + exit 1 + fi + # On main (e.g. after a version bump), direct pushes are blocked by the # branch ruleset (pull_request required), so deliver the regenerated # schema as a PR instead. COMMITTER_TOKEN is used so the PR triggers CI @@ -50,7 +65,7 @@ jobs: with: token: ${{ secrets.COMMITTER_TOKEN }} base: main - commit-message: 'chore(schema): auto generate schema' + commit-message: 'chore(schema): Auto-generate schema' branch: chore/schema-update delete-branch: true title: 'chore(schema): Update configuration JSON schema'