dev-mcps/postgres-mcp/test/execution-database.test.js

100 lines
5.1 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
COMMENT_PREFIX, DEFAULT_DATABASE_PREFIX, databaseName, provision, rolePassword, validPrefix
} from "../src/execution-database.js";
const SECRET = "0123456789abcdef0123456789abcdef";
test("the name and the password are what the workflow manager derives", () => {
// The same two values are asserted in the manager's PostgresExecutionDatabaseTest: the two sides meet only through them.
const name = databaseName("exec_", "00000000-0000-0000-0000-000000000001");
assert.equal(name, "exec_00000000_0000_0000_0000_000000000001");
assert.equal(rolePassword(SECRET, name), "42910f819b45a671f75c2a0d6eaa0ea112df2dd9577c3e35498157c7c673b9bc");
assert.equal(databaseName("exec_", "ABC"), "exec_abc");
assert.equal(DEFAULT_DATABASE_PREFIX, "exec_");
});
test("a name that is not a usable identifier is refused", () => {
assert.throws(() => databaseName("exec_", "has space"), /scope/);
assert.throws(() => databaseName("exec_", "x".repeat(60)), /at most 63/);
});
test("a prefix that cannot start an identifier is refused", () => {
for (const bad of ["", "Exec_", "1exec", "ex-ec", "x".repeat(27), undefined]) assert.throws(() => validPrefix(bad), /prefix/);
assert.equal(validPrefix("exec_"), "exec_");
});
class FakeAdmin {
constructor({ version = 170000, roles = [], databases = [], failures = [] } = {}) {
this.version = version;
this.roles = new Set(roles);
this.databases = new Set(databases);
this.failures = failures;
this.statements = [];
}
async query(sql, values) {
this.statements.push(sql);
if (this.failures.length > 0 && this.failures[0].on.test(sql)) throw Object.assign(new Error("boom"), { code: this.failures.shift().code });
if (sql.startsWith("SELECT 1 FROM pg_roles")) return { rowCount: this.roles.has(values[0]) ? 1 : 0 };
if (sql.startsWith("SELECT 1 FROM pg_database")) return { rowCount: this.databases.has(values[0]) ? 1 : 0 };
if (sql.startsWith("SHOW server_version_num")) return { rows: [{ server_version_num: String(this.version) }] };
if (sql.startsWith("CREATE ROLE")) this.roles.add(sql.match(/"([^"]+)"/)[1]);
if (sql.startsWith("CREATE DATABASE")) this.databases.add(sql.match(/"([^"]+)"/)[1]);
return { rowCount: 0, rows: [] };
}
}
test("makes the user, the database owned by it, closes it to everyone else and sets the password", async () => {
const admin = new FakeAdmin();
await provision(admin, "exec_a", "pw");
const sql = admin.statements.filter((s) => !s.startsWith("SELECT") && !s.startsWith("SHOW"));
assert.match(sql[0], /^CREATE ROLE "exec_a" NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS CONNECTION LIMIT 8$/);
assert.equal(sql[1], 'GRANT "exec_a" TO CURRENT_USER WITH INHERIT TRUE, SET TRUE');
assert.equal(sql[2], 'CREATE DATABASE "exec_a" OWNER "exec_a"');
assert.match(sql[3], new RegExp(`^COMMENT ON DATABASE "exec_a" IS '${COMMENT_PREFIX}\\d+'$`));
assert.equal(sql[4], 'REVOKE ALL ON DATABASE "exec_a" FROM PUBLIC');
assert.equal(sql[5], 'GRANT CONNECT ON DATABASE "exec_a" TO CURRENT_USER');
assert.equal(sql[6], `ALTER ROLE "exec_a" LOGIN PASSWORD 'pw'`);
});
test("before PostgreSQL 16 a plain GRANT does what two options do after", async () => {
const admin = new FakeAdmin({ version: 150004 });
await provision(admin, "exec_a", "pw");
assert.ok(admin.statements.includes('GRANT "exec_a" TO CURRENT_USER'));
});
test("leaves a database and user that are already there, and still closes them and sets the password", async () => {
const admin = new FakeAdmin({ roles: ["exec_a"], databases: ["exec_a"] });
await provision(admin, "exec_a", "pw");
assert.ok(!admin.statements.some((s) => s.startsWith("CREATE ")), "nothing is made twice");
assert.ok(!admin.statements.some((s) => s.startsWith("COMMENT")), "its age is that of the one who made it");
assert.ok(admin.statements.includes(`ALTER ROLE "exec_a" LOGIN PASSWORD 'pw'`));
});
test("a password with a quote cannot break out of its statement", async () => {
const admin = new FakeAdmin();
await provision(admin, "exec_a", "it's");
assert.ok(admin.statements.includes(`ALTER ROLE "exec_a" LOGIN PASSWORD 'it''s'`));
});
test("losing a race for the database is not an error", async () => {
const admin = new FakeAdmin({ failures: [{ on: /^CREATE DATABASE/, code: "42P04" }] });
await provision(admin, "exec_a", "pw");
assert.ok(admin.statements.includes(`ALTER ROLE "exec_a" LOGIN PASSWORD 'pw'`));
});
test("a transient clash starts the steps again, and a real error does not", async () => {
const transient = new FakeAdmin({ failures: [{ on: /^GRANT "exec_a" TO/, code: "XX000" }] });
await provision(transient, "exec_a", "pw");
assert.equal(transient.statements.filter((s) => s.startsWith("GRANT \"exec_a\" TO")).length, 2);
const denied = new FakeAdmin({ failures: [{ on: /^CREATE ROLE/, code: "42501" }] });
await assert.rejects(provision(denied, "exec_a", "pw"), (error) => error.code === "42501");
});
test("a name that is not an identifier never reaches a statement", async () => {
await assert.rejects(provision(new FakeAdmin(), 'x"; DROP DATABASE postgres; --', "pw"), /Not a usable name/);
});