Skip to content

Model packs (<lang>/ext, <lang>/ext-library-sources) silently apply zero models when the consumer's CodeQL CLI doesn't bundle the exact extensionTargets version #206

Description

@felickz

Summary

Every published model/extension pack in this repo (csharp/ext, csharp/ext-library-sources, go/ext, java/ext, java/ext-library-sources, python/ext) pins extensionTargets to a single exact codeql/<lang>-all version, e.g.:

# java/ext/qlpack.yml
extensionTargets:
  codeql/java-all: '9.2.1'

Per the CodeQL model pack docs, a model pack's data extensions are only injected into an analysis if the codeql/<lang>-all version actually resolved for that analysis satisfies extensionTargets. I've now empirically confirmed that when it doesn't, our sink/source/summary models are silently skipped — no error, no warning that mentions the mismatch — and the analysis just quietly loses that coverage.

This affects any consumer whose CodeQL CLI doesn't happen to bundle exactly the pinned version — not just contributors testing locally.

Reproduction (100% confirmed, not just doc-reading)

Environment: local CLI 2.25.6 (bundles codeql/java-all 9.1.2), repo pinned to CLI 2.26.1 (.codeqlversion), java/ext/qlpack.yml pins extensionTargets: codeql/java-all: '9.2.1'.

  1. codeql pack install java/test (no flags, exactly what ci.yml's "Install Dependencies" step runs):

    Nothing downloaded.
    WARNING: Pack 'codeql/java-all' was found via '--additional-packs'. If the generated
    'codeql-pack.lock.yml' file is committed to source control, other users will also have
    to use '--additional-packs' when compiling or running queries.
      (C:\Utils\codeql\qlpacks\codeql\java-all\9.1.2\qlpack.yml:1,1-1)
    ...
    Nothing to install.
    

    The CLI does not attempt to fetch the pinned 9.2.1 from the registry — it silently substitutes its own bundled 9.1.2 via the implicit "found via --additional-packs" path, with only a generic reproducibility warning (nothing that says "this doesn't satisfy the pinned version").

  2. codeql test run java/test/security/CWE-089/spring-r2dbc --failing-exitcode=122 --verbosity=progress --ram=2048 --format=json (the exact command ci.yml's "Test Queries" step runs) — the DatabaseClientSqlInjection.ql test (added in Java: model Spring R2DBC DatabaseClient and io.r2dbc.spi as SQL injection sinks #204) fails silently: 0 actual results vs. 6 expected, FAILED(RESULT), no compile error, no diagnostic about codeql/java-all or extensionTargets at all.

  3. Isolated the fix: temporarily changed java/ext/qlpack.yml's extensionTargets from the exact pin '9.2.1' to a range, '>=9.1.0 <=9.2.1', and re-ran step 2 with the same CLI (2.25.6/java-all 9.1.2, nothing else changed) — all 6 expected results now pass. This proves:

    • The MaD row schema for sinkModel/summaryModel is compatible across 9.1.29.2.1 (no breaking schema change in that span).
    • A version range instead of an exact pin is a viable, low-risk fix for this specific gap.

(Reverted both experimental edits after confirming — no code changes are included in this issue.)

Root cause (two layers)

  1. CLI dependency resolution silently prefers its own bundled codeql/<lang>-all over fetching a different pinned version from the registry, when the bundled one is found via the CLI's implicit --additional-packs-style search path — with no check that the bundled version actually satisfies the declared dependency/lock-file version, and only a generic "you'll need --additional-packs too" warning (not a version-mismatch warning). This appears to be true in both directions (older CLI + newer pin, or newer CLI + older pin) since resolution isn't semver-gated at that layer.
  2. extensionTargets then silently fails to match whatever codeql/<lang>-all version actually got resolved (per (1)), so the model pack's dataExtensions are never injected into the analysis — with no error/warning at all from this layer either.

Net effect: any consumer of a published <lang>/ext or <lang>/ext-library-sources pack — not just local contributors — whose CodeQL CLI doesn't bundle a codeql/<lang>-all inside our pinned extensionTargets range gets zero of that pack's models applied, silently, with no signal anything went wrong.

Scope

Every language's ext/ext-library-sources pack pins an exact extensionTargets version today, all set by .github/scripts/pin-codeql-library-versions.sh on every .codeqlversion bump:

Pack Current exact pin
csharp/ext, csharp/ext-library-sources codeql/csharp-all: '7.1.0'
go/ext codeql/go-all: '7.2.1'
java/ext, java/ext-library-sources codeql/java-all: '9.2.1'
python/ext codeql/python-all: '7.2.1'

So this isn't specific to the Spring R2DBC models (#204) — it's a systemic, repo-wide characteristic of how every model pack we publish is pinned.

What we can do today (partial, undocumented workaround)

Historical pack versions remain published on GHCR (e.g. githubsecuritylab/codeql-java-extensions has 13 tags going back ~3 years), and each version's OCI manifest carries a com.github.codeql.cli.version annotation recording which CLI built it — so a consumer could in principle pin their own dependency to an older, compatible release matching their CLI. But: (a) nothing documents this mapping anywhere today (a user would need to inspect GHCR manifests directly), and (b) it doesn't fully solve determinism on its own, since layer (1) above can still substitute an unexpected bundled version underneath even a correctly-pinned extensions pack.

Options to consider (needs a maintainer decision, not solo-fixing this)

  1. Broaden extensionTargets to a version range (e.g. >=X.Y.0 or a wider bound) instead of re-pinning to the exact bundle version on every CLI bump — confirmed technically viable above, but needs a decision on how wide is safe (risk: if the MaD schema ever changes within the chosen range, that's a real compile break, not just a silent skip) and whether pin-codeql-library-versions.sh's "always overwrite to exact bundle version" approach should change for extensionTargets specifically (still fine for dependencies:, which resolves/locks correctly).
  2. Document the CLI-version ↔ pack-version compatibility mapping (e.g. a table sourced from com.github.codeql.cli.version manifest annotations) so consumers on older CLIs know which pack version to pin — doesn't fix the silent-failure mode, just makes the existing workaround discoverable.
  3. File an upstream CodeQL CLI issue about layer (1) — packs found via the implicit bundled/--additional-packs path aren't checked against the declared dependency version at all, with only a generic (not version-specific) warning. Searched github/codeql issues; didn't find an existing report of this exact behavior.
  4. Some combination of the above.

Flagging this for a maintainer decision rather than picking one unilaterally, per this repo's convention that CLI-compatibility trade-offs are a judgment call, not something to resolve solo.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions