From b5382bbdbfc8772396e553b65ecde21aea46ff3d Mon Sep 17 00:00:00 2001 From: jnasbyupgrade Date: Fri, 24 Jul 2026 17:34:20 -0500 Subject: [PATCH] Add a release-time safety check for silently corrupted versioned install scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sql.mk regenerates the current version's sql/cat_tools--.sql.in from sql/cat_tools.sql.in whenever default_version and that source file change, via the $(EXTENSION_VERSION_FILES:.sql=.sql.in) rule (`cp $< $@`). If default_version is ever left pointing at an already-tagged real version rather than the `stable` pseudo-version, a later source edit silently overwrites — and corrupts — that released version's committed install file. Add a new step 1 to RELEASE.md, before the version-bump steps, that has the release manager compare each committed versioned install script's last-touching commit against the git tag for that version, flagging any file touched after its own release as a red flag worth investigating, while noting that a late touch-date can also be a legitimate backfill rather than corruption. Renumber the remaining steps (2-7) and their cross-references accordingly. Checked cat_tools' own history while writing this: default_version has in fact never been the literal string 'stable' in cat_tools.control's git history (it is a real version right now, 0.3.0) — the stable pseudo-version scheme described elsewhere in this doc is still aspirational, not yet implemented. That's outside this change's scope. Also checked both currently-tagged versions (0.2.2, 0.2.3) against this new check: both are clean, no drift found. --- RELEASE.md | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 8cad584..4180d5e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,7 +4,37 @@ cat_tools builds on pgxntool (https://github.com/Postgres-Extensions/pgxntool); the release machinery (`make tag`, `make dist`) lives in `pgxntool/base.mk`. These steps cut a new release. -## 1. Pre-release checks +## 1. Safety check: verify committed version files haven't drifted + +Before anything else, confirm every committed versioned install script still matches +what that version actually shipped. + +- [ ] For each committed versioned install script — `sql/cat_tools--.sql.in` + (0.2.0 onward) or `sql/cat_tools--.sql` (the historical pre-0.2.0 files + `0.1.0`/`0.1.3`/`0.1.4`/`0.1.5`, which have no `.sql.in` source and are tracked + directly; see CLAUDE.md "SQL file conventions") — find its last-touching commit: + `git log -1 --format='%H %ad' -- sql/cat_tools--.sql.in` (or `.sql`). +- [ ] Confirm that commit is no later than when that version was actually tagged. + cat_tools tags every release, unprefixed (e.g. `0.2.2`, `0.2.3` — see step 6's + `make tag`), so compare directly: `git log -1 --format='%H %ad' `. (No + tags exist before `0.2.2` — `0.1.x`, `0.2.0`, and `0.2.1` predate cat_tools' + tagging convention — so this direct comparison is only available from `0.2.2` + onward.) +- [ ] A version file touched by a commit LATER than its own release's tag is a red + flag — it likely means `default_version` in `cat_tools.control` was left pointing + at that real (non-`stable`) version after release, and a later source edit to + `sql/cat_tools.sql.in` silently regenerated — and corrupted — the committed file + via `sql.mk`'s current-version rule (`$(EXTENSION_VERSION_FILES:.sql=.sql.in): + sql/cat_tools.sql.in cat_tools.control`, which `cp`s the base source over it). + Investigate before proceeding. +- [ ] **Known exception, not necessarily a corruption:** a version file whose + last-touching commit is much later than its version's real release can also mean + the file was legitimately backfilled or reformatted after the fact (e.g. once new + build tooling started requiring something that wasn't tracked before). A late + touch-date alone isn't suspicious — only worry about a file whose *content* + actually differs from what shipped. + +## 2. Pre-release checks - [ ] Open issues/PRs for this release reviewed, merged or deferred. - [ ] CI green on all supported PostgreSQL versions (the `all-checks-passed` job on master). - [ ] Locally: `make verify-results` passes. It depends on `test` (so it runs the suite @@ -12,7 +42,7 @@ steps cut a new release. `installcheck` `.IGNORE`, so it never returns non-zero on a regression; only `verify-results` (which inspects `test/regression.diffs`) is a real gate. -## 2. Decide the version and what to track +## 3. Decide the version and what to track - [ ] Pick the new version (semantic versioning). - [ ] **Minor change? Consider NOT committing the generated versioned install script.** If this release makes only fairly minor changes (unlikely to cross a PostgreSQL @@ -22,14 +52,14 @@ steps cut a new release. at build time). The update script (`sql/cat_tools----.sql.in`) is ALWAYS committed. See CLAUDE.md "SQL file conventions". -## 3. Update version + changelog +## 4. Update version + changelog > **⚠️ CRITICAL — you are temporarily leaving the `stable` pseudo-version.** Master's > `default_version` normally sits at the `stable` pseudo-version so that source edits > regenerate `cat_tools--stable.sql` and never a frozen released file. Stamping a real > version here points the generated current-version file at `cat_tools--`. The > moment this release is merged you **MUST** flip `default_version` back to `stable` on -> master (step 6). If you forget, the next source edit on master will regenerate — and +> master (step 7). If you forget, the next source edit on master will regenerate — and > corrupt — the just-released version's install file. - [ ] Bump `default_version` in `cat_tools.control` (bumped by hand). @@ -44,7 +74,7 @@ steps cut a new release. - [ ] Stamp `HISTORY.asc`: the top `STABLE` section accumulates user-facing changes as PRs land; at release, rename that header to the new version number. -## 4. Verify +## 5. Verify - [ ] `make verify-results` green (it runs `test` first, then gates on the results). - [ ] From a clean checkout (or `git archive` of the tag): `make && make install` regenerates and installs cleanly and `CREATE EXTENSION cat_tools;` reports the new @@ -52,7 +82,7 @@ steps cut a new release. mirrors what `make dist` ships, since it archives the tag: committed files only, so any omitted generated install script is regenerated on the consumer's side.) -## 5. Tag and distribute +## 6. Tag and distribute - [ ] Commit the release changes; working tree must be clean — `make tag` aborts with "Untracked changes!" on a dirty tree. - [ ] `make tag` — creates a git tag named exactly the version, UNPREFIXED (e.g. `0.2.3`, @@ -68,7 +98,7 @@ steps cut a new release. `export-ignore` for committed files). `make forcedist` = `forcetag` + `dist`. - [ ] Upload the `../cat_tools-.zip` to PGXN (manual). -## 6. Return master to `stable` (CRITICAL — do not skip) +## 7. Return master to `stable` (CRITICAL — do not skip) - [ ] As soon as the release is merged, flip `default_version` back to the `stable` pseudo-version on master (`cat_tools.control` + `META.in.json`), open a new top `STABLE` section in `HISTORY.asc`, and re-seed a fresh @@ -83,7 +113,7 @@ steps cut a new release. > with a live `sql/cat_tools----stable.sql.in` update script that every > source fix targets) decouples fixes from version bumps. The machinery is built into > `sql.mk`; it lands immediately after the 0.2.3 release, so 0.2.3 itself is the last -> release cut before the scheme exists — steps 3/6 above describe the flow from the +> release cut before the scheme exists — steps 4/7 above describe the flow from the > next release onward. ## Notes and caveats