diff --git a/.github/workflows/codeql-scan-dispatch.yml b/.github/workflows/codeql-scan-dispatch.yml index 343e7af6ae..1c9dda3e45 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 dba6cbfacd..bad19b54aa 100644 --- a/tests/test_codeql_scan_dispatch_workflow_contract.py +++ b/tests/test_codeql_scan_dispatch_workflow_contract.py @@ -489,3 +489,27 @@ 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 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. + 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:"