Skip to content

ci: self-healing branch-protection + tag/release protection #94

Description

@CameronBrooks11

Summary

All 15 org repos currently have classic main protection applied and current
(verified live 2026-06-26) via scripts/apply-branch-protection.sh, required
check ok. The gap is not missing protection — it's that enforcement is
manual and incomplete:

  1. No drift-healing automation. The script is run by hand; nothing re-asserts
    it on a schedule, so protection drift is invisible until someone notices.
  2. Tags/releases are unprotected, even though providers publish versioned
    releases (tag deletion/force-push is currently possible).

Org is on GitHub Free, so org-level rulesets aren't available — we stay on the
per-repo scripted classic-protection approach, but make it self-healing.

Scope

  • Scheduled drift-healing workflow in .github that re-runs
    apply-branch-protection.sh (or asserts + diffs) across the REPOS list on a
    cron, and reports/fails on drift. Avoid passive compliance reporting — the run
    should re-apply, not just observe.
    • Needs an admin-scoped PAT secret (the default GITHUB_TOKEN can't PUT
      branch protection org-wide). Decision: store an admin PAT as an org/repo
      secret for this workflow. (owner: provision the secret.)
  • Extend the script to protect tags/releases (tag protection rules:
    block deletion + force-push on v* tags at minimum).
  • Keep the ok required-check contract intact (renaming/removing it permanently
    blocks PRs — see script comments).

Out of scope / deferred

  • Revisiting the solo-dev 0 required approvals + enforce_admins posture —
    intentional for now; revisit when more contributors join.
  • Paying for GitHub Team to get real org rulesets — not now.

Acceptance

  • A scheduled workflow re-asserts branch protection across all listed repos and
    surfaces drift loudly.
  • v* tags are protected against deletion/force-push.
  • New-repo onboarding still means "add to the REPOS list" (documented).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions