@aifabrix/builder 2.43.0 → 2.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/.cursor/rules/anchor-docs.mdc +15 -0
  2. package/.cursor/rules/cli-layout.mdc +75 -0
  3. package/.cursor/rules/project-rules.mdc +8 -0
  4. package/.npmrc.token +1 -0
  5. package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  6. package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +1 -0
  7. package/.nyc_output/processinfo/index.json +1 -0
  8. package/README.md +1 -1
  9. package/anchor-docs/README.md +10 -0
  10. package/anchor-docs/_TEMPLATE +24 -0
  11. package/bin/aifabrix.js +13 -4
  12. package/integration/hubspot-test/README.md +31 -0
  13. package/integration/hubspot-test/create-hubspot.js +5 -5
  14. package/integration/hubspot-test/hubspot-test-datasource-company.json +58 -462
  15. package/integration/hubspot-test/hubspot-test-datasource-contact.json +61 -555
  16. package/integration/hubspot-test/hubspot-test-datasource-deal.json +63 -506
  17. package/integration/hubspot-test/hubspot-test-datasource-users.json +42 -83
  18. package/integration/hubspot-test/hubspot-test-deploy.json +3 -3
  19. package/integration/hubspot-test/test-dataplane-down-tests.js +1 -7
  20. package/integration/hubspot-test/test-dataplane-down.js +3 -3
  21. package/integration/hubspot-test/test.js +35 -43
  22. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
  23. package/integration/roundtrip-test-local/README.md +144 -0
  24. package/integration/roundtrip-test-local/application.yaml +13 -0
  25. package/integration/roundtrip-test-local/env.template +15 -0
  26. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
  27. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
  28. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
  29. package/integration/roundtrip-test-local2/README.md +144 -0
  30. package/integration/roundtrip-test-local2/application.yaml +13 -0
  31. package/integration/roundtrip-test-local2/env.template +15 -0
  32. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
  33. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
  34. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
  35. package/integration/test/wizard.yaml +8 -0
  36. package/jest.config.default.js +10 -0
  37. package/jest.config.integration.fixtures.js +22 -0
  38. package/jest.config.integration.js +21 -18
  39. package/jest.config.isolated.js +10 -0
  40. package/jest.projects.js +301 -0
  41. package/lib/api/certificates.api.js +62 -0
  42. package/lib/api/datasources-core.api.js +3 -3
  43. package/lib/api/dev-mtls-request.js +110 -0
  44. package/lib/api/dev-server-https.js +145 -0
  45. package/lib/api/dev.api.js +133 -144
  46. package/lib/api/index.js +11 -3
  47. package/lib/api/pipeline.api.js +67 -20
  48. package/lib/api/types/certificates.types.js +48 -0
  49. package/lib/api/types/dev.types.js +4 -3
  50. package/lib/api/types/pipeline.types.js +8 -5
  51. package/lib/api/types/validation-run.types.js +56 -0
  52. package/lib/api/validation-run.api.js +111 -0
  53. package/lib/api/validation-runner.js +109 -0
  54. package/lib/app/certification-show-enrich.js +129 -0
  55. package/lib/app/certification-verify-rows.js +60 -0
  56. package/lib/app/config.js +1 -1
  57. package/lib/app/deploy-status-display.js +2 -2
  58. package/lib/app/deploy.js +7 -6
  59. package/lib/app/display.js +2 -1
  60. package/lib/app/dockerfile.js +3 -2
  61. package/lib/app/down.js +2 -1
  62. package/lib/app/helpers.js +6 -5
  63. package/lib/app/index.js +27 -8
  64. package/lib/app/list.js +7 -6
  65. package/lib/app/push.js +4 -3
  66. package/lib/app/register.js +16 -7
  67. package/lib/app/rotate-secret.js +14 -13
  68. package/lib/app/run-container-start.js +184 -0
  69. package/lib/app/run-docker-fallback.js +108 -0
  70. package/lib/app/run-env-compose.js +30 -42
  71. package/lib/app/run-helpers.js +49 -126
  72. package/lib/app/run-infra-requirements.js +30 -0
  73. package/lib/app/run-resolve-image.js +21 -0
  74. package/lib/app/run.js +74 -21
  75. package/lib/app/show-display.js +44 -1
  76. package/lib/app/show.js +93 -9
  77. package/lib/build/index.js +13 -10
  78. package/lib/certification/cli-cert-sync-skip.js +21 -0
  79. package/lib/certification/merge-certification-from-artifact.js +185 -0
  80. package/lib/certification/post-unified-cert-sync.js +33 -0
  81. package/lib/certification/sync-after-external-command.js +52 -0
  82. package/lib/certification/sync-system-certification.js +197 -0
  83. package/lib/cli/index.js +2 -0
  84. package/lib/cli/setup-app.help.js +67 -0
  85. package/lib/cli/setup-app.js +61 -121
  86. package/lib/cli/setup-app.test-commands.js +195 -0
  87. package/lib/cli/setup-auth.js +19 -5
  88. package/lib/cli/setup-credential-deployment.js +22 -8
  89. package/lib/cli/setup-dev-path-commands.js +124 -0
  90. package/lib/cli/setup-dev.js +170 -113
  91. package/lib/cli/setup-environment.js +7 -1
  92. package/lib/cli/setup-external-system.js +84 -23
  93. package/lib/cli/setup-infra.js +126 -47
  94. package/lib/cli/setup-parameters.js +32 -0
  95. package/lib/cli/setup-secrets.js +137 -18
  96. package/lib/cli/setup-service-user.js +1 -1
  97. package/lib/cli/setup-utility.js +54 -22
  98. package/lib/commands/app-down.js +5 -7
  99. package/lib/commands/app-install.js +14 -7
  100. package/lib/commands/app-logs.js +13 -10
  101. package/lib/commands/app-shell.js +4 -1
  102. package/lib/commands/app-test.js +25 -19
  103. package/lib/commands/app.js +32 -11
  104. package/lib/commands/auth-config.js +6 -6
  105. package/lib/commands/auth-status.js +4 -3
  106. package/lib/commands/credential-env.js +4 -3
  107. package/lib/commands/credential-list.js +5 -4
  108. package/lib/commands/credential-push.js +4 -3
  109. package/lib/commands/datasource-unified-test-cli.js +428 -0
  110. package/lib/commands/datasource-unified-test-cli.options.js +191 -0
  111. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +106 -0
  112. package/lib/commands/datasource-validation-cli.js +143 -0
  113. package/lib/commands/datasource.js +125 -95
  114. package/lib/commands/deployment-list.js +6 -5
  115. package/lib/commands/dev-cli-handlers.js +122 -18
  116. package/lib/commands/dev-down.js +4 -3
  117. package/lib/commands/dev-init.js +231 -116
  118. package/lib/commands/dev-show-display.js +473 -0
  119. package/lib/commands/login-credentials.js +3 -2
  120. package/lib/commands/login-device.js +4 -3
  121. package/lib/commands/login.js +5 -4
  122. package/lib/commands/logout.js +8 -7
  123. package/lib/commands/parameters-validate.js +54 -0
  124. package/lib/commands/repair-datasource.js +314 -68
  125. package/lib/commands/repair-env-template.js +2 -2
  126. package/lib/commands/repair.js +21 -3
  127. package/lib/commands/secrets-list.js +23 -12
  128. package/lib/commands/secrets-remove-all.js +220 -0
  129. package/lib/commands/secrets-remove.js +21 -12
  130. package/lib/commands/secrets-set.js +21 -12
  131. package/lib/commands/secrets-validate.js +4 -4
  132. package/lib/commands/secure.js +10 -9
  133. package/lib/commands/service-user.js +26 -25
  134. package/lib/commands/test-e2e-external.js +27 -1
  135. package/lib/commands/up-common.js +3 -2
  136. package/lib/commands/up-dataplane.js +29 -16
  137. package/lib/commands/up-miso.js +19 -29
  138. package/lib/commands/upload.js +149 -39
  139. package/lib/commands/wizard-core-helpers.js +1 -1
  140. package/lib/commands/wizard-dataplane.js +4 -3
  141. package/lib/commands/wizard-helpers.js +3 -3
  142. package/lib/commands/wizard.js +2 -2
  143. package/lib/core/admin-secrets.js +14 -5
  144. package/lib/core/audit-logger.js +12 -4
  145. package/lib/core/config-attach-extensions.js +46 -0
  146. package/lib/core/config-runtime-paths.js +29 -0
  147. package/lib/core/config.js +55 -56
  148. package/lib/core/diff.js +3 -2
  149. package/lib/core/ensure-encryption-key.js +1 -1
  150. package/lib/core/secrets-ensure-infra.js +77 -0
  151. package/lib/core/secrets-ensure.js +120 -64
  152. package/lib/core/secrets-env-write.js +35 -7
  153. package/lib/core/secrets-infra-placeholder-sync.js +61 -0
  154. package/lib/core/secrets.js +200 -37
  155. package/lib/core/templates-env.js +4 -3
  156. package/lib/datasource/abac-validator.js +1 -10
  157. package/lib/datasource/deploy.js +75 -53
  158. package/lib/datasource/field-reference-validator.js +9 -6
  159. package/lib/datasource/integration-context.js +63 -0
  160. package/lib/datasource/list.js +8 -7
  161. package/lib/datasource/log-viewer.js +189 -67
  162. package/lib/datasource/resolve-app.js +4 -4
  163. package/lib/datasource/test-e2e.js +113 -146
  164. package/lib/datasource/test-integration.js +114 -122
  165. package/lib/datasource/unified-validation-run-body.js +68 -0
  166. package/lib/datasource/unified-validation-run-post.js +23 -0
  167. package/lib/datasource/unified-validation-run-resolve.js +43 -0
  168. package/lib/datasource/unified-validation-run.js +93 -0
  169. package/lib/datasource/validate.js +157 -13
  170. package/lib/deployment/deployer.js +4 -3
  171. package/lib/deployment/environment.js +7 -6
  172. package/lib/deployment/push.js +17 -8
  173. package/lib/external-system/delete.js +4 -3
  174. package/lib/external-system/deploy.js +166 -53
  175. package/lib/external-system/download-helpers.js +1 -1
  176. package/lib/external-system/download.js +7 -6
  177. package/lib/external-system/generator.js +92 -6
  178. package/lib/external-system/integration-test-dispatch.js +26 -0
  179. package/lib/external-system/test-execution.js +5 -1
  180. package/lib/external-system/test-helpers.js +0 -4
  181. package/lib/external-system/test-system-level-helpers.js +110 -0
  182. package/lib/external-system/test-system-level.js +83 -44
  183. package/lib/external-system/test.js +59 -8
  184. package/lib/generator/builders.js +23 -11
  185. package/lib/generator/deploy-manifest-azure-kv.js +81 -0
  186. package/lib/generator/external.js +16 -4
  187. package/lib/generator/helpers.js +58 -3
  188. package/lib/generator/index.js +4 -0
  189. package/lib/generator/split-readme.js +12 -7
  190. package/lib/generator/split-variables.js +2 -1
  191. package/lib/generator/split.js +1 -1
  192. package/lib/generator/wizard-readme.js +3 -3
  193. package/lib/generator/wizard.js +8 -8
  194. package/lib/infrastructure/compose.js +70 -7
  195. package/lib/infrastructure/helpers-docker-check.js +67 -0
  196. package/lib/infrastructure/helpers.js +203 -42
  197. package/lib/infrastructure/index.js +31 -18
  198. package/lib/infrastructure/services.js +21 -67
  199. package/lib/internal/fs-real-sync.js +104 -0
  200. package/lib/internal/node-fs.js +98 -0
  201. package/lib/parameters/database-secret-values.js +173 -0
  202. package/lib/parameters/infra-kv-discovery.js +121 -0
  203. package/lib/parameters/infra-parameter-catalog.js +458 -0
  204. package/lib/parameters/infra-parameter-validate.js +64 -0
  205. package/lib/schema/application-schema.json +37 -17
  206. package/lib/schema/datasource-test-run.schema.json +493 -0
  207. package/lib/schema/deployment-rules.yaml +102 -63
  208. package/lib/schema/external-datasource.schema.json +1200 -442
  209. package/lib/schema/external-system.schema.json +203 -5
  210. package/lib/schema/flag-map-validation-run.json +31 -0
  211. package/lib/schema/infra-parameter.schema.json +106 -0
  212. package/lib/schema/infra.parameter.yaml +421 -0
  213. package/lib/schema/type/credential-auth-templates.json +40 -0
  214. package/lib/schema/type/document-storage.json +226 -0
  215. package/lib/schema/type/message-service.json +123 -0
  216. package/lib/schema/type/vector-store.json +88 -0
  217. package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
  218. package/lib/utils/api-error-handler.js +2 -2
  219. package/lib/utils/api.js +77 -17
  220. package/lib/utils/app-register-api.js +3 -2
  221. package/lib/utils/app-register-auth.js +1 -1
  222. package/lib/utils/app-register-config.js +4 -4
  223. package/lib/utils/app-register-display.js +3 -2
  224. package/lib/utils/app-register-validator.js +3 -2
  225. package/lib/utils/app-run-containers.js +26 -22
  226. package/lib/utils/app-scoped-config.js +31 -0
  227. package/lib/utils/app-service-env-from-builder.js +164 -0
  228. package/lib/utils/build-copy.js +1 -1
  229. package/lib/utils/build-helpers.js +20 -20
  230. package/lib/utils/build-resolve-image.js +165 -0
  231. package/lib/utils/cli-layout-chalk.js +8 -0
  232. package/lib/utils/cli-test-layout-chalk.js +267 -0
  233. package/lib/utils/cli-utils.js +88 -11
  234. package/lib/utils/compose-db-passwords.js +138 -0
  235. package/lib/utils/compose-generate-docker-compose.js +216 -0
  236. package/lib/utils/compose-generator.js +197 -291
  237. package/lib/utils/compose-miso-env.js +18 -0
  238. package/lib/utils/compose-traefik-ingress-base.js +158 -0
  239. package/lib/utils/config-paths.js +166 -7
  240. package/lib/utils/config-scoped-resources-preference.js +41 -0
  241. package/lib/utils/configuration-env-resolver.js +11 -8
  242. package/lib/utils/controller-deployment-outcome.js +68 -0
  243. package/lib/utils/credential-display.js +2 -2
  244. package/lib/utils/credential-secrets-env.js +5 -5
  245. package/lib/utils/dataplane-pipeline-warning.js +4 -3
  246. package/lib/utils/datasource-test-run-capability-scope.js +43 -0
  247. package/lib/utils/datasource-test-run-certificate-tty.js +82 -0
  248. package/lib/utils/datasource-test-run-debug-display.js +137 -0
  249. package/lib/utils/datasource-test-run-debug-slice.js +93 -0
  250. package/lib/utils/datasource-test-run-display.js +459 -0
  251. package/lib/utils/datasource-test-run-exit.js +83 -0
  252. package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
  253. package/lib/utils/datasource-test-run-report-version.js +51 -0
  254. package/lib/utils/datasource-test-run-schema-sync.js +59 -0
  255. package/lib/utils/datasource-test-run-tty-log.js +81 -0
  256. package/lib/utils/datasource-validation-watch.js +266 -0
  257. package/lib/utils/declarative-url-ports.js +47 -0
  258. package/lib/utils/derive-env-key-from-client-id.js +41 -0
  259. package/lib/utils/dev-ca-install.js +185 -23
  260. package/lib/utils/dev-cert-helper.js +266 -17
  261. package/lib/utils/dev-hosts-helper.js +307 -0
  262. package/lib/utils/dev-init-cert-hints.js +37 -0
  263. package/lib/utils/dev-init-health-messages.js +52 -0
  264. package/lib/utils/dev-init-resolve.js +86 -0
  265. package/lib/utils/dev-init-ssh-merge.js +65 -0
  266. package/lib/utils/dev-ssh-config-helper.js +196 -0
  267. package/lib/utils/dev-user-groups.js +93 -0
  268. package/lib/utils/docker-build.js +42 -17
  269. package/lib/utils/docker-exec.js +28 -0
  270. package/lib/utils/docker-manifest-public-port.js +116 -0
  271. package/lib/utils/docker-not-running-hint.js +52 -0
  272. package/lib/utils/docker.js +98 -11
  273. package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
  274. package/lib/utils/env-config-loader.js +10 -91
  275. package/lib/utils/env-copy.js +19 -10
  276. package/lib/utils/env-map.js +35 -8
  277. package/lib/utils/env-template.js +2 -2
  278. package/lib/utils/environment-scoped-resources.js +144 -0
  279. package/lib/utils/error-formatter.js +92 -13
  280. package/lib/utils/error-formatters/http-status-errors.js +6 -5
  281. package/lib/utils/error-formatters/network-errors.js +2 -1
  282. package/lib/utils/error-formatters/permission-errors.js +2 -1
  283. package/lib/utils/error-formatters/validation-errors.js +2 -1
  284. package/lib/utils/external-readme.js +8 -1
  285. package/lib/utils/external-system-display.js +242 -136
  286. package/lib/utils/external-system-local-test-tty.js +389 -0
  287. package/lib/utils/external-system-readiness-core.js +377 -0
  288. package/lib/utils/external-system-readiness-deploy-display.js +270 -0
  289. package/lib/utils/external-system-readiness-display-internals.js +150 -0
  290. package/lib/utils/external-system-readiness-display.js +186 -0
  291. package/lib/utils/external-system-system-test-tty-overview.js +120 -0
  292. package/lib/utils/external-system-system-test-tty.js +417 -0
  293. package/lib/utils/external-system-test-helpers.js +24 -6
  294. package/lib/utils/external-system-validators.js +30 -12
  295. package/lib/utils/health-check-url.js +119 -0
  296. package/lib/utils/health-check.js +59 -25
  297. package/lib/utils/help-builder.js +11 -8
  298. package/lib/utils/image-version.js +4 -8
  299. package/lib/utils/infra-containers.js +4 -7
  300. package/lib/utils/infra-env-defaults.js +162 -0
  301. package/lib/utils/infra-status-display.js +167 -0
  302. package/lib/utils/infra-status.js +16 -8
  303. package/lib/utils/local-secrets.js +3 -4
  304. package/lib/utils/paths.js +148 -47
  305. package/lib/utils/port-resolver.js +10 -23
  306. package/lib/utils/redis-env-scope.js +62 -0
  307. package/lib/utils/register-aifabrix-shell-env.js +204 -0
  308. package/lib/utils/remote-builder-validation.js +99 -0
  309. package/lib/utils/remote-dev-auth.js +117 -21
  310. package/lib/utils/remote-docker-env.js +67 -15
  311. package/lib/utils/remote-secrets-loader.js +13 -4
  312. package/lib/utils/resolve-docker-image-ref.js +124 -0
  313. package/lib/utils/schema-loader.js +22 -9
  314. package/lib/utils/secrets-bash-kv.js +25 -0
  315. package/lib/utils/secrets-generator.js +169 -49
  316. package/lib/utils/secrets-helpers.js +70 -59
  317. package/lib/utils/secrets-kv-scope.js +60 -0
  318. package/lib/utils/secrets-utils.js +32 -38
  319. package/lib/utils/secrets-validation.js +3 -1
  320. package/lib/utils/secrets-yaml-preserve.js +109 -0
  321. package/lib/utils/ssh-key-helper.js +4 -2
  322. package/lib/utils/template-helpers.js +2 -2
  323. package/lib/utils/test-log-writer.js +3 -3
  324. package/lib/utils/token-manager.js +1 -2
  325. package/lib/utils/url-declarative-public-base.js +188 -0
  326. package/lib/utils/url-declarative-resolve-build.js +493 -0
  327. package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
  328. package/lib/utils/url-declarative-resolve.js +220 -0
  329. package/lib/utils/url-declarative-token-parse.js +74 -0
  330. package/lib/utils/url-declarative-url-flags.js +50 -0
  331. package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
  332. package/lib/utils/url-public-path-prefix.js +34 -0
  333. package/lib/utils/urls-local-registry.js +220 -0
  334. package/lib/utils/validation-report-tty-kit.js +77 -0
  335. package/lib/utils/validation-run-poll.js +112 -0
  336. package/lib/utils/validation-run-post-retry.js +85 -0
  337. package/lib/utils/validation-run-request.js +116 -0
  338. package/lib/utils/variable-transformer.js +21 -4
  339. package/lib/utils/yaml-preserve.js +33 -14
  340. package/lib/validation/datasource-warnings.js +56 -0
  341. package/lib/validation/env-template-auth.js +1 -1
  342. package/lib/validation/external-manifest-validator.js +27 -7
  343. package/lib/validation/validate-display.js +37 -31
  344. package/lib/validation/validate-external-cert-sync.js +23 -0
  345. package/lib/validation/validate.js +8 -14
  346. package/lib/validation/validator-unresolved-placeholders.js +98 -0
  347. package/lib/validation/validator.js +22 -65
  348. package/lib/validation/wizard-config-validator.js +2 -1
  349. package/package.json +9 -4
  350. package/scripts/check-datasource-test-run-schema-sync.js +34 -0
  351. package/scripts/diagnose-cli.js +150 -0
  352. package/scripts/install-local.js +307 -55
  353. package/scripts/pnpm-global-remove.js +48 -0
  354. package/templates/README.md +15 -2
  355. package/templates/applications/dataplane/application.yaml +52 -2
  356. package/templates/applications/dataplane/env.template +79 -17
  357. package/templates/applications/dataplane/rbac.yaml +8 -0
  358. package/templates/applications/keycloak/application.yaml +9 -1
  359. package/templates/applications/keycloak/env.template +15 -6
  360. package/templates/applications/miso-controller/application.yaml +10 -2
  361. package/templates/applications/miso-controller/env.template +42 -12
  362. package/templates/applications/miso-controller/rbac.yaml +5 -0
  363. package/templates/external-system/README.md.hbs +20 -7
  364. package/templates/external-system/deploy.js.hbs +5 -5
  365. package/templates/external-system/external-datasource.yaml.hbs +197 -118
  366. package/templates/infra/compose.yaml.hbs +33 -16
  367. package/templates/infra/servers.json.hbs +3 -1
  368. package/templates/python/docker-compose.hbs +16 -0
  369. package/templates/typescript/docker-compose.hbs +16 -0
  370. package/lib/api/external-test.api.js +0 -111
  371. package/lib/schema/env-config.yaml +0 -60
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Helpers for system-level pipeline test mapping (keeps runSystemLevelTest under max-lines-per-function).
3
+ * @fileoverview
4
+ */
5
+ 'use strict';
6
+
7
+ const { integrationResultFromEnvelope } = require('../utils/datasource-test-run-legacy-adapter');
8
+
9
+ /**
10
+ * Build a single failure-shaped datasource result row.
11
+ * @param {string} error
12
+ * @returns {Object}
13
+ */
14
+ function systemFailureRow(error) {
15
+ return {
16
+ key: 'system',
17
+ success: false,
18
+ skipped: false,
19
+ validationResults: {},
20
+ fieldMappingResults: {},
21
+ endpointTestResults: {},
22
+ error
23
+ };
24
+ }
25
+
26
+ /**
27
+ * Map unified envelope-style response to datasourceResults.
28
+ * @param {Object} data
29
+ * @param {string} datasourceKey
30
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
31
+ */
32
+ function mapEnvelopeSingleDatasource(data, datasourceKey) {
33
+ const legacy = integrationResultFromEnvelope(data, datasourceKey);
34
+ return {
35
+ success: legacy.success,
36
+ datasourceResults: [
37
+ {
38
+ key: legacy.key,
39
+ success: legacy.success,
40
+ skipped: legacy.skipped,
41
+ validationResults: legacy.validationResults,
42
+ fieldMappingResults: legacy.fieldMappingResults,
43
+ endpointTestResults: legacy.endpointTestResults,
44
+ error: legacy.error,
45
+ envelope: legacy.envelope
46
+ }
47
+ ]
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Map legacy array-shaped results to normalized datasource rows.
53
+ * @param {Array} rawResults
54
+ * @param {Object} data
55
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
56
+ */
57
+ function mapLegacyRawResults(rawResults, data) {
58
+ const datasourceResults = [];
59
+ let success = true;
60
+
61
+ for (const r of rawResults) {
62
+ const dsKey = r.key || r.sourceKey || r.name || r.datasourceKey;
63
+ const dsResult = {
64
+ key: dsKey,
65
+ success: r.success !== false,
66
+ skipped: !!r.skipped,
67
+ reason: r.reason,
68
+ validationResults: r.validationResults || {},
69
+ fieldMappingResults: r.fieldMappingResults || {},
70
+ endpointTestResults: r.endpointTestResults || {}
71
+ };
72
+ if (r.error) dsResult.error = r.error;
73
+ if (!dsResult.success && !dsResult.skipped) success = false;
74
+ datasourceResults.push(dsResult);
75
+ }
76
+
77
+ if (rawResults.length === 0 && data.success === false) {
78
+ success = false;
79
+ datasourceResults.push(
80
+ systemFailureRow(data.error || data.formattedError || 'System test failed')
81
+ );
82
+ }
83
+
84
+ return { success, datasourceResults };
85
+ }
86
+
87
+ /**
88
+ * Normalize pipeline response body to { success, datasourceResults }.
89
+ * @param {Object} data
90
+ * @returns {{ success: boolean, datasourceResults: Object[] }}
91
+ */
92
+ function mapPipelineDataToDatasourceResults(data) {
93
+ if (
94
+ data &&
95
+ typeof data === 'object' &&
96
+ typeof data.status === 'string' &&
97
+ typeof data.datasourceKey === 'string'
98
+ ) {
99
+ return mapEnvelopeSingleDatasource(data, data.datasourceKey);
100
+ }
101
+
102
+ const rawResults =
103
+ data.datasourceResults || data.results || data.data?.datasourceResults || (Array.isArray(data) ? data : []);
104
+ return mapLegacyRawResults(rawResults, data);
105
+ }
106
+
107
+ module.exports = {
108
+ systemFailureRow,
109
+ mapPipelineDataToDatasourceResults
110
+ };
@@ -1,17 +1,81 @@
1
1
  /**
2
- * System-level pipeline test - single API call for all datasources
3
- * @fileoverview System-level test execution for integration tests
4
- * @author AI Fabrix Team
5
- * @version 2.0.0
2
+ * @fileoverview System-level unified validation runner for external systems (aggregate layer).
3
+ *
4
+ * Preferred behavior is a single externalSystem-scoped POST that returns an aggregate body.
5
+ * Until that aggregate is guaranteed everywhere, this module performs the plan §2.2 “interim”
6
+ * strategy: fan-out datasource-scoped runs and merge into a single system result.
6
7
  */
7
- /* eslint-disable max-statements,complexity -- Map response to datasource results */
8
+
9
+ 'use strict';
8
10
 
9
11
  const path = require('path');
10
12
  const chalk = require('chalk');
11
13
  const logger = require('../utils/logger');
12
- const { testSystemViaPipeline } = require('../api/pipeline.api');
13
14
  const { writeTestLog } = require('../utils/test-log-writer');
14
15
  const { getIntegrationPath } = require('../utils/paths');
16
+ const { runUnifiedDatasourceValidation } = require('../datasource/unified-validation-run');
17
+
18
+ async function runOneDatasourceKey(appName, datasourceKey, opts) {
19
+ const { environment, runType, debug, timeoutMs } = opts;
20
+ try {
21
+ const uni = await runUnifiedDatasourceValidation(datasourceKey, {
22
+ app: appName,
23
+ environment,
24
+ runType,
25
+ debug,
26
+ verbose: false,
27
+ timeout: timeoutMs,
28
+ async: true,
29
+ noAsync: false
30
+ });
31
+
32
+ if (uni.apiError) {
33
+ return {
34
+ key: datasourceKey,
35
+ success: false,
36
+ skipped: false,
37
+ error: uni.apiError.formattedError || uni.apiError.error || 'Request failed',
38
+ datasourceTestRun: null
39
+ };
40
+ }
41
+ if (uni.pollTimedOut) {
42
+ return {
43
+ key: datasourceKey,
44
+ success: false,
45
+ skipped: false,
46
+ error: 'Report incomplete: timeout',
47
+ datasourceTestRun: uni.envelope
48
+ };
49
+ }
50
+ if (uni.incompleteNoAsync) {
51
+ return {
52
+ key: datasourceKey,
53
+ success: false,
54
+ skipped: false,
55
+ error: 'Report incomplete (async required)',
56
+ datasourceTestRun: uni.envelope
57
+ };
58
+ }
59
+ const env = uni.envelope;
60
+ const ok = env && typeof env.status === 'string' ? env.status !== 'fail' : false;
61
+ return { key: datasourceKey, success: ok, skipped: false, datasourceTestRun: env };
62
+ } catch (err) {
63
+ return { key: datasourceKey, success: false, skipped: false, error: err.message };
64
+ }
65
+ }
66
+
67
+ async function maybeWriteSystemRunLog(appName, systemKey, datasourceKeys, runType, debug, payload) {
68
+ if (!debug) return;
69
+ const appPath = getIntegrationPath(appName);
70
+ const integrationDir = path.dirname(appPath);
71
+ const logPath = await writeTestLog(
72
+ appName,
73
+ { request: { systemKey, datasourceKeys, runType, includeDebug: true }, response: payload },
74
+ runType === 'e2e' ? 'test-e2e' : 'test-integration',
75
+ integrationDir
76
+ );
77
+ logger.log(chalk.gray(` Debug log: ${logPath}`));
78
+ }
15
79
 
16
80
  /**
17
81
  * Run system-level pipeline test and map response to datasource results
@@ -25,49 +89,24 @@ const { getIntegrationPath } = require('../utils/paths');
25
89
  * @param {number} [params.timeout] - Request timeout
26
90
  * @returns {Promise<{success: boolean, datasourceResults: Object[]}>}
27
91
  */
28
- async function runSystemLevelTest({ appName, systemKey, authConfig, dataplaneUrl, debug, timeout }) {
29
- const testData = { includeDebug: !!debug };
30
- const response = await testSystemViaPipeline(dataplaneUrl, systemKey, authConfig, testData, { timeout });
31
- const data = response.data || response;
32
-
33
- if (debug) {
34
- const appPath = getIntegrationPath(appName);
35
- const integrationDir = path.dirname(appPath);
36
- const logPath = await writeTestLog(appName, { request: { systemKey, includeDebug: true }, response: data }, 'test-integration', integrationDir);
37
- logger.log(chalk.gray(` Debug log: ${logPath}`));
92
+ async function runSystemLevelTest({ appName, systemKey, datasourceKeys, environment, runType, debug, timeout }) {
93
+ if (!Array.isArray(datasourceKeys) || datasourceKeys.length === 0) {
94
+ return { success: true, datasourceResults: [] };
38
95
  }
96
+ const timeoutMs = Number.isFinite(timeout) ? timeout : 30000;
39
97
 
40
- const rawResults = data.datasourceResults || data.results || data.data?.datasourceResults || (Array.isArray(data) ? data : []);
41
- const datasourceResults = [];
42
- let success = true;
43
-
44
- for (const r of rawResults) {
45
- const dsKey = r.key || r.sourceKey || r.name || r.datasourceKey;
46
- const dsResult = {
47
- key: dsKey,
48
- success: r.success !== false,
49
- skipped: !!r.skipped,
50
- reason: r.reason,
51
- validationResults: r.validationResults || {},
52
- fieldMappingResults: r.fieldMappingResults || {},
53
- endpointTestResults: r.endpointTestResults || {}
54
- };
55
- if (r.error) dsResult.error = r.error;
56
- if (!dsResult.success && !dsResult.skipped) success = false;
57
- datasourceResults.push(dsResult);
98
+ const results = [];
99
+ for (const key of datasourceKeys) {
100
+ // Keep sequential to avoid spiking external APIs / dataplane concurrency in CLI runs.
101
+ // (Plan allows parallel later, but UX needs stable logs first.)
102
+ // eslint-disable-next-line no-await-in-loop -- intentional sequential execution
103
+ results.push(await runOneDatasourceKey(appName, key, { environment, runType, debug, timeoutMs }));
58
104
  }
59
105
 
60
- if (rawResults.length === 0 && data.success === false) {
61
- success = false;
62
- datasourceResults.push({
63
- key: 'system',
64
- success: false,
65
- skipped: false,
66
- error: data.error || data.formattedError || 'System test failed'
67
- });
68
- }
106
+ const success = results.every(r => r.success);
107
+ await maybeWriteSystemRunLog(appName, systemKey, datasourceKeys, runType, debug, { success, results });
69
108
 
70
- return { success, datasourceResults };
109
+ return { success, datasourceResults: results };
71
110
  }
72
111
 
73
112
  module.exports = { runSystemLevelTest };
@@ -11,12 +11,14 @@ const fs = require('fs').promises;
11
11
  const fsSync = require('fs');
12
12
  const path = require('path');
13
13
  const chalk = require('chalk');
14
+ const { infoLine, formatSuccessLine } = require('../utils/cli-test-layout-chalk');
14
15
  const testHelpers = require('../utils/external-system-test-helpers');
15
16
  const { retryApiCall } = require('../utils/external-system-test-helpers');
16
17
  const { getConfig } = require('../core/config');
17
18
  const { detectAppType } = require('../utils/paths');
18
19
  const { setupIntegrationTestAuth } = require('./test-auth');
19
20
  const logger = require('../utils/logger');
21
+ const { writeTestLog } = require('../utils/test-log-writer');
20
22
  const {
21
23
  validateFieldMappings,
22
24
  validateMetadataSchema,
@@ -35,6 +37,7 @@ const {
35
37
  testSingleDatasourceIntegration
36
38
  } = require('./test-execution');
37
39
  const { runSystemLevelTest } = require('./test-system-level');
40
+ const { shouldUseSystemLevelIntegrationCall } = require('./integration-test-dispatch');
38
41
 
39
42
  /**
40
43
  * Loads and parses application config file
@@ -51,7 +54,7 @@ async function loadVariablesYamlFile(variablesPath) {
51
54
  if (!variables.externalIntegration) {
52
55
  throw new Error(
53
56
  'externalIntegration block not found in application config. ' +
54
- 'test-integration is for external systems only (integration/<app> with externalIntegration in application.yaml). ' +
57
+ 'test-integration is for external systems only (integration/<systemKey> with externalIntegration in application.yaml). ' +
55
58
  'For builder apps use: aifabrix test <app> or aifabrix test-e2e <app>'
56
59
  );
57
60
  }
@@ -251,11 +254,15 @@ function validateSingleDatasource(datasourceFile, systemKey, externalDataSourceS
251
254
  errors: [],
252
255
  warnings: [],
253
256
  fieldMappingResults: null,
254
- metadataSchemaResults: null
257
+ metadataSchemaResults: null,
258
+ structuralValid: true,
259
+ payloadTestsRan: false,
260
+ payloadTestsOk: true
255
261
  };
256
262
 
257
263
  // Validate against schema
258
264
  const schemaValidation = validateDatasourceSchema(datasource, systemKey, externalDataSourceSchema);
265
+ datasourceResult.structuralValid = schemaValidation.valid;
259
266
  if (!schemaValidation.valid) {
260
267
  datasourceResult.valid = false;
261
268
  datasourceResult.errors.push(...schemaValidation.errors);
@@ -263,16 +270,22 @@ function validateSingleDatasource(datasourceFile, systemKey, externalDataSourceS
263
270
 
264
271
  // Test with testPayload if available
265
272
  if (datasource.testPayload && datasource.testPayload.payloadTemplate) {
266
- logger.log(chalk.blue(` Testing datasource: ${datasource.key}`));
273
+ if (verbose) {
274
+ logger.log(`${chalk.cyan(' ℹ')} ${chalk.gray('Testing datasource:')} ${chalk.white.bold(datasource.key)}`);
275
+ }
276
+ datasourceResult.payloadTestsRan = true;
267
277
  const payloadTestResults = testDatasourceWithPayload(datasource, verbose);
268
278
  datasourceResult.fieldMappingResults = payloadTestResults.fieldMappingResults;
269
279
  datasourceResult.metadataSchemaResults = payloadTestResults.metadataSchemaResults;
280
+ datasourceResult.payloadTestsOk = payloadTestResults.valid;
270
281
  if (!payloadTestResults.valid) {
271
282
  datasourceResult.valid = false;
272
283
  datasourceResult.errors.push(...payloadTestResults.errors);
273
284
  }
274
285
  datasourceResult.warnings.push(...payloadTestResults.warnings);
275
286
  } else {
287
+ datasourceResult.payloadTestsRan = false;
288
+ datasourceResult.payloadTestsOk = true;
276
289
  datasourceResult.warnings.push('No testPayload.payloadTemplate found - skipping field mapping and metadata schema tests');
277
290
  }
278
291
 
@@ -302,7 +315,8 @@ async function testExternalSystem(appName, options = {}) {
302
315
  }
303
316
 
304
317
  try {
305
- logger.log(chalk.blue(`\n🧪 Running unit tests for: ${appName}`));
318
+ logger.log('');
319
+ logger.log(infoLine(`Local test: ${appName}`));
306
320
 
307
321
  // Load files
308
322
  const { variables: _variables, systemFiles, datasourceFiles } = await loadExternalSystemFiles(appName);
@@ -312,6 +326,23 @@ async function testExternalSystem(appName, options = {}) {
312
326
  validateSystemFilesForTest(systemFiles, results);
313
327
  validateDatasourceFilesForTest(datasourceFiles, systemFiles, results, options, validateSingleDatasource, determineDatasourcesToTest);
314
328
 
329
+ results.systemKey = systemFiles.length > 0 ? systemFiles[0].data.key : appName;
330
+ results.appName = appName;
331
+
332
+ if (options.debug) {
333
+ try {
334
+ const logPath = await writeTestLog(
335
+ appName,
336
+ {
337
+ request: { appName, datasource: options.datasource || null, verbose: !!options.verbose },
338
+ response: results
339
+ },
340
+ 'test'
341
+ );
342
+ logger.log(chalk.gray(` Debug log: ${logPath}`));
343
+ } catch (_) { /* ignore */ }
344
+ }
345
+
315
346
  return results;
316
347
  } catch (error) {
317
348
  // Preserve original error message for better test compatibility
@@ -371,11 +402,13 @@ function determineDatasourcesToTest(datasourceFiles, datasourceFilter) {
371
402
  * @param {string} appName - Application name
372
403
  * @param {Object} options - Test options
373
404
  * @param {string} [options.datasource] - Test specific datasource only
405
+ * @param {boolean} [options.perDatasource] - When multiple datasources, run POST /validation/run per datasource instead of one externalSystem call
374
406
  * @param {string} [options.payload] - Path to custom test payload file
375
407
  * @param {string} [options.environment] - Environment (dev, tst, pro)
376
408
  * @param {string} [options.controller] - Controller URL
377
409
  * @param {boolean} [options.verbose] - Show detailed test output
378
410
  * @param {number} [options.timeout] - Request timeout in milliseconds
411
+ * @param {boolean} [options.sync] - When true, run full `aifabrix upload`-equivalent publish before tests
379
412
  * @returns {Promise<Object>} Integration test results
380
413
  * @throws {Error} If testing fails
381
414
  */
@@ -415,23 +448,41 @@ async function testExternalSystemIntegration(appName, options = {}) {
415
448
  }
416
449
 
417
450
  try {
418
- logger.log(chalk.blue(`\n🔗 Running integration tests for: ${appName}`));
451
+ logger.log('');
452
+ logger.log(infoLine(`🔗 Running integration tests for: ${appName}`));
419
453
 
420
454
  const { systemKey, authConfig, dataplaneUrl, datasourcesToTest, customPayload } = await prepareIntegrationTestEnvironment(appName, options);
421
455
 
456
+ if (options.sync === true) {
457
+ logger.log(chalk.cyan('Syncing local config to dataplane…'));
458
+ const { uploadExternalSystem } = require('../commands/upload');
459
+ await uploadExternalSystem(systemKey, {
460
+ verbose: !!options.verbose,
461
+ minimal: true
462
+ });
463
+ logger.log(formatSuccessLine('Sync complete'));
464
+ }
465
+
422
466
  const results = {
423
467
  success: true,
424
468
  systemKey,
425
469
  datasourceResults: []
426
470
  };
427
471
 
428
- const useSystemLevel = !options.datasource && datasourcesToTest.length > 0 && !customPayload;
429
472
  const timeout = parseInt(options.timeout, 10) || 30000;
473
+ const useSystemLevel = shouldUseSystemLevelIntegrationCall(options, datasourcesToTest, customPayload);
430
474
 
431
- if (useSystemLevel && datasourcesToTest.length > 1) {
475
+ if (useSystemLevel) {
432
476
  try {
477
+ const datasourceKeys = datasourcesToTest.map(ds => ds?.data?.key).filter(Boolean);
433
478
  const systemResult = await runSystemLevelTest({
434
- appName, systemKey, authConfig, dataplaneUrl, debug: options.debug, timeout
479
+ appName,
480
+ systemKey,
481
+ datasourceKeys,
482
+ environment: options.environment,
483
+ runType: 'integration',
484
+ debug: options.debug,
485
+ timeout
435
486
  });
436
487
  results.success = systemResult.success;
437
488
  results.datasourceResults = systemResult.datasourceResults;
@@ -59,24 +59,33 @@ function buildImageReference(variables) {
59
59
  return `${imageName}:${tag}`;
60
60
  }
61
61
 
62
+ /**
63
+ * Deployment JSON health paths mirror `application.yaml`: probes target the workload (container),
64
+ * not the public Front Door / Traefik URL. Vdir is carried by `frontDoorRouting` and url://
65
+ * expansion elsewhere — do not prepend pattern base here (see dataplane `/health`, Keycloak `/health/ready`).
66
+ *
67
+ * @param {Object} variables - Transformed application variables
68
+ * @returns {Object} healthCheck block for deploy manifest
69
+ */
62
70
  function buildHealthCheck(variables) {
71
+ const hc = variables.healthCheck || {};
72
+ const path = typeof hc.path === 'string' && hc.path.startsWith('/') ? hc.path : '/health';
63
73
  const healthCheck = {
64
- path: variables.healthCheck?.path || '/health',
65
- interval: variables.healthCheck?.interval || 30
74
+ path,
75
+ interval: hc.interval || 30
66
76
  };
67
77
 
68
- // Add optional probe fields if present
69
- if (variables.healthCheck?.probePath) {
70
- healthCheck.probePath = variables.healthCheck.probePath;
78
+ if (hc.probePath) {
79
+ healthCheck.probePath = hc.probePath;
71
80
  }
72
- if (variables.healthCheck?.probeRequestType) {
73
- healthCheck.probeRequestType = variables.healthCheck.probeRequestType;
81
+ if (hc.probeRequestType) {
82
+ healthCheck.probeRequestType = hc.probeRequestType;
74
83
  }
75
- if (variables.healthCheck?.probeProtocol) {
76
- healthCheck.probeProtocol = variables.healthCheck.probeProtocol;
84
+ if (hc.probeProtocol) {
85
+ healthCheck.probeProtocol = hc.probeProtocol;
77
86
  }
78
- if (variables.healthCheck?.probeIntervalInSeconds) {
79
- healthCheck.probeIntervalInSeconds = variables.healthCheck.probeIntervalInSeconds;
87
+ if (hc.probeIntervalInSeconds) {
88
+ healthCheck.probeIntervalInSeconds = hc.probeIntervalInSeconds;
80
89
  }
81
90
 
82
91
  return healthCheck;
@@ -341,6 +350,9 @@ function addSimpleOptionalFields(deployment, variables) {
341
350
  if (variables.frontDoorRouting) {
342
351
  deployment.frontDoorRouting = variables.frontDoorRouting;
343
352
  }
353
+ if (variables.environmentScopedResources === true) {
354
+ deployment.environmentScopedResources = true;
355
+ }
344
356
  }
345
357
 
346
358
  function buildOptionalFields(deployment, variables, rbac) {
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Map url:// placeholders and Traefik host templates to Azure Key Vault secret names
3
+ * in deployment manifests (Miso Controller / App Service @Microsoft.KeyVault references).
4
+ *
5
+ * @fileoverview Plan 122 — deploy JSON must not ship url:// or ${DEV_USERNAME} for Azure
6
+ * @author AI Fabrix Team
7
+ * @version 1.0.0
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const { parseUrlToken } = require('../utils/url-declarative-token-parse');
13
+
14
+ /**
15
+ * @param {string|undefined} surface
16
+ * @param {string} subject
17
+ * @param {boolean} isPublic
18
+ * @returns {string|undefined} Secret name when surface is vdir/host
19
+ */
20
+ function secretNameFromSurface(surface, subject, isPublic) {
21
+ if (surface === 'vdir') {
22
+ return `${subject}-vdir-${isPublic ? 'public' : 'internal'}`;
23
+ }
24
+ if (surface === 'host') {
25
+ return `${subject}-host-${isPublic ? 'public' : 'internal'}`;
26
+ }
27
+ return undefined;
28
+ }
29
+
30
+ /**
31
+ * Key Vault secret name for a url:// token (path after url://).
32
+ * Aligns with infrastructure/bicep (e.g. keycloak-web-server-url, miso-controller-web-server-url).
33
+ *
34
+ * @param {string} ownerAppKey - application.yaml app.key for the manifest being generated
35
+ * @param {string} token - Token after url:// (no scheme)
36
+ * @returns {string}
37
+ */
38
+ function urlTokenToKeyVaultSecretName(ownerAppKey, token) {
39
+ const selfKey = String(ownerAppKey || '').trim() || 'app';
40
+ const t = String(token || '').trim();
41
+ if (!t) {
42
+ throw new Error('Empty url:// reference (expected a token after url://)');
43
+ }
44
+ const { targetKey, kind, surface } = parseUrlToken(t);
45
+ const isPublic = kind === 'public';
46
+ const subject = targetKey ? String(targetKey).trim() : selfKey;
47
+
48
+ const fromSurface = secretNameFromSurface(surface, subject, isPublic);
49
+ if (fromSurface !== undefined) {
50
+ return fromSurface;
51
+ }
52
+ if (targetKey === 'keycloak' || (!targetKey && selfKey === 'keycloak')) {
53
+ return isPublic ? 'keycloak-web-server-url' : 'keycloak-internal-server-url';
54
+ }
55
+ if (!targetKey) {
56
+ return isPublic ? `${selfKey}-web-server-url` : `${selfKey}-internal-server-url`;
57
+ }
58
+ return isPublic ? `${subject}-web-server-url` : `${subject}-internal-server-url`;
59
+ }
60
+
61
+ /**
62
+ * Replace Traefik-style host templates with a Key Vault secret name consumed by Azure provisioning.
63
+ *
64
+ * @param {Object} deployment - Deployment manifest (mutated in place)
65
+ * @returns {void}
66
+ */
67
+ function rewriteFrontDoorHostForAzureDeploy(deployment) {
68
+ if (!deployment || !deployment.frontDoorRouting || typeof deployment.frontDoorRouting.host !== 'string') {
69
+ return;
70
+ }
71
+ const h = deployment.frontDoorRouting.host;
72
+ if (/\$\{(DEV_USERNAME|REMOTE_HOST)\}/.test(h)) {
73
+ const key = deployment.key || 'app';
74
+ deployment.frontDoorRouting.host = `${key}-frontdoor-routing-host`;
75
+ }
76
+ }
77
+
78
+ module.exports = {
79
+ urlTokenToKeyVaultSecretName,
80
+ rewriteFrontDoorHostForAzureDeploy
81
+ };
@@ -11,6 +11,7 @@
11
11
  const fs = require('fs');
12
12
  const path = require('path');
13
13
  const Ajv = require('ajv');
14
+ const addFormats = require('ajv-formats');
14
15
  const { detectAppType, getDeployJsonPath } = require('../utils/paths');
15
16
  const { resolveApplicationConfigPath, resolveRbacPath } = require('../utils/app-config-resolver');
16
17
  const { loadConfigFile } = require('../utils/config-format');
@@ -255,8 +256,10 @@ function formatValidationErrors(errors) {
255
256
  * @throws {Error} If validation fails
256
257
  */
257
258
  function validateSystemSchema(systemJson, externalSystemSchema, ajv) {
258
- const externalSystemSchemaId = externalSystemSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-system.schema.json';
259
- ajv.addSchema(externalSystemSchema, externalSystemSchemaId);
259
+ if (!externalSystemSchema.$id || typeof externalSystemSchema.$id !== 'string') {
260
+ throw new Error('External system schema is missing required $id');
261
+ }
262
+ ajv.addSchema(externalSystemSchema, externalSystemSchema.$id);
260
263
  const validateSystem = ajv.compile(externalSystemSchema);
261
264
  const systemValid = validateSystem(systemJson);
262
265
 
@@ -277,8 +280,16 @@ function validateSystemSchema(systemJson, externalSystemSchema, ajv) {
277
280
  * @throws {Error} If validation fails
278
281
  */
279
282
  function validateDatasourceSchemas(datasourceJsons, externalDatasourceSchema, ajv) {
280
- const externalDatasourceSchemaId = externalDatasourceSchema.$id || 'https://raw.githubusercontent.com/esystemsdev/aifabrix-builder/refs/heads/main/lib/schema/external-datasource.schema.json';
281
- ajv.addSchema(externalDatasourceSchema, externalDatasourceSchemaId);
283
+ if (!externalDatasourceSchema.$id || typeof externalDatasourceSchema.$id !== 'string') {
284
+ throw new Error('External datasource schema is missing required $id');
285
+ }
286
+
287
+ // external-datasource.schema.json references these by $id (aifabrix://schema/type/*)
288
+ ajv.addSchema(require('../schema/type/document-storage.json'));
289
+ ajv.addSchema(require('../schema/type/message-service.json'));
290
+ ajv.addSchema(require('../schema/type/vector-store.json'));
291
+
292
+ ajv.addSchema(externalDatasourceSchema, externalDatasourceSchema.$id);
282
293
  const validateDatasource = ajv.compile(externalDatasourceSchema);
283
294
 
284
295
  for (let i = 0; i < datasourceJsons.length; i++) {
@@ -353,6 +364,7 @@ function prepareSchemasForValidation() {
353
364
  */
354
365
  function validateApplicationSchemaComponents(systemJson, datasourceJsons, externalSystemSchema, datasourceSchemaToAdd) {
355
366
  const ajv = new Ajv({ allErrors: true, strict: false, removeAdditional: false });
367
+ addFormats(ajv);
356
368
 
357
369
  // Validate system against external-system schema
358
370
  validateSystemSchema(systemJson, externalSystemSchema, ajv);