Skip to content

fix(java): remove duplicate codeql-java-extensions dependency causing fatal analysis crash#155

Merged
felickz merged 2 commits into
mainfrom
felickz-fix-java-duplicate-extensions-pack
Jul 10, 2026
Merged

fix(java): remove duplicate codeql-java-extensions dependency causing fatal analysis crash#155
felickz merged 2 commits into
mainfrom
felickz-fix-java-duplicate-extensions-pack

Conversation

@felickz

@felickz felickz commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Stacked on #126. This PR is based on jcogs33/update-to-v0.2.2 (PR #126), which does a blanket repo-wide version bump including java/lib/qlpack.yml0.2.2. Since that version will already be published (with this bug still present) once #126 lands, this PR bumps java/lib to 0.2.3 instead, so the fix actually triggers a republish. Once #126 merges to main, this PR's base should be updated to main (the diff will be unchanged — just the removed dependency line and the version bump to 0.2.3).

Bug

Any Java scan using one of this repo's published configs (configs/default.yml, configs/synthetics.yml, configs/audit.yml) fails with a fatal CodeQL error:

com.semmle.util.exception.CatastrophicError: Encountered two packs with the same name 'Optional[githubsecuritylab/codeql-java-extensions]' used in a single evaluation.

Confirmed against a real, 100%-reproducible failing GitHub Actions run using configs/synthetics.yml verbatim from this repo: dsp-testing/SecurityShepherd run 28809261039, job 85432641504. The crash happens during the java-kotlin analyze step, right after "Resolving data extensions".

Root cause

java/lib/qlpack.yml hard-pinned githubsecuritylab/codeql-java-extensions: '0.2.1' as a dependency. All three published configs also list githubsecuritylab/codeql-java-extensions directly in their packs: list (to load its MaD data extension models). This means the same pack gets resolved twice in a single evaluation:

  • transitively: codeql-java-queriescodeql-java-libscodeql-java-extensions
  • directly: from the config's packs: list

The CodeQL CLI can't reconcile the two resolved instances of the same named pack and fatally errors.

Why only Java is affected: csharp/lib/qlpack.yml only depends on codeql/csharp-allcodeql-csharp-extensions is not baked into csharp-libs, it's purely opt-in via config, same as every other language. Java is the only lib pack that hard-pinned its extensions pack as a dependency (added in #8f4ee8a, "feat: add utility predicates and classes for Java library").

Nothing in java/lib actually needs codeql-java-extensions at QL-compile time: java/lib/ghsl/Utils.qll only imports standard semmle.code.java.* library modules. The extensions pack is a pure MaD data pack (see java/ext/qlpack.yml) with no QL code to import — the dependency existed only to bundle/pull in the pack, which is redundant since every shipped config already lists it explicitly.

Fix

  • Remove the githubsecuritylab/codeql-java-extensions: '0.2.1' line from java/lib/qlpack.yml's dependencies:, bringing Java in line with C# (and every other language) where the extensions pack is purely opt-in via config.
  • Bump java/lib version to 0.2.3 (see stacking note above re: why not 0.2.2) so the fix gets published (.github/workflows/publish.yml compares each pack's qlpack.yml version against what's already published on GHCR, independently per pack).

No other qlpack.yml under java/ needs changes:

  • java/src/qlpack.yml depends on githubsecuritylab/codeql-java-libs: '*', unaffected.
  • java/test/qlpack.yml intentionally keeps its own direct githubsecuritylab/codeql-java-extensions: '*' dependency (for testing the extension models directly) — untouched.
  • java/ext/qlpack.yml (the extensions pack itself) is unchanged.

Lock files (codeql-pack.lock.yml) don't need updating — they only record resolved published-registry packs (e.g. codeql/java-all); local in-workspace packs like codeql-java-libs/codeql-java-extensions are resolved via codeql-workspace.yml and never appeared in the lock files, so removing this dependency doesn't change lock content.

Verification

Local sandbox only had CodeQL CLI 2.25.6 available, not the repo's pinned 2.21.1 (.codeqlversion), so local results can't perfectly reproduce or validate against the exact pinned toolchain:

  • Compiled representative Java queries (including ones importing java/lib/ghsl.qll) with codeql query compile — succeeds cleanly after the fix, no dependency/syntax errors.
  • Ran a subset of the Java test suite (codeql test run) — passing.
  • Attempted to locally reproduce the exact duplicate-pack crash using local workspace pack resolution (--additional-packs); this didn't reproduce because local resolution dedupes identical filesystem paths, whereas the production failure occurs when the registry resolves the same named pack into two distinct locations (once as a transitive dependency, once as a directly-requested config pack).

This repo's CI (.github/workflows/ci.yml) installs the actual pinned 2.21.1 CLI and runs the real Java analyze/compile/test jobs — that run is the authoritative validation of this fix, since it uses the correct pinned toolchain rather than the newer, mismatched local CLI.

Copilot AI review requested due to automatic review settings July 6, 2026 18:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a fatal CodeQL Java analysis crash caused by resolving githubsecuritylab/codeql-java-extensions twice (once transitively via java/lib and once directly via published configs), by removing the redundant hard dependency from the Java libs pack and bumping its version so the fix publishes.

Changes:

  • Remove githubsecuritylab/codeql-java-extensions from java/lib/qlpack.yml dependencies to avoid duplicate-pack resolution.
  • Bump githubsecuritylab/codeql-java-libs version from 0.2.1 to 0.2.2 for publishing.
Show a summary per file
File Description
java/lib/qlpack.yml Removes the redundant extensions dependency and bumps the pack version to publish the fix.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Low

@felickz felickz force-pushed the felickz-fix-java-duplicate-extensions-pack branch from b009584 to 362fe7d Compare July 6, 2026 18:09
@felickz felickz changed the base branch from main to jcogs33/update-to-v0.2.2 July 6, 2026 18:10
… fatal analysis crash

Rebased onto main (0.2.2 already synced/published for real via #158) instead
of the stale #126 branch. Bumps java/lib to 0.2.3 so the fix actually
publishes, since 0.2.2 is already live on GHCR with this bug present.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@felickz felickz force-pushed the felickz-fix-java-duplicate-extensions-pack branch from 362fe7d to db2cd3d Compare July 9, 2026 21:53
@felickz felickz changed the base branch from jcogs33/update-to-v0.2.2 to main July 9, 2026 21:54
@felickz

felickz commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Update: Rebased and retargeted this PR to main (previously based on the stale/superseded jcogs33/update-to-v0.2.2 branch, i.e. PR #126).

Since #158 already synced everything to 0.2.2 on main directly (a different fix — it corrected the stale hardcoded version pin '0.2.1''*' on codeql-java-extensions), I confirmed this bug is still live: the dependency itself (regardless of version pin) causes the fatal duplicate-pack-resolution crash whenever combined with any of the 3 shipped configs that also reference it directly. codeql-java-libs@0.2.2 is already published on GHCR with this bug present today.

Diff is now minimal and clean against main:

 library: true 
 name: githubsecuritylab/codeql-java-libs
-version: 0.2.2
+version: 0.2.3
 dependencies:
   codeql/java-all: '*'
-  githubsecuritylab/codeql-java-extensions: '*'

Bumping to 0.2.3 (not 0.2.2) so publish.yml detects the diff and republishes, since 0.2.2 is already live with the bug.

@felickz felickz left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:octocat: 👍

@felickz felickz merged commit c647011 into main Jul 10, 2026
21 checks passed
@felickz felickz deleted the felickz-fix-java-duplicate-extensions-pack branch July 10, 2026 00:19
felickz added a commit that referenced this pull request Jul 10, 2026
.release.yml's version was bumped to 0.2.3 directly (not via a pack
version bump), and java/lib was independently bumped to 0.2.3 by
PR #155's hotfix. This closes the gap by bringing every other pack's
own qlpack.yml version in line, so merging this triggers the real
batch publish of everything to 0.2.3 (java/lib is already live and
will be a no-op).

Also bumps go/ext and python/ext/qlpack.yml for consistency with
.release.yml's 'CodeQL Pack Versions' location pattern, even though
those two packs aren't wired into publish.yml's matrix yet (tracked
by open PR #144).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
felickz added a commit that referenced this pull request Jul 10, 2026
…lease process

- publish.yml's push trigger now only fires when .release.yml changes
  (paths filter), not on every push to main. workflow_dispatch remains
  as the manual escape hatch for one-off hotfix publishes.
- Rewrite CONTRIBUTING.md's Releases & publishing section to match:
  shipping a pack change now just stages it until the next release cut
  or a manual dispatch; add a Cutting a release walkthrough for
  update-release.yml/patch-release-me now that .release.yml's CodeQL
  Pack Versions location (#158) actually drives every pack's version;
  document the -alpha.N + workflow_dispatch hotfix convention and note
  #155 as an accepted one-off exception; note #159 as the recovery
  path if .release.yml's version is ever hand-edited directly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
felickz added a commit that referenced this pull request Jul 10, 2026
…+ docs (#160)

* feat(publish): add publish-summary table + GitHub Release upsert

publish.yml now records a per-pack JSON result fragment (published /
up-to-date / failed) from each of the 4 jobs' matrix entries, uploads them
as artifacts, and a new summary job downloads and merges them into a
unified markdown table (languages x pack types) that is:
  1. written to the Actions run summary ($GITHUB_STEP_SUMMARY)
  2. upserted into the matching GitHub Release body (.release.yml's
     version -> vX.Y.Z tag), inside marker comments so "What's Changed"
     and other release content is preserved across runs

New scripts:
  - .github/scripts/build-publish-summary.sh
  - .github/scripts/upsert-release-table.sh

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(publish): avoid tee+pipe fragility in Build summary table step

The previous form piped the script's stdout through tee and redirected
tee's own stdout (not the file write) into GITHUB_STEP_SUMMARY. Combined
with 'bash -e' (no pipefail) at the step level, this masked failures and
produced an empty summary.md in a real run, upserting empty
publish-summary markers into the v0.2.2 release. Switch to plain
sequential redirects and add debug output (fragment listing, line/byte
counts) to make future failures visible in the step log.

* feat(publish): gate auto-publish on .release.yml changes; document release process

- publish.yml's push trigger now only fires when .release.yml changes
  (paths filter), not on every push to main. workflow_dispatch remains
  as the manual escape hatch for one-off hotfix publishes.
- Rewrite CONTRIBUTING.md's Releases & publishing section to match:
  shipping a pack change now just stages it until the next release cut
  or a manual dispatch; add a Cutting a release walkthrough for
  update-release.yml/patch-release-me now that .release.yml's CodeQL
  Pack Versions location (#158) actually drives every pack's version;
  document the -alpha.N + workflow_dispatch hotfix convention and note
  #155 as an accepted one-off exception; note #159 as the recovery
  path if .release.yml's version is ever hand-edited directly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: address Copilot review feedback on PR #160

- Anchor CURRENT_VERSION extraction to '^version:' (with head -1) in all
  four publish.yml jobs so a stray 'version' substring elsewhere in a
  qlpack.yml (e.g. a comment) can't be matched instead of the real field.
- upsert-release-table.sh: only take the in-place marker-replacement path
  when BOTH the start and end marker are present in the existing release
  body; otherwise append, so a corrupted/partial marker pair can't cause
  the awk script to silently truncate the rest of the release notes.
- CONTRIBUTING.md: grammar fix (find/replaces -> finds and replaces).

Verified gh release create --notes-file + --generate-notes together is
NOT mutually exclusive in gh 2.96.0 (contrary to a review comment) --
confirmed empirically: the v0.2.3 release this script created has both
the publish-summary table (from --notes-file) and the auto-generated
'What's Changed' changelog (from --generate-notes) in its body.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* feat(publish): add CodeQL standard library versions cross-check table

Every publish.yml run now builds and upserts a second table into the
matching GitHub Release: for each language, the locked codeql/<lang>-all
version (from lib/codeql-pack.lock.yml) versus the version github/codeql
itself bundles with the pinned CodeQL CLI (.codeqlversion), read from its
own <lang>/ql/lib/qlpack.yml at tag codeql-cli/v<version>. Mismatches are
flagged with an actions warning annotation and a table marker, giving a
machine-checkable tripwire for the drift risk documented in CONTRIBUTING.md
(CI's 'codeql pack install' step is non-resolving, so a forgotten
'codeql pack upgrade <dir>' after a .codeqlversion bump silently pins a
language to a stale library version forever).

- Add .github/scripts/build-codeql-lib-versions-table.sh
- Parameterize upsert-release-table.sh with an optional block-name arg so
  multiple independent marker-comment blocks can coexist in one release
  body without clobbering each other
- Wire both into publish.yml's summary job
- Document the new table and cross-check in CONTRIBUTING.md

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: mark build-codeql-lib-versions-table.sh executable

git-created file lost the exec bit, causing publish.yml's new step to
fail with 'Permission denied' (exit 126).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(build-codeql-lib-versions-table): check src lock file, not lib

CONTRIBUTING.md's 'Supported CodeQL versions' table already documents
<language>/src/codeql-pack.lock.yml as the source-of-truth lock file (the
queries pack CI actually compiles/tests against), not lib. Reading from
lib/codeql-pack.lock.yml instead meant the tripwire could miss drift in
the src lock, or flag drift that didn't actually affect the compiled
queries. Switch the check (and its remediation guidance) to src, per
Copilot review feedback on PR #160.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* feat(publish): commit/tag-anchored links + queries pack in lib-versions table

- Discover direct codeql/* dependencies dynamically from each language's
  src/qlpack.yml instead of hardcoding codeql/<lang>-all, so this also
  covers codeql/<lang>-queries for C++/C# (which additionally depend on
  the upstream standard queries pack).
- Link every "our locked" version to the exact commit/file/line in this
  repo (blob/<GITHUB_SHA>/...#L<n>) and every "upstream" version to the
  exact file/line in github/codeql at the matching codeql-cli/vX tag, so
  each row can be verified with one click instead of trusting the table.
- Rename the section/table to "CodeQL standard library & query pack
  versions" and update CONTRIBUTING.md references accordingly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* feat: automate CodeQL CLI version bump detection and dependency refresh

Adds the two workflows needed to close the gap identified while
reviewing PR #118 (codeql pack upgrade weekly cron):

- detect-codeql-release.yml: weekly (+ workflow_dispatch) tripwire that
  compares .codeqlversion against github/codeql-cli-binaries' latest
  release and keeps a single tracking issue open/updated while behind,
  auto-closing it once caught up. Never opens a PR itself.
- update-codeql-version.yml: workflow_dispatch with a codeql_version
  input. Bumps .codeqlversion, runs codeql pack upgrade <dir> for
  every pack, and opens a PR via the same GitHub App token pattern as
  update-release.yml so CI actually runs on it (a GITHUB_TOKEN-authored
  PR would not trigger downstream workflows).

Together these cover detection + mechanical dependency refresh; fixing
compile/test breakage from upstream API changes and bumping each pack's
own version: still needs a human (or delegated Copilot coding agent) -
documented as a 3-step process in CONTRIBUTING.md.

Rewrites CONTRIBUTING.md's "Updating the pinned CodeQL CLI/library
version" section to describe this new process and adds reference-style
links for both new workflows and codeql-cli-binaries.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(publish): gate release-table upsert to push trigger, clarify failed-check cell

Two fixes from Copilot review on PR #160:

- publish.yml: only run the "Upsert release table" step on the push
  (release-cut) trigger, not workflow_dispatch. A manual one-off hotfix
  publish (see CONTRIBUTING.md) still points .release.yml at the last
  cut release, so upserting that run's tables into it would overwrite
  an already-published release's notes with a misleading summary of an
  unrelated hotfix run.
- build-publish-summary.sh: when a pack's version-check step itself
  fails, previous_version can be empty/null, which rendered as the
  confusing "publish failed (still ``)". Now shows an explicit
  "previous version unknown" message in that case.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(publish): check both src and lib lock files for CodeQL version drift

src/qlpack.yml and lib/qlpack.yml each declare their own codeql/<lang>-all
dependency and resolve it into their own independent codeql-pack.lock.yml.
Nothing keeps these two lock files in sync automatically - codeql pack
upgrade resolves each pack directory separately, so running it against one
and not the other silently lets them drift. The standard-library-versions
table previously only checked src as a 'coarse signal', which meant a stale
lib lock could go undetected while the table showed all green.

Now checks both src and lib for every language (ext/ext-library-sources are
still out of scope: they pin via extensionTargets, not dependencies, so
CodeQL never resolves a locked version for them). Adds a Pack column to the
table to distinguish rows. Also updates CONTRIBUTING.md's Supported CodeQL
versions section, which similarly implied a single lock file was the source
of truth per language.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs: fix publish.yml job count in CONTRIBUTING.md (five jobs, not four)

CONTRIBUTING.md said publish.yml is organized as four jobs, but it also has
a fifth 'summary' job (needs: [queries, library, extensions,
library_sources_extensions], if: always()) that aggregates results into the
publish-summary and CodeQL lib-versions tables and upserts them into the
Release notes. Clarify the doc to describe all five.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(publish): don't fail check_version when a pack's GHCR container doesn't exist yet

All four publish jobs (queries/library/extensions/library_sources_extensions)
read the currently-published version via 'gh api .../versions'. run: steps
default to bash -e, so a 404 (package never published, e.g. a brand-new
language/pack) aborted the step and failed the job before it could ever
publish that pack for the first time.

Move '|| true' inside the command substitution so a fetch failure just
leaves PUBLISHED_VERSION empty (correctly differing from CURRENT_VERSION,
triggering a first publish) instead of killing the step under set -e.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@felickz

felickz commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Verified fixed. Re-ran the exact repro scenario against dsp-testing/SecurityShepherd: https://github.com/dsp-testing/SecurityShepherd/actions/runs/29121889021/job/86458636453

The java-kotlin Analyze job completed successfully in ~5 minutes with no fatal error. Log shows a clean sequence with no duplicate pack conflict:

\
Recording pack reference githubsecuritylab/codeql-java-queries at .../0.2.3
Resolving data extensions.
WARNING: Extension pack 'githubsecuritylab/codeql-java-extensions' is unused. (.../codeql-java-extensions/0.2.4/qlpack.yml:1,1-1)
Finished resolving data extensions.
Loading data extensions.
Finished loading data extensions.
...
Successfully uploaded results
\\

No \CatastrophicError, no \Encountered two packs with the same name. This previously crashed at exactly this point (see the original repro run https://github.com/dsp-testing/SecurityShepherd/actions/runs/28809261039/job/85432641504). Confirmed the fix resolves the issue in a real-world CI run using the published config. 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants