Skip to content

ci: Add prd image build workflows + fix TimescaleDB wrong default version image - #674

Merged
aditya1702 merged 2 commits into
mainfrom
ci/prd-image-workflows
Jul 31, 2026
Merged

ci: Add prd image build workflows + fix TimescaleDB wrong default version image#674
aditya1702 merged 2 commits into
mainfrom
ci/prd-image-workflows

Conversation

@aditya1702

@aditya1702 aditya1702 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Makes prd reachable for both images, and fixes a bug where the database image's version tag was wrong.

1. Four build workflows → two

New Replaces Trigger
build.yml build-dev.yml, build-stg.yml push to main → stg (unchanged) · -f environment=dev|stg|prd
build-cnpg-timescaledb.yml build-cnpg-timescaledb-{dev,stg}.yml -f environment=… -f pg_major=17 -f tsdb_version=2.28.2

Why a prd app build when promote-release.yml exists? To exercise a commit in prd before cutting a release. Tags don't collide, so it can't touch a released image:

  • build.ymlprd/wallet-backend:<sha>
  • promote-release.ymlprd/wallet-backend:vX.Y.Z (still the only release path)

2. The database image lied about its TimescaleDB version

timescaledb.control — which supplies default_version — ships in the loader package, not the extension bundle. We pinned only the bundle, so apt took the newest loader. A pg17-tsdb2.28.2 build today gets the 2.29.0 loader:

default_version = '2.29.0'   ← over 2.28.2 artifacts

Result: bare CREATE EXTENSION timescaledb and bare ALTER EXTENSION timescaledb UPDATE fail (no installation script), and pg_available_extensions shows a phantom upgrade forever. Silent otherwise, which is why it survived — once created with an explicit version, queries work fine.

Timescale's docs say to pin both packages; we pinned one. Known upstream trap: timescale/timescaledb#3297.

Fix: pin both packages + two build-time gates, so a recurrence is a red build instead of a bootstrap failure.

Verification

Built locally at pg_major=17, tsdb_version=2.28.2.

default_version = '2.28.2', module_pathname = '$libdir/timescaledb-2.28.2', 37 versioned libs intact

✅ Booted PostgreSQL from the image — bare CREATE EXTENSION timescaledb gives default_version = installed_version = 2.28.2, ALTER EXTENSION … UPDATE returns "already installed", hypertable insert works

✅ Each gate observed failing, so neither is decorative:

Break it Gate says
remove loader pin resolved to 2.29.0~debian12-1710, expected 2.28.2
drift control file default_version=2.99.9 … expected 2.28.2
tsdb_version=9.9.9 Version '9.9.9*' … was not found

actionlint clean · every push event resolves to stg (staging stream unchanged) · make check passes

Reviewer notes

Nothing changes except prd being added — same full-SHA tags, same make docker-build/docker-push, same auto-publish to stg on push to main. No :latest, no short-SHA tags.

New invocations:

gh workflow run build.yml -f environment=dev        # was: build-dev.yml
gh workflow run build-cnpg-timescaledb.yml -f environment=prd -f pg_major=17 -f tsdb_version=2.28.2

Action items:

  • Repoint any branch-protection rule naming Build and Push Wallet Backend (Dev) / (Stg) — those job names are gone
  • Create the prd/cnpg-timescaledb ECR repo before the first prd DB build (prd/wallet-backend already exists)
  • Images already in ECR keep the bad control file until rebuilt under the same tag

Two things deliberately left alone:

  • The .so copy glob still keeps all 37 versions (now commented): a DB registered at an older extension version resolves pg_proc.probin to that version's library, so narrowing it would break pod restarts on a lagging cluster.
  • sdf-ecr-login is now called bare — the action only declares login-public-ecr, so the aws-oidc-role/aws-ecr-login-role inputs the old files passed were never read.

Follow-up (not here): the CNPG base 17-bookworm is PG 17.6, but TimescaleDB 2.28.x wants postgresql-17 (>= 17.10). The builder pulls 17.10 and its libs run on 17.6 — works (minors are ABI-compatible), but a 17.10+ base tag would remove the skew.

Four per-environment build workflows collapse into two that take an
`environment` input, and prd becomes reachable on both.

`build.yml` replaces build-dev.yml + build-stg.yml. A push to main still
publishes `stg/wallet-backend:<sha>` automatically; dev, stg and prd are all
reachable by manual dispatch, which is what allows a specific commit to be
exercised in production before a release is cut around it. Its SHA tags never
collide with promote-release.yml's `vX.Y.Z` tags, so a verification build
cannot overwrite a promoted release image.

`build-cnpg-timescaledb.yml` replaces the dev/stg pair, adds prd, validates
`pg_major`/`tsdb_version` before anything is pushed, and serialises concurrent
dispatches that target the same tag.

Both call `stellar/actions/sdf-ecr-login` with no inputs: the action declares
only `login-public-ecr`, so the `aws-oidc-role`/`aws-ecr-login-role` values the
replaced files passed were never read.
… honest

TimescaleDB ships two Debian packages: the bundle
(`timescaledb-2-postgresql-NN`) carries the versioned `.so` and `.sql`
artifacts, while the loader (`timescaledb-2-loader-postgresql-NN`) carries the
unversioned loader `.so` and `timescaledb.control`. The control file is what
supplies `default_version`, and it is stamped with the *loader's* version.

The bundle depends on the loader with `>=`, so pinning only the bundle leaves
the loader free to resolve to the newest published release. The build then
produces an image whose control file names a version it does not carry: as of
today a `pg17-tsdb2.28.2` build picks up the 2.29.0 loader, so
`default_version` reads 2.29.0 against 2.28.2 artifacts. Bare
`CREATE EXTENSION timescaledb` and bare `ALTER EXTENSION timescaledb UPDATE`
then fail with no installation script, `pg_available_extensions` reports a
phantom upgrade, and the `version:` pin in the CNPG `Database` resource becomes
load-bearing for a fresh bootstrap. Pinning both packages is what Timescale's
own installation docs prescribe.

Two gates make a recurrence a red build rather than a bootstrap failure. Stage
one asserts what apt actually resolved for both packages, which also rejects a
longer upstream version the `${TSDB_VERSION}*` glob would otherwise match
(2.28.21 for a 2.28.2 request). Stage two asserts the assembled image: the
control file's `default_version` and `module_pathname`, the versioned install
script, and the versioned, tsl and loader libraries.

`TSDB_VERSION` moves to a global ARG so both stages share one default; stage two
needs it for the assertion. The `.so` copy glob deliberately keeps every version
the bundle ships — a database with an older extension version registered
resolves `pg_proc.probin` to that version's library — and now says so.

Verified locally: bare `CREATE EXTENSION timescaledb` on the built image yields
`default_version = installed_version = 2.28.2` and a working hypertable insert.
Dropping the loader pin reproduces the 2.29.0 resolution and fails the stage-one
gate; a drifted control file fails the stage-two gate.
Copilot AI review requested due to automatic review settings July 31, 2026 19:07

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

Consolidates environment-specific image workflows and ensures CNPG images contain the requested TimescaleDB version.

Changes:

  • Replaces four workflows with two environment-parameterized workflows supporting dev, stg, and prd.
  • Pins and verifies both TimescaleDB packages and assembled artifacts.
  • Documents image-building and production tagging flows.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
README.md Documents consolidated workflows and database image builds.
Dockerfile-timescale-cnpg Pins and verifies TimescaleDB versions.
.github/workflows/build.yml Adds unified application image workflow.
.github/workflows/build-stg.yml Removes superseded staging workflow.
.github/workflows/build-dev.yml Removes superseded development workflow.
.github/workflows/build-cnpg-timescaledb.yml Adds unified database image workflow.
.github/workflows/build-cnpg-timescaledb-stg.yml Removes superseded staging database workflow.
.github/workflows/build-cnpg-timescaledb-dev.yml Removes superseded development database workflow.

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

@aditya1702 aditya1702 changed the title ci: prd image builds + honest TimescaleDB version pinning ci: prd image build workflows + fix TimescaleDB wrong default version image Jul 31, 2026
@aditya1702 aditya1702 changed the title ci: prd image build workflows + fix TimescaleDB wrong default version image ci: Add prd image build workflows + fix TimescaleDB wrong default version image Jul 31, 2026
@aditya1702
aditya1702 merged commit a80a9dd into main Jul 31, 2026
10 checks passed
@aditya1702
aditya1702 deleted the ci/prd-image-workflows branch July 31, 2026 20:11
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.

3 participants