From 19bbdb9205f485cf5cb5d63ce43addf8db0088db Mon Sep 17 00:00:00 2001 From: felickz Date: Fri, 10 Jul 2026 23:42:44 -0400 Subject: [PATCH 1/3] ci: support full validation on workflow_dispatch (no PR context) The Build CodeQL Packs workflow (ci.yml) previously assumed every run had a PR context (github.event.number). For workflow_dispatch runs this value is empty, which caused two problems: 1. Unquoted script arguments (pr-compile.sh, pr-suites-packs.sh) meant an empty github.event.number was dropped entirely by bash word-splitting, shifting the language argument into position 1 and leaving position 2 unset - crashing immediately under set -u ("unbound variable") before any query compilation happened. 2. Every step was gated on dorny/paths-filter's src output, which is PR-diff-based and not meaningful for a manual "verify everything" run. Fixes: - Quote the PR-number/language args passed to pr-compile.sh and pr-suites-packs.sh so an empty value is passed as an explicit empty string instead of vanishing. - Add || github.event_name == 'workflow_dispatch' to every steps.changes.outputs.src == 'true' step condition (12 occurrences across compile-and-test, extensions, library-sources, and configs jobs) so a manual dispatch always runs every step regardless of path-filter. - Give pr-compile.sh, pr-suites-packs.sh, and pr-configs.sh a "full mode" fallback that activates whenever PR_NUMBER is empty: instead of calling gh pr view / gh pr comment (which require a PR), each script now enumerates the relevant files directly from the filesystem (full --warnings=error compile of the language, find over suites/*.qls, glob over configs/*.yml) and skips any PR-comment logic. This keeps a single dual-mode script per concern instead of forking separate PR/non-PR script files, avoiding future logic drift between the two paths. This lets ci.yml be dispatched manually on any branch (including main) to get a real, full compile-and-test validation without requiring an open pull request - closing the validation gap that let PR #179 get merged on the strength of the wrong CI signal. --- .github/scripts/pr-compile.sh | 14 ++++++-- .github/scripts/pr-configs.sh | 51 ++++++++++++++++++++---------- .github/scripts/pr-suites-packs.sh | 26 +++++++++++++-- .github/workflows/ci.yml | 30 +++++++++--------- 4 files changed, 85 insertions(+), 36 deletions(-) diff --git a/.github/scripts/pr-compile.sh b/.github/scripts/pr-compile.sh index fa1e056f..cdfa4f0c 100755 --- a/.github/scripts/pr-compile.sh +++ b/.github/scripts/pr-compile.sh @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -PR_NUMBER=${1} +PR_NUMBER=${1:-} LANGUAGE=${2} # to stop recompiling all queries if multiple files are modified LIBRARY_SCANNED=false @@ -9,6 +9,16 @@ LIBRARY_SCANNED=false echo "[+] Compiling all queries in $LANGUAGE" codeql query compile --threads=0 --check-only "./$LANGUAGE/" +if [[ -z "$PR_NUMBER" ]]; then + # No PR context (e.g. workflow_dispatch run directly on a branch) - there is no PR + # file list to walk, so do a full strict compile (--warnings=error) of every query + # in the language instead. This is at least as strict as the per-file PR-mode loop below. + echo "[+] No PR number provided - running full strict compile (--warnings=error) for $LANGUAGE" + codeql query compile --threads=0 --check-only --warnings=error "./$LANGUAGE/" + echo "[+] Complete" + exit 0 +fi + for file in $(gh pr view "$PR_NUMBER" --json files --jq '.files.[].path'); do if [[ ! -f "$file" ]]; then continue @@ -31,4 +41,4 @@ for file in $(gh pr view "$PR_NUMBER" --json files --jq '.files.[].path'); do fi done -echo "[+] Complete" +echo "[+] Complete" \ No newline at end of file diff --git a/.github/scripts/pr-configs.sh b/.github/scripts/pr-configs.sh index 941ab9f8..2bc3edde 100755 --- a/.github/scripts/pr-configs.sh +++ b/.github/scripts/pr-configs.sh @@ -1,31 +1,48 @@ #!/bin/bash set -euo pipefail -PR_NUMBER=${1} +PR_NUMBER=${1:-} codeql_code="/tmp/codeql-test-code" codeql_db="/tmp/codeql-test-database" -for file in $(gh pr view $PR_NUMBER --json files --jq '.files.[].path'); do +compile_config() { + local file=$1 + echo "[+] Compiling Config :: $file" + + if [[ -d "$codeql_db" ]]; then + rm -rf "$codeql_db" + fi + + mkdir -p "$codeql_code" + echo "print('Hello, World!')" > "$codeql_code/main.py" + + codeql database create \ + --source-root=$codeql_code \ + --language=python \ + --codescanning-config=$file \ + "$codeql_db" +} + +if [[ -z "$PR_NUMBER" ]]; then + # No PR context (e.g. workflow_dispatch run directly on a branch) - there is no PR + # file list to walk, so validate every config directly from the filesystem instead. + echo "[+] No PR number provided - validating all configs/*.yml" + for file in configs/*.yml; do + [[ -f "$file" ]] || continue + compile_config "$file" + done + echo "[+] Complete" + exit 0 +fi + +for file in $(gh pr view "$PR_NUMBER" --json files --jq '.files.[].path'); do if [[ ! -f "$file" ]]; then continue fi # config file if [[ "$file" == configs/*.yml ]]; then - echo "[+] Compiling Config :: $file" - - if [[ -d "$codeql_db" ]]; then - rm -rf "$codeql_db" - fi - - mkdir -p "$codeql_code" - echo "print('Hello, World!')" > "$codeql_code/main.py" - - codeql database create \ - --source-root=$codeql_code \ - --language=python \ - --codescanning-config=$file \ - "$codeql_db" + compile_config "$file" fi -done +done \ No newline at end of file diff --git a/.github/scripts/pr-suites-packs.sh b/.github/scripts/pr-suites-packs.sh index 55c6c469..c3cfd747 100755 --- a/.github/scripts/pr-suites-packs.sh +++ b/.github/scripts/pr-suites-packs.sh @@ -1,10 +1,32 @@ #!/bin/bash set -euo pipefail -PR_NUMBER=${1} +PR_NUMBER=${1:-} LANGUAGE=${2} PACK_COMPILED=false +if [[ -z "$PR_NUMBER" ]]; then + # No PR context (e.g. workflow_dispatch run directly on a branch) - there is no PR + # file list to walk, so resolve every suite and (re)build the language's packs + # directly. There is no PR to comment on, so the version-diff-comment logic below + # is intentionally skipped in this mode. + echo "[+] No PR number provided - running full suite/pack validation for $LANGUAGE" + + if [[ -d "$LANGUAGE/suites" ]]; then + while IFS= read -r -d '' suite; do + echo "[+] Compiling Suite: $suite" + codeql resolve queries "$suite" + done < <(find "$LANGUAGE/suites" -name '*.qls' -print0) + fi + + echo "[+] Compiling Pack: $LANGUAGE" + codeql pack install "$LANGUAGE" + codeql pack create "$LANGUAGE" + + echo "[+] Complete" + exit 0 +fi + for file in $(gh pr view "$PR_NUMBER" --json files --jq '.files.[].path'); do if [[ ! -f "$file" ]]; then continue @@ -72,4 +94,4 @@ for file in $(gh pr view "$PR_NUMBER" --json files --jq '.files.[].path'); do fi done -echo "[+] Complete" +echo "[+] Complete" \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 53009e5b..9c649cf1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,12 +37,12 @@ jobs: - '.github/**' - name: Setup CodeQL - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' id: install-codeql uses: ./.github/actions/install-codeql - name: Install Packs - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} CODEQL_CLI_VERSION: ${{ steps.install-codeql.outputs.codeql-cli-version }} @@ -53,14 +53,14 @@ jobs: codeql pack install "${{ matrix.language }}/test" - name: Compile Queries - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | - ./.github/scripts/pr-compile.sh ${{ github.event.number }} ${{ matrix.language }} + ./.github/scripts/pr-compile.sh "${{ github.event.number }}" "${{ matrix.language }}" - name: Test Queries - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: RUNNER_TEMP: ${{ runner.temp }} shell: python @@ -110,7 +110,7 @@ jobs: file.close() - name: Upload test results - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: actions/upload-artifact@v7 with: name: ${{ matrix.language }}-test-results @@ -119,11 +119,11 @@ jobs: if-no-files-found: error - name: Compile / Check Suites & Packs - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | - ./.github/scripts/pr-suites-packs.sh ${{ github.event.number }} ${{ matrix.language }} + ./.github/scripts/pr-suites-packs.sh "${{ github.event.number }}" "${{ matrix.language }}" validate-test-results: name: Validate test results @@ -180,11 +180,11 @@ jobs: - '${{ matrix.language }}/ext/**' - name: Setup CodeQL - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/install-codeql - name: Install Packs - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | @@ -213,11 +213,11 @@ jobs: - '${{ matrix.language }}/ext-library-sources/**' - name: Setup CodeQL - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/install-codeql - name: Install CodeQL - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | @@ -242,12 +242,12 @@ jobs: - 'configs/**' - name: Setup CodeQL - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' uses: ./.github/actions/install-codeql - name: "Check Configurations" - if: steps.changes.outputs.src == 'true' + if: steps.changes.outputs.src == 'true' || github.event_name == 'workflow_dispatch' env: GITHUB_TOKEN: ${{ github.token }} run: | - ./.github/scripts/pr-configs.sh "${{ github.event.number }}" + ./.github/scripts/pr-configs.sh "${{ github.event.number }}" \ No newline at end of file From c1e91cf711051d89422ba151d35f7b4bf92c6dcd Mon Sep 17 00:00:00 2001 From: felickz Date: Fri, 10 Jul 2026 23:56:59 -0400 Subject: [PATCH 2/3] fix: pr-suites-packs.sh full-mode must target each pack subdir, not $LANGUAGE codeql pack install/create requires a directory containing a qlpack.yml directly. No language has a top-level qlpack.yml (only nested src/, lib/, ext/, ext-library-sources/) so `codeql pack install "$LANGUAGE"` fails with "ERROR: The directory is not a qlpack." Loop over the actual pack subdirectories instead, matching what codeql-workspace.yml's `**/qlpack.yml` globs actually resolve to. Caught by dispatching this branch's workflow_dispatch run directly - cpp/go/ruby all failed identically before this fix. --- .github/scripts/pr-suites-packs.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/scripts/pr-suites-packs.sh b/.github/scripts/pr-suites-packs.sh index c3cfd747..0c853381 100755 --- a/.github/scripts/pr-suites-packs.sh +++ b/.github/scripts/pr-suites-packs.sh @@ -19,9 +19,13 @@ if [[ -z "$PR_NUMBER" ]]; then done < <(find "$LANGUAGE/suites" -name '*.qls' -print0) fi - echo "[+] Compiling Pack: $LANGUAGE" - codeql pack install "$LANGUAGE" - codeql pack create "$LANGUAGE" + for pack_dir in "$LANGUAGE/src" "$LANGUAGE/lib" "$LANGUAGE/ext" "$LANGUAGE/ext-library-sources"; do + if [[ -f "$pack_dir/qlpack.yml" ]]; then + echo "[+] Compiling Pack: $pack_dir" + codeql pack install "$pack_dir" + codeql pack create "$pack_dir" + fi + done echo "[+] Complete" exit 0 From 68528fd09dab5c0e89c7b3dba787dd031fb82a39 Mon Sep 17 00:00:00 2001 From: felickz Date: Sat, 11 Jul 2026 00:20:32 -0400 Subject: [PATCH 3/3] fix: soften full-mode compile to not fail on pre-existing warning backlog publish.yml never runs --warnings=error (only `codeql pack install`/`publish`, which don't treat warnings as fatal), so full-mode's strict recompile of the entire language directory was a brand-new, stricter check than what actually gates real publishing - and it tripped on 5 pre-existing deprecated-API warnings (getResult, getAUse, SsaVariable) that no PR-mode diff has ever caught because no PR has ever touched all of them at once. The plain compile check above already covers the whole language directory without treating warnings as fatal, so full-mode is done once that passes. Filed a follow-up issue to clean up the warning backlog and then make PR-mode itself trigger a full strict compile when a PR touches .codeqlversion or a codeql-pack.lock.yml, since a dependency/CLI bump can change behavior across every query, not just the files literally edited. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/pr-compile.sh | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/scripts/pr-compile.sh b/.github/scripts/pr-compile.sh index cdfa4f0c..ca18dd48 100755 --- a/.github/scripts/pr-compile.sh +++ b/.github/scripts/pr-compile.sh @@ -11,11 +11,17 @@ codeql query compile --threads=0 --check-only "./$LANGUAGE/" if [[ -z "$PR_NUMBER" ]]; then # No PR context (e.g. workflow_dispatch run directly on a branch) - there is no PR - # file list to walk, so do a full strict compile (--warnings=error) of every query - # in the language instead. This is at least as strict as the per-file PR-mode loop below. - echo "[+] No PR number provided - running full strict compile (--warnings=error) for $LANGUAGE" - codeql query compile --threads=0 --check-only --warnings=error "./$LANGUAGE/" - echo "[+] Complete" + # file list to walk. The plain compile above already covers every query in the + # language directory, matching what publish.yml itself requires to ship a pack + # (`codeql pack install`/`publish` - neither treats warnings as fatal). We deliberately + # do NOT re-run with --warnings=error here: today's tree has pre-existing deprecated-API + # warnings in a handful of files that were never caught because no PR-mode diff has ever + # touched all of them at once. Failing full-mode runs on that backlog would block CI-infra + # validation on unrelated debt. See the tracking issue for the plan to clean up the + # backlog and then make PR-mode itself trigger a full strict compile whenever a PR + # touches .codeqlversion or a codeql-pack.lock.yml (a dependency/CLI bump can change + # behavior across every query, not just the files literally edited). + echo "[+] No PR number provided - full compile above already covered $LANGUAGE. Done." exit 0 fi