@aifabrix/builder 2.49.2 → 2.51.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 (459) hide show
  1. package/.cursor/plans/157.1-security-quality-violations-by-type.csv +374 -0
  2. package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
  3. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  4. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  5. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  6. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  7. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  8. package/.cursor/skills/README.md +1 -0
  9. package/.dockerignore +52 -0
  10. package/.eslintignore +22 -0
  11. package/README.md +2 -0
  12. package/bin/builder-api-cleanup.js +26 -0
  13. package/bin/builder-api-nest.js +10 -0
  14. package/bin/builder-api-spike.js +19 -0
  15. package/enterprise-knowledge/README.md +50 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  20. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  21. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  22. package/integration/README.md +81 -0
  23. package/integration/github/README.md +53 -0
  24. package/integration/github/application.json +21 -0
  25. package/integration/github/deploy.js +72 -0
  26. package/integration/github/env.template +11 -0
  27. package/integration/github/github-datasource-issue-comments.json +239 -0
  28. package/integration/github/github-datasource-issues.json +399 -0
  29. package/integration/github/github-datasource-repository.json +354 -0
  30. package/integration/github/github-deploy.json +1202 -0
  31. package/integration/github/github-system.json +82 -0
  32. package/integration/hubspot-test/README.md +1 -1
  33. package/integration/hubspot-test/create-hubspot.js +1 -16
  34. package/jest.isolated-projects.js +31 -1
  35. package/jest.projects.js +87 -1
  36. package/lib/api/dev-server-https.js +1 -1
  37. package/lib/api/enterprise-knowledge.api.js +63 -0
  38. package/lib/api/evidence-kinds.api.js +128 -0
  39. package/lib/api/evidence.api.js +172 -0
  40. package/lib/api/external-systems.api.js +8 -2
  41. package/lib/api/pipeline.api.js +5 -1
  42. package/lib/api/resource-types.api.js +5 -4
  43. package/lib/api/roles.api.js +121 -0
  44. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  45. package/lib/api/types/evidence-kinds.types.js +42 -0
  46. package/lib/api/types/evidence.types.js +67 -0
  47. package/lib/api/types/resource-types.types.js +2 -0
  48. package/lib/api/types/roles.types.js +36 -0
  49. package/lib/app/certification-verify-rows.js +1 -1
  50. package/lib/app/controller-application-filter.js +36 -0
  51. package/lib/app/deploy.js +1 -1
  52. package/lib/app/list-external-systems.js +130 -0
  53. package/lib/app/list.js +20 -8
  54. package/lib/app/run.js +3 -1
  55. package/lib/app/show-display.js +8 -3
  56. package/lib/app/show-online.js +178 -0
  57. package/lib/app/show.js +39 -90
  58. package/lib/build/builder-api-docker-staging.js +47 -0
  59. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  60. package/lib/build/standard-docker-build.js +2 -0
  61. package/lib/certification/merge-certification-from-artifact.js +1 -1
  62. package/lib/certification/post-unified-cert-sync.js +4 -31
  63. package/lib/certification/sync-after-external-command.js +0 -1
  64. package/lib/certification/sync-system-certification.js +0 -3
  65. package/lib/channels/add-channel.js +40 -34
  66. package/lib/channels/approval-guides/chatgpt.js +33 -0
  67. package/lib/channels/approval-guides/credential-portal.js +38 -0
  68. package/lib/channels/approval-guides/index.js +110 -0
  69. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  70. package/lib/channels/approval-guides/slack.js +34 -0
  71. package/lib/channels/approval-guides/teams-bot.js +35 -0
  72. package/lib/channels/approval-guides/web-embed.js +32 -0
  73. package/lib/channels/channel-approval-guide.js +11 -0
  74. package/lib/channels/channel-artifact-generator.js +18 -5
  75. package/lib/channels/channel-audit.js +3 -0
  76. package/lib/channels/channel-auth-context.js +1 -1
  77. package/lib/channels/channel-description.js +59 -0
  78. package/lib/channels/channel-integration-generator.js +13 -230
  79. package/lib/channels/channel-integration-template.js +94 -0
  80. package/lib/channels/channel-runtime-resolver.js +43 -3
  81. package/lib/channels/channel-status-display.js +66 -26
  82. package/lib/channels/channel-targets.js +3 -3
  83. package/lib/cli/index.js +31 -3
  84. package/lib/cli/infra-guided.js +5 -1
  85. package/lib/cli/setup-app-external-create.js +111 -0
  86. package/lib/cli/setup-app.help.js +1 -1
  87. package/lib/cli/setup-app.js +60 -130
  88. package/lib/cli/setup-app.test-commands.js +26 -52
  89. package/lib/cli/setup-certification-commands.js +4 -4
  90. package/lib/cli/setup-certification.help.js +9 -9
  91. package/lib/cli/setup-dev.js +30 -9
  92. package/lib/cli/setup-external-system-help.js +4 -6
  93. package/lib/cli/setup-external-system.js +58 -52
  94. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  95. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  96. package/lib/cli/setup-infra.js +15 -0
  97. package/lib/cli/setup-list.js +43 -0
  98. package/lib/cli/setup-utility-help-after.js +12 -0
  99. package/lib/cli/setup-utility-repair.js +26 -7
  100. package/lib/cli/setup-utility-validate.js +41 -2
  101. package/lib/cli/setup-utility.js +5 -3
  102. package/lib/commands/app.js +15 -43
  103. package/lib/commands/channel-add-setup.js +110 -0
  104. package/lib/commands/channel.js +42 -8
  105. package/lib/commands/datasource-sync-display.js +96 -0
  106. package/lib/commands/datasource-sync-policy.js +210 -0
  107. package/lib/commands/datasource-test-trust-cli.js +6 -6
  108. package/lib/commands/datasource-unified-test-cli.js +2 -1
  109. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  110. package/lib/commands/deploy-gate-failure-details.js +184 -0
  111. package/lib/commands/deploy-gate-orchestrator.js +368 -0
  112. package/lib/commands/dev-cli-handlers.js +7 -62
  113. package/lib/commands/dev-host-ops-params.js +91 -0
  114. package/lib/commands/dev-host-ops-poll.js +111 -0
  115. package/lib/commands/dev-host-ops.js +107 -94
  116. package/lib/commands/dev-init.js +6 -106
  117. package/lib/commands/dev-refresh.js +197 -0
  118. package/lib/commands/enterprise-knowledge.js +284 -0
  119. package/lib/commands/evidence-cli-leaves.js +250 -0
  120. package/lib/commands/evidence-kind.js +428 -0
  121. package/lib/commands/evidence.js +51 -0
  122. package/lib/commands/governance-cli-shared.js +2 -2
  123. package/lib/commands/governance-command-action.js +5 -3
  124. package/lib/commands/governance-fixture-subjects.js +85 -0
  125. package/lib/commands/governance.js +1 -1
  126. package/lib/commands/lifecycle-command-action.js +2 -2
  127. package/lib/commands/lifecycle-external.js +3 -3
  128. package/lib/commands/manifest-cli-auth.js +29 -0
  129. package/lib/commands/manifest-cli-commands.js +170 -0
  130. package/lib/commands/manifest-cli-integration-path.js +63 -0
  131. package/lib/commands/manifest.js +21 -0
  132. package/lib/commands/protection-cli-leaves.js +3 -3
  133. package/lib/commands/repair-auth-apply.js +15 -1
  134. package/lib/commands/repair-authentications-454.js +169 -0
  135. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  136. package/lib/commands/repair-datasource-apply.js +135 -0
  137. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  138. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  139. package/lib/commands/repair-datasource-operation-security.js +180 -0
  140. package/lib/commands/repair-datasource-run.js +7 -2
  141. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  142. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  143. package/lib/commands/repair-datasource.js +12 -68
  144. package/lib/commands/repair-env-template.js +11 -1
  145. package/lib/commands/repair-external-run.js +121 -31
  146. package/lib/commands/repair-internal.js +1 -1
  147. package/lib/commands/repair-openapi-export.js +156 -0
  148. package/lib/commands/repair-openapi-sync.js +33 -8
  149. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  150. package/lib/commands/repair-persist.js +22 -1
  151. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  152. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  153. package/lib/commands/repair-rbac.js +163 -86
  154. package/lib/commands/repair-steps.js +83 -18
  155. package/lib/commands/repair-system-permissions.js +1 -0
  156. package/lib/commands/repair.js +1 -1
  157. package/lib/commands/resource-type.js +166 -44
  158. package/lib/commands/role.js +452 -0
  159. package/lib/commands/run-post-publish-data-sync.js +68 -0
  160. package/lib/commands/setup-modes.js +1 -1
  161. package/lib/commands/setup.js +1 -1
  162. package/lib/commands/test-e2e-external.js +21 -8
  163. package/lib/commands/test-governance-cli-options.js +2 -2
  164. package/lib/commands/test-trust-cli-options.js +2 -2
  165. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  166. package/lib/commands/up-builder-api-provision.js +241 -0
  167. package/lib/commands/up-builder-api.js +88 -0
  168. package/lib/commands/up-common.js +25 -1
  169. package/lib/commands/upload-credential-push-log.js +117 -0
  170. package/lib/commands/upload-data-sync-finalize.js +60 -0
  171. package/lib/commands/upload-probe.js +66 -0
  172. package/lib/commands/upload-publish-context.js +4 -1
  173. package/lib/commands/upload-sidecar-followups.js +55 -27
  174. package/lib/commands/upload.js +116 -157
  175. package/lib/commands/validate-json.js +230 -0
  176. package/lib/commands/verify-governance-combined-external.js +1 -1
  177. package/lib/commands/verify-governance-db.js +2 -2
  178. package/lib/commands/verify-operations-command-action.js +2 -2
  179. package/lib/commands/verify-operations-step-plan.js +79 -41
  180. package/lib/commands/verify-operations-steps.js +2 -2
  181. package/lib/commands/verify-trust-command-action.js +1 -1
  182. package/lib/commands/wizard-core.js +1 -1
  183. package/lib/commands/wizard-headless.js +2 -1
  184. package/lib/core/admin-secrets.js +2 -6
  185. package/lib/core/audit-logger.js +1 -1
  186. package/lib/core/secrets-env-content.js +10 -4
  187. package/lib/core/secrets-env-write.js +2 -13
  188. package/lib/core/secrets-load.js +1 -3
  189. package/lib/datasource/agent-trust-run.js +3 -3
  190. package/lib/datasource/capability/relate-operations.js +1 -1
  191. package/lib/datasource/deploy.js +3 -1
  192. package/lib/datasource/test-e2e.js +6 -1
  193. package/lib/datasource/unified-validation-run-body.js +4 -1
  194. package/lib/datasource/unified-validation-run.js +1 -1
  195. package/lib/deployment/deploy-poll-ui.js +73 -12
  196. package/lib/deployment/deployer-poll-run.js +113 -0
  197. package/lib/deployment/deployer.js +17 -87
  198. package/lib/evidence/dataplane-context.js +21 -0
  199. package/lib/evidence/evidence-display.js +78 -0
  200. package/lib/evidence/evidence-service.js +392 -0
  201. package/lib/external-system/deploy.js +290 -112
  202. package/lib/external-system/download.js +7 -3
  203. package/lib/external-system/test-execution.js +1 -1
  204. package/lib/external-system/test-system-level.js +8 -10
  205. package/lib/external-system/test.js +12 -6
  206. package/lib/generator/deploy-script.js +73 -0
  207. package/lib/generator/external.js +2 -1
  208. package/lib/generator/helpers.js +13 -5
  209. package/lib/generator/index.js +17 -2
  210. package/lib/generator/split-variables.js +9 -3
  211. package/lib/generator/wizard.js +3 -36
  212. package/lib/infrastructure/helpers-docker-check.js +6 -0
  213. package/lib/infrastructure/helpers.js +1 -1
  214. package/lib/internal/fs-real-sync.js +22 -1
  215. package/lib/internal/node-fs.js +2 -0
  216. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  217. package/lib/lifecycle/verify-step-progress.js +1 -1
  218. package/lib/programmatic/access-log.js +26 -0
  219. package/lib/programmatic/auth-config.js +45 -0
  220. package/lib/programmatic/bearer-auth.js +176 -0
  221. package/lib/programmatic/builder-api-request.js +175 -0
  222. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  223. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  224. package/lib/programmatic/builder-api-server.js +230 -0
  225. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  226. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  227. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  228. package/lib/programmatic/builder-help-envelope.js +36 -0
  229. package/lib/programmatic/builder-help-fixtures.js +200 -0
  230. package/lib/programmatic/builder-help-governance.js +172 -0
  231. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  232. package/lib/programmatic/builder-help.js +361 -0
  233. package/lib/programmatic/capability-registry.js +77 -0
  234. package/lib/programmatic/command-options.js +32 -0
  235. package/lib/programmatic/enterprise-mcp-client.js +114 -0
  236. package/lib/programmatic/http-problem-details.js +99 -0
  237. package/lib/programmatic/http-route-match.js +40 -0
  238. package/lib/programmatic/idempotency-cache.js +69 -0
  239. package/lib/programmatic/index.js +53 -0
  240. package/lib/programmatic/integration-path-scope.js +39 -0
  241. package/lib/programmatic/log-redaction.js +66 -0
  242. package/lib/programmatic/manifest-get-section.js +146 -0
  243. package/lib/programmatic/manifest-patch-section.js +252 -0
  244. package/lib/programmatic/manifest-repair.js +122 -0
  245. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  246. package/lib/programmatic/manifest-section-io.js +225 -0
  247. package/lib/programmatic/manifest-section-quality.js +171 -0
  248. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  249. package/lib/programmatic/manifest-section-registry.js +222 -0
  250. package/lib/programmatic/nest-http-bridge.js +34 -0
  251. package/lib/programmatic/openapi-component-schemas.js +68 -0
  252. package/lib/programmatic/openapi-description-enricher.js +117 -0
  253. package/lib/programmatic/openapi-descriptions.js +190 -0
  254. package/lib/programmatic/openapi-docs-serving.js +123 -0
  255. package/lib/programmatic/openapi-help-schemas.js +63 -0
  256. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  257. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  258. package/lib/programmatic/openapi-request-schemas.js +155 -0
  259. package/lib/programmatic/openapi-result-schemas.js +493 -0
  260. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  261. package/lib/programmatic/openapi-schema-descriptions-core.js +162 -0
  262. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  263. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  264. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  265. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  266. package/lib/programmatic/openapi-schema-helpers.js +108 -0
  267. package/lib/programmatic/openapi-spec.js +203 -0
  268. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  269. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  270. package/lib/programmatic/request-timeout.js +53 -0
  271. package/lib/programmatic/route-handler-map.js +143 -0
  272. package/lib/programmatic/route-handlers-context.js +29 -0
  273. package/lib/programmatic/route-handlers.js +33 -0
  274. package/lib/programmatic/run-certify.js +57 -0
  275. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  276. package/lib/programmatic/run-lifecycle.js +29 -0
  277. package/lib/programmatic/run-repair.js +41 -0
  278. package/lib/programmatic/run-repository-emcp.js +62 -0
  279. package/lib/programmatic/run-template-workspace.js +74 -0
  280. package/lib/programmatic/run-test.js +49 -0
  281. package/lib/programmatic/run-upload.js +63 -0
  282. package/lib/programmatic/run-validate.js +53 -0
  283. package/lib/programmatic/run-wizard.js +40 -0
  284. package/lib/programmatic/system-key.js +48 -0
  285. package/lib/programmatic/wizard-config-normalize.js +118 -0
  286. package/lib/programmatic/workspace-cleanup.js +128 -0
  287. package/lib/programmatic/workspace-context.js +145 -0
  288. package/lib/programmatic/workspace-lock.js +75 -0
  289. package/lib/programmatic/workspace-meta.js +64 -0
  290. package/lib/programmatic/workspace-ops.js +149 -0
  291. package/lib/protection/run-commands-upload-sync.js +35 -0
  292. package/lib/protection/run-commands.js +2 -20
  293. package/lib/protection/upload-batch.js +11 -7
  294. package/lib/resolvers/evidence-kind-file.js +230 -0
  295. package/lib/resolvers/resource-type-file.js +58 -1
  296. package/lib/resolvers/role-file.js +227 -0
  297. package/lib/schema/application-schema.json +22 -2
  298. package/lib/schema/external-datasource.schema.json +245 -2
  299. package/lib/schema/external-system.schema.json +259 -119
  300. package/lib/schema/flag-map-validation-run.json +3 -0
  301. package/lib/schema/infra.parameter.yaml +25 -1
  302. package/lib/schema/type/credential-field-registry.json +21 -5
  303. package/lib/schema/type/document-storage.json +9 -0
  304. package/lib/utils/agent-trust-run-display.js +1 -1
  305. package/lib/utils/api.js +8 -2
  306. package/lib/utils/app-path-resolve.js +168 -0
  307. package/lib/utils/app-register-config.js +4 -3
  308. package/lib/utils/authentication-env-template.js +222 -0
  309. package/lib/utils/cli-sync-options.js +62 -10
  310. package/lib/utils/cli-utils.js +15 -3
  311. package/lib/utils/cli-workspace-options.js +29 -0
  312. package/lib/utils/compose-generate-docker-compose.js +102 -0
  313. package/lib/utils/configuration-env-resolver.js +203 -27
  314. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  315. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  316. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  317. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  318. package/lib/utils/datasource-test-run-display.js +2 -1
  319. package/lib/utils/dev-ca-install.js +5 -6
  320. package/lib/utils/dev-config.js +2 -2
  321. package/lib/utils/dev-init-ssh-merge.js +165 -23
  322. package/lib/utils/dev-list-sort.js +145 -0
  323. package/lib/utils/dev-pin-share-instructions.js +110 -0
  324. package/lib/utils/dev-platform-tls.js +0 -63
  325. package/lib/utils/dev-ssh-config-helper.js +177 -33
  326. package/lib/utils/docker-build.js +46 -27
  327. package/lib/utils/docker-daemon-tls-ca.js +1 -1
  328. package/lib/utils/docker-exec.js +91 -6
  329. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  330. package/lib/utils/env-copy.js +3 -4
  331. package/lib/utils/env-dotenv-format.js +103 -0
  332. package/lib/utils/error-formatters/error-parser.js +0 -3
  333. package/lib/utils/external-env-template.js +5 -2
  334. package/lib/utils/external-system-display.js +5 -1
  335. package/lib/utils/external-system-readiness-compact-blocks.js +248 -0
  336. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  337. package/lib/utils/external-system-readiness-core.js +16 -0
  338. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  339. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  340. package/lib/utils/external-system-readiness-display.js +20 -30
  341. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  342. package/lib/utils/external-system-system-test-tty.js +5 -41
  343. package/lib/utils/health-check-request.js +2 -3
  344. package/lib/utils/help-builder.js +9 -1
  345. package/lib/utils/host-ops-job-labels.js +236 -0
  346. package/lib/utils/host-ops-job-result.js +61 -0
  347. package/lib/utils/host-ops-poll-ui.js +163 -0
  348. package/lib/utils/image-name.js +22 -4
  349. package/lib/utils/integration-path-resolve.js +112 -0
  350. package/lib/utils/logger.js +37 -4
  351. package/lib/utils/manifest-source-emit.js +1 -1
  352. package/lib/utils/paths-reload-source.js +148 -0
  353. package/lib/utils/paths-system-builder-keys.js +25 -0
  354. package/lib/utils/paths.js +183 -30
  355. package/lib/utils/pipeline-upload-auth-retry.js +4 -0
  356. package/lib/utils/postgres-platform-bootstrap.js +24 -17
  357. package/lib/utils/postgres-wipe.js +5 -2
  358. package/lib/utils/remote-dev-auth.js +39 -4
  359. package/lib/utils/resolve-docker-image-ref.js +36 -6
  360. package/lib/utils/runtime-configuration-values.js +64 -2
  361. package/lib/utils/secrets-helpers.js +5 -1
  362. package/lib/utils/ssh-known-hosts.js +130 -0
  363. package/lib/utils/test-target-cli-options.js +75 -0
  364. package/lib/utils/token-manager.js +16 -0
  365. package/lib/utils/upload-sync-options.js +20 -2
  366. package/lib/utils/validation-run-request.js +11 -2
  367. package/lib/validation/external-manifest-validator.js +11 -1
  368. package/lib/validation/openapi-contract-surface-validator.js +430 -0
  369. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  370. package/lib/validation/validate-external-file.js +160 -0
  371. package/lib/validation/validate.js +6 -117
  372. package/lib/validation/validator.js +6 -5
  373. package/package.json +76 -37
  374. package/packages/builder-api/README.md +120 -0
  375. package/packages/builder-api/package.json +30 -0
  376. package/packages/builder-api/src/app.module.ts +7 -0
  377. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  378. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  379. package/packages/builder-api/src/main.ts +16 -0
  380. package/packages/builder-api/tsconfig.json +15 -0
  381. package/scripts/check-builder-api-architecture-grep.js +79 -0
  382. package/scripts/docker_image_content_gate.js +47 -0
  383. package/scripts/docker_image_content_gate.sh +5 -0
  384. package/scripts/export-builder-api-evidence.js +262 -0
  385. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  386. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  387. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  388. package/scripts/lib/plan-actor.js +109 -0
  389. package/scripts/lib/plan-config.js +20 -0
  390. package/scripts/lib/plan-gates.js +154 -0
  391. package/scripts/lib/plan-meta.js +104 -0
  392. package/scripts/lib/plan-parse.js +162 -0
  393. package/scripts/lib/plan-prevalidate-gates.js +337 -0
  394. package/scripts/lib/plan-run-core.js +125 -0
  395. package/scripts/lib/plan-run-report.js +119 -0
  396. package/scripts/plan-approve.js +24 -0
  397. package/scripts/plan-archive.js +49 -0
  398. package/scripts/plan-run.js +13 -0
  399. package/scripts/plan-set-actor.js +21 -0
  400. package/scripts/plan-validate.js +80 -0
  401. package/scripts/pnpm/af.mjs +110 -0
  402. package/scripts/pnpm/check-quiet.mjs +32 -0
  403. package/scripts/pnpm/dev-install.mjs +29 -0
  404. package/scripts/pnpm/dev-reload.mjs +18 -0
  405. package/scripts/pnpm/help.mjs +55 -0
  406. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  407. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  408. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  409. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  410. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  411. package/scripts/pnpm/lib/spinner.mjs +42 -0
  412. package/scripts/stage_builder_api_for_docker.js +65 -0
  413. package/scripts/sync-builder-api-template.js +44 -0
  414. package/templates/README.md +3 -0
  415. package/templates/applications/builder-api/Dockerfile +38 -0
  416. package/templates/applications/builder-api/application.yaml +75 -0
  417. package/templates/applications/builder-api/env.template +48 -0
  418. package/templates/applications/dataplane/application.yaml +27 -5
  419. package/templates/applications/dataplane/env.template +38 -15
  420. package/templates/applications/dataplane/rbac.yaml +85 -3
  421. package/templates/applications/miso-controller/application.yaml +10 -1
  422. package/templates/applications/miso-controller/env.template +11 -10
  423. package/templates/applications/miso-controller/rbac.yaml +72 -0
  424. package/templates/channels/README.md +18 -0
  425. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  426. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  427. package/templates/channels/chatgpt/integration/README.md +11 -0
  428. package/templates/channels/chatgpt/integration/application.json +15 -0
  429. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  430. package/templates/channels/chatgpt/integration/env.template +4 -0
  431. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  432. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  433. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  434. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  435. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  436. package/templates/channels/slack/install.template.md.hbs +48 -18
  437. package/templates/channels/slack/integration/README.md +38 -0
  438. package/templates/channels/slack/integration/application.json +18 -0
  439. package/templates/channels/slack/integration/env.template +29 -0
  440. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  441. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  442. package/templates/channels/slack/integration/slack-system.json +144 -0
  443. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  444. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  445. package/templates/channels/teams-bot/integration/README.md +18 -0
  446. package/templates/channels/teams-bot/integration/application.json +17 -0
  447. package/templates/channels/teams-bot/integration/env.template +5 -0
  448. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  449. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  450. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  451. package/templates/channels/web-embed/integration/README.md +11 -0
  452. package/templates/channels/web-embed/integration/application.json +15 -0
  453. package/templates/channels/web-embed/integration/env.template +4 -0
  454. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  455. package/templates/openapi/redoc_page.html +86 -0
  456. package/templates/python/docker-compose.hbs +11 -0
  457. package/templates/python/requirements.txt +2 -2
  458. package/templates/typescript/docker-compose.hbs +11 -0
  459. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -68,29 +68,37 @@ function extractPasswordFromUrlOrValue(urlOrPassword) {
68
68
  }
69
69
 
70
70
  /**
71
- * Escape SQL for embedding in a double-quoted shell argument (-c "...").
72
- * Bash expands `$` and `$$` (PID) inside double quotes; backslash-escape every `$`.
71
+ * Run psql -c inside the Postgres container without a shell.
72
+ * Passes SQL as an argv element so dollar-quoting (DO $$ … $$) is not mangled.
73
73
  *
74
- * @param {string} s
75
- * @returns {string}
76
- */
77
- function escapeShellDoubleQuoted(s) {
78
- return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\$/g, '\\$');
79
- }
80
-
81
- /**
82
74
  * @async
83
75
  * @param {string} container
84
76
  * @param {string} sql
85
77
  * @param {string} adminPassword
78
+ * @param {string} [database='postgres']
86
79
  * @returns {Promise<void>}
87
80
  */
88
81
  async function runPsqlCommand(container, sql, adminPassword, database = 'postgres') {
89
- const escapedSql = escapeShellDoubleQuoted(sql);
90
- const cmd =
91
- `docker exec -e PGPASSWORD -i ${container} psql -U ${SUPERUSER_ROLE} -d ${database} ` +
92
- `-v ON_ERROR_STOP=1 -c "${escapedSql}"`;
93
- await dockerExec.execWithDockerEnv(cmd, { env: { PGPASSWORD: adminPassword } });
82
+ await dockerExec.execFileWithDockerEnv(
83
+ 'docker',
84
+ [
85
+ 'exec',
86
+ '-e',
87
+ 'PGPASSWORD',
88
+ '-i',
89
+ container,
90
+ 'psql',
91
+ '-U',
92
+ SUPERUSER_ROLE,
93
+ '-d',
94
+ database,
95
+ '-v',
96
+ 'ON_ERROR_STOP=1',
97
+ '-c',
98
+ sql
99
+ ],
100
+ { env: { PGPASSWORD: adminPassword } }
101
+ );
94
102
  }
95
103
 
96
104
  /**
@@ -194,6 +202,5 @@ module.exports = {
194
202
  PLATFORM_DATABASE_SLOTS,
195
203
  bootstrapPlatformPostgresDatabases,
196
204
  pgRoleName,
197
- extractPasswordFromUrlOrValue,
198
- escapeShellDoubleQuoted
205
+ extractPasswordFromUrlOrValue
199
206
  };
@@ -86,9 +86,12 @@ async function runPsql(container, sql, adminPassword) {
86
86
  if (!adminPassword || typeof adminPassword !== 'string') {
87
87
  throw new Error('Admin password is required');
88
88
  }
89
- const escapedSql = sql.replace(/"/g, '\\"');
90
- const cmd = `docker exec -e PGPASSWORD -i ${container} psql -U ${SUPERUSER_ROLE} -d postgres -tAc "${escapedSql}"`;
89
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(container)) {
90
+ throw new Error(`Unsafe Postgres container name: ${container}`);
91
+ }
91
92
  const env = { PGPASSWORD: adminPassword };
93
+ const safeSqlToken = JSON.stringify(String(sql));
94
+ const cmd = `docker exec -e PGPASSWORD -i ${container} psql -U ${SUPERUSER_ROLE} -d postgres -tAc ${safeSqlToken}`;
92
95
  const result = (await dockerExec.execWithDockerEnv(cmd, { env })) || {};
93
96
  return String(result.stdout || '').trim();
94
97
  }
@@ -24,6 +24,17 @@ function expandConfiguredSecretsTilde(filePath) {
24
24
  return filePath;
25
25
  }
26
26
 
27
+ /** One auto-renew attempt per CLI process (shared by concurrent getRemoteDevAuth callers). */
28
+ let autoRenewPromise = null;
29
+
30
+ /**
31
+ * Reset process-level auto-renew gate (tests only).
32
+ * @returns {void}
33
+ */
34
+ function resetDevCertAutoRenewGateForTests() {
35
+ autoRenewPromise = null;
36
+ }
37
+
27
38
  /**
28
39
  * Single API object so resolveSharedSecretsEndpoint and callers share one getRemoteDevAuth
29
40
  * (Jest spies and partial mocks work reliably).
@@ -39,12 +50,11 @@ const remoteDevAuth = {
39
50
  },
40
51
 
41
52
  /**
42
- * Get Builder Server URL, client cert PEM, and optional dev root CA when remote is configured; otherwise null.
43
- * serverCaPem comes from ca.pem (saved at dev init); required for Node TLS to private-CA servers.
44
- * Use for cert-authenticated dev API calls (settings, users, ssh-keys, secrets).
53
+ * Read remote server URL + client cert from disk without auto-renew.
54
+ * Use when renewing (avoids recursion) or when only a local presence check is needed.
45
55
  * @returns {Promise<{ serverUrl: string, clientCertPem: string, serverCaPem: string|null }|null>}
46
56
  */
47
- async getRemoteDevAuth() {
57
+ async readRemoteDevAuth() {
48
58
  const serverUrl = await config.getRemoteServer();
49
59
  if (!serverUrl) return null;
50
60
  const devId = await config.getDeveloperId();
@@ -55,6 +65,30 @@ const remoteDevAuth = {
55
65
  return { serverUrl, clientCertPem, serverCaPem };
56
66
  },
57
67
 
68
+ /**
69
+ * Get Builder Server URL, client cert PEM, and optional dev root CA when remote is configured; otherwise null.
70
+ * When the client cert is still valid but expires within 14 days, renews it once per process before returning.
71
+ * serverCaPem comes from ca.pem (saved at dev init); required for Node TLS to private-CA servers.
72
+ * Use for cert-authenticated dev API calls (settings, users, ssh-keys, secrets).
73
+ * @returns {Promise<{ serverUrl: string, clientCertPem: string, serverCaPem: string|null }|null>}
74
+ */
75
+ async getRemoteDevAuth() {
76
+ const existing = await remoteDevAuth.readRemoteDevAuth();
77
+ if (!existing) return null;
78
+ if (!autoRenewPromise) {
79
+ autoRenewPromise = (async() => {
80
+ const { ensureDevCertFreshIfDue } = require('../commands/dev-refresh');
81
+ return ensureDevCertFreshIfDue({ quiet: false });
82
+ })();
83
+ }
84
+ try {
85
+ await autoRenewPromise;
86
+ } catch {
87
+ // ensureDevCertFreshIfDue already handles failures; keep using current cert
88
+ }
89
+ return remoteDevAuth.readRemoteDevAuth();
90
+ },
91
+
58
92
  /**
59
93
  * Resolve where shared secrets read/write should go. After dev init, config may still hold a
60
94
  * server-side filesystem path from GET /api/dev/settings (not an http URL) if merge did not rewrite it.
@@ -148,3 +182,4 @@ function normalizeSharedSecretsFilePath(configured) {
148
182
  }
149
183
 
150
184
  module.exports = remoteDevAuth;
185
+ module.exports.resetDevCertAutoRenewGateForTests = resetDevCertAutoRenewGateForTests;
@@ -12,6 +12,32 @@
12
12
  'use strict';
13
13
 
14
14
  const { parseImageOverride } = require('./parse-image-ref');
15
+ const DOCKER_REPOSITORY_RE = /^[a-z0-9][a-z0-9._/-]*$/i;
16
+ const DOCKER_TAG_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
17
+
18
+ /**
19
+ * @param {string} repository
20
+ * @returns {string}
21
+ */
22
+ function assertSafeRepository(repository) {
23
+ const trimmed = String(repository || '').trim();
24
+ if (!trimmed || !DOCKER_REPOSITORY_RE.test(trimmed)) {
25
+ throw new Error(`Invalid Docker repository path: ${repository}`);
26
+ }
27
+ return trimmed;
28
+ }
29
+
30
+ /**
31
+ * @param {string} tag
32
+ * @returns {string}
33
+ */
34
+ function assertSafeTag(tag) {
35
+ const trimmed = String(tag || '').trim();
36
+ if (!trimmed || !DOCKER_TAG_RE.test(trimmed)) {
37
+ throw new Error(`Invalid Docker image tag: ${tag}`);
38
+ }
39
+ return trimmed;
40
+ }
15
41
 
16
42
  /**
17
43
  * Repository path without host (same rules as compose-generator getImageName).
@@ -59,7 +85,11 @@ function normalizeDockerRegistryPrefix(registry) {
59
85
  if (!t) {
60
86
  return '';
61
87
  }
62
- return t.replace(/\/+$/, '');
88
+ let end = t.length;
89
+ while (end > 0 && t[end - 1] === '/') {
90
+ end -= 1;
91
+ }
92
+ return t.slice(0, end);
63
93
  }
64
94
 
65
95
  /**
@@ -81,18 +111,18 @@ function resolveDockerImageRef(appName, appConfig, runOptions = {}) {
81
111
  if (opts.image) {
82
112
  const parsed = parseImageOverride(opts.image);
83
113
  return {
84
- imageName: parsed ? parsed.name : getRepositoryPathFromConfig(appConfig, appName),
85
- imageTag: parsed ? parsed.tag : tagFromOpts || imageTagFromConfig(appConfig)
114
+ imageName: assertSafeRepository(parsed ? parsed.name : getRepositoryPathFromConfig(appConfig, appName)),
115
+ imageTag: assertSafeTag(parsed ? parsed.tag : tagFromOpts || imageTagFromConfig(appConfig))
86
116
  };
87
117
  }
88
118
 
89
- const baseRepo = getRepositoryPathFromConfig(appConfig, appName);
90
- const imageTag = tagFromOpts || imageTagFromConfig(appConfig);
119
+ const baseRepo = assertSafeRepository(getRepositoryPathFromConfig(appConfig, appName));
120
+ const imageTag = assertSafeTag(tagFromOpts || imageTagFromConfig(appConfig));
91
121
  const prefix =
92
122
  normalizeDockerRegistryPrefix(opts.registry) ||
93
123
  normalizeDockerRegistryPrefix(appConfig?.image?.registry ?? '');
94
124
  if (prefix) {
95
- return { imageName: `${prefix}/${baseRepo}`, imageTag };
125
+ return { imageName: assertSafeRepository(`${prefix}/${baseRepo}`), imageTag };
96
126
  }
97
127
  return { imageName: baseRepo, imageTag };
98
128
  }
@@ -44,6 +44,65 @@ function collectSystemVariablePutRequests(systemConfiguration, envMap) {
44
44
  return requests;
45
45
  }
46
46
 
47
+ /** OpenAPI path param names resolved from env.template (not valid configuration[] names). */
48
+ const OPENAPI_PATH_PARAM_ENV_KEYS = ['systemKey', 'pillar'];
49
+
50
+ const PATH_PARAM_FALLBACK_ENV_KEYS = {
51
+ systemKey: 'E2E_SYSTEM_KEY',
52
+ pillar: 'E2E_CERTIFY_PILLAR'
53
+ };
54
+
55
+ /**
56
+ * @param {unknown} raw
57
+ * @param {{ allowKv?: boolean }} [options]
58
+ * @returns {string|null}
59
+ */
60
+ function resolvedEnvLiteral(raw, options = {}) {
61
+ if (raw === undefined || raw === null) {
62
+ return null;
63
+ }
64
+ const value = String(raw).trim();
65
+ if (!value || value.includes('{{')) {
66
+ return null;
67
+ }
68
+ if (!options.allowKv && value.startsWith('kv://')) {
69
+ return null;
70
+ }
71
+ return value;
72
+ }
73
+
74
+ function resolvePathParamValue(envMap, name) {
75
+ const direct = resolvedEnvLiteral(envMap[name]);
76
+ if (direct) {
77
+ return direct;
78
+ }
79
+ const fallbackKey = PATH_PARAM_FALLBACK_ENV_KEYS[name];
80
+ if (!fallbackKey) {
81
+ return null;
82
+ }
83
+ return resolvedEnvLiteral(envMap[fallbackKey], { allowKv: true });
84
+ }
85
+
86
+ /**
87
+ * @param {Object.<string, string>} envMap
88
+ * @param {Set<string>} [alreadyPushed]
89
+ * @returns {Array<{ name: string, value: string }>}
90
+ */
91
+ function collectOpenApiPathParamAliasPutRequests(envMap, alreadyPushed = new Set()) {
92
+ const requests = [];
93
+ for (const name of OPENAPI_PATH_PARAM_ENV_KEYS) {
94
+ if (alreadyPushed.has(name)) {
95
+ continue;
96
+ }
97
+ const value = resolvePathParamValue(envMap, name);
98
+ if (!value) {
99
+ continue;
100
+ }
101
+ requests.push({ name, value });
102
+ }
103
+ return requests;
104
+ }
105
+
47
106
  /**
48
107
  * Datasource overrides are name+value only; values may already be resolved in upload payload.
49
108
  *
@@ -83,7 +142,7 @@ function collectDatasourceOverridePutRequests(datasourceConfiguration) {
83
142
  * @returns {Promise<{ pushed: number, names: string[] }>}
84
143
  */
85
144
  async function pushRuntimeConfigurationValues(dataplaneUrl, authConfig, systemKey, payload) {
86
- const { envMap } = await buildResolvedEnvMapForIntegration(systemKey);
145
+ const { envMap } = await buildResolvedEnvMapForIntegration(systemKey, { dataplaneRuntime: true });
87
146
  const names = [];
88
147
  let pushed = 0;
89
148
 
@@ -91,7 +150,9 @@ async function pushRuntimeConfigurationValues(dataplaneUrl, authConfig, systemKe
91
150
  payload?.application?.configuration,
92
151
  envMap
93
152
  );
94
- for (const body of systemRequests) {
153
+ const pushedNames = new Set(systemRequests.map((r) => r.name));
154
+ const aliasRequests = collectOpenApiPathParamAliasPutRequests(envMap, pushedNames);
155
+ for (const body of [...systemRequests, ...aliasRequests]) {
95
156
  await putExternalSystemConfiguration(dataplaneUrl, systemKey, authConfig, body);
96
157
  names.push(body.name);
97
158
  pushed += 1;
@@ -114,6 +175,7 @@ async function pushRuntimeConfigurationValues(dataplaneUrl, authConfig, systemKe
114
175
 
115
176
  module.exports = {
116
177
  collectSystemVariablePutRequests,
178
+ collectOpenApiPathParamAliasPutRequests,
117
179
  collectDatasourceOverridePutRequests,
118
180
  pushRuntimeConfigurationValues
119
181
  };
@@ -226,7 +226,11 @@ function replaceKvInContent(content, secrets, envVars, scopedKv = null) {
226
226
  return envVars[envVar] || m;
227
227
  });
228
228
  }
229
- return value !== null && value !== undefined ? String(value) : match;
229
+ if (value !== null && value !== undefined) {
230
+ const { formatDotenvSubstitutionValue } = require('./env-dotenv-format');
231
+ return formatDotenvSubstitutionValue(String(value));
232
+ }
233
+ return match;
230
234
  });
231
235
  return replaced + suffix;
232
236
  });
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Remove stale OpenSSH known_hosts entries after server reprovision or Host alias rename.
3
+ *
4
+ * @fileoverview ssh-keygen -R helpers for dev init / refresh
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { execFile } = require('child_process');
12
+ const { promisify } = require('util');
13
+ const path = require('path');
14
+ const { getDefaultSshDir } = require('./ssh-key-helper');
15
+ const { getDevSshHostAlias, resolveDevSshHostAlias } = require('./dev-ssh-config-helper');
16
+
17
+ const execFileAsync = promisify(execFile);
18
+
19
+ /**
20
+ * @param {string} baseUrl
21
+ * @returns {string|null}
22
+ */
23
+ function hostnameFromBaseUrl(baseUrl) {
24
+ if (!baseUrl || typeof baseUrl !== 'string') return null;
25
+ const s = baseUrl.trim().replace(/\/+$/, '');
26
+ const withProtocol = /^https?:\/\//i.test(s) ? s : `https://${s}`;
27
+ try {
28
+ return new URL(withProtocol).hostname || null;
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @param {string} hostname
36
+ * @param {string} knownHostsPath
37
+ * @returns {Promise<{ hostname: string, ok: boolean, error?: string }>}
38
+ */
39
+ async function removeKnownHostEntry(hostname, knownHostsPath) {
40
+ const host = String(hostname || '').trim();
41
+ if (!host) {
42
+ return { hostname: host, ok: false, error: 'empty hostname' };
43
+ }
44
+ try {
45
+ await execFileAsync('ssh-keygen', ['-R', host, '-f', knownHostsPath], {
46
+ encoding: 'utf8'
47
+ });
48
+ return { hostname: host, ok: true };
49
+ } catch (err) {
50
+ if (err && err.code === 'ENOENT') {
51
+ return { hostname: host, ok: false, error: 'ssh-keygen not found' };
52
+ }
53
+ return { hostname: host, ok: false, error: err.message || String(err) };
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Hostnames that may appear in known_hosts for a Builder dev SSH connection.
59
+ * Includes current Host alias, HostName (sync-ssh-host), remote-server host, and legacy Host aliases.
60
+ *
61
+ * @param {Object} p
62
+ * @param {string} p.syncHost - sync-ssh-host / HostName
63
+ * @param {string} p.syncUser - sync-ssh-user
64
+ * @param {string} [p.hostAlias] - Preferred ssh config Host alias
65
+ * @param {string} [p.baseUrl] - remote-server URL
66
+ * @param {string} [p.developerId]
67
+ * @param {string} [p.developerRootDomain]
68
+ * @param {string[]} [p.legacyHostAliases] - Previous Host keywords from ~/.ssh/config
69
+ * @returns {string[]}
70
+ */
71
+ function collectDevSshKnownHostCandidates(p) {
72
+ const syncHost = String(p.syncHost || '').trim();
73
+ const syncUser = String(p.syncUser || '').trim();
74
+ const candidates = new Set();
75
+ if (syncHost) {
76
+ candidates.add(syncHost);
77
+ }
78
+ if (p.hostAlias) {
79
+ candidates.add(String(p.hostAlias).trim());
80
+ }
81
+ const preferred = resolveDevSshHostAlias({
82
+ syncUser,
83
+ syncHost,
84
+ developerId: p.developerId,
85
+ developerRootDomain: p.developerRootDomain
86
+ });
87
+ if (preferred) {
88
+ candidates.add(preferred);
89
+ }
90
+ if (syncUser && syncHost) {
91
+ candidates.add(getDevSshHostAlias(syncUser, syncHost));
92
+ }
93
+ const fromUrl = hostnameFromBaseUrl(p.baseUrl);
94
+ if (fromUrl) {
95
+ candidates.add(fromUrl);
96
+ }
97
+ for (const alias of p.legacyHostAliases || []) {
98
+ const trimmed = String(alias || '').trim();
99
+ if (trimmed) {
100
+ candidates.add(trimmed);
101
+ }
102
+ }
103
+ return [...candidates].filter(Boolean);
104
+ }
105
+
106
+ /**
107
+ * @param {string[]} hostnames
108
+ * @param {string} [sshDir]
109
+ * @returns {Promise<{ cleared: string[], failed: Array<{ hostname: string, error: string }> }>}
110
+ */
111
+ async function refreshDevSshKnownHosts(hostnames, sshDir) {
112
+ const knownHostsPath = path.join(sshDir || getDefaultSshDir(), 'known_hosts');
113
+ const cleared = [];
114
+ const failed = [];
115
+ for (const hostname of hostnames) {
116
+ const result = await removeKnownHostEntry(hostname, knownHostsPath);
117
+ if (result.ok) {
118
+ cleared.push(result.hostname);
119
+ } else if (result.error && result.error !== 'empty hostname') {
120
+ failed.push({ hostname: result.hostname, error: result.error });
121
+ }
122
+ }
123
+ return { cleared, failed };
124
+ }
125
+
126
+ module.exports = {
127
+ collectDevSshKnownHostCandidates,
128
+ removeKnownHostEntry,
129
+ refreshDevSshKnownHosts
130
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @fileoverview CLI normalization for manifest version target and test sync policy (456.17).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const SYNC_MODES = new Set(['auto', 'never', 'force']);
10
+ const VERSION_KEYWORDS = new Set(['latest', 'running']);
11
+
12
+ /**
13
+ * @param {string|undefined|null} raw
14
+ * @param {string} [defaultValue='latest']
15
+ * @returns {string}
16
+ */
17
+ function normalizeVersionTarget(raw, defaultValue = 'latest') {
18
+ const value = String(raw ?? defaultValue).trim();
19
+ if (!value) {
20
+ throw new Error('--version is required (latest, running, or explicit version id).');
21
+ }
22
+ const lower = value.toLowerCase();
23
+ if (VERSION_KEYWORDS.has(lower)) {
24
+ return lower;
25
+ }
26
+ if (!/^[a-zA-Z0-9._-]+$/.test(value)) {
27
+ throw new Error(
28
+ '--version must be latest, running, or an explicit version id (letters, numbers, ., _, -).'
29
+ );
30
+ }
31
+ return value;
32
+ }
33
+
34
+ /**
35
+ * @param {string|undefined|null} raw
36
+ * @param {string} [defaultValue='auto']
37
+ * @returns {string}
38
+ */
39
+ function normalizeSyncMode(raw, defaultValue = 'auto') {
40
+ const value = String(raw ?? defaultValue).trim().toLowerCase();
41
+ if (!SYNC_MODES.has(value)) {
42
+ throw new Error('--sync-mode must be auto, never, or force.');
43
+ }
44
+ return value;
45
+ }
46
+
47
+ /**
48
+ * Merge versionTarget and syncMode from CLI options into e2eOptions for ValidationRunRequest.
49
+ *
50
+ * @param {Object} cliOptions - Commander-parsed options
51
+ * @param {Object} [e2eOptions={}]
52
+ * @returns {Object}
53
+ */
54
+ function mergeTestTargetIntoE2eOptions(cliOptions, e2eOptions = {}) {
55
+ const merged = { ...e2eOptions };
56
+ if (cliOptions && cliOptions.version !== undefined && cliOptions.version !== null) {
57
+ merged.versionTarget = normalizeVersionTarget(cliOptions.version);
58
+ } else {
59
+ merged.versionTarget = normalizeVersionTarget(undefined, 'latest');
60
+ }
61
+ if (cliOptions && cliOptions.syncMode !== undefined && cliOptions.syncMode !== null) {
62
+ merged.syncMode = normalizeSyncMode(cliOptions.syncMode);
63
+ } else {
64
+ merged.syncMode = normalizeSyncMode(undefined, 'auto');
65
+ }
66
+ return merged;
67
+ }
68
+
69
+ module.exports = {
70
+ SYNC_MODES,
71
+ VERSION_KEYWORDS,
72
+ normalizeVersionTarget,
73
+ normalizeSyncMode,
74
+ mergeTestTargetIntoE2eOptions
75
+ };
@@ -409,13 +409,29 @@ function applyLabDataplaneApiKeyBearer(authConfig) {
409
409
  }
410
410
 
411
411
  function requireBearerForDataplanePipeline(authConfig) {
412
+ if (!authConfig || typeof authConfig !== 'object') {
413
+ return;
414
+ }
415
+
412
416
  if (authConfig.type === 'client-token' && authConfig.token) {
413
417
  return;
414
418
  }
415
419
 
420
+ // Token-forward (builder-api / bearerForward): never substitute lab API_KEY for the caller JWT.
421
+ if (authConfig.preserveBearer && authConfig.token) {
422
+ return;
423
+ }
424
+
416
425
  const preferAppClientToken =
417
426
  String(process.env.AIFABRIX_DEPLOYMENT_AUTH || '').toLowerCase() === 'client-credentials';
418
427
 
428
+ const existing = authConfig.token ? String(authConfig.token) : '';
429
+ const looksLikeJwt = existing.split('.').length === 3 && existing.length > 80;
430
+ // Enterprise path: keep a real OAuth JWT; do not overwrite with process.env.API_KEY.
431
+ if (looksLikeJwt) {
432
+ return;
433
+ }
434
+
419
435
  if (!preferAppClientToken && process.env.API_KEY) {
420
436
  const apiKey = String(process.env.API_KEY);
421
437
  if (authConfig.type === 'bearer' && authConfig.token !== apiKey) {
@@ -10,20 +10,38 @@
10
10
 
11
11
  /**
12
12
  * @param {Object} [options] - CLI options from test / sync callers
13
- * @returns {{ minimal: true, verbose: boolean, silentResolve: true, syncMode: true, force?: true }}
13
+ * @returns {{ minimal: true, verbose: boolean, silentResolve: true, syncMode: true, force?: true, authConfig?: Object, dataplaneUrl?: string, environment?: string }}
14
14
  */
15
15
  function buildMinimalUploadSyncOptions(options = {}) {
16
+ const deployPreflight = options.uploadContext === 'deploy-preflight';
16
17
  const out = {
17
18
  minimal: true,
18
19
  // CLI -v on verify-* / test-* is for run output, not preflight upload banners.
19
20
  verbose: false,
20
21
  silentResolve: true,
21
22
  syncMode: true,
22
- suppressPipelineSpinner: options.suppressPipelineSpinner === true
23
+ skipDataSync: true,
24
+ suppressPipelineSpinner:
25
+ options.suppressPipelineSpinner === true || deployPreflight === true
23
26
  };
24
27
  if (options.force === true) {
25
28
  out.force = true;
26
29
  }
30
+ if (options.suppressSummary === true || deployPreflight === true) {
31
+ out.suppressSummary = true;
32
+ }
33
+ if (deployPreflight) {
34
+ out.uploadContext = 'deploy-preflight';
35
+ }
36
+ // Builder-api / programmatic callers: keep request Bearer — do not fall back to
37
+ // getDeploymentAuth against a stale mount AIFABRIX_CONFIG device token.
38
+ if (options.authConfig && options.dataplaneUrl) {
39
+ out.authConfig = options.authConfig;
40
+ out.dataplaneUrl = options.dataplaneUrl;
41
+ if (options.environment) {
42
+ out.environment = options.environment;
43
+ }
44
+ }
27
45
  return out;
28
46
  }
29
47
 
@@ -4,6 +4,8 @@
4
4
  * @version 2.0.0
5
5
  */
6
6
 
7
+ const { mergeTestTargetIntoE2eOptions, normalizeVersionTarget } = require('./test-target-cli-options');
8
+
7
9
  /**
8
10
  * Whether the unified validation request should set includeDebug (any `--debug` or `--debug <level>`).
9
11
  * @param {*} debugOpt - Commander `options.debug`
@@ -60,7 +62,7 @@ function buildE2eOptionsFromCli(options = {}) {
60
62
  if (options.e2eOptionsExtra && typeof options.e2eOptionsExtra === 'object') {
61
63
  Object.assign(e2e, options.e2eOptionsExtra);
62
64
  }
63
- return e2e;
65
+ return mergeTestTargetIntoE2eOptions(options, e2e);
64
66
  }
65
67
 
66
68
  /**
@@ -73,6 +75,8 @@ function buildE2eOptionsFromCli(options = {}) {
73
75
  * @param {boolean} [params.asyncRun]
74
76
  * @param {boolean} [params.includeDebug]
75
77
  * @param {boolean} [params.explain]
78
+ * @param {boolean} [params.explainCertification]
79
+ * @param {boolean} [params.explainMetrics]
76
80
  * @param {Object} [params.e2eOptions] - Merged with buildE2eOptionsFromCli when both used by caller
77
81
  * @returns {import('../api/types/validation-run.types').ValidationRunRequestBody}
78
82
  */
@@ -85,6 +89,8 @@ function buildExternalDataSourceValidationRequest(params) {
85
89
  asyncRun,
86
90
  includeDebug,
87
91
  explain,
92
+ explainCertification,
93
+ explainMetrics,
88
94
  e2eOptions
89
95
  } = params;
90
96
  if (!systemKey || !datasourceKey || !runType) {
@@ -101,6 +107,8 @@ function buildExternalDataSourceValidationRequest(params) {
101
107
  if (asyncRun === true) body.asyncRun = true;
102
108
  if (includeDebug === true) body.includeDebug = true;
103
109
  if (explain === true) body.explain = true;
110
+ if (explainCertification === true) body.explainCertification = true;
111
+ if (explainMetrics === true) body.explainMetrics = true;
104
112
  if (e2eOptions && typeof e2eOptions === 'object' && Object.keys(e2eOptions).length > 0) {
105
113
  body.e2eOptions = e2eOptions;
106
114
  }
@@ -110,5 +118,6 @@ function buildExternalDataSourceValidationRequest(params) {
110
118
  module.exports = {
111
119
  includeDebugForRequest,
112
120
  buildE2eOptionsFromCli,
113
- buildExternalDataSourceValidationRequest
121
+ buildExternalDataSourceValidationRequest,
122
+ normalizeVersionTarget
114
123
  };