Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/codeql-scan-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 || '' }}
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
24 changes: 24 additions & 0 deletions tests/test_codeql_scan_dispatch_workflow_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:"
Loading