@aifabrix/builder 2.45.5 → 2.47.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 (355) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/project-rules.mdc +1 -0
  4. package/.npmrc.token +1 -0
  5. package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
  6. package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
  7. package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
  8. package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
  9. package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
  10. package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
  11. package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
  12. package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
  13. package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
  14. package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
  15. package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
  16. package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
  17. package/.temp/validation/summary.txt +5 -0
  18. package/README.md +43 -17
  19. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  20. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  21. package/jest.config.default.js +2 -1
  22. package/jest.config.isolated.js +2 -1
  23. package/jest.global-live-fabrix-hooks.js +36 -0
  24. package/jest.isolated-projects.js +146 -0
  25. package/jest.projects.js +65 -136
  26. package/lib/api/api-response-errors.js +124 -0
  27. package/lib/api/dataplane-health.api.js +19 -7
  28. package/lib/api/governance-scenario-pack.api.js +159 -0
  29. package/lib/api/index.js +43 -3
  30. package/lib/api/lifecycle.api.js +98 -0
  31. package/lib/api/pipeline.api.js +3 -1
  32. package/lib/api/records-bulk.api.js +14 -1
  33. package/lib/api/resource-types.api.js +107 -0
  34. package/lib/api/runtime-configuration.api.js +72 -0
  35. package/lib/api/types/resource-types.types.js +45 -0
  36. package/lib/api/user-groups.api.js +9 -9
  37. package/lib/api/users.api.js +8 -8
  38. package/lib/api/validation-runner.js +3 -1
  39. package/lib/api/wizard.api.js +10 -2
  40. package/lib/app/deploy-config.js +4 -1
  41. package/lib/app/down.js +78 -27
  42. package/lib/app/index.js +2 -2
  43. package/lib/app/push.js +4 -5
  44. package/lib/app/register.js +7 -4
  45. package/lib/app/run-env-compose.js +84 -30
  46. package/lib/app/run-resolve-image.js +2 -1
  47. package/lib/app/run-stop-containers.js +113 -0
  48. package/lib/app/run.js +1 -31
  49. package/lib/app/show-display.js +35 -0
  50. package/lib/app/show.js +32 -1
  51. package/lib/build/index.js +22 -5
  52. package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
  53. package/lib/certification/sync-system-certification.js +13 -6
  54. package/lib/channels/add-channel.js +348 -0
  55. package/lib/channels/channel-artifact-generator.js +141 -0
  56. package/lib/channels/channel-audit.js +101 -0
  57. package/lib/channels/channel-auth-context.js +37 -0
  58. package/lib/channels/channel-credential.js +200 -0
  59. package/lib/channels/channel-display-name.js +64 -0
  60. package/lib/channels/channel-external-system.js +106 -0
  61. package/lib/channels/channel-integration-generator.js +274 -0
  62. package/lib/channels/channel-probe.js +89 -0
  63. package/lib/channels/channel-runtime-resolver.js +152 -0
  64. package/lib/channels/channel-status-display.js +141 -0
  65. package/lib/channels/channel-targets.js +115 -0
  66. package/lib/cli/index.js +20 -4
  67. package/lib/cli/infra-guided-auth.js +109 -0
  68. package/lib/cli/infra-guided.js +84 -81
  69. package/lib/cli/setup-app.help.js +0 -31
  70. package/lib/cli/setup-app.js +82 -5
  71. package/lib/cli/setup-app.test-commands.js +5 -57
  72. package/lib/cli/setup-auth.js +25 -0
  73. package/lib/cli/setup-certification-commands.js +147 -0
  74. package/lib/cli/setup-certification.help.js +141 -0
  75. package/lib/cli/setup-environment.js +19 -2
  76. package/lib/cli/setup-external-system-help.js +62 -0
  77. package/lib/cli/setup-external-system.js +25 -3
  78. package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
  79. package/lib/cli/setup-infra-up-platform-action.js +2 -1
  80. package/lib/cli/setup-infra.js +9 -1
  81. package/lib/cli/setup-platform.js +6 -1
  82. package/lib/cli/setup-secrets.js +33 -1
  83. package/lib/cli/setup-utility-help-after.js +25 -2
  84. package/lib/cli/setup-utility-repair.js +198 -0
  85. package/lib/cli/setup-utility-resolve.js +44 -5
  86. package/lib/cli/setup-utility-validate.js +197 -0
  87. package/lib/cli/setup-utility.js +4 -239
  88. package/lib/commands/app-logs.js +54 -26
  89. package/lib/commands/app.js +41 -0
  90. package/lib/commands/auth-status-client-tokens.js +214 -0
  91. package/lib/commands/auth-status-dataplane-version.js +142 -68
  92. package/lib/commands/auth-status.js +43 -54
  93. package/lib/commands/channel.js +58 -0
  94. package/lib/commands/datasource-test-trust-cli.js +27 -23
  95. package/lib/commands/datasource-unified-test-cli.js +6 -3
  96. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  97. package/lib/commands/datasource.js +8 -8
  98. package/lib/commands/dev-show-display.js +8 -1
  99. package/lib/commands/governance-cli-shared.js +94 -0
  100. package/lib/commands/governance-command-action.js +132 -0
  101. package/lib/commands/governance-download-external.js +34 -0
  102. package/lib/commands/governance-generate-external.js +71 -0
  103. package/lib/commands/governance-upload-external.js +36 -0
  104. package/lib/commands/governance-verify-external.js +64 -0
  105. package/lib/commands/governance.js +144 -0
  106. package/lib/commands/identity-apply-sync.js +49 -8
  107. package/lib/commands/identity-group-cli.js +66 -26
  108. package/lib/commands/identity-membership-role-cache.js +58 -37
  109. package/lib/commands/identity-shared.js +22 -1
  110. package/lib/commands/identity-user-cli.js +80 -34
  111. package/lib/commands/lifecycle-command-action.js +123 -0
  112. package/lib/commands/lifecycle-external.js +268 -0
  113. package/lib/commands/login.js +11 -2
  114. package/lib/commands/repair-auth-apply.js +153 -0
  115. package/lib/commands/repair-auth-config.js +8 -13
  116. package/lib/commands/repair-changed-files.js +41 -0
  117. package/lib/commands/repair-datasource-com-v2.js +15 -0
  118. package/lib/commands/repair-datasource-keys.js +4 -1
  119. package/lib/commands/repair-datasource-run.js +59 -0
  120. package/lib/commands/repair-datasource-service-contract.js +206 -0
  121. package/lib/commands/repair-datasource-test-payload.js +259 -0
  122. package/lib/commands/repair-datasource.js +49 -64
  123. package/lib/commands/repair-env-template.js +76 -25
  124. package/lib/commands/repair-external-run.js +216 -0
  125. package/lib/commands/repair-openapi-sync.js +49 -4
  126. package/lib/commands/repair-persist.js +4 -0
  127. package/lib/commands/repair-rbac.js +52 -1
  128. package/lib/commands/repair-steps.js +160 -0
  129. package/lib/commands/repair-system-alignment.js +7 -4
  130. package/lib/commands/repair.js +29 -296
  131. package/lib/commands/resource-type.js +371 -0
  132. package/lib/commands/secrets-get.js +184 -0
  133. package/lib/commands/secrets-remove-all.js +3 -1
  134. package/lib/commands/setup-image-refresh.js +146 -0
  135. package/lib/commands/setup-modes.js +158 -162
  136. package/lib/commands/setup-platform-auth.js +76 -0
  137. package/lib/commands/setup-prompts-admin.js +244 -0
  138. package/lib/commands/setup-prompts-platform-mode.js +70 -0
  139. package/lib/commands/setup-prompts-validators.js +36 -0
  140. package/lib/commands/setup-prompts.js +24 -76
  141. package/lib/commands/setup-run-context.js +45 -0
  142. package/lib/commands/setup-spinners.js +39 -0
  143. package/lib/commands/setup.js +27 -5
  144. package/lib/commands/teardown.js +39 -0
  145. package/lib/commands/test-e2e-external.js +24 -8
  146. package/lib/commands/test-governance-external.js +3 -24
  147. package/lib/commands/test-trust-external.js +48 -100
  148. package/lib/commands/up-common.js +57 -13
  149. package/lib/commands/up-dataplane.js +56 -15
  150. package/lib/commands/upload-publish-context.js +75 -0
  151. package/lib/commands/upload-sidecar-followups.js +89 -0
  152. package/lib/commands/upload.js +113 -110
  153. package/lib/commands/verify-governance-combined-external.js +61 -0
  154. package/lib/commands/verify-governance-command-action.js +64 -0
  155. package/lib/commands/verify-governance-db.js +102 -0
  156. package/lib/commands/verify-governance-external.js +77 -0
  157. package/lib/commands/verify-governance-result-builders.js +71 -0
  158. package/lib/commands/verify-operations-command-action.js +68 -0
  159. package/lib/commands/verify-operations-external.js +268 -0
  160. package/lib/commands/verify-operations-persist.js +75 -0
  161. package/lib/commands/verify-operations-step-plan.js +68 -0
  162. package/lib/commands/verify-operations-steps.js +111 -0
  163. package/lib/commands/verify-trust-command-action.js +73 -0
  164. package/lib/commands/verify-trust-external.js +59 -0
  165. package/lib/commands/wizard-config-normalizer.js +43 -23
  166. package/lib/commands/wizard-core.js +2 -0
  167. package/lib/core/admin-password-generator.js +38 -0
  168. package/lib/core/admin-secrets-bundle.js +111 -0
  169. package/lib/core/admin-secrets-env-overlay.js +62 -0
  170. package/lib/core/admin-secrets.js +32 -4
  171. package/lib/core/config-attach-extensions.js +3 -0
  172. package/lib/core/config-platform-controller.js +44 -0
  173. package/lib/core/config-setup-installation-profile.js +42 -0
  174. package/lib/core/config-setup-platform-mode.js +46 -0
  175. package/lib/core/config.js +46 -36
  176. package/lib/core/secrets-admin-env.js +6 -2
  177. package/lib/core/secrets-ensure.js +4 -0
  178. package/lib/core/secrets-env-content.js +54 -48
  179. package/lib/core/secrets-env-write.js +10 -1
  180. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  181. package/lib/core/setup-installation-profile.js +43 -0
  182. package/lib/core/setup-platform-mode.js +90 -0
  183. package/lib/datasource/agent-trust-debug-log.js +1 -1
  184. package/lib/datasource/agent-trust-run.js +5 -3
  185. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  186. package/lib/datasource/audit-evidence-extract.js +7 -4
  187. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  188. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  189. package/lib/datasource/capability/capability-diff-slice.js +2 -2
  190. package/lib/datasource/capability/capability-manifest.js +254 -0
  191. package/lib/datasource/capability/capability-resolve.js +3 -4
  192. package/lib/datasource/capability/copy-operations.js +5 -3
  193. package/lib/datasource/capability/remove-operations.js +2 -1
  194. package/lib/datasource/capability/run-capability-copy.js +32 -4
  195. package/lib/datasource/capability/run-capability-diff.js +3 -3
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -4
  197. package/lib/datasource/capability/run-capability-edit.js +4 -7
  198. package/lib/datasource/capability/run-capability-relate.js +2 -4
  199. package/lib/datasource/capability/run-capability-remove.js +2 -4
  200. package/lib/datasource/capability/validate-capability-slice.js +2 -1
  201. package/lib/datasource/datasource-identifier.js +2 -1
  202. package/lib/datasource/datasource-load-export-context.js +3 -0
  203. package/lib/datasource/datasource-validate-display.js +1 -1
  204. package/lib/datasource/field-reference-validator.js +24 -3
  205. package/lib/datasource/log-cleaner.js +2 -2
  206. package/lib/datasource/log-viewer.js +8 -8
  207. package/lib/datasource/orphan-profiles-validator.js +98 -0
  208. package/lib/datasource/test-e2e.js +4 -1
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run.js +5 -2
  211. package/lib/datasource/validate.js +41 -23
  212. package/lib/deployment/environment-poll-status.js +138 -0
  213. package/lib/deployment/environment.js +42 -34
  214. package/lib/external-system/download-helpers.js +87 -0
  215. package/lib/external-system/download.js +78 -138
  216. package/lib/external-system/generator.js +1 -55
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test.js +16 -21
  220. package/lib/generator/builders.js +11 -1
  221. package/lib/generator/external-controller-manifest.js +18 -0
  222. package/lib/generator/split.js +3 -1
  223. package/lib/generator/wizard.js +1 -28
  224. package/lib/governance/governance-cli-errors.js +96 -0
  225. package/lib/governance/governance-download-display.js +38 -0
  226. package/lib/governance/governance-run-display.js +215 -25
  227. package/lib/identity/fk-reference.js +65 -0
  228. package/lib/identity/identity-apply-core.js +13 -58
  229. package/lib/identity/identity-apply-phases.js +5 -1
  230. package/lib/identity/identity-display.js +243 -0
  231. package/lib/identity/identity-response-helpers.js +52 -0
  232. package/lib/identity/identity-sync-errors.js +62 -0
  233. package/lib/identity/resolve-user-id.js +129 -0
  234. package/lib/identity/username-default.js +31 -0
  235. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  236. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  237. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  238. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  239. package/lib/infrastructure/helpers.js +23 -129
  240. package/lib/infrastructure/index.js +5 -6
  241. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  242. package/lib/lifecycle/certification-progress.js +231 -0
  243. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  244. package/lib/lifecycle/exit-codes.js +24 -0
  245. package/lib/lifecycle/json-envelope.js +25 -0
  246. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  247. package/lib/lifecycle/logger-quiet.js +29 -0
  248. package/lib/lifecycle/open-api-published.js +59 -0
  249. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  250. package/lib/lifecycle/product-model.js +196 -0
  251. package/lib/lifecycle/report-display-trust.js +70 -0
  252. package/lib/lifecycle/report-display.js +472 -0
  253. package/lib/lifecycle/scenario-upload.js +191 -0
  254. package/lib/lifecycle/verify-step-progress.js +87 -0
  255. package/lib/parameters/infra-kv-discovery.js +27 -2
  256. package/lib/protection/auth-context.js +10 -4
  257. package/lib/resolvers/datasource-resolver.js +2 -3
  258. package/lib/resolvers/resource-type-file.js +159 -0
  259. package/lib/schema/application-schema.json +17 -1
  260. package/lib/schema/datasource-test-run.schema.json +89 -6
  261. package/lib/schema/deployment-rules.yaml +2 -1
  262. package/lib/schema/external-datasource.schema.json +2947 -2619
  263. package/lib/schema/external-system.schema.json +1418 -761
  264. package/lib/schema/infra.parameter.yaml +45 -0
  265. package/lib/schema/type/credential-field-registry.json +103 -97
  266. package/lib/schema/type/document-storage.json +9 -5
  267. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  268. package/lib/utils/api.js +55 -31
  269. package/lib/utils/app-relative-path-env.js +112 -0
  270. package/lib/utils/app-run-containers.js +25 -2
  271. package/lib/utils/authentication-shape.js +224 -0
  272. package/lib/utils/build-copy.js +36 -5
  273. package/lib/utils/build-resolve-image.js +66 -12
  274. package/lib/utils/celery-companion-apps.js +53 -0
  275. package/lib/utils/cli-secrets-error-format.js +83 -21
  276. package/lib/utils/cli-utils.js +20 -4
  277. package/lib/utils/compose-celery-worker.js +23 -0
  278. package/lib/utils/compose-generate-docker-compose.js +13 -1
  279. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  280. package/lib/utils/config-secrets-path.js +46 -0
  281. package/lib/utils/configuration-env-resolver.js +36 -0
  282. package/lib/utils/controller-url.js +88 -1
  283. package/lib/utils/credential-secrets-env-kv.js +216 -0
  284. package/lib/utils/credential-secrets-env.js +175 -257
  285. package/lib/utils/dataplane-resolver.js +18 -2
  286. package/lib/utils/declarative-url-ports.js +27 -4
  287. package/lib/utils/deployment-auth-mode.js +41 -0
  288. package/lib/utils/developer-volume-id.js +33 -0
  289. package/lib/utils/docker-build.js +1 -4
  290. package/lib/utils/env-copy.js +14 -9
  291. package/lib/utils/env-kv-orphan-lines.js +43 -0
  292. package/lib/utils/error-formatters/network-errors.js +13 -4
  293. package/lib/utils/external-env-template.js +11 -3
  294. package/lib/utils/external-system-readiness-core.js +10 -0
  295. package/lib/utils/external-system-readiness-display.js +80 -23
  296. package/lib/utils/external-system-validators.js +8 -2
  297. package/lib/utils/health-check.js +4 -1
  298. package/lib/utils/help-builder.js +13 -8
  299. package/lib/utils/keycloak-realm-ready.js +101 -0
  300. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  301. package/lib/utils/manifest-source-emit.js +2 -0
  302. package/lib/utils/paths.js +25 -0
  303. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  304. package/lib/utils/platform-controller-url.js +157 -0
  305. package/lib/utils/platform-kv-ref.js +57 -0
  306. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  307. package/lib/utils/postgres-wipe.js +9 -2
  308. package/lib/utils/resolve-env-mode.js +47 -0
  309. package/lib/utils/runtime-configuration-download.js +189 -0
  310. package/lib/utils/runtime-configuration-values.js +119 -0
  311. package/lib/utils/schema-loader.js +19 -4
  312. package/lib/utils/secrets-generator.js +31 -25
  313. package/lib/utils/secrets-missing-error.js +164 -0
  314. package/lib/utils/service-url-label.js +81 -0
  315. package/lib/utils/setup-quiet-output.js +25 -0
  316. package/lib/utils/template-helpers.js +15 -0
  317. package/lib/utils/token-manager-client-credentials.js +201 -0
  318. package/lib/utils/token-manager-messages.js +8 -0
  319. package/lib/utils/token-manager-refresh.js +12 -2
  320. package/lib/utils/token-manager.js +86 -105
  321. package/lib/utils/upload-pipeline-ui.js +12 -5
  322. package/lib/utils/upload-sync-options.js +42 -0
  323. package/lib/utils/url-declarative-public-base.js +21 -3
  324. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  325. package/lib/utils/validation-poll-ui.js +8 -0
  326. package/lib/utils/validation-run-stage.js +45 -0
  327. package/lib/utils/worker-sidecars.js +142 -0
  328. package/lib/validation/external-manifest-validator.js +2 -0
  329. package/lib/validation/runtime-configuration-rules.js +98 -0
  330. package/lib/validation/validate-display-dimensions.js +154 -0
  331. package/lib/validation/validate-display-sections.js +276 -0
  332. package/lib/validation/validate-display-steps.js +67 -0
  333. package/lib/validation/validate-display.js +24 -402
  334. package/package.json +1 -1
  335. package/templates/applications/dataplane/application.yaml +7 -1
  336. package/templates/applications/dataplane/env.template +50 -14
  337. package/templates/applications/dataplane/rbac.yaml +108 -1
  338. package/templates/applications/miso-controller/application.yaml +2 -2
  339. package/templates/applications/miso-controller/env.template +53 -122
  340. package/templates/applications/miso-controller/rbac.yaml +28 -13
  341. package/templates/channels/chatgpt/install.template.md.hbs +49 -0
  342. package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
  343. package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
  344. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
  345. package/templates/channels/slack/install.template.md.hbs +49 -0
  346. package/templates/channels/slack/manifest.template.json.hbs +66 -0
  347. package/templates/channels/teams-bot/install.template.md.hbs +49 -0
  348. package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
  349. package/templates/channels/web-embed/install.template.md.hbs +49 -0
  350. package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
  351. package/templates/external-system/README.md.hbs +74 -17
  352. package/templates/python/docker-compose.hbs +75 -18
  353. package/templates/typescript/docker-compose.hbs +70 -17
  354. package/lib/commands/test-governance-command-action.js +0 -55
  355. package/lib/commands/test-trust-command-action.js +0 -118
@@ -33,10 +33,11 @@ const logger = require('../utils/logger');
33
33
  const dockerfileUtils = require('../utils/dockerfile-utils');
34
34
  const dockerBuild = require('../utils/docker-build');
35
35
  const buildCopy = require('../utils/build-copy');
36
- const { buildDevImageName } = require('../utils/image-name');
36
+ const { resolveBuildDockerTagNames } = require('../utils/build-resolve-image');
37
37
  const buildHelpers = require('../utils/build-helpers');
38
38
  const secretsEnvWrite = require('../core/secrets-env-write');
39
39
  const { ensureRunSecretsForApp } = require('../app/run-env-compose');
40
+ const { assertMisoControllerNpmSdkDeps } = require('./miso-controller-npm-sdk-guard');
40
41
 
41
42
  /**
42
43
  * Loads application config for an application
@@ -286,8 +287,15 @@ async function prepareDevDirectory(appName, buildConfig, options) {
286
287
  const devDir = await buildCopy.copyBuilderToDevDirectory(appName, developerId);
287
288
  logger.log(formatSuccessLine(`Workspace ready: ${devDir}`));
288
289
 
289
- const { config: appConfig, imageName } = await buildHelpers.loadAndValidateConfig(appName);
290
- const effectiveImageName = buildDevImageName(imageName, developerId);
290
+ const { config: appConfig } = await buildHelpers.loadAndValidateConfig(appName);
291
+ const { buildImageName, compatBaseName } = await resolveBuildDockerTagNames(
292
+ appName,
293
+ appConfig,
294
+ developerId,
295
+ options
296
+ );
297
+ const effectiveImageName = buildImageName;
298
+ const imageName = compatBaseName || buildImageName;
291
299
 
292
300
  // Check if application source files exist, if not copy from templates
293
301
  const filesCopied = await copyApplicationSourceFiles(appName, devDir);
@@ -389,9 +397,10 @@ async function handleDockerfileGeneration(appName, params, options, buildHelpers
389
397
  /**
390
398
  * Resolve Docker build-args from resolved env map and merged BASH_* secrets.
391
399
  * @param {string} appName
400
+ * @param {string} [contextPath] Docker build context (repo root for miso-controller)
392
401
  * @returns {Promise<Object.<string, string>>}
393
402
  */
394
- async function resolveDockerBuildArgsForApp(appName) {
403
+ async function resolveDockerBuildArgsForApp(appName, contextPath) {
395
404
  const envMap = await secretsEnvWrite.resolveAndGetEnvMap(appName, { environment: 'docker' });
396
405
  const { getBashPrefixedProcessEnvOverlay } = require('../utils/bash-secret-env');
397
406
  const bashOverlay = await getBashPrefixedProcessEnvOverlay(null, appName);
@@ -401,6 +410,14 @@ async function resolveDockerBuildArgsForApp(appName) {
401
410
  for (const [k, v] of Object.entries(bashOverlay)) {
402
411
  if (v && buildArgs[k] === undefined) buildArgs[k] = v;
403
412
  }
413
+ // Exported shell tokens win (local dev: export NPM_TOKEN=... before af build / docker build).
414
+ const shellNpm = typeof process.env.NPM_TOKEN === 'string' ? process.env.NPM_TOKEN.trim() : '';
415
+ const shellPypi = typeof process.env.PYPI_TOKEN === 'string' ? process.env.PYPI_TOKEN.trim() : '';
416
+ if (shellNpm) buildArgs.NPM_TOKEN = shellNpm;
417
+ if (shellPypi) buildArgs.PYPI_TOKEN = shellPypi;
418
+ if (appName === 'miso-controller' && contextPath) {
419
+ assertMisoControllerNpmSdkDeps(path.resolve(contextPath));
420
+ }
404
421
  return buildArgs;
405
422
  }
406
423
 
@@ -424,7 +441,7 @@ async function runStandardDockerBuild(appName, options) {
424
441
  appConfig
425
442
  }, options, buildHelpers);
426
443
  await ensureRunSecretsForApp(appName);
427
- const buildArgs = await resolveDockerBuildArgsForApp(appName);
444
+ const buildArgs = await resolveDockerBuildArgsForApp(appName, contextPath);
428
445
  const buildOptions = { ...options, buildArgs };
429
446
  const tag = options.tag || 'latest';
430
447
  if (typeof tag === 'string' && tag.includes(',')) {
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Ensure miso-controller SDK deps are npm semver before Docker build (no file: vendor hacks).
3
+ * @fileoverview miso-controller npm SDK guard for builder
4
+ */
5
+
6
+ const { execFileSync } = require('child_process');
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ /**
11
+ * @param {string} repoRoot - aifabrix-miso repo root (Docker build context)
12
+ * @throws {Error} When guard script is missing or deps use file:
13
+ */
14
+ function assertMisoControllerNpmSdkDeps(repoRoot) {
15
+ const script = path.join(
16
+ repoRoot,
17
+ 'packages/miso-controller/scripts/assert-npm-sdk-deps.js'
18
+ );
19
+ if (!fs.existsSync(script)) {
20
+ throw new Error(`miso-controller SDK guard not found: ${script}`);
21
+ }
22
+ execFileSync('node', [script], { cwd: repoRoot, stdio: 'inherit' });
23
+ }
24
+
25
+ module.exports = { assertMisoControllerNpmSdkDeps };
@@ -211,7 +211,8 @@ async function maybeSyncSystemCertificationFromDataplane(params) {
211
211
  authConfig,
212
212
  datasourceKeys,
213
213
  issuanceFailureHint,
214
- verboseCertHints
214
+ verboseCertHints,
215
+ silent
215
216
  } = params;
216
217
  if (noCertSync === true) return;
217
218
  try {
@@ -224,14 +225,20 @@ async function maybeSyncSystemCertificationFromDataplane(params) {
224
225
  verboseCertHints
225
226
  });
226
227
  if (r.written) {
227
- logger.log(
228
- chalk.gray(`Updated certification block from dataplane${label ? ` (${label})` : ''} in system file.`)
229
- );
228
+ if (silent !== true) {
229
+ logger.log(
230
+ chalk.gray(`Updated certification block from dataplane${label ? ` (${label})` : ''} in system file.`)
231
+ );
232
+ }
230
233
  } else if (r.reason) {
231
- logCertificationSyncNotWritten(r, label, verboseCertHints === true);
234
+ if (silent !== true) {
235
+ logCertificationSyncNotWritten(r, label, verboseCertHints === true);
236
+ }
232
237
  }
233
238
  } catch (e) {
234
- logger.log(chalk.yellow(`⚠ Certification sync skipped: ${e.message}`));
239
+ if (silent !== true) {
240
+ logger.log(chalk.yellow(`⚠ Certification sync skipped: ${e.message}`));
241
+ }
235
242
  }
236
243
  }
237
244
 
@@ -0,0 +1,348 @@
1
+ /**
2
+ * Orchestrate aifabrix app add-channel (plan 152).
3
+ *
4
+ * @fileoverview Channel install after communication external system deploy
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const { getChannelTarget, getDefaultChannelDescription } = require('./channel-targets');
12
+ const { resolveChannelRuntimeValues } = require('./channel-runtime-resolver');
13
+ const { generateChannelArtifact } = require('./channel-artifact-generator');
14
+ const {
15
+ getExistingChannelExtension,
16
+ buildChannelExtensionBlock,
17
+ fetchCommunicationSystem,
18
+ patchChannelExtension
19
+ } = require('./channel-external-system');
20
+ const {
21
+ auditArtifactGenerated,
22
+ auditConfigPatched,
23
+ auditApprovalRequired,
24
+ auditValidated,
25
+ auditFailed
26
+ } = require('./channel-audit');
27
+ const { runChannelProbe } = require('./channel-probe');
28
+ const { resolveChannelAuthContext } = require('./channel-auth-context');
29
+ const { ensureChannelCredential } = require('./channel-credential');
30
+ const {
31
+ normalizeBaseChannelName,
32
+ resolveChannelDisplayName
33
+ } = require('./channel-display-name');
34
+ const {
35
+ displayExistingChannelStatus,
36
+ displayChannelInstallResult,
37
+ displayChannelError
38
+ } = require('./channel-status-display');
39
+
40
+ /**
41
+ * @param {typeof import('./channel-targets').CHANNEL_TARGETS[string]} target
42
+ * @param {Object} channelExt
43
+ * @param {Object} [context]
44
+ * @returns {string|null}
45
+ */
46
+ function resolveApprovalUrl(target, channelExt, context = {}) {
47
+ if (!target.approvalRequired) return null;
48
+ if (channelExt?.status === 'installed' || channelExt?.status === 'validated') return null;
49
+ if (target.key === 'slack' && context.artifactPath) {
50
+ return `https://api.slack.com/apps/new — upload manifest: ${context.artifactPath}`;
51
+ }
52
+ if (target.key === 'teams-bot') {
53
+ return 'https://admin.teams.microsoft.com/ — configure Bot Channel Registration for this tenant';
54
+ }
55
+ return `https://platform-admin.example/configure/${target.key}`;
56
+ }
57
+
58
+ /**
59
+ * @param {Object} target
60
+ * @param {Object} channelExt
61
+ * @param {boolean} dryRun
62
+ * @returns {string}
63
+ */
64
+ function resolveInstallStatus(target, channelExt, dryRun) {
65
+ if (dryRun) return 'generated';
66
+ if (channelExt?.status === 'approvalRequired') return 'approvalRequired';
67
+ if (target.approvalRequired && !channelExt) return 'approvalRequired';
68
+ if (target.approvalRequired && channelExt?.status !== 'installed') return 'approvalRequired';
69
+ return 'installed';
70
+ }
71
+
72
+ /**
73
+ * @param {Object|null} validation
74
+ * @returns {Object|null}
75
+ */
76
+ function toValidationDisplay(validation) {
77
+ if (!validation) return null;
78
+ return {
79
+ callbackReachable: validation.callbackReachable,
80
+ credentialValid: validation.credentialValid,
81
+ assistantCatalogReachable: validation.assistantCatalogReachable,
82
+ inboundVerification: Object.values(validation.inboundVerification).every(Boolean)
83
+ };
84
+ }
85
+
86
+ /**
87
+ * @param {Object} params
88
+ * @returns {Object|null}
89
+ */
90
+ function showExistingChannelStatus(params) {
91
+ const { existing, options, target, channelTarget, name, baseName } = params;
92
+ if (!existing || options.force || options.dryRun) return null;
93
+ const sameInstall =
94
+ (existing.baseName && existing.baseName === baseName) ||
95
+ (!existing.baseName && existing.name === name);
96
+ if (!sameInstall) {
97
+ throw new Error(
98
+ `Channel already configured as "${existing.name}". ` +
99
+ `Use --force to replace with "${name}".`
100
+ );
101
+ }
102
+ displayExistingChannelStatus({
103
+ channelTarget,
104
+ name: existing.name || name,
105
+ channelExt: existing,
106
+ approvalUrl: resolveApprovalUrl(target, existing)
107
+ });
108
+ return { skipped: true, channelExt: existing };
109
+ }
110
+
111
+ /**
112
+ * @param {string} channelTarget
113
+ * @param {Object} artifactParams
114
+ * @returns {Object}
115
+ */
116
+ function generateArtifactWithAudit(channelTarget, artifactParams) {
117
+ try {
118
+ const artifact = generateChannelArtifact(artifactParams);
119
+ auditArtifactGenerated(channelTarget, {
120
+ artifactHash: artifact.artifactHash,
121
+ outputPath: artifact.outputPath,
122
+ dryRun: artifactParams.dryRun === true
123
+ });
124
+ return artifact;
125
+ } catch (err) {
126
+ auditFailed(channelTarget, { phase: 'artifact', error: err.message });
127
+ throw err;
128
+ }
129
+ }
130
+
131
+ /**
132
+ * @param {Object} ctx
133
+ * @param {string} channelTarget
134
+ * @param {Object} channelBlock
135
+ * @param {string} status
136
+ * @param {string} artifactHash
137
+ * @returns {Promise<void>}
138
+ */
139
+ async function patchConfigWithAudit(ctx, channelTarget, channelBlock, status, artifactHash) {
140
+ try {
141
+ await patchChannelExtension(
142
+ { dataplaneUrl: ctx.dataplaneUrl, authConfig: ctx.authConfig, channelTarget },
143
+ channelBlock
144
+ );
145
+ auditConfigPatched(channelTarget, { status, artifactHash });
146
+ } catch (err) {
147
+ auditFailed(channelTarget, { phase: 'patch', error: err.message });
148
+ throw err;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * @param {Object} ctx
154
+ * @param {Object} channelBlock
155
+ * @param {string} channelTarget
156
+ * @param {boolean} probe
157
+ * @returns {Promise<Object|null>}
158
+ */
159
+ async function maybeRunProbe(ctx, channelBlock, channelTarget, probe) {
160
+ if (!probe) return null;
161
+ const validation = await runChannelProbe(
162
+ { dataplaneUrl: ctx.dataplaneUrl, authConfig: ctx.authConfig },
163
+ channelBlock
164
+ );
165
+ if (validation.passed) {
166
+ auditValidated(channelTarget, { probe: true });
167
+ } else {
168
+ auditFailed(channelTarget, { phase: 'probe', validation });
169
+ }
170
+ return validation;
171
+ }
172
+
173
+ /**
174
+ * @param {string} channelTarget
175
+ * @param {Object} options
176
+ * @returns {Promise<{ target: Object, name: string, baseName: string, description: string, ctx: Object, existing: Object|null }>}
177
+ */
178
+ async function prepareChannelContext(channelTarget, options) {
179
+ const target = getChannelTarget(channelTarget);
180
+ if (target.experimental) {
181
+ throw new Error(
182
+ `Channel target "${channelTarget}" is experimental. Confirm product requirement before use.`
183
+ );
184
+ }
185
+ if (!options.name || typeof options.name !== 'string' || !options.name.trim()) {
186
+ throw new Error('--name is required for app add-channel');
187
+ }
188
+
189
+ const baseName = normalizeBaseChannelName(options.name);
190
+ const ctx = await resolveChannelAuthContext(channelTarget, { silent: options.quiet });
191
+ const name = resolveChannelDisplayName(baseName, ctx.environment);
192
+ const description =
193
+ options.description && String(options.description).trim()
194
+ ? String(options.description).trim()
195
+ : getDefaultChannelDescription();
196
+
197
+ const system = await fetchCommunicationSystem({
198
+ dataplaneUrl: ctx.dataplaneUrl,
199
+ authConfig: ctx.authConfig,
200
+ channelTarget
201
+ });
202
+ const existing = getExistingChannelExtension(system);
203
+ return { target, name, baseName, description, ctx, existing };
204
+ }
205
+
206
+ /**
207
+ * @param {Object} params
208
+ * @returns {Promise<Object>}
209
+ */
210
+ async function completeLiveInstall(params) {
211
+ const { ctx, channelTarget, channelBlock, status, artifact, target, name, baseName, options } = params;
212
+
213
+ await ensureChannelCredential({
214
+ ctx,
215
+ channelTarget,
216
+ target,
217
+ force: options.force === true
218
+ });
219
+
220
+ await patchConfigWithAudit(ctx, channelTarget, channelBlock, status, artifact.artifactHash);
221
+
222
+ const approvalUrl =
223
+ status === 'approvalRequired'
224
+ ? resolveApprovalUrl(target, channelBlock, { artifactPath: artifact.outputPath })
225
+ : null;
226
+ if (approvalUrl) {
227
+ auditApprovalRequired(channelTarget, { approvalUrl });
228
+ }
229
+
230
+ const validation = await maybeRunProbe(ctx, channelBlock, channelTarget, options.probe);
231
+
232
+ displayChannelInstallResult({
233
+ channelTarget,
234
+ name,
235
+ baseName,
236
+ statusLabel: status === 'approvalRequired' ? 'Approval required' : 'Installed',
237
+ credentialKey: target.credentialKey,
238
+ capabilities: target.capabilities,
239
+ artifactPath: artifact.outputPath,
240
+ installGuidePath: artifact.installPath,
241
+ validation: toValidationDisplay(validation),
242
+ approvalUrl
243
+ });
244
+
245
+ return { channelBlock, artifact, validation, approvalUrl };
246
+ }
247
+
248
+ /**
249
+ * @param {Object} params
250
+ * @returns {{ dryRun: true, channelBlock: Object, artifact: Object }}
251
+ */
252
+ function finishDryRunInstall(params) {
253
+ displayChannelInstallResult({
254
+ channelTarget: params.channelTarget,
255
+ name: params.name,
256
+ baseName: params.baseName,
257
+ statusLabel: 'Generated (dry-run)',
258
+ credentialKey: params.target.credentialKey,
259
+ capabilities: params.target.capabilities,
260
+ artifactPath: params.artifact.outputPath,
261
+ installGuidePath: params.artifact.installPath
262
+ });
263
+ return { dryRun: true, channelBlock: params.channelBlock, artifact: params.artifact };
264
+ }
265
+
266
+ /**
267
+ * @param {string} channelTarget
268
+ * @param {Object} options
269
+ * @returns {Promise<Object>}
270
+ */
271
+ async function runAddChannel(channelTarget, options = {}) {
272
+ const { target, name, baseName, description, ctx, existing } = await prepareChannelContext(
273
+ channelTarget,
274
+ options
275
+ );
276
+
277
+ const skipped = showExistingChannelStatus({
278
+ existing,
279
+ options,
280
+ target,
281
+ channelTarget,
282
+ name,
283
+ baseName
284
+ });
285
+ if (skipped) return skipped;
286
+
287
+ const runtimeValues = resolveChannelRuntimeValues({
288
+ dataplaneBaseUrl: ctx.dataplaneUrl,
289
+ channelTarget,
290
+ appName: name,
291
+ baseName,
292
+ environment: ctx.environment,
293
+ appDescription: description,
294
+ icon: options.icon
295
+ });
296
+
297
+ const projectRoot = options.projectRoot || process.cwd();
298
+ const artifact = generateArtifactWithAudit(channelTarget, {
299
+ projectRoot,
300
+ channelTarget,
301
+ runtimeValues,
302
+ dryRun: options.dryRun === true
303
+ });
304
+
305
+ const status = resolveInstallStatus(target, existing, options.dryRun === true);
306
+ const channelBlock = buildChannelExtensionBlock(
307
+ { name, baseName, description, artifactHash: artifact.artifactHash, status },
308
+ target
309
+ );
310
+
311
+ if (options.dryRun) {
312
+ return finishDryRunInstall({ channelTarget, name, baseName, target, artifact, channelBlock });
313
+ }
314
+
315
+ return completeLiveInstall({
316
+ ctx,
317
+ channelTarget,
318
+ channelBlock,
319
+ status,
320
+ artifact,
321
+ target,
322
+ name,
323
+ baseName,
324
+ options
325
+ });
326
+ }
327
+
328
+ /**
329
+ * @param {string} channelTarget
330
+ * @param {Object} options
331
+ */
332
+ async function addChannelCommand(channelTarget, options = {}) {
333
+ try {
334
+ await runAddChannel(channelTarget, options);
335
+ } catch (err) {
336
+ displayChannelError(err.message || String(err));
337
+ throw err;
338
+ }
339
+ }
340
+
341
+ module.exports = {
342
+ runAddChannel,
343
+ addChannelCommand,
344
+ resolveApprovalUrl,
345
+ resolveInstallStatus,
346
+ normalizeBaseChannelName,
347
+ resolveChannelDisplayName
348
+ };
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Generate channel artifacts from Handlebars templates (plan 152).
3
+ *
4
+ * @fileoverview Channel artifact generation — dist/channels, sha256 hash, no secrets
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const crypto = require('crypto');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const Handlebars = require('handlebars');
15
+ const { getChannelTarget } = require('./channel-targets');
16
+
17
+ const SECRET_PATTERNS = [/xoxb-/i, /xoxp-/i, /client_secret/i, /signing_secret/i, /Bearer\s+/i];
18
+
19
+ /**
20
+ * @param {string} content
21
+ * @throws {Error}
22
+ */
23
+ function assertNoSecretsInArtifact(content) {
24
+ for (const pattern of SECRET_PATTERNS) {
25
+ if (pattern.test(content)) {
26
+ throw new Error('Generated artifact must not contain secret-like values');
27
+ }
28
+ }
29
+ if (content.includes('your-domain.com')) {
30
+ throw new Error('Generated artifact still contains placeholder domain your-domain.com');
31
+ }
32
+ }
33
+
34
+ /**
35
+ * @param {string} projectRoot
36
+ * @param {string} channelTarget
37
+ * @returns {string}
38
+ */
39
+ function getTemplatesDir(projectRoot, channelTarget) {
40
+ const target = getChannelTarget(channelTarget);
41
+ return path.join(projectRoot, 'templates', 'channels', target.templateDir);
42
+ }
43
+
44
+ /**
45
+ * @param {string} projectRoot
46
+ * @param {string} channelTarget
47
+ * @returns {string}
48
+ */
49
+ function getArtifactOutputPath(projectRoot, channelTarget) {
50
+ const target = getChannelTarget(channelTarget);
51
+ return path.join(
52
+ projectRoot,
53
+ 'dist',
54
+ 'channels',
55
+ channelTarget,
56
+ target.artifactFileName
57
+ );
58
+ }
59
+
60
+ /**
61
+ * @param {string} templatePath
62
+ * @param {Object} context
63
+ * @returns {string}
64
+ */
65
+ function renderTemplateFile(templatePath, context) {
66
+ if (!fs.existsSync(templatePath)) {
67
+ throw new Error(`Channel template not found: ${templatePath}`);
68
+ }
69
+ const raw = fs.readFileSync(templatePath, 'utf8');
70
+ const template = Handlebars.compile(raw);
71
+ return template(context);
72
+ }
73
+
74
+ /**
75
+ * @param {string} templatesDir
76
+ * @param {Object} runtimeValues
77
+ * @param {string} outputDir
78
+ * @param {boolean} dryRun
79
+ * @returns {{ installPath: string, content: string }|null}
80
+ */
81
+ function renderInstallGuideIfPresent(templatesDir, runtimeValues, outputDir, dryRun) {
82
+ const installTemplate = path.join(templatesDir, 'install.template.md.hbs');
83
+ if (!fs.existsSync(installTemplate)) {
84
+ return null;
85
+ }
86
+ const content = renderTemplateFile(installTemplate, runtimeValues);
87
+ assertNoSecretsInArtifact(content);
88
+ const installPath = path.join(outputDir, 'INSTALL.md');
89
+ if (!dryRun) {
90
+ fs.mkdirSync(outputDir, { recursive: true });
91
+ fs.writeFileSync(installPath, content, 'utf8');
92
+ }
93
+ return { installPath, content };
94
+ }
95
+
96
+ /**
97
+ * @param {Object} params
98
+ * @param {string} params.projectRoot
99
+ * @param {string} params.channelTarget
100
+ * @param {Object} params.runtimeValues
101
+ * @param {boolean} [params.dryRun]
102
+ * @returns {{ outputPath: string, artifactHash: string, content: string, installPath?: string }}
103
+ */
104
+ function generateChannelArtifact(params) {
105
+ const templatesDir = getTemplatesDir(params.projectRoot, params.channelTarget);
106
+ const manifestTemplate = path.join(templatesDir, 'manifest.template.json.hbs');
107
+ const content = renderTemplateFile(manifestTemplate, params.runtimeValues);
108
+ assertNoSecretsInArtifact(content);
109
+
110
+ const outputPath = getArtifactOutputPath(params.projectRoot, params.channelTarget);
111
+ const artifactHash = crypto.createHash('sha256').update(content, 'utf8').digest('hex');
112
+ const outputDir = path.dirname(outputPath);
113
+
114
+ if (!params.dryRun) {
115
+ fs.mkdirSync(outputDir, { recursive: true });
116
+ fs.writeFileSync(outputPath, content, 'utf8');
117
+ }
118
+
119
+ const install = renderInstallGuideIfPresent(
120
+ templatesDir,
121
+ params.runtimeValues,
122
+ outputDir,
123
+ params.dryRun === true
124
+ );
125
+
126
+ return {
127
+ outputPath,
128
+ artifactHash,
129
+ content,
130
+ installPath: install?.installPath
131
+ };
132
+ }
133
+
134
+ module.exports = {
135
+ assertNoSecretsInArtifact,
136
+ getTemplatesDir,
137
+ getArtifactOutputPath,
138
+ renderTemplateFile,
139
+ renderInstallGuideIfPresent,
140
+ generateChannelArtifact
141
+ };