diff --git a/cli/scripts/cli.py b/cli/scripts/cli.py index 3a99780b..38190f09 100644 --- a/cli/scripts/cli.py +++ b/cli/scripts/cli.py @@ -542,6 +542,10 @@ def upgrade_component(p_comp): os.environ[p_comp + "_update_version"] = update_version if rc == 0: meta.update_component_version(p_comp, update_version) + # Upgrading base Postgres to an affected minor: if Spock 5.x is already + # installed for this PG, allow-list spock_output before the restart below. + if re.match(r"^pg\d+$", p_comp): + util.maybe_enable_spock_output(p_comp, require_spock_installed=True) util.run_script(p_comp, "update-" + p_comp, "update") if isJSON: msg = ( diff --git a/cli/scripts/install.py b/cli/scripts/install.py index 8a2e3b73..8ce0e1e8 100644 --- a/cli/scripts/install.py +++ b/cli/scripts/install.py @@ -3,7 +3,7 @@ import sys, os, tarfile, platform -VER = "25.6.3" +VER = "25.7.0" REPO = os.getenv("REPO", "https://downloads.pgedge.com/platform/repos/download") if sys.version_info < (3, 9): diff --git a/cli/scripts/util.py b/cli/scripts/util.py index 3a4dfee8..8d709428 100644 --- a/cli/scripts/util.py +++ b/cli/scripts/util.py @@ -4,7 +4,7 @@ import os import time -MY_VERSION = "25.6.3" +MY_VERSION = "25.7.0" MY_CODENAME = "" DEFAULT_PG = "17" @@ -206,6 +206,89 @@ def guc_value_as_bool(guc_value): _SPOCK5_NAME_RE = re.compile(r"^spock5(?:0)?(?:-pg\d+)?$", re.IGNORECASE) _SPOCK5_VER_RE = re.compile(r"^5\.", re.IGNORECASE) +# PG's Nov-2025 security releases added the output_plugin_libraries allow-list +# (default 'pgoutput, test_decoding'). spock_output has to be permitted or Spock +# can't create its replication slot. Minimum affected minor per major: +_OUTPUT_PLUGIN_MIN_MINOR = {15: 19, 16: 15, 17: 11} +_SPOCK_OUTPUT_PLUGIN = "spock_output" +# Stock plugins seeded when the GUC isn't configured at all, so we never drop +# them while adding spock_output. +_DEFAULT_OUTPUT_PLUGINS = "pgoutput, test_decoding" + + +def pg_minor_needs_output_plugin(pg_comp): + """ + True when pg_comp's installed minor is at/above the release that introduced + the output_plugin_libraries allow-list (PG 15.19 / 16.15 / 17.11+). + """ + ver = meta.get_version(pg_comp) + if not ver: + return False + try: + v = Version.coerce(str(ver)) + except Exception: + return False + min_minor = _OUTPUT_PLUGIN_MIN_MINOR.get(v.major) + if min_minor is None: + return False + return v.minor >= min_minor + + +def spock5_installed_for_pg(pg_comp): + """ + True when a Spock 5.x extension is installed for this specific PG major + (e.g. spock50-pg17 for pg17). Scoped by the -pgNN suffix so side-by-side + PG installs don't cross-trigger. + """ + try: + c = cL.cursor() + c.execute( + "SELECT 1 FROM components " + "WHERE component LIKE ? AND version LIKE '5.%' LIMIT 1", + ["spock5%-" + str(pg_comp)], + ) + return c.fetchone() is not None + except Exception: + return False + + +def ensure_spock_output_plugin(pg_comp): + """ + Make sure output_plugin_libraries permits spock_output on pg_comp, preserving + anything already configured. No-op when spock_output is already present; when + the parameter isn't set at all (e.g. an upgraded conf that predates it) the + stock plugins are seeded alongside spock_output. Writes postgresql.conf only; + the new value is picked up by the restart the caller already performs. + """ + current = get_guc_value(pg_comp, "output_plugin_libraries") + + if current: + if _SPOCK_OUTPUT_PLUGIN in current.replace(",", " ").split(): + return + new_val = current.strip() + ", " + _SPOCK_OUTPUT_PLUGIN + else: + new_val = _DEFAULT_OUTPUT_PLUGINS + ", " + _SPOCK_OUTPUT_PLUGIN + + message("Allow-listing " + _SPOCK_OUTPUT_PLUGIN + " in output_plugin_libraries for " + str(pg_comp)) + # new_val already carries every existing entry, so replace the line wholesale. + change_pgconf_keyval(pg_comp, "output_plugin_libraries", new_val, True) + + +def maybe_enable_spock_output(pg_comp, require_spock_installed=False): + """ + Single gate for the spock_output / output_plugin_libraries handling. Only + acts when pg_comp is on an affected PG minor; when require_spock_installed is + set (the PG-upgrade path) it also confirms Spock 5.x is installed for this + same PG major first. Everything is scoped to pg_comp, so side-by-side PG + majors are handled independently. + """ + if not pg_minor_needs_output_plugin(pg_comp): + return + if require_spock_installed and not spock5_installed_for_pg(pg_comp): + return + ensure_spock_output_plugin(pg_comp) + + def validate_spock_upgrade(spock_component): """ Validate Spock↔PostgreSQL compatibility for an upcoming Spock 5 install. @@ -1277,6 +1360,11 @@ def config_extension(p_pg=None, p_comp=None): else: change_pgconf_keyval(p_pg, str(df_l[0]), str(df_l[1]), True) + # Installing/upgrading Spock 5.x on an affected PG minor: allow-list + # spock_output before create_extension() drives the restart below. + if _SPOCK5_NAME_RE.match(str(p_comp)): + maybe_enable_spock_output(pgV) + rc = create_extension(p_pg, p_ext=preload_name, p_extension=extension_name, p_enable=True) if rc is True: return(0) diff --git a/env.sh b/env.sh index adf6027b..1dea7b4f 100755 --- a/env.sh +++ b/env.sh @@ -1,5 +1,5 @@ -hubV=25.6.3 -hubVV=25.6.3 +hubV=25.7.0 +hubVV=25.7.0 aceV=$hubV kirkV=$hubV @@ -23,13 +23,13 @@ removeComponentFromOut=spock60 lolorV=1.2.2-1 snwflkV=2.4-1 -P17=17.10-1 +P17=17.11-1 P171=17.0-1 -P16=16.14-1 +P16=16.15-1 P161=16.4-2 -P15=15.18-1 +P15=15.19-1 P151=15.8-2 vectorV=0.8.1-1 diff --git a/src/conf/versions.sql b/src/conf/versions.sql index 006f3961..f6b043ad 100644 --- a/src/conf/versions.sql +++ b/src/conf/versions.sql @@ -1,7 +1,7 @@ DROP TABLE IF EXISTS hub; CREATE TABLE hub(v TEXT NOT NULL PRIMARY KEY, c TEXT NOT NULL, d TEXT NOT NULL); -INSERT INTO hub VALUES ('25.6.1', '', '20260624'); +INSERT INTO hub VALUES ('25.7.0', '', '20260624'); DROP VIEW IF EXISTS v_versions; DROP VIEW IF EXISTS v_products; @@ -152,21 +152,24 @@ INSERT INTO projects VALUES ('pg', 'pge', 1, 5432, '', 1, 'https://github.com/po INSERT INTO releases VALUES ('pg15', 2, 'pg', '', '', 'prod', 'New in 2022', 1, 'POSTGRES', '', ''); -INSERT INTO versions VALUES ('pg15', '15.18-1', 'amd', 1, '20260514','', '', ''); +INSERT INTO versions VALUES ('pg15', '15.19-1', 'amd', 1, '20260714','', '', ''); +INSERT INTO versions VALUES ('pg15', '15.18-1', 'amd', 0, '20260514','', '', ''); INSERT INTO versions VALUES ('pg15', '15.17-1', 'amd, arm', 0, '20260226','', '', ''); INSERT INTO versions VALUES ('pg15', '15.16-1', 'amd, arm', 0, '20260211','', '', ''); INSERT INTO versions VALUES ('pg15', '15.15-1', 'amd, arm', 0, '20251113','', '', ''); INSERT INTO releases VALUES ('pg16', 2, 'pg', '', '', 'prod', 'New in 2023!', 1, 'POSTGRES', '', ''); -INSERT INTO versions VALUES ('pg16', '16.14-1', 'amd', 1, '20260514','', '', ''); +INSERT INTO versions VALUES ('pg16', '16.15-1', 'amd', 1, '20260714','', '', ''); +INSERT INTO versions VALUES ('pg16', '16.14-1', 'amd', 0, '20260514','', '', ''); INSERT INTO versions VALUES ('pg16', '16.13-1', 'amd, arm', 0, '20260226','', '', ''); INSERT INTO versions VALUES ('pg16', '16.12-1', 'amd, arm', 0, '20260211','', '', ''); INSERT INTO versions VALUES ('pg16', '16.11-1', 'amd, arm', 0, '20251113','', '', ''); INSERT INTO releases VALUES ('pg17', 2, 'pg', '', '', 'prod', 'New in 2024!', 1, 'POSTGRES', '', ''); -INSERT INTO versions VALUES ('pg17', '17.10-1', 'amd', 1, '20260514','', '', ''); +INSERT INTO versions VALUES ('pg17', '17.11-1', 'amd', 1, '20260714','', '', ''); +INSERT INTO versions VALUES ('pg17', '17.10-1', 'amd', 0, '20260514','', '', ''); INSERT INTO versions VALUES ('pg17', '17.9-1', 'amd, arm', 0, '20260226','', '', ''); INSERT INTO versions VALUES ('pg17', '17.8-1', 'amd, arm', 0, '20260211','', '', ''); INSERT INTO versions VALUES ('pg17', '17.7-1', 'amd, arm', 0, '20251113','', '', '');