@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
@@ -10,9 +10,12 @@
10
10
  */
11
11
 
12
12
  const Ajv = require('ajv');
13
+ const addFormats = require('ajv-formats');
13
14
  const fs = require('fs');
14
15
  const path = require('path');
15
16
  const { formatValidationErrors } = require('../utils/error-formatter');
17
+ const { validateFieldReferences } = require('../datasource/field-reference-validator');
18
+ const { validateAbac } = require('../datasource/abac-validator');
16
19
 
17
20
  /**
18
21
  * Sets up AJV validator with external schemas
@@ -26,6 +29,7 @@ async function setupAjvWithSchemas() {
26
29
  strict: false,
27
30
  removeAdditional: false
28
31
  });
32
+ addFormats(ajv);
29
33
 
30
34
  // Load raw schema objects (not compiled validators)
31
35
  const externalSystemSchemaPath = path.join(__dirname, '..', 'schema', 'external-system.schema.json');
@@ -41,11 +45,20 @@ async function setupAjvWithSchemas() {
41
45
  externalDatasourceSchema = schemaCopy;
42
46
  }
43
47
 
44
- const externalSystemSchemaId = externalSystemSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-system.schema.json';
45
- const externalDatasourceSchemaId = externalDatasourceSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-datasource.schema.json';
48
+ if (!externalSystemSchema.$id || typeof externalSystemSchema.$id !== 'string') {
49
+ throw new Error('External system schema is missing required $id');
50
+ }
51
+ if (!externalDatasourceSchema.$id || typeof externalDatasourceSchema.$id !== 'string') {
52
+ throw new Error('External datasource schema is missing required $id');
53
+ }
46
54
 
47
- ajv.addSchema(externalSystemSchema, externalSystemSchemaId);
48
- ajv.addSchema(externalDatasourceSchema, externalDatasourceSchemaId);
55
+ // external-datasource.schema.json references these by $id (aifabrix://schema/type/*)
56
+ ajv.addSchema(require('../schema/type/document-storage.json'));
57
+ ajv.addSchema(require('../schema/type/message-service.json'));
58
+ ajv.addSchema(require('../schema/type/vector-store.json'));
59
+
60
+ ajv.addSchema(externalSystemSchema, externalSystemSchema.$id);
61
+ ajv.addSchema(externalDatasourceSchema, externalDatasourceSchema.$id);
49
62
 
50
63
  return { ajv, externalSystemSchema, externalDatasourceSchema };
51
64
  }
@@ -64,7 +77,10 @@ function validateManifestStructure(manifest, ajv, applicationSchema, errors) {
64
77
  const manifestValid = validateManifest(manifest);
65
78
 
66
79
  if (!manifestValid) {
67
- const manifestErrors = formatValidationErrors(validateManifest.errors);
80
+ const manifestErrors = formatValidationErrors(validateManifest.errors, {
81
+ rootData: manifest,
82
+ deploymentManifest: manifest
83
+ });
68
84
  errors.push(...manifestErrors.map(err => `Manifest validation: ${err}`));
69
85
  }
70
86
  }
@@ -84,7 +100,10 @@ function validateInlineSystem(manifest, ajv, externalSystemSchema, errors) {
84
100
  const systemValid = validateSystem(manifest.system);
85
101
 
86
102
  if (!systemValid) {
87
- const systemErrors = formatValidationErrors(validateSystem.errors);
103
+ const systemErrors = formatValidationErrors(validateSystem.errors, {
104
+ rootData: manifest.system,
105
+ deploymentManifest: manifest.system
106
+ });
88
107
  errors.push(...systemErrors.map(err => `System validation: ${err}`));
89
108
  }
90
109
  } else if (manifest.type === 'external') {
@@ -111,8 +130,17 @@ function validateDatasources(manifest, ajv, externalDatasourceSchema, errors, wa
111
130
  manifest.dataSources.forEach((datasource, index) => {
112
131
  const datasourceValid = validateDatasource(datasource);
113
132
  if (!datasourceValid) {
114
- const datasourceErrors = formatValidationErrors(validateDatasource.errors);
133
+ const datasourceErrors = formatValidationErrors(validateDatasource.errors, {
134
+ rootData: datasource,
135
+ deploymentManifest: datasource
136
+ });
115
137
  errors.push(...datasourceErrors.map(err => `Datasource ${index + 1} (${datasource.key || 'unknown'}): ${err}`));
138
+ } else {
139
+ const fieldRefErrors = validateFieldReferences(datasource);
140
+ const abacErrors = validateAbac(datasource);
141
+ const prefix = `Datasource ${index + 1} (${datasource.key || 'unknown'}): `;
142
+ fieldRefErrors.forEach(e => errors.push(prefix + e));
143
+ abacErrors.forEach(e => errors.push(prefix + e));
116
144
  }
117
145
  });
118
146
  }
@@ -1,3 +1,4 @@
1
+ const { formatBlockingError, formatSuccessLine, formatSuccessParagraph } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * Validation Display Utilities
3
4
  *
@@ -25,9 +26,9 @@ function displayApplicationValidation(application) {
25
26
 
26
27
  logger.log(chalk.blue('\nApplication:'));
27
28
  if (application.valid) {
28
- logger.log(chalk.green(' Application configuration is valid'));
29
+ logger.log(chalk.green(' Application configuration is valid'));
29
30
  } else {
30
- logger.log(chalk.red(' Application configuration has errors:'));
31
+ logger.log(chalk.red(' Application configuration has errors:'));
31
32
  if (application.errors && application.errors.length > 0) {
32
33
  application.errors.forEach(error => {
33
34
  logger.log(chalk.red(` • ${error}`));
@@ -51,12 +52,17 @@ function extractDimensionsFromDatasource(filePath) {
51
52
  try {
52
53
  const parsed = loadConfigFile(filePath);
53
54
 
54
- // Check fieldMappings.dimensions (primary location)
55
- const dimensions = parsed.fieldMappings?.dimensions || {};
55
+ const rootFlat = {};
56
+ const root = parsed.dimensions;
57
+ if (root && typeof root === 'object' && !Array.isArray(root)) {
58
+ for (const [dimKey, binding] of Object.entries(root)) {
59
+ if (binding && typeof binding === 'object' && typeof binding.field === 'string') {
60
+ rootFlat[dimKey] = `metadata.${binding.field}`;
61
+ }
62
+ }
63
+ }
56
64
  const abacDimensions = parsed.abac?.dimensions || {};
57
-
58
- // Merge both sources (abac.dimensions can override fieldMappings.dimensions)
59
- const allDimensions = { ...dimensions, ...abacDimensions };
65
+ const allDimensions = { ...rootFlat, ...abacDimensions };
60
66
  const dimensionKeys = Object.keys(allDimensions);
61
67
 
62
68
  return {
@@ -82,9 +88,9 @@ function displayExternalFilesValidation(externalFiles) {
82
88
  logger.log(chalk.blue('\nExternal Integration Files:'));
83
89
  externalFiles.forEach(file => {
84
90
  if (file.valid) {
85
- logger.log(chalk.green(` ${file.file} (${file.type})`));
91
+ logger.log(chalk.green(` ${file.file} (${file.type})`));
86
92
  } else {
87
- logger.log(chalk.red(` ${file.file} (${file.type}):`));
93
+ logger.log(chalk.red(` ${file.file} (${file.type}):`));
88
94
  file.errors.forEach(error => {
89
95
  logger.log(chalk.red(` • ${error}`));
90
96
  });
@@ -126,7 +132,7 @@ function displayDimensionsValidation(externalFiles) {
126
132
 
127
133
  if (dimensionsInfo.hasDimensions) {
128
134
  anyDatasourceHasDimensions = true;
129
- logger.log(chalk.green(` ${file.file}`));
135
+ logger.log(chalk.green(` ${file.file}`));
130
136
  dimensionsInfo.dimensionKeys.forEach(key => {
131
137
  const mapping = dimensionsInfo.dimensions[key];
132
138
  logger.log(chalk.gray(` ${key} → ${mapping}`));
@@ -156,9 +162,9 @@ function displayRbacValidation(rbac) {
156
162
 
157
163
  logger.log(chalk.blue('\nRBAC Configuration:'));
158
164
  if (rbac.valid) {
159
- logger.log(chalk.green(' RBAC configuration is valid'));
165
+ logger.log(chalk.green(' RBAC configuration is valid'));
160
166
  } else {
161
- logger.log(chalk.red(' RBAC configuration has errors:'));
167
+ logger.log(chalk.red(' RBAC configuration has errors:'));
162
168
  rbac.errors.forEach(error => {
163
169
  logger.log(chalk.red(` • ${error}`));
164
170
  });
@@ -183,9 +189,9 @@ function displayFileValidation(result) {
183
189
  logger.log(chalk.blue(`\nFile: ${result.file}`));
184
190
  logger.log(chalk.blue(`Type: ${result.type}`));
185
191
  if (result.valid) {
186
- logger.log(chalk.green(' File is valid'));
192
+ logger.log(chalk.green(' File is valid'));
187
193
  } else {
188
- logger.log(chalk.red(' File has errors:'));
194
+ logger.log(chalk.red(' File has errors:'));
189
195
  result.errors.forEach(error => {
190
196
  logger.log(chalk.red(` • ${error}`));
191
197
  });
@@ -222,9 +228,9 @@ function displayAggregatedWarnings(warnings) {
222
228
  function displayApplicationStep(application) {
223
229
  logger.log(chalk.blue('\nApplication:'));
224
230
  if (application.valid) {
225
- logger.log(chalk.green(' Application configuration is valid'));
231
+ logger.log(chalk.green(' Application configuration is valid'));
226
232
  } else {
227
- logger.log(chalk.red(' Application configuration has errors:'));
233
+ logger.log(chalk.red(' Application configuration has errors:'));
228
234
  application.errors.forEach(error => {
229
235
  logger.log(chalk.red(` • ${error}`));
230
236
  });
@@ -253,9 +259,9 @@ function displayComponentsStep(components) {
253
259
  if (hasFiles) {
254
260
  components.files.forEach(file => {
255
261
  if (file.valid) {
256
- logger.log(chalk.green(` ${file.file} (${file.type})`));
262
+ logger.log(chalk.green(` ${file.file} (${file.type})`));
257
263
  } else {
258
- logger.log(chalk.red(` ${file.file} (${file.type})`));
264
+ logger.log(chalk.red(` ${file.file} (${file.type})`));
259
265
  }
260
266
  });
261
267
  }
@@ -282,7 +288,7 @@ function displayDimensionsStep(datasourceFiles) {
282
288
  try {
283
289
  const dimensionsInfo = extractDimensionsFromDatasource(file.path || file.file);
284
290
  if (dimensionsInfo.hasDimensions) {
285
- logger.log(chalk.green(` ${file.file}`));
291
+ logger.log(chalk.green(` ${file.file}`));
286
292
  dimensionsInfo.dimensionKeys.forEach(key => {
287
293
  const mapping = dimensionsInfo.dimensions[key];
288
294
  logger.log(chalk.gray(` ${key} → ${mapping}`));
@@ -308,15 +314,15 @@ function displayManifestStep(manifest, componentFiles) {
308
314
  if (manifest.skipped) {
309
315
  logger.log(chalk.yellow(' ⊘ Skipped (fix errors above first)'));
310
316
  } else if (manifest.valid) {
311
- logger.log(chalk.green(' Full deployment manifest is valid'));
317
+ logger.log(chalk.green(' Full deployment manifest is valid'));
312
318
  if (componentFiles) {
313
319
  const datasourceFiles = componentFiles.filter(f => f.type === 'datasource' || f.type === 'external-datasource');
314
- logger.log(chalk.green(' System configuration valid'));
315
- logger.log(chalk.green(` ${datasourceFiles.length} datasource(s) valid`));
316
- logger.log(chalk.green(' Schema validation passed'));
320
+ logger.log(chalk.green(' System configuration valid'));
321
+ logger.log(chalk.green(` ${datasourceFiles.length} datasource(s) valid`));
322
+ logger.log(chalk.green(' Schema validation passed'));
317
323
  }
318
324
  } else {
319
- logger.log(chalk.red(' Full deployment manifest validation failed:'));
325
+ logger.log(chalk.red(' Full deployment manifest validation failed:'));
320
326
  const errs = manifest.errors && manifest.errors.length > 0 ? manifest.errors : [];
321
327
  if (errs.length > 0) {
322
328
  errs.forEach(error => {
@@ -341,9 +347,9 @@ function displayManifestStep(manifest, componentFiles) {
341
347
  */
342
348
  function displayStepByStepValidation(result) {
343
349
  if (result.valid) {
344
- logger.log(chalk.green('\n✓ Validation passed!'));
350
+ logger.log(formatSuccessParagraph('Validation passed!'));
345
351
  } else {
346
- logger.log(chalk.red('\n Validation failed!'));
352
+ logger.log(chalk.red('\n Validation failed!'));
347
353
  }
348
354
 
349
355
  displayApplicationStep(result.steps.application);
@@ -388,7 +394,7 @@ function displayBatchValidationResults(batchResult) {
388
394
  results.forEach(item => {
389
395
  logger.log(chalk.blue(`\n--- ${item.appName} ---`));
390
396
  if (item.error) {
391
- logger.log(chalk.red(` ${item.error}`));
397
+ logger.log(chalk.red(` ${item.error}`));
392
398
  } else if (item.result) {
393
399
  displayValidationResults(item.result);
394
400
  }
@@ -398,10 +404,10 @@ function displayBatchValidationResults(batchResult) {
398
404
  const failed = results.length - passed;
399
405
  logger.log(chalk.blue('\n--- Summary ---'));
400
406
  if (failed === 0) {
401
- logger.log(chalk.green(`✓ ${passed} passed, 0 failed`));
407
+ logger.log(formatSuccessLine(`${passed} passed, 0 failed`));
402
408
  logger.log(chalk.green('Overall: Passed'));
403
409
  } else {
404
- logger.log(chalk.red(`✗ ${passed} passed, ${failed} failed`));
410
+ logger.log(formatBlockingError(`${passed} passed, ${failed} failed`));
405
411
  logger.log(chalk.red('Overall: Failed'));
406
412
  }
407
413
  }
@@ -445,9 +451,9 @@ function displayValidationResults(result) {
445
451
 
446
452
  // Legacy format (for regular apps)
447
453
  if (result.valid) {
448
- logger.log(chalk.green('\n✓ Validation passed!'));
454
+ logger.log(formatSuccessParagraph('Validation passed!'));
449
455
  } else {
450
- logger.log(chalk.red('\n Validation failed!'));
456
+ logger.log(chalk.red('\n Validation failed!'));
451
457
  }
452
458
 
453
459
  displayApplicationValidation(result.application);
@@ -15,6 +15,8 @@ const validator = require('./validator');
15
15
  const { resolveExternalFiles } = require('../utils/schema-resolver');
16
16
  const { loadExternalSystemSchema, loadExternalDataSourceSchema, detectSchemaType } = require('../utils/schema-loader');
17
17
  const { formatValidationErrors } = require('../utils/error-formatter');
18
+ const { validateFieldReferences } = require('../datasource/field-reference-validator');
19
+ const { validateAbac } = require('../datasource/abac-validator');
18
20
  const { detectAppType } = require('../utils/paths');
19
21
  const batch = require('./validate-batch');
20
22
  const { logOfflinePathWhenType } = require('../utils/cli-utils');
@@ -102,15 +104,6 @@ function aggregateValidationResults(appValidation, externalValidations, rbacVali
102
104
  };
103
105
  }
104
106
 
105
- /**
106
- * Validates a single external file against its schema
107
- *
108
- * @async
109
- * @function validateExternalFile
110
- * @param {string} filePath - Path to the file
111
- * @param {string} type - File type: 'system' | 'datasource'
112
- * @returns {Promise<Object>} Validation result
113
- */
114
107
  /**
115
108
  * Parses external system/datasource file content (JSON or YAML).
116
109
  * @function parseJsonFileContent
@@ -177,6 +170,7 @@ function validateRoleReferences(parsed, errors) {
177
170
  });
178
171
  }
179
172
 
173
+ /** @async */
180
174
  async function validateExternalFile(filePath, type) {
181
175
  if (!fs.existsSync(filePath)) {
182
176
  throw new Error(`File not found: ${filePath}`);
@@ -200,6 +194,12 @@ async function validateExternalFile(filePath, type) {
200
194
  validateConfigurationNoStandardAuthVariables(parseResult.parsed, errors);
201
195
  }
202
196
 
197
+ if (normalizedType === 'datasource') {
198
+ const { collectExternalDatasourceWarnings } = require('./datasource-warnings');
199
+ errors.push(...validateFieldReferences(parseResult.parsed), ...validateAbac(parseResult.parsed));
200
+ warnings.push(...collectExternalDatasourceWarnings(parseResult.parsed));
201
+ }
202
+
203
203
  return {
204
204
  valid: errors.length === 0,
205
205
  errors,
@@ -489,4 +489,3 @@ module.exports = {
489
489
  validateAll: (opts = {}) => batch.validateAll(validateAppOrFile, opts),
490
490
  buildBatchResult: batch.buildBatchResult
491
491
  };
492
-
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Scan deployment/config objects for unresolved ${VAR} placeholders (validator helper).
3
+ *
4
+ * @fileoverview Extracted from validator.js for ESLint max-lines
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ /** Pattern matching ${VAR} style unresolved variables in strings */
12
+ const UNRESOLVED_VAR_REGEX = /\$\{[^}]+\}/g;
13
+
14
+ /** Allowed manifest placeholders in frontDoorRouting.host (expanded at run/resolve time; plan 122). */
15
+ const FRONT_DOOR_HOST_ALLOWED = /\$\{DEV_USERNAME\}|\$\{REMOTE_HOST\}/g;
16
+
17
+ /**
18
+ * First ${...} still present after stripping allowed DEV_USERNAME / REMOTE_HOST segments, or null.
19
+ * @param {string} str
20
+ * @returns {string|null}
21
+ */
22
+ function getFrontDoorHostFirstForbiddenPlaceholder(str) {
23
+ let t = String(str).trim();
24
+ t = t.replace(FRONT_DOOR_HOST_ALLOWED, '');
25
+ t = t.replace(/^\.+|\.+$/g, '').trim();
26
+ const m = t.match(UNRESOLVED_VAR_REGEX);
27
+ return m ? m[0] : null;
28
+ }
29
+
30
+ /**
31
+ * @param {string} obj
32
+ * @param {string} prefix
33
+ * @returns {string[]}
34
+ */
35
+ function collectStringUnresolved(obj, prefix) {
36
+ if (prefix === 'frontDoorRouting.host') {
37
+ const bad = getFrontDoorHostFirstForbiddenPlaceholder(obj);
38
+ return bad ? [`${prefix}: ${bad}`] : [];
39
+ }
40
+ const matches = obj.match(UNRESOLVED_VAR_REGEX);
41
+ if (matches && matches.length > 0) {
42
+ const pathLabel = prefix || 'value';
43
+ return [`${pathLabel}: ${matches[0]}`];
44
+ }
45
+ return [];
46
+ }
47
+
48
+ /**
49
+ * Recursively finds all string values in obj that contain ${...} placeholders.
50
+ *
51
+ * @param {Object} obj - Object to scan (e.g. deployment manifest)
52
+ * @param {string} [prefix=''] - Path prefix for error reporting
53
+ * @returns {string[]} List of paths with example placeholder (e.g. "port: ${PORT}")
54
+ */
55
+ function findUnresolvedVariablesInObject(obj, prefix = '') {
56
+ const found = [];
57
+ if (obj === null || obj === undefined) {
58
+ return found;
59
+ }
60
+ if (typeof obj === 'string') {
61
+ return collectStringUnresolved(obj, prefix);
62
+ }
63
+ if (Array.isArray(obj)) {
64
+ obj.forEach((item, i) => {
65
+ found.push(...findUnresolvedVariablesInObject(item, `${prefix}[${i}]`));
66
+ });
67
+ return found;
68
+ }
69
+ if (typeof obj === 'object') {
70
+ for (const [key, value] of Object.entries(obj)) {
71
+ const path = prefix ? `${prefix}.${key}` : key;
72
+ found.push(...findUnresolvedVariablesInObject(value, path));
73
+ }
74
+ return found;
75
+ }
76
+ return found;
77
+ }
78
+
79
+ /**
80
+ * Validates that deployment manifest contains no unresolved ${...} variables.
81
+ * @param {Object} deployment - Deployment manifest object
82
+ * @throws {Error} If any ${...} placeholders are found
83
+ */
84
+ function validateNoUnresolvedVariablesInDeployment(deployment) {
85
+ const unresolved = findUnresolvedVariablesInObject(deployment);
86
+ if (unresolved.length > 0) {
87
+ const examples = [...new Set(unresolved)].slice(0, 5).join(', ');
88
+ throw new Error(
89
+ `Deployment manifest contains unresolved variables (e.g. ${examples}). ` +
90
+ 'Use secret variables (kv://) in env.template for sensitive values, and set the application port as a number in application.yaml.'
91
+ );
92
+ }
93
+ }
94
+
95
+ module.exports = {
96
+ findUnresolvedVariablesInObject,
97
+ validateNoUnresolvedVariablesInDeployment
98
+ };
@@ -11,17 +11,17 @@
11
11
 
12
12
  const fs = require('fs');
13
13
  const path = require('path');
14
- const yaml = require('js-yaml');
15
14
  const Ajv = require('ajv');
15
+ const addFormats = require('ajv-formats');
16
16
  const applicationSchema = require('../schema/application-schema.json');
17
17
  const externalSystemSchema = require('../schema/external-system.schema.json');
18
18
  const externalDataSourceSchema = require('../schema/external-datasource.schema.json');
19
19
  const { transformVariablesForValidation } = require('../utils/variable-transformer');
20
20
  const { checkEnvironment } = require('../utils/environment-checker');
21
21
  const { formatValidationErrors } = require('../utils/error-formatter');
22
- const { detectAppType, resolveApplicationConfigPath } = require('../utils/paths');
22
+ const { detectAppType, resolveApplicationConfigPath, resolveRbacPath } = require('../utils/paths');
23
23
  const { loadConfigFile } = require('../utils/config-format');
24
- const { validateAuthKvCoverage } = require('./env-template-auth');
24
+ const { validateAuthKvCoverage, validateAuthSecurityPathConsistency } = require('./env-template-auth');
25
25
  const { validateKvReferencesInLines } = require('./env-template-kv');
26
26
 
27
27
  /**
@@ -58,7 +58,8 @@ async function loadVariablesYaml(appName, options = {}) {
58
58
  * @returns {Function} Compiled validator function
59
59
  */
60
60
  function setupAjvValidator() {
61
- const ajv = new Ajv({ allErrors: true, strict: false });
61
+ const ajv = new Ajv({ allErrors: true, strict: false, verbose: true });
62
+ addFormats(ajv);
62
63
  const externalSystemSchemaCopy = { ...externalSystemSchema };
63
64
  const externalDataSourceSchemaCopy = { ...externalDataSourceSchema };
64
65
 
@@ -66,6 +67,11 @@ function setupAjvValidator() {
66
67
  delete externalDataSourceSchemaCopy.$schema;
67
68
  }
68
69
 
70
+ // external-datasource.schema.json references these by $id (aifabrix://schema/type/*)
71
+ ajv.addSchema(require('../schema/type/document-storage.json'));
72
+ ajv.addSchema(require('../schema/type/message-service.json'));
73
+ ajv.addSchema(require('../schema/type/vector-store.json'));
74
+
69
75
  ajv.addSchema(externalSystemSchemaCopy, externalSystemSchema.$id);
70
76
  ajv.addSchema(externalDataSourceSchemaCopy, externalDataSourceSchema.$id);
71
77
  return ajv.compile(applicationSchema);
@@ -155,7 +161,7 @@ async function validateVariables(appName, options = {}) {
155
161
  function validateRoles(roles) {
156
162
  const errors = [];
157
163
  if (!roles || !Array.isArray(roles)) {
158
- errors.push('rbac.yaml must contain a "roles" array');
164
+ errors.push('rbac file must contain a "roles" array');
159
165
  return errors;
160
166
  }
161
167
 
@@ -179,7 +185,7 @@ function validateRoles(roles) {
179
185
  function validatePermissions(permissions) {
180
186
  const errors = [];
181
187
  if (!permissions || !Array.isArray(permissions)) {
182
- errors.push('rbac.yaml must contain a "permissions" array');
188
+ errors.push('rbac file must contain a "permissions" array');
183
189
  return errors;
184
190
  }
185
191
 
@@ -203,21 +209,18 @@ async function validateRbac(appName, options = {}) {
203
209
 
204
210
  // Support both builder/ and integration/ directories using detectAppType
205
211
  const { appPath } = await detectAppType(appName, options);
206
- const rbacYaml = path.join(appPath, 'rbac.yaml');
207
- const rbacYml = path.join(appPath, 'rbac.yml');
208
- const rbacPath = fs.existsSync(rbacYaml) ? rbacYaml : (fs.existsSync(rbacYml) ? rbacYml : null);
212
+ const rbacPath = resolveRbacPath(appPath);
209
213
 
210
214
  if (!rbacPath) {
211
- return { valid: true, errors: [], warnings: ['rbac.yaml not found - authentication disabled'] };
215
+ return { valid: true, errors: [], warnings: ['rbac file not found - authentication disabled'] };
212
216
  }
213
217
 
214
- const content = fs.readFileSync(rbacPath, 'utf8');
215
218
  let rbac;
216
-
217
219
  try {
218
- rbac = yaml.load(content);
220
+ rbac = loadConfigFile(rbacPath);
219
221
  } catch (error) {
220
- throw new Error(`Invalid YAML syntax in rbac.yaml: ${error.message}`);
222
+ const basename = path.basename(rbacPath);
223
+ throw new Error(`Invalid syntax in ${basename}: ${error.message}`);
221
224
  }
222
225
 
223
226
  const errors = [
@@ -287,6 +290,7 @@ async function validateEnvTemplate(appName, options = {}) {
287
290
 
288
291
  if (isExternal) {
289
292
  await validateAuthKvCoverage(appPath, content, errors, warnings, options);
293
+ await validateAuthSecurityPathConsistency(appPath, errors, warnings);
290
294
  }
291
295
 
292
296
  return {
@@ -344,7 +348,8 @@ function validateDeploymentJson(deployment) {
344
348
 
345
349
  // verbose: true includes the actual data value in error objects for better error messages
346
350
  const ajv = new Ajv({ allErrors: true, strict: false, verbose: true });
347
- // Register external schemas with their $id (GitHub raw URLs)
351
+ addFormats(ajv);
352
+ // Register external schemas with their $id
348
353
  // Create copies to avoid modifying the original schemas
349
354
  const externalSystemSchemaCopy = { ...externalSystemSchema };
350
355
  const externalDataSourceSchemaCopy = { ...externalDataSourceSchema };
@@ -352,6 +357,10 @@ function validateDeploymentJson(deployment) {
352
357
  if (externalDataSourceSchemaCopy.$schema && externalDataSourceSchemaCopy.$schema.includes('2020-12')) {
353
358
  delete externalDataSourceSchemaCopy.$schema;
354
359
  }
360
+ // external-datasource.schema.json references these by $id (aifabrix://schema/type/*)
361
+ ajv.addSchema(require('../schema/type/document-storage.json'));
362
+ ajv.addSchema(require('../schema/type/message-service.json'));
363
+ ajv.addSchema(require('../schema/type/vector-store.json'));
355
364
  ajv.addSchema(externalSystemSchemaCopy, externalSystemSchema.$id);
356
365
  ajv.addSchema(externalDataSourceSchemaCopy, externalDataSourceSchema.$id);
357
366
  const validate = ajv.compile(applicationSchema);
@@ -359,72 +368,17 @@ function validateDeploymentJson(deployment) {
359
368
 
360
369
  return {
361
370
  valid,
362
- errors: valid ? [] : formatValidationErrors(validate.errors)
371
+ errors: valid ? [] : formatValidationErrors(validate.errors, {
372
+ deploymentManifest: deployment,
373
+ rootData: deployment
374
+ })
363
375
  };
364
376
  }
365
377
 
366
- /** Pattern matching ${VAR} style unresolved variables in strings */
367
- const UNRESOLVED_VAR_REGEX = /\$\{[^}]+\}/g;
368
-
369
- /**
370
- * Recursively finds all string values in obj that contain ${...} placeholders.
371
- * Used to ensure deployment manifest has no unresolved variables before deploy.
372
- *
373
- * @function findUnresolvedVariablesInObject
374
- * @param {Object} obj - Object to scan (e.g. deployment manifest)
375
- * @param {string} [prefix=''] - Path prefix for error reporting
376
- * @returns {string[]} List of paths with example placeholder (e.g. "port: ${PORT}")
377
- *
378
- * @example
379
- * findUnresolvedVariablesInObject({ port: '${PORT}' }) // ['port: ${PORT}']
380
- */
381
- function findUnresolvedVariablesInObject(obj, prefix = '') {
382
- const found = [];
383
- if (obj === null || obj === undefined) {
384
- return found;
385
- }
386
- if (typeof obj === 'string') {
387
- const matches = obj.match(UNRESOLVED_VAR_REGEX);
388
- if (matches && matches.length > 0) {
389
- const pathLabel = prefix || 'value';
390
- found.push(`${pathLabel}: ${matches[0]}`);
391
- }
392
- return found;
393
- }
394
- if (Array.isArray(obj)) {
395
- obj.forEach((item, i) => {
396
- found.push(...findUnresolvedVariablesInObject(item, `${prefix}[${i}]`));
397
- });
398
- return found;
399
- }
400
- if (typeof obj === 'object') {
401
- for (const [key, value] of Object.entries(obj)) {
402
- const path = prefix ? `${prefix}.${key}` : key;
403
- found.push(...findUnresolvedVariablesInObject(value, path));
404
- }
405
- return found;
406
- }
407
- return found;
408
- }
409
-
410
- /**
411
- * Validates that deployment manifest contains no unresolved ${...} variables.
412
- * Throws if any are found, with a message to use secret variables or literal values.
413
- *
414
- * @function validateNoUnresolvedVariablesInDeployment
415
- * @param {Object} deployment - Deployment manifest object
416
- * @throws {Error} If any ${...} placeholders are found
417
- */
418
- function validateNoUnresolvedVariablesInDeployment(deployment) {
419
- const unresolved = findUnresolvedVariablesInObject(deployment);
420
- if (unresolved.length > 0) {
421
- const examples = [...new Set(unresolved)].slice(0, 5).join(', ');
422
- throw new Error(
423
- `Deployment manifest contains unresolved variables (e.g. ${examples}). ` +
424
- 'Use secret variables (kv://) in env.template for sensitive values, and set the application port as a number in application.yaml.'
425
- );
426
- }
427
- }
378
+ const {
379
+ findUnresolvedVariablesInObject,
380
+ validateNoUnresolvedVariablesInDeployment
381
+ } = require('./validator-unresolved-placeholders');
428
382
 
429
383
  /**
430
384
  * Validates all application configuration files
@@ -1,3 +1,4 @@
1
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
1
2
  /**
2
3
  * @fileoverview Wizard configuration validator for wizard.yaml files
3
4
  * @author AI Fabrix Team
@@ -281,7 +282,7 @@ function displayValidationResults(result) {
281
282
  console.log(chalk.green('Wizard configuration is valid'));
282
283
  } else {
283
284
  // eslint-disable-next-line no-console
284
- console.log(chalk.red('Wizard configuration validation failed:'));
285
+ console.log(formatBlockingError('Wizard configuration validation failed:'));
285
286
  result.errors.forEach(error => {
286
287
  // eslint-disable-next-line no-console
287
288
  console.log(chalk.red(` - ${error}`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.42.1",
3
+ "version": "2.44.0",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -8,6 +8,7 @@
8
8
  "af": "bin/aifabrix.js"
9
9
  },
10
10
  "scripts": {
11
+ "all": "npm run precommit && npm run test:manual && npm run test:integration:fixtures && npm run test:hubspot-wizard",
11
12
  "test": "node tests/scripts/test-wrapper.js",
12
13
  "test:ci": "bash tests/scripts/ci-simulate.sh",
13
14
  "test:same-as-github": "npm run build:ci",
@@ -15,8 +16,13 @@
15
16
  "test:coverage:nyc": "nyc --reporter=text --reporter=lcov --reporter=html jest --config jest.config.coverage.js --runInBand",
16
17
  "test:watch": "jest --watch",
17
18
  "test:integration": "jest --config jest.config.integration.js --runInBand",
19
+ "test:integration:fixtures": "jest --config jest.config.integration.fixtures.js --runInBand",
18
20
  "test:integration:python": "cross-env TEST_LANGUAGE=python jest --config jest.config.integration.js --runInBand",
19
21
  "test:integration:typescript": "cross-env TEST_LANGUAGE=typescript jest --config jest.config.integration.js --runInBand",
22
+ "test:hubspot-wizard": "node integration/hubspot-test/test.js",
23
+ "test:hubspot-wizard:negative": "node integration/hubspot-test/test.js --type negative",
24
+ "test:hubspot-wizard:positive": "node integration/hubspot-test/test.js --type positive",
25
+ "test:hubspot-dataplane-down": "node integration/hubspot-test/test-dataplane-down.js",
20
26
  "test:manual": "jest --config jest.config.manual.js --runInBand",
21
27
  "lint": "eslint . --ext .js",
22
28
  "lint:fix": "eslint . --ext .js --fix",
@@ -28,8 +34,10 @@
28
34
  "validate": "npm run build",
29
35
  "prepublishOnly": "npm run validate",
30
36
  "precommit": "npm run lint:fix && npm run test",
31
- "install:local": "node scripts/install-local.js",
32
- "uninstall:local": "node scripts/install-local.js uninstall"
37
+ "install:local": "node scripts/install-local.js && which aifabrix && which af",
38
+ "uninstall:local": "node scripts/install-local.js uninstall && which aifabrix && which af",
39
+ "diagnose:cli": "node scripts/diagnose-cli.js",
40
+ "check:schema-sync": "node scripts/check-datasource-test-run-schema-sync.js"
33
41
  },
34
42
  "keywords": [
35
43
  "aifabrix",