chore(db): harden workspace env wrappers

This commit is contained in:
2026-03-31 22:47:07 +02:00
parent 5097ceab7e
commit 3e8b1702bc
6 changed files with 72 additions and 14 deletions
+33 -1
View File
@@ -1,7 +1,7 @@
import assert from "node:assert/strict";
import test from "node:test";
import { assertDestructiveDbAllowed } from "./destructive-db-guard.js";
import { assertSafeSeedTarget } from "./safe-destructive-env.js";
import { assertCapaKrakenDbTarget, assertSafeSeedTarget } from "./safe-destructive-env.js";
const ORIGINAL_ENV = { ...process.env };
@@ -98,3 +98,35 @@ test("assertSafeSeedTarget rejects unexpected legacy disposable databases", () =
/not in the destructive-tool allowlist/u,
);
});
test("assertCapaKrakenDbTarget accepts non-destructive capakraken targets", () => {
setEnv({
DATABASE_URL: "postgresql://tester:secret@localhost:5432/capakraken_dev",
});
const target = assertCapaKrakenDbTarget("db:seed:holidays");
assert.equal(target.databaseName, "capakraken_dev");
});
test("assertCapaKrakenDbTarget rejects legacy non-capakraken targets", () => {
setEnv({
DATABASE_URL: "postgresql://tester:secret@localhost:5432/legacy_non_capakraken",
});
assert.throws(
() => assertCapaKrakenDbTarget("db:seed:holidays"),
/not a valid CapaKraken target/u,
);
});
test("assertCapaKrakenDbTarget explains missing env loading clearly", () => {
setEnv({
DATABASE_URL: undefined,
});
assert.throws(
() => assertCapaKrakenDbTarget("db:update:blueprints"),
/Run the command through the CapaKraken env wrappers/u,
);
});
+2 -2
View File
@@ -8,7 +8,7 @@ interface DestructiveGuardOptions {
const PROTECTED_DATABASE_NAMES = new Set(["capakraken"]);
function parseDatabaseUrl(rawUrl: string) {
export function parseDatabaseUrl(rawUrl: string) {
const parsed = new URL(rawUrl);
const databaseName = parsed.pathname.replace(/^\/+/, "");
@@ -21,7 +21,7 @@ function parseDatabaseUrl(rawUrl: string) {
};
}
function formatTarget(target: ReturnType<typeof parseDatabaseUrl>) {
export function formatTarget(target: ReturnType<typeof parseDatabaseUrl>) {
const port = target.port ? `:${target.port}` : "";
return `${target.protocol}//${target.username}@${target.hostname}${port}/${target.databaseName}`;
}
+21 -1
View File
@@ -1,4 +1,4 @@
import { assertDestructiveDbAllowed } from "./destructive-db-guard.js";
import { assertDestructiveDbAllowed, formatTarget, parseDatabaseUrl } from "./destructive-db-guard.js";
const TEST_DATABASE_NAMES = [
"capakraken_test",
@@ -12,3 +12,23 @@ export function assertSafeSeedTarget(commandName: string) {
allowedDatabaseNames: TEST_DATABASE_NAMES,
});
}
export function assertCapaKrakenDbTarget(commandName: string) {
const rawUrl = process.env.DATABASE_URL;
if (!rawUrl) {
throw new Error(
`${commandName} aborted: DATABASE_URL is not configured. Run the command through the CapaKraken env wrappers so the workspace env files are loaded.`,
);
}
const target = parseDatabaseUrl(rawUrl);
if (!target.databaseName.startsWith("capakraken")) {
throw new Error(
`${commandName} aborted: database '${target.databaseName}' is not a valid CapaKraken target. Target=${formatTarget(target)}`,
);
}
return target;
}