#!/usr/bin/env tsx import "dotenv/config"; import { randomUUID } from "node:crypto"; import { writeFile } from "node:fs/promises"; import { createPrismaPlatformLeadService } from "@hivegrid/db/platform-leads-admin.server"; import { disconnectDbClients, getDbClient } from "@hivegrid/db/client.server"; import { runWithRlsContext } from "@hivegrid/db/rls-context.server"; import { closeSharedStores } from "../../apps/web/app/shared-store.server.js"; import { userHasPermission } from "../../apps/web/app/utils/db/permissions/userRoles.db.server.js"; import { isSuccessfulPlatformLeadSourceBootstrapManifest, PlatformLeadSourceBootstrapError, runPlatformLeadSourceBootstrap, type PlatformLeadSourceBootstrapMode, } from "./source-bootstrap.js"; export type PlatformLeadSourceBootstrapCliOptions = { mode: PlatformLeadSourceBootstrapMode; actorAdminUserId: string; routingAdminUserId: string; manifestPath: string; runId: string; expectedPlanSha256?: string; }; export function parsePlatformLeadSourceBootstrapCliArgs(argv: readonly string[]): PlatformLeadSourceBootstrapCliOptions { const values = parseNamedArguments(argv); const allowed = new Set(["mode", "actor-admin-user-id", "routing-admin-user-id", "manifest", "run-id", "expected-plan-sha256"]); if ([...values.keys()].some((key) => !allowed.has(key))) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); const modeValue = required(values.get("mode")); if (modeValue !== "dry-run" && modeValue !== "apply") throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); const options: PlatformLeadSourceBootstrapCliOptions = { mode: modeValue, actorAdminUserId: identifier(values.get("actor-admin-user-id")), routingAdminUserId: identifier(values.get("routing-admin-user-id")), manifestPath: required(values.get("manifest")), runId: values.get("run-id")?.trim() || randomUUID(), }; if (!/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,190}$/u.test(options.runId)) { throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); } if (modeValue === "apply") { const expected = required(values.get("expected-plan-sha256")).toLowerCase(); if (!/^[a-f0-9]{64}$/u.test(expected)) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); options.expectedPlanSha256 = expected; } else if (values.has("expected-plan-sha256")) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); return options; } export async function runPlatformLeadSourceBootstrapCli(argv: readonly string[] = process.argv.slice(2)): Promise { let options: PlatformLeadSourceBootstrapCliOptions; try { options = parsePlatformLeadSourceBootstrapCliArgs(argv); } catch (error) { writeSafeError(error); return 1; } try { const manifest = await runWithRlsContext({ userId: options.actorAdminUserId }, async () => { if (!(await userHasPermission(options.actorAdminUserId, null, "admin.leads.admin"))) { throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); } const [canReadOwn, canWrite] = await Promise.all([ userHasPermission(options.routingAdminUserId, null, "admin.leads.read_own"), userHasPermission(options.routingAdminUserId, null, "admin.leads.write"), ]); if (!canReadOwn || !canWrite) { throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); } const db = getDbClient(); const routingOperator = await db.adminUser.findUnique({ where: { userId: options.routingAdminUserId }, select: { user: { select: { active: true, pendingDeletion: true, pseudonymized: true } } }, }); if ( !routingOperator?.user.active || routingOperator.user.pendingDeletion || routingOperator.user.pseudonymized ) { throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); } const service = createPrismaPlatformLeadService(); const existingSources = await service.listSources(); return runPlatformLeadSourceBootstrap({ mode: options.mode, runId: options.runId, actorAdminUserId: options.actorAdminUserId, routingAdminUserId: options.routingAdminUserId, existingSources, expectedPlanSha256: options.expectedPlanSha256, service, }); }); const serialized = `${JSON.stringify(manifest, null, 2)}\n`; await writeFile(options.manifestPath, serialized, { encoding: "utf8", flag: "wx", mode: 0o600 }); process.stdout.write(serialized); return isSuccessfulPlatformLeadSourceBootstrapManifest(manifest) ? 0 : 2; } catch (error) { writeSafeError(error); return 1; } finally { await Promise.allSettled([closeSharedStores(), disconnectDbClients()]); } } function parseNamedArguments(argv: readonly string[]): Map { const values = new Map(); for (let index = 0; index < argv.length; index += 1) { const argument = argv[index]!; if (argument === "--" && index === 0) continue; if (!argument.startsWith("--")) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); const equalsIndex = argument.indexOf("="); const key = argument.slice(2, equalsIndex === -1 ? undefined : equalsIndex); const value = equalsIndex === -1 ? argv[++index] : argument.slice(equalsIndex + 1); if (!key || !value || value.startsWith("--") || values.has(key)) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); values.set(key, value); } return values; } function required(value: string | undefined): string { const normalized = value?.trim(); if (!normalized || /[\u0000-\u001f\u007f]/u.test(normalized)) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); return normalized; } function identifier(value: string | undefined): string { const normalized = required(value); if (normalized.length > 191 || !/^[A-Za-z0-9_-]+$/u.test(normalized)) throw new PlatformLeadSourceBootstrapError("INVALID_CONFIGURATION"); return normalized; } function writeSafeError(error: unknown): void { const code = error instanceof PlatformLeadSourceBootstrapError ? error.code : "OPERATION_FAILED"; process.stderr.write(`${JSON.stringify({ ok: false, code })}\n`); } if (import.meta.url === `file://${process.argv[1]}`) { runPlatformLeadSourceBootstrapCli() .then((exitCode) => { process.exitCode = exitCode; }) .catch(() => { process.exitCode = 1; }); }