@aifabrix/builder 2.45.0 → 2.46.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 (352) 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/docs-rules.mdc +3 -1
  4. package/.cursor/rules/project-rules.mdc +1 -0
  5. package/README.md +43 -17
  6. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  7. package/jest.config.default.js +2 -1
  8. package/jest.config.isolated.js +2 -1
  9. package/jest.global-live-fabrix-hooks.js +36 -0
  10. package/jest.isolated-projects.js +130 -0
  11. package/jest.projects.js +69 -121
  12. package/lib/api/agent-metadata-validation.api.js +93 -0
  13. package/lib/api/api-response-errors.js +124 -0
  14. package/lib/api/audit-api-helpers.js +68 -0
  15. package/lib/api/audit.api.js +119 -0
  16. package/lib/api/auth-cache.api.js +44 -0
  17. package/lib/api/certificates.api.js +4 -4
  18. package/lib/api/credential.api.js +2 -2
  19. package/lib/api/dataplane-health.api.js +137 -0
  20. package/lib/api/dataplane-sync.api.js +27 -0
  21. package/lib/api/datasources-core.api.js +21 -18
  22. package/lib/api/datasources-extended.api.js +22 -22
  23. package/lib/api/dimensions.api.js +3 -0
  24. package/lib/api/external-systems.api.js +13 -13
  25. package/lib/api/governance-scenario-pack.api.js +159 -0
  26. package/lib/api/governance-scenarios.api.js +39 -0
  27. package/lib/api/groups.api.js +79 -0
  28. package/lib/api/index.js +88 -5
  29. package/lib/api/lifecycle.api.js +77 -0
  30. package/lib/api/pipeline.api.js +7 -5
  31. package/lib/api/protection.api.js +157 -0
  32. package/lib/api/records-bulk.api.js +43 -0
  33. package/lib/api/records-search-parse.js +49 -0
  34. package/lib/api/records-search.api.js +29 -0
  35. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  36. package/lib/api/types/audit.types.js +72 -0
  37. package/lib/api/types/dataplane-health.types.js +27 -0
  38. package/lib/api/types/dimensions.types.js +2 -0
  39. package/lib/api/types/governance-scenarios.types.js +39 -0
  40. package/lib/api/types/protection.types.js +69 -0
  41. package/lib/api/types/records-bulk.types.js +35 -0
  42. package/lib/api/types/records-search.types.js +28 -0
  43. package/lib/api/user-groups.api.js +50 -0
  44. package/lib/api/users.api.js +95 -0
  45. package/lib/api/validation-run.api.js +3 -3
  46. package/lib/api/validation-runner.js +5 -3
  47. package/lib/api/wizard-platform.api.js +3 -3
  48. package/lib/api/wizard.api.js +21 -21
  49. package/lib/app/deploy-config.js +4 -1
  50. package/lib/app/deploy.js +34 -19
  51. package/lib/app/down.js +20 -1
  52. package/lib/app/push.js +4 -5
  53. package/lib/app/register.js +7 -4
  54. package/lib/app/run-env-compose.js +84 -30
  55. package/lib/build/index.js +5 -0
  56. package/lib/certification/sync-system-certification.js +13 -6
  57. package/lib/cli/index.js +8 -2
  58. package/lib/cli/infra-guided-auth.js +109 -0
  59. package/lib/cli/infra-guided.js +91 -69
  60. package/lib/cli/setup-app.help.js +19 -2
  61. package/lib/cli/setup-app.js +58 -23
  62. package/lib/cli/setup-app.test-commands.js +28 -21
  63. package/lib/cli/setup-auth.js +55 -3
  64. package/lib/cli/setup-certification-commands.js +147 -0
  65. package/lib/cli/setup-certification.help.js +141 -0
  66. package/lib/cli/setup-environment.js +19 -2
  67. package/lib/cli/setup-external-system-help.js +62 -0
  68. package/lib/cli/setup-external-system.js +62 -6
  69. package/lib/cli/setup-infra.js +9 -1
  70. package/lib/cli/setup-platform.js +6 -1
  71. package/lib/cli/setup-secrets.js +33 -1
  72. package/lib/cli/setup-utility-help-after.js +65 -0
  73. package/lib/cli/setup-utility-repair.js +198 -0
  74. package/lib/cli/setup-utility-resolve.js +42 -6
  75. package/lib/cli/setup-utility-validate.js +197 -0
  76. package/lib/cli/setup-utility.js +41 -258
  77. package/lib/commands/auth-status-client-tokens.js +214 -0
  78. package/lib/commands/auth-status-dataplane-version.js +269 -0
  79. package/lib/commands/auth-status-display.js +94 -0
  80. package/lib/commands/auth-status.js +111 -53
  81. package/lib/commands/credential-push.js +10 -5
  82. package/lib/commands/datasource-load-export-cli.js +178 -0
  83. package/lib/commands/datasource-test-trust-cli.js +118 -0
  84. package/lib/commands/datasource-unified-test-cli.js +31 -20
  85. package/lib/commands/datasource-unified-test-cli.options.js +22 -3
  86. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  87. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  88. package/lib/commands/datasource.js +68 -1
  89. package/lib/commands/dev-show-display.js +8 -1
  90. package/lib/commands/dimension-value.js +43 -13
  91. package/lib/commands/dimension.js +38 -7
  92. package/lib/commands/governance-cli-shared.js +94 -0
  93. package/lib/commands/governance-command-action.js +132 -0
  94. package/lib/commands/governance-download-external.js +34 -0
  95. package/lib/commands/governance-generate-external.js +71 -0
  96. package/lib/commands/governance-upload-external.js +36 -0
  97. package/lib/commands/governance-verify-external.js +64 -0
  98. package/lib/commands/governance.js +144 -0
  99. package/lib/commands/identity-apply-sync.js +131 -0
  100. package/lib/commands/identity-group-cli.js +146 -0
  101. package/lib/commands/identity-membership-role-cache.js +175 -0
  102. package/lib/commands/identity-shared.js +94 -0
  103. package/lib/commands/identity-user-cli.js +158 -0
  104. package/lib/commands/identity.js +43 -0
  105. package/lib/commands/lifecycle-command-action.js +123 -0
  106. package/lib/commands/lifecycle-external.js +268 -0
  107. package/lib/commands/login.js +56 -17
  108. package/lib/commands/protection-cli-leaves.js +286 -0
  109. package/lib/commands/protection.js +50 -0
  110. package/lib/commands/repair-auth-apply.js +127 -0
  111. package/lib/commands/repair-changed-files.js +41 -0
  112. package/lib/commands/repair-datasource-keys.js +4 -1
  113. package/lib/commands/repair-datasource-run.js +59 -0
  114. package/lib/commands/repair-datasource-test-payload.js +259 -0
  115. package/lib/commands/repair-datasource.js +1 -51
  116. package/lib/commands/repair-env-template.js +64 -13
  117. package/lib/commands/repair-external-run.js +216 -0
  118. package/lib/commands/repair-openapi-sync.js +23 -0
  119. package/lib/commands/repair-persist.js +4 -0
  120. package/lib/commands/repair-rbac.js +52 -1
  121. package/lib/commands/repair-steps.js +145 -0
  122. package/lib/commands/repair.js +29 -286
  123. package/lib/commands/secrets-get.js +184 -0
  124. package/lib/commands/secrets-remove-all.js +3 -1
  125. package/lib/commands/setup-image-refresh.js +146 -0
  126. package/lib/commands/setup-modes.js +158 -162
  127. package/lib/commands/setup-platform-auth.js +76 -0
  128. package/lib/commands/setup-prompts-admin.js +244 -0
  129. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  130. package/lib/commands/setup-prompts-validators.js +36 -0
  131. package/lib/commands/setup-prompts.js +24 -76
  132. package/lib/commands/setup-run-context.js +45 -0
  133. package/lib/commands/setup-spinners.js +39 -0
  134. package/lib/commands/setup.js +27 -5
  135. package/lib/commands/teardown.js +39 -0
  136. package/lib/commands/test-e2e-external.js +61 -14
  137. package/lib/commands/test-governance-cli-options.js +47 -0
  138. package/lib/commands/test-governance-external.js +67 -0
  139. package/lib/commands/test-trust-cli-options.js +32 -0
  140. package/lib/commands/test-trust-external.js +126 -0
  141. package/lib/commands/up-common.js +25 -13
  142. package/lib/commands/up-dataplane.js +50 -13
  143. package/lib/commands/upload-publish-context.js +75 -0
  144. package/lib/commands/upload-sidecar-followups.js +89 -0
  145. package/lib/commands/upload.js +108 -105
  146. package/lib/commands/verify-governance-combined-external.js +61 -0
  147. package/lib/commands/verify-governance-command-action.js +64 -0
  148. package/lib/commands/verify-governance-db.js +102 -0
  149. package/lib/commands/verify-governance-external.js +77 -0
  150. package/lib/commands/verify-governance-result-builders.js +71 -0
  151. package/lib/commands/verify-operations-command-action.js +68 -0
  152. package/lib/commands/verify-operations-external.js +268 -0
  153. package/lib/commands/verify-operations-persist.js +75 -0
  154. package/lib/commands/verify-operations-step-plan.js +68 -0
  155. package/lib/commands/verify-operations-steps.js +111 -0
  156. package/lib/commands/verify-trust-command-action.js +70 -0
  157. package/lib/commands/verify-trust-external.js +67 -0
  158. package/lib/commands/wizard-config-normalizer.js +43 -23
  159. package/lib/commands/wizard-core.js +5 -0
  160. package/lib/core/admin-password-generator.js +38 -0
  161. package/lib/core/admin-secrets-bundle.js +111 -0
  162. package/lib/core/admin-secrets-env-overlay.js +62 -0
  163. package/lib/core/admin-secrets.js +32 -4
  164. package/lib/core/config-attach-extensions.js +3 -0
  165. package/lib/core/config-device-dataplane.js +185 -0
  166. package/lib/core/config-platform-controller.js +44 -0
  167. package/lib/core/config-setup-installation-profile.js +42 -0
  168. package/lib/core/config-setup-platform-mode.js +46 -0
  169. package/lib/core/config.js +46 -36
  170. package/lib/core/secrets-admin-env.js +6 -2
  171. package/lib/core/secrets-ensure.js +4 -0
  172. package/lib/core/secrets-env-content.js +54 -48
  173. package/lib/core/secrets-env-write.js +10 -1
  174. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  175. package/lib/core/setup-installation-profile.js +43 -0
  176. package/lib/core/setup-platform-mode.js +55 -0
  177. package/lib/datasource/agent-trust-debug-log.js +45 -0
  178. package/lib/datasource/agent-trust-fetch.js +115 -0
  179. package/lib/datasource/agent-trust-map.js +101 -0
  180. package/lib/datasource/agent-trust-mock.js +44 -0
  181. package/lib/datasource/agent-trust-run.js +95 -0
  182. package/lib/datasource/agent-trust-timeout.js +25 -0
  183. package/lib/datasource/audit-evidence-display.js +80 -0
  184. package/lib/datasource/audit-evidence-extract-debug.js +115 -0
  185. package/lib/datasource/audit-evidence-extract.js +180 -0
  186. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  187. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  188. package/lib/datasource/audit-evidence-poll.js +109 -0
  189. package/lib/datasource/audit-evidence-run.js +177 -0
  190. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  191. package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
  192. package/lib/datasource/audit-evidence-verify.js +108 -0
  193. package/lib/datasource/bulk-loader-run-batches.js +100 -0
  194. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  195. package/lib/datasource/bulk-loader-service.js +127 -0
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  197. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  198. package/lib/datasource/datasource-exporter-service.js +144 -0
  199. package/lib/datasource/datasource-identifier.js +148 -0
  200. package/lib/datasource/datasource-load-export-context.js +95 -0
  201. package/lib/datasource/integration-context.js +6 -4
  202. package/lib/datasource/local-data-paths.js +145 -0
  203. package/lib/datasource/log-cleaner.js +241 -0
  204. package/lib/datasource/log-viewer.js +111 -6
  205. package/lib/datasource/record-file-parser.js +85 -0
  206. package/lib/datasource/record-mapper.js +129 -0
  207. package/lib/datasource/resolve-app.js +74 -55
  208. package/lib/datasource/test-e2e.js +29 -2
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  211. package/lib/datasource/unified-validation-run.js +47 -18
  212. package/lib/datasource/validate.js +37 -20
  213. package/lib/deployment/environment-poll-status.js +138 -0
  214. package/lib/deployment/environment.js +42 -34
  215. package/lib/external-system/download.js +21 -20
  216. package/lib/external-system/generator.js +5 -1
  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-system-level.js +25 -4
  220. package/lib/external-system/test.js +9 -7
  221. package/lib/generator/external-controller-manifest.js +15 -0
  222. package/lib/governance/governance-cli-errors.js +96 -0
  223. package/lib/governance/governance-download-display.js +38 -0
  224. package/lib/governance/governance-pack-loader.js +70 -0
  225. package/lib/governance/governance-run-display.js +309 -0
  226. package/lib/identity/identity-apply-core.js +108 -0
  227. package/lib/identity/identity-apply-phases.js +244 -0
  228. package/lib/identity/identity-apply-service.js +77 -0
  229. package/lib/identity/identity-csv-parser.js +114 -0
  230. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  231. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  232. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  233. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  234. package/lib/infrastructure/helpers.js +23 -129
  235. package/lib/infrastructure/index.js +5 -6
  236. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  237. package/lib/internal/fs-real-sync.js +29 -1
  238. package/lib/lifecycle/certification-progress.js +231 -0
  239. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  240. package/lib/lifecycle/exit-codes.js +24 -0
  241. package/lib/lifecycle/json-envelope.js +25 -0
  242. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  243. package/lib/lifecycle/logger-quiet.js +29 -0
  244. package/lib/lifecycle/open-api-published.js +59 -0
  245. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  246. package/lib/lifecycle/product-model.js +196 -0
  247. package/lib/lifecycle/report-display.js +471 -0
  248. package/lib/lifecycle/scenario-upload.js +191 -0
  249. package/lib/lifecycle/verify-step-progress.js +87 -0
  250. package/lib/parameters/infra-kv-discovery.js +27 -2
  251. package/lib/protection/auth-context.js +51 -0
  252. package/lib/protection/convert-batch.js +90 -0
  253. package/lib/protection/load.js +41 -0
  254. package/lib/protection/paths.js +158 -0
  255. package/lib/protection/preflight-datasource-ready.js +46 -0
  256. package/lib/protection/protection-create-probe-lines.js +142 -0
  257. package/lib/protection/protection-create-probes.js +95 -0
  258. package/lib/protection/protection-create-scaffold.js +281 -0
  259. package/lib/protection/protection-display-helpers.js +445 -0
  260. package/lib/protection/protection-display.js +215 -0
  261. package/lib/protection/protection-preset-registry.js +97 -0
  262. package/lib/protection/report-exit.js +62 -0
  263. package/lib/protection/resolve.js +202 -0
  264. package/lib/protection/run-commands-validate.js +130 -0
  265. package/lib/protection/run-commands.js +216 -0
  266. package/lib/protection/run-protection-create-helpers.js +134 -0
  267. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  268. package/lib/protection/run-protection-create.js +191 -0
  269. package/lib/protection/scope.js +22 -0
  270. package/lib/protection/sync-after-upload.js +64 -0
  271. package/lib/protection/upload-batch.js +127 -0
  272. package/lib/protection/validate-batch.js +113 -0
  273. package/lib/protection/validate-local.js +65 -0
  274. package/lib/resolvers/dimension-file.js +29 -4
  275. package/lib/schema/application-schema.json +1 -1
  276. package/lib/schema/datasource-test-run.schema.json +89 -6
  277. package/lib/schema/external-datasource.schema.json +2636 -2588
  278. package/lib/schema/external-system.schema.json +1089 -761
  279. package/lib/schema/flag-map-validation-run.json +2 -2
  280. package/lib/schema/infra.parameter.yaml +45 -0
  281. package/lib/schema/protection.schema.json +374 -0
  282. package/lib/schema/type/credential-field-registry.json +642 -0
  283. package/lib/schema/wizard-config.schema.json +1 -1
  284. package/lib/utils/agent-trust-run-display.js +231 -0
  285. package/lib/utils/agent-trust-run-exit.js +59 -0
  286. package/lib/utils/agent-trust-wait-ui.js +94 -0
  287. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  288. package/lib/utils/api.js +55 -31
  289. package/lib/utils/app-relative-path-env.js +112 -0
  290. package/lib/utils/cli-exit-codes.js +30 -0
  291. package/lib/utils/cli-secrets-error-format.js +83 -21
  292. package/lib/utils/cli-sync-options.js +33 -0
  293. package/lib/utils/cli-utils.js +16 -4
  294. package/lib/utils/compose-generate-docker-compose.js +4 -0
  295. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  296. package/lib/utils/config-secrets-path.js +46 -0
  297. package/lib/utils/controller-url.js +88 -1
  298. package/lib/utils/credential-push-ui.js +90 -0
  299. package/lib/utils/credential-secrets-env.js +137 -9
  300. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  301. package/lib/utils/dataplane-cli-version-help.js +74 -0
  302. package/lib/utils/dataplane-resolver.js +129 -2
  303. package/lib/utils/datasource-export-display.js +137 -0
  304. package/lib/utils/datasource-load-display.js +174 -0
  305. package/lib/utils/datasource-load-export-ui.js +120 -0
  306. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  307. package/lib/utils/datasource-test-run-display.js +3 -3
  308. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  309. package/lib/utils/declarative-url-ports.js +3 -3
  310. package/lib/utils/deployment-auth-mode.js +41 -0
  311. package/lib/utils/developer-volume-id.js +33 -0
  312. package/lib/utils/env-copy.js +14 -9
  313. package/lib/utils/env-kv-orphan-lines.js +43 -0
  314. package/lib/utils/error-formatters/network-errors.js +13 -4
  315. package/lib/utils/external-env-template.js +1 -0
  316. package/lib/utils/external-system-readiness-core.js +10 -0
  317. package/lib/utils/external-system-readiness-display.js +80 -23
  318. package/lib/utils/health-check.js +4 -1
  319. package/lib/utils/help-builder.js +35 -26
  320. package/lib/utils/keycloak-realm-ready.js +101 -0
  321. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  322. package/lib/utils/manifest-source-emit.js +24 -0
  323. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  324. package/lib/utils/platform-controller-url.js +156 -0
  325. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  326. package/lib/utils/postgres-wipe.js +9 -2
  327. package/lib/utils/resolve-env-mode.js +47 -0
  328. package/lib/utils/secrets-generator.js +31 -25
  329. package/lib/utils/secrets-missing-error.js +164 -0
  330. package/lib/utils/semver-compare.js +127 -0
  331. package/lib/utils/service-url-label.js +81 -0
  332. package/lib/utils/setup-quiet-output.js +25 -0
  333. package/lib/utils/template-helpers.js +15 -0
  334. package/lib/utils/token-manager-client-credentials.js +201 -0
  335. package/lib/utils/token-manager-messages.js +8 -0
  336. package/lib/utils/token-manager-refresh.js +12 -2
  337. package/lib/utils/token-manager.js +86 -105
  338. package/lib/utils/upload-pipeline-ui.js +98 -0
  339. package/lib/utils/upload-sync-options.js +42 -0
  340. package/lib/utils/url-declarative-public-base.js +21 -3
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  342. package/lib/utils/validation-poll-ui.js +22 -7
  343. package/lib/utils/validation-run-stage.js +45 -0
  344. package/lib/validation/wizard-config-validator.js +58 -19
  345. package/package.json +1 -1
  346. package/templates/applications/dataplane/application.yaml +2 -1
  347. package/templates/applications/dataplane/env.template +36 -1
  348. package/templates/applications/dataplane/rbac.yaml +4 -0
  349. package/templates/applications/miso-controller/env.template +16 -0
  350. package/templates/external-system/README.md.hbs +116 -11
  351. package/templates/python/docker-compose.hbs +19 -18
  352. package/templates/typescript/docker-compose.hbs +18 -17
@@ -15,12 +15,19 @@
15
15
  */
16
16
 
17
17
  const { handleCommandError } = require('../utils/cli-utils');
18
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
18
19
  const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
19
20
  const { TEST_INTEGRATION_HELP_AFTER } = require('./setup-app.help');
21
+ const {
22
+ UPLOAD_HELP_AFTER,
23
+ DOWNLOAD_HELP_AFTER,
24
+ DELETE_HELP_AFTER
25
+ } = require('./setup-external-system-help');
20
26
 
21
27
  function setupDownloadCommand(program) {
22
28
  program.command('download <systemKey>')
23
29
  .description('Pull external system from dataplane into integration/<key>/')
30
+ .addHelpText('after', DOWNLOAD_HELP_AFTER)
24
31
  .option('--format <format>', 'Output format: json | yaml (default: yaml or config format)')
25
32
  .option('--dry-run', 'Show what would be downloaded without actually downloading')
26
33
  .option('--force', 'Overwrite existing README.md without prompting')
@@ -42,8 +49,12 @@ function setupDownloadCommand(program) {
42
49
 
43
50
  function setupUploadCommand(program) {
44
51
  program.command('upload <systemKey>')
45
- .description('Validate, publish to dataplane, and register with controller (draft application)')
52
+ .description('Validate, publish to dataplane, and register with controller (draft application); or upload .protection batch')
53
+ .addHelpText('after', UPLOAD_HELP_AFTER)
46
54
  .option('--dry-run', 'Validate and build payload only; no API calls')
55
+ .option('--no-sync', 'For .protection: skip datasource sync after upload')
56
+ .option('--json', 'For .protection: JSON output')
57
+ .option('--warnings-as-errors', 'For .protection: pass strict=true to dataplane validate')
47
58
  .option('-v, --verbose', 'Run server-side pipeline validate and print warnings before publish')
48
59
  .option('--probe', 'After publish, run dataplane runtime checks (validation/run); slower')
49
60
  .option('--minimal', 'Print only a short readiness summary after upload')
@@ -52,8 +63,32 @@ function setupUploadCommand(program) {
52
63
  '--no-cert-sync',
53
64
  'Skip updating the system file certification block from the dataplane active certificate after publish'
54
65
  )
66
+ .option(
67
+ '--force',
68
+ 'Bypass schema guards on active datasources during publish (dangerous; shows a warning)'
69
+ )
55
70
  .action(async(systemKey, options) => {
56
71
  try {
72
+ const { isProtectionScope } = require('../protection/scope');
73
+ if (isProtectionScope(systemKey)) {
74
+ const { uploadProtectionBatchCommand } = require('../protection/upload-batch');
75
+ const logger = require('../utils/logger');
76
+ const code = await uploadProtectionBatchCommand(
77
+ {
78
+ env: options.env,
79
+ dryRun: options.dryRun === true,
80
+ noSync: options.noSync === true,
81
+ json: options.json === true,
82
+ verbose: options.verbose === true,
83
+ warningsAsErrors: options.warningsAsErrors === true
84
+ },
85
+ logger
86
+ );
87
+ if (code !== 0) {
88
+ process.exit(code);
89
+ }
90
+ return;
91
+ }
57
92
  const upload = require('../commands/upload');
58
93
  const probeTimeout =
59
94
  options.probeTimeout === undefined || options.probeTimeout === null
@@ -74,11 +109,23 @@ function setupUploadCommand(program) {
74
109
  function setupDeleteCommand(program) {
75
110
  program.command('delete <systemKey>')
76
111
  .description('Remove external system and its datasources from dataplane')
112
+ .addHelpText('after', DELETE_HELP_AFTER)
77
113
  .option('--type <type>', 'Application type (default: external; use "external" to target integration/<systemKey>)')
78
114
  .option('--yes', 'Skip confirmation prompt')
79
115
  .option('--force', 'Skip confirmation prompt (alias for --yes)')
80
116
  .action(async(systemKey, options) => {
81
117
  try {
118
+ const { isProtectionScope } = require('../protection/scope');
119
+ if (isProtectionScope(systemKey)) {
120
+ const logger = require('../utils/logger');
121
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
122
+ logger.error(
123
+ formatBlockingError(
124
+ 'delete .protection is not supported. Use: aifabrix protection delete <datasourceKey>'
125
+ )
126
+ );
127
+ process.exit(1);
128
+ }
82
129
  const externalDelete = require('../external-system/delete');
83
130
  await externalDelete.deleteExternalSystem(systemKey, options);
84
131
  } catch (error) {
@@ -134,7 +181,7 @@ async function runExternalSystemTestIntegration(appName, options) {
134
181
  environment: options.env || options.environment,
135
182
  debug: options.debug,
136
183
  perDatasource: options.perDatasource,
137
- sync: options.sync === true
184
+ noSync: cliOptsSkipSync(options)
138
185
  };
139
186
  const results = await test.testExternalSystemIntegration(appName, opts);
140
187
  test.displayIntegrationTestResults(results, options.verbose, { debug: options.debug, runType: 'integration' });
@@ -186,14 +233,22 @@ async function runTestIntegrationCommand(appName, options) {
186
233
 
187
234
  function setupExternalSystemTestCommands(program) {
188
235
  // 'test <app>' is registered in setup-app.js and dispatches by app type (builder vs external)
189
- program.command('test-integration <app>')
190
- .description('Integration tests: builder in container; external via dataplane')
236
+ program.command('test-integration <appKey|systemKey>')
237
+ .description('Integration tests: builder appKey in container; external systemKey via dataplane')
191
238
  .option('-e, --env <env>', 'Environment: dev, tst, or pro (builder: dev/tst for container)', 'dev')
192
239
  .option('-v, --verbose', 'Show detailed test output')
193
240
  .option('-d, --debug', 'Include debug output and write log to integration/<systemKey>/logs/')
241
+ .option(
242
+ '--no-sync',
243
+ 'Skip publishing local integration files; use system config already on the dataplane'
244
+ )
194
245
  .option(
195
246
  '--sync',
196
- 'Publish local system and datasource files to the dataplane before running tests (same as aifabrix upload <systemKey>)'
247
+ 'Publish local system and datasource files before tests (default for external integration; same as upload)'
248
+ )
249
+ .option(
250
+ '--force',
251
+ 'With --sync, pass force to upload (bypass active-datasource schema replacement guards; same as aifabrix upload --force)'
197
252
  )
198
253
  .option('--warnings-as-errors', 'Treat aggregate warn as failure (exit 1)')
199
254
  .option('--require-cert', 'Require certification passed on every datasource (exit 2 if not)')
@@ -208,7 +263,8 @@ function setupExternalSystemTestCommands(program) {
208
263
  const envExplicit = rawArgs.includes('-e') || rawArgs.includes('--env');
209
264
  const opts = {
210
265
  ...options,
211
- env: envExplicit ? options.env : undefined
266
+ env: envExplicit ? options.env : undefined,
267
+ noSync: cliOptsSkipSync(options, cmd)
212
268
  };
213
269
  await runTestIntegrationCommand(appName, opts);
214
270
  } catch (error) {
@@ -134,6 +134,8 @@ async function runUpInfraCommand(options) {
134
134
  const cfg = await config.getConfig();
135
135
  await persistOptionalInfraFlagsFromCli(options, cfg);
136
136
  await maybePersistTlsFromUpInfra(options, cfg);
137
+ const { passwordBundleFromCliOptions } = require('../core/admin-secrets-bundle');
138
+ const bundle = passwordBundleFromCliOptions(options);
137
139
  const adminPass = options.adminPassword || options.adminPwd;
138
140
  const tlsEnabledEffective = cfg.tlsEnabled === true;
139
141
  const effective = computeEffectiveInfraOptionalFlags(cfg, options);
@@ -145,6 +147,8 @@ async function runUpInfraCommand(options) {
145
147
  adminPwd: adminPass,
146
148
  adminEmail: options.adminEmail,
147
149
  userPassword: options.userPassword,
150
+ passwordBundle: bundle,
151
+ syncAdminKv: options.syncAdminKv === true,
148
152
  tlsEnabled: tlsEnabledEffective
149
153
  });
150
154
  await persistMissingInfraOptionalServiceFlags(cfg, effective);
@@ -156,8 +160,12 @@ function setupUpInfraCommand(program) {
156
160
  .addHelpText('after', UP_INFRA_HELP_AFTER)
157
161
  .option('-d, --developer <id>', 'Set developer ID and start infrastructure')
158
162
  .option('--verbose', 'Show full orchestration output (default is guided summary)')
159
- .option('--adminPassword <password>', 'Override {{adminPassword}} defaults (Postgres, pgAdmin, Redis Commander, catalog literals)')
163
+ .option('--adminPassword <password>', 'Override admin password (dev: all roles; pro manual-single)')
160
164
  .option('--adminEmail <email>', 'Override {{adminEmail}} default (e.g. pgAdmin login email)')
165
+ .option('--infraAdminPassword <password>', 'Pro profile: infra DB/pgAdmin/Redis Commander password')
166
+ .option('--keycloakAdminPassword <password>', 'Pro profile: Keycloak install admin password')
167
+ .option('--platformAdminPassword <password>', 'Pro profile: platform UI login password (user admin)')
168
+ .option('--syncAdminKv', 'Also sync {{adminPassword}} catalog keys into secrets.local.yaml (legacy)')
161
169
  .option('--userPassword <password>', 'Override {{userPassword}} default (e.g. Keycloak default user password)')
162
170
  .option('--pgAdmin', 'Include pgAdmin web UI and save to config')
163
171
  .option('--no-pgAdmin', 'Exclude pgAdmin and save to config')
@@ -23,7 +23,7 @@ const { handleTeardown } = require('../commands/teardown');
23
23
 
24
24
  const SETUP_HELP_AFTER = `
25
25
  What this command does:
26
- - With no infra running: prompts for admin email/password (used for Postgres, pgAdmin, Keycloak). The email is saved as adminEmail in config.yaml so the next setup can show it as the default (you can still change it). Prompts for an AI tool (OpenAI or Azure OpenAI) only when keys are not already set, then runs up-infra and up-platform.
26
+ - With no infra running: prompts for installation profile (dev = one password for infra + Keycloak + platform UI; pro = autogen or manual split passwords). Credentials are stored in admin-secrets.env (encrypted secure:// values), not in secrets.local.yaml unless you pass --syncAdminKv on up-infra. The admin email is saved in config.yaml for the next run. Prompts for an AI tool (OpenAI or Azure OpenAI) only when keys are not already set, then runs up-infra and up-platform.
27
27
  - With infra running: shows a mode menu:
28
28
  1) Re-install — stop infra and remove all volumes, then up-infra + up-platform --force.
29
29
  2) Wipe data — drop every database and DB user, then up-infra + up-platform --force.
@@ -54,6 +54,11 @@ function registerSetup(program) {
54
54
  .command('setup')
55
55
  .description('Install or refresh the full AI Fabrix platform (infra + miso + dataplane)')
56
56
  .option('-d, --developer <id>', 'Pin developer ID before fresh install (fresh path only; ignored when infra is already up)')
57
+ .option('--platform <mode>', 'Platform mode: single (direct ports) or full (Traefik front door + multi-env)')
58
+ .option('--installation <profile>', 'Installation profile: dev (one password) or pro (autogen/manual)')
59
+ .option('--pro-password-mode <mode>', 'Pro profile only: autogen or manual')
60
+ .option('--admin-email <email>', 'Admin email (non-interactive fresh install)')
61
+ .option('--admin-password <password>', 'Admin password for dev or pro manual-single (non-interactive)')
57
62
  .option('-y, --yes', 'Skip destructive confirmation prompts (re-install, wipe data, teardown)')
58
63
  .addHelpText('after', SETUP_HELP_AFTER)
59
64
  .action(async(options) => {
@@ -10,6 +10,7 @@ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
10
10
  const { handleCommandError } = require('../utils/cli-utils');
11
11
  const { handleSecretsSet } = require('../commands/secrets-set');
12
12
  const { handleSecretsList } = require('../commands/secrets-list');
13
+ const { handleSecretsGet } = require('../commands/secrets-get');
13
14
  const { handleSecretsRemove } = require('../commands/secrets-remove');
14
15
  const { handleSecretsValidate } = require('../commands/secrets-validate');
15
16
  const { handleSecure } = require('../commands/secure');
@@ -18,7 +19,7 @@ const logger = require('../utils/logger');
18
19
 
19
20
  const SECRET_GROUP_HELP_AFTER = `
20
21
  Subcommands:
21
- list, set, remove, remove-all User secrets.local.yaml (add --shared for shared/remote)
22
+ list, get, set, remove, remove-all User secrets.local.yaml (add --shared for shared/remote)
22
23
  set-secrets-file Point config at a shared secrets file or https URL
23
24
  validate YAML structure (+ optional --naming)
24
25
 
@@ -38,6 +39,17 @@ Examples:
38
39
  Shared over https: key BASH_NPM_TOKEN --shared → NPM_TOKEN available in terminal (exported).
39
40
  `;
40
41
 
42
+ const SECRET_GET_HELP_AFTER = `
43
+ Examples:
44
+ $ aifabrix secret get hubspot-demo/token --shared --exists
45
+ $ aifabrix secret get myapp/clientSecret
46
+ $ aifabrix secret get hubspot/apiKey --shared --json
47
+
48
+ --exists Script mode: exit 0 when the key is present and non-empty; no output.
49
+ Default Local user secrets.local.yaml only (same target as secret set without --shared).
50
+ --shared aifabrix-secrets store only (team file or remote API; same as secret set --shared).
51
+ `;
52
+
41
53
  const SECRET_LIST_HELP_AFTER = `
42
54
  Examples:
43
55
  $ aifabrix secret list
@@ -168,6 +180,25 @@ function setupSecureCommand(program) {
168
180
  });
169
181
  }
170
182
 
183
+ function setupSecretGetCommand(secretCmd) {
184
+ secretCmd
185
+ .command('get <key>')
186
+ .description('Get one secret (local user file by default; --shared for team store; --exists for scripts)')
187
+ .addHelpText('after', SECRET_GET_HELP_AFTER)
188
+ .option('--shared', 'Read from shared secrets (config aifabrix-secrets or remote API)')
189
+ .option('--exists', 'Exit 0 when key is present and non-empty; print nothing (for scripts)')
190
+ .option('--json', 'Output JSON { key, exists, value }')
191
+ .action(async(key, options) => {
192
+ try {
193
+ await config.ensureSecretsEncryptionKey();
194
+ await handleSecretsGet(key, options);
195
+ } catch (error) {
196
+ handleCommandError(error, 'secret get');
197
+ process.exit(1);
198
+ }
199
+ });
200
+ }
201
+
171
202
  function setupSecretListCommand(secretCmd) {
172
203
  secretCmd
173
204
  .command('list')
@@ -196,6 +227,7 @@ function setupSecretsCommands(program) {
196
227
  .addHelpText('after', SECRET_GROUP_HELP_AFTER);
197
228
 
198
229
  setupSecretListCommand(secretCmd);
230
+ setupSecretGetCommand(secretCmd);
199
231
 
200
232
  secretCmd
201
233
  .command('set <key> <value>')
@@ -0,0 +1,65 @@
1
+ /**
2
+ * @fileoverview Help-after strings for setup-utility CLI commands.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const JSON_HELP_AFTER = `
8
+ Example:
9
+ $ aifabrix json myapp
10
+ Generates *-deploy.json (or application-schema.json) for commit before deploy.
11
+ `;
12
+
13
+ const VALIDATE_HELP_AFTER = `
14
+ Examples:
15
+ $ aifabrix validate myapp
16
+ $ aifabrix validate myapp --cert-sync
17
+ $ aifabrix validate --integration
18
+ $ aifabrix validate --builder
19
+ `;
20
+
21
+ const REPAIR_HELP_AFTER = `
22
+ Examples:
23
+ $ aifabrix repair hubspot-demo
24
+ Align manifest, system/datasource files, RBAC extract, env.template, and deploy JSON under integration/<systemKey>/.
25
+
26
+ $ aifabrix repair hubspot-demo --dry-run
27
+ Show what would change without writing files.
28
+
29
+ $ aifabrix repair hubspot-demo --auth bearerToken
30
+ Private-app style apikey: Authorization + Bearer prefix; preserves baseUrl/testEndpoint when present. Warns if testEndpoint is missing.
31
+
32
+ $ aifabrix repair hubspot-demo --auth oauth2
33
+ Set authentication method; updates the system file and env.template (oauth2, aad, apikey, bearerToken, basic, …).
34
+
35
+ $ aifabrix repair hubspot-demo --rbac --expose --sync --test
36
+ Optional datasource fixes: RBAC roles/permissions, exposed.schema from attributes, default sync block, testPayload stubs.
37
+
38
+ $ aifabrix repair hubspot-demo --doc
39
+ Regenerate README.md from the current deployment manifest only (other drift fixes unchanged).
40
+
41
+ Before overwriting files, repair writes timestamped backups under integration/<systemKey>/backup/ (same as datasource capability copy). Use --no-backup to skip.
42
+ `;
43
+
44
+ const RESOLVE_HELP_AFTER = `
45
+ Examples:
46
+ $ aifabrix resolve hubspot-demo
47
+ External integration: resolves integration/<systemKey>/env.template to .env using local host ports (no Docker rewrite).
48
+
49
+ $ aifabrix resolve dataplane --fresh
50
+ Regenerate the full .env from env.template (no merge with an existing file). Use after adding many new variables or when a normal resolve did not pick up new template lines.
51
+
52
+ $ aifabrix secret set hubspot-demo/token "<your-token>"
53
+ Store a secret when resolve reports a missing kv:// reference.
54
+
55
+ If a key is not required by your system file, comment out its line in env.template instead of creating a secret.
56
+ $ aifabrix repair hubspot-demo
57
+ Align env.template with authentication.security and comment stale OAuth KV lines after --auth bearerToken.
58
+ `;
59
+
60
+ module.exports = {
61
+ JSON_HELP_AFTER,
62
+ VALIDATE_HELP_AFTER,
63
+ REPAIR_HELP_AFTER,
64
+ RESOLVE_HELP_AFTER
65
+ };
@@ -0,0 +1,198 @@
1
+ /**
2
+ * `aifabrix repair` command wiring and CLI output (split from setup-utility for size limits).
3
+ *
4
+ * @fileoverview Repair CLI command
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const chalk = require('chalk');
12
+ const logger = require('../utils/logger');
13
+ const { handleCommandError, logOfflinePathWhenType } = require('../utils/cli-utils');
14
+ const { detectAppType } = require('../utils/paths');
15
+ const { formatSuccessParagraph, formatWarningLine } = require('../utils/cli-test-layout-chalk');
16
+ const { REPAIR_HELP_AFTER } = require('./setup-utility-help-after');
17
+
18
+ /**
19
+ * @param {string} appName
20
+ * @param {object} options
21
+ * @param {string} format
22
+ * @returns {object}
23
+ */
24
+ function buildRepairExternalIntegrationOptions(appName, options, format) {
25
+ const all = options.all === true;
26
+ return {
27
+ auth: options.auth,
28
+ doc: options.doc || all,
29
+ dryRun: options.dryRun,
30
+ format,
31
+ rbac: options.rbac || all,
32
+ expose: options.expose || all,
33
+ sync: options.sync || all,
34
+ api: options.api || all,
35
+ test: options.test || all,
36
+ backup: options.backup,
37
+ noBackup: options.noBackup
38
+ };
39
+ }
40
+
41
+ /**
42
+ * @param {string[]} changedFiles
43
+ * @param {boolean} dryRun
44
+ */
45
+ function logRepairChangedFiles(changedFiles, dryRun) {
46
+ if (!Array.isArray(changedFiles) || changedFiles.length === 0) return;
47
+ const title = dryRun ? '\nWould change files:' : '\nChanged files:';
48
+ logger.log(chalk.white(title));
49
+ changedFiles.forEach((filePath) => logger.log(chalk.cyan(` ${filePath}`)));
50
+ }
51
+
52
+ /**
53
+ * @param {string[]} warnings
54
+ */
55
+ function logRepairWarnings(warnings) {
56
+ if (!Array.isArray(warnings) || warnings.length === 0) return;
57
+ warnings.forEach((msg) => logger.log(formatWarningLine(msg)));
58
+ }
59
+
60
+ /**
61
+ * @param {string[]} changedFiles
62
+ * @param {string[]} warnings
63
+ */
64
+ function logRepairNextActions(changedFiles, warnings) {
65
+ const hasFiles = Array.isArray(changedFiles) && changedFiles.length > 0;
66
+ const hasWarnings = Array.isArray(warnings) && warnings.length > 0;
67
+ if (!hasFiles && !hasWarnings) return;
68
+ logger.log(chalk.white('\nNext actions:'));
69
+ if (hasFiles) {
70
+ logger.log(chalk.gray(' • Open the paths above in your editor and review the diff'));
71
+ logger.log(chalk.gray(' • Run: aifabrix validate <systemKey>'));
72
+ }
73
+ if (hasWarnings) {
74
+ logger.log(chalk.gray(' • Fix warnings in the system file (especially authentication.variables.testEndpoint)'));
75
+ logger.log(chalk.gray(' • Run: aifabrix json <systemKey> && aifabrix upload <systemKey>'));
76
+ }
77
+ }
78
+
79
+ /**
80
+ * @param {object} options
81
+ * @param {object} result
82
+ * @param {string[]} changedFiles
83
+ */
84
+ function logRepairDryRunOutcome(options, result, changedFiles) {
85
+ logger.log(chalk.yellow('\nWould apply:'));
86
+ result.changes.forEach((c) => logger.log(chalk.gray(` ${c}`)));
87
+ logRepairChangedFiles(changedFiles, true);
88
+ logRepairWarnings(result.warnings);
89
+ logRepairNextActions(changedFiles, result.warnings);
90
+ }
91
+
92
+ /**
93
+ * @param {object} result
94
+ * @param {string[]} changedFiles
95
+ */
96
+ function logRepairSuccessOutcome(result, changedFiles) {
97
+ if (result.updated) {
98
+ logger.log(formatSuccessParagraph('Repaired external integration config.'));
99
+ logRepairChangedFiles(changedFiles, false);
100
+ logRepairNextActions(changedFiles, result.warnings);
101
+ return;
102
+ }
103
+ if (Array.isArray(result.changes) && result.changes.length > 0) {
104
+ logger.log(formatSuccessParagraph('Repair actions completed.'));
105
+ result.changes.forEach((c) => logger.log(chalk.gray(` ${c}`)));
106
+ logRepairChangedFiles(changedFiles, false);
107
+ logRepairNextActions(changedFiles, result.warnings);
108
+ return;
109
+ }
110
+ if (result.readmeRegenerated) {
111
+ logger.log(formatSuccessParagraph('Regenerated README.md from deployment manifest.'));
112
+ return;
113
+ }
114
+ if (Array.isArray(result.warnings) && result.warnings.length > 0) {
115
+ logRepairNextActions(changedFiles, result.warnings);
116
+ return;
117
+ }
118
+ logger.log(chalk.gray('No changes needed; config already matches files on disk.'));
119
+ }
120
+
121
+ /**
122
+ * @param {object} options
123
+ * @param {object} result
124
+ */
125
+ function logRepairResult(options, result) {
126
+ const changedFiles = result.changedFiles;
127
+ if (options.dryRun && result.updated && result.changes.length > 0) {
128
+ logRepairDryRunOutcome(options, result, changedFiles);
129
+ return;
130
+ }
131
+ if (Array.isArray(result.backupPaths) && result.backupPaths.length > 0) {
132
+ result.backupPaths.forEach((p) => logger.log(chalk.gray(`Backup: ${p}`)));
133
+ }
134
+ logRepairWarnings(result.warnings);
135
+ logRepairSuccessOutcome(result, changedFiles);
136
+ }
137
+
138
+ /**
139
+ * @param {string} appName
140
+ * @param {object} options
141
+ * @returns {Promise<void>}
142
+ */
143
+ async function handleRepairCommand(appName, options) {
144
+ const { repairExternalIntegration } = require('../commands/repair');
145
+ const { appPath } = await detectAppType(appName);
146
+ logOfflinePathWhenType(appPath);
147
+ let format = 'yaml';
148
+ try {
149
+ const config = require('../core/config');
150
+ format = (await config.getFormat()) || format;
151
+ } catch (_) {
152
+ /* default yaml when config unavailable */
153
+ }
154
+ const result = await repairExternalIntegration(
155
+ appName,
156
+ buildRepairExternalIntegrationOptions(appName, options, format)
157
+ );
158
+ logRepairResult(options, result);
159
+ }
160
+
161
+ /**
162
+ * @param {import('commander').Command} program
163
+ */
164
+ function setupRepairCommand(program) {
165
+ program.command('repair <systemKey>')
166
+ .description('Fix external integration drift (files, RBAC, manifest, …)')
167
+ .option('--all', 'Run all repair actions (api, doc, expose, rbac, sync, test)')
168
+ .option(
169
+ '--api',
170
+ 'Validate and sync API contracts needed for OpenAPI/MCP (uses local OpenAPI specs at integration/<systemKey>/openapi/*.json when present)'
171
+ )
172
+ .option(
173
+ '--auth <method>',
174
+ 'Set authentication method (oauth2, aad, apikey, bearerToken, basic, queryParam, oidc, hmac, none); updates system file and env.template'
175
+ )
176
+ .option('--doc', 'Regenerate README.md from deployment manifest')
177
+ .option('--expose', 'Set exposed.schema on each datasource from all fieldMappings.attributes keys (metadata.<key>); removes deprecated exposed.attributes if present')
178
+ .option('--rbac', 'Ensure RBAC permissions per datasource and add default Admin/Reader roles if none exist')
179
+ .option('--sync', 'Add default sync section to datasources that lack it')
180
+ .option('--test', 'Generate testPayload.payloadTemplate and testPayload.expectedResult from attributes')
181
+ .option('--no-backup', 'Skip timestamped copies under integration/<systemKey>/backup/')
182
+ .option('--dry-run', 'Report changes only; do not write')
183
+ .addHelpText('after', REPAIR_HELP_AFTER)
184
+ .action(async(appName, options) => {
185
+ try {
186
+ await handleRepairCommand(appName, options);
187
+ } catch (error) {
188
+ handleCommandError(error, 'repair');
189
+ process.exit(1);
190
+ }
191
+ });
192
+ }
193
+
194
+ module.exports = {
195
+ setupRepairCommand,
196
+ buildRepairExternalIntegrationOptions,
197
+ logRepairResult
198
+ };
@@ -8,13 +8,18 @@
8
8
 
9
9
  'use strict';
10
10
 
11
+ const path = require('path');
11
12
  const chalk = require('chalk');
12
13
  const secrets = require('../core/secrets');
14
+ const secretsEnsure = require('../core/secrets-ensure');
13
15
  const logger = require('../utils/logger');
14
16
  const { handleCommandError } = require('../utils/cli-utils');
15
17
  const coreConfig = require('../core/config');
18
+ const pathsUtil = require('../utils/paths');
16
19
  const { resolvePreferLocalEnvOutputPathFlag } = require('../utils/applications-config-defaults');
17
20
  const { getResolveAppPath } = require('../utils/paths');
21
+ const { resolveGenerateEnvEnvironment } = require('../utils/resolve-env-mode');
22
+ const { RESOLVE_HELP_AFTER } = require('./setup-utility-help-after');
18
23
 
19
24
  /**
20
25
  * @param {string} appName
@@ -50,10 +55,17 @@ async function runResolveJsonOutput(appName, appPath, envOnly, envPath, options,
50
55
  * @param {string} envPath
51
56
  * @param {boolean} envOnly
52
57
  * @param {{ skipValidation?: boolean }} options
58
+ * @param {'local'|'docker'} environment
53
59
  * @returns {Promise<void>}
54
60
  */
55
- async function runResolveHumanOutput(appName, envPath, envOnly, options) {
61
+ async function runResolveHumanOutput(appName, envPath, envOnly, options, environment) {
56
62
  logger.log(`✔ Generated .env file: ${envPath}`);
63
+ if (options.fresh) {
64
+ logger.log(chalk.gray(' Wrote full resolved content (--fresh; did not merge with an existing .env).'));
65
+ }
66
+ if (environment === 'local') {
67
+ logger.log(chalk.gray(' Resolved for local use (host ports; no Docker port rewrite).'));
68
+ }
57
69
  logger.log(chalk.gray(' Note: up-platform / up-miso / up-dataplane / register / build resolve secrets in memory only.'));
58
70
  logger.log(chalk.gray(` Re-run "aifabrix resolve ${appName}" whenever you need an on-disk .env again.`));
59
71
  if (envOnly) {
@@ -77,9 +89,26 @@ async function runResolveHumanOutput(appName, envPath, envOnly, options) {
77
89
  * @param {{ force?: boolean, skipValidation?: boolean, json?: boolean }} options
78
90
  * @returns {Promise<void>}
79
91
  */
92
+ async function ensureResolveSecretsFromEnvTemplate(appPath, appName) {
93
+ const templatePath = path.join(appPath, 'env.template');
94
+ let emptyValuesForCredentials = false;
95
+ try {
96
+ const appType = await pathsUtil.detectAppType(appName);
97
+ emptyValuesForCredentials = appType?.baseDir === 'integration';
98
+ } catch {
99
+ emptyValuesForCredentials = false;
100
+ }
101
+ await secretsEnsure.ensureSecretsFromEnvTemplate(templatePath, {
102
+ preferredFilePath: pathsUtil.getPrimaryUserSecretsLocalPath(),
103
+ placeholderContext: secretsEnsure.buildInfraPlaceholderContext({}),
104
+ emptyValuesForCredentials
105
+ });
106
+ }
107
+
80
108
  async function runResolveAppAction(appName, options) {
81
109
  const jsonMode = options.json === true;
82
110
  const { appPath, envOnly } = await getResolveAppPath(appName);
111
+ await ensureResolveSecretsFromEnvTemplate(appPath, appName);
83
112
  const manifestEmit = require('../utils/manifest-source-emit');
84
113
  manifestEmit.emitManifestMetadataLineIfTTY(logger, {
85
114
  appKey: appName,
@@ -89,24 +118,26 @@ async function runResolveAppAction(appName, options) {
89
118
  });
90
119
  const userCfg = await coreConfig.getConfig();
91
120
  const preferLocalEnvOutputPath = await resolvePreferLocalEnvOutputPathFlag(userCfg, appName);
121
+ const environment = resolveGenerateEnvEnvironment(appPath, appName);
92
122
  const envPath = await secrets.generateEnvFile(
93
123
  appName,
94
124
  undefined,
95
- 'docker',
125
+ environment,
96
126
  options.force,
97
127
  {
98
128
  appPath,
99
129
  envOnly,
100
130
  skipOutputPath: false,
101
131
  preserveFromPath: null,
102
- preferLocalEnvOutputPath
132
+ preferLocalEnvOutputPath,
133
+ freshEnv: options.fresh === true
103
134
  }
104
135
  );
105
136
  if (jsonMode) {
106
137
  await runResolveJsonOutput(appName, appPath, envOnly, envPath, options, manifestEmit);
107
138
  return;
108
139
  }
109
- await runResolveHumanOutput(appName, envPath, envOnly, options);
140
+ await runResolveHumanOutput(appName, envPath, envOnly, options, environment);
110
141
  }
111
142
 
112
143
  /**
@@ -114,9 +145,14 @@ async function runResolveAppAction(appName, options) {
114
145
  * @returns {void}
115
146
  */
116
147
  function setupResolveCommand(program) {
117
- program.command('resolve <app>')
118
- .description('Generate .env from template; optional validate after')
148
+ program.command('resolve <appKey|systemKey>')
149
+ .description('Generate .env from template (builder/<appKey>/ or integration/<systemKey>/); optional validate after')
150
+ .addHelpText('after', RESOLVE_HELP_AFTER)
119
151
  .option('-f, --force', 'Generate missing secret keys in secrets file')
152
+ .option(
153
+ '--fresh',
154
+ 'Replace .env from env.template (no merge with existing .env or envOutputPath; same as deleting .env first)'
155
+ )
120
156
  .option('--skip-validation', 'Skip file validation after generating .env')
121
157
  .option('--json', 'Print JSON summary (envPath, manifestSource, optional validation)')
122
158
  .action(async(appName, options) => {