@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
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @fileoverview Upload sidecar follow-ups (governance packs, certification sync).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const logger = require('../utils/logger');
10
+ const { formatWarningLine } = require('../utils/cli-test-layout-chalk');
11
+ const { unwrapPublicationResult, isPublicationUnchanged } = require('../utils/external-system-readiness-core');
12
+ const { logUploadReadinessSummary } = require('../utils/external-system-readiness-display');
13
+ const { maybeSyncSystemCertificationFromDataplane } = require('../certification/sync-system-certification');
14
+ const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
15
+ const { isQuietMinimalSync } = require('../utils/upload-sync-options');
16
+
17
+ /**
18
+ * Sidecar follow-ups that are independent of pipeline publish hash (scenario packs, cert sync).
19
+ * @param {Object} ctx
20
+ * @returns {Promise<void>}
21
+ */
22
+ async function runUploadSidecarFollowups(ctx) {
23
+ const { systemKey, options, payload, dataplaneUrl, authConfig } = ctx;
24
+ const quietSidecar = isQuietMinimalSync(options);
25
+ const dsKeys = (payload.dataSources || []).map((ds) => ds && ds.key).filter(Boolean);
26
+ try {
27
+ const { uploadGovernanceScenarioPacks } = require('../lifecycle/scenario-upload');
28
+ await uploadGovernanceScenarioPacks(systemKey, dataplaneUrl, authConfig, { silent: quietSidecar });
29
+ } catch (err) {
30
+ if (!quietSidecar) {
31
+ logger.log(formatWarningLine(`Governance scenario upload skipped: ${err.message}`));
32
+ }
33
+ }
34
+ await maybeSyncSystemCertificationFromDataplane({
35
+ label: 'upload',
36
+ noCertSync: cliOptsSkipCertSync(options),
37
+ systemKey,
38
+ dataplaneUrl,
39
+ authConfig,
40
+ datasourceKeys: dsKeys,
41
+ silent: quietSidecar
42
+ });
43
+ }
44
+
45
+ /**
46
+ * @param {Object} ctx
47
+ * @param {Function} maybeRunUploadProbe
48
+ * @returns {Promise<void>}
49
+ */
50
+ async function handlePublicationAndFollowups(ctx, maybeRunUploadProbe) {
51
+ const {
52
+ systemKey,
53
+ options,
54
+ manifest,
55
+ payload,
56
+ environment,
57
+ dataplaneUrl,
58
+ authConfig,
59
+ rawRes
60
+ } = ctx;
61
+ const publication = unwrapPublicationResult(rawRes);
62
+ if (!publication) {
63
+ throw new Error(
64
+ 'Unexpected response from dataplane upload: missing publication result (uploadId/system/datasources).'
65
+ );
66
+ }
67
+ if (isPublicationUnchanged(publication)) {
68
+ await runUploadSidecarFollowups({ systemKey, options, payload, dataplaneUrl, authConfig });
69
+ return;
70
+ }
71
+ logUploadReadinessSummary({
72
+ environment,
73
+ dataplaneUrl,
74
+ systemKey,
75
+ publication,
76
+ manifest,
77
+ minimal: !!options.minimal,
78
+ willProbe: !!options.probe
79
+ });
80
+ if (options.probe) {
81
+ await maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, options.probeTimeout);
82
+ }
83
+ await runUploadSidecarFollowups({ systemKey, options, payload, dataplaneUrl, authConfig });
84
+ }
85
+
86
+ module.exports = {
87
+ runUploadSidecarFollowups,
88
+ handlePublicationAndFollowups
89
+ };
@@ -21,7 +21,7 @@ const logger = require('../utils/logger');
21
21
 
22
22
  const SEP = chalk.gray('────────────────────────────────────────');
23
23
  const { resolveControllerUrl } = require('../utils/controller-url');
24
- const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../utils/token-manager');
24
+ const { getDeploymentAuth } = require('../utils/token-manager');
25
25
  const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
26
26
  const { getIntegrationPath } = require('../utils/paths');
27
27
  const { pushCredentialSecrets } = require('../utils/credential-secrets-env');
@@ -36,22 +36,24 @@ const { validateExternalSystemComplete } = require('../validation/validate');
36
36
  const { displayValidationResults } = require('../validation/validate-display');
37
37
  const { generateControllerManifest } = require('../generator/external-controller-manifest');
38
38
  const {
39
- uploadApplicationViaPipeline,
40
39
  validatePipelineConfig,
41
40
  testSystemViaPipeline
42
41
  } = require('../api/pipeline.api');
42
+ const { uploadApplicationViaPipelineWithAuthRetry } = require('../utils/pipeline-upload-auth-retry');
43
43
  const { formatApiError } = require('../utils/api-error-handler');
44
- const { logDataplanePipelineWarning } = require('../utils/dataplane-pipeline-warning');
45
- const { unwrapPublicationResult, unwrapApiData } = require('../utils/external-system-readiness-core');
44
+ const { unwrapPublicationResult, unwrapApiData, isPublicationUnchanged } = require('../utils/external-system-readiness-core');
46
45
  const {
47
- logUploadReadinessSummary,
48
46
  logServerValidationWarnings,
49
47
  logProbeRuntimeBlock
50
48
  } = require('../utils/external-system-readiness-display');
51
- const { maybeSyncSystemCertificationFromDataplane } = require('../certification/sync-system-certification');
52
- const { cliOptsSkipCertSync } = require('../certification/cli-cert-sync-skip');
53
49
  const { maybeSyncOpenApiFilesForMcp } = require('./repair-openapi-sync');
54
- const { assertDataplaneCliVersionCompatible } = require('../utils/dataplane-cli-version-gate');
50
+ const { resolveUploadPublishContext } = require('./upload-publish-context');
51
+ const { syncDeployJsonFromSources } = require('../external-system/sync-deploy-manifest');
52
+ const { isQuietMinimalSync } = require('../utils/upload-sync-options');
53
+ const {
54
+ runUploadSidecarFollowups,
55
+ handlePublicationAndFollowups
56
+ } = require('./upload-sidecar-followups');
55
57
 
56
58
  /**
57
59
  * Validates system-key format (same as download).
@@ -73,13 +75,22 @@ function validateSystemKeyFormat(systemKey) {
73
75
  * @param {Object} manifest - Controller manifest from generateControllerManifest
74
76
  * @returns {Object} { version, application, dataSources, status: "draft" }
75
77
  */
76
- function buildUploadPayload(manifest) {
77
- return {
78
+ /**
79
+ * @param {Object} manifest - Controller manifest from generateControllerManifest
80
+ * @param {{ force?: boolean }} [opts]
81
+ * @returns {Object}
82
+ */
83
+ function buildUploadPayload(manifest, opts = {}) {
84
+ const payload = {
78
85
  version: manifest.version || '1.0.0',
79
86
  application: manifest.system,
80
87
  dataSources: manifest.dataSources || [],
81
88
  status: 'draft'
82
89
  };
90
+ if (opts.force === true) {
91
+ payload.force = true;
92
+ }
93
+ return payload;
83
94
  }
84
95
 
85
96
  /**
@@ -113,11 +124,15 @@ async function resolveDataplaneAndAuth(systemKey, opts = {}) {
113
124
  * @param {Object} payload - { version, application, dataSources, status: "draft" }
114
125
  * @returns {Promise<Object>} Raw API response envelope
115
126
  */
116
- async function runUploadValidatePublish(dataplaneUrl, authConfig, payload) {
117
- const res = await uploadApplicationViaPipeline(dataplaneUrl, authConfig, payload);
127
+ async function runUploadValidatePublish(dataplaneUrl, authConfig, payload, systemKey) {
128
+ const res = await uploadApplicationViaPipelineWithAuthRetry(
129
+ dataplaneUrl,
130
+ authConfig,
131
+ payload,
132
+ systemKey
133
+ );
118
134
  if (res?.success === false) {
119
- const msg = formatApiError(res, dataplaneUrl);
120
- throw new Error(msg);
135
+ throw new Error(formatApiError(res, dataplaneUrl));
121
136
  }
122
137
  return res;
123
138
  }
@@ -269,18 +284,22 @@ async function maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, probeTim
269
284
 
270
285
  /**
271
286
  * Local validation, manifest, payload, and configuration resolution.
272
- * Does not write *-deploy.json; run `aifabrix json <systemKey>` to regenerate the deployment manifest from sources.
287
+ * Regenerates integration/<systemKey>/<systemKey>-deploy.json from sources (same as `aifabrix json`).
273
288
  *
274
289
  * @param {string} systemKey
275
290
  * @param {{ dryRun?: boolean }} [_opts] - Reserved for callers (e.g. dry-run); manifest is always built from current disk files
276
291
  * @returns {Promise<{ manifest: Object, payload: Object }>}
277
292
  */
278
- async function buildValidatedUploadManifestPayload(systemKey, _opts = {}) {
293
+ async function buildValidatedUploadManifestPayload(systemKey, opts = {}) {
294
+ const quiet = opts.minimal === true || opts.quiet === true;
279
295
  const validationResult = await validateExternalSystemComplete(systemKey, { type: 'external' });
280
296
  throwIfValidationFailed(validationResult);
281
- logger.log(formatSuccessLine('Local validation passed'));
297
+ if (!quiet) {
298
+ logger.log(formatSuccessLine('Local validation passed'));
299
+ }
300
+ await syncDeployJsonFromSources(systemKey, { quiet });
282
301
  const manifest = await generateControllerManifest(systemKey, { type: 'external' });
283
- const payload = buildUploadPayload(manifest);
302
+ const payload = buildUploadPayload(manifest, { force: opts.force === true });
284
303
  await resolvePayloadConfiguration(systemKey, payload);
285
304
  return { manifest, payload };
286
305
  }
@@ -311,58 +330,6 @@ async function logAndSyncLocalOpenApiForUpload(systemKey, manifest) {
311
330
  }
312
331
  }
313
332
 
314
- /**
315
- * @param {Object} ctx
316
- * @param {string} ctx.systemKey
317
- * @param {Object} ctx.options
318
- * @param {Object} ctx.manifest
319
- * @param {Object} ctx.payload
320
- * @param {string} ctx.environment
321
- * @param {string} ctx.dataplaneUrl
322
- * @param {Object} ctx.authConfig
323
- * @param {Object} ctx.rawRes
324
- * @returns {Promise<void>}
325
- */
326
- async function handlePublicationAndFollowups(ctx) {
327
- const {
328
- systemKey,
329
- options,
330
- manifest,
331
- payload,
332
- environment,
333
- dataplaneUrl,
334
- authConfig,
335
- rawRes
336
- } = ctx;
337
- const publication = unwrapPublicationResult(rawRes);
338
- if (!publication) {
339
- throw new Error(
340
- 'Unexpected response from dataplane upload: missing publication result (uploadId/system/datasources).'
341
- );
342
- }
343
- logUploadReadinessSummary({
344
- environment,
345
- dataplaneUrl,
346
- systemKey,
347
- publication,
348
- manifest,
349
- minimal: !!options.minimal,
350
- willProbe: !!options.probe
351
- });
352
- if (options.probe) {
353
- await maybeRunUploadProbe(dataplaneUrl, systemKey, authConfig, options.probeTimeout);
354
- }
355
- const dsKeys = (payload.dataSources || []).map((ds) => ds && ds.key).filter(Boolean);
356
- await maybeSyncSystemCertificationFromDataplane({
357
- label: 'upload',
358
- noCertSync: cliOptsSkipCertSync(options),
359
- systemKey,
360
- dataplaneUrl,
361
- authConfig,
362
- datasourceKeys: dsKeys
363
- });
364
- }
365
-
366
333
  /**
367
334
  * Upload path after dry-run check.
368
335
  * @param {string} systemKey
@@ -371,45 +338,55 @@ async function handlePublicationAndFollowups(ctx) {
371
338
  * @param {Object} payload
372
339
  */
373
340
  async function runUploadPublishAndSummary(systemKey, options, manifest, payload) {
374
- const { dataplaneUrl, authConfig, environment } = await resolveDataplaneAndAuth(systemKey, {
375
- silent: options.silentResolve === true
376
- });
377
- requireBearerForDataplanePipeline(authConfig);
378
- const controllerUrl = await resolveControllerUrl();
379
- // Plan 142.0: gate dataplane API entrypoints by the dataplane-advertised minimum Builder CLI version.
380
- await assertDataplaneCliVersionCompatible(dataplaneUrl, { controllerUrl });
381
- logger.log('');
382
- logger.log(sectionTitle('Target'));
383
- logger.log(SEP);
384
- logger.log(headerKeyValue('Environment:', environment));
385
- logger.log(headerKeyValue('Dataplane:', dataplaneUrl));
386
- logDataplanePipelineWarning();
387
- if (options.verbose) {
388
- await maybeRunVerboseServerValidation(dataplaneUrl, authConfig, payload);
341
+ const { dataplaneUrl, authConfig, environment } = await resolveUploadPublishContext(
342
+ resolveDataplaneAndAuth,
343
+ maybeRunVerboseServerValidation,
344
+ systemKey,
345
+ options,
346
+ payload
347
+ );
348
+ const rawRes = await runWithUploadPipelineSpinner(
349
+ async() => runUploadValidatePublish(dataplaneUrl, authConfig, payload, systemKey),
350
+ {
351
+ systemKey,
352
+ json: options.json === true,
353
+ syncMode: options.syncMode === true,
354
+ suppressPipelineSpinner: options.suppressPipelineSpinner === true
355
+ }
356
+ );
357
+ const publication = unwrapPublicationResult(rawRes);
358
+ if (isPublicationUnchanged(publication)) {
359
+ if (!isQuietMinimalSync(options)) {
360
+ logger.log(formatSuccessLine('Config unchanged on dataplane — upload skipped.'));
361
+ }
362
+ await runUploadSidecarFollowups({
363
+ systemKey,
364
+ options,
365
+ payload,
366
+ dataplaneUrl,
367
+ authConfig
368
+ });
369
+ return { dataplaneUrl, authConfig, environment, uploadSkipped: true };
389
370
  }
371
+
390
372
  await pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload, {
391
373
  json: options.json === true
392
374
  });
393
-
394
- const rawRes = await runWithUploadPipelineSpinner(
395
- async() => {
396
- const res = await runUploadValidatePublish(dataplaneUrl, authConfig, payload);
397
- await logAndSyncLocalOpenApiForUpload(systemKey, manifest);
398
- return res;
375
+ await logAndSyncLocalOpenApiForUpload(systemKey, manifest);
376
+ await handlePublicationAndFollowups(
377
+ {
378
+ systemKey,
379
+ options,
380
+ manifest,
381
+ payload,
382
+ environment,
383
+ dataplaneUrl,
384
+ authConfig,
385
+ rawRes
399
386
  },
400
- { systemKey, json: options.json === true }
387
+ maybeRunUploadProbe
401
388
  );
402
- await handlePublicationAndFollowups({
403
- systemKey,
404
- options,
405
- manifest,
406
- payload,
407
- environment,
408
- dataplaneUrl,
409
- authConfig,
410
- rawRes
411
- });
412
- return { dataplaneUrl, authConfig, environment };
389
+ return { dataplaneUrl, authConfig, environment, uploadSkipped: false };
413
390
  }
414
391
 
415
392
  /**
@@ -426,12 +403,17 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
426
403
  */
427
404
  async function uploadExternalSystem(systemKey, options = {}) {
428
405
  validateSystemKeyFormat(systemKey);
429
- logger.log('');
430
- logger.log(sectionTitle('Upload external system'));
431
- logger.log(SEP);
432
- logger.log(headerKeyValue('System:', systemKey));
406
+ const minimal = options.minimal === true;
407
+ if (!minimal) {
408
+ logger.log('');
409
+ logger.log(sectionTitle('Upload external system'));
410
+ logger.log(SEP);
411
+ logger.log(headerKeyValue('System:', systemKey));
412
+ }
433
413
  const { manifest, payload } = await buildValidatedUploadManifestPayload(systemKey, {
434
- dryRun: !!options.dryRun
414
+ dryRun: !!options.dryRun,
415
+ force: options.force === true,
416
+ minimal
435
417
  });
436
418
  if (options.dryRun) {
437
419
  logger.log(chalk.yellow('Dry run: would upload payload (no API calls).'));
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview verify-governance — sync, generate, verify (424.0 dataplane-first).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const { runGovernanceGenerateForExternalSystem } = require('./governance-generate-external');
8
+ const { runVerifyGovernanceForExternalSystem } = require('./verify-governance-external');
9
+ const {
10
+ buildSubjectsFromOptions,
11
+ resolveGovernanceIntegrationContext
12
+ } = require('./governance-cli-shared');
13
+
14
+ /**
15
+ * @async
16
+ * @param {string} systemKey
17
+ * @param {Object} options
18
+ * @returns {Promise<Object>}
19
+ */
20
+ async function runVerifyGovernanceCombined(systemKey, options = {}) {
21
+ if (options.pack) {
22
+ return runVerifyGovernanceForExternalSystem(systemKey, options);
23
+ }
24
+
25
+ const subjects = buildSubjectsFromOptions(options);
26
+ if (subjects.length === 0) {
27
+ throw new Error(
28
+ 'At least one --subject-user-id or --subject-email is required for verify-governance'
29
+ );
30
+ }
31
+
32
+ const { resolvedKey, authConfig, dataplaneUrl } = await resolveGovernanceIntegrationContext(
33
+ systemKey,
34
+ options
35
+ );
36
+
37
+ const pipelineOpts = {
38
+ ...options,
39
+ noSync: true,
40
+ authConfig,
41
+ dataplaneUrl
42
+ };
43
+
44
+ const generateResult = await runGovernanceGenerateForExternalSystem(
45
+ resolvedKey,
46
+ pipelineOpts
47
+ );
48
+
49
+ const verifyResult = await runVerifyGovernanceForExternalSystem(resolvedKey, pipelineOpts);
50
+
51
+ return {
52
+ ...verifyResult,
53
+ command: 'verify-governance',
54
+ generated: generateResult.generated,
55
+ generateResults: generateResult.results
56
+ };
57
+ }
58
+
59
+ module.exports = {
60
+ runVerifyGovernanceCombined
61
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview CLI action for `aifabrix verify-governance` (plan 150.0 / 424.0).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const logger = require('../utils/logger');
8
+ const { handleCommandError } = require('../utils/cli-utils');
9
+ const { runVerifyGovernanceCombined } = require('./verify-governance-combined-external');
10
+ const { normalizeTestGovernanceCliOptions } = require('./test-governance-cli-options');
11
+ const { displayVerifyGovernanceTTY } = require('../lifecycle/report-display');
12
+ const { exitCodeFromVerdict } = require('../lifecycle/exit-codes');
13
+ const { buildJsonEnvelope } = require('../lifecycle/json-envelope');
14
+ const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
15
+
16
+ /**
17
+ * @param {Object} options
18
+ * @param {import('commander').Command} [cmd]
19
+ * @returns {Object}
20
+ */
21
+ function normalizeVerifyGovernanceCliOptions(options, cmd) {
22
+ const base = normalizeTestGovernanceCliOptions(options, cmd);
23
+ return {
24
+ ...base,
25
+ certificationProfile: options.certificationProfile || 'bronze',
26
+ subjectUserIds: options.subjectUserId || [],
27
+ subjectEmails: options.subjectEmail || [],
28
+ maxSamplesPerPartition: options.maxSamplesPerPartition
29
+ };
30
+ }
31
+
32
+ async function runVerifyGovernanceCommandAction(appName, options, cmd) {
33
+ const opts = normalizeVerifyGovernanceCliOptions(options, cmd);
34
+ const result = await runVerifyGovernanceCombined(appName, opts);
35
+
36
+ if (opts.json) {
37
+ logger.log(JSON.stringify(buildJsonEnvelope(result, opts.verbose), null, 2));
38
+ } else {
39
+ if (opts.verbose && !opts.pack && typeof result.generated === 'number' && result.generated > 0) {
40
+ logger.log(formatSuccessLine(`Generated packs for ${result.generated} datasource(s)`));
41
+ }
42
+ displayVerifyGovernanceTTY(result.systemKey, result, { details: opts.verbose });
43
+ }
44
+
45
+ const exitCode = exitCodeFromVerdict(result.verdict);
46
+ if (exitCode !== 0) {
47
+ process.exit(exitCode);
48
+ }
49
+ }
50
+
51
+ async function verifyGovernanceCommandHandler(appName, options, cmd) {
52
+ try {
53
+ await runVerifyGovernanceCommandAction(appName, options, cmd);
54
+ } catch (error) {
55
+ handleCommandError(error, 'verify-governance');
56
+ process.exit(3);
57
+ }
58
+ }
59
+
60
+ module.exports = {
61
+ runVerifyGovernanceCommandAction,
62
+ verifyGovernanceCommandHandler,
63
+ normalizeVerifyGovernanceCliOptions
64
+ };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * @fileoverview verify-governance DB pack path (plan 150.0).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const {
8
+ resolveExternalIntegrationContext,
9
+ syncLocalIfRequested
10
+ } = require('./test-e2e-external');
11
+ const { runDatasourceGovernanceScenarios, getDatasourceGovernancePack } = require('../api/governance-scenario-pack.api');
12
+ const { resolveIntegrationAuth } = require('../external-system/integration-auth-context');
13
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
14
+ const { VERDICT } = require('../lifecycle/product-model');
15
+ const { runWithVerifyStepProgress } = require('../lifecycle/verify-step-progress');
16
+
17
+ /**
18
+ * @param {Object} options
19
+ * @param {Object|null} uploadCtx
20
+ */
21
+ function attachUploadAuthToOptions(options, uploadCtx) {
22
+ if (!uploadCtx?.authConfig || !uploadCtx?.dataplaneUrl) {
23
+ return;
24
+ }
25
+ options.authConfig = uploadCtx.authConfig;
26
+ options.dataplaneUrl = uploadCtx.dataplaneUrl;
27
+ options.silentResolve = true;
28
+ }
29
+
30
+ /**
31
+ * @async
32
+ * @param {string[]} keys
33
+ * @param {Object} ctx
34
+ * @param {{ setLabel?: (label: string) => void }} [progress]
35
+ * @returns {Promise<Array>}
36
+ */
37
+ async function runGovernanceForDatasourceKeys(keys, ctx, progress = {}) {
38
+ const rows = [];
39
+ for (let index = 0; index < keys.length; index += 1) {
40
+ const key = keys[index];
41
+ if (typeof progress.setLabel === 'function') {
42
+ progress.setLabel(`Running governance scenarios: ${key} (${index + 1}/${keys.length})`);
43
+ }
44
+ try {
45
+ const packRow = await getDatasourceGovernancePack(ctx.dataplaneUrl, ctx.authConfig, key);
46
+ if (!packRow || !packRow.pack) {
47
+ continue;
48
+ }
49
+ const result = await runDatasourceGovernanceScenarios(ctx.dataplaneUrl, ctx.authConfig, key);
50
+ const summary = result.summary || {};
51
+ rows.push({
52
+ datasourceKey: key,
53
+ verdict: summary.failed > 0 ? VERDICT.FAILED : VERDICT.VERIFIED,
54
+ scenarios: { passed: summary.passed || 0, total: summary.total || 0 },
55
+ policyCoveragePercent: result.policyCoveragePercent ?? 100,
56
+ dimensionCoveragePercent: result.dimensionCoveragePercent ?? 100,
57
+ packDocument: packRow.pack,
58
+ result
59
+ });
60
+ } catch (err) {
61
+ rows.push({
62
+ datasourceKey: key,
63
+ verdict: VERDICT.FAILED,
64
+ error: err.message,
65
+ scenarios: { passed: 0, total: 0 }
66
+ });
67
+ }
68
+ }
69
+ return rows;
70
+ }
71
+
72
+ /**
73
+ * @async
74
+ * @param {string} systemKey
75
+ * @param {Object} options
76
+ * @returns {Promise<Object>}
77
+ */
78
+ async function runVerifyGovernanceFromDbPacks(systemKey, options) {
79
+ const { systemKey: resolvedKey, keys } = resolveExternalIntegrationContext(systemKey);
80
+ if (keys.length === 0) {
81
+ return { resolvedKey, datasourceRows: [] };
82
+ }
83
+
84
+ if (!cliOptsSkipSync(options)) {
85
+ const uploadCtx = await syncLocalIfRequested(resolvedKey, options);
86
+ attachUploadAuthToOptions(options, uploadCtx);
87
+ }
88
+
89
+ const { authConfig, dataplaneUrl } = await resolveIntegrationAuth(resolvedKey, options);
90
+ const datasourceRows = await runWithVerifyStepProgress(
91
+ 'Running governance scenarios',
92
+ async(progress) =>
93
+ runGovernanceForDatasourceKeys(keys, { authConfig, dataplaneUrl }, progress),
94
+ options
95
+ );
96
+ return { resolvedKey, datasourceRows };
97
+ }
98
+
99
+ module.exports = {
100
+ runGovernanceForDatasourceKeys,
101
+ runVerifyGovernanceFromDbPacks
102
+ };
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @fileoverview verify-governance orchestration — DB scenario packs per datasource (plan 150.0).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
10
+ const { runVerifyGovernanceFromDbPacks } = require('./verify-governance-db');
11
+ const { VERDICT, verdictFromPassed } = require('../lifecycle/product-model');
12
+ const {
13
+ sumEnforcementScenarios,
14
+ aggregateCoverage,
15
+ buildPackOverrideResult
16
+ } = require('./verify-governance-result-builders');
17
+
18
+ /**
19
+ * @param {Array<Object>} rows
20
+ * @returns {{ passed: number, total: number }}
21
+ */
22
+ function buildDbPackResult(resolvedKey, datasourceRows) {
23
+ const allVerified = datasourceRows.every(r => r.verdict === VERDICT.VERIFIED);
24
+ const coverage = aggregateCoverage(datasourceRows);
25
+ return {
26
+ systemKey: resolvedKey,
27
+ command: 'verify-governance',
28
+ verdict: verdictFromPassed(allVerified),
29
+ policyCoveragePercent: coverage.policy ?? (allVerified ? 100 : 0),
30
+ dimensionCoveragePercent: coverage.dimension ?? (allVerified ? 100 : 0),
31
+ enforcementScenarios: sumEnforcementScenarios(datasourceRows),
32
+ datasourceRows
33
+ };
34
+ }
35
+
36
+ /**
37
+ * @async
38
+ * @param {string} systemKey
39
+ * @param {Object} options
40
+ * @returns {Promise<Object>}
41
+ */
42
+ async function runVerifyGovernanceForExternalSystem(systemKey, options = {}) {
43
+ const pathsUtil = require('../utils/paths');
44
+ const appType = await pathsUtil.detectAppType(systemKey).catch(() => null);
45
+ if (!appType || appType.baseDir !== 'integration') {
46
+ throw new Error(
47
+ 'verify-governance applies to external integration folders only (integration/<systemKey>/).'
48
+ );
49
+ }
50
+
51
+ if (options.pack) {
52
+ const runPayload = await runTestGovernanceForExternalSystem(systemKey, options);
53
+ return buildPackOverrideResult(systemKey, runPayload);
54
+ }
55
+
56
+ const { resolvedKey, datasourceRows } = await runVerifyGovernanceFromDbPacks(systemKey, options);
57
+ if (datasourceRows.length === 0) {
58
+ return {
59
+ systemKey: resolvedKey,
60
+ command: 'verify-governance',
61
+ verdict: VERDICT.FAILED,
62
+ policyCoveragePercent: 0,
63
+ dimensionCoveragePercent: 0,
64
+ enforcementScenarios: { passed: 0, total: 0 },
65
+ datasourceRows: []
66
+ };
67
+ }
68
+
69
+ return buildDbPackResult(resolvedKey, datasourceRows);
70
+ }
71
+
72
+ module.exports = {
73
+ runVerifyGovernanceForExternalSystem,
74
+ buildPackOverrideResult,
75
+ sumEnforcementScenarios,
76
+ aggregateCoverage
77
+ };