@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
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * AI Fabrix Builder - Up Dataplane Command
3
4
  *
@@ -11,10 +12,12 @@
11
12
  * @version 2.0.0
12
13
  */
13
14
 
15
+ const path = require('path');
14
16
  const readline = require('readline');
15
17
  const chalk = require('chalk');
16
18
  const pathsUtil = require('../utils/paths');
17
19
  const { loadConfigFile } = require('../utils/config-format');
20
+ const { resolveDockerImageRef, normalizeDockerRegistryPrefix } = require('../utils/resolve-docker-image-ref');
18
21
  const logger = require('../utils/logger');
19
22
  const config = require('../core/config');
20
23
  const { checkAuthentication } = require('../utils/app-register-auth');
@@ -80,7 +83,7 @@ async function resolveControllerUrlWithHealthCheck() {
80
83
  logger.log(chalk.yellow(`\nController at ${controllerUrl} is not responding (health check failed).\n`));
81
84
  const newUrl = await promptForControllerUrl(controllerUrl);
82
85
  if (!newUrl) {
83
- throw new Error('Controller URL is required. Run "aifabrix up-dataplane" again and enter a valid controller URL, or set it with: aifabrix auth config --set-controller <url>');
86
+ throw new Error('Controller URL is required. Run "aifabrix up-dataplane" again and enter a valid controller URL, or set it with: aifabrix auth --set-controller <url>');
84
87
  }
85
88
 
86
89
  try {
@@ -96,7 +99,7 @@ async function resolveControllerUrlWithHealthCheck() {
96
99
  throw new Error(`Controller at ${normalizedNew} is not responding. Ensure the controller is running and reachable, then run "aifabrix up-dataplane" again.`);
97
100
  }
98
101
 
99
- logger.log(chalk.green(`✓ Using controller: ${normalizedNew}`));
102
+ logger.log(formatSuccessLine(`Using controller: ${normalizedNew}`));
100
103
  return normalizedNew;
101
104
  }
102
105
 
@@ -114,7 +117,7 @@ async function registerOrRotateDataplane(options, controllerUrl, environmentKey,
114
117
  logger.log(chalk.blue('Dataplane already registered; rotating secret...'));
115
118
  await rotateSecret('dataplane', options);
116
119
  } else {
117
- const imageOverride = options.image || (options.registry ? buildDataplaneImageRef(options.registry) : undefined);
120
+ const imageOverride = options.image || buildDataplaneImageRef(options);
118
121
  const registerOpts = { imageOverride, image: imageOverride, registryMode: options.registryMode };
119
122
  await registerApplication('dataplane', registerOpts);
120
123
  }
@@ -126,25 +129,32 @@ async function registerOrRotateDataplane(options, controllerUrl, environmentKey,
126
129
  * @returns {Promise<void>}
127
130
  */
128
131
  async function deployDataplaneToController(options) {
129
- const imageOverride = options.image || (options.registry ? buildDataplaneImageRef(options.registry) : undefined);
132
+ const imageOverride = options.image || buildDataplaneImageRef(options);
130
133
  const deployOpts = { imageOverride, image: imageOverride, registryMode: options.registryMode };
131
134
  await app.deployApp('dataplane', deployOpts);
132
135
  }
133
136
 
134
137
  /**
135
- * Build full image ref from registry and dataplane config (registry/name:tag)
136
- * @param {string} registry - Registry URL
137
- * @returns {string|undefined} Full image reference or undefined
138
+ * Full pullable image ref when CLI `--registry` and/or manifest `image.registry` is set.
139
+ * Returns undefined when neither is set (register/deploy use application config as before).
140
+ * @param {Object} [options] - Commander options
141
+ * @param {string} [options.registry] - CLI registry override (wins over manifest)
142
+ * @returns {string|undefined} Full reference or undefined
138
143
  */
139
- function buildDataplaneImageRef(registry) {
144
+ function buildDataplaneImageRef(options = {}) {
140
145
  try {
141
146
  const builderPath = pathsUtil.getBuilderPath('dataplane');
142
147
  const configPath = pathsUtil.resolveApplicationConfigPath(builderPath);
143
- const variables = loadConfigFile(configPath);
144
- const name = variables?.image?.name || variables?.app?.key || 'dataplane';
145
- const tag = variables?.image?.tag || 'latest';
146
- const base = (registry || '').replace(/\/+$/, '');
147
- return base ? `${base}/${name}:${tag}` : undefined;
148
+ const variables = loadConfigFile(configPath) || {};
149
+ const cli = normalizeDockerRegistryPrefix(options.registry);
150
+ const manifestReg = normalizeDockerRegistryPrefix(variables.image?.registry);
151
+ if (!cli && !manifestReg) {
152
+ return undefined;
153
+ }
154
+ const { imageName, imageTag } = resolveDockerImageRef('dataplane', variables, {
155
+ registry: options.registry || undefined
156
+ });
157
+ return `${imageName}:${imageTag}`;
148
158
  } catch {
149
159
  return undefined;
150
160
  }
@@ -167,7 +177,7 @@ function buildDataplaneImageRef(registry) {
167
177
  async function handleUpDataplane(options = {}) {
168
178
  const builderDir = await config.getAifabrixBuilderDir();
169
179
  if (builderDir) {
170
- process.env.AIFABRIX_BUILDER_DIR = builderDir;
180
+ process.env.AIFABRIX_BUILDER_DIR = path.resolve(builderDir);
171
181
  }
172
182
  logger.log(chalk.blue('Starting up-dataplane (register/rotate, deploy, then run dataplane locally)...\n'));
173
183
 
@@ -179,10 +189,10 @@ async function handleUpDataplane(options = {}) {
179
189
  const environment = (cfg && cfg.environment) ? cfg.environment : 'dev';
180
190
  if (environment !== 'dev') {
181
191
  throw new Error(
182
- 'Dataplane is only supported in dev environment. Set with: aifabrix auth config --set-environment dev.'
192
+ 'Dataplane is only supported in dev environment. Set with: aifabrix auth --set-environment dev.'
183
193
  );
184
194
  }
185
- logger.log(chalk.green('Logged in and environment is dev'));
195
+ logger.log(formatSuccessLine('Logged in and environment is dev'));
186
196
 
187
197
  await ensureAppFromTemplate('dataplane');
188
198
  // If envOutputPath target folder does not exist, set envOutputPath to null
@@ -192,9 +202,12 @@ async function handleUpDataplane(options = {}) {
192
202
 
193
203
  await deployDataplaneToController(options);
194
204
  logger.log('');
195
- await app.runApp('dataplane', { skipEnvOutputPath: true });
205
+ await app.runApp('dataplane', {
206
+ skipEnvOutputPath: true,
207
+ registry: options.registry || undefined
208
+ });
196
209
 
197
- logger.log(chalk.green('\n✓ up-dataplane complete. Dataplane is registered, deployed in dev, and running locally.'));
210
+ logger.log(formatSuccessParagraph('up-dataplane complete. Dataplane is registered, deployed in dev, and running locally.'));
198
211
  }
199
212
 
200
213
  module.exports = { handleUpDataplane, buildDataplaneImageRef };
@@ -1,3 +1,4 @@
1
+ const { formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * AI Fabrix Builder - Up Miso Command
3
4
  *
@@ -9,9 +10,8 @@
9
10
  * @version 2.0.0
10
11
  */
11
12
 
13
+ const path = require('path');
12
14
  const chalk = require('chalk');
13
- const pathsUtil = require('../utils/paths');
14
- const { loadConfigFile } = require('../utils/config-format');
15
15
  const logger = require('../utils/logger');
16
16
  const config = require('../core/config');
17
17
  const infra = require('../infrastructure');
@@ -38,26 +38,6 @@ function parseImageOptions(imageOpts) {
38
38
  return map;
39
39
  }
40
40
 
41
- /**
42
- * Build full image ref from registry and app config (registry/name:tag)
43
- * @param {string} appName - keycloak or miso-controller
44
- * @param {string} registry - Registry URL
45
- * @returns {string} Full image reference
46
- */
47
- function buildImageRefFromRegistry(appName, registry) {
48
- try {
49
- const builderPath = pathsUtil.getBuilderPath(appName);
50
- const configPath = pathsUtil.resolveApplicationConfigPath(builderPath);
51
- const variables = loadConfigFile(configPath);
52
- const name = variables?.image?.name || variables?.app?.key || appName;
53
- const tag = variables?.image?.tag || 'latest';
54
- const base = (registry || '').replace(/\/+$/, '');
55
- return base ? `${base}/${name}:${tag}` : undefined;
56
- } catch {
57
- return undefined;
58
- }
59
- }
60
-
61
41
  /**
62
42
  * Build run options and run keycloak, then miso-controller
63
43
  * @async
@@ -65,10 +45,20 @@ function buildImageRefFromRegistry(appName, registry) {
65
45
  */
66
46
  async function runMisoApps(options) {
67
47
  const imageMap = parseImageOptions(options.image);
68
- const keycloakImage = imageMap.keycloak || (options.registry ? buildImageRefFromRegistry('keycloak', options.registry) : undefined);
69
- const misoImage = imageMap['miso-controller'] || (options.registry ? buildImageRefFromRegistry('miso-controller', options.registry) : undefined);
70
- const keycloakRunOpts = { image: keycloakImage, registry: options.registry, registryMode: options.registryMode, skipEnvOutputPath: true, skipInfraCheck: true };
71
- const misoRunOpts = { image: misoImage, registry: options.registry, registryMode: options.registryMode, skipEnvOutputPath: true, skipInfraCheck: true };
48
+ const common = {
49
+ registry: options.registry,
50
+ registryMode: options.registryMode,
51
+ skipEnvOutputPath: true,
52
+ skipInfraCheck: true
53
+ };
54
+ const keycloakRunOpts = { ...common };
55
+ if (imageMap.keycloak) {
56
+ keycloakRunOpts.image = imageMap.keycloak;
57
+ }
58
+ const misoRunOpts = { ...common };
59
+ if (imageMap['miso-controller']) {
60
+ misoRunOpts.image = imageMap['miso-controller'];
61
+ }
72
62
  logger.log(chalk.blue('Starting keycloak...'));
73
63
  await app.runApp('keycloak', keycloakRunOpts);
74
64
  logger.log(chalk.blue('Starting miso-controller...'));
@@ -90,7 +80,7 @@ async function runMisoApps(options) {
90
80
  async function handleUpMiso(options = {}) {
91
81
  const builderDir = await config.getAifabrixBuilderDir();
92
82
  if (builderDir) {
93
- process.env.AIFABRIX_BUILDER_DIR = builderDir;
83
+ process.env.AIFABRIX_BUILDER_DIR = path.resolve(builderDir);
94
84
  }
95
85
  logger.log(chalk.blue('Starting up-miso (keycloak + miso-controller from images)...\n'));
96
86
  // Strict: only this developer's infra (same as status), so up-miso and status agree
@@ -99,7 +89,7 @@ async function handleUpMiso(options = {}) {
99
89
  if (!allHealthy) {
100
90
  throw new Error('Infrastructure is not up. Run \'aifabrix up-infra\' first.');
101
91
  }
102
- logger.log(chalk.green('Infrastructure is up'));
92
+ logger.log(formatSuccessLine('Infrastructure is up'));
103
93
  await ensureAppFromTemplate('keycloak');
104
94
  await ensureAppFromTemplate('miso-controller');
105
95
  // If envOutputPath target folder does not exist, set envOutputPath to null
@@ -109,7 +99,7 @@ async function handleUpMiso(options = {}) {
109
99
  patchEnvOutputPathForDeployOnly('keycloak');
110
100
  patchEnvOutputPathForDeployOnly('miso-controller');
111
101
  await runMisoApps(options);
112
- logger.log(chalk.green('\n✓ up-miso complete. Keycloak and miso-controller are running.') +
102
+ logger.log(formatSuccessParagraph('up-miso complete. Keycloak and miso-controller are running.') +
113
103
  chalk.gray('\n Run onboarding and register Keycloak from the miso-controller repo if needed. Use \'aifabrix up-dataplane\' for dataplane.'));
114
104
  }
115
105
 
@@ -1,7 +1,8 @@
1
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
- * Upload external system to dataplane (single pipeline upload: uploadvalidatepublish).
3
+ * Upload external system to dataplane (single pipeline upload: validatepublishcontroller register).
3
4
  *
4
- * @fileoverview Upload command handler for aifabrix upload <system-key>
5
+ * @fileoverview Upload command handler for aifabrix upload <systemKey>
5
6
  * @author AI Fabrix Team
6
7
  * @version 2.0.0
7
8
  */
@@ -21,9 +22,19 @@ const {
21
22
  const { validateExternalSystemComplete } = require('../validation/validate');
22
23
  const { displayValidationResults } = require('../validation/validate-display');
23
24
  const { generateControllerManifest } = require('../generator/external-controller-manifest');
24
- const { uploadApplicationViaPipeline } = require('../api/pipeline.api');
25
+ const {
26
+ uploadApplicationViaPipeline,
27
+ validatePipelineConfig,
28
+ testSystemViaPipeline
29
+ } = require('../api/pipeline.api');
25
30
  const { formatApiError } = require('../utils/api-error-handler');
26
31
  const { logDataplanePipelineWarning } = require('../utils/dataplane-pipeline-warning');
32
+ const { unwrapPublicationResult, unwrapApiData } = require('../utils/external-system-readiness-core');
33
+ const {
34
+ logUploadReadinessSummary,
35
+ logServerValidationWarnings,
36
+ logProbeRuntimeBlock
37
+ } = require('../utils/external-system-readiness-display');
27
38
 
28
39
  /**
29
40
  * Validates system-key format (same as download).
@@ -66,10 +77,10 @@ async function resolveDataplaneAndAuth(systemKey) {
66
77
  const authConfig = await getDeploymentAuth(controllerUrl, environment, systemKey);
67
78
 
68
79
  if (!authConfig.token && !authConfig.clientId) {
69
- throw new Error('Authentication required. Run "aifabrix login" or "aifabrix app register <system-key>" first.');
80
+ throw new Error('Authentication required. Run "aifabrix login" or "aifabrix app register <systemKey>" first.');
70
81
  }
71
82
 
72
- logger.log(chalk.blue('Resolving dataplane URL...'));
83
+ logger.log(chalk.gray('Resolving dataplane URL...'));
73
84
  const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
74
85
  return { dataplaneUrl, authConfig, environment };
75
86
  }
@@ -79,7 +90,7 @@ async function resolveDataplaneAndAuth(systemKey) {
79
90
  * @param {string} dataplaneUrl - Dataplane base URL
80
91
  * @param {Object} authConfig - Auth config
81
92
  * @param {Object} payload - { version, application, dataSources, status: "draft" }
82
- * @returns {Promise<Object>} Publication result from Dataplane
93
+ * @returns {Promise<Object>} Raw API response envelope
83
94
  */
84
95
  async function runUploadValidatePublish(dataplaneUrl, authConfig, payload) {
85
96
  const res = await uploadApplicationViaPipeline(dataplaneUrl, authConfig, payload);
@@ -91,9 +102,8 @@ async function runUploadValidatePublish(dataplaneUrl, authConfig, payload) {
91
102
  }
92
103
 
93
104
  /**
94
- * Builds a short summary of validation errors for the thrown message.
95
105
  * @param {Object} validationResult - Result from validateExternalSystemComplete
96
- * @returns {string} First few errors joined for the error message
106
+ * @returns {string}
97
107
  */
98
108
  function formatValidationErrorSummary(validationResult) {
99
109
  const errors = validationResult.errors || [];
@@ -108,7 +118,6 @@ function formatValidationErrorSummary(validationResult) {
108
118
  }
109
119
 
110
120
  /**
111
- * Throws if validation result is invalid (displays results first).
112
121
  * @param {Object} validationResult - Result from validateExternalSystemComplete
113
122
  * @throws {Error} If validationResult.valid is false
114
123
  */
@@ -162,52 +171,142 @@ async function pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey,
162
171
  }
163
172
 
164
173
  /**
165
- * Uploads external system to dataplane (single pipeline upload). No controller deploy.
166
- * @param {string} systemKey - External system key (integration/<system-key>/)
167
- * @param {Object} [options] - Options
168
- * @param {boolean} [options.dryRun] - Validate and build payload only; no API calls
169
- * @returns {Promise<void>}
170
- * @throws {Error} If validation or API calls fail
174
+ * Optional server-side pipeline validate when --verbose.
175
+ * @param {string} dataplaneUrl
176
+ * @param {Object} authConfig
177
+ * @param {Object} payload
171
178
  */
172
- async function uploadExternalSystem(systemKey, options = {}) {
173
- validateSystemKeyFormat(systemKey);
174
- logger.log(chalk.blue(`\nUploading external system to dataplane: ${systemKey}`));
179
+ async function maybeRunVerboseServerValidation(dataplaneUrl, authConfig, payload) {
180
+ const vr = await validatePipelineConfig(dataplaneUrl, authConfig, {
181
+ config: {
182
+ version: payload.version,
183
+ application: payload.application,
184
+ dataSources: payload.dataSources
185
+ }
186
+ });
187
+ if (vr?.success === false) {
188
+ throw new Error(formatApiError(vr, dataplaneUrl));
189
+ }
190
+ const body = unwrapApiData(vr);
191
+ logServerValidationWarnings(body);
192
+ }
175
193
 
194
+ /**
195
+ * Empty payload template for POST /validation/run: selects dataplane **payload test** path
196
+ * (per-datasource template / connectivity), not the full validation-engine run.
197
+ * Avoids false RBAC failures right after upload: engine security checks autoRbac vs
198
+ * `system.permissions[]` before the controller has synced permissions (deploy --probe
199
+ * still uses the engine path without payloadTemplate).
200
+ */
201
+ const UPLOAD_PROBE_TEST_DATA = { payloadTemplate: {} };
202
+
203
+ /**
204
+ * Optional POST validation/run after successful upload.
205
+ * @param {string} dataplaneUrl
206
+ * @param {string} systemKey
207
+ * @param {Object} authConfig
208
+ * @param {number|undefined} probeTimeoutMs
209
+ */
210
+ async function maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, probeTimeoutMs) {
211
+ logger.log(chalk.blue('\nRunning runtime checks (--probe)...'));
212
+ const timeoutMs = probeTimeoutMs === undefined || probeTimeoutMs === null ? 120000 : probeTimeoutMs;
213
+ try {
214
+ const pr = await testSystemViaPipeline(
215
+ dataplaneUrl,
216
+ systemKey,
217
+ authConfig,
218
+ UPLOAD_PROBE_TEST_DATA,
219
+ { timeout: timeoutMs }
220
+ );
221
+ if (pr.success === false) {
222
+ logger.log(chalk.yellow(`⚠ Probe request failed: ${pr.formattedError || pr.error || 'unknown error'}`));
223
+ return;
224
+ }
225
+ const probeData = unwrapApiData(pr);
226
+ logProbeRuntimeBlock(probeData, systemKey);
227
+ } catch (e) {
228
+ logger.log(chalk.yellow(`⚠ Probe failed: ${e.message}`));
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Local validation, manifest, payload, and configuration resolution.
234
+ * @param {string} systemKey
235
+ * @returns {Promise<{ manifest: Object, payload: Object }>}
236
+ */
237
+ async function buildValidatedUploadManifestPayload(systemKey) {
176
238
  const validationResult = await validateExternalSystemComplete(systemKey, { type: 'external' });
177
239
  throwIfValidationFailed(validationResult);
178
- logger.log(chalk.green('Validation passed.'));
179
-
240
+ logger.log(formatSuccessLine('Local validation passed'));
180
241
  const manifest = await generateControllerManifest(systemKey, { type: 'external' });
181
242
  const payload = buildUploadPayload(manifest);
182
243
  await resolvePayloadConfiguration(systemKey, payload);
244
+ return { manifest, payload };
245
+ }
183
246
 
184
- if (options.dryRun) {
185
- logger.log(chalk.yellow('Dry run: would upload payload (no API calls).'));
186
- logger.log(chalk.gray(` System: ${manifest.key}, version: ${payload.version}, datasources: ${payload.dataSources.length}`));
187
- return;
188
- }
189
-
247
+ /**
248
+ * Upload path after dry-run check.
249
+ * @param {string} systemKey
250
+ * @param {Object} options
251
+ * @param {Object} manifest
252
+ * @param {Object} payload
253
+ */
254
+ async function runUploadPublishAndSummary(systemKey, options, manifest, payload) {
190
255
  const { dataplaneUrl, authConfig, environment } = await resolveDataplaneAndAuth(systemKey);
191
256
  requireBearerForDataplanePipeline(authConfig);
192
- logger.log(chalk.blue(`Dataplane: ${dataplaneUrl}`));
257
+ logger.log(chalk.gray('Target:'));
258
+ logger.log(chalk.gray(`Environment: ${environment}`));
259
+ logger.log(chalk.gray(`Dataplane: ${dataplaneUrl}`));
193
260
  logDataplanePipelineWarning();
194
-
261
+ if (options.verbose) {
262
+ await maybeRunVerboseServerValidation(dataplaneUrl, authConfig, payload);
263
+ }
195
264
  await pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload);
196
- await runUploadValidatePublish(dataplaneUrl, authConfig, payload);
197
- logUploadSuccess(environment, systemKey, dataplaneUrl);
265
+ const rawRes = await runUploadValidatePublish(dataplaneUrl, authConfig, payload);
266
+ const publication = unwrapPublicationResult(rawRes);
267
+ if (!publication) {
268
+ throw new Error(
269
+ 'Unexpected response from dataplane upload: missing publication result (uploadId/system/datasources).'
270
+ );
271
+ }
272
+ logUploadReadinessSummary({
273
+ environment,
274
+ dataplaneUrl,
275
+ systemKey,
276
+ publication,
277
+ manifest,
278
+ minimal: !!options.minimal,
279
+ willProbe: !!options.probe
280
+ });
281
+ if (options.probe) {
282
+ await maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, options.probeTimeout);
283
+ }
198
284
  }
199
285
 
200
286
  /**
201
- * Logs upload success summary.
202
- * @param {string} environment - Environment key
203
- * @param {string} systemKey - System key
204
- * @param {string} dataplaneUrl - Dataplane URL
287
+ * Uploads external system: publishes to dataplane and registers with controller (draft).
288
+ * @param {string} systemKey - External system key (integration/<systemKey>/)
289
+ * @param {Object} [options] - Options
290
+ * @param {boolean} [options.dryRun] - Validate and build payload only; no API calls
291
+ * @param {boolean} [options.verbose] - POST pipeline/validate for server warnings
292
+ * @param {boolean} [options.probe] - POST validation/run after publish
293
+ * @param {number} [options.probeTimeout] - Probe timeout ms (default 120000)
294
+ * @param {boolean} [options.minimal] - Short summary only
295
+ * @returns {Promise<void>}
296
+ * @throws {Error} If validation or API calls fail
205
297
  */
206
- function logUploadSuccess(environment, systemKey, dataplaneUrl) {
207
- logger.log(chalk.green('\nUpload validated and published to dataplane.'));
208
- logger.log(chalk.blue(`Environment: ${environment}`));
209
- logger.log(chalk.blue(`System: ${systemKey}`));
210
- logger.log(chalk.blue(`Dataplane: ${dataplaneUrl}`));
298
+ async function uploadExternalSystem(systemKey, options = {}) {
299
+ validateSystemKeyFormat(systemKey);
300
+ logger.log(chalk.blue(`\nUploading external system: ${chalk.bold(systemKey)}`));
301
+ const { manifest, payload } = await buildValidatedUploadManifestPayload(systemKey);
302
+ if (options.dryRun) {
303
+ logger.log(chalk.yellow('Dry run: would upload payload (no API calls).'));
304
+ logger.log(
305
+ chalk.gray(` System: ${manifest.key}, version: ${payload.version}, datasources: ${payload.dataSources.length}`)
306
+ );
307
+ return;
308
+ }
309
+ await runUploadPublishAndSummary(systemKey, options, manifest, payload);
211
310
  }
212
311
 
213
312
  module.exports = {
@@ -308,7 +308,7 @@ function throwConfigGenerationError(generateResponse, options = {}) {
308
308
  }
309
309
 
310
310
  /**
311
- * Write debug log to integration/<appName>/debug.log
311
+ * Write debug log to integration/<systemKey>/debug.log
312
312
  * @async
313
313
  * @param {string} appName - Application name
314
314
  * @param {string} content - Debug log content
@@ -6,6 +6,7 @@
6
6
 
7
7
  const chalk = require('chalk');
8
8
  const logger = require('../utils/logger');
9
+ const { infoLine, formatSuccessLine } = require('../utils/cli-test-layout-chalk');
9
10
  const { getDataplaneUrl } = require('../datasource/deploy');
10
11
  const { listEnvironmentApplications } = require('../api/environments.api');
11
12
 
@@ -75,7 +76,7 @@ function createDataplaneNotFoundError() {
75
76
  async function tryFallbackDataplaneUrl(controllerUrl, environment, authConfig) {
76
77
  try {
77
78
  const fallbackUrl = await getDataplaneUrl(controllerUrl, 'dataplane', environment, authConfig);
78
- logger.log(chalk.green(`\u2713 Dataplane URL: ${fallbackUrl}`));
79
+ logger.log(formatSuccessLine(`Dataplane URL: ${fallbackUrl}`));
79
80
  return fallbackUrl;
80
81
  } catch (fallbackError) {
81
82
  if (isNotFoundError(fallbackError)) {
@@ -96,12 +97,12 @@ async function tryFallbackDataplaneUrl(controllerUrl, environment, authConfig) {
96
97
  * @throws {Error} If dataplane URL cannot be discovered
97
98
  */
98
99
  async function discoverDataplaneUrl(controllerUrl, environment, authConfig) {
99
- logger.log(chalk.blue('\uD83C\uDF10 Getting dataplane URL from controller...'));
100
+ logger.log(infoLine('🌐 Getting dataplane URL from controller...'));
100
101
  try {
101
102
  const dataplaneAppKey = await findDataplaneServiceAppKey(controllerUrl, environment, authConfig);
102
103
  if (dataplaneAppKey) {
103
104
  const dataplaneUrl = await getDataplaneUrl(controllerUrl, dataplaneAppKey, environment, authConfig);
104
- logger.log(chalk.green(`\u2713 Dataplane URL: ${dataplaneUrl}`));
105
+ logger.log(formatSuccessLine(`Dataplane URL: ${dataplaneUrl}`));
105
106
  return dataplaneUrl;
106
107
  }
107
108
  return await tryFallbackDataplaneUrl(controllerUrl, environment, authConfig);
@@ -117,9 +117,9 @@ function showWizardConfigSummary(config, displayPath) {
117
117
  }
118
118
 
119
119
  /**
120
- * Ensure integration/<appKey> directory exists
121
- * @param {string} appKey - Application key
122
- * @returns {Promise<string>} Resolved config path (integration/<appKey>/wizard.yaml)
120
+ * Ensure integration/<systemKey> directory exists
121
+ * @param {string} appKey - Integration folder name (system key)
122
+ * @returns {Promise<string>} Resolved config path (integration/<systemKey>/wizard.yaml)
123
123
  */
124
124
  async function ensureIntegrationDir(appKey) {
125
125
  const dir = path.join(process.cwd(), 'integration', appKey);
@@ -344,7 +344,7 @@ async function executeWizardFlow(appKey, dataplaneUrl, authConfig, flowOpts = {}
344
344
 
345
345
  /**
346
346
  * Load wizard config from configPath if it exists (for prefill)
347
- * @param {string} [configPath] - Path to wizard.yaml (e.g. integration/<app>/wizard.yaml)
347
+ * @param {string} [configPath] - Path to wizard.yaml (e.g. integration/<systemKey>/wizard.yaml)
348
348
  * @param {string} [appName] - App name (for log message)
349
349
  * @returns {Promise<Object|null>} Loaded config or null
350
350
  */
@@ -441,7 +441,7 @@ async function handleWizardError(appKey, configPath, mode, systemIdOrKey, error)
441
441
  * @param {Object} options - Command options
442
442
  * @param {string} [options.app] - Application name (from positional or -a)
443
443
  * @param {string} [options.config] - Path to wizard.yaml (headless mode)
444
- * @param {string} [options.configPath] - Resolved path integration/<app>/wizard.yaml for load/save
444
+ * @param {string} [options.configPath] - Resolved path integration/<systemKey>/wizard.yaml for load/save
445
445
  * @returns {Promise<void>} Resolves when wizard completes
446
446
  * @throws {Error} If wizard fails (wizardResumeMessage set when appKey known)
447
447
  */
@@ -11,9 +11,10 @@
11
11
  'use strict';
12
12
 
13
13
  const path = require('path');
14
- const fs = require('fs');
14
+ const fsRealSync = require('../internal/fs-real-sync');
15
15
  const config = require('./config');
16
16
  const { decryptSecret, isEncrypted } = require('../utils/secrets-encryption');
17
+ const { ensureSecureFilePermissions } = require('../utils/secure-file-permissions');
17
18
 
18
19
  /**
19
20
  * Parse .env-style content into key-value map (excludes comments and empty lines).
@@ -47,17 +48,27 @@ function parseAdminEnvContent(content) {
47
48
  * Use the returned object only in memory (e.g. to build a temporary .env for docker compose).
48
49
  *
49
50
  * @async
50
- * @param {string} [adminSecretsPath] - Path to admin-secrets.env; default: ~/.aifabrix/admin-secrets.env
51
+ * @param {string} [adminSecretsPath] - Path to admin-secrets.env; default: beside config.yaml (typically ~/.aifabrix), with legacy fallback under aifabrix-home when only that file exists
51
52
  * @returns {Promise<Object.<string, string>>} Plain object e.g. { POSTGRES_PASSWORD, PGADMIN_DEFAULT_EMAIL, ... }
52
53
  * @throws {Error} If file missing, or encrypted value and decryption fails / no key configured
53
54
  */
54
55
  async function readAndDecryptAdminSecrets(adminSecretsPath) {
55
56
  const pathsUtil = require('../utils/paths');
56
- const resolvedPath = adminSecretsPath || path.join(pathsUtil.getAifabrixHome(), 'admin-secrets.env');
57
- if (!fs.existsSync(resolvedPath)) {
57
+ let resolvedPath = adminSecretsPath;
58
+ if (!resolvedPath) {
59
+ const systemPath = path.join(pathsUtil.getAifabrixSystemDir(), 'admin-secrets.env');
60
+ const legacyPath = path.join(pathsUtil.getAifabrixHome(), 'admin-secrets.env');
61
+ resolvedPath = fsRealSync.existsSync(systemPath)
62
+ ? systemPath
63
+ : fsRealSync.existsSync(legacyPath)
64
+ ? legacyPath
65
+ : systemPath;
66
+ }
67
+ if (!fsRealSync.existsSync(resolvedPath)) {
58
68
  throw new Error(`Admin secrets file not found: ${resolvedPath}. Run 'aifabrix up-infra' or ensure admin-secrets.env exists.`);
59
69
  }
60
- const content = fs.readFileSync(resolvedPath, 'utf8');
70
+ ensureSecureFilePermissions(resolvedPath);
71
+ const content = fsRealSync.readFileSync(resolvedPath, 'utf8');
61
72
  const raw = parseAdminEnvContent(content);
62
73
  const encryptionKey = await config.getSecretsEncryptionKey();
63
74
  const out = {};
@@ -16,12 +16,12 @@ const path = require('path');
16
16
  const os = require('os');
17
17
  const paths = require('../utils/paths');
18
18
 
19
- // Audit log file path (in user's home directory for compliance)
19
+ // Audit log file path (beside config.yaml / CLI system dir for compliance)
20
20
  let auditLogPath = null;
21
21
 
22
22
  /**
23
23
  * Gets the audit log file path
24
- * Creates .aifabrix directory in user's home if it doesn't exist
24
+ * Creates config / system directory if it doesn't exist
25
25
  * @returns {Promise<string>} Path to audit log file
26
26
  */
27
27
  async function getAuditLogPath() {
@@ -29,7 +29,7 @@ async function getAuditLogPath() {
29
29
  return auditLogPath;
30
30
  }
31
31
 
32
- const aifabrixDir = paths.getAifabrixHome();
32
+ const aifabrixDir = paths.getAifabrixSystemDir();
33
33
 
34
34
  try {
35
35
  await fs.mkdir(aifabrixDir, { recursive: true });
@@ -336,6 +336,13 @@ function extractPathFromUrl(url) {
336
336
  }
337
337
  }
338
338
 
339
+ /**
340
+ * Clears cached audit log path (for tests that vary getAifabrixSystemDir between calls).
341
+ */
342
+ function resetAuditLogPathCache() {
343
+ auditLogPath = null;
344
+ }
345
+
339
346
  module.exports = {
340
347
  auditLog,
341
348
  logDeploymentAttempt,
@@ -345,6 +352,7 @@ module.exports = {
345
352
  logApplicationCreation,
346
353
  logApiCall,
347
354
  maskSensitiveData,
348
- createAuditEntry
355
+ createAuditEntry,
356
+ resetAuditLogPathCache
349
357
  };
350
358