postgresai 0.14.0-dev.36 → 0.14.0-dev.38
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 +23 -23
- package/bin/postgres-ai.ts +357 -24
- package/dist/bin/postgres-ai.js +331 -23
- package/dist/bin/postgres-ai.js.map +1 -1
- package/dist/lib/checkup-api.d.ts +33 -0
- package/dist/lib/checkup-api.d.ts.map +1 -0
- package/dist/lib/checkup-api.js +187 -0
- package/dist/lib/checkup-api.js.map +1 -0
- package/dist/lib/checkup.d.ts +153 -0
- package/dist/lib/checkup.d.ts.map +1 -0
- package/dist/lib/checkup.js +536 -0
- package/dist/lib/checkup.js.map +1 -0
- package/dist/lib/config.d.ts +1 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +2 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/package.json +1 -1
- package/lib/checkup-api.ts +177 -0
- package/lib/checkup.ts +622 -0
- package/lib/config.ts +3 -0
- package/package.json +1 -1
- package/reports/A002.json +23 -0
- package/reports/A003.json +3343 -0
- package/reports/A004.json +134 -0
- package/reports/A007.json +683 -0
- package/reports/A013.json +23 -0
- package/test/checkup.test.cjs +645 -0
- package/test/init.integration.test.cjs +10 -10
- package/test/init.test.cjs +73 -4
|
@@ -157,7 +157,7 @@ async function withTempPostgres(t) {
|
|
|
157
157
|
async function runCliInit(args, env = {}) {
|
|
158
158
|
const node = process.execPath;
|
|
159
159
|
const cliPath = path.resolve(__dirname, "..", "dist", "bin", "postgres-ai.js");
|
|
160
|
-
const res = spawnSync(node, [cliPath, "
|
|
160
|
+
const res = spawnSync(node, [cliPath, "prepare-db", ...args], {
|
|
161
161
|
encoding: "utf8",
|
|
162
162
|
env: { ...process.env, ...env },
|
|
163
163
|
});
|
|
@@ -165,7 +165,7 @@ async function runCliInit(args, env = {}) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
test(
|
|
168
|
-
"integration:
|
|
168
|
+
"integration: prepare-db supports URI / conninfo / psql-like connection styles",
|
|
169
169
|
{ skip: !havePostgresBinaries() },
|
|
170
170
|
async (t) => {
|
|
171
171
|
const pg = await withTempPostgres(t);
|
|
@@ -207,7 +207,7 @@ test(
|
|
|
207
207
|
);
|
|
208
208
|
|
|
209
209
|
test(
|
|
210
|
-
"integration:
|
|
210
|
+
"integration: prepare-db requires explicit monitoring password in non-interactive mode (unless --print-password)",
|
|
211
211
|
{ skip: !havePostgresBinaries() },
|
|
212
212
|
async (t) => {
|
|
213
213
|
const pg = await withTempPostgres(t);
|
|
@@ -231,7 +231,7 @@ test(
|
|
|
231
231
|
);
|
|
232
232
|
|
|
233
233
|
test(
|
|
234
|
-
"integration:
|
|
234
|
+
"integration: prepare-db fixes slightly-off permissions idempotently",
|
|
235
235
|
{ skip: !havePostgresBinaries() },
|
|
236
236
|
async (t) => {
|
|
237
237
|
const pg = await withTempPostgres(t);
|
|
@@ -285,7 +285,7 @@ test(
|
|
|
285
285
|
}
|
|
286
286
|
);
|
|
287
287
|
|
|
288
|
-
test("integration:
|
|
288
|
+
test("integration: prepare-db reports nicely when lacking permissions", { skip: !havePostgresBinaries() }, async (t) => {
|
|
289
289
|
const pg = await withTempPostgres(t);
|
|
290
290
|
const { Client } = require("pg");
|
|
291
291
|
|
|
@@ -310,13 +310,13 @@ test("integration: init reports nicely when lacking permissions", { skip: !haveP
|
|
|
310
310
|
const limitedUri = `postgresql://limited:${limitedPw}@127.0.0.1:${pg.port}/testdb`;
|
|
311
311
|
const r = await runCliInit([limitedUri, "--password", "monpw", "--skip-optional-permissions"]);
|
|
312
312
|
assert.notEqual(r.status, 0);
|
|
313
|
-
assert.match(r.stderr, /Error:
|
|
313
|
+
assert.match(r.stderr, /Error: prepare-db:/);
|
|
314
314
|
// Should include step context and hint.
|
|
315
315
|
assert.match(r.stderr, /Failed at step "/);
|
|
316
316
|
assert.match(r.stderr, /Fix: connect as a superuser/i);
|
|
317
317
|
});
|
|
318
318
|
|
|
319
|
-
test("integration:
|
|
319
|
+
test("integration: prepare-db --verify returns 0 when ok and non-zero when missing", { skip: !havePostgresBinaries() }, async (t) => {
|
|
320
320
|
const pg = await withTempPostgres(t);
|
|
321
321
|
const { Client } = require("pg");
|
|
322
322
|
|
|
@@ -330,7 +330,7 @@ test("integration: init --verify returns 0 when ok and non-zero when missing", {
|
|
|
330
330
|
{
|
|
331
331
|
const r = await runCliInit([pg.adminUri, "--verify", "--skip-optional-permissions"]);
|
|
332
332
|
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
333
|
-
assert.match(r.stdout, /
|
|
333
|
+
assert.match(r.stdout, /prepare-db verify: OK/i);
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
// Break a required privilege and ensure verify fails
|
|
@@ -345,12 +345,12 @@ test("integration: init --verify returns 0 when ok and non-zero when missing", {
|
|
|
345
345
|
{
|
|
346
346
|
const r = await runCliInit([pg.adminUri, "--verify", "--skip-optional-permissions"]);
|
|
347
347
|
assert.notEqual(r.status, 0);
|
|
348
|
-
assert.match(r.stderr, /
|
|
348
|
+
assert.match(r.stderr, /prepare-db verify failed/i);
|
|
349
349
|
assert.match(r.stderr, /pg_catalog\.pg_index/i);
|
|
350
350
|
}
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
-
test("integration:
|
|
353
|
+
test("integration: prepare-db --reset-password updates the monitoring role login password", { skip: !havePostgresBinaries() }, async (t) => {
|
|
354
354
|
const pg = await withTempPostgres(t);
|
|
355
355
|
const { Client } = require("pg");
|
|
356
356
|
|
package/test/init.test.cjs
CHANGED
|
@@ -177,8 +177,8 @@ test("resolveAdminConnection rejects when connection is missing", () => {
|
|
|
177
177
|
assert.throws(() => init.resolveAdminConnection({}), /Connection is required/);
|
|
178
178
|
});
|
|
179
179
|
|
|
180
|
-
test("cli:
|
|
181
|
-
const r = runCli(["
|
|
180
|
+
test("cli: prepare-db with missing connection prints help/options", () => {
|
|
181
|
+
const r = runCli(["prepare-db"]);
|
|
182
182
|
assert.notEqual(r.status, 0);
|
|
183
183
|
// We should show options, not just the error message.
|
|
184
184
|
assert.match(r.stderr, /--print-sql/);
|
|
@@ -307,8 +307,8 @@ test("redactPasswordsInSql redacts password literals with embedded quotes", asyn
|
|
|
307
307
|
assert.match(redacted, /password '<redacted>'/i);
|
|
308
308
|
});
|
|
309
309
|
|
|
310
|
-
test("cli:
|
|
311
|
-
const r = runCli(["
|
|
310
|
+
test("cli: prepare-db --print-sql works without connection (offline mode)", () => {
|
|
311
|
+
const r = runCli(["prepare-db", "--print-sql", "-d", "mydb", "--password", "monpw"]);
|
|
312
312
|
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
313
313
|
assert.match(r.stdout, /SQL plan \(offline; not connected\)/);
|
|
314
314
|
assert.match(r.stdout, new RegExp(`grant connect on database "mydb" to "${DEFAULT_MONITORING_USER}"`, "i"));
|
|
@@ -320,4 +320,73 @@ test("pgai wrapper forwards to postgresai CLI", () => {
|
|
|
320
320
|
assert.match(r.stdout, /postgresai|PostgresAI/i);
|
|
321
321
|
});
|
|
322
322
|
|
|
323
|
+
test("cli: prepare-db command exists and shows help", () => {
|
|
324
|
+
const r = runCli(["prepare-db", "--help"]);
|
|
325
|
+
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
326
|
+
assert.match(r.stdout, /monitoring user/i);
|
|
327
|
+
assert.match(r.stdout, /--print-sql/);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("cli: prepare-db with missing connection prints help/options", () => {
|
|
331
|
+
const r = runCli(["prepare-db"]);
|
|
332
|
+
assert.notEqual(r.status, 0);
|
|
333
|
+
assert.match(r.stderr, /--print-sql/);
|
|
334
|
+
assert.match(r.stderr, /--monitoring-user/);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("cli: prepare-db --print-sql works without connection (offline mode)", () => {
|
|
338
|
+
const r = runCli(["prepare-db", "--print-sql", "-d", "mydb", "--password", "monpw"]);
|
|
339
|
+
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
340
|
+
assert.match(r.stdout, /SQL plan \(offline; not connected\)/);
|
|
341
|
+
assert.match(r.stdout, new RegExp(`grant connect on database "mydb" to "${DEFAULT_MONITORING_USER}"`, "i"));
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("cli: mon local-install command exists and shows help", () => {
|
|
345
|
+
const r = runCli(["mon", "local-install", "--help"]);
|
|
346
|
+
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
347
|
+
assert.match(r.stdout, /--demo/);
|
|
348
|
+
assert.match(r.stdout, /--api-key/);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
// Auth --set-key tests
|
|
352
|
+
test("cli: auth --set-key stores key without OAuth", () => {
|
|
353
|
+
const fs = require("node:fs");
|
|
354
|
+
const path = require("node:path");
|
|
355
|
+
const os = require("node:os");
|
|
356
|
+
|
|
357
|
+
// Use a temp directory for config to avoid modifying user's actual config
|
|
358
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pgai-auth-test-"));
|
|
359
|
+
|
|
360
|
+
try {
|
|
361
|
+
// Create the postgresai subdirectory so we know exactly where config goes
|
|
362
|
+
const postgresaiDir = path.join(tmpDir, "postgresai");
|
|
363
|
+
fs.mkdirSync(postgresaiDir, { recursive: true });
|
|
364
|
+
|
|
365
|
+
// Set XDG_CONFIG_HOME to redirect config to temp dir
|
|
366
|
+
const r = runCli(["auth", "--set-key", "test-api-key-12345"], {
|
|
367
|
+
XDG_CONFIG_HOME: tmpDir,
|
|
368
|
+
// Also clear HOME to prevent fallbacks
|
|
369
|
+
HOME: tmpDir,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
373
|
+
assert.match(r.stdout, /API key saved/i);
|
|
374
|
+
|
|
375
|
+
// Verify the config file was created with the API key
|
|
376
|
+
const actualConfigPath = path.join(postgresaiDir, "config.json");
|
|
377
|
+
assert.ok(fs.existsSync(actualConfigPath), "Config file should exist at " + actualConfigPath);
|
|
378
|
+
|
|
379
|
+
const config = JSON.parse(fs.readFileSync(actualConfigPath, "utf8"));
|
|
380
|
+
assert.equal(config.apiKey, "test-api-key-12345");
|
|
381
|
+
} finally {
|
|
382
|
+
// Cleanup
|
|
383
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("cli: auth --help shows --set-key option", () => {
|
|
388
|
+
const r = runCli(["auth", "--help"]);
|
|
389
|
+
assert.equal(r.status, 0, r.stderr || r.stdout);
|
|
390
|
+
assert.match(r.stdout, /--set-key/);
|
|
391
|
+
});
|
|
323
392
|
|