fix(ci): separate CodeQL merge enforcement from SDL scans - #2968
fix(ci): separate CodeQL merge enforcement from SDL scans#2968Daniel Meppiel (danielmeppiel) wants to merge 2 commits into
Conversation
Keep default-branch database uploads for SDL scanning, add JavaScript coverage, and enforce current-run CodeQL results through the trusted merge gate. Retain native protection until the documented post-merge rollout. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Docs sync advisoryVerdict: no_change * Pages affected: 0 additional * LLM calls: 2/15 * Took: not recorded No additional documentation-corpus edits are needed. Rechecked after the JavaScript helper fixes: these are private CI/governance scripts, not APM commands, flags, APIs, or configuration schemas. The contributor development guide already documents the CodeQL policy, newly covered findings, and staged ruleset rollout. Classifier: high confidence, L1. The isolated classifier could not access its tools; classification was completed directly against the docs index and changed paths. No downstream panel was needed. This advisory does not gate merge. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved critical and moderate findings affect merge-queue enforcement, analysis matching, workflow provenance, freshness, command resolution, and timeout behavior.
Get a fresh assessment by requesting another Copilot review.
Review tier: Lite
Findings: 3
Open findings (4)
What changed in this PR
This PR adds workflow-scoped CodeQL enforcement to the merge gate while preserving default-branch SDL uploads.
Changes:
- Adds CodeQL policy evaluation and evidence validation.
- Expands analysis to JavaScript/TypeScript.
- Integrates gate checks, tests, lint coverage, and rollout documentation.
| File | Summary and final findings |
|---|---|
tests/unit/test_security_workflow_contracts.py |
Adds workflow contract coverage. No final findings. |
tests/unit/test_codeql_policy.py |
Adds policy behavior and edge-case tests. No final findings. |
docs/src/content/docs/contributing/development-guide.md |
Documents policy, rollout, and rollback procedures. No final findings. |
.github/workflows/merge-gate.yml |
Adds required read permissions. No final findings. |
.github/workflows/codeql.yml |
Expands scans and publishes evidence. Critical · 1 vote: PR-modified workflow output is not bound to a base-owned workflow or verified workflow revision. |
.github/workflows/ci.yml |
Includes the helper in CI checks. No final findings. |
.github/scripts/ci/merge_gate_wait.sh |
Runs CodeQL checks before and after other checks. Moderate · 1 vote: the initial policy wait can consume the entire shared 55-minute deadline. |
.github/scripts/ci/codeql_policy.py |
Implements CodeQL policy evaluation. Critical · 1 vote: merge-queue ref validation rejects the real payload shape. Moderate · 3 votes: the final consistency check does not re-read open findings. Critical · 1 vote: analysis-category matching filters out real uploads. Moderate · 1 vote: gh resolution permits PATH shadowing from the project tree. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| group["head_sha"] != sha | ||
| or group["head_ref"] != ref | ||
| or not ref.startswith("refs/heads/gh-readonly-queue/main/") | ||
| or group["base_ref"] != "refs/heads/main" |
| if record.get("analysis_key") != ANALYSIS_KEY: | ||
| return None | ||
| for language in LANGUAGES: | ||
| if record.get("category") == f"{ANALYSIS_KEY}/language:{language}": |
| - name: Record CodeQL upload identity | ||
| env: | ||
| LANGUAGE: ${{ matrix.language }} | ||
| SARIF_ID: ${{ steps.analyze.outputs.sarif-id }} | ||
| run: | | ||
| python3 - <<'PY' |
| if ( | ||
| successful_run(context, api) != run | ||
| or successful_analyses(context, api, uploads) != analyses | ||
| ): | ||
| raise Pending("CodeQL evidence changed during evaluation") |
Remove redundant nested regex repetition and validate every governance roster row rather than filtering by a URL substring. Add regression coverage for bounded log parsing and malformed roster identities. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Live CodeQL verificationVerified head
The initial PR still executes the old trusted-base gate by design. The live |


fix(ci): separate CodeQL merge enforcement from SDL scans
TL;DR
Add a trusted, workflow-scoped CodeQL policy to the existing required
gate,while preserving default-branch database uploads for external SDL scanning.
Extend coverage to JavaScript/TypeScript and require successful full-tree scans,
current-attempt upload evidence, and no open findings at blocking severity.
The native ruleset remains unchanged until the documented post-merge rollout.
Important
This PR does not remove the live
code_scanningrequirement.Keep it until the deployed replacement succeeds on a fresh PR and a merge-queue
run; only then remove CodeQL from that native rule through the API.
The initial PR still executes the old trusted base gate implementation.
Follow-up to #2870 and the maintainer's report of repeated
“Code scanning is still expecting 2 results from CodeQL” messages.
Problem (WHY)
identifies an additional
API upload / <default>configuration onmain,despite successful Python and Actions workflow uploads.
CodeQL, not a particularworkflow configuration. The external default-branch producer cannot be
satisfied by rerunning the repository's PR analysis.
contains JavaScript. Existing Python and Actions identities must stay stable.
processing can lag, and old analyses can survive a same-commit rerun.
maintainer's approval, this PR also removes ambiguous regex repetition from
smoke-log parsing and makes every governance roster row undergo validation.
The implementation follows the Agent Skills validation loop:
"do the work, run a validator (a script, a reference checklist, or a self-check), fix any issues, and repeat until validation passes."
The first review identified four gaps—diff filtering, rerun provenance,
moving-ref snapshots, and final-gate freshness—which were fixed before publishing.
Approach (WHAT)
gatecheck as the single required status-check authority.from this workflow, including pre-existing findings, as approved by the maintainer.
Implementation (HOW)
.github/scripts/ci/codeql_policy.py.github/scripts/ci/merge_gate_wait.sh.github/workflows/codeql.yml.github/workflows/merge-gate.ymlactions: readandsecurity-events: readpermissions needed to inspect evidence..github/workflows/ci.ymltests/unit/test_codeql_policy.pytests/unit/test_security_workflow_contracts.pydocs/src/content/docs/contributing/development-guide.mdscripts/daily-release-smoke-signal.cjsscripts/governance/authority.cjstests/unit/test_daily_release_smoke_signal.pytests/scripts/governance_evidence.test.cjsNo production CLI, dependency manifest, README, or CHANGELOG changes.
Diagrams
The highlighted interactions add current-run merge enforcement without replacing the independent default-branch SDL feed.
sequenceDiagram participant W as codeql.yml Analyze jobs participant A as GitHub analyses and artifacts participant S as External SDL scanner participant G as Trusted merge gate participant C as Other required CI W->>A: Upload Python, Actions, and JavaScript results rect rgb(255, 247, 200) W->>A: Record SARIF IDs for this run and attempt end alt Default branch W->>A: Publish CodeQL databases A->>S: Databases remain available S->>A: Return independent API scan results else Pull request or merge queue rect rgb(255, 247, 200) G->>A: Read exact run, attempt, ref, SHA, and alerts A-->>G: Successful scans and matching upload evidence G->>G: Reject open blocking findings end G->>C: Wait for existing required checks C-->>G: Checks complete rect rgb(255, 247, 200) G->>A: Revalidate CodeQL before passing gate A-->>G: Stable passing evidence end end Note over G,A: Native scanning rule remains until post-merge rolloutTrade-offs
severity thresholds block, including pre-existing ones. Full-tree scans cost
more than diff-informed queries; dismissals remain a deliberate human action.
need a CodeQL rerun rather than reuse evidence that can no longer be verified.
default-branch compliance scans; this does not claim to run them before merge.
deployed GitHub verification. The first PR uses the old base gate; removing
native protection before fresh PR/queue verification would create a gap.
gh,not APM imports or an editable project install in the trusted gate job.
Benefits
workflow-scoped policy after the ruleset migration.
gatecheck and existing non-CodeQL protections stay in place.Validation
Local validation against
mainat6f3dd393ce82e4aa3b56d0de292836590af2d59e.Remote CI and post-merge activation are not claimed complete.
uv run --frozen --extra dev pytest -q tests/unit/test_codeql_policy.py tests/unit/test_security_workflow_contracts.py tests/unit/test_daily_release_smoke_signal.py tests/unit/test_governance_evidence.py tests/quality --tb=shortThe live first scan completed all three languages and uploaded genuine evidence;
the candidate policy correctly rejected two high-severity JavaScript findings.
Before the fixes, the new regex regression exceeded its 10-second deadline and
the roster regression demonstrated a silently skipped malformed identity.
Both now pass without exclusions, alert dismissals, or weaker thresholds.
Type, lint, and guardrail evidence
uv run --frozen --extra dev mypy --follow-imports=skip .github/scripts/ci/codeql_policy.pyThe canonical ruff/format/pylint/auth mirror, including the new helper:
Remaining CI guards and test-quality checks:
Architecture-boundary lint and
git diff --checkexited successfully.The Mermaid diagram passed
mmdcand was visually inspected.Locked dependencies were restored through pip using uv-exported requirements
after uv's package-download transport failed; no dependency files changed.
Scenario Evidence
tests/unit/test_codeql_policy.py::test_clean_exact_commit_with_no_sdl_pr_upload_passes(regression trap for the reported missing-configuration failure)test_thresholds_block_all_open_findings_including_existing;test_all_instances_are_inspected_not_only_most_recentintests/unit/test_codeql_policy.pytests/unit/test_codeql_policy.py::test_completed_rerun_cannot_reuse_previous_attempt_sarif;test_newer_commit_analysis_cannot_use_historical_alert_snapshottests/unit/test_codeql_policy.py::test_artifact_reader_rejects_unexpected_names;test_artifact_reader_accepts_bounded_jsontests/unit/test_codeql_policy.py::test_shell_rechecks_codeql_after_other_checks_finish(real Bash orchestration with simulated external checks)tests/unit/test_security_workflow_contracts.py::test_codeql_covers_merge_queue_with_existing_analysis_configurations;test_merge_gate_executes_base_commit_scripttests/unit/test_daily_release_smoke_signal.py::test_failure_report_parses_logs_within_deadline;tests/unit/test_governance_evidence.py::test_governance_node_regressionsHow to test
Analyzejobs succeed and each publishes its current-attempt evidence artifact.9294522, remove only CodeQL fromparameters.code_scanning_tools, and verify every other rule/tool and requiredgateremain unchanged.Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com