Description
Configure GitHub branch protection on main so direct pushes, force-pushes, and accidental deletions are blocked, and so PRs cannot merge until CI is green.
Why
While shipping v0.6.0 a malformed release tag (v0.5.1) had to be rolled back with git push --force-with-lease +<sha>:main. That was only possible because main is currently unprotected — and would have been irrecoverable if anyone else had already pulled the bad state. As contributor count grows (or once external PRs start landing) the cost of an accidentally-broken main rises sharply. The stable-release contract advertised by the v1.0.0 milestone needs guarantees behind it, so this should land before v1.0 ships.
Acceptance Criteria
Configure the main branch (Settings → Branches, or via gh api -X PUT repos/PMDevSolutions/Nerva/branches/main/protection):
Release-workflow compatibility
The current .github/workflows/release.yml pushes directly to main (git push --follow-tags origin ${{ github.ref_name }}) after commit-and-tag-version creates a bump commit and tag. Once "require PR before merge" is enabled this push will fail unless we make a deliberate choice:
- Option A — bypass: Add the
github-actions[bot] actor (or a dedicated release PAT) to the branch-protection bypass list. Smallest change; keeps current release.yml working as-is.
- Option B — release PR: Switch to a release-PR flow (e.g.
release-please, or have release.yml open a PR from a release/vX.Y.Z branch and auto-merge once CI is green). Cleaner audit trail, more moving parts.
- Option C — unprotected release branch: Run the release on a separate branch (e.g.
release) that doesn't have PR-required protection, then merge to main. Mostly a worse hybrid.
Decide between these as part of this issue. A is the pragmatic default for a small team; B is the right end state if/when the project grows beyond solo maintenance.
Out of scope
- CODEOWNERS configuration
- Signed-commit enforcement (
required_signatures) — probably premature pre-1.0
- Required reviews from specific reviewers (single-maintainer project for now)
- Protecting non-
main branches (release/*, staging, etc. — only relevant if Option B/C is chosen)
Description
Configure GitHub branch protection on
mainso direct pushes, force-pushes, and accidental deletions are blocked, and so PRs cannot merge until CI is green.Why
While shipping v0.6.0 a malformed release tag (v0.5.1) had to be rolled back with
git push --force-with-lease +<sha>:main. That was only possible becausemainis currently unprotected — and would have been irrecoverable if anyone else had already pulled the bad state. As contributor count grows (or once external PRs start landing) the cost of an accidentally-brokenmainrises sharply. The stable-release contract advertised by the v1.0.0 milestone needs guarantees behind it, so this should land before v1.0 ships.Acceptance Criteria
Configure the
mainbranch (Settings → Branches, or viagh api -X PUT repos/PMDevSolutions/Nerva/branches/main/protection):allow_force_pushes: false)allow_deletions: false).github/workflows/ci.yml):Validate StructureNode.js 20 CompatibilityNode.js 22 CompatibilityType-check Embedded TemplatesCheck Markdown Linksgh pr merge --squash)CONTRIBUTING.mdso contributors know what CI must pass before reviewRelease-workflow compatibility
The current
.github/workflows/release.ymlpushes directly tomain(git push --follow-tags origin ${{ github.ref_name }}) aftercommit-and-tag-versioncreates a bump commit and tag. Once "require PR before merge" is enabled this push will fail unless we make a deliberate choice:github-actions[bot]actor (or a dedicated release PAT) to the branch-protection bypass list. Smallest change; keeps currentrelease.ymlworking as-is.release-please, or haverelease.ymlopen a PR from arelease/vX.Y.Zbranch and auto-merge once CI is green). Cleaner audit trail, more moving parts.release) that doesn't have PR-required protection, then merge tomain. Mostly a worse hybrid.Decide between these as part of this issue. A is the pragmatic default for a small team; B is the right end state if/when the project grows beyond solo maintenance.
Out of scope
required_signatures) — probably premature pre-1.0mainbranches (release/*,staging, etc. — only relevant if Option B/C is chosen)