From 4f63ccc80b7047b1b1b8651753d9f62c820b40cf Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Sat, 23 May 2026 09:16:45 +0200 Subject: [PATCH 1/2] docs(security-config): soften aspirational MUSTs to align with init template PR #77 shipped a branch-protection.json.template that sets `enforce_admins: false` and deliberately omits `required_signatures`, per the user-chosen pragmatic baseline for solo-maintainer Netresearch repos (snipe-it-docker-compose-stack, usercentrics-widgets, ldap-selfservice-password-changer, etc. all benefit from admin-bypass in emergencies; bot PRs from Dependabot/Renovate without per-repo signing setup would otherwise be blocked indefinitely). `references/security-config.md` claimed: - "enforce_admins MUST be true" (line 98) - "required_signatures | true" in the settings table (line 166) Both contradicted the new template. Anyone reading the skill now would see the contradiction as a bug, either "correct" per-repo (admin sperrt sich raus) or assume the template ignores the doc. Reframed: - `enforce_admins`: "SHOULD be true on mature multi-maintainer repos as a hardening target" + explicit "init script ships false as pragmatic baseline" + concrete upgrade command + emergency-bypass rationale. - `required_signatures`: table cell shows both states (target: true / init: unset) + bot-signing precondition + per-repo upgrade trigger. Plus the security-note callout under enforce_admins now points at the unresolved-threads memory rule as the operator-side safety valve when enforce_admins=false is the right per-repo choice. No template change in this PR; this is doc-only alignment with what PR #77 already shipped. Signed-off-by: Sebastian Mendel --- skills/github-project/references/security-config.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/skills/github-project/references/security-config.md b/skills/github-project/references/security-config.md index 88e93b5..13684f9 100644 --- a/skills/github-project/references/security-config.md +++ b/skills/github-project/references/security-config.md @@ -95,20 +95,20 @@ printf "%s\n" "/home/linuxbrew/.linuxbrew/bin" "/home/linuxbrew/.linuxbrew/sbin" ## Branch Protection: Enforce for Admins -`enforce_admins` **MUST be `true`** on the default branch. Without it, repository admins can bypass all branch protection rules including required status checks, required reviews, required conversation resolution, and signed commit requirements. +`enforce_admins` **SHOULD be `true`** on mature multi-maintainer repos as a hardening target. The [init script](repo-bootstrap.md) ships `false` as the pragmatic baseline — solo-maintainer Netresearch repos benefit from admin-bypass in emergencies (stuck required checks, ruleset races, dependency outages). Once the team has documented its emergency-merge paths and on-call coverage, tighten: ```bash # Check current state gh api repos/OWNER/REPO/branches/main/protection --jq '.enforce_admins.enabled' -# Enable enforce_admins +# Enable enforce_admins (target hardening) gh api repos/OWNER/REPO/branches/main/protection/enforce_admins -X POST # Verify -gh api repos/OWNER/REPO/branches/main/protection --jq 'if .enforce_admins.enabled then "OK: Admin enforcement enabled" else "FAIL: Admins can bypass branch protection" end' +gh api repos/OWNER/REPO/branches/main/protection --jq 'if .enforce_admins.enabled then "OK: Admin enforcement enabled" else "INFO: Admins can bypass branch protection (acceptable on solo-maintainer repos)" end' ``` -> **Security note:** Even with `required_conversation_resolution: true`, admins can merge with unresolved review threads if `enforce_admins` is `false`. Both settings must be enabled together for effective protection. +> **Security note:** Even with `required_conversation_resolution: true`, admins can merge with unresolved review threads if `enforce_admins` is `false`. For repos where the bypass is the safety valve (single maintainer, no on-call), accept the trade-off and discipline-enforce the unresolved-threads check at the operator level (see [feedback memory: HARD RULE — NEVER merge with unresolved review threads](https://github.com/netresearch/github-project-skill/blob/main/skills/github-project/references/repo-bootstrap.md)). For repos with multiple maintainers, both settings should be enabled together. ## Branch Protection: Required Reviews @@ -163,7 +163,7 @@ For signed commits workflow (rebase locally + merge commit): | Branch Protection | Value | Why | |-------------------|-------|-----| -| `required_signatures` | true | Enforces GPG/SSH signed commits | +| `required_signatures` | target: `true`; [init](repo-bootstrap.md): unset | Enforces GPG/SSH signed commits. Init script omits this so Dependabot/Renovate bot PRs aren't blocked before each bot's signing flow is configured per-repo. Turn on once you've verified bot signing works (Renovate `gitSignOff: true` + Dependabot secret-based signing or `gh api PATCH`). | | `required_linear_history` | **false** | Must be false - conflicts with merge commits | | `required_conversation_resolution` | true | All review threads must be resolved before merge | From 0e7cd21989de23ce013060dd4b536ba63faee5dd Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Sat, 23 May 2026 09:54:31 +0200 Subject: [PATCH 2/2] review(PR-79): address copilot + gemini feedback on link + API references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three medium-priority threads on PR #79, all addressed: 1. (gemini) absolute github.com/blob/main URL → relative path `[the bootstrap reference](repo-bootstrap.md)`. Survives forks, offline renders, future branch renames. 2. (copilot) link text described "feedback memory" but linked at the bootstrap reference (which is the right page; the wrong claim was only in the link's display text). Rephrased the text to match what the reader will actually find on the linked page: "the pre-merge GraphQL query operators should run before every `gh pr merge`". 3. (copilot) `gh api PATCH` was ambiguous (no endpoint, no fields). Replaced with the concrete enablement command + verify command: `gh api repos/OWNER/REPO/branches/main/protection/required_signatures -X POST` plus the `.required_signatures.enabled` jq probe. Signed-off-by: Sebastian Mendel --- skills/github-project/references/security-config.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skills/github-project/references/security-config.md b/skills/github-project/references/security-config.md index 13684f9..b761c9b 100644 --- a/skills/github-project/references/security-config.md +++ b/skills/github-project/references/security-config.md @@ -108,7 +108,7 @@ gh api repos/OWNER/REPO/branches/main/protection/enforce_admins -X POST gh api repos/OWNER/REPO/branches/main/protection --jq 'if .enforce_admins.enabled then "OK: Admin enforcement enabled" else "INFO: Admins can bypass branch protection (acceptable on solo-maintainer repos)" end' ``` -> **Security note:** Even with `required_conversation_resolution: true`, admins can merge with unresolved review threads if `enforce_admins` is `false`. For repos where the bypass is the safety valve (single maintainer, no on-call), accept the trade-off and discipline-enforce the unresolved-threads check at the operator level (see [feedback memory: HARD RULE — NEVER merge with unresolved review threads](https://github.com/netresearch/github-project-skill/blob/main/skills/github-project/references/repo-bootstrap.md)). For repos with multiple maintainers, both settings should be enabled together. +> **Security note:** Even with `required_conversation_resolution: true`, admins can merge with unresolved review threads if `enforce_admins` is `false`. For repos where the bypass is the safety valve (single maintainer, no on-call), accept the trade-off and discipline-enforce the unresolved-threads check at the operator level (see [the bootstrap reference](repo-bootstrap.md) for the pre-merge GraphQL query operators should run before every `gh pr merge`). For repos with multiple maintainers, both settings should be enabled together. ## Branch Protection: Required Reviews @@ -163,7 +163,7 @@ For signed commits workflow (rebase locally + merge commit): | Branch Protection | Value | Why | |-------------------|-------|-----| -| `required_signatures` | target: `true`; [init](repo-bootstrap.md): unset | Enforces GPG/SSH signed commits. Init script omits this so Dependabot/Renovate bot PRs aren't blocked before each bot's signing flow is configured per-repo. Turn on once you've verified bot signing works (Renovate `gitSignOff: true` + Dependabot secret-based signing or `gh api PATCH`). | +| `required_signatures` | target: `true`; [init](repo-bootstrap.md): unset | Enforces GPG/SSH signed commits. Init script omits this so Dependabot/Renovate bot PRs aren't blocked before each bot's signing flow is configured per-repo. Turn on once you've verified bot signing works: `gh api repos/OWNER/REPO/branches/main/protection/required_signatures -X POST`. Verify with `gh api repos/OWNER/REPO/branches/main/protection --jq '.required_signatures.enabled'`. | | `required_linear_history` | **false** | Must be false - conflicts with merge commits | | `required_conversation_resolution` | true | All review threads must be resolved before merge |