Surfaced while hardening check_rulesets.py in #146. The validator now pins the
bypass-actor set so a change shows up as a reviewed diff, but it deliberately
does not decide whether the current posture is the intended one. That is an
owner's call, and it should be made explicitly rather than inherited.
Current state, as declared in .github/rulesets/
branch-main.json (target branch, ~DEFAULT_BRANCH, enforcement: active):
required_status_checks: ci-gate, strict
required_signatures, deletion, non_fast_forward
pull_request with required_approving_review_count: 0, thread resolution
required, merge-commit only
bypass_actors: repository-admin role (actor_id: 5), bypass_mode: always
tag-semver.json carries the same admin bypass over release tags, alongside
deletion / non_fast_forward / update / required_signatures.
docs/08 already records the zero-approval choice honestly, so nothing here is
undisclosed. The question is whether it should stay.
Why it is worth deciding rather than leaving
Consumers pin these workflows by SHA, so a change here is a supply-chain change
in someone else's repository. With zero required approvals and an always-on admin
bypass, the effective control on that supply chain is ci-gate plus commit
signing — a single actor can author, merge and tag. That may be entirely correct
for a solo-maintained repository, and GitHub does not allow self-approval anyway,
so requiring one approval would block the sole maintainer rather than add review.
The point is that this should be a recorded decision with its compensating
controls named, not a default nobody revisited.
Options
- Keep as is, and state the compensating controls in
docs/08: required
ci-gate, signed commits, immutable tags, protected release environment
with a required reviewer, and the negative-gate probes.
- Remove the admin bypass on
tag-semver.json only, so release tags are
immutable even to an admin while day-to-day branch work is unaffected. This is
the narrowest change that strengthens the consumer-facing promise.
- Add a second maintainer or a machine reviewer and require one approval.
Note on scope
Ruleset mutation is live repository configuration and is outside what a validator
or an automated change should do. Whatever is chosen, the JSON under
.github/rulesets/ and EXPECTED_BYPASS_ACTORS in scripts/check_rulesets.py
must be updated together — the validator will fail if they drift, which is the
intended behaviour.
Surfaced while hardening
check_rulesets.pyin #146. The validator now pins thebypass-actor set so a change shows up as a reviewed diff, but it deliberately
does not decide whether the current posture is the intended one. That is an
owner's call, and it should be made explicitly rather than inherited.
Current state, as declared in
.github/rulesets/branch-main.json(targetbranch,~DEFAULT_BRANCH,enforcement: active):required_status_checks:ci-gate, strictrequired_signatures,deletion,non_fast_forwardpull_requestwithrequired_approving_review_count: 0, thread resolutionrequired, merge-commit only
bypass_actors: repository-admin role (actor_id: 5),bypass_mode: alwaystag-semver.jsoncarries the same admin bypass over release tags, alongsidedeletion/non_fast_forward/update/required_signatures.docs/08already records the zero-approval choice honestly, so nothing here isundisclosed. The question is whether it should stay.
Why it is worth deciding rather than leaving
Consumers pin these workflows by SHA, so a change here is a supply-chain change
in someone else's repository. With zero required approvals and an always-on admin
bypass, the effective control on that supply chain is
ci-gateplus commitsigning — a single actor can author, merge and tag. That may be entirely correct
for a solo-maintained repository, and GitHub does not allow self-approval anyway,
so requiring one approval would block the sole maintainer rather than add review.
The point is that this should be a recorded decision with its compensating
controls named, not a default nobody revisited.
Options
docs/08: requiredci-gate, signed commits, immutable tags, protectedreleaseenvironmentwith a required reviewer, and the negative-gate probes.
tag-semver.jsononly, so release tags areimmutable even to an admin while day-to-day branch work is unaffected. This is
the narrowest change that strengthens the consumer-facing promise.
Note on scope
Ruleset mutation is live repository configuration and is outside what a validator
or an automated change should do. Whatever is chosen, the JSON under
.github/rulesets/andEXPECTED_BYPASS_ACTORSinscripts/check_rulesets.pymust be updated together — the validator will fail if they drift, which is the
intended behaviour.