graphql-server-test 3.33.2 → 3.33.4
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/README.md +0 -1
- package/esm/get-connections.js +45 -3
- package/get-connections.js +45 -3
- package/package.json +11 -10
package/README.md
CHANGED
|
@@ -181,7 +181,6 @@ The `server.api` option provides full control over the GraphQL server configurat
|
|
|
181
181
|
|
|
182
182
|
| Property | Type | Default | Description |
|
|
183
183
|
|----------|------|---------|-------------|
|
|
184
|
-
| `routingSchema` | `string` | `routing_public` | Schema that owns `resolve_route()` and the routing tables |
|
|
185
184
|
| `exposedSchemas` | `string[]` | from `schemas` | Database schemas to expose (overridden by `schemas`) |
|
|
186
185
|
| `anonRole` | `string` | from `authRole` | Anonymous role name (overridden by `authRole`) |
|
|
187
186
|
| `roleName` | `string` | from `authRole` | Default role name (overridden by `authRole`) |
|
package/esm/get-connections.js
CHANGED
|
@@ -1,7 +1,41 @@
|
|
|
1
1
|
import { getEnvOptions } from '@constructive-io/graphql-env';
|
|
2
|
+
import { randomBytes } from 'crypto';
|
|
3
|
+
import { pgCache } from 'pg-cache';
|
|
2
4
|
import { getConnections as getPgConnections } from 'pgsql-test';
|
|
3
5
|
import { createDevTestServer, createTestServer } from './server';
|
|
4
6
|
import { createQueryFn, createSuperTestAgent } from './supertest';
|
|
7
|
+
/**
|
|
8
|
+
* The server connects as its own login, as in production: NOBYPASSRLS, a
|
|
9
|
+
* member of the request roles only, never of administrator. It holds the
|
|
10
|
+
* table/function privileges the seeded schemas grant it, so whatever RLS hides
|
|
11
|
+
* from it stays hidden and a read that silently relied on BYPASSRLS fails here.
|
|
12
|
+
*/
|
|
13
|
+
const createServerLogin = async (pg) => {
|
|
14
|
+
const user = `server_test_${randomBytes(6).toString('hex')}`;
|
|
15
|
+
const password = randomBytes(18).toString('hex');
|
|
16
|
+
await pg.query(`
|
|
17
|
+
CREATE ROLE "${user}" LOGIN NOSUPERUSER NOBYPASSRLS PASSWORD '${password}' IN ROLE anonymous, authenticated;
|
|
18
|
+
GRANT CONNECT ON DATABASE "${pg.config.database}" TO "${user}";
|
|
19
|
+
DO $grant$
|
|
20
|
+
DECLARE s text;
|
|
21
|
+
BEGIN
|
|
22
|
+
FOR s IN
|
|
23
|
+
SELECT nspname FROM pg_namespace
|
|
24
|
+
WHERE nspname NOT LIKE 'pg\\_%' AND nspname <> 'information_schema'
|
|
25
|
+
LOOP
|
|
26
|
+
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', s, '${user}');
|
|
27
|
+
EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO %I', s, '${user}');
|
|
28
|
+
EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA %I TO %I', s, '${user}');
|
|
29
|
+
END LOOP;
|
|
30
|
+
END
|
|
31
|
+
$grant$;
|
|
32
|
+
`);
|
|
33
|
+
// The seed's pg-cache entry must not hand the server the seeding connection.
|
|
34
|
+
pgCache.delete(pg.config.database);
|
|
35
|
+
await pgCache.waitForDisposals();
|
|
36
|
+
return { user, password };
|
|
37
|
+
};
|
|
38
|
+
const liveSuites = new Set();
|
|
5
39
|
/**
|
|
6
40
|
* Creates connections with an HTTP server for SuperTest testing
|
|
7
41
|
*
|
|
@@ -35,10 +69,11 @@ export const getConnections = async (input, seedAdapters) => {
|
|
|
35
69
|
// Get database connections using pgsql-test
|
|
36
70
|
const conn = await getPgConnections(input, seedAdapters);
|
|
37
71
|
const { pg, db, teardown: dbTeardown } = conn;
|
|
72
|
+
const login = await createServerLogin(pg);
|
|
38
73
|
// Build options for the HTTP server
|
|
39
74
|
// Merge user-provided server.api options with convenience properties (schemas, authRole)
|
|
40
75
|
const serverOpts = getEnvOptions({
|
|
41
|
-
pg: pg.config,
|
|
76
|
+
pg: { ...pg.config, user: login.user, password: login.password },
|
|
42
77
|
api: {
|
|
43
78
|
// Start with user-provided api options from server.api
|
|
44
79
|
...input.server?.api,
|
|
@@ -57,9 +92,16 @@ export const getConnections = async (input, seedAdapters) => {
|
|
|
57
92
|
: await createDevTestServer(serverOpts, input.server);
|
|
58
93
|
// Create SuperTest agent
|
|
59
94
|
const request = createSuperTestAgent(server);
|
|
60
|
-
|
|
95
|
+
const suite = { server, pg, user: login.user };
|
|
96
|
+
liveSuites.add(suite);
|
|
97
|
+
// pgsql-test's teardown closes every database this process opened, so the
|
|
98
|
+
// first teardown also releases every other live suite's server and login.
|
|
61
99
|
const teardown = async () => {
|
|
62
|
-
|
|
100
|
+
for (const live of [...liveSuites]) {
|
|
101
|
+
liveSuites.delete(live);
|
|
102
|
+
await live.server.stop();
|
|
103
|
+
await live.pg.query(`DROP OWNED BY "${live.user}"; DROP ROLE "${live.user}"`);
|
|
104
|
+
}
|
|
63
105
|
await dbTeardown();
|
|
64
106
|
};
|
|
65
107
|
return {
|
package/get-connections.js
CHANGED
|
@@ -2,9 +2,43 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getConnections = void 0;
|
|
4
4
|
const graphql_env_1 = require("@constructive-io/graphql-env");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const pg_cache_1 = require("pg-cache");
|
|
5
7
|
const pgsql_test_1 = require("pgsql-test");
|
|
6
8
|
const server_1 = require("./server");
|
|
7
9
|
const supertest_1 = require("./supertest");
|
|
10
|
+
/**
|
|
11
|
+
* The server connects as its own login, as in production: NOBYPASSRLS, a
|
|
12
|
+
* member of the request roles only, never of administrator. It holds the
|
|
13
|
+
* table/function privileges the seeded schemas grant it, so whatever RLS hides
|
|
14
|
+
* from it stays hidden and a read that silently relied on BYPASSRLS fails here.
|
|
15
|
+
*/
|
|
16
|
+
const createServerLogin = async (pg) => {
|
|
17
|
+
const user = `server_test_${(0, crypto_1.randomBytes)(6).toString('hex')}`;
|
|
18
|
+
const password = (0, crypto_1.randomBytes)(18).toString('hex');
|
|
19
|
+
await pg.query(`
|
|
20
|
+
CREATE ROLE "${user}" LOGIN NOSUPERUSER NOBYPASSRLS PASSWORD '${password}' IN ROLE anonymous, authenticated;
|
|
21
|
+
GRANT CONNECT ON DATABASE "${pg.config.database}" TO "${user}";
|
|
22
|
+
DO $grant$
|
|
23
|
+
DECLARE s text;
|
|
24
|
+
BEGIN
|
|
25
|
+
FOR s IN
|
|
26
|
+
SELECT nspname FROM pg_namespace
|
|
27
|
+
WHERE nspname NOT LIKE 'pg\\_%' AND nspname <> 'information_schema'
|
|
28
|
+
LOOP
|
|
29
|
+
EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', s, '${user}');
|
|
30
|
+
EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO %I', s, '${user}');
|
|
31
|
+
EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA %I TO %I', s, '${user}');
|
|
32
|
+
END LOOP;
|
|
33
|
+
END
|
|
34
|
+
$grant$;
|
|
35
|
+
`);
|
|
36
|
+
// The seed's pg-cache entry must not hand the server the seeding connection.
|
|
37
|
+
pg_cache_1.pgCache.delete(pg.config.database);
|
|
38
|
+
await pg_cache_1.pgCache.waitForDisposals();
|
|
39
|
+
return { user, password };
|
|
40
|
+
};
|
|
41
|
+
const liveSuites = new Set();
|
|
8
42
|
/**
|
|
9
43
|
* Creates connections with an HTTP server for SuperTest testing
|
|
10
44
|
*
|
|
@@ -38,10 +72,11 @@ const getConnections = async (input, seedAdapters) => {
|
|
|
38
72
|
// Get database connections using pgsql-test
|
|
39
73
|
const conn = await (0, pgsql_test_1.getConnections)(input, seedAdapters);
|
|
40
74
|
const { pg, db, teardown: dbTeardown } = conn;
|
|
75
|
+
const login = await createServerLogin(pg);
|
|
41
76
|
// Build options for the HTTP server
|
|
42
77
|
// Merge user-provided server.api options with convenience properties (schemas, authRole)
|
|
43
78
|
const serverOpts = (0, graphql_env_1.getEnvOptions)({
|
|
44
|
-
pg: pg.config,
|
|
79
|
+
pg: { ...pg.config, user: login.user, password: login.password },
|
|
45
80
|
api: {
|
|
46
81
|
// Start with user-provided api options from server.api
|
|
47
82
|
...input.server?.api,
|
|
@@ -60,9 +95,16 @@ const getConnections = async (input, seedAdapters) => {
|
|
|
60
95
|
: await (0, server_1.createDevTestServer)(serverOpts, input.server);
|
|
61
96
|
// Create SuperTest agent
|
|
62
97
|
const request = (0, supertest_1.createSuperTestAgent)(server);
|
|
63
|
-
|
|
98
|
+
const suite = { server, pg, user: login.user };
|
|
99
|
+
liveSuites.add(suite);
|
|
100
|
+
// pgsql-test's teardown closes every database this process opened, so the
|
|
101
|
+
// first teardown also releases every other live suite's server and login.
|
|
64
102
|
const teardown = async () => {
|
|
65
|
-
|
|
103
|
+
for (const live of [...liveSuites]) {
|
|
104
|
+
liveSuites.delete(live);
|
|
105
|
+
await live.server.stop();
|
|
106
|
+
await live.pg.query(`DROP OWNED BY "${live.user}"; DROP ROLE "${live.user}"`);
|
|
107
|
+
}
|
|
66
108
|
await dbTeardown();
|
|
67
109
|
};
|
|
68
110
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "graphql-server-test",
|
|
3
|
-
"version": "3.33.
|
|
3
|
+
"version": "3.33.4",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Constructive GraphQL Server Testing with SuperTest HTTP requests",
|
|
6
6
|
"main": "index.js",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@0no-co/graphql.web": "^1.3.3",
|
|
33
33
|
"@agentic-kit/ollama": "2.16.0",
|
|
34
|
-
"@constructive-io/graphql-codegen": "^5.24.
|
|
35
|
-
"@constructive-io/graphql-query": "^4.21.
|
|
34
|
+
"@constructive-io/graphql-codegen": "^5.24.4",
|
|
35
|
+
"@constructive-io/graphql-query": "^4.21.4",
|
|
36
36
|
"@constructive-io/s3-utils": "^2.35.0",
|
|
37
37
|
"@pgpmjs/core": "^7.34.0",
|
|
38
38
|
"@simplewebauthn/server": "13.3.2",
|
|
@@ -47,18 +47,19 @@
|
|
|
47
47
|
"nested-obj": "^0.2.3"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@constructive-io/
|
|
51
|
-
"@constructive-io/graphql-
|
|
52
|
-
"@constructive-io/graphql-
|
|
53
|
-
"@constructive-io/graphql-
|
|
50
|
+
"@constructive-io/express-context": "^0.35.1",
|
|
51
|
+
"@constructive-io/graphql-dev-server": "^3.21.4",
|
|
52
|
+
"@constructive-io/graphql-env": "^3.37.2",
|
|
53
|
+
"@constructive-io/graphql-server": "^5.32.4",
|
|
54
|
+
"@constructive-io/graphql-types": "^3.36.1",
|
|
54
55
|
"@constructive-io/upload-client": "0.29.0",
|
|
55
56
|
"@pgpmjs/types": "^2.58.0",
|
|
56
57
|
"express": "^5.2.1",
|
|
57
|
-
"graphile-schema": "^2.20.
|
|
58
|
+
"graphile-schema": "^2.20.4",
|
|
58
59
|
"graphql": "16.13.0",
|
|
59
60
|
"pg": "^8.21.0",
|
|
60
61
|
"pg-cache": "^3.30.0",
|
|
61
|
-
"pgsql-test": "^5.18.
|
|
62
|
+
"pgsql-test": "^5.18.1",
|
|
62
63
|
"supertest": "^7.0.0"
|
|
63
64
|
},
|
|
64
65
|
"keywords": [
|
|
@@ -72,5 +73,5 @@
|
|
|
72
73
|
"e2e",
|
|
73
74
|
"server"
|
|
74
75
|
],
|
|
75
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "b6c80da2ba0532a4aaf0d0154901efa7911974d8"
|
|
76
77
|
}
|