From a3acc2b506c60823cf7b9e3dac6702d2c2ff53ee Mon Sep 17 00:00:00 2001 From: pashifika Date: Fri, 28 Aug 2026 15:18:56 +0900 Subject: [PATCH] chore: commit the ruleset payloads under .github/rulesets `omp-relayd` and `omp-toolgate` both keep the exact GitHub ruleset API payload in the repository, and this repository's protection existed only in a settings screen. GitHub does not read these files -- there is no protection-as-code feature -- so they buy two things: the protection is reviewable in a diff instead of being invisible to review, and re-applying it after an accident is one `gh api --input` call rather than a reconstruction from memory. Both payloads are field-for-field identical to the live rulesets, checked with the deep key-sorted comparison `omp-relayd` documents: gh api "repos/$OWNER/$REPO/rulesets/$ID" | jq -S '[.rules[] | {(.type): .parameters}] | add' > /tmp/live.json jq -S '[.rules[] | {(.type): .parameters}] | add' .github/rulesets/main.json | diff - /tmp/live.json && echo "no drift" main.json (ruleset 21701346) is byte-identical to `omp-relayd`'s, which already carries `allowed_merge_methods: ["merge"]` and `require_extra_approval_for_unattributed_changes: true`. tags.json (ruleset 21701352) is byte-identical to `omp-toolgate`'s. A future difference is therefore real drift rather than serialisation noise. `required_reviewers: []` is declared rather than omitted. GitHub fills that field in on the `pull_request` rule at creation time, and omitting it cost `omp-toolgate` an extra pull request to make the committed payload match the live one. The `ci` job's comment now names `.github/rulesets/main.json` explicitly, because that file hard-codes the literal string `ci` and nothing verifies the two agree: renaming the job would block every merge with no failing job to point at. --- .github/rulesets/main.json | 37 +++++++++++++++++++++++++++++++++++++ .github/rulesets/tags.json | 13 +++++++++++++ .github/workflows/ci.yml | 8 ++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 .github/rulesets/main.json create mode 100644 .github/rulesets/tags.json diff --git a/.github/rulesets/main.json b/.github/rulesets/main.json new file mode 100644 index 0000000..f31c72f --- /dev/null +++ b/.github/rulesets/main.json @@ -0,0 +1,37 @@ +{ + "name": "main", + "target": "branch", + "enforcement": "active", + "bypass_actors": [], + "conditions": { + "ref_name": { + "include": ["~DEFAULT_BRANCH"], + "exclude": [] + } + }, + "rules": [ + { "type": "deletion" }, + { "type": "non_fast_forward" }, + { + "type": "pull_request", + "parameters": { + "required_approving_review_count": 0, + "dismiss_stale_reviews_on_push": false, + "require_code_owner_review": false, + "require_last_push_approval": false, + "require_extra_approval_for_unattributed_changes": true, + "required_review_thread_resolution": true, + "required_reviewers": [], + "allowed_merge_methods": ["merge"] + } + }, + { + "type": "required_status_checks", + "parameters": { + "strict_required_status_checks_policy": true, + "do_not_enforce_on_create": false, + "required_status_checks": [{ "context": "ci" }] + } + } + ] +} diff --git a/.github/rulesets/tags.json b/.github/rulesets/tags.json new file mode 100644 index 0000000..9f0d064 --- /dev/null +++ b/.github/rulesets/tags.json @@ -0,0 +1,13 @@ +{ + "name": "release-tags", + "target": "tag", + "enforcement": "active", + "bypass_actors": [], + "conditions": { + "ref_name": { + "include": ["refs/tags/v*"], + "exclude": [] + } + }, + "rules": [{ "type": "deletion" }, { "type": "non_fast_forward" }] +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43b69ec..e4732c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -309,8 +309,12 @@ jobs: cat "$HOME/plugins.txt" grep -q 'omp-codebase-memory' "$HOME/plugins.txt" - # The single status check branch protection requires. Runtime jobs are never - # named there, so changing the matrix never means editing the ruleset. + # The single status check branch protection requires. `.github/rulesets/main.json` + # names the literal string `ci`; nothing mechanically verifies the two agree, so + # renaming this job silently blocks every merge with no failing job to point at. + # + # Runtime jobs are never named there. Adding, removing, or restructuring one + # means editing this job's `needs` and nothing else. ci: name: ci needs: [hygiene, bun]