Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/scripts/verify-migrator-role.test.mjs
T

115 lines
3.5 KiB
JavaScript

import assert from "node:assert/strict";
import { describe, it } from "vitest";
import { MIGRATOR_DATABASE_URL_ENV, MigratorRoleVerificationError, verifyMigratorRole, verifyMigratorRoleState } from "./verify-migrator-role.mjs";
const SECRET_URL = "postgresql://hivegrid_migrator:migrator-secret@db.example.test:5432/hivegrid";
function validState() {
return {
session: { sessionRole: "hivegrid_migrator", currentRole: "hivegrid_migrator" },
roles: [
{
roleName: "hivegrid_migrator",
canLogin: true,
isSuperuser: false,
canCreateDb: false,
canCreateRole: false,
inherits: false,
replicates: false,
bypassesRls: false,
},
],
memberships: [
{
grantedRole: "hivegrid_rls_definer",
memberRole: "hivegrid_migrator",
adminOption: false,
inheritOption: false,
setOption: true,
},
],
};
}
class FakeClient {
constructor({ state = validState(), queryError } = {}) {
this.state = state;
this.queryError = queryError;
this.queryIndex = 0;
this.connected = false;
this.ended = false;
}
async connect() {
this.connected = true;
}
async query() {
if (this.queryError) {
throw this.queryError;
}
const rows = [this.state.session, this.state.roles, this.state.memberships][this.queryIndex++];
return { rows: Array.isArray(rows) ? rows : [rows] };
}
async end() {
this.ended = true;
}
}
describe("verify-migrator-role", () => {
it("requires DIRECT_URL", async () => {
await assert.rejects(verifyMigratorRole({ env: {} }), new RegExp(MIGRATOR_DATABASE_URL_ENV));
});
it("accepts only the exact non-superuser migrator contract", async () => {
const client = new FakeClient();
let output = "";
await verifyMigratorRole({
env: { [MIGRATOR_DATABASE_URL_ENV]: SECRET_URL },
clientFactory: () => client,
stdout: { write: (value) => (output += value) },
});
assert.equal(client.connected, true);
assert.equal(client.ended, true);
assert.equal(output, "PASS HiveGrid migrator role verified\n");
assert.doesNotMatch(output, /migrator-secret|db\.example\.test/);
});
it("rejects superuser, role switching, and membership drift", () => {
const superuser = validState();
superuser.roles[0].isSuperuser = true;
assert.throws(() => verifyMigratorRoleState(superuser), /non-superuser security contract/);
const switched = validState();
switched.session.sessionRole = "postgres";
assert.throws(() => verifyMigratorRoleState(switched), /authenticate directly as hivegrid_migrator/);
const extraMembership = validState();
extraMembership.memberships.push({ grantedRole: "admin", memberRole: "hivegrid_migrator" });
assert.throws(() => verifyMigratorRoleState(extraMembership), /unexpected PostgreSQL role membership/);
});
it("suppresses database errors and connection details", async () => {
const client = new FakeClient({ queryError: new Error(`database rejected ${SECRET_URL}`) });
let error;
try {
await verifyMigratorRole({
env: { [MIGRATOR_DATABASE_URL_ENV]: SECRET_URL },
clientFactory: () => client,
});
} catch (caught) {
error = caught;
}
assert.ok(error instanceof MigratorRoleVerificationError);
assert.match(error.message, /inspect restricted database logs/);
assert.doesNotMatch(error.message, /migrator-secret|db\.example\.test/);
assert.equal(client.ended, true);
});
});