@aifabrix/builder 2.42.1 → 2.44.0

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 (392) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/README.md +2 -2
  3. package/anchor-docs/README.md +10 -0
  4. package/anchor-docs/_TEMPLATE +24 -0
  5. package/bin/aifabrix.js +13 -4
  6. package/integration/hubspot-test/README.md +157 -0
  7. package/integration/{hubspot → hubspot-test}/application.json +6 -6
  8. package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
  9. package/integration/hubspot-test/env.template +4 -0
  10. package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
  11. package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
  12. package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
  13. package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
  14. package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
  15. package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
  16. package/integration/hubspot-test/rbac.json +166 -0
  17. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
  18. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
  19. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
  20. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
  21. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
  22. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
  23. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
  24. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
  25. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
  26. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
  27. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
  28. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
  29. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
  30. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
  31. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
  32. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
  33. package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
  34. package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
  35. package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
  36. package/integration/{hubspot → hubspot-test}/test.js +137 -102
  37. package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
  38. package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
  39. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  40. package/integration/roundtrip-test-local/README.md +144 -0
  41. package/integration/roundtrip-test-local/application.yaml +13 -0
  42. package/integration/roundtrip-test-local/env.template +15 -0
  43. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  44. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  45. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  46. package/integration/roundtrip-test-local2/README.md +144 -0
  47. package/integration/roundtrip-test-local2/application.yaml +13 -0
  48. package/integration/roundtrip-test-local2/env.template +15 -0
  49. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  50. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  51. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  52. package/integration/test/wizard.yaml +8 -0
  53. package/jest.config.default.js +10 -0
  54. package/jest.config.integration.fixtures.js +22 -0
  55. package/jest.config.integration.js +21 -18
  56. package/jest.config.isolated.js +10 -0
  57. package/jest.projects.js +288 -0
  58. package/lib/api/datasources-core.api.js +3 -3
  59. package/lib/api/dev-mtls-request.js +110 -0
  60. package/lib/api/dev-server-https.js +145 -0
  61. package/lib/api/dev.api.js +133 -144
  62. package/lib/api/index.js +0 -1
  63. package/lib/api/pipeline.api.js +67 -20
  64. package/lib/api/service-users.api.js +111 -2
  65. package/lib/api/types/dev.types.js +4 -3
  66. package/lib/api/types/pipeline.types.js +8 -5
  67. package/lib/api/types/service-users.types.js +41 -0
  68. package/lib/api/types/validation-run.types.js +56 -0
  69. package/lib/api/validation-run.api.js +99 -0
  70. package/lib/api/validation-runner.js +99 -0
  71. package/lib/app/config.js +1 -1
  72. package/lib/app/deploy-status-display.js +2 -2
  73. package/lib/app/deploy.js +7 -6
  74. package/lib/app/display.js +2 -1
  75. package/lib/app/dockerfile.js +3 -2
  76. package/lib/app/down.js +2 -1
  77. package/lib/app/helpers.js +6 -5
  78. package/lib/app/index.js +27 -8
  79. package/lib/app/list.js +7 -6
  80. package/lib/app/push.js +4 -3
  81. package/lib/app/register.js +19 -8
  82. package/lib/app/rotate-secret.js +17 -13
  83. package/lib/app/run-container-start.js +184 -0
  84. package/lib/app/run-docker-fallback.js +108 -0
  85. package/lib/app/run-env-compose.js +30 -42
  86. package/lib/app/run-helpers.js +49 -126
  87. package/lib/app/run-infra-requirements.js +30 -0
  88. package/lib/app/run-resolve-image.js +21 -0
  89. package/lib/app/run.js +74 -21
  90. package/lib/app/show-display.js +1 -1
  91. package/lib/app/show.js +1 -1
  92. package/lib/build/index.js +13 -10
  93. package/lib/cli/index.js +2 -0
  94. package/lib/cli/setup-app.help.js +67 -0
  95. package/lib/cli/setup-app.js +59 -123
  96. package/lib/cli/setup-app.test-commands.js +179 -0
  97. package/lib/cli/setup-auth.js +36 -14
  98. package/lib/cli/setup-credential-deployment.js +22 -8
  99. package/lib/cli/setup-dev-path-commands.js +124 -0
  100. package/lib/cli/setup-dev.js +190 -103
  101. package/lib/cli/setup-environment.js +11 -20
  102. package/lib/cli/setup-external-system.js +62 -22
  103. package/lib/cli/setup-infra.js +139 -47
  104. package/lib/cli/setup-parameters.js +32 -0
  105. package/lib/cli/setup-secrets.js +147 -10
  106. package/lib/cli/setup-service-user.js +146 -20
  107. package/lib/cli/setup-utility.js +47 -19
  108. package/lib/commands/app-down.js +5 -7
  109. package/lib/commands/app-install.js +14 -7
  110. package/lib/commands/app-logs.js +13 -10
  111. package/lib/commands/app-shell.js +4 -1
  112. package/lib/commands/app-test.js +25 -19
  113. package/lib/commands/app.js +22 -10
  114. package/lib/commands/auth-config.js +10 -14
  115. package/lib/commands/auth-status.js +4 -3
  116. package/lib/commands/credential-env.js +4 -3
  117. package/lib/commands/credential-list.js +5 -4
  118. package/lib/commands/credential-push.js +4 -3
  119. package/lib/commands/datasource-unified-test-cli.js +495 -0
  120. package/lib/commands/datasource-unified-test-cli.options.js +149 -0
  121. package/lib/commands/datasource-validation-cli.js +129 -0
  122. package/lib/commands/datasource.js +123 -71
  123. package/lib/commands/deployment-list.js +6 -5
  124. package/lib/commands/dev-cli-handlers.js +122 -18
  125. package/lib/commands/dev-down.js +4 -3
  126. package/lib/commands/dev-init.js +231 -116
  127. package/lib/commands/dev-show-display.js +473 -0
  128. package/lib/commands/login-credentials.js +3 -2
  129. package/lib/commands/login-device.js +4 -3
  130. package/lib/commands/login.js +5 -4
  131. package/lib/commands/logout.js +8 -7
  132. package/lib/commands/parameters-validate.js +54 -0
  133. package/lib/commands/repair-datasource.js +314 -68
  134. package/lib/commands/repair-env-template.js +16 -10
  135. package/lib/commands/repair-rbac.js +25 -19
  136. package/lib/commands/repair.js +116 -32
  137. package/lib/commands/secrets-list.js +23 -12
  138. package/lib/commands/secrets-remove-all.js +220 -0
  139. package/lib/commands/secrets-remove.js +22 -13
  140. package/lib/commands/secrets-set.js +21 -12
  141. package/lib/commands/secrets-validate.js +20 -7
  142. package/lib/commands/secure.js +10 -9
  143. package/lib/commands/service-user.js +243 -13
  144. package/lib/commands/test-e2e-external.js +27 -1
  145. package/lib/commands/up-common.js +28 -2
  146. package/lib/commands/up-dataplane.js +31 -18
  147. package/lib/commands/up-miso.js +19 -29
  148. package/lib/commands/upload.js +138 -39
  149. package/lib/commands/wizard-core-helpers.js +1 -1
  150. package/lib/commands/wizard-dataplane.js +4 -3
  151. package/lib/commands/wizard-helpers.js +3 -3
  152. package/lib/commands/wizard.js +2 -2
  153. package/lib/core/admin-secrets.js +16 -5
  154. package/lib/core/audit-logger.js +12 -4
  155. package/lib/core/config-attach-extensions.js +46 -0
  156. package/lib/core/config-runtime-paths.js +29 -0
  157. package/lib/core/config.js +59 -58
  158. package/lib/core/diff.js +3 -2
  159. package/lib/core/ensure-encryption-key.js +2 -4
  160. package/lib/core/secrets-ensure-infra.js +77 -0
  161. package/lib/core/secrets-ensure.js +120 -64
  162. package/lib/core/secrets-env-write.js +35 -7
  163. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  164. package/lib/core/secrets.js +228 -42
  165. package/lib/core/templates-env.js +4 -3
  166. package/lib/core/templates.js +1 -1
  167. package/lib/datasource/abac-validator.js +148 -0
  168. package/lib/datasource/deploy.js +75 -53
  169. package/lib/datasource/field-reference-validator.js +77 -36
  170. package/lib/datasource/integration-context.js +63 -0
  171. package/lib/datasource/list.js +8 -7
  172. package/lib/datasource/log-viewer.js +252 -0
  173. package/lib/datasource/resolve-app.js +109 -0
  174. package/lib/datasource/test-e2e.js +95 -155
  175. package/lib/datasource/test-integration.js +121 -109
  176. package/lib/datasource/unified-validation-run-body.js +65 -0
  177. package/lib/datasource/unified-validation-run-post.js +23 -0
  178. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  179. package/lib/datasource/unified-validation-run.js +92 -0
  180. package/lib/datasource/validate.js +162 -15
  181. package/lib/deployment/deployer.js +4 -3
  182. package/lib/deployment/environment.js +7 -6
  183. package/lib/deployment/push.js +17 -8
  184. package/lib/external-system/delete.js +4 -3
  185. package/lib/external-system/deploy.js +131 -53
  186. package/lib/external-system/download-helpers.js +1 -1
  187. package/lib/external-system/download.js +7 -6
  188. package/lib/external-system/generator.js +104 -14
  189. package/lib/external-system/integration-test-dispatch.js +26 -0
  190. package/lib/external-system/test-execution.js +5 -1
  191. package/lib/external-system/test-helpers.js +0 -4
  192. package/lib/external-system/test-system-level-helpers.js +110 -0
  193. package/lib/external-system/test-system-level.js +83 -44
  194. package/lib/external-system/test.js +59 -8
  195. package/lib/generator/builders.js +23 -11
  196. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  197. package/lib/generator/external-controller-manifest.js +3 -3
  198. package/lib/generator/external.js +23 -11
  199. package/lib/generator/helpers.js +71 -12
  200. package/lib/generator/index.js +8 -4
  201. package/lib/generator/split-readme.js +12 -7
  202. package/lib/generator/split-variables.js +2 -1
  203. package/lib/generator/split.js +46 -11
  204. package/lib/generator/wizard-readme.js +3 -3
  205. package/lib/generator/wizard.js +16 -13
  206. package/lib/infrastructure/compose.js +60 -6
  207. package/lib/infrastructure/helpers.js +238 -51
  208. package/lib/infrastructure/index.js +64 -37
  209. package/lib/infrastructure/services.js +21 -15
  210. package/lib/internal/fs-real-sync.js +104 -0
  211. package/lib/internal/node-fs.js +98 -0
  212. package/lib/parameters/database-secret-values.js +173 -0
  213. package/lib/parameters/infra-kv-discovery.js +121 -0
  214. package/lib/parameters/infra-parameter-catalog.js +458 -0
  215. package/lib/parameters/infra-parameter-validate.js +64 -0
  216. package/lib/schema/application-schema.json +37 -17
  217. package/lib/schema/datasource-test-run.schema.json +493 -0
  218. package/lib/schema/deployment-rules.yaml +102 -63
  219. package/lib/schema/external-datasource.schema.json +1201 -433
  220. package/lib/schema/external-system.schema.json +181 -5
  221. package/lib/schema/flag-map-validation-run.json +31 -0
  222. package/lib/schema/infra-parameter.schema.json +106 -0
  223. package/lib/schema/infra.parameter.yaml +421 -0
  224. package/lib/schema/type/credential-auth-templates.json +40 -0
  225. package/lib/schema/type/document-storage.json +213 -0
  226. package/lib/schema/type/message-service.json +123 -0
  227. package/lib/schema/type/vector-store.json +88 -0
  228. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  229. package/lib/utils/api-error-handler.js +2 -2
  230. package/lib/utils/api.js +49 -14
  231. package/lib/utils/app-config-resolver.js +23 -1
  232. package/lib/utils/app-register-api.js +3 -2
  233. package/lib/utils/app-register-auth.js +1 -1
  234. package/lib/utils/app-register-config.js +4 -4
  235. package/lib/utils/app-register-display.js +3 -2
  236. package/lib/utils/app-register-validator.js +3 -2
  237. package/lib/utils/app-run-containers.js +26 -22
  238. package/lib/utils/app-scoped-config.js +31 -0
  239. package/lib/utils/app-service-env-from-builder.js +164 -0
  240. package/lib/utils/build-copy.js +1 -1
  241. package/lib/utils/build-helpers.js +20 -20
  242. package/lib/utils/build-resolve-image.js +165 -0
  243. package/lib/utils/cli-layout-chalk.js +8 -0
  244. package/lib/utils/cli-test-layout-chalk.js +267 -0
  245. package/lib/utils/cli-utils.js +88 -11
  246. package/lib/utils/compose-db-passwords.js +138 -0
  247. package/lib/utils/compose-generate-docker-compose.js +216 -0
  248. package/lib/utils/compose-generator.js +197 -291
  249. package/lib/utils/compose-miso-env.js +18 -0
  250. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  251. package/lib/utils/config-paths.js +209 -6
  252. package/lib/utils/config-scoped-resources-preference.js +41 -0
  253. package/lib/utils/controller-deployment-outcome.js +68 -0
  254. package/lib/utils/credential-display.js +2 -2
  255. package/lib/utils/credential-secrets-env.js +16 -1
  256. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  257. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  258. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  259. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  260. package/lib/utils/datasource-test-run-display.js +442 -0
  261. package/lib/utils/datasource-test-run-exit.js +58 -0
  262. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  263. package/lib/utils/datasource-test-run-report-version.js +51 -0
  264. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  265. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  266. package/lib/utils/datasource-validation-watch.js +266 -0
  267. package/lib/utils/declarative-url-ports.js +47 -0
  268. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  269. package/lib/utils/dev-ca-install.js +185 -23
  270. package/lib/utils/dev-cert-helper.js +266 -17
  271. package/lib/utils/dev-hosts-helper.js +307 -0
  272. package/lib/utils/dev-init-cert-hints.js +37 -0
  273. package/lib/utils/dev-init-health-messages.js +52 -0
  274. package/lib/utils/dev-init-resolve.js +86 -0
  275. package/lib/utils/dev-init-ssh-merge.js +65 -0
  276. package/lib/utils/dev-ssh-config-helper.js +196 -0
  277. package/lib/utils/dev-user-groups.js +93 -0
  278. package/lib/utils/docker-build.js +42 -17
  279. package/lib/utils/docker-exec.js +28 -0
  280. package/lib/utils/docker-manifest-public-port.js +116 -0
  281. package/lib/utils/docker-not-running-hint.js +52 -0
  282. package/lib/utils/docker.js +98 -11
  283. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  284. package/lib/utils/env-config-loader.js +10 -91
  285. package/lib/utils/env-copy.js +19 -10
  286. package/lib/utils/env-map.js +42 -11
  287. package/lib/utils/env-template.js +2 -2
  288. package/lib/utils/environment-scoped-resources.js +144 -0
  289. package/lib/utils/error-formatter.js +125 -9
  290. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  291. package/lib/utils/error-formatters/network-errors.js +2 -1
  292. package/lib/utils/error-formatters/permission-errors.js +2 -1
  293. package/lib/utils/error-formatters/validation-errors.js +2 -1
  294. package/lib/utils/external-env-template.js +180 -0
  295. package/lib/utils/external-readme.js +8 -1
  296. package/lib/utils/external-system-display.js +277 -136
  297. package/lib/utils/external-system-local-test-tty.js +389 -0
  298. package/lib/utils/external-system-readiness-core.js +377 -0
  299. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  300. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  301. package/lib/utils/external-system-readiness-display.js +186 -0
  302. package/lib/utils/external-system-test-helpers.js +24 -6
  303. package/lib/utils/external-system-validators.js +32 -14
  304. package/lib/utils/health-check-url.js +119 -0
  305. package/lib/utils/health-check.js +59 -25
  306. package/lib/utils/help-builder.js +14 -13
  307. package/lib/utils/image-version.js +4 -8
  308. package/lib/utils/infra-containers.js +4 -7
  309. package/lib/utils/infra-env-defaults.js +162 -0
  310. package/lib/utils/infra-status-display.js +167 -0
  311. package/lib/utils/infra-status.js +16 -8
  312. package/lib/utils/local-secrets.js +29 -7
  313. package/lib/utils/paths.js +136 -48
  314. package/lib/utils/port-resolver.js +10 -23
  315. package/lib/utils/redis-env-scope.js +62 -0
  316. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  317. package/lib/utils/remote-builder-validation.js +99 -0
  318. package/lib/utils/remote-dev-auth.js +117 -21
  319. package/lib/utils/remote-docker-env.js +67 -15
  320. package/lib/utils/remote-secrets-loader.js +13 -4
  321. package/lib/utils/resolve-docker-image-ref.js +124 -0
  322. package/lib/utils/schema-loader.js +22 -9
  323. package/lib/utils/secrets-bash-kv.js +25 -0
  324. package/lib/utils/secrets-generator.js +171 -51
  325. package/lib/utils/secrets-helpers.js +70 -59
  326. package/lib/utils/secrets-kv-scope.js +60 -0
  327. package/lib/utils/secrets-utils.js +35 -37
  328. package/lib/utils/secrets-validation.js +3 -1
  329. package/lib/utils/secrets-yaml-preserve.js +109 -0
  330. package/lib/utils/secure-file-permissions.js +91 -0
  331. package/lib/utils/ssh-key-helper.js +4 -2
  332. package/lib/utils/template-helpers.js +2 -2
  333. package/lib/utils/test-log-writer.js +3 -3
  334. package/lib/utils/token-manager.js +37 -5
  335. package/lib/utils/url-declarative-public-base.js +188 -0
  336. package/lib/utils/url-declarative-resolve-build.js +493 -0
  337. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  338. package/lib/utils/url-declarative-resolve.js +220 -0
  339. package/lib/utils/url-declarative-token-parse.js +74 -0
  340. package/lib/utils/url-declarative-url-flags.js +50 -0
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  342. package/lib/utils/url-public-path-prefix.js +34 -0
  343. package/lib/utils/urls-local-registry.js +220 -0
  344. package/lib/utils/validation-report-tty-kit.js +77 -0
  345. package/lib/utils/validation-run-poll.js +89 -0
  346. package/lib/utils/validation-run-post-retry.js +73 -0
  347. package/lib/utils/validation-run-request.js +98 -0
  348. package/lib/utils/variable-transformer.js +21 -4
  349. package/lib/utils/yaml-preserve.js +78 -1
  350. package/lib/validation/datasource-warnings.js +56 -0
  351. package/lib/validation/env-template-auth.js +50 -2
  352. package/lib/validation/external-manifest-validator.js +35 -7
  353. package/lib/validation/validate-display.js +37 -31
  354. package/lib/validation/validate.js +9 -10
  355. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  356. package/lib/validation/validator.js +32 -78
  357. package/lib/validation/wizard-config-validator.js +2 -1
  358. package/package.json +11 -3
  359. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  360. package/scripts/diagnose-cli.js +150 -0
  361. package/scripts/install-local.js +304 -55
  362. package/templates/README.md +15 -2
  363. package/templates/applications/dataplane/application.yaml +52 -2
  364. package/templates/applications/dataplane/env.template +80 -18
  365. package/templates/applications/dataplane/rbac.yaml +8 -0
  366. package/templates/applications/keycloak/application.yaml +9 -1
  367. package/templates/applications/keycloak/env.template +15 -6
  368. package/templates/applications/miso-controller/application.yaml +10 -2
  369. package/templates/applications/miso-controller/env.template +55 -14
  370. package/templates/applications/miso-controller/rbac.yaml +5 -0
  371. package/templates/external-system/README.md.hbs +20 -7
  372. package/templates/external-system/deploy.js.hbs +5 -5
  373. package/templates/external-system/env.template.hbs +22 -0
  374. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  375. package/templates/infra/compose.yaml.hbs +20 -4
  376. package/templates/python/docker-compose.hbs +16 -0
  377. package/templates/typescript/docker-compose.hbs +16 -0
  378. package/integration/hubspot/README.md +0 -102
  379. package/integration/hubspot/env.template +0 -4
  380. package/integration/hubspot/hubspot-datasource-company.json +0 -541
  381. package/integration/hubspot/hubspot-datasource-contact.json +0 -639
  382. package/integration/hubspot/hubspot-datasource-deal.json +0 -588
  383. package/integration/hubspot/hubspot-datasource-users.json +0 -116
  384. package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  385. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  386. package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  387. package/lib/api/external-test.api.js +0 -111
  388. package/lib/schema/env-config.yaml +0 -43
  389. /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
  390. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
  391. /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
  392. /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
@@ -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 {
@@ -59,14 +58,15 @@ async function startDockerServices(composePath, projectName, adminSecretsPath, i
59
58
  * @param {string} pgpassPath - Path to pgpass file
60
59
  */
61
60
  async function copyPgAdminConfig(pgadminContainerName, serversJsonPath, pgpassPath) {
61
+ const { execWithDockerEnv } = require('../utils/docker-exec');
62
62
  try {
63
63
  await new Promise(resolve => setTimeout(resolve, 2000)); // Wait for container to be ready
64
64
  if (fs.existsSync(serversJsonPath)) {
65
- await execAsync(`docker cp "${serversJsonPath}" ${pgadminContainerName}:/pgadmin4/servers.json`);
65
+ await execWithDockerEnv(`docker cp "${serversJsonPath}" ${pgadminContainerName}:/pgadmin4/servers.json`);
66
66
  }
67
67
  if (fs.existsSync(pgpassPath)) {
68
- await execAsync(`docker cp "${pgpassPath}" ${pgadminContainerName}:/pgpass`);
69
- await execAsync(`docker exec ${pgadminContainerName} chmod 600 /pgpass`);
68
+ await execWithDockerEnv(`docker cp "${pgpassPath}" ${pgadminContainerName}:/pgpass`);
69
+ await execWithDockerEnv(`docker exec ${pgadminContainerName} chmod 600 /pgpass`);
70
70
  }
71
71
  } catch (error) {
72
72
  // Ignore copy errors - files might already be there or container not ready
@@ -195,8 +195,10 @@ async function waitForServices(devId = null, opts = {}) {
195
195
  * @param {number|string|null} [devId] - Developer ID (null = use current)
196
196
  * @param {Object} [options] - Options
197
197
  * @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
198
+ * @param {boolean} [options.postgres=true] - When false, skip Postgres (and pgAdmin) checks for apps with requires.database: false
199
+ * @param {boolean} [options.redis=true] - When false, skip Redis (and Redis Commander) checks for apps with requires.redis: false
200
+ * @param {boolean} [options.pgadmin=true] - Include pgAdmin in health check (only when Postgres is checked)
201
+ * @param {boolean} [options.redisCommander=true] - Include Redis Commander in health check (only when Redis is checked)
200
202
  * @param {boolean} [options.traefik=false] - Include Traefik in health check
201
203
  * @returns {Promise<Object>} Health status of each service
202
204
  *
@@ -206,10 +208,14 @@ async function waitForServices(devId = null, opts = {}) {
206
208
  */
207
209
  async function checkInfraHealth(devId = null, options = {}) {
208
210
  const developerId = devId || await config.getDeveloperId();
209
- const servicesWithHealthCheck = ['postgres', 'redis'];
211
+ const includePostgres = options.postgres !== false;
212
+ const includeRedis = options.redis !== false;
213
+ const servicesWithHealthCheck = [];
214
+ if (includePostgres) servicesWithHealthCheck.push('postgres');
215
+ if (includeRedis) servicesWithHealthCheck.push('redis');
210
216
  const servicesWithoutHealthCheck = [];
211
- if (options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
212
- if (options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
217
+ if (includePostgres && options.pgadmin !== false) servicesWithoutHealthCheck.push('pgadmin');
218
+ if (includeRedis && options.redisCommander !== false) servicesWithoutHealthCheck.push('redis-commander');
213
219
  if (options.traefik === true) servicesWithoutHealthCheck.push('traefik');
214
220
  const health = {};
215
221
  const lookupOptions = options.strict ? { strict: true } : {};
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Synchronous fs helpers that use `global.__AIFABRIX_NODE_FS_UNMOCKED__` from
3
+ * `tests/capture-real-fs.js` when present so Jest `jest.mock('fs')` and partial
4
+ * `jest.mock('internal/node-fs')` cannot break config, schema, or builder scans.
5
+ *
6
+ * @fileoverview Real filesystem sync for config, schemas, urls.local registry, url:// resolution
7
+ */
8
+ 'use strict';
9
+
10
+ /**
11
+ * @returns {import('node:fs')|null}
12
+ */
13
+ function unmockedFsSnapshot() {
14
+ const g = typeof globalThis !== 'undefined' ? globalThis : global;
15
+ return g && g.__AIFABRIX_NODE_FS_UNMOCKED__ ? g.__AIFABRIX_NODE_FS_UNMOCKED__ : null;
16
+ }
17
+
18
+ function delegate(name, args) {
19
+ const snap = unmockedFsSnapshot();
20
+ if (snap && typeof snap[name] === 'function') {
21
+ return snap[name](...args);
22
+ }
23
+ // When Jest is active, bypass any manual module mocks of node:fs.
24
+ // This keeps schema/catalog reads stable even if a suite does jest.mock('node:fs').
25
+ const fs =
26
+ typeof jest !== 'undefined' && typeof jest.requireActual === 'function'
27
+ ? jest.requireActual('node:fs')
28
+ : require('node:fs');
29
+ return fs[name](...args);
30
+ }
31
+
32
+ /**
33
+ * @param {string} p
34
+ * @returns {boolean}
35
+ */
36
+ function existsSync(p) {
37
+ return delegate('existsSync', [p]);
38
+ }
39
+
40
+ /**
41
+ * Read file via snapshot/delegate only — not the same binding as {@link readFileSync} on `module.exports`.
42
+ * Tests may `jest.spyOn(exports, 'readFileSync')`; this function stays the real implementation for env/PIN paths.
43
+ * @param {string} p
44
+ * @param {string|import('node:fs').ObjectEncodingOptions} [enc]
45
+ * @returns {string|Buffer}
46
+ */
47
+ function readFileSyncDirect(p, enc) {
48
+ return delegate('readFileSync', enc !== undefined ? [p, enc] : [p]);
49
+ }
50
+
51
+ /**
52
+ * @param {string} p
53
+ * @param {string|import('node:fs').ObjectEncodingOptions} [enc]
54
+ * @returns {string|Buffer}
55
+ */
56
+ function readFileSync(p, enc) {
57
+ return readFileSyncDirect(p, enc);
58
+ }
59
+
60
+ /**
61
+ * @param {string} p
62
+ * @param {string|Buffer} data
63
+ * @param {object|string} [opts]
64
+ * @returns {void}
65
+ */
66
+ function writeFileSync(p, data, opts) {
67
+ return delegate('writeFileSync', opts !== undefined ? [p, data, opts] : [p, data]);
68
+ }
69
+
70
+ /**
71
+ * @param {string} p
72
+ * @param {object} [opts]
73
+ * @returns {string|undefined}
74
+ */
75
+ function mkdirSync(p, opts) {
76
+ return delegate('mkdirSync', opts !== undefined ? [p, opts] : [p]);
77
+ }
78
+
79
+ /**
80
+ * @param {string} p
81
+ * @returns {import('node:fs').Stats}
82
+ */
83
+ function statSync(p) {
84
+ return delegate('statSync', [p]);
85
+ }
86
+
87
+ /**
88
+ * @param {string} p
89
+ * @param {object} [opts]
90
+ * @returns {string[]|import('node:fs').Dirent[]}
91
+ */
92
+ function readdirSync(p, opts) {
93
+ return delegate('readdirSync', opts !== undefined ? [p, opts] : [p]);
94
+ }
95
+
96
+ module.exports = {
97
+ existsSync,
98
+ readFileSync,
99
+ readFileSyncDirect,
100
+ writeFileSync,
101
+ mkdirSync,
102
+ statSync,
103
+ readdirSync
104
+ };
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @fileoverview Filesystem helpers that ignore jest.spyOn on require('node:fs') for sync reads.
3
+ * Uses jest.requireActual when Jest is active so .bind() captures native implementations even if
4
+ * this module loads after another suite spied fs. watch still delegates to live fs so tests can spy it.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * Bound native fs from tests/capture-real-fs.js (Jest setupFiles, before mocks).
11
+ * @returns {Record<string, unknown>|null}
12
+ */
13
+ function getUnmockedFsSnapshot() {
14
+ const g = typeof globalThis !== 'undefined' ? globalThis : global;
15
+ return g && g.__AIFABRIX_NODE_FS_UNMOCKED__ ? g.__AIFABRIX_NODE_FS_UNMOCKED__ : null;
16
+ }
17
+
18
+ function getRealFs() {
19
+ const snap = getUnmockedFsSnapshot();
20
+ if (snap) {
21
+ return snap;
22
+ }
23
+ // When Jest is active, bypass manual module mocks (singleton may still carry spyOn).
24
+ if (typeof jest !== 'undefined' && typeof jest.requireActual === 'function') {
25
+ return jest.requireActual('node:fs');
26
+ }
27
+ return require('node:fs');
28
+ }
29
+
30
+ /**
31
+ * @param {import('node:fs')} fsModule
32
+ * @param {string} name
33
+ * @returns {unknown}
34
+ */
35
+ function bindSync(fsModule, name) {
36
+ const fn = fsModule[name];
37
+ return typeof fn === 'function' ? fn.bind(fsModule) : fn;
38
+ }
39
+
40
+ function liveFs() {
41
+ return require('node:fs');
42
+ }
43
+
44
+ /**
45
+ * Resolve real fs on each access so callers still see the filesystem after other
46
+ * suites replace require('fs') with mocks (schema-loader, schema sync helpers).
47
+ * @returns {typeof import('node:fs')}
48
+ */
49
+ function freshRealFs() {
50
+ return getRealFs();
51
+ }
52
+
53
+ /**
54
+ * @returns {Record<string, unknown>}
55
+ */
56
+ function buildBoundFs() {
57
+ const snap = getUnmockedFsSnapshot();
58
+ const rf = freshRealFs();
59
+ const live = liveFs();
60
+ const promiseHost = live.promises || {};
61
+ const boundPromises = {
62
+ mkdir: bindSync(promiseHost, 'mkdir'),
63
+ writeFile: bindSync(promiseHost, 'writeFile'),
64
+ appendFile: bindSync(promiseHost, 'appendFile'),
65
+ readFile: bindSync(promiseHost, 'readFile')
66
+ };
67
+ if (snap) {
68
+ return {
69
+ existsSync: snap.existsSync,
70
+ readFileSync: snap.readFileSync,
71
+ writeFileSync: snap.writeFileSync,
72
+ mkdirSync: snap.mkdirSync,
73
+ readdirSync: snap.readdirSync,
74
+ statSync: snap.statSync,
75
+ watch: (...args) => live.watch(...args),
76
+ promises: boundPromises
77
+ };
78
+ }
79
+ return {
80
+ existsSync: bindSync(rf, 'existsSync'),
81
+ readFileSync: bindSync(rf, 'readFileSync'),
82
+ writeFileSync: bindSync(rf, 'writeFileSync'),
83
+ mkdirSync: bindSync(rf, 'mkdirSync'),
84
+ readdirSync: bindSync(rf, 'readdirSync'),
85
+ statSync: bindSync(rf, 'statSync'),
86
+ watch: (...args) => live.watch(...args),
87
+ promises: boundPromises
88
+ };
89
+ }
90
+
91
+ /**
92
+ * @returns {ReturnType<typeof buildBoundFs>}
93
+ */
94
+ function nodeFs() {
95
+ return buildBoundFs();
96
+ }
97
+
98
+ module.exports = { nodeFs };
@@ -0,0 +1,173 @@
1
+ /**
2
+ * @fileoverview Index-aware local PostgreSQL URL/password defaults for databases-{app}-{i}-* keys
3
+ * @author AI Fabrix Team
4
+ * @version 2.1.0
5
+ */
6
+
7
+ const path = require('path');
8
+ const { nodeFs } = require('../internal/node-fs');
9
+ const yaml = require('js-yaml');
10
+
11
+ /**
12
+ * Shipped platform templates (when builder/<app> does not exist yet).
13
+ * Prefer Jest/global.PROJECT_ROOT when that tree contains templates (stable under isolated projects).
14
+ * @returns {string}
15
+ */
16
+ function getTemplatesApplicationsRoot() {
17
+ const fallback = path.join(__dirname, '..', '..', 'templates', 'applications');
18
+ try {
19
+ if (typeof global !== 'undefined' && global.PROJECT_ROOT) {
20
+ const g = path.join(path.resolve(String(global.PROJECT_ROOT)), 'templates', 'applications');
21
+ const marker = path.join(g, 'miso-controller', 'application.yaml');
22
+ if (nodeFs().existsSync(marker)) {
23
+ return g;
24
+ }
25
+ }
26
+ } catch {
27
+ /* ignore */
28
+ }
29
+ return fallback;
30
+ }
31
+
32
+ /**
33
+ * PostgreSQL role name from database name (same as compose pgUserName helper).
34
+ * @param {string} dbName - Logical database name (e.g. miso-logs)
35
+ * @returns {string}
36
+ */
37
+ function pgUserFromDbName(dbName) {
38
+ if (!dbName) return '';
39
+ return `${String(dbName).replace(/-/g, '_')}_user`;
40
+ }
41
+
42
+ /**
43
+ * Local dev password aligned with infra init scripts (user base + _pass123).
44
+ * @param {string} userName - e.g. miso_user, miso_logs_user
45
+ * @returns {string}
46
+ */
47
+ function localDevPasswordFromPgUser(userName) {
48
+ const base = String(userName).replace(/_user$/i, '');
49
+ return `${base}_pass123`;
50
+ }
51
+
52
+ /**
53
+ * Load requires.databases from application config if present (read-only; no rename).
54
+ * @param {string} appDir - Absolute path to builder/integration app folder
55
+ * @returns {Array<{name?: string}>|null}
56
+ */
57
+ function loadRequiresDatabasesArray(appDir) {
58
+ if (!appDir || !nodeFs().existsSync(appDir)) return null;
59
+ const candidates = ['application.yaml', 'application.yml', 'variables.yaml'];
60
+ for (const name of candidates) {
61
+ const p = path.join(appDir, name);
62
+ if (!nodeFs().existsSync(p)) continue;
63
+ try {
64
+ const doc = yaml.load(nodeFs().readFileSync(p, 'utf8'));
65
+ const dbs = doc?.requires?.databases;
66
+ if (Array.isArray(dbs) && dbs.length > 0) return dbs;
67
+ } catch {
68
+ /* ignore */
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+
74
+ /**
75
+ * Load requires.databases from shipped Builder template (templates/applications/<appKey>/application.yaml).
76
+ * @param {string} appKey - Application key
77
+ * @returns {Array<{name?: string}>|null}
78
+ */
79
+ function loadShippedRequiresDatabases(appKey) {
80
+ if (!appKey || typeof appKey !== 'string') return null;
81
+ const p = path.join(getTemplatesApplicationsRoot(), appKey, 'application.yaml');
82
+ if (!nodeFs().existsSync(p)) return null;
83
+ try {
84
+ const doc = yaml.load(nodeFs().readFileSync(p, 'utf8'));
85
+ const dbs = doc?.requires?.databases;
86
+ return Array.isArray(dbs) && dbs.length > 0 ? dbs : null;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Resolve logical PostgreSQL database name for a databases-{appKey}-{index}-* key.
94
+ * @param {string} appKey - App key segment from secret key
95
+ * @param {number} index - Database index
96
+ * @param {string|null} appDir - Optional app directory to read application.yaml
97
+ * @returns {string}
98
+ */
99
+ function resolveLogicalDbName(appKey, index, appDir) {
100
+ const fromDir = appDir ? loadRequiresDatabasesArray(appDir) : null;
101
+ const dbs = fromDir || loadShippedRequiresDatabases(appKey);
102
+ if (dbs && dbs[index] && dbs[index].name) {
103
+ return String(dbs[index].name);
104
+ }
105
+ if (index === 0) {
106
+ return String(appKey).replace(/-/g, '_');
107
+ }
108
+ return `${String(appKey).replace(/-/g, '_')}_${index}`;
109
+ }
110
+
111
+ /**
112
+ * Parse databases-{appKey}-{index}-(urlKeyVault|passwordKeyVault).
113
+ * @param {string} key - Secret key
114
+ * @returns {{ appKey: string, index: number, kind: 'url'|'password' }|null}
115
+ */
116
+ function parseDatabaseSecretKey(key) {
117
+ const m = String(key).match(/^databases-([a-z0-9-]+)-(\d+)-(urlKeyVault|passwordKeyVault)$/i);
118
+ if (!m) return null;
119
+ return {
120
+ appKey: m[1],
121
+ index: parseInt(m[2], 10),
122
+ kind: m[3].toLowerCase().startsWith('url') ? 'url' : 'password'
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Build postgres URL with unresolved host/port placeholders.
128
+ * @param {string} dbName - Database name in connection path (may contain hyphens)
129
+ * @param {string} userName - DB user
130
+ * @param {string} password - DB password
131
+ * @returns {string}
132
+ */
133
+ function buildPostgresUrlTemplate(dbName, userName, password) {
134
+ return `postgresql://${userName}:${password}@\${DB_HOST}:\${DB_PORT}/${dbName}`;
135
+ }
136
+
137
+ /**
138
+ * Generate password value for databases-*-passwordKeyVault.
139
+ * @param {string} key - Full secret key
140
+ * @param {string|null} appDir - Optional app directory for YAML lookup
141
+ * @returns {string|null} Value or null if key does not match
142
+ */
143
+ function generateDatabasePasswordValueForKey(key, appDir = null) {
144
+ const parsed = parseDatabaseSecretKey(key);
145
+ if (!parsed || parsed.kind !== 'password') return null;
146
+ const dbName = resolveLogicalDbName(parsed.appKey, parsed.index, appDir);
147
+ const user = pgUserFromDbName(dbName);
148
+ return localDevPasswordFromPgUser(user);
149
+ }
150
+
151
+ /**
152
+ * Generate URL value for databases-*-urlKeyVault.
153
+ * @param {string} key - Full secret key
154
+ * @param {string|null} appDir - Optional app directory for YAML lookup
155
+ * @returns {string|null} Value or null if key does not match
156
+ */
157
+ function generateDatabaseUrlValueForKey(key, appDir = null) {
158
+ const parsed = parseDatabaseSecretKey(key);
159
+ if (!parsed || parsed.kind !== 'url') return null;
160
+ const dbName = resolveLogicalDbName(parsed.appKey, parsed.index, appDir);
161
+ const user = pgUserFromDbName(dbName);
162
+ const pass = localDevPasswordFromPgUser(user);
163
+ return buildPostgresUrlTemplate(dbName, user, pass);
164
+ }
165
+
166
+ module.exports = {
167
+ parseDatabaseSecretKey,
168
+ generateDatabasePasswordValueForKey,
169
+ generateDatabaseUrlValueForKey,
170
+ loadRequiresDatabasesArray,
171
+ loadShippedRequiresDatabases,
172
+ resolveLogicalDbName
173
+ };
@@ -0,0 +1,121 @@
1
+ /**
2
+ * @fileoverview Discover kv:// keys for up-infra from workspace templates and application.yaml
3
+ * @author AI Fabrix Team
4
+ * @version 2.0.0
5
+ */
6
+
7
+ const fsRealSync = require('../internal/fs-real-sync');
8
+ const path = require('path');
9
+ const { loadRequiresDatabasesArray } = require('./database-secret-values');
10
+
11
+ /**
12
+ * Extract kv:// secret key names from env template content (active lines only).
13
+ * @param {string} content - env.template body
14
+ * @returns {string[]}
15
+ */
16
+ function extractKvKeysFromEnvContent(content) {
17
+ if (!content || typeof content !== 'string') return [];
18
+ const keys = new Set();
19
+ const kvPattern = /kv:\/\/([a-zA-Z0-9-_]+)/g;
20
+ const lines = content.split('\n');
21
+ for (const line of lines) {
22
+ const t = line.trim();
23
+ if (t === '' || t.startsWith('#')) continue;
24
+ let m;
25
+ kvPattern.lastIndex = 0;
26
+ while ((m = kvPattern.exec(line)) !== null) {
27
+ keys.add(m[1]);
28
+ }
29
+ }
30
+ return [...keys];
31
+ }
32
+
33
+ /**
34
+ * List app directories for discovery (builder first, then integration-only apps).
35
+ * @param {object} pathsUtil - paths module
36
+ * @returns {{ appKey: string, dir: string }[]}
37
+ */
38
+ function listAppDirsForDiscovery(pathsUtil) {
39
+ const out = [];
40
+ const seen = new Set();
41
+ for (const name of pathsUtil.listBuilderAppNames()) {
42
+ const dir = pathsUtil.getBuilderPath(name);
43
+ if (fsRealSync.existsSync(dir)) {
44
+ out.push({ appKey: name, dir });
45
+ seen.add(name);
46
+ }
47
+ }
48
+ for (const name of pathsUtil.listIntegrationAppNames()) {
49
+ if (seen.has(name)) continue;
50
+ const dir = pathsUtil.getIntegrationPath(name);
51
+ if (fsRealSync.existsSync(dir)) {
52
+ out.push({ appKey: name, dir });
53
+ }
54
+ }
55
+ return out;
56
+ }
57
+
58
+ /**
59
+ * Derive databases-{appKey}-{i}-url/password keys from requires.databases length.
60
+ * @param {object} pathsUtil - paths module
61
+ * @returns {string[]}
62
+ */
63
+ function deriveDatabaseKvKeysFromWorkspace(pathsUtil) {
64
+ const keys = new Set();
65
+ for (const { appKey, dir } of listAppDirsForDiscovery(pathsUtil)) {
66
+ const dbs = loadRequiresDatabasesArray(dir);
67
+ if (!Array.isArray(dbs) || dbs.length === 0) continue;
68
+ for (let i = 0; i < dbs.length; i++) {
69
+ keys.add(`databases-${appKey}-${i}-urlKeyVault`);
70
+ keys.add(`databases-${appKey}-${i}-passwordKeyVault`);
71
+ }
72
+ }
73
+ return [...keys];
74
+ }
75
+
76
+ /**
77
+ * Keys from env.template files whose catalog entry includes the given hook (e.g. upInfra).
78
+ * @param {object} pathsUtil - paths module
79
+ * @param {string} hook - ensureOn hook name
80
+ * @param {{ keyMatchesEnsureHook: Function }} catalog - loaded catalog API
81
+ * @returns {string[]}
82
+ */
83
+ function discoverKvKeysFromEnvTemplatesForHook(pathsUtil, hook, catalog) {
84
+ const keys = new Set();
85
+ for (const { dir } of listAppDirsForDiscovery(pathsUtil)) {
86
+ const envPath = path.join(dir, 'env.template');
87
+ if (!fsRealSync.existsSync(envPath)) continue;
88
+ let content;
89
+ try {
90
+ content = fsRealSync.readFileSync(envPath, 'utf8');
91
+ } catch {
92
+ continue;
93
+ }
94
+ for (const k of extractKvKeysFromEnvContent(content)) {
95
+ if (catalog.keyMatchesEnsureHook(k, hook)) keys.add(k);
96
+ }
97
+ }
98
+ return [...keys];
99
+ }
100
+
101
+ /**
102
+ * Full key list for ensureInfraSecrets: catalog exact upInfra + standard miso DB + derived DB + template hooks.
103
+ * @param {{ getEnsureOnKeys: Function, keyMatchesEnsureHook: Function }} catalog
104
+ * @param {object} pathsUtil - paths module
105
+ * @returns {string[]}
106
+ */
107
+ function getAllInfraEnsureKeys(catalog, pathsUtil) {
108
+ const set = new Set(catalog.getEnsureOnKeys('upInfra'));
109
+ for (const k of catalog.getStandardUpInfraBootstrapKeys()) set.add(k);
110
+ for (const k of deriveDatabaseKvKeysFromWorkspace(pathsUtil)) set.add(k);
111
+ for (const k of discoverKvKeysFromEnvTemplatesForHook(pathsUtil, 'upInfra', catalog)) set.add(k);
112
+ return [...set].sort();
113
+ }
114
+
115
+ module.exports = {
116
+ extractKvKeysFromEnvContent,
117
+ deriveDatabaseKvKeysFromWorkspace,
118
+ discoverKvKeysFromEnvTemplatesForHook,
119
+ getAllInfraEnsureKeys,
120
+ listAppDirsForDiscovery
121
+ };