From b934ba8779949abf4db6d9c7bf027433fc6db617 Mon Sep 17 00:00:00 2001 From: Neil Smithline Date: Wed, 26 Aug 2026 11:33:55 -0400 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20correct=20new-repo=20section=20?= =?UTF-8?q?=E2=80=94=20bootstrapping=20is=20not=20automatic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Adding a new repo" section claimed new repos are "protected as soon as they're created." That is false and actively dangerous: a brand-new empty repo's first commit cannot go through a PR (no base branch exists), and pushing code then renaming/repointing a side branch onto the default lands unscanned code on a protected branch while the ruleset still reports all rules active. Replace it with explicit guidance: create repos with --add-readme so the default branch exists and is protected from commit zero, do real work via PRs, and treat a GH013 rejection as stop-and-report rather than something to route around — for humans and AI coding agents alike. Co-Authored-By: Claude Opus 4.8 --- docs/security-review-setup.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/docs/security-review-setup.md b/docs/security-review-setup.md index 3587a8f..e9fa18f 100644 --- a/docs/security-review-setup.md +++ b/docs/security-review-setup.md @@ -63,10 +63,35 @@ access set to "All repositories." The required workflow forwards it via There should be no repo-level copies of `ANTHROPIC_API_KEY` — they are redundant and create drift. -## Adding a new repo - -Nothing. The ruleset targets every repo in the org by default, so new -repos are protected as soon as they're created. +## Creating a new repo + +**Create every new repo with its default branch already initialized** — +`gh repo create --add-readme`, or tick "Add a README file" in the +UI. Then do all real work through pull requests, as normal. + +Why this matters, and what NOT to do: + +The ruleset protects the default branch of every repo, but it can only +act on a branch that already exists. A brand-new **empty** repo has no +default branch yet, so its very first commit cannot go through a PR — a +PR needs an existing base branch (chicken-and-egg). `--add-readme` makes +that unavoidable first commit a server-side README with no code in it, +and the default branch exists and is protected from that point on, so all +real code arrives via a scanned PR. + +If instead you create an empty repo and push code to it, you will hit the +gate — and there is a wrong way around it. **Do not** push your code to a +side branch and then rename it onto the default, or repoint the default +branch at it, or use an admin bypass. Every one of those lands unscanned +code on a protected branch while leaving the ruleset reporting all rules +active — the repo *looks* governed but its initial code never was. If a +push is rejected with `GH013 ... Required workflow 'Claude Security +Review (required)' is not satisfied`, that is the gate working as +intended. Start over with `--add-readme` and open a PR. + +> This holds for any tool driving the repo — a human, or an AI coding +> agent (Claude Code, Codex, Gemini, …). A rejected push is a +> stop-and-report signal, never an obstacle to engineer around. ## Bypassing in an emergency From 780bc5f6faa2983eb978e17d22bf42bae44f560d Mon Sep 17 00:00:00 2001 From: Neil Smithline Date: Wed, 26 Aug 2026 11:44:39 -0400 Subject: [PATCH 2/3] docs: distinguish the sanctioned PR flow from the bypass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewer point: "a rejected push is never an obstacle to engineer around" was too blunt — it could read as discouraging the legitimate recovery (move changes to a branch, push, open a PR), which is the intended workflow, not a workaround. Split the guidance in two: (1) a rejected push to an existing default branch just means "open a PR instead" — that works and is sanctioned; the bypass is specifically landing code on the default WITHOUT a scanned PR (rename onto default, repoint default, admin bypass). (2) commit zero in a brand-new empty repo is the one case branch-and-PR cannot cover (no base branch to target), which is why repos must be created with --add-readme. Co-Authored-By: Claude Opus 4.8 --- docs/security-review-setup.md | 54 +++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/docs/security-review-setup.md b/docs/security-review-setup.md index e9fa18f..5132ce8 100644 --- a/docs/security-review-setup.md +++ b/docs/security-review-setup.md @@ -69,29 +69,39 @@ redundant and create drift. `gh repo create --add-readme`, or tick "Add a README file" in the UI. Then do all real work through pull requests, as normal. -Why this matters, and what NOT to do: - -The ruleset protects the default branch of every repo, but it can only -act on a branch that already exists. A brand-new **empty** repo has no -default branch yet, so its very first commit cannot go through a PR — a -PR needs an existing base branch (chicken-and-egg). `--add-readme` makes -that unavoidable first commit a server-side README with no code in it, -and the default branch exists and is protected from that point on, so all -real code arrives via a scanned PR. - -If instead you create an empty repo and push code to it, you will hit the -gate — and there is a wrong way around it. **Do not** push your code to a -side branch and then rename it onto the default, or repoint the default -branch at it, or use an admin bypass. Every one of those lands unscanned -code on a protected branch while leaving the ruleset reporting all rules -active — the repo *looks* governed but its initial code never was. If a -push is rejected with `GH013 ... Required workflow 'Claude Security -Review (required)' is not satisfied`, that is the gate working as -intended. Start over with `--add-readme` and open a PR. - -> This holds for any tool driving the repo — a human, or an AI coding +### If a push to the default branch is rejected + +Putting your changes on a feature branch, pushing that, and opening a PR +is the **normal workflow, not a workaround** — the PR gets scanned and +merges once it passes. A `GH013 ... Required workflow 'Claude Security +Review (required)' is not satisfied` rejection on a direct push to the +default branch just means "open a PR instead." + +What *is* a bypass is getting code onto the default branch **without a +scanned PR**: pushing it to a side branch and then renaming that branch +onto the default, repointing the default branch at it, or an admin bypass +merge. Each lands unscanned code on a protected branch while the ruleset +still reports every rule active — the repo *looks* governed, but that +code never was. Do not do this. + +### The one case branch-and-PR can't cover: commit zero + +The ruleset protects a default branch that already exists. A brand-new +**empty** repo has no default branch yet, and a PR needs an existing base +branch to target — so the very first commit cannot go through a PR at all +(chicken-and-egg). This is exactly the gap the rename/repoint trick +abuses to smuggle a whole initial codebase in unscanned. + +The fix is to never let commit zero carry code: create the repo with +`--add-readme` so the first commit is a harmless server-side README, the +default branch exists and is protected from that point on, and every real +change after it arrives through a scanned PR. + +> This holds for any tool driving the repo — a person, or an AI coding > agent (Claude Code, Codex, Gemini, …). A rejected push is a -> stop-and-report signal, never an obstacle to engineer around. +> stop-and-report signal: open a PR, or (for a new repo) recreate it with +> `--add-readme` — never route the code onto the default branch some +> other way. ## Bypassing in an emergency From 94adcf9e29a5828693e3adad9ce539dd47b548b2 Mon Sep 17 00:00:00 2001 From: Neil Smithline <766467+Neil-Smithline@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:49:04 -0400 Subject: [PATCH 3/3] Update security review guidelines for PRs Clarify the importance of using a scanned PR to avoid bypassing security checks on the default branch. --- docs/security-review-setup.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/security-review-setup.md b/docs/security-review-setup.md index 5132ce8..e3316e2 100644 --- a/docs/security-review-setup.md +++ b/docs/security-review-setup.md @@ -72,17 +72,17 @@ UI. Then do all real work through pull requests, as normal. ### If a push to the default branch is rejected Putting your changes on a feature branch, pushing that, and opening a PR -is the **normal workflow, not a workaround** — the PR gets scanned and +is the **normal workflow** — the PR gets scanned and merges once it passes. A `GH013 ... Required workflow 'Claude Security Review (required)' is not satisfied` rejection on a direct push to the default branch just means "open a PR instead." -What *is* a bypass is getting code onto the default branch **without a -scanned PR**: pushing it to a side branch and then renaming that branch -onto the default, repointing the default branch at it, or an admin bypass -merge. Each lands unscanned code on a protected branch while the ruleset -still reports every rule active — the repo *looks* governed, but that -code never was. Do not do this. +Do not use any strategy that allows bypassing the security check and getting code onto the default branch +**without a scanned PR**. This includes pushing it to a side branch and then +renaming that branch onto the default, repointing the default branch at it, or +an admin bypass merge. Each lands unscanned code on a protected branch while +the ruleset still reports every rule active — the repo *looks* governed, but that +code never was scanned. Do not do this. ### The one case branch-and-PR can't cover: commit zero