diff --git a/skills/github-project/checkpoints.yaml b/skills/github-project/checkpoints.yaml index 458ce4b..9705cab 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,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" + 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 @@ -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: "{ISSUE_TEMPLATE/bug_report.yml,ISSUE_TEMPLATE/bug_report.md}" 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/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: "{ISSUE_TEMPLATE/feature_request.yml,ISSUE_TEMPLATE/feature_request.md}" 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/ISSUE_TEMPLATE/feature_request.yml or .md when present." # === CONTENT CHECKS === - id: GH-10 @@ -136,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)" @@ -234,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 @@ -311,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