Skip to content

Commit f043582

Browse files
committed
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.
1 parent fb79d32 commit f043582

File tree

5 files changed

+314
-31
lines changed

5 files changed

+314
-31
lines changed

nix/ext/tests/default.nix

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,21 @@ let
6969
enable = true;
7070
package = psql_15;
7171
enableTCPIP = true;
72-
initialScript = pkgs.writeText "init-postgres-with-password" ''
73-
CREATE USER test WITH PASSWORD 'secret';
74-
'';
7572
authentication = ''
76-
host test postgres samenet scram-sha-256
73+
local all postgres peer map=postgres
74+
local all all peer map=root
75+
'';
76+
identMap = ''
77+
root root supabase_admin
78+
postgres postgres postgres
7779
'';
80+
ensureUsers = [
81+
{
82+
name = "supabase_admin";
83+
ensureClauses.superuser = true;
84+
}
85+
];
86+
7887
settings = (installedExtension "15").defaultSettings or { };
7988
};
8089

nix/ext/tests/lib.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@ def __init__(
3838

3939
def run_sql(self, query: str) -> str:
4040
return self.vm.succeed(
41-
f"""sudo -u postgres psql -t -A -F\",\" -c \"{query}\" """
41+
f"""psql -U supabase_admin -d postgres -t -A -F\",\" -c \"{query}\" """
4242
).strip()
4343

4444
def run_sql_file(self, file: str) -> str:
4545
return self.vm.succeed(
46-
f"""sudo -u postgres psql -v ON_ERROR_STOP=1 -f \"{file}\""""
46+
f"""psql -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -f \"{file}\""""
4747
).strip()
4848

4949
def drop_extension(self):

nix/ext/tests/vault.nix

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
{ self, pkgs }:
2+
let
3+
pname = "supabase_vault";
4+
inherit (pkgs) lib;
5+
installedExtension =
6+
postgresMajorVersion: self.packages.${pkgs.system}."psql_${postgresMajorVersion}/exts/${pname}-all";
7+
versions = postgresqlMajorVersion: (installedExtension postgresqlMajorVersion).versions;
8+
postgresqlWithExtension =
9+
postgresql:
10+
let
11+
majorVersion = lib.versions.major postgresql.version;
12+
pkg = pkgs.buildEnv {
13+
name = "postgresql-${majorVersion}-${pname}";
14+
paths = [
15+
postgresql
16+
postgresql.lib
17+
(installedExtension majorVersion)
18+
self.packages.${pkgs.system}."psql_${majorVersion}/exts/pgsodium-all" # dependency
19+
];
20+
passthru = {
21+
inherit (postgresql) version psqlSchema;
22+
lib = pkg;
23+
withPackages = _: pkg;
24+
};
25+
nativeBuildInputs = [ pkgs.makeWrapper ];
26+
pathsToLink = [
27+
"/"
28+
"/bin"
29+
"/lib"
30+
];
31+
postBuild = ''
32+
wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
33+
wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib
34+
wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib
35+
'';
36+
};
37+
in
38+
pkg;
39+
vaultGetKey = lib.getExe (
40+
pkgs.writeShellScriptBin "vault-getkey" ''
41+
echo 0000000000000000000000000000000000000000000000000000000000000000
42+
''
43+
);
44+
psql_15 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_15;
45+
psql_17 = postgresqlWithExtension self.packages.${pkgs.system}.postgresql_17;
46+
in
47+
self.inputs.nixpkgs.lib.nixos.runTest {
48+
name = pname;
49+
hostPkgs = pkgs;
50+
nodes.server =
51+
{ config, ... }:
52+
{
53+
virtualisation = {
54+
forwardPorts = [
55+
{
56+
from = "host";
57+
host.port = 13022;
58+
guest.port = 22;
59+
}
60+
];
61+
};
62+
63+
services.postgresql = {
64+
enable = true;
65+
package = psql_15;
66+
authentication = ''
67+
local all postgres peer map=postgres
68+
local all all peer map=root
69+
'';
70+
identMap = ''
71+
root root supabase_admin
72+
postgres postgres postgres
73+
'';
74+
initialScript = pkgs.writeText "vault-init.sql" ''
75+
CREATE SCHEMA vault;
76+
'';
77+
78+
ensureUsers = [
79+
{
80+
name = "supabase_admin";
81+
ensureClauses.superuser = true;
82+
}
83+
{ name = "service_role"; }
84+
];
85+
settings = {
86+
"shared_preload_libraries" = "${pname},pgsodium";
87+
"pgsodium.getkey_script" = vaultGetKey;
88+
"vault.getkey_script" = vaultGetKey;
89+
};
90+
};
91+
92+
specialisation.postgresql17.configuration = {
93+
services.postgresql = {
94+
package = lib.mkForce psql_17;
95+
};
96+
97+
systemd.services.postgresql-migrate = {
98+
serviceConfig = {
99+
Type = "oneshot";
100+
RemainAfterExit = true;
101+
User = "postgres";
102+
Group = "postgres";
103+
StateDirectory = "postgresql";
104+
WorkingDirectory = "${builtins.dirOf config.services.postgresql.dataDir}";
105+
};
106+
script =
107+
let
108+
oldPostgresql = psql_15;
109+
newPostgresql = psql_17;
110+
oldDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${oldPostgresql.psqlSchema}";
111+
newDataDir = "${builtins.dirOf config.services.postgresql.dataDir}/${newPostgresql.psqlSchema}";
112+
in
113+
''
114+
if [[ ! -d ${newDataDir} ]]; then
115+
install -d -m 0700 -o postgres -g postgres "${newDataDir}"
116+
${newPostgresql}/bin/initdb -D "${newDataDir}"
117+
echo "shared_preload_libraries = '${pname},pgsodium'" >> "${newDataDir}/postgresql.conf"
118+
echo "vault.getkey_script = '${vaultGetKey}'" >> "${newDataDir}/postgresql.conf";
119+
echo "pgsodium.getkey_script = '${vaultGetKey}'" >> "${newDataDir}/postgresql.conf";
120+
${newPostgresql}/bin/pg_upgrade --old-datadir "${oldDataDir}" --new-datadir "${newDataDir}" \
121+
--old-bindir "${oldPostgresql}/bin" --new-bindir "${newPostgresql}/bin"
122+
else
123+
echo "${newDataDir} already exists"
124+
fi
125+
'';
126+
};
127+
128+
systemd.services.postgresql = {
129+
after = [ "postgresql-migrate.service" ];
130+
requires = [ "postgresql-migrate.service" ];
131+
};
132+
};
133+
};
134+
testScript =
135+
{ nodes, ... }:
136+
let
137+
pg17-configuration = "${nodes.server.system.build.toplevel}/specialisation/postgresql17";
138+
in
139+
''
140+
from pathlib import Path
141+
versions = {
142+
"15": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "15"))}],
143+
"17": [${lib.concatStringsSep ", " (map (s: ''"${s}"'') (versions "17"))}],
144+
}
145+
extension_name = "${pname}"
146+
support_upgrade = True
147+
pg17_configuration = "${pg17-configuration}"
148+
ext_has_background_worker = ${
149+
if (installedExtension "15") ? hasBackgroundWorker then "True" else "False"
150+
}
151+
sql_test_directory = Path("${../../tests}")
152+
pg_regress_test_name = "${(installedExtension "15").pgRegressTestName or pname}"
153+
154+
${builtins.readFile ./lib.py}
155+
156+
start_all()
157+
158+
server.wait_for_unit("multi-user.target")
159+
server.wait_for_unit("postgresql.service")
160+
161+
test = PostgresExtensionTest(server, extension_name, versions, sql_test_directory, support_upgrade)
162+
163+
164+
with subtest("Check upgrade path with postgresql 15"):
165+
test.check_upgrade_path("15")
166+
167+
with subtest("Check pg_regress with postgresql 15 after extension upgrade"):
168+
test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}")
169+
test.check_pg_regress(Path("${psql_15}/lib/pgxs/src/test/regress/pg_regress"), "15", pg_regress_test_name)
170+
171+
last_version = None
172+
with subtest("Check the install of the last version of the extension"):
173+
last_version = test.check_install_last_version("15")
174+
175+
with subtest("Check pg_regress with postgresql 15 after installing the last version"):
176+
test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}")
177+
test.check_pg_regress(Path("${psql_15}/lib/pgxs/src/test/regress/pg_regress"), "15", pg_regress_test_name)
178+
179+
with subtest("switch to postgresql 17"):
180+
server.succeed(
181+
f"{pg17_configuration}/bin/switch-to-configuration test >&2"
182+
)
183+
184+
with subtest("Check last version of the extension after postgresql upgrade"):
185+
test.assert_version_matches(last_version)
186+
187+
with subtest("Check upgrade path with postgresql 17"):
188+
test.check_upgrade_path("17")
189+
190+
with subtest("Check pg_regress with postgresql 17 after extension upgrade"):
191+
test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}")
192+
test.check_pg_regress(Path("${psql_17}/lib/pgxs/src/test/regress/pg_regress"), "17", pg_regress_test_name)
193+
194+
with subtest("Check the install of the last version of the extension"):
195+
test.check_install_last_version("17")
196+
197+
with subtest("Check pg_regress with postgresql 17 after installing the last version"):
198+
test.run_sql_file("${../../../ansible/files/postgresql_extension_custom_scripts/supabase_vault/after-create.sql}")
199+
test.check_pg_regress(Path("${psql_17}/lib/pgxs/src/test/regress/pg_regress"), "17", pg_regress_test_name)
200+
'';
201+
}

nix/ext/vault.nix

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,96 @@
11
{
2+
pkgs,
23
lib,
34
stdenv,
45
fetchFromGitHub,
56
libsodium,
67
postgresql,
78
}:
9+
let
10+
pname = "supabase_vault";
811

9-
stdenv.mkDerivation rec {
10-
pname = "vault";
11-
version = "0.3.1";
12+
# Load version configuration from external file
13+
allVersions = (builtins.fromJSON (builtins.readFile ./versions.json)).${pname};
1214

13-
buildInputs = [
14-
libsodium
15-
postgresql
16-
];
15+
# Filter versions compatible with current PostgreSQL version
16+
supportedVersions = lib.filterAttrs (
17+
_: value: builtins.elem (lib.versions.major postgresql.version) value.postgresql
18+
) allVersions;
1719

18-
src = fetchFromGitHub {
19-
owner = "supabase";
20-
repo = pname;
21-
rev = "refs/tags/v${version}";
22-
hash = "sha256-MC87bqgtynnDhmNZAu96jvfCpsGDCPB0g5TZfRQHd30=";
23-
};
20+
# Derived version information
21+
versions = lib.naturalSort (lib.attrNames supportedVersions);
22+
latestVersion = lib.last versions;
23+
numberOfVersions = builtins.length versions;
24+
packages = builtins.attrValues (
25+
lib.mapAttrs (name: value: build name value.hash) supportedVersions
26+
);
27+
28+
# Build function for individual pgsodium versions
29+
build =
30+
version: hash:
31+
32+
stdenv.mkDerivation rec {
33+
inherit pname version;
34+
35+
buildInputs = [
36+
libsodium
37+
postgresql
38+
];
2439

25-
installPhase = ''
26-
mkdir -p $out/{lib,share/postgresql/extension}
40+
src = fetchFromGitHub {
41+
owner = "supabase";
42+
repo = "vault";
43+
rev = "refs/tags/v${version}";
44+
inherit hash;
45+
};
2746

28-
install -D *${postgresql.dlSuffix} $out/lib
29-
install -D -t $out/share/postgresql/extension sql/*.sql
30-
install -D -t $out/share/postgresql/extension *.control
31-
'';
47+
installPhase =
48+
''
49+
mkdir -p $out/{lib,share/postgresql/extension}
50+
51+
# Create version-specific control file
52+
sed -e "/^default_version =/d" \
53+
-e "s|^module_pathname = .*|module_pathname = '\$libdir/${pname}'|" \
54+
${pname}.control > $out/share/postgresql/extension/${pname}--${version}.control
55+
56+
''
57+
# for versions <= 0.2.8, we don't have a library to install
58+
+ lib.optionalString (builtins.compareVersions "0.2.8" version < 0) ''
59+
# Install shared library with version suffix
60+
mv ${pname}${postgresql.dlSuffix} $out/lib/${pname}-${version}${postgresql.dlSuffix}
61+
62+
# For the latest version, copy the sql files
63+
if [[ "${version}" == "${latestVersion}" ]]; then
64+
install -D -t $out/share/postgresql/extension sql/*.sql
65+
{
66+
echo "default_version = '${latestVersion}'"
67+
cat $out/share/postgresql/extension/${pname}--${latestVersion}.control
68+
} > $out/share/postgresql/extension/${pname}.control
69+
fi
70+
ln -sfn ${pname}-${latestVersion}${postgresql.dlSuffix} $out/lib/${pname}${postgresql.dlSuffix}
71+
'';
72+
73+
meta = with lib; {
74+
description = "Store encrypted secrets in PostgreSQL";
75+
homepage = "https://github.com/supabase/vault";
76+
platforms = postgresql.meta.platforms;
77+
license = licenses.postgresql;
78+
};
79+
};
80+
in
81+
pkgs.buildEnv {
82+
name = pname;
83+
paths = packages;
84+
pathsToLink = [
85+
"/lib"
86+
"/share/postgresql/extension"
87+
];
3288

33-
meta = with lib; {
34-
description = "Store encrypted secrets in PostgreSQL";
35-
homepage = "https://github.com/supabase/${pname}";
36-
platforms = postgresql.meta.platforms;
37-
license = licenses.postgresql;
89+
passthru = {
90+
inherit versions numberOfVersions;
91+
pname = "${pname}-all";
92+
version =
93+
"multi-" + lib.concatStringsSep "-" (map (v: lib.replaceStrings [ "." ] [ "-" ] v) versions);
94+
pgRegressTestName = "vault";
3895
};
3996
}

nix/ext/versions.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,23 @@
406406
"revision": "1.3.14"
407407
}
408408
},
409-
"timescaledb": {
409+
"supabase_vault": {
410+
"0.2.8": {
411+
"postgresql": [
412+
"15",
413+
"17"
414+
],
415+
"hash": "sha256-+QBd4/wj1n33ynt7Gopr6g3xT+TLJ9jMhLffdYeRy4k="
416+
},
417+
"0.3.1": {
418+
"postgresql": [
419+
"15",
420+
"17"
421+
],
422+
"hash": "sha256-MC87bqgtynnDhmNZAu96jvfCpsGDCPB0g5TZfRQHd30="
423+
}
424+
},
425+
"timescaledb": {
410426
"2.9.1": {
411427
"postgresql": [
412428
"15"

0 commit comments

Comments
 (0)