From 7920a70b47a20cbffeffe5fc3f2ee8cb33f05c99 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 20:22:26 +0900 Subject: [PATCH 1/2] fix(codeql): serialise the dispatched scan matrix with toJSON codeql-pr.yml sends client_payload.matrix as an array, and the dispatch handler assigned it straight into env:, where a value must be a scalar. GitHub rejects the step with "A sequence was not expected", so the step dies before running any of its script and the dispatched scan is skipped. The handler has 0 successes against 136 failures since #1776 added it. The validate step already reads the value through jq and checks `type == "array" and length == 1`, so JSON text is what it was written to consume; no consumer changes. Dropping the `|| ''` fallback is safe because an absent matrix yields the string "null", which fails the same array check and reaches the existing error path. Neither yaml.safe_load nor actionlint 1.7.12 reports this file as invalid -- it is an Actions template rule rather than YAML syntax, so only GitHub's validator rejects it and no local gate catches the class. The added string contract test is therefore the only guard that runs before a dispatch does. Refs #1925 Co-Authored-By: Claude Opus 5 --- .github/workflows/codeql-scan-dispatch.yml | 2 +- CHANGELOG.md | 4 ++++ ..._codeql_scan_dispatch_workflow_contract.py | 23 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql-scan-dispatch.yml b/.github/workflows/codeql-scan-dispatch.yml index 1ad28f3086..70da23870b 100644 --- a/.github/workflows/codeql-scan-dispatch.yml +++ b/.github/workflows/codeql-scan-dispatch.yml @@ -146,7 +146,7 @@ jobs: SUPPLIED_BASE_SHA: ${{ github.event.client_payload.pr_base_sha || '' }} SUPPLIED_HEAD_REF: ${{ github.event.client_payload.pr_head_ref || '' }} SUPPLIED_HEAD_SHA: ${{ github.event.client_payload.pr_head_sha || '' }} - SUPPLIED_MATRIX: ${{ github.event.client_payload.matrix || '' }} + SUPPLIED_MATRIX: ${{ toJSON(github.event.client_payload.matrix) }} SUPPLIED_REQUIRED_RUN_ID: ${{ github.event.client_payload.required_run_id || '' }} SUPPLIED_REQUIRED_JOB_ID: ${{ github.event.client_payload.required_job_id || '' }} SUPPLIED_REQUIRED_LANGUAGE: ${{ github.event.client_payload.required_language || '' }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 06b3dba425..7b040db1b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### CodeQL scan dispatch matrix serialisation + +- Serialised the dispatched CodeQL matrix with `toJSON()` in `codeql-scan-dispatch.yml`. `codeql-pr.yml` sends `client_payload.matrix` as an array and the handler assigned it straight into `env:`, where a value must be a scalar, so GitHub rejected the step with "A sequence was not expected" and the dispatched scan never ran -- 0 successes against 136 failures since the handler was added in #1776. The validate step already consumes the value through `jq`, so JSON text is the shape it was written for and no consumer changes. Added a string contract test, because neither `yaml.safe_load` nor `actionlint` 1.7.12 flags this: it is an Actions template rule, so only GitHub's own validator rejects it and no local gate catches the class. + ### Contextual-orchestrator pin refresh - Advanced the central sidecar's default immutable CO revision to protected `main@2e414d15ba58f28597751b625a8a2f00fc9fadcf`, carrying current provider discovery, `orchestrator/free` workflow budget, web-search gateway, OpenCode Go, OpenRouter composition, and CI fixes into Strix, OpenCode, and Noema. The shared ModelClient default-timeout removal remains pending in contextual-orchestrator PR #1053. All callers still consume an exact SHA; no branch or tag is introduced. diff --git a/tests/test_codeql_scan_dispatch_workflow_contract.py b/tests/test_codeql_scan_dispatch_workflow_contract.py index dbc0e4bb73..32c1bc9bbc 100644 --- a/tests/test_codeql_scan_dispatch_workflow_contract.py +++ b/tests/test_codeql_scan_dispatch_workflow_contract.py @@ -443,3 +443,26 @@ def test_dispatch_wake_allows_parallel_language_rerun_on_same_exact_run(tmp_path assert result.returncode == 0, result.stderr assert post_log.exists() + + +def test_codeql_scan_dispatch_serialises_the_matrix_payload() -> None: + """The dispatched matrix reaches `env:` as JSON text, never as a raw sequence. + + `codeql-pr.yml` sends `client_payload.matrix` as an array. An `env:` value must be + a scalar, so assigning the array directly makes GitHub reject the whole file at + template validation -- "A sequence was not expected" -- before any step runs. That + shipped in #1776 and left this workflow at 0 successes across 136 attempts. + + No local tool catches it: `yaml.safe_load` parses the file and `actionlint` 1.7.12 + reports it clean, because it is an Actions template rule rather than YAML syntax. + Only GitHub's own validator rejects it, so this string contract is the only guard + that runs before a dispatch does. The validate step consumes the value through + `jq`, so JSON text is what it already expects. + """ + workflow = WORKFLOW_PATH.read_text(encoding="utf-8") + assert ( + "SUPPLIED_MATRIX: ${{ toJSON(github.event.client_payload.matrix) }}" in workflow + ), "SUPPLIED_MATRIX must be serialised with toJSON(); a bare array breaks template validation" + assert ( + "SUPPLIED_MATRIX: ${{ github.event.client_payload.matrix" not in workflow + ), "SUPPLIED_MATRIX must not assign the raw client_payload array to env:" From eb9e59722dcfb4ea1157258852a42c80b1d3c989 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 22:43:57 +0900 Subject: [PATCH 2/2] docs(codeql): the matrix env: failure is step-scoped, not a whole-file rejection The validate-dispatch job does get a runner and its first steps run; GitHub rejects only the step whose env: receives the array, when that env: is evaluated. Docstring wording corrected to match the observed job timeline. Co-Authored-By: Claude Fable 5.1 (cherry picked from commit f90c23b3c0386e22528cc1ab8680c4a31fa630b9) --- tests/test_codeql_scan_dispatch_workflow_contract.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_codeql_scan_dispatch_workflow_contract.py b/tests/test_codeql_scan_dispatch_workflow_contract.py index 8c06e0ae55..bad19b54aa 100644 --- a/tests/test_codeql_scan_dispatch_workflow_contract.py +++ b/tests/test_codeql_scan_dispatch_workflow_contract.py @@ -495,9 +495,10 @@ def test_codeql_scan_dispatch_serialises_the_matrix_payload() -> None: """The dispatched matrix reaches `env:` as JSON text, never as a raw sequence. `codeql-pr.yml` sends `client_payload.matrix` as an array. An `env:` value must be - a scalar, so assigning the array directly makes GitHub reject the whole file at - template validation -- "A sequence was not expected" -- before any step runs. That - shipped in #1776 and left this workflow at 0 successes across 136 attempts. + a scalar, so assigning the array directly makes GitHub reject that step when its + `env:` is evaluated -- "A sequence was not expected" -- after the runner has been + assigned and the earlier steps have already run. That shipped in #1776 and left this + workflow at 0 successes across 136 attempts. No local tool catches it: `yaml.safe_load` parses the file and `actionlint` 1.7.12 reports it clean, because it is an Actions template rule rather than YAML syntax.