feat: prepare 2.6.1-rc5 shared databases and build SSE

This commit is contained in:
2026-10-05 11:09:52 +00:00 Unverified
parent f76165603e
commit 828bf3a328
25 changed files with 2557 additions and 196 deletions
+158 -3
View File
@@ -8,6 +8,7 @@ import {
getServicePostgresClaim,
isPostgresVolumeEntry,
reconcilePostgresClaim,
reconcilePostgresClaims,
} from "../../lib/database";
import { objectApi } from "../../lib/k8s";
@@ -127,6 +128,7 @@ describe("managed PostgreSQL claims", () => {
secretName: "postgres-app",
};
spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database") throw { code: 404 };
if (resource.kind === "Secret") {
return {
...resource,
@@ -141,6 +143,7 @@ describe("managed PostgreSQL claims", () => {
const patch = spyOn(objectApi, "patch").mockImplementation(
async (resource) => resource as never,
);
const create = spyOn(objectApi, "create").mockImplementation(async (resource) => resource as never);
expect(await reconcilePostgresClaim("project", claim)).toEqual({
username: "app",
@@ -149,8 +152,8 @@ describe("managed PostgreSQL claims", () => {
expect(patch.mock.calls.map(([resource]) => resource.kind)).toEqual([
"Secret",
"Cluster",
"Database",
]);
expect(create.mock.calls.map(([resource]) => resource.kind)).toEqual(["Database"]);
});
test("reports database apply phase and claim without exposing provider credentials", async () => {
@@ -161,12 +164,14 @@ describe("managed PostgreSQL claims", () => {
secretName: "postgres-app_role",
};
spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database") throw { code: 404 };
if (resource.kind === "Secret") {
return { ...resource, data: { password: Buffer.from("private-value").toString("base64") } } as never;
}
return { ...resource, spec: { managed: { roles: [] } } } as never;
});
spyOn(objectApi, "patch").mockImplementation(async (resource) => {
spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
spyOn(objectApi, "create").mockImplementation(async (resource) => {
if (resource.kind === "Database") {
throw Object.assign(new Error("Forbidden: password=private-value"), { code: 403 });
}
@@ -180,11 +185,78 @@ describe("managed PostgreSQL claims", () => {
}
expect(failure).toBeInstanceOf(DatabaseReconciliationError);
expect((failure as Error).message).toBe(
"Database reconciliation failed during database apply for database app_db (service app, role app_role): Forbidden (HTTP 403)",
"Database reconciliation failed during database apply for requested database claim: Forbidden (HTTP 403)",
);
expect((failure as Error).message).not.toContain("private-value");
});
test.each(["read", "patch"])("distinguishes role secret %s failure", async (method) => {
const secretLike = "DB_PASSWORD_private123";
spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database") throw { code: 404 };
if (method === "read") throw new Error(`token=${secretLike}`);
return undefined as never;
});
spyOn(objectApi, "patch").mockImplementation(async () => {
throw new Error(`token=${secretLike}`);
});
let failure: unknown;
try {
await reconcilePostgresClaim("project", {
service: secretLike, username: secretLike, database: secretLike, secretName: `postgres-${secretLike}`,
});
} catch (error) { failure = error; }
expect(failure).toBeInstanceOf(DatabaseReconciliationError);
expect((failure as DatabaseReconciliationError).phase).toBe(`role secret ${method === "read" ? "lookup" : "apply"}`);
expect((failure as Error).message).not.toContain(secretLike);
});
test("uses safe provider status and reason without exposing request bodies or unsafe claim identifiers", () => {
const cause = Object.assign(new Error("request body DATABASE_URL=postgresql://admin:[email protected]/app"), {
statusCode: 422,
body: { reason: "Invalid", code: 422, message: "token=private" },
});
const failure = new DatabaseReconciliationError("managed role update", cause, {
service: "web", database: "postgresql://admin:[email protected]/app", username: "web_role", secretName: "secret",
});
expect(failure.message).toBe(
"Database reconciliation failed during managed role update for requested database claim: Invalid (HTTP 422)",
);
expect(failure.cause).toBe(cause);
expect(failure.message).not.toContain("private");
});
test("rejects an unrecognized phase containing a syntactically valid secret-like name", () => {
const failure = new DatabaseReconciliationError("DB_PASSWORD_private123", new Error("private"));
expect(failure.phase).toBe("operation execution");
expect(failure.message).not.toContain("DB_PASSWORD_private123");
});
test("identifies failure while preparing malformed managed roles before a Cluster write", async () => {
spyOn(objectApi, "read").mockImplementation(async (resource) => resource.kind === "Secret"
? { ...resource, data: { password: Buffer.from("private").toString("base64") } } as never
: resource.kind === "Database" ? Promise.reject({ code: 404 }) : { ...resource, spec: { managed: { roles: {} } } } as never);
const patch = spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
let failure: unknown;
try {
await reconcilePostgresClaim("project", {
service: "DB_PASSWORD_private123", username: "role", database: "db", secretName: "postgres-role",
});
} catch (error) { failure = error; }
expect(failure).toBeInstanceOf(DatabaseReconciliationError);
expect((failure as DatabaseReconciliationError).phase).toBe("managed role preparation");
expect((failure as Error).message).not.toContain("DB_PASSWORD_private123");
expect(patch.mock.calls.map(([resource]) => resource.kind)).toEqual(["Secret"]);
});
test("reports malformed claims as claim discovery failures without echoing compose input", async () => {
await expect(reconcilePostgresClaims("project", {
services: { web: { volumes: ["postgresql:user:password=private"] } },
} as ComposeSpecification)).rejects.toThrow(
"Database reconciliation failed during claim discovery: Check PostgreSQL claim declarations",
);
});
test("reconciles a CNPG cluster returned with managed fields without sending them back", async () => {
const claim = {
service: "app",
@@ -193,6 +265,7 @@ describe("managed PostgreSQL claims", () => {
secretName: "postgres-app",
};
spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database") throw { code: 404 };
if (resource.kind === "Secret") {
return {
...resource,
@@ -223,6 +296,7 @@ describe("managed PostgreSQL claims", () => {
return resource as never;
},
);
spyOn(objectApi, "create").mockImplementation(async (resource) => resource as never);
await reconcilePostgresClaim("project", claim);
@@ -239,4 +313,85 @@ describe("managed PostgreSQL claims", () => {
expect(cluster?.metadata).not.toHaveProperty("resourceVersion");
expect(cluster).not.toHaveProperty("status");
});
test("two projects reuse a foreign database without applying its metadata", async () => {
const claim = { service: "web", username: "sastify", database: "sastify-store", secretName: "postgres-sastify" };
const live = {
apiVersion: "postgresql.cnpg.io/v1", kind: "Database",
metadata: { name: claim.database, namespace: "database", labels: {
"kuber.dev/project": "sastify-api", "kuber.dev/workspace-uid": "foreign-uid",
} },
spec: { owner: claim.username, cluster: { name: "postgres" } },
};
const original = structuredClone(live);
spyOn(objectApi, "read").mockImplementation(async (resource) => resource.kind === "Database"
? live as never
: resource.kind === "Secret"
? { ...resource, data: { password: Buffer.from("shared-password").toString("base64") } } as never
: { ...resource, spec: { managed: { roles: [] } } } as never);
const patch = spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
const create = spyOn(objectApi, "create").mockImplementation(async (resource) => resource as never);
const compose = { services: { web: { volumes: ["postgresql:sastify/sastify-store"] } } } as ComposeSpecification;
for (const project of ["sastify-api", "another-project"]) {
const env = await reconcilePostgresClaims(project, compose);
expect(env.web?.DATABASE_URL).toBe("postgresql://sastify:[email protected]:5432/sastify-store");
}
expect(live).toEqual(original);
expect(patch.mock.calls.map(([resource]) => resource.kind)).toEqual(["Secret", "Cluster", "Secret", "Cluster"]);
expect(create).not.toHaveBeenCalled();
});
test("validates all databases in a compose file before writing the first role", async () => {
const read = spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database" && resource.metadata?.name === "first") throw { code: 404 };
if (resource.kind === "Database") return { ...resource, spec: {
owner: "another-role", cluster: { name: "postgres" },
} } as never;
throw new Error("Role lookup must not run");
});
const patch = spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
const create = spyOn(objectApi, "create").mockImplementation(async (resource) => resource as never);
await expect(reconcilePostgresClaims("project", { services: {
first: { volumes: ["postgresql:first"] },
second: { volumes: ["postgresql:second"] },
} } as ComposeSpecification)).rejects.toMatchObject({ phase: "database ownership" });
expect(read.mock.calls.map(([resource]) => resource.kind)).toEqual(["Database", "Database"]);
expect(patch).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
test.each([
["wrong role", "other", "postgres"],
["wrong cluster", "sastify", "other"],
])("rejects existing database with %s before any writes", async (_case, owner, cluster) => {
const claim = { service: "web", username: "sastify", database: "sastify-store", secretName: "postgres-sastify" };
spyOn(objectApi, "read").mockImplementation(async (resource) => resource.kind === "Database"
? { ...resource, spec: { owner, cluster: { name: cluster } } } as never
: undefined as never);
const patch = spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
const create = spyOn(objectApi, "create").mockImplementation(async (resource) => resource as never);
await expect(reconcilePostgresClaim("project", claim)).rejects.toMatchObject({ phase: "database ownership" });
expect(patch).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
test("creates missing databases only once and fails closed on create races", async () => {
spyOn(objectApi, "read").mockImplementation(async (resource) => {
if (resource.kind === "Database") throw { code: 404 };
return { ...resource, spec: { managed: { roles: [] } } } as never;
});
spyOn(objectApi, "patch").mockImplementation(async (resource) => resource as never);
const create = spyOn(objectApi, "create").mockImplementation(async () => {
throw Object.assign(new Error("Conflict"), { code: 409 });
});
await expect(reconcilePostgresClaims("project", { services: {
web: { volumes: ["postgresql:sastify/sastify-store"] },
worker: { volumes: ["postgresql:sastify/sastify-store"] },
} } as ComposeSpecification)).rejects.toMatchObject({ phase: "database apply" });
expect(create).toHaveBeenCalledTimes(1);
expect(create.mock.calls[0]?.[0]).toMatchObject({
metadata: { name: "sastify-store", labels: { "kuber.dev/project": "project" } },
spec: { owner: "sastify", cluster: { name: "postgres" } },
});
});
});