supabase-postgres.git / summary / log / commit / refs

commit    3b2b18a3b09b741ca96b2ffc2875e7674371a4e5
Author:   Jean-François Roche <jfroche@pyxel.be>
Commit:   GitHub <noreply@github.com>
Date:     Tue Nov 04 00:55:09 2025 +0000

    feat: multiple versions for the vault extension (#1661)
    
    * feat: multiple versions for the vault extension
    
    Build multiple versions of the vault extension on different PostgreSQL versions.
    Add test for the extensions and their upgrade on PostgreSQL 15 and 17.
    
    * fix: nixos tests for pg_repack, pgroonga, and plpgsql_check to use the supabase_admin user
    
    We switched to using the supabase_admin user for our Postgres tests instead of the default postgres user. 
    This change updates the authentication methods and user management in the NixOS test configurations for the pg_repack, pgroonga, and plpgsql_check extensions.
    
    * fix: nixos test for plv8 extension to use the supabase_admin user
    
    We switched to using the supabase_admin user for our Postgres tests instead of the default postgres user.
    This change updates the authentication methods and user management in the NixOS test configurations for the plv8 extension.
    
    * chore: bump one more
    
    ---------
    
    Co-authored-by: Sam Rose <samuel@supabase.io>


ansible/vars.yml | 6 +- nix/ext/tests/default.nix | 16 +++- nix/ext/tests/lib.py | 4 +- nix/ext/tests/pg_repack.nix | 16 +++- nix/ext/tests/pgmq.nix | 14 +++ nix/ext/tests/pgroonga.nix | 18 +++- nix/ext/tests/plpgsql_check.nix | 16 +++- nix/ext/tests/plv8.nix | 14 +++ nix/ext/tests/timescaledb.nix | 16 ++++ nix/ext/tests/vault.nix | 200 ++++++++++++++++++++++++++++++++++++++++ nix/ext/vault.nix | 105 ++++++++++++++++----- nix/ext/versions.json | 18 +++- 12 files changed, 399 insertions(+), 44 deletions(-) diff --git a/ansible/vars.yml b/ansible/vars.yml index 691b2fc3..d75fe045 100644 --- a/ansible/vars.yml +++ b/ansible/vars.yml @@ -10,9 +10,9 @@ postgres_major: # Full version strings for each major version postgres_release: - postgresorioledb-17: "17.5.1.058-orioledb" - postgres17: "17.6.1.037" - postgres15: "15.14.1.037" + postgresorioledb-17: "17.5.1.059-orioledb" + postgres17: "17.6.1.038" + postgres15: "15.14.1.038" # Non Postgres Extensions pgbouncer_release: 1.19.0 diff --git a/nix/ext/tests/default.nix b/nix/ext/tests/default.nix index f8b69cd3..c21cedd2 100644 --- a/nix/ext/tests/default.nix +++ b/nix/ext/tests/default.nix @@ -69,12 +69,20 @@ let enable = true; package = psql_15; enableTCPIP = true; - initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER test WITH PASSWORD 'secret'; - ''; authentication = '' - host test postgres samenet scram-sha-256 + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; settings = (installedExtension "15").defaultSettings or { }; }; diff --git a/nix/ext/tests/lib.py b/nix/ext/tests/lib.py index 3383f249..42b5eb36 100644 --- a/nix/ext/tests/lib.py +++ b/nix/ext/tests/lib.py @@ -38,12 +38,12 @@ class PostgresExtensionTest(object): def run_sql(self, query: str) -> str: return self.vm.succeed( - f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """ + f"""psql -U supabase_admin -d postgres -t -A -F\",\" -c \"{query}\" """ ).strip() def run_sql_file(self, file: str) -> str: return self.vm.succeed( - f"""sudo -u postgres psql -v ON_ERROR_STOP=1 -f \"{file}\"""" + f"""psql -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -f \"{file}\"""" ).strip() def drop_extension(self): diff --git a/nix/ext/tests/pg_repack.nix b/nix/ext/tests/pg_repack.nix index 41860d84..dae534d2 100644 --- a/nix/ext/tests/pg_repack.nix +++ b/nix/ext/tests/pg_repack.nix @@ -59,12 +59,20 @@ self.inputs.nixpkgs.lib.nixos.runTest { enable = true; package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; enableTCPIP = true; - initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER test WITH PASSWORD 'secret'; - ''; authentication = '' - host test postgres samenet scram-sha-256 + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; }; networking.firewall.allowedTCPPorts = [ config.services.postgresql.settings.port ]; diff --git a/nix/ext/tests/pgmq.nix b/nix/ext/tests/pgmq.nix index eabebff9..94438d61 100644 --- a/nix/ext/tests/pgmq.nix +++ b/nix/ext/tests/pgmq.nix @@ -47,6 +47,20 @@ self.inputs.nixpkgs.lib.nixos.runTest { services.postgresql = { enable = true; package = (postgresqlWithExtension psql_15); + authentication = '' + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres + ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; settings = (installedExtension "15").defaultSettings or { }; }; diff --git a/nix/ext/tests/pgroonga.nix b/nix/ext/tests/pgroonga.nix index dd15b918..83af20ac 100644 --- a/nix/ext/tests/pgroonga.nix +++ b/nix/ext/tests/pgroonga.nix @@ -60,6 +60,21 @@ self.inputs.nixpkgs.lib.nixos.runTest { services.postgresql = { enable = true; package = psql_15; + enableTCPIP = true; + authentication = '' + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres + ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; }; systemd.services.postgresql.environment.MECAB_DICDIR = "${ self.packages.${pkgs.system}.mecab-naist-jdic @@ -120,7 +135,6 @@ self.inputs.nixpkgs.lib.nixos.runTest { "17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}], } extension_name = "${pname}" - support_upgrade = False pg17_configuration = "${pg17-configuration}" ext_has_background_worker = ${ if (installedExtension "15") ? hasBackgroundWorker then "True" else "False" @@ -135,7 +149,7 @@ self.inputs.nixpkgs.lib.nixos.runTest { server.wait_for_unit("multi-user.target") server.wait_for_unit("postgresql.service") - test = PostgresExtensionTest(server, extension_name, versions, sql_test_directory, support_upgrade) + test = PostgresExtensionTest(server, extension_name, versions, sql_test_directory) with subtest("Check upgrade path with postgresql 15"): test.check_upgrade_path("15") diff --git a/nix/ext/tests/plpgsql_check.nix b/nix/ext/tests/plpgsql_check.nix index 5ab950df..105ed8a8 100644 --- a/nix/ext/tests/plpgsql_check.nix +++ b/nix/ext/tests/plpgsql_check.nix @@ -61,12 +61,20 @@ self.inputs.nixpkgs.lib.nixos.runTest { enable = true; package = psql_15; enableTCPIP = true; - initialScript = pkgs.writeText "init-postgres-with-password" '' - CREATE USER test WITH PASSWORD 'secret'; - ''; authentication = '' - host test postgres samenet scram-sha-256 + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; settings = (installedExtension "15").defaultSettings or { }; }; diff --git a/nix/ext/tests/plv8.nix b/nix/ext/tests/plv8.nix index 37b4da82..085ddd42 100644 --- a/nix/ext/tests/plv8.nix +++ b/nix/ext/tests/plv8.nix @@ -60,6 +60,20 @@ self.inputs.nixpkgs.lib.nixos.runTest { services.postgresql = { enable = true; package = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; + authentication = '' + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres + ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + ]; }; }; testScript = diff --git a/nix/ext/tests/timescaledb.nix b/nix/ext/tests/timescaledb.nix index 85755a82..1bab187d 100644 --- a/nix/ext/tests/timescaledb.nix +++ b/nix/ext/tests/timescaledb.nix @@ -46,6 +46,22 @@ self.inputs.nixpkgs.lib.nixos.runTest { services.postgresql = { enable = true; package = (postgresqlWithExtension psql_15); + authentication = '' + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres + ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + { name = "service_role"; } + ]; + settings = { shared_preload_libraries = "timescaledb"; }; diff --git a/nix/ext/tests/vault.nix b/nix/ext/tests/vault.nix new file mode 100644 index 00000000..f5cbd872 --- /dev/null +++ b/nix/ext/tests/vault.nix @@ -0,0 +1,200 @@ +{ self, pkgs }: +let + pname = "supabase_vault"; + inherit (pkgs) lib; + installedExtension = + postgresMajorVersion: self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all"; + versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions; + postgresqlWithExtension = + postgresql: + let + majorVersion = lib.versions.major postgresql.version; + pkg = pkgs.buildEnv { + name = "postgresql-${majorVersion}-${pname}"; + paths = [ + postgresql + postgresql.lib + (installedExtension majorVersion) + self.packages.${pkgs.system}."psql_${majorVersion}/exts/pgsodium-all" # dependency + ]; + passthru = { + inherit (postgresql) version psqlSchema; + lib = pkg; + withPackages = _: pkg; + }; + nativeBuildInputs = [ pkgs.makeWrapper ]; + pathsToLink = [ + "/" + "/bin" + "/lib" + ]; + postBuild = '' + wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib + wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib + wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib + ''; + }; + in + pkg; + vaultGetKey = lib.getExe ( + pkgs.writeShellScriptBin "vault-getkey" '' + echo 0000000000000000000000000000000000000000000000000000000000000000 + '' + ); + psql_15 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15; + psql_17 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17; +in +self.inputs.nixpkgs.lib.nixos.runTest { + name = pname; + hostPkgs = pkgs; + nodes.server = + { config, ... }: + { + virtualisation = { + forwardPorts = [ + { + from = "host"; + host.port = 13022; + guest.port = 22; + } + ]; + }; + + services.postgresql = { + enable = true; + package = psql_15; + authentication = '' + local all postgres peer map=postgres + local all all peer map=root + ''; + identMap = '' + root root supabase_admin + postgres postgres postgres + ''; + initialScript = pkgs.writeText "vault-init.sql" '' + CREATE SCHEMA vault; + ''; + ensureUsers = [ + { + name = "supabase_admin"; + ensureClauses.superuser = true; + } + { name = "service_role"; } + ]; + settings = { + "shared_preload_libraries" = "${pname},pgsodium"; + "pgsodium.getkey_script" = vaultGetKey; + "vault.getkey_script" = vaultGetKey; + }; + }; + + specialisation.postgresql17.configuration = { + services.postgresql = { + package = lib.mkForce psql_17; + }; + + systemd.services.postgresql-migrate = { + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "postgres"; + Group = "postgres"; + StateDirectory = "postgresql"; + WorkingDirectory = "${builtins.dirOf config.services.postgresql.dataDir}"; + }; + script = + let + oldPostgresql = psql_15; + newPostgresql = psql_17; + oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}"; + newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}"; + in + '' + if [[ ! -d ${newDataDir} ]]; then + install -d -m 0700 -o postgres -g postgres "${newDataDir}" + ${newPostgresql}/bin/initdb -D "${newDataDir}" + echo "shared_preload_libraries = '${pname},pgsodium'" >> "${newDataDir}/postgresql.conf" + echo "vault.getkey_script = '${vaultGetKey}'" >> "${newDataDir}/postgresql.conf"; + echo "pgsodium.getkey_script = '${vaultGetKey}'" >> "${newDataDir}/postgresql.conf"; + ${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \ + --old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin" + else + echo "${newDataDir} already exists" + fi + ''; + }; + + systemd.services.postgresql = { + after = [ "postgresql-migrate.service" ]; + requires = [ "postgresql-migrate.service" ]; + }; + }; + }; + testScript = + { nodes, ... }: + let + pg17-configuration = "${nodes.server.system.build.toplevel}/specialisation/postgresql17"; + in + '' + from pathlib import Path + versions = { + "15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}], + "17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}], + } + extension_name = "${pname}" + support_upgrade = True + pg17_configuration = "${pg17-configuration}" + ext_has_background_worker = ${ + if (installedExtension "15") ? hasBackgroundWorker then "True" else "False" + } + sql_test_directory = Path("${../../tests}") + pg_regress_test_name = "${(installedExtension "15").pgRegressTestName or pname}" + + ${builtins.readFile ./lib.py} + + start_all() + + server.wait_for_unit("multi-user.target") + server.wait_for_unit("postgresql.service") + + test = PostgresExtensionTest(server, extension_name, versions, sql_test_directory, support_upgrade) + + + with subtest("Check upgrade path with postgresql 15"): + test.check_upgrade_path("15") + + with subtest("Check pg_regress with postgresql 15 after extension upgrade"): + test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}") + test.check_pg_regress(Path("${psql_15}/lib/pgxs/src/test/regress/pg_regress"), "15", pg_regress_test_name) + + last_version = None + with subtest("Check the install of the last version of the extension"): + last_version = test.check_install_last_version("15") + + with subtest("Check pg_regress with postgresql 15 after installing the last version"): + test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}") + test.check_pg_regress(Path("${psql_15}/lib/pgxs/src/test/regress/pg_regress"), "15", pg_regress_test_name) + + with subtest("switch to postgresql 17"): + server.succeed( + f"{pg17_configuration}/bin/switch-to-configuration test >&2" + ) + + with subtest("Check last version of the extension after postgresql upgrade"): + test.assert_version_matches(last_version) + + with subtest("Check upgrade path with postgresql 17"): + test.check_upgrade_path("17") + + with subtest("Check pg_regress with postgresql 17 after extension upgrade"): + test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}") + test.check_pg_regress(Path("${psql_17}/lib/pgxs/src/test/regress/pg_regress"), "17", pg_regress_test_name) + + with subtest("Check the install of the last version of the extension"): + test.check_install_last_version("17") + + with subtest("Check pg_regress with postgresql 17 after installing the last version"): + test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}") + test.check_pg_regress(Path("${psql_17}/lib/pgxs/src/test/regress/pg_regress"), "17", pg_regress_test_name) + ''; +} diff --git a/nix/ext/vault.nix b/nix/ext/vault.nix index 275d6967..c518e1e1 100644 --- a/nix/ext/vault.nix +++ b/nix/ext/vault.nix @@ -1,39 +1,96 @@ { + pkgs, lib, stdenv, fetchFromGitHub, libsodium, postgresql, }: +let + pname = "supabase_vault"; -stdenv.mkDerivation rec { - pname = "vault"; - version = "0.3.1"; + # Load version configuration from external file + allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname}; - buildInputs = [ - libsodium - postgresql - ]; + # Filter versions compatible with current PostgreSQL version + supportedVersions = lib.filterAttrs ( + _: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql + ) allVersions; - src = fetchFromGitHub { - owner = "supabase"; - repo = pname; - rev = "refs/tags/v${version}"; - hash = "sha256-MC87bqgtynnDhmNZAu96jvfCpsGDCPB0g5TZfRQHd30="; - }; + # Derived version information + versions = lib.naturalSort (lib.attrNames supportedVersions); + latestVersion = lib.last versions; + numberOfVersions = builtins.length versions; + packages = builtins.attrValues ( + lib.mapAttrs (name: value: build name value.hash) supportedVersions + ); + + # Build function for individual pgsodium versions + build = + version: hash: + + stdenv.mkDerivation rec { + inherit pname version; + + buildInputs = [ + libsodium + postgresql + ]; - installPhase = '' - mkdir -p $out/{lib,share/postgresql/extension} + src = fetchFromGitHub { + owner = "supabase"; + repo = "vault"; + rev = "refs/tags/v${version}"; + inherit hash; + }; - install -D *${postgresql.dlSuffix} $out/lib - install -D -t $out/share/postgresql/extension sql/*.sql - install -D -t $out/share/postgresql/extension *.control - ''; + installPhase = + '' + mkdir -p $out/{lib,share/postgresql/extension} + + # Create version-specific control file + sed -e "/^default_version =/d" \ + -e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \ + ${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control + + '' + # for versions <= 0.2.8, we don't have a library to install + + lib.optionalString (builtins.compareVersions "0.2.8" version < 0) '' + # Install shared library with version suffix + mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix} + + # For the latest version, copy the sql files + if [[ "${version}" == "${latestVersion}" ]]; then + install -D -t $out/share/postgresql/extension sql/*.sql + { + echo "default_version = '${latestVersion}'" + cat $out/share/postgresql/extension/${pname}--${latestVersion}.control + } > $out/share/postgresql/extension/${pname}.control + fi + ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix} + ''; + + meta = with lib; { + description = "Store encrypted secrets in PostgreSQL"; + homepage = "https://github.com/supabase/vault"; + platforms = postgresql.meta.platforms; + license = licenses.postgresql; + }; + }; +in +pkgs.buildEnv { + name = pname; + paths = packages; + pathsToLink = [ + "/lib" + "/share/postgresql/extension" + ]; - meta = with lib; { - description = "Store encrypted secrets in PostgreSQL"; - homepage = "https://github.com/supabase/${pname}"; - platforms = postgresql.meta.platforms; - license = licenses.postgresql; + passthru = { + inherit versions numberOfVersions; + pname = "${pname}-all"; + version = + "multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions); + pgRegressTestName = "vault"; }; } diff --git a/nix/ext/versions.json b/nix/ext/versions.json index d106c2c8..e91d7919 100644 --- a/nix/ext/versions.json +++ b/nix/ext/versions.json @@ -459,7 +459,23 @@ "revision": "1.3.14" } }, - "timescaledb": { + "supabase_vault": { + "0.2.8": { + "postgresql": [ + "15", + "17" + ], + "hash": "sha256-+QBd4/wj1n33ynt7Gopr6g3xT+TLJ9jMhLffdYeRy4k=" + }, + "0.3.1": { + "postgresql": [ + "15", + "17" + ], + "hash": "sha256-MC87bqgtynnDhmNZAu96jvfCpsGDCPB0g5TZfRQHd30=" + } + }, + "timescaledb": { "2.9.1": { "postgresql": [ "15" [parent: f8c523cb5b44]