Skip to content

ci: replace classic branch protection with a bypassable ruleset - #61

Merged
loadinglucian merged 3 commits into
mainfrom
ci/ruleset-merge-protection
Aug 4, 2026
Merged

ci: replace classic branch protection with a bypassable ruleset#61
loadinglucian merged 3 commits into
mainfrom
ci/ruleset-merge-protection

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Migrates merge protection from classic branch protection to a protect_main repository ruleset; see commit message for details.

Summary by CodeRabbit

  • New Features

    • Updated main-branch protection with required reviews, status checks, linear history, and squash-only merges.
    • Owner-authored changes to protected paths can pass the protected-controls check without additional approval.
  • Bug Fixes

    • Improved automation for consistently applying and maintaining repository protection settings.
    • Added validation for protected-change approval behavior.
    • Updated repository configuration snapshots and administrative records to reflect current protection and workflow settings.

@cursor

cursor Bot commented Aug 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_c2d348e6-f8ab-4742-abd5-29d1c927b42e)

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e671354c-a6a0-421f-91a0-16d186c93c83

📥 Commits

Reviewing files that changed from the base of the PR and between b395c30 and f71e13c.

📒 Files selected for processing (6)
  • .github/workflows/protected-controls.yml
  • docs/admin-state/php-bin-after.json
  • docs/repository-settings.md
  • scripts/configure-github-autorelease
  • scripts/snapshot-github-admin-state
  • tests/test_autorelease.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • scripts/snapshot-github-admin-state
  • .github/workflows/protected-controls.yml
  • docs/admin-state/php-bin-after.json
  • tests/test_autorelease.py
  • docs/repository-settings.md
  • scripts/configure-github-autorelease

📝 Walkthrough

Walkthrough

The PR adds an owner-authored bypass to protected-controls and replaces classic main branch protection with an idempotently managed protect_main ruleset. Documentation, the administrative snapshot, and tests reflect the updated behavior.

Changes

Protected controls and repository ruleset

Layer / File(s) Summary
protect_main ruleset provisioning and state capture
scripts/configure-github-autorelease, scripts/snapshot-github-admin-state, docs/admin-state/php-bin-after.json
The script creates or updates protect_main, removes classic protection, and handles duplicate or unexpected protection states. Snapshot collection now fetches full ruleset details. The administrative snapshot records the updated repository state.
Repository ruleset settings documentation
docs/repository-settings.md
Documentation defines protect_main, required checks, administrator bypasses, and protected-controls approval behavior.
Owner-authored protected-path bypass
.github/workflows/protected-controls.yml, tests/test_autorelease.py
The workflow accepts owner-authored protected changes before automation exemptions and approval lookup. The test verifies this ordering.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequest
  participant ProtectedControls
  participant GitHub
  PullRequest->>ProtectedControls: Submit protected-path change
  ProtectedControls->>GitHub: Read author and configured owner
  GitHub-->>ProtectedControls: Owner identity
  ProtectedControls-->>PullRequest: Pass owner-authored change
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description states the main change but omits the required Verification and Security and licensing sections. Add the required template sections and complete the verification, security, licensing, and compatibility checks.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes replacing classic branch protection with a bypassable ruleset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/ruleset-merge-protection

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
tests/test_autorelease.py (1)

874-883: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover all ordering boundaries in the authorization test.

The workflow has a second trusted-automation branch for autorelease/(event|eol-complete)-*, followed by the reviews = api(...) lookup. Assert that the owner bypass precedes both locations.

Proposed test additions
         self.assertLess(owner_pass, protected.index('re.fullmatch(r"autorelease/evidence-'))
+        self.assertLess(
+            owner_pass,
+            protected.index('re.fullmatch(r"autorelease/(event|eol-complete)-'),
+        )
+        self.assertLess(owner_pass, protected.index("reviews = api("))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_autorelease.py` around lines 874 - 883, Extend
test_protected_controls_pass_owner_authored_changes_before_bot_exemptions to
assert that the owner_pass position precedes the second trusted-automation
branch matching autorelease/(event|eol-complete)-* and the subsequent reviews =
api(...) lookup, while retaining the existing no-protected-path and first
automation-branch ordering assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/test_autorelease.py`:
- Around line 874-883: Extend
test_protected_controls_pass_owner_authored_changes_before_bot_exemptions to
assert that the owner_pass position precedes the second trusted-automation
branch matching autorelease/(event|eol-complete)-* and the subsequent reviews =
api(...) lookup, while retaining the existing no-protected-path and first
automation-branch ordering assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 460a24b8-c24e-4a4f-9c49-7592afdd344b

📥 Commits

Reviewing files that changed from the base of the PR and between 1e3b14f and ed498ad.

📒 Files selected for processing (4)
  • .github/workflows/protected-controls.yml
  • docs/repository-settings.md
  • scripts/configure-github-autorelease
  • tests/test_autorelease.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/admin-state/php-bin-after.json`:
- Around line 115-135: Update the ruleset snapshot generation for the
protect_main ruleset (id 20378719) to fetch the full ruleset details via the
repository ruleset GET endpoint before serializing rulesets. Regenerate the
snapshot so conditions, bypass_actors, and rules are included while preserving
the existing metadata.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b6377c69-9396-4b9a-aacf-32cd6014d4ea

📥 Commits

Reviewing files that changed from the base of the PR and between ed498ad and e0aa68b.

📒 Files selected for processing (1)
  • docs/admin-state/php-bin-after.json

Comment thread docs/admin-state/php-bin-after.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
scripts/snapshot-github-admin-state (1)

117-122: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Document the rulesets shape.

Keep schemaVersion: 1; the v1 after fixture already stores conditions, rules, and bypass_actors. Add an explicit schema or fixture assertion for this detailed shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/snapshot-github-admin-state` around lines 117 - 122, Update the
rulesets fixture handling around the rulesets collection to explicitly assert or
document the v1 shape, including conditions, rules, and bypass_actors, while
preserving schemaVersion: 1 and the existing single_document generation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/snapshot-github-admin-state`:
- Around line 117-122: Update the rulesets fixture handling around the rulesets
collection to explicitly assert or document the v1 shape, including conditions,
rules, and bypass_actors, while preserving schemaVersion: 1 and the existing
single_document generation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 478fdf2c-0b4e-4650-94be-33759667d982

📥 Commits

Reviewing files that changed from the base of the PR and between e0aa68b and b395c30.

📒 Files selected for processing (2)
  • docs/admin-state/php-bin-after.json
  • scripts/snapshot-github-admin-state
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/admin-state/php-bin-after.json

The configure script now installs a protect_main ruleset (same PR,
check, and history rules) with repository administrators as bypass
actors in pull_request mode, and removes classic protection along with
the enforce_admins toggle the old merge procedure depended on.
Protected controls now passes owner-authored PRs: a solo owner cannot
approve their own PR, so that requirement was unsatisfiable and every
such merge ended in an administrative bypass regardless. The gate keeps
its full strength against non-owner authors.
The ruleset list endpoint returns metadata only, so the snapshot could
not show drift in conditions, rules, or bypass actors now that the
ruleset is the merge protection. Each ruleset is re-fetched
individually and both snapshots are regenerated.
@loadinglucian
loadinglucian force-pushed the ci/ruleset-merge-protection branch from b395c30 to f71e13c Compare August 4, 2026 13:20
loadinglucian added a commit to Bigpixelrocket/mise-php that referenced this pull request Aug 4, 2026
## What

Companion to Bigpixelrocket/php-bin#61.

- `.github/workflows/protected-controls.yml`: owner-authored PRs now
pass. A solo owner cannot approve their own PR, so the exact-head
owner-review requirement was unsatisfiable for owner-authored changes
and always ended in an administrative bypass. The short-circuit sits
before the readiness-record exemption, so it cannot widen what the
automation identity may merge; all non-owner authors still require the
exact-head owner approval.
- `docs/repository-settings.md`: documents the `protect_main` ruleset
model (installed by php-bin's configure script) with repository
administrators as bypass actors in `pull_request` mode, replacing
classic branch protection and its enforce_admins toggle.
- `test/test_autorelease.py`: pins the owner short-circuit's position
relative to the automation exemption.

## Notes

- `protected-controls.yml` runs on `pull_request_target`, so the
owner-pass behavior takes effect only after this merges; this PR itself
shows the old red-by-design failure.
- Admin-state snapshot will be refreshed once the ruleset migration has
been applied.

## Verification

`./scripts/test.sh` passes (23 tests).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

- **New Features**
- Updated repository controls to support streamlined handling of
owner-authored changes.
- Added comprehensive main-branch protections, including pull requests,
required reviews and checks, resolved threads, linear history, and
safeguards against force pushes and branch deletion.
  - Updated protected-path validation and approval requirements.

- **Documentation**
- Updated repository settings documentation and administrative state
records to reflect the new controls.

- **Tests**
  - Added regression coverage for protected-control evaluation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
@loadinglucian
loadinglucian merged commit 5adef4c into main Aug 4, 2026
4 of 5 checks passed
@loadinglucian
loadinglucian deleted the ci/ruleset-merge-protection branch August 4, 2026 13:37
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