import { EventEmitter } from "node:events"; import assert from "node:assert/strict"; import { describe, it } from "vitest"; import { buildMigrateStatusCommand, formatMigrateStatusResult, redactSecrets, verifyDbMigrateStatus, } from "./verify-db-migrate-status.mjs"; function createSpawnStub({ exitCode = 0, stdout = "", stderr = "", error = null } = {}) { const calls = []; const spawnImpl = (command, args, options) => { calls.push({ command, args, options }); if (error?.throwSync) { throw error.value; } const child = new EventEmitter(); child.stdout = new EventEmitter(); child.stderr = new EventEmitter(); queueMicrotask(() => { if (stdout) { child.stdout.emit("data", Buffer.from(stdout)); } if (stderr) { child.stderr.emit("data", Buffer.from(stderr)); } if (error) { child.emit("error", error.value ?? error); } else { child.emit("close", exitCode); } }); return child; }; return { spawnImpl, calls }; } const SECRET_URL = "postgresql://ci_user:super-secret@db.example.test:5432/toolctrl"; describe("verify-db-migrate-status", () => { it("constructs the package-owned Prisma migrate status command", () => { const command = buildMigrateStatusCommand(); assert.equal(command.command, "pnpm"); assert.deepEqual(command.args, ["--filter", "@toolctrl/db", "prisma:migrate:status"]); assert.equal(command.display, "pnpm --filter @toolctrl/db prisma:migrate:status"); }); it("passes when Prisma migrate status exits successfully", async () => { const { spawnImpl, calls } = createSpawnStub({ stdout: "Database schema is up to date\n", exitCode: 0 }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL, PATH: "/bin" }, spawnImpl, cwd: "/repo", }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, true); assert.equal(result.phase, "prisma:migrate:status"); assert.equal(result.exitCode, 0); assert.equal(calls.length, 1); assert.equal(calls[0].command, "pnpm"); assert.deepEqual(calls[0].args, ["--filter", "@toolctrl/db", "prisma:migrate:status"]); assert.equal(calls[0].options.cwd, "/repo"); assert.equal(calls[0].options.env.CI, "1"); assert.equal(calls[0].options.env.DATABASE_URL, SECRET_URL); assert.match(output, /^PASS database migrate status verification/); assert.match(output, /phase: prisma:migrate:status/); assert.match(output, /command: pnpm --filter @toolctrl\/db prisma:migrate:status/); assert.match(output, /exitCode: 0/); }); it("fails before spawning when DATABASE_URL is missing", async () => { const { spawnImpl, calls } = createSpawnStub(); const result = await verifyDbMigrateStatus({ env: { PATH: "/bin" }, spawnImpl }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, false); assert.equal(result.phase, "preflight"); assert.equal(calls.length, 0); assert.match(output, /^FAIL database migrate status verification/); assert.match(output, /status: missing DATABASE_URL/); assert.match(output, /DATABASE_URL is required/); }); it("fails with sanitized output when Prisma migrate status exits non-zero", async () => { const { spawnImpl } = createSpawnStub({ exitCode: 1, stdout: `Connecting with DATABASE_URL=${SECRET_URL}\n`, stderr: `Migration failed for ${SECRET_URL}\n`, }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL }, spawnImpl }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, false); assert.equal(result.exitCode, 1); assert.equal(result.status, "prisma migrate status failed"); assert.match(output, /^FAIL database migrate status verification/); assert.match(output, /exitCode: 1/); assert.doesNotMatch(output, /super-secret/); assert.doesNotMatch(output, new RegExp(SECRET_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))); assert.match(output, //); }); it("passes unreachable database failures only when explicitly allowed", async () => { const { spawnImpl } = createSpawnStub({ exitCode: 1, stderr: "Error: P1001: Can't reach database server at `db.internal:5432`\n", }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL, DB_MIGRATE_STATUS_ALLOW_UNREACHABLE: "1", }, spawnImpl, }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, true); assert.equal(result.exitCode, 1); assert.equal(result.status, "database unreachable; skipped by DB_MIGRATE_STATUS_ALLOW_UNREACHABLE"); assert.match(output, /^PASS database migrate status verification/); }); it("still fails unreachable database errors without the explicit allow flag", async () => { const { spawnImpl } = createSpawnStub({ exitCode: 1, stderr: "Error: P1001: Can't reach database server at `db.internal:5432`\n", }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL }, spawnImpl }); assert.equal(result.ok, false); assert.equal(result.status, "prisma migrate status failed"); }); it("fails with spawn diagnostics when command execution errors", async () => { const { spawnImpl } = createSpawnStub({ error: { value: new Error(`spawn failed for ${SECRET_URL}`) } }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL }, spawnImpl }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, false); assert.equal(result.phase, "spawn"); assert.equal(result.exitCode, null); assert.match(output, /status: spawn error/); assert.match(output, /error: spawn failed for /); assert.doesNotMatch(output, /super-secret/); }); it("redacts literal DATABASE_URL values and generic URL credentials", () => { const output = redactSecrets( `DATABASE_URL=${SECRET_URL}\njson={"DATABASE_URL":"${SECRET_URL}"}\nother=mysql://user:password@localhost:3306/app`, { DATABASE_URL: SECRET_URL }, ); assert.doesNotMatch(output, /super-secret/); assert.doesNotMatch(output, /password/); assert.doesNotMatch(output, /ci_user/); assert.match(output, /DATABASE_URL=/); assert.match(output, /mysql:\/\/@localhost/); }); it("captures synchronous spawn failures as sanitized failures", async () => { const { spawnImpl } = createSpawnStub({ error: { throwSync: true, value: new Error(`ENOENT ${SECRET_URL}`) } }); const result = await verifyDbMigrateStatus({ env: { DATABASE_URL: SECRET_URL }, spawnImpl }); const output = formatMigrateStatusResult(result); assert.equal(result.ok, false); assert.equal(result.phase, "spawn"); assert.match(output, /ENOENT /); assert.doesNotMatch(output, /super-secret/); }); });