@aifabrix/builder 2.43.0 → 2.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/.cursor/rules/cli-layout.mdc +75 -0
  3. package/.cursor/rules/project-rules.mdc +8 -0
  4. package/.npmrc.token +1 -0
  5. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  6. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  7. package/.nyc_output/processinfo/index.json +1 -0
  8. package/README.md +1 -1
  9. package/anchor-docs/README.md +10 -0
  10. package/anchor-docs/_TEMPLATE +24 -0
  11. package/bin/aifabrix.js +13 -4
  12. package/integration/hubspot-test/README.md +31 -0
  13. package/integration/hubspot-test/create-hubspot.js +5 -5
  14. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  15. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  16. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  17. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  18. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  19. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  20. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  21. package/integration/hubspot-test/test.js +35 -43
  22. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  23. package/integration/roundtrip-test-local/README.md +144 -0
  24. package/integration/roundtrip-test-local/application.yaml +13 -0
  25. package/integration/roundtrip-test-local/env.template +15 -0
  26. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  27. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  28. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  29. package/integration/roundtrip-test-local2/README.md +144 -0
  30. package/integration/roundtrip-test-local2/application.yaml +13 -0
  31. package/integration/roundtrip-test-local2/env.template +15 -0
  32. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  33. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  34. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  35. package/integration/test/wizard.yaml +8 -0
  36. package/jest.config.default.js +10 -0
  37. package/jest.config.integration.fixtures.js +22 -0
  38. package/jest.config.integration.js +21 -18
  39. package/jest.config.isolated.js +10 -0
  40. package/jest.projects.js +301 -0
  41. package/lib/api/certificates.api.js +62 -0
  42. package/lib/api/datasources-core.api.js +3 -3
  43. package/lib/api/dev-mtls-request.js +110 -0
  44. package/lib/api/dev-server-https.js +145 -0
  45. package/lib/api/dev.api.js +133 -144
  46. package/lib/api/index.js +11 -3
  47. package/lib/api/pipeline.api.js +67 -20
  48. package/lib/api/types/certificates.types.js +48 -0
  49. package/lib/api/types/dev.types.js +4 -3
  50. package/lib/api/types/pipeline.types.js +8 -5
  51. package/lib/api/types/validation-run.types.js +56 -0
  52. package/lib/api/validation-run.api.js +111 -0
  53. package/lib/api/validation-runner.js +109 -0
  54. package/lib/app/certification-show-enrich.js +129 -0
  55. package/lib/app/certification-verify-rows.js +60 -0
  56. package/lib/app/config.js +1 -1
  57. package/lib/app/deploy-status-display.js +2 -2
  58. package/lib/app/deploy.js +7 -6
  59. package/lib/app/display.js +2 -1
  60. package/lib/app/dockerfile.js +3 -2
  61. package/lib/app/down.js +2 -1
  62. package/lib/app/helpers.js +6 -5
  63. package/lib/app/index.js +27 -8
  64. package/lib/app/list.js +7 -6
  65. package/lib/app/push.js +4 -3
  66. package/lib/app/register.js +16 -7
  67. package/lib/app/rotate-secret.js +14 -13
  68. package/lib/app/run-container-start.js +184 -0
  69. package/lib/app/run-docker-fallback.js +108 -0
  70. package/lib/app/run-env-compose.js +30 -42
  71. package/lib/app/run-helpers.js +49 -126
  72. package/lib/app/run-infra-requirements.js +30 -0
  73. package/lib/app/run-resolve-image.js +21 -0
  74. package/lib/app/run.js +74 -21
  75. package/lib/app/show-display.js +44 -1
  76. package/lib/app/show.js +93 -9
  77. package/lib/build/index.js +13 -10
  78. package/lib/certification/cli-cert-sync-skip.js +21 -0
  79. package/lib/certification/merge-certification-from-artifact.js +185 -0
  80. package/lib/certification/post-unified-cert-sync.js +33 -0
  81. package/lib/certification/sync-after-external-command.js +52 -0
  82. package/lib/certification/sync-system-certification.js +197 -0
  83. package/lib/cli/index.js +2 -0
  84. package/lib/cli/setup-app.help.js +67 -0
  85. package/lib/cli/setup-app.js +61 -121
  86. package/lib/cli/setup-app.test-commands.js +195 -0
  87. package/lib/cli/setup-auth.js +19 -5
  88. package/lib/cli/setup-credential-deployment.js +22 -8
  89. package/lib/cli/setup-dev-path-commands.js +124 -0
  90. package/lib/cli/setup-dev.js +170 -113
  91. package/lib/cli/setup-environment.js +7 -1
  92. package/lib/cli/setup-external-system.js +84 -23
  93. package/lib/cli/setup-infra.js +126 -47
  94. package/lib/cli/setup-parameters.js +32 -0
  95. package/lib/cli/setup-secrets.js +137 -18
  96. package/lib/cli/setup-service-user.js +1 -1
  97. package/lib/cli/setup-utility.js +54 -22
  98. package/lib/commands/app-down.js +5 -7
  99. package/lib/commands/app-install.js +14 -7
  100. package/lib/commands/app-logs.js +13 -10
  101. package/lib/commands/app-shell.js +4 -1
  102. package/lib/commands/app-test.js +25 -19
  103. package/lib/commands/app.js +32 -11
  104. package/lib/commands/auth-config.js +6 -6
  105. package/lib/commands/auth-status.js +4 -3
  106. package/lib/commands/credential-env.js +4 -3
  107. package/lib/commands/credential-list.js +5 -4
  108. package/lib/commands/credential-push.js +4 -3
  109. package/lib/commands/datasource-unified-test-cli.js +428 -0
  110. package/lib/commands/datasource-unified-test-cli.options.js +191 -0
  111. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
  112. package/lib/commands/datasource-validation-cli.js +143 -0
  113. package/lib/commands/datasource.js +125 -95
  114. package/lib/commands/deployment-list.js +6 -5
  115. package/lib/commands/dev-cli-handlers.js +122 -18
  116. package/lib/commands/dev-down.js +4 -3
  117. package/lib/commands/dev-init.js +231 -116
  118. package/lib/commands/dev-show-display.js +473 -0
  119. package/lib/commands/login-credentials.js +3 -2
  120. package/lib/commands/login-device.js +4 -3
  121. package/lib/commands/login.js +5 -4
  122. package/lib/commands/logout.js +8 -7
  123. package/lib/commands/parameters-validate.js +54 -0
  124. package/lib/commands/repair-datasource.js +314 -68
  125. package/lib/commands/repair-env-template.js +2 -2
  126. package/lib/commands/repair.js +21 -3
  127. package/lib/commands/secrets-list.js +23 -12
  128. package/lib/commands/secrets-remove-all.js +220 -0
  129. package/lib/commands/secrets-remove.js +21 -12
  130. package/lib/commands/secrets-set.js +21 -12
  131. package/lib/commands/secrets-validate.js +4 -4
  132. package/lib/commands/secure.js +10 -9
  133. package/lib/commands/service-user.js +26 -25
  134. package/lib/commands/test-e2e-external.js +27 -1
  135. package/lib/commands/up-common.js +3 -2
  136. package/lib/commands/up-dataplane.js +29 -16
  137. package/lib/commands/up-miso.js +19 -29
  138. package/lib/commands/upload.js +149 -39
  139. package/lib/commands/wizard-core-helpers.js +1 -1
  140. package/lib/commands/wizard-dataplane.js +4 -3
  141. package/lib/commands/wizard-helpers.js +3 -3
  142. package/lib/commands/wizard.js +2 -2
  143. package/lib/core/admin-secrets.js +14 -5
  144. package/lib/core/audit-logger.js +12 -4
  145. package/lib/core/config-attach-extensions.js +46 -0
  146. package/lib/core/config-runtime-paths.js +29 -0
  147. package/lib/core/config.js +55 -56
  148. package/lib/core/diff.js +3 -2
  149. package/lib/core/ensure-encryption-key.js +1 -1
  150. package/lib/core/secrets-ensure-infra.js +77 -0
  151. package/lib/core/secrets-ensure.js +120 -64
  152. package/lib/core/secrets-env-write.js +35 -7
  153. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  154. package/lib/core/secrets.js +200 -37
  155. package/lib/core/templates-env.js +4 -3
  156. package/lib/datasource/abac-validator.js +1 -10
  157. package/lib/datasource/deploy.js +75 -53
  158. package/lib/datasource/field-reference-validator.js +9 -6
  159. package/lib/datasource/integration-context.js +63 -0
  160. package/lib/datasource/list.js +8 -7
  161. package/lib/datasource/log-viewer.js +189 -67
  162. package/lib/datasource/resolve-app.js +4 -4
  163. package/lib/datasource/test-e2e.js +113 -146
  164. package/lib/datasource/test-integration.js +114 -122
  165. package/lib/datasource/unified-validation-run-body.js +68 -0
  166. package/lib/datasource/unified-validation-run-post.js +23 -0
  167. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  168. package/lib/datasource/unified-validation-run.js +93 -0
  169. package/lib/datasource/validate.js +157 -13
  170. package/lib/deployment/deployer.js +4 -3
  171. package/lib/deployment/environment.js +7 -6
  172. package/lib/deployment/push.js +17 -8
  173. package/lib/external-system/delete.js +4 -3
  174. package/lib/external-system/deploy.js +166 -53
  175. package/lib/external-system/download-helpers.js +1 -1
  176. package/lib/external-system/download.js +7 -6
  177. package/lib/external-system/generator.js +92 -6
  178. package/lib/external-system/integration-test-dispatch.js +26 -0
  179. package/lib/external-system/test-execution.js +5 -1
  180. package/lib/external-system/test-helpers.js +0 -4
  181. package/lib/external-system/test-system-level-helpers.js +110 -0
  182. package/lib/external-system/test-system-level.js +83 -44
  183. package/lib/external-system/test.js +59 -8
  184. package/lib/generator/builders.js +23 -11
  185. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  186. package/lib/generator/external.js +16 -4
  187. package/lib/generator/helpers.js +58 -3
  188. package/lib/generator/index.js +4 -0
  189. package/lib/generator/split-readme.js +12 -7
  190. package/lib/generator/split-variables.js +2 -1
  191. package/lib/generator/split.js +1 -1
  192. package/lib/generator/wizard-readme.js +3 -3
  193. package/lib/generator/wizard.js +8 -8
  194. package/lib/infrastructure/compose.js +70 -7
  195. package/lib/infrastructure/helpers-docker-check.js +67 -0
  196. package/lib/infrastructure/helpers.js +203 -42
  197. package/lib/infrastructure/index.js +31 -18
  198. package/lib/infrastructure/services.js +21 -67
  199. package/lib/internal/fs-real-sync.js +104 -0
  200. package/lib/internal/node-fs.js +98 -0
  201. package/lib/parameters/database-secret-values.js +173 -0
  202. package/lib/parameters/infra-kv-discovery.js +121 -0
  203. package/lib/parameters/infra-parameter-catalog.js +458 -0
  204. package/lib/parameters/infra-parameter-validate.js +64 -0
  205. package/lib/schema/application-schema.json +37 -17
  206. package/lib/schema/datasource-test-run.schema.json +493 -0
  207. package/lib/schema/deployment-rules.yaml +102 -63
  208. package/lib/schema/external-datasource.schema.json +1200 -442
  209. package/lib/schema/external-system.schema.json +203 -5
  210. package/lib/schema/flag-map-validation-run.json +31 -0
  211. package/lib/schema/infra-parameter.schema.json +106 -0
  212. package/lib/schema/infra.parameter.yaml +421 -0
  213. package/lib/schema/type/credential-auth-templates.json +40 -0
  214. package/lib/schema/type/document-storage.json +226 -0
  215. package/lib/schema/type/message-service.json +123 -0
  216. package/lib/schema/type/vector-store.json +88 -0
  217. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  218. package/lib/utils/api-error-handler.js +2 -2
  219. package/lib/utils/api.js +77 -17
  220. package/lib/utils/app-register-api.js +3 -2
  221. package/lib/utils/app-register-auth.js +1 -1
  222. package/lib/utils/app-register-config.js +4 -4
  223. package/lib/utils/app-register-display.js +3 -2
  224. package/lib/utils/app-register-validator.js +3 -2
  225. package/lib/utils/app-run-containers.js +26 -22
  226. package/lib/utils/app-scoped-config.js +31 -0
  227. package/lib/utils/app-service-env-from-builder.js +164 -0
  228. package/lib/utils/build-copy.js +1 -1
  229. package/lib/utils/build-helpers.js +20 -20
  230. package/lib/utils/build-resolve-image.js +165 -0
  231. package/lib/utils/cli-layout-chalk.js +8 -0
  232. package/lib/utils/cli-test-layout-chalk.js +267 -0
  233. package/lib/utils/cli-utils.js +88 -11
  234. package/lib/utils/compose-db-passwords.js +138 -0
  235. package/lib/utils/compose-generate-docker-compose.js +216 -0
  236. package/lib/utils/compose-generator.js +197 -291
  237. package/lib/utils/compose-miso-env.js +18 -0
  238. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  239. package/lib/utils/config-paths.js +166 -7
  240. package/lib/utils/config-scoped-resources-preference.js +41 -0
  241. package/lib/utils/configuration-env-resolver.js +11 -8
  242. package/lib/utils/controller-deployment-outcome.js +68 -0
  243. package/lib/utils/credential-display.js +2 -2
  244. package/lib/utils/credential-secrets-env.js +5 -5
  245. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  246. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  247. package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
  248. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  249. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  250. package/lib/utils/datasource-test-run-display.js +459 -0
  251. package/lib/utils/datasource-test-run-exit.js +83 -0
  252. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  253. package/lib/utils/datasource-test-run-report-version.js +51 -0
  254. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  255. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  256. package/lib/utils/datasource-validation-watch.js +266 -0
  257. package/lib/utils/declarative-url-ports.js +47 -0
  258. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  259. package/lib/utils/dev-ca-install.js +185 -23
  260. package/lib/utils/dev-cert-helper.js +266 -17
  261. package/lib/utils/dev-hosts-helper.js +307 -0
  262. package/lib/utils/dev-init-cert-hints.js +37 -0
  263. package/lib/utils/dev-init-health-messages.js +52 -0
  264. package/lib/utils/dev-init-resolve.js +86 -0
  265. package/lib/utils/dev-init-ssh-merge.js +65 -0
  266. package/lib/utils/dev-ssh-config-helper.js +196 -0
  267. package/lib/utils/dev-user-groups.js +93 -0
  268. package/lib/utils/docker-build.js +42 -17
  269. package/lib/utils/docker-exec.js +28 -0
  270. package/lib/utils/docker-manifest-public-port.js +116 -0
  271. package/lib/utils/docker-not-running-hint.js +52 -0
  272. package/lib/utils/docker.js +98 -11
  273. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  274. package/lib/utils/env-config-loader.js +10 -91
  275. package/lib/utils/env-copy.js +19 -10
  276. package/lib/utils/env-map.js +35 -8
  277. package/lib/utils/env-template.js +2 -2
  278. package/lib/utils/environment-scoped-resources.js +144 -0
  279. package/lib/utils/error-formatter.js +92 -13
  280. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  281. package/lib/utils/error-formatters/network-errors.js +2 -1
  282. package/lib/utils/error-formatters/permission-errors.js +2 -1
  283. package/lib/utils/error-formatters/validation-errors.js +2 -1
  284. package/lib/utils/external-readme.js +8 -1
  285. package/lib/utils/external-system-display.js +242 -136
  286. package/lib/utils/external-system-local-test-tty.js +389 -0
  287. package/lib/utils/external-system-readiness-core.js +377 -0
  288. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  289. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  290. package/lib/utils/external-system-readiness-display.js +186 -0
  291. package/lib/utils/external-system-system-test-tty-overview.js +120 -0
  292. package/lib/utils/external-system-system-test-tty.js +417 -0
  293. package/lib/utils/external-system-test-helpers.js +24 -6
  294. package/lib/utils/external-system-validators.js +30 -12
  295. package/lib/utils/health-check-url.js +119 -0
  296. package/lib/utils/health-check.js +59 -25
  297. package/lib/utils/help-builder.js +11 -8
  298. package/lib/utils/image-version.js +4 -8
  299. package/lib/utils/infra-containers.js +4 -7
  300. package/lib/utils/infra-env-defaults.js +162 -0
  301. package/lib/utils/infra-status-display.js +167 -0
  302. package/lib/utils/infra-status.js +16 -8
  303. package/lib/utils/local-secrets.js +3 -4
  304. package/lib/utils/paths.js +148 -47
  305. package/lib/utils/port-resolver.js +10 -23
  306. package/lib/utils/redis-env-scope.js +62 -0
  307. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  308. package/lib/utils/remote-builder-validation.js +99 -0
  309. package/lib/utils/remote-dev-auth.js +117 -21
  310. package/lib/utils/remote-docker-env.js +67 -15
  311. package/lib/utils/remote-secrets-loader.js +13 -4
  312. package/lib/utils/resolve-docker-image-ref.js +124 -0
  313. package/lib/utils/schema-loader.js +22 -9
  314. package/lib/utils/secrets-bash-kv.js +25 -0
  315. package/lib/utils/secrets-generator.js +169 -49
  316. package/lib/utils/secrets-helpers.js +70 -59
  317. package/lib/utils/secrets-kv-scope.js +60 -0
  318. package/lib/utils/secrets-utils.js +32 -38
  319. package/lib/utils/secrets-validation.js +3 -1
  320. package/lib/utils/secrets-yaml-preserve.js +109 -0
  321. package/lib/utils/ssh-key-helper.js +4 -2
  322. package/lib/utils/template-helpers.js +2 -2
  323. package/lib/utils/test-log-writer.js +3 -3
  324. package/lib/utils/token-manager.js +1 -2
  325. package/lib/utils/url-declarative-public-base.js +188 -0
  326. package/lib/utils/url-declarative-resolve-build.js +493 -0
  327. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  328. package/lib/utils/url-declarative-resolve.js +220 -0
  329. package/lib/utils/url-declarative-token-parse.js +74 -0
  330. package/lib/utils/url-declarative-url-flags.js +50 -0
  331. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  332. package/lib/utils/url-public-path-prefix.js +34 -0
  333. package/lib/utils/urls-local-registry.js +220 -0
  334. package/lib/utils/validation-report-tty-kit.js +77 -0
  335. package/lib/utils/validation-run-poll.js +112 -0
  336. package/lib/utils/validation-run-post-retry.js +85 -0
  337. package/lib/utils/validation-run-request.js +116 -0
  338. package/lib/utils/variable-transformer.js +21 -4
  339. package/lib/utils/yaml-preserve.js +33 -14
  340. package/lib/validation/datasource-warnings.js +56 -0
  341. package/lib/validation/env-template-auth.js +1 -1
  342. package/lib/validation/external-manifest-validator.js +27 -7
  343. package/lib/validation/validate-display.js +37 -31
  344. package/lib/validation/validate-external-cert-sync.js +23 -0
  345. package/lib/validation/validate.js +8 -14
  346. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  347. package/lib/validation/validator.js +22 -65
  348. package/lib/validation/wizard-config-validator.js +2 -1
  349. package/package.json +9 -4
  350. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  351. package/scripts/diagnose-cli.js +150 -0
  352. package/scripts/install-local.js +307 -55
  353. package/scripts/pnpm-global-remove.js +48 -0
  354. package/templates/README.md +15 -2
  355. package/templates/applications/dataplane/application.yaml +52 -2
  356. package/templates/applications/dataplane/env.template +79 -17
  357. package/templates/applications/dataplane/rbac.yaml +8 -0
  358. package/templates/applications/keycloak/application.yaml +9 -1
  359. package/templates/applications/keycloak/env.template +15 -6
  360. package/templates/applications/miso-controller/application.yaml +10 -2
  361. package/templates/applications/miso-controller/env.template +42 -12
  362. package/templates/applications/miso-controller/rbac.yaml +5 -0
  363. package/templates/external-system/README.md.hbs +20 -7
  364. package/templates/external-system/deploy.js.hbs +5 -5
  365. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  366. package/templates/infra/compose.yaml.hbs +33 -16
  367. package/templates/infra/servers.json.hbs +3 -1
  368. package/templates/python/docker-compose.hbs +16 -0
  369. package/templates/typescript/docker-compose.hbs +16 -0
  370. package/lib/api/external-test.api.js +0 -111
  371. package/lib/schema/env-config.yaml +0 -60
@@ -11,14 +11,30 @@
11
11
 
12
12
  const path = require('path');
13
13
  const fs = require('fs');
14
+ const fsRealSync = require('../internal/fs-real-sync');
15
+ const { nodeFs } = require('../internal/node-fs');
14
16
  const chalk = require('chalk');
15
17
  const handlebars = require('handlebars');
16
- const secrets = require('../core/secrets');
17
18
  const adminSecrets = require('../core/admin-secrets');
18
19
  const logger = require('../utils/logger');
19
- const dockerUtils = require('../utils/docker');
20
20
  const paths = require('../utils/paths');
21
21
  const secretsEnsure = require('../core/secrets-ensure');
22
+ const {
23
+ mergeInfraParameterDefaultsForCli,
24
+ getInfraParameterCatalog,
25
+ readRelaxedCatalogDefaults
26
+ } = require('../parameters/infra-parameter-catalog');
27
+ const { checkDockerAvailability } = require('./helpers-docker-check');
28
+
29
+ /**
30
+ * Lazy-load core/secrets at call time. A top-level require creates a circular dependency:
31
+ * secrets → url-declarative-resolve → compose-generator → compose-generate-docker-compose → this module,
32
+ * which left `generateAdminSecretsEnv` / `formatAdminSecretsContent` undefined on the captured export.
33
+ * @returns {Object} core/secrets module exports (loadSecrets, generateAdminSecretsEnv, …)
34
+ */
35
+ function getCoreSecrets() {
36
+ return require('../core/secrets');
37
+ }
22
38
 
23
39
  /**
24
40
  * Gets infrastructure directory name based on developer ID
@@ -43,22 +59,13 @@ function getInfraProjectName(devId) {
43
59
  }
44
60
 
45
61
  /**
46
- * Check Docker availability
47
- * @async
48
- * @returns {Promise<void>}
49
- * @throws {Error} If Docker is not available
62
+ * Fallback for admin password/email when validated catalog load failed but YAML is still readable.
63
+ * @returns {Record<string, string>}
50
64
  */
51
- async function checkDockerAvailability() {
52
- try {
53
- await dockerUtils.ensureDockerAndCompose();
54
- } catch (error) {
55
- throw new Error('Docker or Docker Compose is not available. Please install and start Docker.');
56
- }
65
+ function readInfraDefaultScalars() {
66
+ return readRelaxedCatalogDefaults();
57
67
  }
58
68
 
59
- /** Default admin password for new local installations when admin-secrets.env is empty */
60
- const DEFAULT_ADMIN_PASSWORD = 'admin123';
61
-
62
69
  /**
63
70
  * Log hint to reset Postgres volume when admin password was changed after first init.
64
71
  * @param {string} infraDir - Path to infra directory
@@ -66,7 +73,7 @@ const DEFAULT_ADMIN_PASSWORD = 'admin123';
66
73
  function logVolumeResetHint(infraDir) {
67
74
  logger.log(chalk.yellow(
68
75
  'If Postgres was already started with a different password, login will fail until you reset the volume. ' +
69
- `Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --adminPwd <password>' again.`
76
+ `Run: cd ${infraDir} && docker compose -f compose.yaml -p aifabrix down -v , then run 'aifabrix up-infra --adminPassword <password>' again.`
70
77
  ));
71
78
  }
72
79
 
@@ -82,9 +89,8 @@ async function syncPostgresPasswordToStore(password) {
82
89
  }
83
90
  }
84
91
 
85
- /** Default admin env keys and values when missing. */
92
+ /** Non-email defaults for admin-secrets.env merge (email default comes from infra.parameter.yaml `defaults`). */
86
93
  const DEFAULT_ADMIN_OBJ = {
87
- PGADMIN_DEFAULT_EMAIL: 'admin@aifabrix.dev',
88
94
  REDIS_HOST: 'local:redis:6379:0:',
89
95
  REDIS_COMMANDER_USER: 'admin'
90
96
  };
@@ -96,23 +102,87 @@ const DEFAULT_ADMIN_OBJ = {
96
102
  * @param {Object} adminObj - Decrypted admin secrets object
97
103
  * @param {string} passwordToUse - Password to set for Postgres, pgAdmin, Redis Commander
98
104
  * @param {boolean} shouldOverwriteWithAdminPwd - Whether this was an explicit admin password update
105
+ * @param {{ updateEmail?: boolean, emailToUse?: string }} [emailOpts]
99
106
  */
100
- async function applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordToUse, shouldOverwriteWithAdminPwd) {
107
+ async function applyAdminSecretsUpdate(
108
+ adminSecretsPath,
109
+ adminObj,
110
+ passwordToUse,
111
+ shouldOverwriteWithAdminPwd,
112
+ emailOpts
113
+ ) {
101
114
  const merged = { ...DEFAULT_ADMIN_OBJ, ...adminObj };
102
115
  merged.POSTGRES_PASSWORD = passwordToUse;
103
116
  merged.PGADMIN_DEFAULT_PASSWORD = passwordToUse;
104
117
  merged.REDIS_COMMANDER_PASSWORD = passwordToUse;
105
- const content = await secrets.formatAdminSecretsContent(merged);
106
- fs.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
118
+ if (emailOpts && emailOpts.updateEmail && emailOpts.emailToUse) {
119
+ merged.PGADMIN_DEFAULT_EMAIL = emailOpts.emailToUse;
120
+ }
121
+ const content = await getCoreSecrets().formatAdminSecretsContent(merged);
122
+ fsRealSync.writeFileSync(adminSecretsPath, content, { mode: 0o600 });
107
123
  if (shouldOverwriteWithAdminPwd) {
108
124
  logger.log('Updated admin password in admin-secrets.env.');
109
125
  await syncPostgresPasswordToStore(passwordToUse);
110
- logVolumeResetHint(path.join(paths.getAifabrixHome(), getInfraDirName(0)));
126
+ logVolumeResetHint(path.join(paths.getAifabrixSystemDir(), getInfraDirName(0)));
127
+ } else if (emailOpts && emailOpts.updateEmail) {
128
+ logger.log('Updated admin email in admin-secrets.env.');
111
129
  } else {
112
130
  logger.log('Set default admin password in admin-secrets.env for local use.');
113
131
  }
114
132
  }
115
133
 
134
+ function loadAdminMergedDefaultsForInfra(options) {
135
+ try {
136
+ return mergeInfraParameterDefaultsForCli(getInfraParameterCatalog().data, options);
137
+ } catch {
138
+ return mergeInfraParameterDefaultsForCli({}, options);
139
+ }
140
+ }
141
+
142
+ function resolveAdminPasswordAndEmailCli(options, mergedDefaults) {
143
+ const infraDefaults = readInfraDefaultScalars();
144
+ const adminPwdCli = String(options.adminPassword || options.adminPwd || '').trim();
145
+ const adminPwdOverride = adminPwdCli !== '' ? adminPwdCli : null;
146
+ const passwordToUse =
147
+ adminPwdOverride !== null
148
+ ? adminPwdOverride
149
+ : mergedDefaults.adminPassword || infraDefaults.adminPassword || '';
150
+ const emailCli = String(options.adminEmail || '').trim();
151
+ const emailOverride = emailCli !== '' ? emailCli : null;
152
+ const emailToUse =
153
+ emailOverride !== null
154
+ ? emailOverride
155
+ : mergedDefaults.adminEmail || infraDefaults.adminEmail || '';
156
+ return { adminPwdOverride, passwordToUse, emailOverride, emailToUse };
157
+ }
158
+
159
+ function computeAdminSecretsBackfillFlags(adminObj) {
160
+ const needsPasswordBackfill =
161
+ !(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
162
+ !(adminObj.PGADMIN_DEFAULT_PASSWORD && adminObj.PGADMIN_DEFAULT_PASSWORD.trim()) ||
163
+ !(adminObj.REDIS_COMMANDER_PASSWORD && adminObj.REDIS_COMMANDER_PASSWORD.trim());
164
+ const needsEmailBackfill = !(adminObj.PGADMIN_DEFAULT_EMAIL && adminObj.PGADMIN_DEFAULT_EMAIL.trim());
165
+ return { needsPasswordBackfill, needsEmailBackfill };
166
+ }
167
+
168
+ function resolvePasswordForAdminFile(
169
+ shouldOverwriteWithAdminPwd,
170
+ needsPasswordBackfill,
171
+ passwordToUse,
172
+ adminObj,
173
+ mergedDefaults
174
+ ) {
175
+ if (shouldOverwriteWithAdminPwd || needsPasswordBackfill) {
176
+ return passwordToUse;
177
+ }
178
+ return (
179
+ String(adminObj.POSTGRES_PASSWORD || '').trim() ||
180
+ mergedDefaults.adminPassword ||
181
+ readInfraDefaultScalars().adminPassword ||
182
+ ''
183
+ );
184
+ }
185
+
116
186
  /**
117
187
  * Ensure admin secrets file exists and set admin password.
118
188
  * When adminPwd is provided, update POSTGRES_PASSWORD, PGADMIN_DEFAULT_PASSWORD, REDIS_COMMANDER_PASSWORD
@@ -121,42 +191,82 @@ async function applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordToUse
121
191
  *
122
192
  * @async
123
193
  * @param {Object} [options] - Options
124
- * @param {string} [options.adminPwd] - Override admin password for Postgres, pgAdmin, Redis Commander (updates file when provided)
194
+ * @param {string} [options.adminPassword] - Override admin password (alias: adminPwd)
195
+ * @param {string} [options.adminPwd] - Override admin password for Postgres, pgAdmin, Redis Commander
196
+ * @param {string} [options.adminEmail] - Override pgAdmin default email (matches {{adminEmail}} defaults)
197
+ * @param {string} [options.userPassword] - Reserved for Keycloak user template (secrets use ensureInfraSecrets)
125
198
  * @returns {Promise<string>} Path to admin secrets file
126
199
  */
127
200
  async function ensureAdminSecrets(options = {}) {
128
- const adminPwdOverride = options.adminPwd && typeof options.adminPwd === 'string' && options.adminPwd.trim() !== ''
129
- ? options.adminPwd.trim()
130
- : null;
131
- const passwordToUse = adminPwdOverride || DEFAULT_ADMIN_PASSWORD;
132
- const adminSecretsPath = path.join(paths.getAifabrixHome(), 'admin-secrets.env');
201
+ const mergedDefaults = loadAdminMergedDefaultsForInfra(options);
202
+ const { adminPwdOverride, passwordToUse, emailOverride, emailToUse } = resolveAdminPasswordAndEmailCli(
203
+ options,
204
+ mergedDefaults
205
+ );
206
+ const adminSecretsPath = path.join(paths.getAifabrixSystemDir(), 'admin-secrets.env');
133
207
 
134
- if (!fs.existsSync(adminSecretsPath)) {
208
+ if (!fsRealSync.existsSync(adminSecretsPath)) {
135
209
  logger.log('Generating admin-secrets.env...');
136
- await secrets.generateAdminSecretsEnv(undefined);
210
+ await getCoreSecrets().generateAdminSecretsEnv(undefined);
137
211
  return adminSecretsPath;
138
212
  }
139
213
 
140
214
  const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
141
- const needsBackfill = !(adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
142
- !(adminObj.PGADMIN_DEFAULT_PASSWORD && adminObj.PGADMIN_DEFAULT_PASSWORD.trim()) ||
143
- !(adminObj.REDIS_COMMANDER_PASSWORD && adminObj.REDIS_COMMANDER_PASSWORD.trim());
215
+ const { needsPasswordBackfill, needsEmailBackfill } = computeAdminSecretsBackfillFlags(adminObj);
144
216
  const shouldOverwriteWithAdminPwd = adminPwdOverride !== null;
217
+ const shouldOverwriteEmail = emailOverride !== null;
218
+ const updateEmail = shouldOverwriteEmail || needsEmailBackfill;
145
219
 
146
- if (!shouldOverwriteWithAdminPwd && !needsBackfill) {
220
+ if (!shouldOverwriteWithAdminPwd && !needsPasswordBackfill && !updateEmail) {
147
221
  return adminSecretsPath;
148
222
  }
149
223
 
150
- await applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordToUse, shouldOverwriteWithAdminPwd);
224
+ const passwordForFile = resolvePasswordForAdminFile(
225
+ shouldOverwriteWithAdminPwd,
226
+ needsPasswordBackfill,
227
+ passwordToUse,
228
+ adminObj,
229
+ mergedDefaults
230
+ );
231
+
232
+ await applyAdminSecretsUpdate(adminSecretsPath, adminObj, passwordForFile, shouldOverwriteWithAdminPwd, {
233
+ updateEmail,
234
+ emailToUse
235
+ });
151
236
  return adminSecretsPath;
152
237
  }
153
238
 
239
+ /** Host-side pgpass for pgAdmin bind mount (must exist before container starts so servers.json import succeeds). */
240
+ const PGPASS_BOOTSTRAP_BASENAME = '.pgpass.bootstrap';
241
+
242
+ /**
243
+ * Writes pgpass next to servers.json for Docker bind mount into /pgadmin4 (not under /var/lib/pgadmin volume).
244
+ * Prefer chown to pgAdmin UID so mode 600 is readable in the container; fall back to 644 if not root.
245
+ *
246
+ * @param {string} infraDir - Infrastructure directory path
247
+ * @param {string} postgresPassword - PostgreSQL password for the pgpass line
248
+ */
249
+ function writePgpassBootstrap(infraDir, postgresPassword) {
250
+ const line = `postgres:5432:postgres:pgadmin:${postgresPassword}\n`;
251
+ const dest = path.join(infraDir, PGPASS_BOOTSTRAP_BASENAME);
252
+ fs.writeFileSync(dest, line, { mode: 0o600 });
253
+ try {
254
+ fs.chownSync(dest, 5050, 5050);
255
+ } catch {
256
+ try {
257
+ fs.chmodSync(dest, 0o644);
258
+ } catch {
259
+ // Ignore — container may still read depending on daemon / user namespace
260
+ }
261
+ }
262
+ }
263
+
154
264
  /**
155
- * Generates pgAdmin4 servers.json only. pgpass is not written to disk (ISO 27K);
156
- * it is created temporarily in startDockerServicesAndConfigure and deleted after copy to container.
265
+ * Generates pgAdmin4 servers.json only. pgpass for the container is supplied via bind-mounted
266
+ * `.pgpass.bootstrap` (written by writePgpassBootstrap); not embedded in servers.json.
157
267
  *
158
268
  * @param {string} infraDir - Infrastructure directory path
159
- * @param {string} postgresPassword - PostgreSQL password (for servers.json PassFile reference only; password not stored in file)
269
+ * @param {string} postgresPassword - Used only for consistency / future template fields (password is not written into servers.json)
160
270
  */
161
271
  function generatePgAdminConfig(infraDir, postgresPassword) {
162
272
  const serversJsonTemplatePath = path.join(__dirname, '..', '..', 'templates', 'infra', 'servers.json.hbs');
@@ -215,7 +325,7 @@ async function ensureMisoInitScript(infraDir) {
215
325
  const secretKey = 'databases-miso-controller-0-passwordKeyVault';
216
326
  let password;
217
327
  try {
218
- const loaded = await secrets.loadSecrets(undefined);
328
+ const loaded = await getCoreSecrets().loadSecrets(undefined);
219
329
  const urlOrPassword = loaded[secretKey] || loaded['databases-miso-controller-0-urlKeyVault'];
220
330
  const extracted = extractPasswordFromUrlOrValue(urlOrPassword);
221
331
  if (extracted !== null && extracted.trim() !== '') {
@@ -263,10 +373,11 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "miso" -c "GRANT AL
263
373
  * @async
264
374
  * @param {string} devId - Developer ID
265
375
  * @param {string} adminSecretsPath - Path to admin secrets file
376
+ * @param {{ pgpassBootstrap?: boolean }} [prepOptions] - When pgpassBootstrap is false, skip/remove host pgpass bootstrap file (pgAdmin disabled)
266
377
  * @returns {Promise<Object>} Object with infraDir and postgresPassword
267
378
  */
268
- async function prepareInfraDirectory(devId, adminSecretsPath) {
269
- const aifabrixDir = paths.getAifabrixHome();
379
+ async function prepareInfraDirectory(devId, adminSecretsPath, prepOptions = {}) {
380
+ const aifabrixDir = paths.getAifabrixSystemDir();
270
381
  const infraDirName = getInfraDirName(devId);
271
382
  const infraDir = path.join(aifabrixDir, infraDirName);
272
383
  if (!fs.existsSync(infraDir)) {
@@ -283,12 +394,59 @@ async function prepareInfraDirectory(devId, adminSecretsPath) {
283
394
  }
284
395
 
285
396
  const adminObj = await adminSecrets.readAndDecryptAdminSecrets(adminSecretsPath);
286
- const postgresPassword = (adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) || DEFAULT_ADMIN_PASSWORD;
397
+ const postgresPassword =
398
+ (adminObj.POSTGRES_PASSWORD && adminObj.POSTGRES_PASSWORD.trim()) ||
399
+ readInfraDefaultScalars().adminPassword ||
400
+ '';
287
401
  generatePgAdminConfig(infraDir, postgresPassword);
288
402
 
403
+ const pgpassBootstrap = prepOptions.pgpassBootstrap !== false;
404
+ const bootstrapPath = path.join(infraDir, PGPASS_BOOTSTRAP_BASENAME);
405
+ if (pgpassBootstrap) {
406
+ writePgpassBootstrap(infraDir, postgresPassword);
407
+ } else {
408
+ try {
409
+ if (fs.existsSync(bootstrapPath)) {
410
+ fs.unlinkSync(bootstrapPath);
411
+ }
412
+ } catch {
413
+ // Ignore
414
+ }
415
+ }
416
+
289
417
  return { infraDir, postgresPassword };
290
418
  }
291
419
 
420
+ /**
421
+ * Resolve infra working directory and admin-secrets path for stop/restart.
422
+ * Infra dir: prefer system dir compose; if missing, use legacy home when compose exists there.
423
+ * Admin secrets: prefer `admin-secrets.env` under system dir; if missing, use legacy home (covers mixed layouts).
424
+ *
425
+ * @param {string|number} devId - Developer ID
426
+ * @returns {{ infraDir: string, adminSecretsPath: string }}
427
+ */
428
+ function resolveInfraStatePaths(devId) {
429
+ const syncFs = nodeFs();
430
+ const name = getInfraDirName(devId);
431
+ const systemBase = paths.getAifabrixSystemDir();
432
+ const legacyBase = paths.getAifabrixHome();
433
+ const sysInfra = path.join(systemBase, name);
434
+ const legInfra = path.join(legacyBase, name);
435
+ const sysCompose = path.join(sysInfra, 'compose.yaml');
436
+ const legCompose = path.join(legInfra, 'compose.yaml');
437
+ let infraDir = sysInfra;
438
+ if (!syncFs.existsSync(sysCompose) && syncFs.existsSync(legCompose) && legacyBase !== systemBase) {
439
+ infraDir = legInfra;
440
+ }
441
+ const sysAdmin = path.join(systemBase, 'admin-secrets.env');
442
+ const legAdmin = path.join(legacyBase, 'admin-secrets.env');
443
+ let adminSecretsPath = sysAdmin;
444
+ if (!syncFs.existsSync(sysAdmin) && syncFs.existsSync(legAdmin) && legacyBase !== systemBase) {
445
+ adminSecretsPath = legAdmin;
446
+ }
447
+ return { infraDir, adminSecretsPath };
448
+ }
449
+
292
450
  /**
293
451
  * Register Handlebars helper for equality comparison
294
452
  */
@@ -312,7 +470,10 @@ module.exports = {
312
470
  checkDockerAvailability,
313
471
  ensureAdminSecrets,
314
472
  generatePgAdminConfig,
473
+ writePgpassBootstrap,
474
+ PGPASS_BOOTSTRAP_BASENAME,
315
475
  prepareInfraDirectory,
476
+ resolveInfraStatePaths,
316
477
  ensureMisoInitScript,
317
478
  registerHandlebarsHelper
318
479
  };
@@ -15,14 +15,13 @@ const config = require('../core/config');
15
15
  const devConfig = require('../utils/dev-config');
16
16
  const logger = require('../utils/logger');
17
17
  const dockerUtils = require('../utils/docker');
18
- const paths = require('../utils/paths');
19
18
  const statusHelpers = require('../utils/infra-status');
20
19
  const {
21
- getInfraDirName,
22
20
  getInfraProjectName,
23
21
  checkDockerAvailability,
24
22
  ensureAdminSecrets,
25
23
  prepareInfraDirectory,
24
+ resolveInfraStatePaths,
26
25
  ensureMisoInitScript,
27
26
  registerHandlebarsHelper
28
27
  } = require('./helpers');
@@ -72,18 +71,35 @@ async function withRunEnv(infraDir, adminSecretsPath, fn) {
72
71
  * @async
73
72
  * @function prepareInfrastructureEnvironment
74
73
  * @param {string|number|null} developerId - Developer ID
75
- * @param {Object} [options] - Options (traefik, adminPwd)
74
+ * @param {Object} [options] - Options (traefik, adminPwd, tlsEnabled)
76
75
  * @returns {Promise<Object>} Prepared environment configuration
77
76
  */
78
77
  async function prepareInfrastructureEnvironment(developerId, options = {}) {
79
78
  await checkDockerAvailability();
80
- await secretsEnsure.ensureInfraSecrets({ adminPwd: options.adminPwd });
81
- const adminSecretsPath = await ensureAdminSecrets({ adminPwd: options.adminPwd });
79
+ const adminPass = options.adminPassword || options.adminPwd;
80
+ const tlsEnabled = options.tlsEnabled === true;
81
+ const infraOpts = {
82
+ adminPassword: adminPass,
83
+ adminPwd: adminPass,
84
+ adminEmail: options.adminEmail,
85
+ userPassword: options.userPassword,
86
+ tlsEnabled
87
+ };
88
+ await secretsEnsure.ensureInfraSecrets(infraOpts);
89
+ const adminSecretsPath = await ensureAdminSecrets(infraOpts);
82
90
 
83
91
  const devId = developerId || await config.getDeveloperId();
92
+ const remoteServer = await config.getRemoteServer();
93
+ const {
94
+ assertRemoteBuilderDeveloperId,
95
+ remoteServerHostIsNonLocalhost
96
+ } = require('../utils/remote-builder-validation');
97
+ assertRemoteBuilderDeveloperId(remoteServer, devId);
98
+
84
99
  const devIdNum = typeof devId === 'string' ? parseInt(devId, 10) : devId;
85
100
  const ports = devConfig.getDevPorts(devIdNum);
86
101
  const idNum = devIdNum;
102
+ const trustForwardedHeaders = remoteServerHostIsNonLocalhost(remoteServer);
87
103
 
88
104
  const templatePath = path.join(__dirname, '..', '..', 'templates', 'infra', 'compose.yaml.hbs');
89
105
  if (!fs.existsSync(templatePath)) {
@@ -91,10 +107,12 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
91
107
  }
92
108
 
93
109
  // Prepare infrastructure directory
94
- const { infraDir } = await prepareInfraDirectory(devId, adminSecretsPath);
110
+ const { infraDir } = await prepareInfraDirectory(devId, adminSecretsPath, {
111
+ pgpassBootstrap: options.pgadmin !== false
112
+ });
95
113
  await ensureMisoInitScript(infraDir);
96
114
 
97
- return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath };
115
+ return { devId, idNum, ports, templatePath, infraDir, adminSecretsPath, trustForwardedHeaders };
98
116
  }
99
117
 
100
118
  /**
@@ -114,9 +132,10 @@ async function prepareInfrastructureEnvironment(developerId, options = {}) {
114
132
  * // Infrastructure services are now running
115
133
  */
116
134
  async function startInfra(developerId = null, options = {}) {
117
- const { devId, idNum, ports, templatePath, infraDir } = await prepareInfrastructureEnvironment(developerId, options);
135
+ const { devId, idNum, ports, templatePath, infraDir, trustForwardedHeaders } =
136
+ await prepareInfrastructureEnvironment(developerId, options);
118
137
  const { traefik = false, pgadmin = true, redisCommander = true } = options;
119
- const traefikConfig = buildTraefikConfig(traefik);
138
+ const traefikConfig = { ...buildTraefikConfig(traefik), trustForwardedHeaders };
120
139
  const validation = validateTraefikConfig(traefikConfig);
121
140
  if (!validation.valid) {
122
141
  throw new Error(validation.errors.join('\n'));
@@ -199,10 +218,8 @@ async function removeAppVolumes(appNames, devId) {
199
218
  */
200
219
  async function stopInfra() {
201
220
  const devId = await config.getDeveloperId();
202
- const aifabrixDir = paths.getAifabrixHome();
203
- const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
221
+ const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
204
222
  const composePath = path.join(infraDir, 'compose.yaml');
205
- const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
206
223
 
207
224
  if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
208
225
  logger.log('Infrastructure not running or not properly configured');
@@ -262,10 +279,8 @@ async function stopAllAppContainersAndVolumes(devId) {
262
279
  */
263
280
  async function stopInfraWithVolumes() {
264
281
  const devId = await config.getDeveloperId();
265
- const aifabrixDir = paths.getAifabrixHome();
266
- const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
282
+ const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
267
283
  const composePath = path.join(infraDir, 'compose.yaml');
268
- const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
269
284
 
270
285
  if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
271
286
  logger.log('Infrastructure not running or not properly configured');
@@ -307,10 +322,8 @@ async function restartService(serviceName) {
307
322
  }
308
323
 
309
324
  const devId = await config.getDeveloperId();
310
- const aifabrixDir = paths.getAifabrixHome();
311
- const infraDir = path.join(aifabrixDir, getInfraDirName(devId));
325
+ const { infraDir, adminSecretsPath } = resolveInfraStatePaths(devId);
312
326
  const composePath = path.join(infraDir, 'compose.yaml');
313
- const adminSecretsPath = path.join(aifabrixDir, 'admin-secrets.env');
314
327
 
315
328
  if (!fs.existsSync(composePath) || !fs.existsSync(adminSecretsPath)) {
316
329
  throw new Error('Infrastructure not properly configured');
@@ -9,7 +9,6 @@
9
9
  */
10
10
 
11
11
  const { exec } = require('child_process');
12
- const { promisify } = require('util');
13
12
  const path = require('path');
14
13
  const fs = require('fs');
15
14
  const logger = require('../utils/logger');
@@ -19,13 +18,13 @@ const config = require('../core/config');
19
18
  const { getInfraProjectName } = require('./helpers');
20
19
  const adminSecrets = require('../core/admin-secrets');
21
20
 
22
- const execAsync = promisify(exec);
23
-
24
- // Wrapper to support cwd option
25
- function execAsyncWithCwd(command, options = {}) {
21
+ // Wrapper to support cwd option and dev-config remote Docker (docker-endpoint + TLS)
22
+ async function execAsyncWithCwd(command, options = {}) {
23
+ const { getDockerExecEnv } = require('../utils/remote-docker-env');
24
+ const { cwd, env: extraEnv, ...execOptions } = options;
25
+ const env = { ...(await getDockerExecEnv()), ...(extraEnv || {}) };
26
26
  return new Promise((resolve, reject) => {
27
- const { cwd, ...execOptions } = options;
28
- exec(command, { ...execOptions, cwd }, (error, stdout, stderr) => {
27
+ exec(command, { ...execOptions, cwd, env }, (error, stdout, stderr) => {
29
28
  if (error) {
30
29
  reject(error);
31
30
  } else {
@@ -51,29 +50,6 @@ async function startDockerServices(composePath, projectName, adminSecretsPath, i
51
50
  logger.log('Infrastructure services started successfully');
52
51
  }
53
52
 
54
- /**
55
- * Copy pgAdmin4 configuration files into container
56
- * @async
57
- * @param {string} pgadminContainerName - pgAdmin container name
58
- * @param {string} serversJsonPath - Path to servers.json file
59
- * @param {string} pgpassPath - Path to pgpass file
60
- */
61
- async function copyPgAdminConfig(pgadminContainerName, serversJsonPath, pgpassPath) {
62
- try {
63
- await new Promise(resolve => setTimeout(resolve, 2000)); // Wait for container to be ready
64
- if (fs.existsSync(serversJsonPath)) {
65
- await execAsync(`docker cp "${serversJsonPath}" ${pgadminContainerName}:/pgadmin4/servers.json`);
66
- }
67
- if (fs.existsSync(pgpassPath)) {
68
- await execAsync(`docker cp "${pgpassPath}" ${pgadminContainerName}:/pgpass`);
69
- await execAsync(`docker exec ${pgadminContainerName} chmod 600 /pgpass`);
70
- }
71
- } catch (error) {
72
- // Ignore copy errors - files might already be there or container not ready
73
- logger.log('Note: Could not copy pgAdmin4 config files (this is OK if container was just restarted)');
74
- }
75
- }
76
-
77
53
  /**
78
54
  * Prepare run env file from decrypted admin secrets.
79
55
  * @async
@@ -89,34 +65,12 @@ async function prepareRunEnv(infraDir) {
89
65
  }
90
66
 
91
67
  /**
92
- * Write pgpass file and copy pgAdmin config into container.
93
- * @async
94
- * @param {string} infraDir - Infrastructure directory
95
- * @param {Object} adminObj - Decrypted admin secrets object
96
- * @param {string} devId - Developer ID
97
- * @param {number} idNum - Developer ID number
98
- * @returns {Promise<string>} Path to pgpass run file
99
- */
100
- async function writePgpassAndCopyPgAdminConfig(infraDir, adminObj, devId, idNum) {
101
- const pgpassRunPath = path.join(infraDir, '.pgpass.run');
102
- const pgadminContainerName = idNum === 0 ? 'aifabrix-pgadmin' : `aifabrix-dev${devId}-pgadmin`;
103
- const serversJsonPath = path.join(infraDir, 'servers.json');
104
- const postgresPassword = adminObj.POSTGRES_PASSWORD || '';
105
- const pgpassContent = `postgres:5432:postgres:pgadmin:${postgresPassword}\n`;
106
- fs.writeFileSync(pgpassRunPath, pgpassContent, { mode: 0o600 });
107
- await copyPgAdminConfig(pgadminContainerName, serversJsonPath, pgpassRunPath);
108
- return pgpassRunPath;
109
- }
110
-
111
- /**
112
- * Remove temporary run files (env and pgpass) if they exist.
68
+ * Remove temporary run files (env) if they exist.
113
69
  * @param {string} runEnvPath - Path to .env.run
114
- * @param {string} [pgpassRunPath] - Path to .pgpass.run
115
70
  */
116
- function cleanupRunFiles(runEnvPath, pgpassRunPath) {
71
+ function cleanupRunFiles(runEnvPath) {
117
72
  try {
118
73
  if (fs.existsSync(runEnvPath)) fs.unlinkSync(runEnvPath);
119
- if (pgpassRunPath && fs.existsSync(pgpassRunPath)) fs.unlinkSync(pgpassRunPath);
120
74
  } catch {
121
75
  // Ignore unlink errors
122
76
  }
@@ -136,11 +90,9 @@ function cleanupRunFiles(runEnvPath, pgpassRunPath) {
136
90
  */
137
91
  async function startDockerServicesAndConfigure(composePath, devId, idNum, infraDir, opts = {}) {
138
92
  let runEnvPath;
139
- let pgpassRunPath;
140
- let adminObj;
141
93
  const { pgadmin = true, redisCommander = true, traefik = false } = opts;
142
94
  try {
143
- ({ adminObj, runEnvPath } = await prepareRunEnv(infraDir));
95
+ ({ runEnvPath } = await prepareRunEnv(infraDir));
144
96
  } catch (err) {
145
97
  throw new Error(`Failed to prepare infra env: ${err.message}`);
146
98
  }
@@ -148,13 +100,10 @@ async function startDockerServicesAndConfigure(composePath, devId, idNum, infraD
148
100
  try {
149
101
  const projectName = getInfraProjectName(devId);
150
102
  await startDockerServices(composePath, projectName, runEnvPath, infraDir);
151
- if (pgadmin) {
152
- pgpassRunPath = await writePgpassAndCopyPgAdminConfig(infraDir, adminObj, devId, idNum);
153
- }
154
103
  await waitForServices(devId, { pgadmin, redisCommander, traefik });
155
104
  logger.log('All services are healthy and ready');
156
105
  } finally {
157
- cleanupRunFiles(runEnvPath, pgpassRunPath);
106
+ cleanupRunFiles(runEnvPath);
158
107
  }
159
108
  }
160
109
 
@@ -195,8 +144,10 @@ async function waitForServices(devId = null, opts = {}) {
195
144
  * @param {number|string|null} [devId] - Developer ID (null = use current)
196
145
  * @param {Object} [options] - Options
197
146
  * @param {boolean} [options.strict=false] - When true, only consider current dev's containers (no fallback to dev 0); use for up-miso and status consistency
198
- * @param {boolean} [options.pgadmin=true] - Include pgAdmin in health check
199
- * @param {boolean} [options.redisCommander=true] - Include Redis Commander in health check
147
+ * @param {boolean} [options.postgres=true] - When false, skip Postgres (and pgAdmin) checks for apps with requires.database: false
148
+ * @param {boolean} [options.redis=true] - When false, skip Redis (and Redis Commander) checks for apps with requires.redis: false
149
+ * @param {boolean} [options.pgadmin=true] - Include pgAdmin in health check (only when Postgres is checked)
150
+ * @param {boolean} [options.redisCommander=true] - Include Redis Commander in health check (only when Redis is checked)
200
151
  * @param {boolean} [options.traefik=false] - Include Traefik in health check
201
152
  * @returns {Promise<Object>} Health status of each service
202
153
  *
@@ -206,10 +157,14 @@ async function waitForServices(devId = null, opts = {}) {
206
157
  */
207
158
  async function checkInfraHealth(devId = null, options = {}) {
208
159
  const developerId = devId || await config.getDeveloperId();
209
- const servicesWithHealthCheck = ['postgres', 'redis'];
160
+ const includePostgres = options.postgres !== false;
161
+ const includeRedis = options.redis !== false;
162
+ const servicesWithHealthCheck = [];
163
+ if (includePostgres) servicesWithHealthCheck.push('postgres');
164
+ if (includeRedis) servicesWithHealthCheck.push('redis');
210
165
  const servicesWithoutHealthCheck = [];
211
- if (options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
212
- if (options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
166
+ if (includePostgres && options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
167
+ if (includeRedis && options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
213
168
  if (options.traefik === true) servicesWithoutHealthCheck.push('traefik');
214
169
  const health = {};
215
170
  const lookupOptions = options.strict ? { strict: true } : {};
@@ -230,7 +185,6 @@ async function checkInfraHealth(devId = null, options = {}) {
230
185
  module.exports = {
231
186
  execAsyncWithCwd,
232
187
  startDockerServices,
233
- copyPgAdminConfig,
234
188
  startDockerServicesAndConfigure,
235
189
  waitForServices,
236
190
  checkInfraHealth