From 1ad104a47847efad295727391967530e9e7b7e24 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 5 May 2026 08:14:05 +0200 Subject: [PATCH 1/4] feat(checkpoints): use org_provides for community-health files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GH-03 (SECURITY.md), GH-04 (CONTRIBUTING.md), GH-07 (PR template) declare org_provides: paths so the runner falls back to `gh api repos/{owner}/.github/contents/` when the local file is missing. Repos that opt into org-wide community-health files (the documented GitHub default) now stop being flagged. GH-07 also accepts both PULL_REQUEST_TEMPLATE.md and the lowercase pull_request_template.md (which is what netresearch/.github actually uses) — GitHub treats these case-insensitively. GH-05 (CODEOWNERS) intentionally stays local-only — GitHub's review routing only honours CODEOWNERS in the consuming repo, not the org's .github fallback. GH-08 / GH-09 (issue templates) declare org_provides for completeness but most orgs don't ship default issue templates; for those repos this still surfaces as a finding. When an org does provide them at {owner}/.github/.github/ISSUE_TEMPLATE/, the checkpoint passes. Signed-off-by: Sebastian Mendel --- skills/github-project/checkpoints.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/skills/github-project/checkpoints.yaml b/skills/github-project/checkpoints.yaml index 458ce4b..c54dc72 100644 --- a/skills/github-project/checkpoints.yaml +++ b/skills/github-project/checkpoints.yaml @@ -27,14 +27,16 @@ mechanical: - id: GH-03 type: file_exists target: "{SECURITY.md,.github/SECURITY.md,docs/SECURITY.md}" + org_provides: SECURITY.md severity: info - desc: "SECURITY.md should exist for vulnerability reporting (satisfied org-wide if the GitHub owner has a `.github` repo providing these files)" + desc: "SECURITY.md should exist for vulnerability reporting. Satisfied org-wide via {owner}/.github/SECURITY.md when present." - id: GH-04 type: file_exists target: "{CONTRIBUTING.md,.github/CONTRIBUTING.md,docs/CONTRIBUTING.md}" + org_provides: CONTRIBUTING.md severity: info - desc: "CONTRIBUTING.md should exist (satisfied org-wide if the GitHub owner has a `.github` repo providing these files)" + desc: "CONTRIBUTING.md should exist. Satisfied org-wide via {owner}/.github/CONTRIBUTING.md when present." - id: GH-05 type: file_exists @@ -58,9 +60,10 @@ mechanical: - id: GH-07 type: file_exists - target: .github/PULL_REQUEST_TEMPLATE.md + target: "{.github/PULL_REQUEST_TEMPLATE.md,.github/pull_request_template.md,PULL_REQUEST_TEMPLATE.md,pull_request_template.md}" + org_provides: pull_request_template.md severity: info - desc: "PR template should exist" + desc: "PR template should exist. Satisfied org-wide via {owner}/.github/pull_request_template.md when present." # Issue templates: prefer the modern `.yml` form templates (structured # fields, validation, required inputs) over legacy `.md` files. Accept @@ -68,14 +71,16 @@ mechanical: - id: GH-08 type: file_exists target: "{.github/ISSUE_TEMPLATE/bug_report.yml,.github/ISSUE_TEMPLATE/bug_report.md}" + org_provides: .github/ISSUE_TEMPLATE/bug_report.yml severity: info - desc: "Bug report template should exist (prefer .yml form template — structured fields + validation)" + desc: "Bug report template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github when present." - id: GH-09 type: file_exists target: "{.github/ISSUE_TEMPLATE/feature_request.yml,.github/ISSUE_TEMPLATE/feature_request.md}" + org_provides: .github/ISSUE_TEMPLATE/feature_request.yml severity: info - desc: "Feature request template should exist (prefer .yml form template — structured fields + validation)" + desc: "Feature request template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github when present." # === CONTENT CHECKS === - id: GH-10 From 9b777eebe572dd4f95cdcd2b9cdfe38088a5bc1e Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 5 May 2026 08:16:24 +0200 Subject: [PATCH 2/4] feat(checkpoints): add follow_uses for CodeQL/Scorecard delegation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GH-19, GH-20, and GH-21 now set follow_uses: true so the runner expands the searched workflow files with the contents of any reusable workflow referenced via uses: owner/repo/.github/workflows/file.yml@ref (one hop, fetched via gh api). The pattern then matches against either the local file OR the upstream content. This lets repos satisfy CodeQL/Scorecard checks by delegating to a shared reusable workflow (e.g. netresearch/typo3-ci-workflows/.github/ workflows/security.yml) instead of duplicating the github/codeql-action and ossf/scorecard-action wiring locally. The semantics are unchanged — the upstream workflow body must still actually use the named action. For GH-21 (regex_not for slsa-github-generator), follow_uses prevents hiding the deprecated generator inside a delegated workflow. Signed-off-by: Sebastian Mendel --- skills/github-project/checkpoints.yaml | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/skills/github-project/checkpoints.yaml b/skills/github-project/checkpoints.yaml index c54dc72..c4f492d 100644 --- a/skills/github-project/checkpoints.yaml +++ b/skills/github-project/checkpoints.yaml @@ -141,23 +141,38 @@ mechanical: type: regex target: ".github/workflows/*.{yml,yaml}" pattern: 'uses:[[:space:]]*github/codeql-action|uses:[[:space:]]*netresearch/[.]github/[.]github/workflows/codeql[.]yml' + follow_uses: true severity: warning - desc: "CodeQL must be wired up (dedicated workflow or reusable-workflow job calling github/codeql-action or netresearch/.github/...codeql.yml)" + desc: >- + CodeQL must be wired up. Satisfied by either a local workflow that uses + github/codeql-action directly, or a job that delegates to a reusable + workflow (e.g. netresearch/.github/.github/workflows/codeql.yml) whose + upstream body uses github/codeql-action. follow_uses: true expands the + search to fetch the reusable workflow contents one hop via gh api. - id: GH-20 type: regex target: ".github/workflows/*.{yml,yaml}" pattern: 'uses:[[:space:]]*ossf/scorecard-action|uses:[[:space:]]*netresearch/[.]github/[.]github/workflows/scorecard[.]yml' + follow_uses: true severity: info desc: >- - OpenSSF Scorecard must be wired up (dedicated workflow or reusable-workflow - job calling ossf/scorecard-action or netresearch/.github/...scorecard.yml) + OpenSSF Scorecard must be wired up. Satisfied by a local workflow using + ossf/scorecard-action directly, or a job that delegates to a reusable + workflow (e.g. netresearch/.github/.github/workflows/scorecard.yml) whose + upstream body uses ossf/scorecard-action. follow_uses: true expands the + search to fetch the reusable workflow contents one hop via gh api. # === SLSA PROVENANCE === + # regex_not with follow_uses: the legacy slsa-github-generator pattern must + # not appear in either the local workflow OR any one-hop reusable workflow + # body — otherwise a repo could "hide" the deprecated generator inside a + # delegated workflow and silently pass. - id: GH-21 type: regex_not target: ".github/workflows/*.{yml,yaml}" pattern: 'slsa-framework/slsa-github-generator' + follow_uses: true severity: warning desc: "Should migrate from slsa-github-generator to actions/attest-build-provenance (cannot be SHA-pinned)" From 4f2d504a6457ce7d68ae5a3835fd7f08b3b8bdbb Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 5 May 2026 11:50:03 +0200 Subject: [PATCH 3/4] fix(checkpoints): demote GH-30 (enforce_admins) from error to info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit netresearch's org-wide default leaves enforce_admins=false so admins retain bypass for emergency response — none of the surveyed mature repos enables it. Forcing severity=error against this org policy created persistent red findings everywhere. Demoted to info so the checkpoint still reminds reviewers but doesn't block as a hard failure. Description updated to make the policy choice explicit. Signed-off-by: Sebastian Mendel --- skills/github-project/checkpoints.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/skills/github-project/checkpoints.yaml b/skills/github-project/checkpoints.yaml index c4f492d..5a03d14 100644 --- a/skills/github-project/checkpoints.yaml +++ b/skills/github-project/checkpoints.yaml @@ -254,11 +254,13 @@ mechanical: type: gh_api endpoint: "repos/{owner}/{repo}/branches/{default_branch}/protection" json_path: ".enforce_admins.enabled" - severity: error + severity: info desc: >- - enforce_admins must be true on default branch — without it admins can - bypass required status checks and review requirements (audited by - GH-32 llm_review; runner skips because gh API access requires auth). + enforce_admins recommended on default branch so admins are also bound + by required status checks and review requirements. Severity is info + (not error) because netresearch's org default leaves this off — admins + retain bypass for emergency response. Tighten to true if your org + requires admin-bind policy. - id: GH-31 type: gh_api From 6e665939b39c6408793cbc6ac0230c6b6706420d Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Tue, 5 May 2026 12:00:56 +0200 Subject: [PATCH 4/4] fix(checkpoints): address PR review feedback on org_provides and GH-32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GH-07: add docs/ paths to target list and accept both upper/lowercase PULL_REQUEST_TEMPLATE.md in org_provides via brace expansion. - GH-08/09: drop redundant .github/ prefix from org_provides (path is resolved against the {owner}/.github repo root) and accept both .yml and .md forms for the org-wide fallback so repos following either Netresearch convention pass. - GH-32: align prompt with GH-30 demote — enforce_admins is advisory (info), only required_conversation_resolution remains error-level. Prevents repos following the org default (enforce_admins=false) from failing GH-32 even though GH-30 was demoted to info. Signed-off-by: Sebastian Mendel --- skills/github-project/checkpoints.yaml | 35 ++++++++++++++------------ 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/skills/github-project/checkpoints.yaml b/skills/github-project/checkpoints.yaml index 5a03d14..9705cab 100644 --- a/skills/github-project/checkpoints.yaml +++ b/skills/github-project/checkpoints.yaml @@ -60,10 +60,10 @@ mechanical: - id: GH-07 type: file_exists - target: "{.github/PULL_REQUEST_TEMPLATE.md,.github/pull_request_template.md,PULL_REQUEST_TEMPLATE.md,pull_request_template.md}" - org_provides: pull_request_template.md + target: "{.github/PULL_REQUEST_TEMPLATE.md,.github/pull_request_template.md,PULL_REQUEST_TEMPLATE.md,pull_request_template.md,docs/PULL_REQUEST_TEMPLATE.md,docs/pull_request_template.md}" + org_provides: "{PULL_REQUEST_TEMPLATE.md,pull_request_template.md}" severity: info - desc: "PR template should exist. Satisfied org-wide via {owner}/.github/pull_request_template.md when present." + desc: "PR template should exist (also accepted in docs/). Satisfied org-wide via {owner}/.github/PULL_REQUEST_TEMPLATE.md or pull_request_template.md when present." # Issue templates: prefer the modern `.yml` form templates (structured # fields, validation, required inputs) over legacy `.md` files. Accept @@ -71,16 +71,16 @@ mechanical: - id: GH-08 type: file_exists target: "{.github/ISSUE_TEMPLATE/bug_report.yml,.github/ISSUE_TEMPLATE/bug_report.md}" - org_provides: .github/ISSUE_TEMPLATE/bug_report.yml + org_provides: "{ISSUE_TEMPLATE/bug_report.yml,ISSUE_TEMPLATE/bug_report.md}" severity: info - desc: "Bug report template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github when present." + desc: "Bug report template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github/ISSUE_TEMPLATE/bug_report.yml or .md when present." - id: GH-09 type: file_exists target: "{.github/ISSUE_TEMPLATE/feature_request.yml,.github/ISSUE_TEMPLATE/feature_request.md}" - org_provides: .github/ISSUE_TEMPLATE/feature_request.yml + org_provides: "{ISSUE_TEMPLATE/feature_request.yml,ISSUE_TEMPLATE/feature_request.md}" severity: info - desc: "Feature request template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github when present." + desc: "Feature request template should exist (prefer .yml form template). Satisfied org-wide via {owner}/.github/ISSUE_TEMPLATE/feature_request.yml or .md when present." # === CONTENT CHECKS === - id: GH-10 @@ -333,21 +333,24 @@ llm_reviews: prompt: | Audit branch protection enforcement on the default branch: 1. Run: gh api repos/OWNER/REPO/branches/BRANCH/protection --jq '.enforce_admins.enabled' - Must be true. Without enforce_admins, repository admins can bypass ALL - branch protection rules: required status checks, required reviews, - required conversation resolution, and signed commit requirements. + Recommended (informational only — see GH-30). When false, repository + admins can bypass branch protection rules. Netresearch's org default + leaves this off so admins retain bypass for emergency response; + tighten to true only if your org requires admin-bind policy. Do NOT + report this as an error on its own — flag it as info/advisory. 2. Run: gh api repos/OWNER/REPO/branches/BRANCH/protection --jq '.required_conversation_resolution.enabled' Must be true. Without this, unresolved review threads do not block merges. - 3. Verify BOTH are enabled together. enforce_admins alone is insufficient if - conversation resolution is not required (admins could merge with unresolved - feedback). Conversation resolution alone is insufficient if enforce_admins - is false (admins bypass it entirely). + This is the primary error-level enforcement check (paired with GH-31). + 3. Note the interaction: enforce_admins=false means admins COULD bypass + required_conversation_resolution. Surface this as an advisory trade-off, + not a blocking failure, since it matches the documented org default. 4. If using rulesets instead of branch protection, check the equivalent: gh api repos/OWNER/REPO/rulesets --jq '.[].rules[] | select(.type=="pull_request") | .parameters' Look for required_review_thread_resolution: true and bypass_actors being empty. - Report which settings are missing and the specific security risk each creates. + Report required_conversation_resolution gaps as errors; report + enforce_admins gaps as info (advisory). severity: error - desc: "Verify enforce_admins and required_conversation_resolution are both enabled to prevent bypassing review requirements" + desc: "Verify required_conversation_resolution is enabled (error); enforce_admins is advisory only (see GH-30)." # === SUBJECTIVE CHECKS (require LLM judgment) === - id: GH-15