@@ -20,9 +20,9 @@ provisioning. Branch protection is the last guardrail.
2020| Restrict deletions | ** on** | — |
2121| Restrict pushes (no force-pushes, no direct commits) | ** on** | — |
2222| Require pull request before merging | ** on** | — |
23- | Required approving review count | ** 1** (minimum) | #95 |
23+ | Required approving review count | ** 1** (minimum) | #95 (enforced) |
2424| Dismiss stale approvals on new commits | ** on** | — |
25- | Require review from code owners | ** on** | #102 (applied via scripts/branch-protection-apply.sh ) |
25+ | Require review from code owners | ** on** | #102 (enforced via API; CODEOWNERS coverage audit remains open ) |
2626| Require status checks to pass | ** on** | — |
2727| Required status checks | see below | #94 |
2828| Require branches to be up to date before merging | ** on** | — |
@@ -31,52 +31,40 @@ provisioning. Branch protection is the last guardrail.
3131
3232### Required status checks
3333
34- The following CI checks (from ` .github/workflows/_required.yml ` ,
35- ` ci.yml ` , ` cross-repo-dispatch.yml ` , and ` promote.yml ` ) are the
36- authoritative required set :
34+ The following CI checks (from ` .github/workflows/_required.yml ` and ` ci.yml ` )
35+ are the authoritative required set. Names match the workflow job ` name: ` field,
36+ which is what GitHub uses for protection contexts :
3737
38- - ` lint-scripts ` (CI / shellcheck)
39- - ` typecheck ` (CI / ` tsc --noEmit ` )
38+ - ` lint ` (shellcheck + yamllint + mypy)
39+ - ` Lint Shell Scripts ` (ci.yml)
40+ - ` TypeScript Type Check ` (ci.yml)
4041- ` forbid-suppressions ` (no-silent-failures guard)
41- - ` unit-tests ` (YAML schema validation; to be replaced by real tests — #88 )
42- - ` integration-tests ` (cross-config reference check; to be expanded — #89 )
43- - ` markdownlint ` (docs lint)
44- - ` security/npm-audit ` (npm audit for known CVEs — #23 )
45- - ` security/secrets-scan ` (Gitleaks SARIF upload + PR gating — #23 , #86 )
46- - ` CodeQL / javascript-typescript ` (SAST for TypeScript — #23 )
47-
48- A required status check that does not actually run on a PR will block
49- merges; whenever a check is renamed, this list must be updated in the
50- same PR.
51-
52- ## Why we are not enforcing this today
53-
54- The defects in #95 (zero required approvals) and #102 (CODEOWNERS not
55- enforced in branch protection) are tracked separately. This document
56- exists so the next maintainer with admin access can apply the policy
57- in one pass without re-deriving it.
58-
59- ## Procedure to apply
60-
61- The repo-level apply is scripted and idempotent:
62-
63- 1 . ` gh auth status ` — confirm authentication has admin scope on the repo.
64- 2 . ` just branch-protection-dry-run ` — prints the merged payload ** without
65- PUT-ing it** . Review that ` required_status_checks.contexts ` lists the
66- expected checks from #94 , ` required_approving_review_count ` matches #95 ,
67- and ` restrictions ` (if non-null) lists the expected users/teams/apps.
68- 3 . ` just branch-protection-apply ` — performs read-modify-write: every sibling
69- field on ` branches/main/protection ` is round-tripped verbatim; only
70- ` require_code_owner_reviews ` is mutated to ` true ` . Safe to re-run.
71- 4 . Verify:
72- ` gh api repos/HomericIntelligence/ProjectProteus/branches/main/protection --jq '.required_pull_request_reviews.require_code_owner_reviews' `
73- prints ` true ` .
74- 5 . Close #102 once step 4 returns ` true ` .
75-
76- The script uses ` gh api -i ` to parse HTTP status lines from stdout (a stable
77- contract across ` gh ` versions), so 404 (no existing protection) is handled by
78- creating minimal protection, while 401/403 (insufficient scope) fail fast with
79- an explicit error.
42+ - ` unit-tests ` (placeholder; to be replaced — #88 )
43+ - ` integration-tests ` (placeholder; to be expanded — #89 )
44+ - ` schema-validation ` (YAML pipeline config validation)
45+ - ` markdownlint ` (documentation lint)
46+ - ` pixi-check ` (pixi lock file consistency)
47+ - ` justfile-check ` (justfile validation)
48+ - ` symlink-check ` (verify all symlinks resolve)
49+ - ` build ` (dagger build test)
50+ - ` security/secrets-scan ` (gitleaks)
51+ - ` security/dependency-scan ` (dependency audit)
52+ - ` branch-protection-test ` (offline branch protection verification)
53+
54+ ## Enforcement
55+
56+ The ruleset above is the ** literal** body of ` .github/branch-protection.main.json ` .
57+ It is applied automatically by ` .github/workflows/apply-branch-protection.yml `
58+ on every push to ` main ` that modifies the JSON file, using the admin-scoped
59+ ` BRANCH_PROTECTION_PAT ` repository secret.
60+
61+ Manual operations (admin token required):
62+
63+ - Apply / re-apply: ` GITHUB_TOKEN=<admin-pat> just apply-branch-protection `
64+ - Detect drift: ` GITHUB_TOKEN=<admin-pat> just verify-branch-protection `
65+
66+ Offline regression coverage runs on every PR via ` _required.yml ` →
67+ ` branch-protection-test ` ; no token is required.
8068
8169## See also
8270
0 commit comments