Skip to content

ci: fix dpkg-query format-string escaping in check-versions.yml - #1170

Merged
dimitri merged 1 commit into
mainfrom
fix/check-versions-dpkg-query-escaping
Jul 27, 2026
Merged

ci: fix dpkg-query format-string escaping in check-versions.yml#1170
dimitri merged 1 commit into
mainfrom
fix/check-versions-dpkg-query-escaping

Conversation

@dimitri

@dimitri dimitri commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Problem

The weekly "Check PGDG + Citus versions" workflow (check-versions.yml) has been failing on every scheduled run, for every supported PG version (14–17), regardless of whether PGDG actually released anything new:

PGDG PG14: installed=, available=14.23-1.pgdg12+1 → STALE
PGDG PG15: installed=, available=15.18-1.pgdg12+1 → STALE
PGDG PG16: installed=, available=16.14-1.pgdg12+1 → STALE
PGDG PG17: installed=, available=17.10-1.pgdg12+1 → STALE

This is a false negative in the check script itself, not a real version drift — installed is always empty, for every version, every run.

Root cause

installed=$(dpkg-query -W -f="\\${Version}" postgresql-${pg} 2>/dev/null || echo "")

This line sits inside docker run --rm "$IMAGE" bash -c '...', where the entire inner script is single-quoted by the outer (runner) shell — so the outer shell passes \\${Version} through completely unchanged. Inside the container's own bash -c, though, this text is part of a double-quoted -f="..." argument: \\ collapses to one literal backslash, and the now-unescaped ${Version} gets parameter-expanded as a shell variable. Version was never set anywhere, so it silently expands to nothing. dpkg-query ends up invoked with a bare backslash as its format string, instead of the literal ${Version} template it needs (that's dpkg-query's own field-substitution syntax, not a shell variable) — and returns nothing.

With installed always empty and available resolving correctly one line below (via a separately, correctly, double-quoted apt-cache/awk pipeline), every PG version compares unequal and gets flagged STALE, forcing pgdg_changed=true unconditionally on every run.

Fix

Drop one backslash: \\${Version}\${Version}. The outer single-quoting still passes it through unchanged; the container's bash now sees \$ inside its double-quoted string, which escapes to a literal $, yielding the literal string ${Version} that dpkg-query expects.

Verification

Reproduced the exact quoting locally, then built a throwaway debian:bookworm-slim container and installed postgresql-17 from the real PGDG repo the same way Dockerfile.base does, to test both the old and fixed format strings against a real installed package:

old (\\${Version}): installed=[]                        <- garbage, always empty
new (\${Version}):  installed=[17.10-1.pgdg12+1]
                     available=[17.10-1.pgdg12+1]        <- correctly matches, not stale

No functional change to what the workflow does when a version genuinely is stale — only fixes the comparison so it stops reporting every run as stale unconditionally.

The "Check PGDG minor versions" step always reported every supported PG
version as stale, failing the job on every scheduled run regardless of
whether PGDG had actually released anything new.

Root cause: dpkg-query -f="\\${Version}" postgresql-${pg} -- this line
sits inside docker run --rm "$IMAGE" bash -c '...', where the entire
inner script is single-quoted by the outer (runner) shell, so no
expansion happens there and \\${Version} is passed through literally.
Inside the container's own bash -c, though, that text is inside a
double-quoted -f="..." argument: \\ collapses to one literal backslash,
and the now-unescaped ${Version} gets parameter-expanded as a shell
variable -- which was never set, so it expands to nothing. dpkg-query
ends up invoked with a bare backslash as its format string instead of
the literal ${Version} template it needs, and returns nothing.

With `installed` always empty and `available` resolving correctly via
the separately (correctly) quoted apt-cache/awk one line below, every
PG version compared unequal and got flagged STALE, forcing
pgdg_changed=true unconditionally.

Fix: \\${Version} -> \${Version} (one fewer backslash). The outer
single quotes still pass it through unchanged; the container's bash
now sees \$ inside the double-quoted string, which escapes to a
literal $, yielding the literal string ${Version} dpkg-query expects.

Verified locally: built a throwaway debian:bookworm-slim container,
installed postgresql-17 from the real PGDG repo the same way
Dockerfile.base does, and ran both the old and fixed format strings
against it.

  old (\\${Version}): installed=[]                       (garbage, always empty)
  new (\${Version}):  installed=[17.10-1.pgdg12+1]
                       available=[17.10-1.pgdg12+1]      (correctly matches -> not stale)
@dimitri dimitri added the Packaging and CI Enhancements to our CI integration label Jul 27, 2026
@dimitri dimitri self-assigned this Jul 27, 2026
@dimitri
dimitri merged commit eeb9d8a into main Jul 27, 2026
17 checks passed
@dimitri
dimitri deleted the fix/check-versions-dpkg-query-escaping branch July 27, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Packaging and CI Enhancements to our CI integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant