Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .github/workflows/codeql-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Uploads CodeQL code scanning analyses on every PR so the org ruleset
# "CWL Central required workflows" -> code_scanning(CodeQL) can evaluate
# mergeability. Without PR-head and merge-preview SARIF on merge_commit_sha,
# approved PRs stay mergeStateStatus=BLOCKED with
# "Code scanning is waiting for results from CodeQL".
name: CodeQL PR

on:
pull_request:
branches: [main, master, develop]

permissions:
contents: read

jobs:
detect-languages:
name: Detect CodeQL languages
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.detect.outputs.matrix }}
steps:
- name: Checkout PR head
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}

- name: Build language matrix
id: detect
run: |
matrix='[]'
if [ -d .github/workflows ]; then
matrix=$(echo "$matrix" | jq -c '. + [{"language":"actions","build-mode":"none"}]')
fi
if find . -type f \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) \
-not -path './.git/*' | head -1 | grep -q .; then
matrix=$(echo "$matrix" | jq -c '. + [{"language":"javascript-typescript","build-mode":"none"}]')
fi
if find . -type f -name '*.py' -not -path './.git/*' | head -1 | grep -q .; then
matrix=$(echo "$matrix" | jq -c '. + [{"language":"python","build-mode":"none"}]')
fi
if [ "$(echo "$matrix" | jq 'length')" -eq 0 ]; then
matrix='[{"language":"actions","build-mode":"none"}]'
fi
{
echo 'matrix<<EOF'
jq -nc --argjson include "$matrix" '{include: $include}'
echo 'EOF'
} >> "$GITHUB_OUTPUT"

analyze-head:
name: CodeQL compatibility analysis (${{ matrix.language }})
needs: detect-languages
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.detect-languages.outputs.matrix) }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha }}

- name: Initialize CodeQL
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
category: "/language:${{ matrix.language }}"
upload: always
ref: ${{ format('refs/pull/{0}/head', github.event.pull_request.number) }}
sha: ${{ github.event.pull_request.head.sha }}

analyze-merge:
name: CodeQL merge preview (${{ matrix.language }})
needs: detect-languages
if: github.event.pull_request.merge_commit_sha != ''
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.detect-languages.outputs.matrix) }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4
with:
egress-policy: audit

- name: Checkout merge preview
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
ref: ${{ format('refs/pull/{0}/merge', github.event.pull_request.number) }}

- name: Initialize CodeQL
uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2
with:
category: "/language:${{ matrix.language }}-merge"
upload: always
ref: ${{ format('refs/pull/{0}/merge', github.event.pull_request.number) }}
sha: ${{ github.event.pull_request.merge_commit_sha }}
2 changes: 1 addition & 1 deletion .github/workflows/osv-scanner-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ name: OSV-Scanner PR

on:
pull_request:
branches: [main]
branches: [main, master, develop]

permissions:
# Upload SARIF to Security > Code Scanning. See github/codeql-action#2117.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ name: Scorecard PR

on:
pull_request:
branches: [main]
branches: [main, master, develop]

permissions:
contents: read
Expand Down
41 changes: 41 additions & 0 deletions docs/org-required-workflow-rollout.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Use an organization repository ruleset instead of copying workflow files into ea
- `.github/workflows/strix.yml`
- `.github/workflows/opencode-review.yml`
- `.github/workflows/pr-review-merge-scheduler.yml`
- `.github/workflows/osv-scanner-pr.yml`
- `.github/workflows/scorecard-pr.yml`
- `.github/workflows/codeql-pr.yml`
- Required workflow ref: `refs/heads/main`
- Last verified workflow implementation base commit: `ef9950e6b55bf943c0295e1df3e34c94210d21cc` (`#283`)
- Required workflow trigger support: `pull_request_target`, `push`, `workflow_run`
Expand Down Expand Up @@ -44,6 +47,44 @@ The central `.github/workflows/opencode-review.yml` is now part of the active or

Keep the OpenCode required workflow active only while the central workflow keeps proving current-head coverage, CodeGraph initialization, bounded evidence, model review output, and approval-gate publication on the current head.

## Code scanning required workflow posture

The central `.github/workflows/codeql-pr.yml`, `.github/workflows/scorecard-pr.yml`,
and `.github/workflows/osv-scanner-pr.yml` workflows supply PR-head and merge-preview
code scanning analyses for ruleset `18156473` `code_scanning` (CodeQL, Scorecard,
osv-scanner). They trigger on pull requests to `main`, `master`, and `develop` so
Git Flow repositories on `develop` inherit the same merge gate as GitHub Flow repos.

CodeQL merge preview checks out `refs/pull/<n>/merge` and uploads SARIF with
`sha: pull_request.merge_commit_sha` because the ruleset evaluates that commit,
not the ephemeral merge ref OID.

Repository-local `codeql.yml` push/default-branch scans may remain for branch
history, but PR merge gates should rely on the central `codeql-pr.yml` workflow.

### Repository-local CodeQL inventory (2026-07-04)

Org audit of default-branch workflow files. Repos without any local CodeQL
workflow depend entirely on central `codeql-pr.yml` once ruleset `18156473`
includes that path; they are the most exposed to
`Code scanning is waiting for results from CodeQL` until the ruleset update
lands.

| Repository | Default branch | Local CodeQL workflow | PR trigger | merge_commit_sha SARIF |
| --- | --- | --- | ---: | ---: |
| `aFIPC` | `master` | `codeql.yml` | yes | no |
| `bandscope` | `develop` | `codeql.yml` | yes | no |
| `newsdom-api` | `develop` | `codeql.yml` | yes | no |
| `pg-erd-cloud` | `main` | `codeql.yml`, `codeql-backfill.yml` | yes (`codeql.yml`) | no |
| `xtrmLLMBatchPython` | `develop` | `codeql.yml` | yes | no |
| `naruon` | `develop` | `codeql.yml` | yes (temporary; PR `#916` retires PR trigger) | yes (repo-local interim fix) |
| all other public non-fork org repos | varies | none observed | — | — |

No repository-local PR CodeQL workflow besides `naruon` uploads merge-preview
SARIF on `merge_commit_sha`. Centralizing through `codeql-pr.yml` fixes every
inherited repository in one ruleset change; per-repo deletion of PR triggers is
optional cleanup to avoid duplicate scans.

## Scheduler required workflow posture

The central `.github/workflows/pr-review-merge-scheduler.yml` is now part of the active organization required workflow ruleset.
Expand Down
24 changes: 24 additions & 0 deletions tests/test_codeql_pr_workflow_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]


def test_codeql_pr_workflow_uploads_head_and_merge_sarif_for_ruleset_gate() -> None:
workflow = (REPO_ROOT / ".github/workflows/codeql-pr.yml").read_text(
encoding="utf-8"
)

assert "name: CodeQL PR" in workflow
assert "branches: [main, master, develop]" in workflow
assert "upload: always" in workflow
assert "detect-languages:" in workflow
assert "analyze-head:" in workflow
assert "analyze-merge:" in workflow
assert "merge_commit_sha != ''" in workflow
assert "CodeQL merge preview" in workflow
assert "github.event.pull_request.head.sha" in workflow
assert "github.event.pull_request.merge_commit_sha" in workflow
assert "refs/pull/{0}/head" in workflow
assert "refs/pull/{0}/merge" in workflow
assert "security-events: write" in workflow
Loading