Skip to content

chore: commit the ruleset payloads under .github/rulesets - #2

Merged
pashifika merged 1 commit into
mainfrom
chore/commit-ruleset-payloads
Aug 28, 2026
Merged

chore: commit the ruleset payloads under .github/rulesets#2
pashifika merged 1 commit into
mainfrom
chore/commit-ruleset-payloads

Conversation

@pashifika

Copy link
Copy Markdown
Owner

Summary

Adopts the shape omp-relayd and omp-toolgate already use: the exact GitHub ruleset API payloads live in the repository under .github/rulesets/, instead of the protection existing only in a settings screen.

Both rulesets on this repository were created out of band, so nothing in the tree recorded what protection is in force:

  • main (branch, active) — no committed record of which rules apply, which merge methods are permitted, or that ci is the one required check.
  • release-tags (tag, active) — no committed record that refs/tags/v* refuses deletion and non-fast-forward, which is what keeps a published release from silently diverging from the tag it was built from.

GitHub does not read these files. There is no protection-as-code feature, and this change does not pretend otherwise. What the files buy is narrower and still worth having: the protection becomes reviewable in a diff, and re-applying it after an accident is one gh api --method PUT --input call rather than a reconstruction from memory.

Fidelity to the live rulesets

Both payloads are field-for-field identical to what is live, checked with the deep key-sorted comparison omp-relayd documents rather than by eye:

gh api "repos/pashifika/omp-codebase-memory/rulesets/21701346" |
  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 vs ruleset 21701346 ===
IDENTICAL — no drift
=== tags.json vs ruleset 21701352 ===
IDENTICAL — no drift

The files are also byte-identical to their counterparts in the reference repositories: main.json to omp-relayd's, which already carries allowed_merge_methods: ["merge"] and require_extra_approval_for_unattributed_changes: true, and tags.json to omp-toolgate's. A future difference is therefore real drift rather than serialisation noise.

required_reviewers: [] is declared rather than omitted on purpose. GitHub fills that field in on the pull_request rule at creation time, and omitting it cost omp-toolgate an extra pull request before its committed payload matched the live ruleset.

What the payloads record

main.json, targeting ~DEFAULT_BRANCH with bypass_actors: [] — so the rules apply to the owner too:

Rule Effect
deletion, non_fast_forward main cannot be deleted or rewound
pull_request Every change arrives through a PR. required_approving_review_count: 0, so a sole maintainer is not deadlocked by GitHub's refusal to let an author approve their own PR. required_review_thread_resolution: true. allowed_merge_methods: ["merge"]
required_status_checks Exactly one context, ci, with strict_required_status_checks_policy: true

tags.json, targeting refs/tags/v*: deletion and non_fast_forward only. Creation is deliberately unrestricted — release.yml derives the published version from the tag name, so what has to be immutable is where a v* tag points once it exists.

One rule is worth calling out because it is a latent trap rather than a setting: require_extra_approval_for_unattributed_changes: true combined with required_approving_review_count: 0 means a PR containing a commit GitHub cannot attribute to an account needs one approval, which a sole maintainer cannot self-provide. Every commit on main is currently attributed to pashifika via a linked address, so it does not fire; a commit authored from a machine whose git config user.email is not linked would be unmergeable.

ci's comment now names the file

.github/rulesets/main.json hard-codes the literal string ci, and nothing mechanically verifies that it matches the aggregating job's name. Renaming the job would block every merge with no failing job to point at, so the comment says so, and says that runtime jobs are never named in the ruleset — adding or removing one means editing needs and nothing else.

Key files changed

File Purpose
.github/rulesets/main.json The main branch ruleset payload (ruleset 21701346), byte-identical to omp-relayd's
.github/rulesets/tags.json The release-tags tag ruleset payload (ruleset 21701352), byte-identical to omp-toolgate's
.github/workflows/ci.yml The aggregating ci job's comment now names the ruleset file that depends on its name

Test plan

  • jq empty on both payloads — valid JSON
  • Deep key-sorted comparison of each payload against its live ruleset — IDENTICAL for both, transcript above
  • diff against the reference repositories' files — byte-identical
  • Direct push to main rejected (Changes must be made through a pull request., Required status check "ci" is expected.), measured with a throwaway empty commit before this branch was cut, then discarded
  • ci / hygiene and ci / bun pass on this PR — the only source change is a comment, so bun is expected green unchanged, and hygiene still finds its 8 pinned uses: references
  • ci / ci green, which is also the first exercise of the now-active required_status_checks rule on a real PR

This change touches no runtime code. install check remains skipped on pull requests by design.

🤖 Generated with Claude Code

`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.
@pashifika
pashifika merged commit 8ac2e37 into main Aug 28, 2026
4 checks passed
@pashifika
pashifika deleted the chore/commit-ruleset-payloads branch August 28, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant