run script
github-repo-config checkto validate repo configrulesets:
Only allow commits from email ending with certain domain
# only allow commits from email ending with: # @example.com # @users.noreply.github.com (users that have "dont reveal my email" setting), or # @github.com (last one is used for github merge/squash commits) # Note: to block commits with a specific author email domain, set "negate": true in "parameters" gh api -X POST 'repos/{owner}/{repo}/rulesets' --input - <<'EOF' { "name": "restrict-emails", "target": "branch", "enforcement": "active", "conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } }, "rules": [ { "type": "commit_author_email_pattern", "parameters": { "operator": "regex", "pattern": "(@example\\.com|@users\\.noreply\\.github\\.com|^noreply@github\\.com)$" } }, { "type": "committer_email_pattern", "parameters": { "operator": "regex", "pattern": "(@example\\.com|@users\\.noreply\\.github\\.com|^noreply@github\\.com)$" } } ] } EOFProtect the default branch: require a PR (approvals 0 or 1) + resolved review threads, block deletion/force-push, require linear history, bypass "pull requests only"
# One ruleset, because "bypass_actors" is per-ruleset: split these rules across # several rulesets and you have to repeat the bypass config in each one, and a # bypass on ruleset A does not bypass ruleset B. (GitHub does not force the # grouping -- several rulesets can target the same branch and they stack, with # every applicable rule having to pass.) # # "required_review_thread_resolution" is a parameter of the "pull_request" rule, # not a rule of its own -- it is what forces codex review comments to be dealt # with before merging. # # deletion / non_fast_forward / required_linear_history are three separate rule # objects; bypass_actors is a top-level key, sibling of "rules", not inside it. # bypass_mode "pull_request" = the actor can only bypass via a PR, never on a # direct push, so an admin can force-merge a PR but nobody can push to main. gh api -X POST 'repos/{owner}/{repo}/rulesets' --input - <<'EOF' { "name": "protect-main", "target": "branch", "enforcement": "active", "conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } }, "bypass_actors": [ { "actor_id": 1, "actor_type": "OrganizationAdmin", "bypass_mode": "pull_request" } ], "rules": [ { "type": "pull_request", "parameters": { "required_approving_review_count": 0, "dismiss_stale_reviews_on_push": false, "require_code_owner_review": false, "require_last_push_approval": false, "required_review_thread_resolution": true } }, { "type": "deletion" }, { "type": "non_fast_forward" }, { "type": "required_linear_history" } ] } EOF # actor ids are not guessable -- read a ruleset that already has the bypass you want: gh api 'repos/{owner}/{repo}/rulesets' --jq '.[] | {id, name}' gh api 'repos/{owner}/{repo}/rulesets/RULESET_ID' --jq '.bypass_actors'Require code scanning results
# own ruleset: blocks merging while CodeQL has unresolved high/critical alerts gh api -X POST 'repos/{owner}/{repo}/rulesets' --input - <<'EOF' { "name": "require-code-scanning", "target": "branch", "enforcement": "active", "conditions": { "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } }, "rules": [ { "type": "code_scanning", "parameters": { "code_scanning_tools": [ { "tool": "CodeQL", "security_alerts_threshold": "high_or_higher", "alerts_threshold": "errors" } ] } } ] } EOFrepo settings:
Allow auto-merge
# enable auto-merge for a repo gh repo edit OWNER/REPO --enable-auto-merge # check if auto-merge is enabled gh repo view --json autoMergeAllowedRestrict the `prod` environment to deploy from `main` only
# 1) switch the environment to custom branch policies gh api -X PUT 'repos/{owner}/{repo}/environments/prod' --input - <<'EOF' { "deployment_branch_policy": { "protected_branches": false, "custom_branch_policies": true } } EOF # 2) allow only main (repeat the POST for each extra pattern you want to allow) gh api -X POST 'repos/{owner}/{repo}/environments/prod/deployment-branch-policies' \ -f name='main' -f type='branch' # check what is allowed now gh api 'repos/{owner}/{repo}/environments/prod/deployment-branch-policies' --jq '.branch_policies[].name'other:
main has any open high/critical code scanning alerts (detects alerts that newer CodeQL queries find in code that's already merged)