Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/scripts/rls-live-migration-chain-mode.test.mjs
T

85 lines
4.4 KiB
JavaScript

import { readFile } from "node:fs/promises";
import { spawnSync } from "node:child_process";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
const root = process.cwd();
const liveGatePath = join(root, "scripts/verify-rls-live.sh");
describe("verify:rls-live migration-chain mode", () => {
it("probes fresh schema and exact portal policies before any feature-branch overlay", async () => {
const liveGate = await readFile(liveGatePath, "utf8");
const schemaProbe = liveGate.indexOf("pnpm exec prisma migrate diff");
const policyProbe = liveGate.indexOf("pnpm exec tsx scripts/verify-portal-migration-chain-policy-state.ts");
const dbPush = liveGate.indexOf("pnpm exec prisma db push --accept-data-loss");
const actorOverlay = liveGate.indexOf("< prisma/rls/portal-actor-invariants.sql");
const tenantOverlay = liveGate.indexOf("< prisma/rls/tenant-policy-contract-isolation.sql");
const portalOverlay = liveGate.indexOf("< prisma/rls/portal-policy-contract-isolation.sql");
const domainOverlay = liveGate.indexOf("< prisma/rls/portal-domain-capabilities.sql");
expect(schemaProbe).toBeGreaterThan(-1);
expect(liveGate).toContain("--from-config-datasource");
expect(liveGate).toContain("--to-schema prisma/schema");
expect(liveGate).toContain("--exit-code");
expect(policyProbe).toBeGreaterThan(schemaProbe);
expect(dbPush).toBeGreaterThan(policyProbe);
expect(tenantOverlay).toBeGreaterThan(dbPush);
expect(actorOverlay).toBeGreaterThan(tenantOverlay);
expect(portalOverlay).toBeGreaterThan(actorOverlay);
expect(domainOverlay).toBeGreaterThan(portalOverlay);
expect(liveGate).toContain("packages/db/src/portal-p26b-rls-live.integration.test.ts");
expect(liveGate).toContain("packages/db/src/portal-domain-capabilities.rls.integration.test.ts");
});
it("fails strict mode closed and gates every mutation behind the feature-branch overlay flag", async () => {
const liveGate = await readFile(liveGatePath, "utf8");
expect(liveGate).toContain('elif [[ "$REQUIRE_MIGRATION_CHAIN_PARITY" == "1" ]]; then');
expect(liveGate).toContain("strict mode never runs db push or a policy overlay");
expect(liveGate.match(/if \[\[ "\$USE_FEATURE_BRANCH_OVERLAY" == "1" \]\]; then/g)).toHaveLength(2);
expect(liveGate).toContain(
"MODE migration-chain: fresh migrations provide the current schema and exact portal policy contract; db push and manual policy overlays are disabled"
);
expect(liveGate).toContain("MODE feature-branch-overlay: migration-chain parity is not available yet");
});
it("rejects invalid strict-mode values before starting Docker", () => {
const result = spawnSync("bash", [liveGatePath], {
cwd: root,
encoding: "utf8",
env: {
...process.env,
HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY: "yes",
},
});
expect(result.status).toBe(1);
expect(result.stderr).toContain("HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY must be exactly 0 or 1");
expect(result.stdout).not.toContain("PHASE 1/8");
});
it("keeps all CI and exact-revision deploy callers in strict mode", async () => {
const workflowPaths = [".gitea/workflows/ci.yml", ".gitea/workflows/deploy.yml"];
for (const workflowPath of workflowPaths) {
const workflow = await readFile(join(root, workflowPath), "utf8");
const liveStepStart = workflow.indexOf("run: pnpm run verify:rls-live");
const nextStepStart = workflow.indexOf("\n - name:", liveStepStart + 1);
const liveStep = workflow.slice(liveStepStart, nextStepStart === -1 ? workflow.length : nextStepStart);
expect(liveStepStart, workflowPath).toBeGreaterThan(-1);
expect(liveStep, workflowPath).toContain('HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY: "1"');
}
});
it("uses the canonical exact portal runtime-readiness contract for policy parity", async () => {
const verifier = await readFile(join(root, "scripts/verify-portal-migration-chain-policy-state.ts"), "utf8");
expect(verifier).toContain('from "@hivegrid/db/portal-rls-runtime-readiness.server"');
expect(verifier).toContain("verifyPortalRlsRuntimeReadiness([client]");
expect(verifier).toContain('RLS_RUNTIME_MODE: "required"');
expect(verifier).toContain('"../prisma/rls/tenant-policy-contract-isolation.sql"');
expect(verifier).toContain("verifyPortalAppWorkerPolicyParity(");
expect(verifier).toContain("disconnectDbClients");
});
});