pg_ripple — Release Procedure

This document describes how to release a new version of pg_ripple.

Versions follow the milestones in ROADMAP.md. Each release corresponds to a completed roadmap version (e.g. v0.1.0, v0.2.0).


Pre-Release Checklist

Complete every item before starting the release process.

  • All roadmap deliverables for the version are implemented
    • Cross-check against the version's deliverables list in ROADMAP.md
    • All deliverable checkboxes are ticked (- [x]) in ROADMAP.md — if any are unticked, tick them now before proceeding
  • All exit criteria in ROADMAP.md are satisfied
    • Verify each criterion explicitly — do not rely on partial evidence
  • Tests pass
    • cargo fmt --all -- --check (formatting)
    • cargo clippy --features pg18 -- -D warnings (lint, zero warnings)
    • cargo pgrx test pg18 (unit + integration tests)
    • cargo pgrx regress pg18 --postgresql-conf "allow_system_table_mods=on" (pg_regress suite, includes schema_state migration schema check)
    • bash tests/test_migration_chain.shverify all migration SQL scripts apply cleanly in sequence (requires cargo pgrx start pg18 first; also run via just test-migration)
  • Cargo.toml version field matches the release version
    • e.g. version = "0.2.0" for a v0.2.0 release
  • pg_ripple.control default_version matches the release version
  • Dependency versions are up to date
    • Update .versions.toml if pg_trickle or pg_tide versions changed
    • Update the corresponding Dockerfile ARG PG_TRICKLE_VERSION / ARG PG_TIDE_VERSION to match
    • src/lib.rs constants are injected automatically at compile time from .versions.toml — no manual edits needed (DEP-VER-BUILD-01)
    • Run bash scripts/check_dep_versions.sh to verify Dockerfile alignment
  • Extension migration script createdCRITICAL
    • File: sql/pg_ripple--X.(Y-1).Z--X.Y.Z.sql where the previous version is X.(Y-1).Z
    • If there are schema changes (ALTER TABLE, CREATE INDEX, etc.), include them in the script
    • If there are no schema changes (new Rust functions), write only a comment header explaining what's new
    • See Extension Versioning & Migration Scripts in AGENTS.md for the checklist and examples
    • Without this file, users on earlier versions cannot upgrade via ALTER EXTENSION ... UPDATE — they must dump/restore
  • CHANGELOG.md is up to date
    • The [Unreleased] section has been moved under the new version heading
    • Written in plain, accessible language (see Changelog Style below)
    • All significant user-visible changes are included
    • Date is set to today's date
  • README.md is updated
    • The "What works today (v0.X.Y)" section heading and body reflect the current release
    • Describes only functionality implemented and merged in this version
    • Remove planned features that haven't shipped yet
    • The Roadmap table in the ## Roadmap section is updated:
      • The newly released version row is bolded and its status cell is changed to ✅ Done
      • Any in-progress sentence above the table (e.g. "X is coming in a later milestone") no longer mentions capabilities that have now shipped
    • The "Where we're headed" section no longer lists the just-released version as upcoming — move it to a "What works today" bullet or remove it
  • No uncommitted changesgit status is clean
  • Main branch is up to dategit pull origin main

Release Checklist

Perform these steps in order.

  1. Final test run

    cargo fmt --all -- --check
    cargo clippy --features pg18 -- -D warnings
    cargo pgrx test pg18
    cargo pgrx regress pg18 --postgresql-conf "allow_system_table_mods=on"
    bash tests/test_migration_chain.sh
    

    All five must pass with zero warnings and zero failures.

  2. Documentation validation

    Run the full docs check before tagging:

    just docs-check
    mdbook build docs
    

    Verify:

    • just docs-check-links exits 0 (no broken local links).
    • just docs-check-summary exits 0 (no orphan pages).
    • just docs-check-http-routes lists no undocumented routes.
    • just docs-check-guc-drift lists no missing GUCs with significant defaults.
    • New HTTP routes added in this version appear in docs/src/reference/http-api.md.
    • New GUCs added in this version appear in docs/src/reference/guc-reference.md and docs/gucs.md.
    • New public SQL functions appear in docs/src/reference/sql-api.md or are explicitly marked as internal/admin.
    • The migration script has upgrade docs if it changes user-visible schema.
    • CHANGELOG.md links to any new user-facing docs pages.
  3. Tag the release

    Before tagging, verify the version bump and compatibility constant are correct:

    # L16-13 (v0.117.0): verify version bump before tagging.
    just bump-version-dry         # preview what would change
    just bump-version <new> <floor>   # apply the bump (updates Cargo.toml, pg_ripple.control,
                                      # COMPATIBLE_EXTENSION_MIN in pg_ripple_http/src/main.rs)
    # Then inspect the changes:
    git diff --stat
    

    Use an annotated tag with the version number:

    git tag -a v0.X.Y -m "Release v0.X.Y — <version name from ROADMAP>"
    git push origin v0.X.Y
    

    This step is done manually. The release skill deliberately does not create tags.

  4. The GitHub release is created automatically

    Pushing the tag triggers .github/workflows/release.yml, which:

    • Runs the full test + pg_regress suite on the tagged commit
    • Extracts the changelog entry for this version from CHANGELOG.md
    • Creates the GitHub release with the extracted notes

    Monitor the workflow:

    gh run list --limit 5
    gh run view <run-id>
    

Post-Release Checklist

  • Verify the release workflow passed — check .github/workflows/release.yml run on the tag
    • gh run list --limit 5
  • Verify the GitHub release page looks correct
    • gh release view v0.X.Y
  • Update the [Unreleased] section in CHANGELOG.md
    • Add an empty [Unreleased] section above the just-released version
    • Commit: git commit -am "docs: start unreleased section after v0.X.Y"
  • Announce the release (if applicable)
    • Post to relevant channels, update project website, etc.
  • Verify the extension installs cleanly from the release
    • On a fresh PostgreSQL 18 instance: CREATE EXTENSION pg_ripple;

Changelog Style

The CHANGELOG.md should be written so that someone without deep knowledge of Rust, PostgreSQL internals, or RDF can understand what changed. Guidelines:

  • Lead with what users can do, not how it was implemented
  • Use short sentences and bullet points
  • Avoid jargon — say "store and retrieve facts" instead of "triple CRUD via VP tables"
  • Technical implementation details go in a separate "Technical Details" subsection for those who want them
  • Each version section should open with a one-sentence summary

Version Numbering

RangeMeaning
0.x.yPre-1.0 development milestones — features may change
1.0.0Production release — stable API, standards compliance
1.x.yPost-1.0 enhancements (federation, Cypher/GQL, etc.)

Security Advisory Calendar

HTTP Companion Compatibility Window Policy (C16-01, v0.112.0)

The pg_ripple_http HTTP companion supports the prior 2 minor extension versions at any given time. Concretely: if the current extension version is 0.X.Y, the companion built from the same commit is guaranteed to work with extensions 0.(X-1).0 and 0.(X-2).0 (and any patch releases within those minors). Older extension versions are served in degraded mode with a startup warning. The COMPATIBLE_EXTENSION_MIN constant in pg_ripple_http/src/main.rs is updated atomically with every just bump-version <new> <floor> invocation, and the release.yml CI gate (compat-check job) enforces that this constant is never more than 1 minor version behind the current extension. Set PG_RIPPLE_HTTP_STRICT_COMPAT=1 to convert the warning to a fatal error.

Security Advisory Calendar

RSA timing side-channel advisories (SEC-06, v0.92.0)

Two RUSTSEC advisories for the rsa crate are tracked in audit.toml:

  • RUSTSEC-2024-0436 (Marvin attack on RSA decryption)
  • RUSTSEC-2023-0071 (PKCS#1 v1.5 timing side-channel)

Both expire 2026-12-01. Before v1.0.0:

  1. Run cargo tree -i rsa to verify the rsa crate is still only a transitive dep.
  2. If reqwest is configured with rustls-tls-native-roots (no native-TLS), the RSA crate may not be reachable. If unreachable, remove the advisory ignores from audit.toml.
  3. If still present as a transitive dep, renew the expiry dates in audit.toml after confirming no pg_ripple code path exercises RSA decryption with untrusted input.

Action required before v1.0.0: Re-audit RSA advisory status and update audit.toml.