From 26eec181a0349f1946e67ef1be027753442ebea8 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 17 Jul 2026 00:13:07 +0200 Subject: [PATCH] fix: isolate production migration database URL --- deploy/deploy.yaml | 7 +++++++ scripts/gitops-render.test.ts | 19 ++++++++++++++++++- .../src/gitops-render/runtime-manifests.mjs | 17 +++++++++++++++-- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/deploy/deploy.yaml b/deploy/deploy.yaml index 45fc0ae7..54e4477a 100644 --- a/deploy/deploy.yaml +++ b/deploy/deploy.yaml @@ -993,6 +993,13 @@ lanes: nodePort: 32010 frp: enabled: false + externalPostgres: + enabled: true + serviceName: nc01-host-postgres + endpointAddress: 10.42.0.1 + port: 5432 + migrationSecretName: hwlab-cloud-api-production-db + migrationSecretKey: migration-database-url envReuseServices: *v03EnvReuseServices bootScripts: *v03BootScripts serviceDeclarations: *v03ServiceDeclarations diff --git a/scripts/gitops-render.test.ts b/scripts/gitops-render.test.ts index fbbfc321..aaa5372d 100644 --- a/scripts/gitops-render.test.ts +++ b/scripts/gitops-render.test.ts @@ -8,10 +8,27 @@ import test from "node:test"; import { parse as parseYaml } from "yaml"; import { configString } from "./src/gitops-render/core.mjs"; -import { opencodeEgressProxyUrlForProfile } from "./src/gitops-render/runtime-manifests.mjs"; +import { externalPostgresConfigForLane, externalPostgresManifest, opencodeEgressProxyUrlForProfile } from "./src/gitops-render/runtime-manifests.mjs"; import { CLOUD_CORE_MIGRATIONS, CLOUD_TRANSACTIONAL_REALTIME_MIGRATION_ID } from "../internal/db/schema.ts"; +test("production migration uses its YAML-declared database Secret key", async () => { + const deploy = parseYaml(await readFile("deploy/deploy.yaml", "utf8")); + const config = externalPostgresConfigForLane(deploy, "production", { nodeId: "NC01" }); + const manifest = externalPostgresManifest({ + profile: "production", + config, + source: { full: "a".repeat(40), short: "a".repeat(12), imageTag: "a".repeat(12) }, + deploy, + migrationSources: [{ path: "0001_test.sql", sql: "select 1;" }] + }); + const job = manifest.items.find((item) => item.kind === "Job"); + assert.deepEqual(job?.spec?.template?.spec?.containers?.[0]?.env?.[0]?.valueFrom?.secretKeyRef, { + name: "hwlab-cloud-api-production-db", + key: "migration-database-url" + }); +}); + function taskByName(pipeline, name) { const task = pipeline.spec.tasks.find((item) => item.name === name); assert.ok(task, `missing task ${name}`); diff --git a/scripts/src/gitops-render/runtime-manifests.mjs b/scripts/src/gitops-render/runtime-manifests.mjs index 21784ec0..738542d0 100644 --- a/scripts/src/gitops-render/runtime-manifests.mjs +++ b/scripts/src/gitops-render/runtime-manifests.mjs @@ -737,7 +737,15 @@ function externalPostgresConfigForLane(deploy, profile, args = {}) { assert.ok(typeof effective.endpointAddress === "string" && effective.endpointAddress.length > 0, `deploy.lanes.${profile}.externalPostgres.endpointAddress is required`); const port = Number(effective.port ?? 5432); assert.ok(Number.isInteger(port) && port > 0 && port <= 65535, `deploy.lanes.${profile}.externalPostgres.port must be a valid TCP port`); - return { serviceName: effective.serviceName, endpointAddress: effective.endpointAddress, port }; + const migrationSecretName = effective.migrationSecretName; + const migrationSecretKey = effective.migrationSecretKey; + assert.equal(typeof migrationSecretName === "string", typeof migrationSecretKey === "string", `deploy.lanes.${profile}.externalPostgres migration Secret name and key must be declared together`); + return { + serviceName: effective.serviceName, + endpointAddress: effective.endpointAddress, + port, + ...(typeof migrationSecretName === "string" ? { migrationSecretName, migrationSecretKey } : {}) + }; } function externalPostgresManifest({ profile = "v03", config, source, deploy = null, migrationSources = [], catalog = null, registryPrefix = defaultRegistryPrefix, useDeployImages = false }) { @@ -816,7 +824,12 @@ function externalPostgresManifest({ profile = "v03", config, source, deploy = nu command: ["node", "/opt/hwlab-migrations/run.mjs"], env: [{ name: "DATABASE_URL", - valueFrom: { secretKeyRef: { name: `hwlab-cloud-api-${profile}-db`, key: "database-url" } } + valueFrom: { + secretKeyRef: { + name: config.migrationSecretName ?? `hwlab-cloud-api-${profile}-db`, + key: config.migrationSecretKey ?? "database-url" + } + } }], volumeMounts: [{ name: "migrations", mountPath: "/opt/hwlab-migrations", readOnly: true }] }],