Repository navigation
feat(standards): code scanning merge protection on every default branch (CodeQL, medium_or_higher) - #1358
Conversation
Make "a code-scanning rule on every repo" an org standard: - standards/rulesets/code-quality.json gains a code_scanning rule: CodeQL, security_alerts_threshold medium_or_higher, alerts_threshold errors. GitHub's code scanning check fails only on high/critical by default, so a medium security alert merged silently. - The thresholds are a floor. scripts/lib/code-scanning.sh holds the one ordering of GitHub's threshold values; apply-rulesets.sh keeps a stricter live threshold on update (and does not PUT when it cannot read the live ruleset), so a repo at `all` is never lowered. - compliance-audit.sh: check_code_scanning_rule reads the rules that apply to the default branch (any active ruleset) and reports code-scanning-rule-missing / -weak-<field>, failing closed on an unreadable read. Stricter passes. Category rulesets, so findings route to dev-lead:hands-off like every ruleset finding. - Documented in github-settings.md (why, the floor, what feeds it, a repo with no CodeQL language, merge-queue and Dependabot limits), with pointers from ci-standards.md, advanced-security.md, the rulesets README and AGENTS.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dev-Lead — waiting on PR blockers (intent: review-changes)PR: #1358 |
|
Note @don-petry I reviewed this PR and no code changes were needed, but I can't mark it done yet: required check |
|
Advisory bots were rate-limited; auto-approval is withheld until they recover. pr-review-sweep will re-review this PR after 2026-10-20T20:48:40Z. |
|
No description provided. |
|
No actionable findings identified. The code review summary indicates a status of "Failed" but provides no specific defects tied to files or line numbers. All CI checks are passing and there are no review threads with detailed issues to address. |
Dev-Lead — fix-bot-comment (no-changes)Agent reasoning |
|
@donpetry-bot review — CI is green and the advisory bots are rate-limited (Codex out of usage, CodeRabbit limited); please review this PR. |
|
@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes. |
donpetry-bot
left a comment
There was a problem hiding this comment.
Automated review — APPROVED ✓
Risk: MEDIUM
Reviewed commit: fb98442eb650fe13b8061729cd57d715b908df19
Review mode: triage-approved (single reviewer)
Summary
Adds a CodeQL code_scanning ruleset rule (security_alerts_threshold medium_or_higher, alerts_threshold errors) to the codified code-quality ruleset as an org standard. It also adds a shared threshold-ordering library so apply-rulesets.sh never lowers a stricter live threshold and compliance-audit.sh reports a missing or weaker rule (fail-closed). Tests and docs are included. The triage low-risk call holds up. I rated it MEDIUM rather than LOW because it is non-trivial logic in fleet-wide enforcement tooling, but it only tightens security and touches no secrets.
Linked issue analysis
No closing issue is linked. #1352 is referenced for context only and is correctly not closed. The PR body explains the motivation, the expected effect on each repo (13 code-scanning-rule-missing findings, 5 self-healed) and the merge-queue limitation it did not verify.
Findings
No blocking findings.
Verified:
- Floor logic (
scripts/lib/code-scanning.sh). I sourced the library and exercised it directly. With no rule it reportsmissing. A stricterallpasses. With layered weaker rulesets it takes the strictest entry per field and reports the shortfall correctly.cs_floor_payloadkeeps a livealland raises a livenoneto the floor. An empty live ruleset gives back the codified file. Unknown or null values rank -1, so the audit fails closed and the applier never keeps them. - Applier. It does no PUT when the live ruleset can't be read, and the temp payload is cleaned up on every path. The create (POST) path is unchanged and already carries the rule.
- Audit. It reads
rules/branches/{default}across all active rulesets.pipefailis set, so aghfailure becomes-unreadableand the repo is marked inconclusive. The existingcheck_ruleset_contentsdrift check compares onlyrequired_status_checksforcode-quality, so a stricter livecode_scanningvalue won't show up as drift there. shellcheck --severity=warning -xis clean on all three scripts. bats wasn't available in this runner, but the CIbats/Lint and batsjobs pass.- No secrets or internal-only details in the diff (public repo). The MCP secret scan tool isn't available in this run; gitleaks CI passed.
Non-blocking notes:
cs_floor_payloadrewrites only the codified tool(s). A code_scanning entry for another tool in a repo's livecode-qualityruleset would be dropped on PUT. That matches the existing full-replace convergence semantics, but it is worth knowing.- The PR body lists the audit finding slugs but leaves out
code-scanning-rule-uncomparable, which the code also emits. - Rollout: the rule blocks merges while CodeQL is still running or isn't configured. The PR body says every repo has CodeQL configured; it's worth watching the first self-heal run.
CI status
All required checks are green: CodeQL, Analyze (actions/python), SonarCloud, ShellCheck, bats, Lint and bats, gitleaks, AgentShield, dependency-audit. Skipped jobs aren't relevant. There are no unresolved review threads and no unanswered human questions. Codex and CodeRabbit were rate-limited and gave no substantive findings. mergeStateStatus is BEHIND, which isn't blocking.
Reviewed automatically by the PR-review agent (single-reviewer mode: opus 5.5 [opus 4.8, opus 4.7]). Reply if you need a human review.
|
pr-review approved on PARTIAL advisory evidence: 2/5 required advisory bots reported before the gate's head-age-timeout fallback proceeded. Recorded for the miss-rate metric (#1596). |
|



What
Makes code scanning merge protection on every default branch an org standard: a
code_scanningruleset rule for CodeQL withsecurity_alerts_threshold: medium_or_higherandalerts_threshold: errors.Why: the required
CodeQLstatus check only says the analysis ran. GitHub's code scanning check fails only onhighorcriticalsecurity alerts, so a pull request that adds amediumsecurity alert merges silently. This rule blocks that merge.standards/github-settings.md§ Code scanning merge protection (All Repositories): the values, why, the floor rule, what feeds it, what a repo with no CodeQL language does, and GitHub's limits. Pointers added inci-standards.md§2,advanced-security.md(audit check 5),standards/rulesets/README.mdandAGENTS.md. TheAGENTS.mdnote this replaces said google-app-scripts had aprotect-branchesruleset with code scanning. It doesn't any more (live, it has onlycode-qualityandpr-quality), so that note was out of date.standards/rulesets/code-quality.jsongains the rule beside its required status checks, soapply-rulesets.shapplies it along with the rest ofcode-quality.scripts/lib/code-scanning.shholds the one ordering of GitHub's threshold values (none < critical < high_or_higher < medium_or_higher < all;none < errors < errors_and_warnings < all). Before a PUT,apply-rulesets.shreads the live ruleset and keeps any stricter threshold. If it cannot read the live ruleset it does not PUT, so it can never lower a stricter setting.--dry-runreports when it would keep one.compliance-audit.shgetscheck_code_scanning_rule, called fromcheck_rulesets. It readsGET repos/{o}/{r}/rules/branches/{default}, which lists the rules from every active ruleset, and compares the strictest CodeQL entry with the floor incode-quality.json. Findings:code-scanning-rule-missing,code-scanning-rule-weak-security_alerts_threshold,code-scanning-rule-weak-alerts_threshold, plus fail-closed-unreadable(the repo is also marked inconclusive) and-source-invalid. All of them use categoryrulesets, so they route todev-lead:hands-offlike every other ruleset finding. A stricter repo (all) passes.test/scripts/compliance-audit/code-scanning-rule.bats(19 tests): at the floor, stricter, the rule living in the repo's own ruleset, layered rulesets, pagination, missing, another tool only, each weaker field, an unknown value, unreadable, not-an-array, source invalid, wiring and routing.test/scripts/apply-rulesets/apply-rulesets.batsgains 9 tests: the codified rule, create, keeping a stricter live value for each field, raising a weaker one, no live rule, unreadable live means no PUT, dry-run, and the pure payload function.apply-rulesets-tests.ymlnow also triggers onscripts/lib/code-scanning.sh.Nothing here writes any live setting. The rule reaches a repo only when the audit or the applier next runs after merge.
What the next runs will change (read live on 2026-10-20, without writing)
maintodayall/errors(ownmainruleset)code-scanning-rule-missingcode-qualitycode-scanning-rule-missingcode-scanning-rule-missingcode-scanning-rule-missingcode-scanning-rule-missingcode-scanning-rule-missingapply-repo-settings.ymlstub): needsapply-rulesets.sh --repo combsmith/<repo> code-qualitywith an admin token, per the runbookmainruleset, nocode-quality)code-scanning-rule-missing, next to the ruleset findings it already getsSo the audit files 13 new
Compliance: code-scanning-rule-missingissues, one per repo, and 0 weak-threshold issues: no repo has a weaker rule today. The self-heal then fixes 5 of them. Every repo has CodeQL working, so the rule won't block merges because a tool is missing: 12 use default setupconfigured, and.githuband.github-privaterun the advancedcodeql.yml. Every repo reports at least theactionslanguage.combsmith/software-factory and #1352
software-factory asked in combsmith/.github#1352 to be left out of the compliance audit, the scorecard and the fleet monitor. That issue is still open, and the audit has no opt-out mechanism yet. This PR doesn't add one and doesn't depend on one:
mainruleset (CodeQL,all/errors, applied 2026-10-20 from its issue docs(standards): propose push protection standard #95 and recorded as a departure in its decision 0014) passes. The check files nothing there.code-qualityruleset and noapply-repo-settings.ymlstub, so nothing reaches it. Even an explicitapply-rulesets.sh --repo combsmith/software-factorywould only createcode-qualitybeside its ownmainruleset. Rulesets add together, so itsallwould still be enforced. If that repo ever moves its rule intocode-quality, the floor logic keepsall.Merge queues: verified against GitHub's docs
GitHub's merge protection page says merge protection with rulesets does not apply to "Merge queue groups", or to "Dependabot pull requests analyzed by default setup". It is "not related to status checks". The rules reference says it blocks a merge when a required tool finds an alert at the configured severity, when its analysis is still in progress, or when it "is not configured for the repository".
So in the repos with a merge queue (
.github-private,software-factory), the rule is checked on the pull request, not on themerge_grouprun. The group is gated only by required status checks, which for CodeQL means the advancedcodeql.yml'sCodeQLcheck. Not verified: whether GitHub checks the rule when a pull request is added to the queue, or only on a direct merge. The docs don't say, and I ran no trial. The standard says this.Checks run locally
shellcheck --severity=warning -x scripts/*.sh scripts/lib/*.sh: cleanbats test/scripts/apply-rulesets/ test/scripts/compliance-audit/: all pass (bash 5)markdownlint-cli2 "**/*.md": 0 errorstest/scripts/apply-repo-settings/reusable-contract.batsfails locally only becauseyqisn't installed here. It's unrelated and doesn't touch these files.🤖 Generated with Claude Code