@aifabrix/builder 2.45.5 → 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 (231) 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/README.md +43 -17
  5. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  6. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.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 +41 -136
  12. package/lib/api/api-response-errors.js +124 -0
  13. package/lib/api/governance-scenario-pack.api.js +159 -0
  14. package/lib/api/index.js +43 -3
  15. package/lib/api/lifecycle.api.js +77 -0
  16. package/lib/api/pipeline.api.js +3 -1
  17. package/lib/api/records-bulk.api.js +14 -1
  18. package/lib/api/validation-runner.js +3 -1
  19. package/lib/app/deploy-config.js +4 -1
  20. package/lib/app/down.js +20 -1
  21. package/lib/app/push.js +4 -5
  22. package/lib/app/register.js +7 -4
  23. package/lib/app/run-env-compose.js +84 -30
  24. package/lib/build/index.js +5 -0
  25. package/lib/certification/sync-system-certification.js +13 -6
  26. package/lib/cli/index.js +4 -0
  27. package/lib/cli/infra-guided-auth.js +109 -0
  28. package/lib/cli/infra-guided.js +84 -81
  29. package/lib/cli/setup-app.help.js +0 -31
  30. package/lib/cli/setup-app.js +28 -2
  31. package/lib/cli/setup-app.test-commands.js +5 -57
  32. package/lib/cli/setup-auth.js +25 -0
  33. package/lib/cli/setup-certification-commands.js +147 -0
  34. package/lib/cli/setup-certification.help.js +141 -0
  35. package/lib/cli/setup-environment.js +19 -2
  36. package/lib/cli/setup-external-system-help.js +62 -0
  37. package/lib/cli/setup-external-system.js +25 -3
  38. package/lib/cli/setup-infra.js +9 -1
  39. package/lib/cli/setup-platform.js +6 -1
  40. package/lib/cli/setup-secrets.js +33 -1
  41. package/lib/cli/setup-utility-help-after.js +22 -2
  42. package/lib/cli/setup-utility-repair.js +198 -0
  43. package/lib/cli/setup-utility-resolve.js +40 -4
  44. package/lib/cli/setup-utility-validate.js +197 -0
  45. package/lib/cli/setup-utility.js +4 -239
  46. package/lib/commands/auth-status-client-tokens.js +214 -0
  47. package/lib/commands/auth-status-dataplane-version.js +58 -20
  48. package/lib/commands/auth-status.js +41 -47
  49. package/lib/commands/datasource-test-trust-cli.js +27 -23
  50. package/lib/commands/datasource-unified-test-cli.js +6 -3
  51. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  52. package/lib/commands/datasource.js +7 -7
  53. package/lib/commands/dev-show-display.js +8 -1
  54. package/lib/commands/governance-cli-shared.js +94 -0
  55. package/lib/commands/governance-command-action.js +132 -0
  56. package/lib/commands/governance-download-external.js +34 -0
  57. package/lib/commands/governance-generate-external.js +71 -0
  58. package/lib/commands/governance-upload-external.js +36 -0
  59. package/lib/commands/governance-verify-external.js +64 -0
  60. package/lib/commands/governance.js +144 -0
  61. package/lib/commands/lifecycle-command-action.js +123 -0
  62. package/lib/commands/lifecycle-external.js +268 -0
  63. package/lib/commands/login.js +11 -2
  64. package/lib/commands/repair-auth-apply.js +127 -0
  65. package/lib/commands/repair-changed-files.js +41 -0
  66. package/lib/commands/repair-datasource-keys.js +4 -1
  67. package/lib/commands/repair-datasource-run.js +59 -0
  68. package/lib/commands/repair-datasource-test-payload.js +259 -0
  69. package/lib/commands/repair-datasource.js +1 -51
  70. package/lib/commands/repair-env-template.js +64 -13
  71. package/lib/commands/repair-external-run.js +216 -0
  72. package/lib/commands/repair-openapi-sync.js +23 -0
  73. package/lib/commands/repair-persist.js +4 -0
  74. package/lib/commands/repair-rbac.js +52 -1
  75. package/lib/commands/repair-steps.js +145 -0
  76. package/lib/commands/repair.js +29 -296
  77. package/lib/commands/secrets-get.js +184 -0
  78. package/lib/commands/secrets-remove-all.js +3 -1
  79. package/lib/commands/setup-image-refresh.js +146 -0
  80. package/lib/commands/setup-modes.js +158 -162
  81. package/lib/commands/setup-platform-auth.js +76 -0
  82. package/lib/commands/setup-prompts-admin.js +244 -0
  83. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  84. package/lib/commands/setup-prompts-validators.js +36 -0
  85. package/lib/commands/setup-prompts.js +24 -76
  86. package/lib/commands/setup-run-context.js +45 -0
  87. package/lib/commands/setup-spinners.js +39 -0
  88. package/lib/commands/setup.js +27 -5
  89. package/lib/commands/teardown.js +39 -0
  90. package/lib/commands/test-e2e-external.js +24 -8
  91. package/lib/commands/test-governance-external.js +3 -24
  92. package/lib/commands/test-trust-external.js +20 -21
  93. package/lib/commands/up-common.js +25 -13
  94. package/lib/commands/up-dataplane.js +50 -13
  95. package/lib/commands/upload-publish-context.js +75 -0
  96. package/lib/commands/upload-sidecar-followups.js +89 -0
  97. package/lib/commands/upload.js +90 -108
  98. package/lib/commands/verify-governance-combined-external.js +61 -0
  99. package/lib/commands/verify-governance-command-action.js +64 -0
  100. package/lib/commands/verify-governance-db.js +102 -0
  101. package/lib/commands/verify-governance-external.js +77 -0
  102. package/lib/commands/verify-governance-result-builders.js +71 -0
  103. package/lib/commands/verify-operations-command-action.js +68 -0
  104. package/lib/commands/verify-operations-external.js +268 -0
  105. package/lib/commands/verify-operations-persist.js +75 -0
  106. package/lib/commands/verify-operations-step-plan.js +68 -0
  107. package/lib/commands/verify-operations-steps.js +111 -0
  108. package/lib/commands/verify-trust-command-action.js +70 -0
  109. package/lib/commands/verify-trust-external.js +67 -0
  110. package/lib/commands/wizard-config-normalizer.js +43 -23
  111. package/lib/commands/wizard-core.js +2 -0
  112. package/lib/core/admin-password-generator.js +38 -0
  113. package/lib/core/admin-secrets-bundle.js +111 -0
  114. package/lib/core/admin-secrets-env-overlay.js +62 -0
  115. package/lib/core/admin-secrets.js +32 -4
  116. package/lib/core/config-attach-extensions.js +3 -0
  117. package/lib/core/config-platform-controller.js +44 -0
  118. package/lib/core/config-setup-installation-profile.js +42 -0
  119. package/lib/core/config-setup-platform-mode.js +46 -0
  120. package/lib/core/config.js +46 -36
  121. package/lib/core/secrets-admin-env.js +6 -2
  122. package/lib/core/secrets-ensure.js +4 -0
  123. package/lib/core/secrets-env-content.js +54 -48
  124. package/lib/core/secrets-env-write.js +10 -1
  125. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  126. package/lib/core/setup-installation-profile.js +43 -0
  127. package/lib/core/setup-platform-mode.js +55 -0
  128. package/lib/datasource/agent-trust-debug-log.js +1 -1
  129. package/lib/datasource/agent-trust-run.js +5 -3
  130. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  131. package/lib/datasource/audit-evidence-extract.js +7 -4
  132. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  133. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  134. package/lib/datasource/datasource-load-export-context.js +3 -0
  135. package/lib/datasource/log-cleaner.js +2 -2
  136. package/lib/datasource/log-viewer.js +8 -8
  137. package/lib/datasource/test-e2e.js +4 -1
  138. package/lib/datasource/unified-validation-run-body.js +3 -1
  139. package/lib/datasource/unified-validation-run.js +5 -2
  140. package/lib/deployment/environment-poll-status.js +138 -0
  141. package/lib/deployment/environment.js +42 -34
  142. package/lib/external-system/download.js +21 -20
  143. package/lib/external-system/generator.js +5 -1
  144. package/lib/external-system/integration-auth-context.js +45 -0
  145. package/lib/external-system/test-auth.js +12 -5
  146. package/lib/external-system/test.js +6 -6
  147. package/lib/generator/external-controller-manifest.js +15 -0
  148. package/lib/governance/governance-cli-errors.js +96 -0
  149. package/lib/governance/governance-download-display.js +38 -0
  150. package/lib/governance/governance-run-display.js +215 -25
  151. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  152. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  153. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  154. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  155. package/lib/infrastructure/helpers.js +23 -129
  156. package/lib/infrastructure/index.js +5 -6
  157. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  158. package/lib/lifecycle/certification-progress.js +231 -0
  159. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  160. package/lib/lifecycle/exit-codes.js +24 -0
  161. package/lib/lifecycle/json-envelope.js +25 -0
  162. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  163. package/lib/lifecycle/logger-quiet.js +29 -0
  164. package/lib/lifecycle/open-api-published.js +59 -0
  165. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  166. package/lib/lifecycle/product-model.js +196 -0
  167. package/lib/lifecycle/report-display.js +471 -0
  168. package/lib/lifecycle/scenario-upload.js +191 -0
  169. package/lib/lifecycle/verify-step-progress.js +87 -0
  170. package/lib/parameters/infra-kv-discovery.js +27 -2
  171. package/lib/protection/auth-context.js +10 -4
  172. package/lib/schema/application-schema.json +1 -1
  173. package/lib/schema/datasource-test-run.schema.json +89 -6
  174. package/lib/schema/external-datasource.schema.json +2636 -2622
  175. package/lib/schema/external-system.schema.json +1089 -761
  176. package/lib/schema/infra.parameter.yaml +45 -0
  177. package/lib/schema/type/credential-field-registry.json +103 -97
  178. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  179. package/lib/utils/api.js +55 -31
  180. package/lib/utils/app-relative-path-env.js +112 -0
  181. package/lib/utils/cli-secrets-error-format.js +83 -21
  182. package/lib/utils/cli-utils.js +16 -4
  183. package/lib/utils/compose-generate-docker-compose.js +4 -0
  184. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  185. package/lib/utils/config-secrets-path.js +46 -0
  186. package/lib/utils/controller-url.js +88 -1
  187. package/lib/utils/credential-secrets-env.js +137 -9
  188. package/lib/utils/dataplane-resolver.js +129 -2
  189. package/lib/utils/declarative-url-ports.js +3 -3
  190. package/lib/utils/deployment-auth-mode.js +41 -0
  191. package/lib/utils/developer-volume-id.js +33 -0
  192. package/lib/utils/env-copy.js +14 -9
  193. package/lib/utils/env-kv-orphan-lines.js +43 -0
  194. package/lib/utils/error-formatters/network-errors.js +13 -4
  195. package/lib/utils/external-env-template.js +1 -0
  196. package/lib/utils/external-system-readiness-core.js +10 -0
  197. package/lib/utils/external-system-readiness-display.js +80 -23
  198. package/lib/utils/health-check.js +4 -1
  199. package/lib/utils/help-builder.js +11 -8
  200. package/lib/utils/keycloak-realm-ready.js +101 -0
  201. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  202. package/lib/utils/manifest-source-emit.js +2 -0
  203. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  204. package/lib/utils/platform-controller-url.js +156 -0
  205. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  206. package/lib/utils/postgres-wipe.js +9 -2
  207. package/lib/utils/resolve-env-mode.js +47 -0
  208. package/lib/utils/secrets-generator.js +31 -25
  209. package/lib/utils/secrets-missing-error.js +164 -0
  210. package/lib/utils/service-url-label.js +81 -0
  211. package/lib/utils/setup-quiet-output.js +25 -0
  212. package/lib/utils/template-helpers.js +15 -0
  213. package/lib/utils/token-manager-client-credentials.js +201 -0
  214. package/lib/utils/token-manager-messages.js +8 -0
  215. package/lib/utils/token-manager-refresh.js +12 -2
  216. package/lib/utils/token-manager.js +86 -105
  217. package/lib/utils/upload-pipeline-ui.js +12 -5
  218. package/lib/utils/upload-sync-options.js +42 -0
  219. package/lib/utils/url-declarative-public-base.js +21 -3
  220. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  221. package/lib/utils/validation-poll-ui.js +8 -0
  222. package/lib/utils/validation-run-stage.js +45 -0
  223. package/package.json +1 -1
  224. package/templates/applications/dataplane/application.yaml +2 -1
  225. package/templates/applications/dataplane/env.template +24 -1
  226. package/templates/applications/miso-controller/env.template +16 -0
  227. package/templates/external-system/README.md.hbs +74 -17
  228. package/templates/python/docker-compose.hbs +19 -18
  229. package/templates/typescript/docker-compose.hbs +18 -17
  230. package/lib/commands/test-governance-command-action.js +0 -55
  231. package/lib/commands/test-trust-command-action.js +0 -118
@@ -2,8 +2,8 @@
2
2
  * Top-level handler for `aifabrix setup`.
3
3
  *
4
4
  * Decides between:
5
- * - fresh install (no infra running) — wizard for admin creds + AI tool, then up-infra + up-platform.
6
- * - mode menu (infra already running) — dispatch one of four destructive/refresh paths.
5
+ * - fresh install (no infra running) — wipe volumes, wizard for admin creds + AI tool, then up-infra + up-platform.
6
+ * - mode menu (infra already running) — dispatch one of three destructive/refresh paths.
7
7
  *
8
8
  * The mode handlers live in `setup-modes.js`; the prompts live in
9
9
  * `setup-prompts.js`. This module is a thin orchestrator so it stays well
@@ -28,8 +28,12 @@ const {
28
28
  } = require('../utils/cli-test-layout-chalk');
29
29
 
30
30
  const setupPrompts = require('./setup-prompts');
31
+ const setupPlatformModePrompts = require('./setup-prompts-platform-mode');
32
+ const { flagsForSetupPlatformMode } = require('../core/setup-platform-mode');
31
33
  const setupModes = require('./setup-modes');
34
+ const { syncPlatformControllerUrlsInConfig } = require('./setup-platform-auth');
32
35
  const installationLog = require('../utils/installation-log');
36
+ const { beginSetupCommandFlow, endSetupCommandFlow } = require('./setup-run-context');
33
37
 
34
38
  const MODE = setupPrompts.MODE;
35
39
 
@@ -54,10 +58,24 @@ async function maybePinDeveloperIdForFreshInstall(rawDeveloper) {
54
58
  logger.log(infoLine(`Developer ID pinned to ${dev}.`));
55
59
  }
56
60
 
61
+ async function applySetupPlatformMode(options) {
62
+ const mode = await setupPlatformModePrompts.promptSetupPlatformMode(options);
63
+ await config.setSetupPlatformMode(mode);
64
+ const derived = flagsForSetupPlatformMode(mode);
65
+ // These are the user gates that control full-mode behavior.
66
+ const cfg = await config.getConfig();
67
+ cfg.traefik = derived.traefik;
68
+ cfg.useEnvironmentScopedResources = derived.useEnvironmentScopedResources;
69
+ await config.saveConfig(cfg);
70
+ await syncPlatformControllerUrlsInConfig();
71
+ return mode;
72
+ }
73
+
57
74
  async function runFreshInstallFlow(options) {
58
75
  await maybePinDeveloperIdForFreshInstall(options.developer);
59
76
  logger.log(infoLine('No infrastructure detected; starting fresh install.'));
60
- const adminCreds = await setupPrompts.promptAdminCredentials();
77
+ await applySetupPlatformMode(options);
78
+ const adminCreds = await setupPrompts.promptAdminCredentials(options);
61
79
  await config.setAdminEmail(adminCreds.adminEmail);
62
80
  await setupModes.runFreshInstall(adminCreds);
63
81
  logger.log(formatSuccessParagraph('aifabrix setup complete (fresh install).'));
@@ -74,6 +92,10 @@ async function runExistingInfraFlow(assumeYes) {
74
92
  logger.log(chalk.yellow('Aborted by user.'));
75
93
  return { aborted: true, mode };
76
94
  }
95
+ // Re-install / wipe-data can change platform topology; re-prompt so the next up-platform matches intent.
96
+ if (mode === MODE.REINSTALL || mode === MODE.WIPE_DATA) {
97
+ await applySetupPlatformMode({});
98
+ }
77
99
  await dispatchMode(mode);
78
100
  logger.log(formatSuccessParagraph(`aifabrix setup complete (mode: ${mode}).`));
79
101
  return { aborted: false, mode };
@@ -114,8 +136,6 @@ async function dispatchMode(mode) {
114
136
  return setupModes.runReinstall();
115
137
  case MODE.WIPE_DATA:
116
138
  return setupModes.runWipeData();
117
- case MODE.CLEAN_FILES:
118
- return setupModes.runCleanInstallFiles();
119
139
  case MODE.UPDATE_IMAGES:
120
140
  return setupModes.runUpdateImages();
121
141
  default:
@@ -224,6 +244,7 @@ async function handleSetup(options = {}) {
224
244
  let setupMode = null;
225
245
  let err = null;
226
246
 
247
+ beginSetupCommandFlow();
227
248
  try {
228
249
  const main = await runSetupMainPath(options, assumeYes);
229
250
  outcome = main.outcome;
@@ -232,6 +253,7 @@ async function handleSetup(options = {}) {
232
253
  outcome = 'failure';
233
254
  err = e;
234
255
  } finally {
256
+ endSetupCommandFlow();
235
257
  await appendSetupInstallationRecord({
236
258
  outcome,
237
259
  startedAt,
@@ -118,6 +118,37 @@ function cleanAifabrixSystemDir() {
118
118
  return { removed, failed };
119
119
  }
120
120
 
121
+ /**
122
+ * Remove materialized `builder/` trees (aifabrix-work, aifabrix-home / config dir, cwd).
123
+ * Complements {@link cleanAifabrixSystemDir} when `builder/` lives under `aifabrix-work` outside
124
+ * the config directory.
125
+ *
126
+ * @returns {{ removed: string[], failed: string[] }}
127
+ */
128
+ function cleanMaterializedBuilderTrees() {
129
+ const candidates = [
130
+ pathsUtil.getBuilderRoot(),
131
+ path.join(pathsUtil.getAifabrixSystemDir(), 'builder'),
132
+ path.join(process.cwd(), 'builder')
133
+ ];
134
+ const seen = new Set();
135
+ const removed = [];
136
+ const failed = [];
137
+ for (const candidate of candidates) {
138
+ const resolved = path.resolve(candidate);
139
+ if (seen.has(resolved)) continue;
140
+ seen.add(resolved);
141
+ if (!fs.existsSync(resolved)) continue;
142
+ try {
143
+ fs.rmSync(resolved, { recursive: true, force: true });
144
+ removed.push(resolved);
145
+ } catch {
146
+ failed.push(resolved);
147
+ }
148
+ }
149
+ return { removed, failed };
150
+ }
151
+
121
152
  /**
122
153
  * Stop infra with `down-infra -v` semantics. Tolerates already-down state.
123
154
  * @async
@@ -259,6 +290,13 @@ async function handleTeardown(options = {}) {
259
290
  try {
260
291
  await stopInfraQuietly();
261
292
  const { removed, failed } = cleanFilesWithSpinner();
293
+ const builderClean = cleanMaterializedBuilderTrees();
294
+ for (const p of builderClean.removed) {
295
+ removed.push(p);
296
+ }
297
+ for (const p of builderClean.failed) {
298
+ failed.push(p);
299
+ }
262
300
  const devStr = await buildDeveloperLabel();
263
301
  logTeardownFooter({ devStr, removedCount: removed.length, failedCount: failed.length });
264
302
 
@@ -271,6 +309,7 @@ async function handleTeardown(options = {}) {
271
309
  module.exports = {
272
310
  handleTeardown,
273
311
  cleanAifabrixSystemDir,
312
+ cleanMaterializedBuilderTrees,
274
313
  stopInfraQuietly,
275
314
  PRESERVE_FILE,
276
315
  PRESERVE_CERTS_DIR
@@ -19,6 +19,7 @@ const { loadConfigFile } = require('../utils/config-format');
19
19
  const { discoverIntegrationFiles, buildEffectiveDatasourceFiles } = require('./repair-internal');
20
20
  const { runDatasourceTestE2E } = require('../datasource/test-e2e');
21
21
  const { cliOptsSkipSync } = require('../utils/cli-sync-options');
22
+ const { buildMinimalUploadSyncOptions, isQuietMinimalSync } = require('../utils/upload-sync-options');
22
23
  const { getConfig } = require('../core/config');
23
24
  const { setupIntegrationTestAuth } = require('../external-system/test-auth');
24
25
 
@@ -96,13 +97,12 @@ function getDatasourceKeys(appPath, configPath, variables, systemKey, systemPars
96
97
  */
97
98
  async function syncLocalIfRequested(systemKey, options) {
98
99
  if (cliOptsSkipSync(options)) return null;
99
- logger.log(chalk.cyan('Syncing local config to dataplane…'));
100
100
  const { uploadExternalSystem } = require('./upload');
101
- const uploadCtx = await uploadExternalSystem(systemKey, {
102
- verbose: !!options.verbose,
103
- minimal: true
104
- });
105
- logger.log(formatSuccessLine('Sync complete'));
101
+ const uploadOpts = buildMinimalUploadSyncOptions(options);
102
+ const uploadCtx = await uploadExternalSystem(systemKey, uploadOpts);
103
+ if (uploadCtx?.uploadSkipped !== true && !isQuietMinimalSync(uploadOpts)) {
104
+ logger.log(formatSuccessLine('Sync complete'));
105
+ }
106
106
  return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
107
107
  }
108
108
 
@@ -176,11 +176,18 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
176
176
  let dataplaneUrl;
177
177
  if (uploadCtx) {
178
178
  ({ authConfig, dataplaneUrl } = uploadCtx);
179
+ } else if (options.authConfig && options.dataplaneUrl) {
180
+ ({ authConfig, dataplaneUrl } = options);
179
181
  } else {
180
182
  const configObj = await getConfig();
181
183
  ({ authConfig, dataplaneUrl } = await setupIntegrationTestAuth(
182
184
  externalSystem,
183
- { environment: options.env },
185
+ {
186
+ environment: options.env,
187
+ authConfig: options.authConfig,
188
+ dataplaneUrl: options.dataplaneUrl,
189
+ silentResolve: options.silentResolve === true
190
+ },
184
191
  configObj
185
192
  ));
186
193
  }
@@ -193,9 +200,18 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
193
200
  verbose: options.verbose,
194
201
  async: options.async !== false,
195
202
  authConfig,
196
- dataplaneUrl
203
+ dataplaneUrl,
204
+ quietPollUi: options.quietPollUi === true,
205
+ onPollProgress: options.onPollProgress
197
206
  };
198
207
  for (const key of keys) {
208
+ if (typeof options.onDatasourceProgress === 'function') {
209
+ options.onDatasourceProgress({
210
+ key,
211
+ index: results.length,
212
+ total: keys.length
213
+ });
214
+ }
199
215
  try {
200
216
  const data = await runDatasourceTestE2E(key, opts);
201
217
  const steps = data.steps || data.completedActions || [];
@@ -6,9 +6,6 @@
6
6
 
7
7
  'use strict';
8
8
 
9
- const chalk = require('chalk');
10
- const logger = require('../utils/logger');
11
- const { cliOptsSkipSync } = require('../utils/cli-sync-options');
12
9
  const { getConfig } = require('../core/config');
13
10
  const { setupIntegrationTestAuth } = require('../external-system/test-auth');
14
11
  const { runGovernanceScenarios } = require('../api/governance-scenarios.api');
@@ -16,25 +13,7 @@ const {
16
13
  resolveGovernancePackPath,
17
14
  loadGovernancePackYaml
18
15
  } = require('../governance/governance-pack-loader');
19
-
20
- /**
21
- * @param {string} systemKey
22
- * @param {Object} options
23
- * @returns {Promise<{ authConfig: Object, dataplaneUrl: string }|null>}
24
- */
25
- async function syncLocalIfRequested(systemKey, options) {
26
- if (cliOptsSkipSync(options)) {
27
- return null;
28
- }
29
- const { uploadExternalSystem } = require('./upload');
30
- logger.log(chalk.cyan('Syncing local config to dataplane…'));
31
- const uploadCtx = await uploadExternalSystem(systemKey, {
32
- minimal: true,
33
- verbose: !!options.verbose
34
- });
35
- logger.log(chalk.green('✔ Sync complete'));
36
- return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
37
- }
16
+ const { syncLocalIfRequested } = require('./test-e2e-external');
38
17
 
39
18
  /**
40
19
  * @async
@@ -47,7 +26,7 @@ async function runTestGovernanceForExternalSystem(externalSystem, options = {})
47
26
  const appType = await pathsUtil.detectAppType(externalSystem).catch(() => null);
48
27
  if (!appType || appType.baseDir !== 'integration') {
49
28
  throw new Error(
50
- 'test-governance applies to external integration folders only (integration/<systemKey>/).'
29
+ 'verify-governance applies to external integration folders only (integration/<systemKey>/).'
51
30
  );
52
31
  }
53
32
 
@@ -79,7 +58,7 @@ async function runTestGovernanceForExternalSystem(externalSystem, options = {})
79
58
  scenarios: options.scenarioIds
80
59
  };
81
60
  const result = await runGovernanceScenarios(dataplaneUrl, authConfig, body);
82
- return { result, packPath, systemKey };
61
+ return { result, packPath, systemKey, packDocument: pack };
83
62
  }
84
63
 
85
64
  module.exports = {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @fileoverview test-trust <systemKey> — semantic agent metadata validation for all datasources.
2
+ * @fileoverview verify-trust <systemKey> — semantic agent metadata validation for all datasources.
3
3
  * @author AI Fabrix Team
4
4
  * @version 1.0.0
5
5
  */
@@ -8,28 +8,13 @@
8
8
 
9
9
  const chalk = require('chalk');
10
10
  const logger = require('../utils/logger');
11
- const { cliOptsSkipSync } = require('../utils/cli-sync-options');
12
11
  const { getConfig } = require('../core/config');
13
12
  const { setupIntegrationTestAuth } = require('../external-system/test-auth');
14
13
  const { runDatasourceAgentTrust } = require('../datasource/agent-trust-run');
15
- const { resolveExternalIntegrationContext } = require('./test-e2e-external');
16
-
17
- /**
18
- * @param {string} systemKey
19
- * @param {Object} options
20
- * @returns {Promise<{ authConfig: Object, dataplaneUrl: string }|null>}
21
- */
22
- async function syncLocalIfRequested(systemKey, options) {
23
- if (cliOptsSkipSync(options)) return null;
24
- const { uploadExternalSystem } = require('./upload');
25
- logger.log(chalk.cyan('Syncing local config to dataplane…'));
26
- const uploadCtx = await uploadExternalSystem(systemKey, {
27
- minimal: true,
28
- verbose: !!options.verbose
29
- });
30
- logger.log(chalk.green('✔ Sync complete'));
31
- return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
32
- }
14
+ const {
15
+ resolveExternalIntegrationContext,
16
+ syncLocalIfRequested
17
+ } = require('./test-e2e-external');
33
18
 
34
19
  function pushTrustResult(results, key, trustRun, apiError) {
35
20
  const failed =
@@ -61,7 +46,16 @@ async function resolveTrustAuthContext(uploadCtx, externalSystem, options) {
61
46
  return { authConfig: uploadCtx.authConfig, dataplaneUrl: uploadCtx.dataplaneUrl };
62
47
  }
63
48
  const configObj = await getConfig();
64
- return setupIntegrationTestAuth(externalSystem, { environment: options.env }, configObj);
49
+ return setupIntegrationTestAuth(
50
+ externalSystem,
51
+ {
52
+ environment: options.env,
53
+ authConfig: options.authConfig,
54
+ dataplaneUrl: options.dataplaneUrl,
55
+ silentResolve: options.silentResolve === true
56
+ },
57
+ configObj
58
+ );
65
59
  }
66
60
 
67
61
  /**
@@ -95,6 +89,11 @@ async function runTestTrustForExternalSystem(externalSystem, options = {}) {
95
89
  }
96
90
 
97
91
  const uploadCtx = await syncLocalIfRequested(systemKey, options);
92
+ if (uploadCtx?.authConfig && uploadCtx?.dataplaneUrl) {
93
+ options.authConfig = uploadCtx.authConfig;
94
+ options.dataplaneUrl = uploadCtx.dataplaneUrl;
95
+ options.silentResolve = true;
96
+ }
98
97
  if (options.revalidate === true) {
99
98
  logger.log(chalk.cyan('Forcing revalidation (cache bypass) for each datasource…'));
100
99
  }
@@ -14,7 +14,7 @@ const fs = require('fs');
14
14
  const chalk = require('chalk');
15
15
  const logger = require('../utils/logger');
16
16
  const config = require('../core/config');
17
- const { getDefaultControllerUrl } = require('../utils/controller-url');
17
+ const { resolvePlatformControllerUrl } = require('../utils/platform-controller-url');
18
18
  const pathsUtil = require('../utils/paths');
19
19
  const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
20
20
  const { isYamlPath } = require('../utils/config-format');
@@ -189,19 +189,29 @@ function patchEnvOutputPathForDeployOnly(appName) {
189
189
 
190
190
  /**
191
191
  * For ``up-platform --force`` only: clear all stored auth tokens, set ``environment`` to ``dev``,
192
- * set ``controller`` to the default URL for the current ``developer-id`` (``http://localhost`` +
193
- * app port = 3000 + developerId × 100), and persist config. Does not change ``developer-id``.
192
+ * set ``controller`` and ``platform-controller`` to the default URL (or ``defaultControllerUrl`` when
193
+ * provided), and persist config. Does not change ``developer-id``. Pass ``clearTokens: false`` to
194
+ * keep device/client tokens (setup when already logged in to the platform controller).
194
195
  * Builder dirs (keycloak, miso-controller, dataplane) are cleaned separately.
195
196
  *
196
197
  * @returns {Promise<void>}
197
198
  */
198
199
  async function applyUpPlatformForceConfig(opts = {}) {
199
200
  const silent = Boolean(opts.silent);
200
- const deviceCleared = await config.clearAllDeviceTokens();
201
- const clientCleared = await config.clearAllClientTokens();
201
+ const clearTokens = opts.clearTokens !== false;
202
+ let deviceCleared = 0;
203
+ let clientCleared = 0;
204
+ if (clearTokens) {
205
+ deviceCleared = await config.clearAllDeviceTokens();
206
+ clientCleared = await config.clearAllClientTokens();
207
+ }
202
208
  await config.setCurrentEnvironment('dev');
203
- const defaultControllerUrl = await getDefaultControllerUrl();
209
+ const defaultControllerUrl =
210
+ opts.defaultControllerUrl && typeof opts.defaultControllerUrl === 'string'
211
+ ? String(opts.defaultControllerUrl).replace(/\/+$/, '')
212
+ : await resolvePlatformControllerUrl();
204
213
  await config.setControllerUrl(defaultControllerUrl);
214
+ await config.setPlatformControllerUrl(defaultControllerUrl);
205
215
 
206
216
  const summary = { deviceCleared, clientCleared, defaultControllerUrl, environment: 'dev' };
207
217
  if (!silent) {
@@ -287,14 +297,15 @@ async function cleanBuilderAppDirs(appNames, opts = {}) {
287
297
  * @example
288
298
  * await ensureAppFromTemplate('keycloak');
289
299
  */
290
- async function ensureAppFromTemplate(appName) {
300
+ async function ensureAppFromTemplate(appName, opts = {}) {
291
301
  if (!appName || typeof appName !== 'string') {
292
302
  throw new Error('Application name is required and must be a string');
293
303
  }
304
+ const silent = Boolean(opts.silent);
294
305
 
295
306
  const appPath = pathsUtil.getBuilderPath(appName);
296
307
  const primaryCopied = await ensureTemplateAtPath(appName, appPath);
297
- if (primaryCopied) {
308
+ if (primaryCopied && !silent) {
298
309
  logger.log(chalk.blue(`Creating builder/${appName} from template...`));
299
310
  logger.log(formatSuccessLine(`Copied template for ${appName}`));
300
311
  }
@@ -307,7 +318,7 @@ async function ensureAppFromTemplate(appName) {
307
318
  !pathsUtil.isSystemBuilderAppName(appName)
308
319
  ) {
309
320
  const cwdCopied = await ensureTemplateAtPath(appName, cwdBuilderPath);
310
- if (cwdCopied) {
321
+ if (cwdCopied && !silent) {
311
322
  logger.log(chalk.blue(`Creating builder/${appName} in project (from template)...`));
312
323
  logger.log(formatSuccessLine(`Copied template for ${appName} into builder/`));
313
324
  }
@@ -339,10 +350,11 @@ function refreshUrlsLocalRegistryForCurrentProject() {
339
350
  *
340
351
  * @returns {Promise<void>}
341
352
  */
342
- async function prepareUrlsLocalRegistryForUpPlatform() {
343
- await ensureAppFromTemplate('keycloak');
344
- await ensureAppFromTemplate('miso-controller');
345
- await ensureAppFromTemplate('dataplane');
353
+ async function prepareUrlsLocalRegistryForUpPlatform(opts = {}) {
354
+ const templateOpts = { silent: Boolean(opts.silent) };
355
+ await ensureAppFromTemplate('keycloak', templateOpts);
356
+ await ensureAppFromTemplate('miso-controller', templateOpts);
357
+ await ensureAppFromTemplate('dataplane', templateOpts);
346
358
  refreshUrlsLocalRegistryForCurrentProject();
347
359
  }
348
360
 
@@ -103,6 +103,22 @@ async function resolveControllerUrlWithHealthCheck() {
103
103
  return normalizedNew;
104
104
  }
105
105
 
106
+ async function resolveUpDataplaneAuthContext(options, environmentKey) {
107
+ if (options.skipInfraCheck !== true) {
108
+ await assertDevInfraUp();
109
+ }
110
+
111
+ const controllerUrl = await resolveControllerUrlWithHealthCheck();
112
+ const authConfig = await checkAuthentication(controllerUrl, environmentKey, { throwOnFailure: true });
113
+
114
+ const cfg = await config.getConfig();
115
+ if (options.allowNonDev !== true) {
116
+ assertDevEnvironmentForDataplane(cfg);
117
+ }
118
+ logger.log(formatSuccessLine(`Logged in (environment: ${environmentKey})`));
119
+ return { controllerUrl, authConfig };
120
+ }
121
+
106
122
  /**
107
123
  * Register or rotate dataplane: if app exists in controller, rotate secret; otherwise register.
108
124
  * @async
@@ -118,7 +134,12 @@ async function registerOrRotateDataplane(options, controllerUrl, environmentKey,
118
134
  await rotateSecret('dataplane', options);
119
135
  } else {
120
136
  const imageOverride = options.image || buildDataplaneImageRef(options);
121
- const registerOpts = { imageOverride, image: imageOverride, registryMode: options.registryMode };
137
+ const registerOpts = {
138
+ imageOverride,
139
+ image: imageOverride,
140
+ registryMode: options.registryMode,
141
+ envKey: environmentKey
142
+ };
122
143
  await registerApplication('dataplane', registerOpts);
123
144
  }
124
145
  }
@@ -134,6 +155,7 @@ async function deployDataplaneToController(options) {
134
155
  imageOverride,
135
156
  image: imageOverride,
136
157
  registryMode: options.registryMode,
158
+ envKey: options.envKey ? String(options.envKey).trim().toLowerCase() : undefined,
137
159
  // Guided up-platform already shows a top-level spinner for the dataplane step.
138
160
  // Avoid nested deploy polling spinners/logs.
139
161
  silentPoll: options.platformInstall === true
@@ -172,6 +194,14 @@ function emitDataplaneManifestLineFromBuilder() {
172
194
  emitSystemBuilderAppManifestLineIfTTY(logger, 'dataplane');
173
195
  }
174
196
 
197
+ function computeDataplanePortOverride(runEnvKey, developerIdNum) {
198
+ if (runEnvKey !== 'dev' && runEnvKey !== 'tst') {
199
+ return undefined;
200
+ }
201
+ const baseHostPort = 3001 + (Number.isFinite(developerIdNum) ? developerIdNum : 0) * 100;
202
+ return runEnvKey === 'dev' ? baseHostPort + 10 : baseHostPort + 20;
203
+ }
204
+
175
205
  function assertDevEnvironmentForDataplane(cfg) {
176
206
  const environment = (cfg && cfg.environment) ? cfg.environment : 'dev';
177
207
  if (environment !== 'dev') {
@@ -181,6 +211,14 @@ function assertDevEnvironmentForDataplane(cfg) {
181
211
  }
182
212
  }
183
213
 
214
+ async function computeDataplaneRunOverrides(options) {
215
+ const runEnvKey = options.runEnvKey ? String(options.runEnvKey).trim().toLowerCase() : undefined;
216
+ const developerIdRaw = await config.getDeveloperId();
217
+ const developerIdNum = typeof developerIdRaw === 'string' ? parseInt(developerIdRaw, 10) : developerIdRaw;
218
+ const portOverride = computeDataplanePortOverride(runEnvKey, developerIdNum);
219
+ return { runEnvKey, portOverride };
220
+ }
221
+
184
222
  /**
185
223
  * Handle up-dataplane command: ensure logged in, environment dev, ensure dataplane,
186
224
  * register or rotate (if already registered), deploy (send manifest to controller),
@@ -199,17 +237,11 @@ function assertDevEnvironmentForDataplane(cfg) {
199
237
  async function handleUpDataplane(options = {}) {
200
238
  logger.log(chalk.blue('Starting up-dataplane (register/rotate, deploy, then run dataplane locally)...\n'));
201
239
 
202
- if (options.skipInfraCheck !== true) {
203
- await assertDevInfraUp();
204
- }
205
-
206
- const controllerUrl = await resolveControllerUrlWithHealthCheck();
207
- const environmentKey = await resolveEnvironment();
208
- const authConfig = await checkAuthentication(controllerUrl, environmentKey, { throwOnFailure: true });
209
-
210
- const cfg = await config.getConfig();
211
- assertDevEnvironmentForDataplane(cfg);
212
- logger.log(formatSuccessLine('Logged in and environment is dev'));
240
+ const environmentKey =
241
+ options && options.envKey
242
+ ? String(options.envKey).trim().toLowerCase()
243
+ : await resolveEnvironment();
244
+ const { controllerUrl, authConfig } = await resolveUpDataplaneAuthContext(options, environmentKey);
213
245
 
214
246
  await ensureAppFromTemplate('dataplane');
215
247
  // If envOutputPath target folder does not exist, set envOutputPath to null
@@ -223,10 +255,15 @@ async function handleUpDataplane(options = {}) {
223
255
 
224
256
  await registerOrRotateDataplane(options, controllerUrl, environmentKey, authConfig);
225
257
 
226
- await deployDataplaneToController(options);
258
+ await deployDataplaneToController({ ...options, envKey: environmentKey });
227
259
  logger.log('');
260
+
261
+ const { runEnvKey, portOverride } = await computeDataplaneRunOverrides(options);
262
+
228
263
  await app.runApp('dataplane', {
229
264
  skipEnvOutputPath: true,
265
+ env: runEnvKey,
266
+ port: portOverride,
230
267
  registry: options.registry || undefined,
231
268
  base: options.base !== false,
232
269
  skipManifestMetadataLine: true
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @fileoverview Upload publish preflight: auth resolve, CLI gate, target logging.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const logger = require('../utils/logger');
11
+ const { sectionTitle, headerKeyValue } = require('../utils/cli-test-layout-chalk');
12
+ const { resolveControllerUrl } = require('../utils/controller-url');
13
+ const { requireBearerForDataplanePipeline } = require('../utils/token-manager');
14
+ const { logDataplanePipelineWarning } = require('../utils/dataplane-pipeline-warning');
15
+ const { assertDataplaneCliVersionCompatible } = require('../utils/dataplane-cli-version-gate');
16
+
17
+ const SEP = chalk.gray('────────────────────────────────────────');
18
+
19
+ function logForcePublishWarning() {
20
+ logger.log(
21
+ chalk.yellow(
22
+ 'Warning: --force bypasses active-datasource schema replacement guards on publish. '
23
+ + 'Existing records and ABAC may be inconsistent; run validation/sync after upload.'
24
+ )
25
+ );
26
+ }
27
+
28
+ function logUploadTargetSection(environment, dataplaneUrl) {
29
+ logger.log('');
30
+ logger.log(sectionTitle('Target'));
31
+ logger.log(SEP);
32
+ logger.log(headerKeyValue('Environment:', environment));
33
+ logger.log(headerKeyValue('Dataplane:', dataplaneUrl));
34
+ logDataplanePipelineWarning();
35
+ }
36
+
37
+ /**
38
+ * Resolve dataplane auth and run upload preflight checks.
39
+ * @param {Function} resolveDataplaneAndAuth
40
+ * @param {Function} maybeRunVerboseServerValidation
41
+ * @param {string} systemKey
42
+ * @param {Object} options
43
+ * @param {Object} payload
44
+ * @returns {Promise<{ dataplaneUrl: string, authConfig: Object, environment: string }>}
45
+ */
46
+ async function resolveUploadPublishContext(
47
+ resolveDataplaneAndAuth,
48
+ maybeRunVerboseServerValidation,
49
+ systemKey,
50
+ options,
51
+ payload
52
+ ) {
53
+ const resolved = await resolveDataplaneAndAuth(systemKey, {
54
+ silent: options.silentResolve === true
55
+ });
56
+ requireBearerForDataplanePipeline(resolved.authConfig);
57
+ if (options.force === true) {
58
+ logForcePublishWarning();
59
+ }
60
+ const controllerUrl = await resolveControllerUrl();
61
+ await assertDataplaneCliVersionCompatible(resolved.dataplaneUrl, { controllerUrl });
62
+ if (options.minimal !== true) {
63
+ logUploadTargetSection(resolved.environment, resolved.dataplaneUrl);
64
+ }
65
+ if (options.verbose) {
66
+ await maybeRunVerboseServerValidation(resolved.dataplaneUrl, resolved.authConfig, payload);
67
+ }
68
+ return resolved;
69
+ }
70
+
71
+ module.exports = {
72
+ logForcePublishWarning,
73
+ logUploadTargetSection,
74
+ resolveUploadPublishContext
75
+ };