Skip to content

Branch Protection Plan (SOC 2) β€” verified, apply-ready

Status: verified against live runtime identities + GitHub ruleset mechanics. Apply main + staging Variant A now (zero automation risk). Variant B (real review gate) needs the GitHub App-token migration first β€” see Β§5.

Targets: Formal Code Review Process, Only Authorized Employees Change Code, Production Code Changes Restricted.

Path Who actually does it Healthy?
staging release Version-PR merge github-actions[bot] (default GITHUB_TOKEN) β€” release.yml’s ${RELEASE_PAT || github.token} is always github.token because RELEASE_PAT is never mapped from secrets. yes
staging feature PRs humans (dboone31), PR UI yes
main FF promotion github-actions[bot] β€” git push …:refs/heads/main on manual dispatch yes
main promotion merges dboone31 (admin), UI yes
David’s RELEASE_PAT dead / unwired β€” no workflow reads it, so post-org-move auth is irrelevant n/a

Hard constraint: the default GITHUB_TOKEN cannot be added to a ruleset bypass list for a pull_request rule. No workflow mints a custom App token today. So a require-review rule on either branch would break the bot with no bypass β€” unless the automation moves onto a custom App token first (Β§5).

The existing ruleset 6222454 (β€œPull-Requests Only”) is not truly inert β€” it already carries the Drata-shaped rules (pull_request count 0 + required_status_checks β€œVerify pnpm supply-chain controls” + bypass admin) but with an empty include[] (targets nothing). Disable it to avoid auditor confusion: gh api -X PUT repos/ERP-Unlocked/ordermatic/rulesets/6222454 -f enforcement=disabled.

  • main β€” restrict push, NO require-PR. Rules deletion + non_fast_forward; bypass = admin (RepositoryRole 5) + bot (Integration 15368). The FF push survives (a fast-forward isn’t blocked by non_fast_forward, and there’s no require-PR rule). Satisfies Production Code Changes Restricted.
  • staging Variant A (now, zero risk): required_status_checks (β€œVerify pnpm supply-chain controls” + β€œChangeset required”) + non_fast_forward, review count 0. The bot’s self-merge keeps working. Satisfies Only Authorized Employees via restricted history + required check.
  • staging Variant B (later): required_approving_review_count: 1 β€” the real review gate that Formal Code Review Process most wants β€” but only after Β§5 (App token), or it hard-breaks the release auto-merge.
Terminal window
# main β€” restrict push
gh api -X POST repos/ERP-Unlocked/ordermatic/rulesets --input - <<'JSON'
{ "name":"main - production restricted","target":"branch","enforcement":"active",
"conditions":{"ref_name":{"include":["refs/heads/main"],"exclude":[]}},
"rules":[{"type":"deletion"},{"type":"non_fast_forward"}],
"bypass_actors":[{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"always"},
{"actor_id":15368,"actor_type":"Integration","bypass_mode":"always"}] }
JSON
# staging β€” Variant A
gh api -X POST repos/ERP-Unlocked/ordermatic/rulesets --input - <<'JSON'
{ "name":"staging - reviewed integration","target":"branch","enforcement":"active",
"conditions":{"ref_name":{"include":["refs/heads/staging"],"exclude":[]}},
"rules":[{"type":"deletion"},{"type":"non_fast_forward"},
{"type":"required_status_checks","parameters":{"strict_required_status_checks_policy":false,
"do_not_enforce_on_create":false,
"required_status_checks":[{"context":"Verify pnpm supply-chain controls"},{"context":"Changeset required"}]}}],
"bypass_actors":[{"actor_id":5,"actor_type":"RepositoryRole","bypass_mode":"always"},
{"actor_id":15368,"actor_type":"Integration","bypass_mode":"always"}] }
JSON

If a POST 422s on the 15368 entry, drop that one line and re-POST β€” the admin entry + absence of a require-PR rule is what keeps the bot working.

Terminal window
# static check: main has NO pull_request rule; both target correctly
gh api repos/ERP-Unlocked/ordermatic/rulesets --jq '.[]|select(.enforcement=="active")|.id' \
| while read id; do gh api repos/ERP-Unlocked/ordermatic/rulesets/$id \
--jq '{name,target:.conditions.ref_name.include,rules:[.rules[].type]}'; done
# live: confirm the latest release auto-merge still succeeded
gh run list --workflow=release.yml -L3 --json conclusion,displayTitle
# rollback (reversible): disable a misbehaving ruleset
gh api -X PUT repos/ERP-Unlocked/ordermatic/rulesets/<ID> -f enforcement=disabled

5. Variant B unlock = the GitHub App-token migration (shared with the release plan)

Section titled β€œ5. Variant B unlock = the GitHub App-token migration (shared with the release plan)”

To require a real review on staging (and, if Drata insists on review evidence on the default branch, on main), the release/promotion automation must stop using the default GITHUB_TOKEN:

  1. Create an org GitHub App (Contents R/W, Pull-requests R/W); install on the repo.
  2. Mint a token via actions/create-github-app-token in release.yml’s auto-merge-staging job (and auto-deploy-main.yml if review-on-main is needed).
  3. Add {actor_id:<APP_ID>, actor_type:"Integration", bypass_mode:"always"} to the ruleset bypass and set required_approving_review_count: 1.

This is also the fix for the dead RELEASE_PAT config β€” see ../RELEASING.md. One App token, two problems solved.