@@ -14,8 +14,9 @@ import { readFileSync, existsSync } from "fs";
1414
1515import { Client } from "pg" ;
1616
17- import { base64Encode } from "./helper" ;
17+ import { base64Encode , getReleaseName , resolveInstallMethod } from "./helper" ;
1818import { KubeClient , BACKSTAGE_BACKEND_CONTAINER } from "./kube-client" ;
19+ import { BACKSTAGE_CR_API_VERSION } from "./runtime-config" ;
1920import type { AppConfigYaml } from "./runtime-config" ;
2021
2122/**
@@ -128,6 +129,15 @@ export async function configurePostgresCredentials(
128129 data,
129130 } ;
130131 await kubeClient . createOrUpdateSecret ( secret , namespace ) ;
132+
133+ // For operator installs, ensure the Backstage CR includes postgres-cred in
134+ // extraEnvs.secrets so the operator injects the credentials as env vars.
135+ // This is done here (not in prepareForExternalDatabase) because the secret
136+ // must contain real credentials before the operator reconciles — placeholder
137+ // values would break the DB connection and leave readiness at 503.
138+ if ( resolveInstallMethod ( ) === "operator" ) {
139+ await addPostgresCredToBackstageCR ( kubeClient , namespace ) ;
140+ }
131141}
132142
133143const SYSTEM_DATABASES = [
@@ -297,7 +307,11 @@ export async function prepareForExternalDatabase(
297307 // Schema-mode tests may have added individual secretKeyRef env vars pointing
298308 // to a *-postgresql secret. These override the bulk envFrom injection from
299309 // postgres-cred and must be removed before external DB tests.
300- await removeSchemaModePatchedEnvVars ( kubeClient , deploymentName , namespace ) ;
310+ // Skip for operator — the operator manages env vars via extraEnvs.secrets
311+ // in the Backstage CR, so there are no direct deployment patches to remove.
312+ if ( resolveInstallMethod ( ) !== "operator" ) {
313+ await removeSchemaModePatchedEnvVars ( kubeClient , deploymentName , namespace ) ;
314+ }
301315
302316 // --- 2. Patch app-config ConfigMap to use external DB connection ---
303317 console . log ( "Patching app-config to use external database connection (env var placeholders)..." ) ;
@@ -314,11 +328,20 @@ export async function prepareForExternalDatabase(
314328 } ) ;
315329 console . log ( "App-config patched for external database connection" ) ;
316330
317- // --- 3. Add POSTGRES_* env vars to the deployment via secretKeyRef ---
318- // The deployment starts with internal DB (no postgres-cred env vars).
319- // Add individual env vars pointing to the postgres-cred secret so the
320- // app-config ${POSTGRES_HOST} etc. placeholders resolve correctly.
321- await ensurePostgresCredEnvVars ( kubeClient , deploymentName , namespace ) ;
331+ // --- 3. Add POSTGRES_* env vars to the deployment ---
332+ // Helm: patch individual env vars pointing to the postgres-cred secret so
333+ // the app-config ${POSTGRES_HOST} etc. placeholders resolve correctly.
334+ // Operator: the Backstage CR is patched later by configurePostgresCredentials()
335+ // after real credentials are written to the postgres-cred secret. Patching the
336+ // CR here with placeholder values would trigger operator reconciliation and
337+ // break the DB connection (readiness 503).
338+ if ( resolveInstallMethod ( ) === "operator" ) {
339+ console . log (
340+ "Skipping env var setup (operator CR will be patched by configurePostgresCredentials)" ,
341+ ) ;
342+ } else {
343+ await ensurePostgresCredEnvVars ( kubeClient , deploymentName , namespace ) ;
344+ }
322345}
323346
324347/**
@@ -371,3 +394,49 @@ async function ensurePostgresCredEnvVars(
371394 ) ;
372395 console . log ( "POSTGRES_* env vars added to deployment from postgres-cred" ) ;
373396}
397+
398+ /**
399+ * Patch the operator Backstage CR to add postgres-cred to extraEnvs.secrets.
400+ * This causes the operator to inject all keys from the postgres-cred secret
401+ * as env vars into the RHDH container.
402+ *
403+ * The postgres-cred secret is NOT included in the CR at deployment time —
404+ * it contains placeholder values that would override the operator-managed
405+ * internal PostgreSQL credentials. It is only added here, when external DB
406+ * tests need the real credentials injected.
407+ *
408+ * Uses JSON merge-patch so the secrets array is replaced wholesale.
409+ * The CR is created by generateBackstageCR() with only rhdh-runtime-config
410+ * in extraEnvs.secrets, so we set both here explicitly.
411+ */
412+ async function addPostgresCredToBackstageCR (
413+ kubeClient : KubeClient ,
414+ namespace : string ,
415+ ) : Promise < void > {
416+ const releaseName = getReleaseName ( ) ;
417+ const [ group , version ] = BACKSTAGE_CR_API_VERSION . split ( "/" ) ;
418+
419+ const patch = {
420+ spec : {
421+ application : {
422+ extraEnvs : {
423+ secrets : [ { name : "rhdh-runtime-config" } , { name : "postgres-cred" } ] ,
424+ } ,
425+ } ,
426+ } ,
427+ } ;
428+
429+ await kubeClient . customObjectsApi . patchNamespacedCustomObject (
430+ group ,
431+ version ,
432+ namespace ,
433+ "backstages" ,
434+ releaseName ,
435+ patch ,
436+ undefined ,
437+ undefined ,
438+ undefined ,
439+ { headers : { "Content-Type" : "application/merge-patch+json" } } ,
440+ ) ;
441+ console . log ( "Patched Backstage CR: added postgres-cred to extraEnvs.secrets" ) ;
442+ }
0 commit comments