pgsql-test 2.11.4 → 2.11.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin.js +68 -22
- package/esm/admin.js +68 -22
- package/package.json +3 -3
package/admin.js
CHANGED
|
@@ -97,7 +97,33 @@ class DbAdmin {
|
|
|
97
97
|
}
|
|
98
98
|
async grantRole(role, user, dbName) {
|
|
99
99
|
const db = dbName ?? this.config.database;
|
|
100
|
-
const sql = `
|
|
100
|
+
const sql = `
|
|
101
|
+
DO $$
|
|
102
|
+
DECLARE
|
|
103
|
+
v_user TEXT := '${user.replace(/'/g, "''")}';
|
|
104
|
+
v_role TEXT := '${role.replace(/'/g, "''")}';
|
|
105
|
+
BEGIN
|
|
106
|
+
-- Pre-check to avoid unnecessary GRANTs; still catch TOCTOU under concurrency
|
|
107
|
+
IF NOT EXISTS (
|
|
108
|
+
SELECT 1 FROM pg_auth_members am
|
|
109
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
110
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
111
|
+
WHERE r1.rolname = v_role AND r2.rolname = v_user
|
|
112
|
+
) THEN
|
|
113
|
+
BEGIN
|
|
114
|
+
EXECUTE format('GRANT %I TO %I', v_role, v_user);
|
|
115
|
+
EXCEPTION
|
|
116
|
+
WHEN unique_violation THEN
|
|
117
|
+
-- Concurrent membership grant; safe to ignore
|
|
118
|
+
NULL;
|
|
119
|
+
WHEN undefined_object THEN
|
|
120
|
+
-- Role or user missing; emit notice and continue
|
|
121
|
+
RAISE NOTICE 'Missing role when granting % to %', v_role, v_user;
|
|
122
|
+
END;
|
|
123
|
+
END IF;
|
|
124
|
+
END
|
|
125
|
+
$$;
|
|
126
|
+
`;
|
|
101
127
|
await this.streamSql(sql, db);
|
|
102
128
|
}
|
|
103
129
|
async grantConnect(role, dbName) {
|
|
@@ -126,35 +152,55 @@ class DbAdmin {
|
|
|
126
152
|
-- Role already exists; optionally sync attributes here with ALTER ROLE
|
|
127
153
|
NULL;
|
|
128
154
|
END;
|
|
129
|
-
|
|
130
|
-
--
|
|
155
|
+
|
|
156
|
+
-- CI/CD concurrency note: GRANT role membership can race on pg_auth_members unique index
|
|
157
|
+
-- We pre-check membership and still catch unique_violation to handle TOCTOU safely.
|
|
131
158
|
IF NOT EXISTS (
|
|
132
|
-
SELECT 1 FROM pg_auth_members am
|
|
133
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
134
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
135
|
-
WHERE r1.rolname = '${anonRole}' AND r2.rolname =
|
|
159
|
+
SELECT 1 FROM pg_auth_members am
|
|
160
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
161
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
162
|
+
WHERE r1.rolname = '${anonRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
136
163
|
) THEN
|
|
137
|
-
|
|
164
|
+
BEGIN
|
|
165
|
+
EXECUTE format('GRANT %I TO %I', '${anonRole.replace(/'/g, "''")}', v_user);
|
|
166
|
+
EXCEPTION
|
|
167
|
+
WHEN unique_violation THEN
|
|
168
|
+
NULL;
|
|
169
|
+
WHEN undefined_object THEN
|
|
170
|
+
RAISE NOTICE 'Missing role when granting % to %', '${anonRole.replace(/'/g, "''")}', v_user;
|
|
171
|
+
END;
|
|
138
172
|
END IF;
|
|
139
|
-
|
|
140
|
-
-- Grant authenticated role if not already granted
|
|
173
|
+
|
|
141
174
|
IF NOT EXISTS (
|
|
142
|
-
SELECT 1 FROM pg_auth_members am
|
|
143
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
144
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
145
|
-
WHERE r1.rolname = '${authRole}' AND r2.rolname =
|
|
175
|
+
SELECT 1 FROM pg_auth_members am
|
|
176
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
177
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
178
|
+
WHERE r1.rolname = '${authRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
146
179
|
) THEN
|
|
147
|
-
|
|
180
|
+
BEGIN
|
|
181
|
+
EXECUTE format('GRANT %I TO %I', '${authRole.replace(/'/g, "''")}', v_user);
|
|
182
|
+
EXCEPTION
|
|
183
|
+
WHEN unique_violation THEN
|
|
184
|
+
NULL;
|
|
185
|
+
WHEN undefined_object THEN
|
|
186
|
+
RAISE NOTICE 'Missing role when granting % to %', '${authRole.replace(/'/g, "''")}', v_user;
|
|
187
|
+
END;
|
|
148
188
|
END IF;
|
|
149
|
-
|
|
150
|
-
-- Grant administrator role if not already granted
|
|
189
|
+
|
|
151
190
|
IF NOT EXISTS (
|
|
152
|
-
SELECT 1 FROM pg_auth_members am
|
|
153
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
154
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
155
|
-
WHERE r1.rolname = '${adminRole}' AND r2.rolname =
|
|
191
|
+
SELECT 1 FROM pg_auth_members am
|
|
192
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
193
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
194
|
+
WHERE r1.rolname = '${adminRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
156
195
|
) THEN
|
|
157
|
-
|
|
196
|
+
BEGIN
|
|
197
|
+
EXECUTE format('GRANT %I TO %I', '${adminRole.replace(/'/g, "''")}', v_user);
|
|
198
|
+
EXCEPTION
|
|
199
|
+
WHEN unique_violation THEN
|
|
200
|
+
NULL;
|
|
201
|
+
WHEN undefined_object THEN
|
|
202
|
+
RAISE NOTICE 'Missing role when granting % to %', '${adminRole.replace(/'/g, "''")}', v_user;
|
|
203
|
+
END;
|
|
158
204
|
END IF;
|
|
159
205
|
END $$;
|
|
160
206
|
`.trim();
|
package/esm/admin.js
CHANGED
|
@@ -94,7 +94,33 @@ export class DbAdmin {
|
|
|
94
94
|
}
|
|
95
95
|
async grantRole(role, user, dbName) {
|
|
96
96
|
const db = dbName ?? this.config.database;
|
|
97
|
-
const sql = `
|
|
97
|
+
const sql = `
|
|
98
|
+
DO $$
|
|
99
|
+
DECLARE
|
|
100
|
+
v_user TEXT := '${user.replace(/'/g, "''")}';
|
|
101
|
+
v_role TEXT := '${role.replace(/'/g, "''")}';
|
|
102
|
+
BEGIN
|
|
103
|
+
-- Pre-check to avoid unnecessary GRANTs; still catch TOCTOU under concurrency
|
|
104
|
+
IF NOT EXISTS (
|
|
105
|
+
SELECT 1 FROM pg_auth_members am
|
|
106
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
107
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
108
|
+
WHERE r1.rolname = v_role AND r2.rolname = v_user
|
|
109
|
+
) THEN
|
|
110
|
+
BEGIN
|
|
111
|
+
EXECUTE format('GRANT %I TO %I', v_role, v_user);
|
|
112
|
+
EXCEPTION
|
|
113
|
+
WHEN unique_violation THEN
|
|
114
|
+
-- Concurrent membership grant; safe to ignore
|
|
115
|
+
NULL;
|
|
116
|
+
WHEN undefined_object THEN
|
|
117
|
+
-- Role or user missing; emit notice and continue
|
|
118
|
+
RAISE NOTICE 'Missing role when granting % to %', v_role, v_user;
|
|
119
|
+
END;
|
|
120
|
+
END IF;
|
|
121
|
+
END
|
|
122
|
+
$$;
|
|
123
|
+
`;
|
|
98
124
|
await this.streamSql(sql, db);
|
|
99
125
|
}
|
|
100
126
|
async grantConnect(role, dbName) {
|
|
@@ -123,35 +149,55 @@ export class DbAdmin {
|
|
|
123
149
|
-- Role already exists; optionally sync attributes here with ALTER ROLE
|
|
124
150
|
NULL;
|
|
125
151
|
END;
|
|
126
|
-
|
|
127
|
-
--
|
|
152
|
+
|
|
153
|
+
-- CI/CD concurrency note: GRANT role membership can race on pg_auth_members unique index
|
|
154
|
+
-- We pre-check membership and still catch unique_violation to handle TOCTOU safely.
|
|
128
155
|
IF NOT EXISTS (
|
|
129
|
-
SELECT 1 FROM pg_auth_members am
|
|
130
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
131
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
132
|
-
WHERE r1.rolname = '${anonRole}' AND r2.rolname =
|
|
156
|
+
SELECT 1 FROM pg_auth_members am
|
|
157
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
158
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
159
|
+
WHERE r1.rolname = '${anonRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
133
160
|
) THEN
|
|
134
|
-
|
|
161
|
+
BEGIN
|
|
162
|
+
EXECUTE format('GRANT %I TO %I', '${anonRole.replace(/'/g, "''")}', v_user);
|
|
163
|
+
EXCEPTION
|
|
164
|
+
WHEN unique_violation THEN
|
|
165
|
+
NULL;
|
|
166
|
+
WHEN undefined_object THEN
|
|
167
|
+
RAISE NOTICE 'Missing role when granting % to %', '${anonRole.replace(/'/g, "''")}', v_user;
|
|
168
|
+
END;
|
|
135
169
|
END IF;
|
|
136
|
-
|
|
137
|
-
-- Grant authenticated role if not already granted
|
|
170
|
+
|
|
138
171
|
IF NOT EXISTS (
|
|
139
|
-
SELECT 1 FROM pg_auth_members am
|
|
140
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
141
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
142
|
-
WHERE r1.rolname = '${authRole}' AND r2.rolname =
|
|
172
|
+
SELECT 1 FROM pg_auth_members am
|
|
173
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
174
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
175
|
+
WHERE r1.rolname = '${authRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
143
176
|
) THEN
|
|
144
|
-
|
|
177
|
+
BEGIN
|
|
178
|
+
EXECUTE format('GRANT %I TO %I', '${authRole.replace(/'/g, "''")}', v_user);
|
|
179
|
+
EXCEPTION
|
|
180
|
+
WHEN unique_violation THEN
|
|
181
|
+
NULL;
|
|
182
|
+
WHEN undefined_object THEN
|
|
183
|
+
RAISE NOTICE 'Missing role when granting % to %', '${authRole.replace(/'/g, "''")}', v_user;
|
|
184
|
+
END;
|
|
145
185
|
END IF;
|
|
146
|
-
|
|
147
|
-
-- Grant administrator role if not already granted
|
|
186
|
+
|
|
148
187
|
IF NOT EXISTS (
|
|
149
|
-
SELECT 1 FROM pg_auth_members am
|
|
150
|
-
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
151
|
-
JOIN pg_roles r2 ON am.member = r2.oid
|
|
152
|
-
WHERE r1.rolname = '${adminRole}' AND r2.rolname =
|
|
188
|
+
SELECT 1 FROM pg_auth_members am
|
|
189
|
+
JOIN pg_roles r1 ON am.roleid = r1.oid
|
|
190
|
+
JOIN pg_roles r2 ON am.member = r2.oid
|
|
191
|
+
WHERE r1.rolname = '${adminRole.replace(/'/g, "''")}' AND r2.rolname = v_user
|
|
153
192
|
) THEN
|
|
154
|
-
|
|
193
|
+
BEGIN
|
|
194
|
+
EXECUTE format('GRANT %I TO %I', '${adminRole.replace(/'/g, "''")}', v_user);
|
|
195
|
+
EXCEPTION
|
|
196
|
+
WHEN unique_violation THEN
|
|
197
|
+
NULL;
|
|
198
|
+
WHEN undefined_object THEN
|
|
199
|
+
RAISE NOTICE 'Missing role when granting % to %', '${adminRole.replace(/'/g, "''")}', v_user;
|
|
200
|
+
END;
|
|
155
201
|
END IF;
|
|
156
202
|
END $$;
|
|
157
203
|
`.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pgsql-test",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.5",
|
|
4
4
|
"author": "Dan Lynch <pyramation@gmail.com>",
|
|
5
5
|
"description": "pgsql-test offers isolated, role-aware, and rollback-friendly PostgreSQL environments for integration tests — giving developers realistic test coverage without external state pollution",
|
|
6
6
|
"main": "index.js",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"@types/pg-copy-streams": "^1.2.5"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@launchql/core": "^2.11.
|
|
63
|
+
"@launchql/core": "^2.11.5",
|
|
64
64
|
"@launchql/env": "^2.4.1",
|
|
65
65
|
"@launchql/server-utils": "^2.4.1",
|
|
66
66
|
"@launchql/types": "^2.6.0",
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"pg-copy-streams": "^6.0.6",
|
|
70
70
|
"pg-env": "^1.1.0"
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
72
|
+
"gitHead": "8830d7a2b4d2ded6bc33a657449ab92e0c948348"
|
|
73
73
|
}
|