@aifabrix/builder 2.44.6 → 2.45.5

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 (257) hide show
  1. package/.cursor/rules/cli-layout.mdc +7 -3
  2. package/.cursor/rules/docs-rules.mdc +3 -1
  3. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  4. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  5. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  6. package/jest.projects.js +100 -1
  7. package/lib/api/agent-metadata-validation.api.js +93 -0
  8. package/lib/api/audit-api-helpers.js +68 -0
  9. package/lib/api/audit.api.js +119 -0
  10. package/lib/api/auth-cache.api.js +44 -0
  11. package/lib/api/certificates.api.js +4 -4
  12. package/lib/api/credential.api.js +2 -2
  13. package/lib/api/dataplane-health.api.js +137 -0
  14. package/lib/api/dataplane-sync.api.js +27 -0
  15. package/lib/api/datasources-core.api.js +21 -18
  16. package/lib/api/datasources-extended.api.js +22 -22
  17. package/lib/api/dimensions.api.js +3 -0
  18. package/lib/api/external-systems.api.js +13 -13
  19. package/lib/api/governance-scenarios.api.js +39 -0
  20. package/lib/api/groups.api.js +79 -0
  21. package/lib/api/index.js +45 -2
  22. package/lib/api/pipeline.api.js +4 -4
  23. package/lib/api/protection.api.js +157 -0
  24. package/lib/api/records-bulk.api.js +30 -0
  25. package/lib/api/records-search-parse.js +49 -0
  26. package/lib/api/records-search.api.js +29 -0
  27. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  28. package/lib/api/types/audit.types.js +72 -0
  29. package/lib/api/types/dataplane-health.types.js +27 -0
  30. package/lib/api/types/dimensions.types.js +2 -0
  31. package/lib/api/types/governance-scenarios.types.js +39 -0
  32. package/lib/api/types/protection.types.js +69 -0
  33. package/lib/api/types/records-bulk.types.js +35 -0
  34. package/lib/api/types/records-search.types.js +28 -0
  35. package/lib/api/user-groups.api.js +50 -0
  36. package/lib/api/users.api.js +95 -0
  37. package/lib/api/validation-run.api.js +3 -3
  38. package/lib/api/validation-runner.js +3 -3
  39. package/lib/api/wizard-platform.api.js +3 -3
  40. package/lib/api/wizard.api.js +21 -21
  41. package/lib/app/deploy.js +34 -19
  42. package/lib/app/helpers.js +3 -3
  43. package/lib/app/index.js +3 -3
  44. package/lib/app/register.js +7 -6
  45. package/lib/app/restart-display.js +52 -21
  46. package/lib/app/rotate-secret.js +7 -6
  47. package/lib/app/run-helpers.js +15 -8
  48. package/lib/app/run.js +57 -9
  49. package/lib/app/show-display.js +7 -0
  50. package/lib/app/show.js +87 -5
  51. package/lib/build/index.js +9 -5
  52. package/lib/cli/index.js +4 -2
  53. package/lib/cli/infra-guided.js +62 -28
  54. package/lib/cli/installation-log-command.js +73 -0
  55. package/lib/cli/setup-app.help.js +50 -2
  56. package/lib/cli/setup-app.js +44 -25
  57. package/lib/cli/setup-app.test-commands.js +80 -21
  58. package/lib/cli/setup-auth.js +124 -52
  59. package/lib/cli/setup-external-system.js +37 -3
  60. package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
  61. package/lib/cli/setup-infra-up-platform-action.js +131 -0
  62. package/lib/cli/setup-infra.js +60 -119
  63. package/lib/cli/setup-platform.js +1 -1
  64. package/lib/cli/setup-utility-help-after.js +45 -0
  65. package/lib/cli/setup-utility-resolve.js +132 -0
  66. package/lib/cli/setup-utility.js +148 -116
  67. package/lib/commands/app-logs.js +81 -33
  68. package/lib/commands/auth-config.js +116 -18
  69. package/lib/commands/auth-status-dataplane-version.js +231 -0
  70. package/lib/commands/auth-status-display.js +94 -0
  71. package/lib/commands/auth-status.js +70 -6
  72. package/lib/commands/credential-push.js +10 -5
  73. package/lib/commands/datasource-load-export-cli.js +178 -0
  74. package/lib/commands/datasource-test-trust-cli.js +114 -0
  75. package/lib/commands/datasource-unified-test-cli.js +25 -17
  76. package/lib/commands/datasource-unified-test-cli.options.js +18 -3
  77. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  78. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  79. package/lib/commands/datasource.js +68 -1
  80. package/lib/commands/dimension-value.js +43 -13
  81. package/lib/commands/dimension.js +38 -7
  82. package/lib/commands/identity-apply-sync.js +131 -0
  83. package/lib/commands/identity-group-cli.js +146 -0
  84. package/lib/commands/identity-membership-role-cache.js +175 -0
  85. package/lib/commands/identity-shared.js +94 -0
  86. package/lib/commands/identity-user-cli.js +158 -0
  87. package/lib/commands/identity.js +43 -0
  88. package/lib/commands/login.js +46 -16
  89. package/lib/commands/protection-cli-leaves.js +286 -0
  90. package/lib/commands/protection.js +50 -0
  91. package/lib/commands/repair.js +13 -3
  92. package/lib/commands/setup-modes.js +19 -6
  93. package/lib/commands/setup-prompts.js +41 -8
  94. package/lib/commands/setup.js +114 -9
  95. package/lib/commands/teardown.js +54 -5
  96. package/lib/commands/test-e2e-external.js +40 -9
  97. package/lib/commands/test-governance-cli-options.js +47 -0
  98. package/lib/commands/test-governance-command-action.js +55 -0
  99. package/lib/commands/test-governance-external.js +88 -0
  100. package/lib/commands/test-trust-cli-options.js +32 -0
  101. package/lib/commands/test-trust-command-action.js +118 -0
  102. package/lib/commands/test-trust-external.js +127 -0
  103. package/lib/commands/up-common.js +48 -14
  104. package/lib/commands/up-dataplane.js +21 -18
  105. package/lib/commands/up-miso.js +12 -8
  106. package/lib/commands/upload.js +38 -15
  107. package/lib/commands/wizard-core.js +3 -0
  108. package/lib/core/audit-logger.js +1 -34
  109. package/lib/core/config-admin-email.js +56 -0
  110. package/lib/core/config-device-dataplane.js +185 -0
  111. package/lib/core/config-normalize.js +60 -0
  112. package/lib/core/config-registered-controller-urls.js +54 -0
  113. package/lib/core/config.js +33 -50
  114. package/lib/core/secrets-ensure-infra.js +1 -1
  115. package/lib/core/secrets-env-content.js +86 -90
  116. package/lib/core/secrets-env-declarative-expand.js +170 -0
  117. package/lib/core/secrets-env-write.js +2 -0
  118. package/lib/core/secrets-load.js +106 -102
  119. package/lib/datasource/agent-trust-debug-log.js +45 -0
  120. package/lib/datasource/agent-trust-fetch.js +115 -0
  121. package/lib/datasource/agent-trust-map.js +101 -0
  122. package/lib/datasource/agent-trust-mock.js +44 -0
  123. package/lib/datasource/agent-trust-run.js +93 -0
  124. package/lib/datasource/agent-trust-timeout.js +25 -0
  125. package/lib/datasource/audit-evidence-display.js +80 -0
  126. package/lib/datasource/audit-evidence-extract-debug.js +103 -0
  127. package/lib/datasource/audit-evidence-extract.js +177 -0
  128. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  129. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  130. package/lib/datasource/audit-evidence-poll.js +109 -0
  131. package/lib/datasource/audit-evidence-run.js +177 -0
  132. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  133. package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
  134. package/lib/datasource/audit-evidence-verify.js +108 -0
  135. package/lib/datasource/bulk-loader-run-batches.js +88 -0
  136. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  137. package/lib/datasource/bulk-loader-service.js +127 -0
  138. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  139. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  140. package/lib/datasource/datasource-exporter-service.js +144 -0
  141. package/lib/datasource/datasource-identifier.js +148 -0
  142. package/lib/datasource/datasource-load-export-context.js +92 -0
  143. package/lib/datasource/integration-context.js +6 -4
  144. package/lib/datasource/local-data-paths.js +145 -0
  145. package/lib/datasource/log-cleaner.js +241 -0
  146. package/lib/datasource/log-viewer.js +111 -6
  147. package/lib/datasource/record-file-parser.js +85 -0
  148. package/lib/datasource/record-mapper.js +129 -0
  149. package/lib/datasource/resolve-app.js +74 -55
  150. package/lib/datasource/test-e2e.js +26 -2
  151. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  152. package/lib/datasource/unified-validation-run.js +43 -17
  153. package/lib/datasource/validate.js +37 -20
  154. package/lib/external-system/deploy.js +5 -1
  155. package/lib/external-system/test-system-level.js +25 -4
  156. package/lib/external-system/test.js +3 -1
  157. package/lib/governance/governance-pack-loader.js +70 -0
  158. package/lib/governance/governance-run-display.js +119 -0
  159. package/lib/identity/identity-apply-core.js +108 -0
  160. package/lib/identity/identity-apply-phases.js +244 -0
  161. package/lib/identity/identity-apply-service.js +77 -0
  162. package/lib/identity/identity-csv-parser.js +114 -0
  163. package/lib/internal/fs-real-sync.js +29 -1
  164. package/lib/internal/node-fs.js +2 -0
  165. package/lib/protection/auth-context.js +45 -0
  166. package/lib/protection/convert-batch.js +90 -0
  167. package/lib/protection/load.js +41 -0
  168. package/lib/protection/paths.js +158 -0
  169. package/lib/protection/preflight-datasource-ready.js +46 -0
  170. package/lib/protection/protection-create-probe-lines.js +142 -0
  171. package/lib/protection/protection-create-probes.js +95 -0
  172. package/lib/protection/protection-create-scaffold.js +281 -0
  173. package/lib/protection/protection-display-helpers.js +445 -0
  174. package/lib/protection/protection-display.js +215 -0
  175. package/lib/protection/protection-preset-registry.js +97 -0
  176. package/lib/protection/report-exit.js +62 -0
  177. package/lib/protection/resolve.js +202 -0
  178. package/lib/protection/run-commands-validate.js +130 -0
  179. package/lib/protection/run-commands.js +216 -0
  180. package/lib/protection/run-protection-create-helpers.js +134 -0
  181. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  182. package/lib/protection/run-protection-create.js +191 -0
  183. package/lib/protection/scope.js +22 -0
  184. package/lib/protection/sync-after-upload.js +64 -0
  185. package/lib/protection/upload-batch.js +127 -0
  186. package/lib/protection/validate-batch.js +113 -0
  187. package/lib/protection/validate-local.js +65 -0
  188. package/lib/resolvers/dimension-file.js +29 -4
  189. package/lib/schema/application-schema.json +4 -0
  190. package/lib/schema/external-datasource.schema.json +47 -13
  191. package/lib/schema/flag-map-validation-run.json +2 -2
  192. package/lib/schema/infra.parameter.yaml +10 -0
  193. package/lib/schema/protection.schema.json +374 -0
  194. package/lib/schema/type/credential-field-registry.json +636 -0
  195. package/lib/schema/wizard-config.schema.json +1 -1
  196. package/lib/utils/agent-trust-run-display.js +231 -0
  197. package/lib/utils/agent-trust-run-exit.js +59 -0
  198. package/lib/utils/agent-trust-wait-ui.js +94 -0
  199. package/lib/utils/app-config-resolver.js +24 -1
  200. package/lib/utils/applications-config-defaults.js +206 -0
  201. package/lib/utils/auth-config-validator.js +2 -12
  202. package/lib/utils/bash-secret-env.js +1 -1
  203. package/lib/utils/cli-exit-codes.js +30 -0
  204. package/lib/utils/cli-sync-options.js +33 -0
  205. package/lib/utils/compose-generate-docker-compose.js +111 -6
  206. package/lib/utils/compose-generator.js +17 -8
  207. package/lib/utils/controller-url.js +50 -7
  208. package/lib/utils/credential-push-ui.js +90 -0
  209. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  210. package/lib/utils/dataplane-cli-version-help.js +74 -0
  211. package/lib/utils/datasource-export-display.js +137 -0
  212. package/lib/utils/datasource-load-display.js +174 -0
  213. package/lib/utils/datasource-load-export-ui.js +120 -0
  214. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  215. package/lib/utils/datasource-test-run-display.js +3 -3
  216. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  217. package/lib/utils/env-copy.js +99 -14
  218. package/lib/utils/env-template.js +5 -1
  219. package/lib/utils/health-check-url.js +18 -15
  220. package/lib/utils/health-check.js +7 -5
  221. package/lib/utils/help-builder.js +30 -24
  222. package/lib/utils/infra-optional-service-flags.js +69 -0
  223. package/lib/utils/installation-log-core.js +282 -0
  224. package/lib/utils/installation-log-record.js +237 -0
  225. package/lib/utils/installation-log.js +123 -0
  226. package/lib/utils/log-redaction.js +105 -0
  227. package/lib/utils/manifest-location.js +164 -0
  228. package/lib/utils/manifest-source-emit.js +184 -0
  229. package/lib/utils/paths.js +238 -89
  230. package/lib/utils/remote-secrets-loader.js +7 -1
  231. package/lib/utils/run-cli-flags.js +29 -0
  232. package/lib/utils/secrets-canonical.js +10 -3
  233. package/lib/utils/secrets-path.js +3 -4
  234. package/lib/utils/secrets-utils.js +20 -10
  235. package/lib/utils/semver-compare.js +127 -0
  236. package/lib/utils/system-builder-root.js +10 -2
  237. package/lib/utils/upload-pipeline-ui.js +91 -0
  238. package/lib/utils/url-declarative-public-base.js +80 -12
  239. package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
  240. package/lib/utils/url-declarative-resolve-build.js +24 -393
  241. package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
  242. package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
  243. package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
  244. package/lib/utils/url-declarative-resolve.js +47 -7
  245. package/lib/utils/url-declarative-runtime-base-path.js +21 -1
  246. package/lib/utils/urls-local-registry-scan.js +103 -0
  247. package/lib/utils/urls-local-registry.js +161 -90
  248. package/lib/utils/validation-poll-ui.js +14 -7
  249. package/lib/validation/wizard-config-validator.js +58 -19
  250. package/package.json +3 -1
  251. package/templates/applications/dataplane/application.yaml +4 -0
  252. package/templates/applications/dataplane/env.template +13 -1
  253. package/templates/applications/dataplane/rbac.yaml +4 -0
  254. package/templates/applications/miso-controller/application.yaml +2 -0
  255. package/templates/applications/miso-controller/env.template +27 -29
  256. package/templates/external-system/README.md.hbs +56 -8
  257. package/.npmrc.token +0 -1
@@ -24,6 +24,7 @@ const chalk = require('chalk');
24
24
  const ora = require('ora');
25
25
 
26
26
  const config = require('../core/config');
27
+ const installationLog = require('../utils/installation-log');
27
28
  const infra = require('../infrastructure');
28
29
  const pathsUtil = require('../utils/paths');
29
30
  const logger = require('../utils/logger');
@@ -193,6 +194,47 @@ function cleanFilesWithSpinner() {
193
194
  return result;
194
195
  }
195
196
 
197
+ async function appendTeardownAbortedLog(options) {
198
+ const t = new Date();
199
+ try {
200
+ await installationLog.appendInstallationRecord({
201
+ command: 'teardown',
202
+ outcome: 'aborted',
203
+ startedAt: t,
204
+ completedAt: t,
205
+ options
206
+ });
207
+ } catch {
208
+ // ignore
209
+ }
210
+ }
211
+
212
+ async function appendTeardownSuccessLog(options, startedAt) {
213
+ let cfg = {};
214
+ try {
215
+ cfg = await config.getConfig();
216
+ } catch {
217
+ cfg = {};
218
+ }
219
+ try {
220
+ await installationLog.appendInstallationRecord({
221
+ command: 'teardown',
222
+ outcome: 'success',
223
+ startedAt,
224
+ completedAt: new Date(),
225
+ options,
226
+ infra: { cfg, options: {} },
227
+ cleanup: { volumesRemoved: true, configPreserved: true },
228
+ configExtra: {
229
+ controllerUrl: await installationLog.resolveControllerUrlForLog(),
230
+ adminEmail: await installationLog.resolveAdminEmailPresence()
231
+ }
232
+ });
233
+ } catch {
234
+ // ignore
235
+ }
236
+ }
237
+
196
238
  /**
197
239
  * Run the teardown.
198
240
  *
@@ -208,15 +250,22 @@ async function handleTeardown(options = {}) {
208
250
 
209
251
  const ok = await confirmTeardown(assumeYes);
210
252
  if (!ok) {
253
+ await appendTeardownAbortedLog(options);
211
254
  logger.log(chalk.yellow('Aborted by user.'));
212
255
  return;
213
256
  }
214
- await stopInfraQuietly();
215
- const { removed, failed } = cleanFilesWithSpinner();
216
- const devStr = await buildDeveloperLabel();
217
- logTeardownFooter({ devStr, removedCount: removed.length, failedCount: failed.length });
218
257
 
219
- logger.log(formatSuccessParagraph('aifabrix teardown complete.'));
258
+ const startedAt = new Date();
259
+ try {
260
+ await stopInfraQuietly();
261
+ const { removed, failed } = cleanFilesWithSpinner();
262
+ const devStr = await buildDeveloperLabel();
263
+ logTeardownFooter({ devStr, removedCount: removed.length, failedCount: failed.length });
264
+
265
+ logger.log(formatSuccessParagraph('aifabrix teardown complete.'));
266
+ } finally {
267
+ await appendTeardownSuccessLog(options, startedAt);
268
+ }
220
269
  }
221
270
 
222
271
  module.exports = {
@@ -18,6 +18,9 @@ const { resolveApplicationConfigPath } = require('../utils/app-config-resolver')
18
18
  const { loadConfigFile } = require('../utils/config-format');
19
19
  const { discoverIntegrationFiles, buildEffectiveDatasourceFiles } = require('./repair-internal');
20
20
  const { runDatasourceTestE2E } = require('../datasource/test-e2e');
21
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
22
+ const { getConfig } = require('../core/config');
23
+ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
21
24
 
22
25
  /**
23
26
  * Derives datasource key from filename when file has no key (same logic as repair).
@@ -89,17 +92,18 @@ function getDatasourceKeys(appPath, configPath, variables, systemKey, systemPars
89
92
  * unless ``options.noSync`` is true.
90
93
  * @param {string} systemKey
91
94
  * @param {Object} options
92
- * @returns {Promise<void>}
95
+ * @returns {Promise<{ authConfig: Object, dataplaneUrl: string, environment?: string }|null>}
93
96
  */
94
97
  async function syncLocalIfRequested(systemKey, options) {
95
- if (options.noSync === true) return;
98
+ if (cliOptsSkipSync(options)) return null;
96
99
  logger.log(chalk.cyan('Syncing local config to dataplane…'));
97
100
  const { uploadExternalSystem } = require('./upload');
98
- await uploadExternalSystem(systemKey, {
101
+ const uploadCtx = await uploadExternalSystem(systemKey, {
99
102
  verbose: !!options.verbose,
100
103
  minimal: true
101
104
  });
102
105
  logger.log(formatSuccessLine('Sync complete'));
106
+ return uploadCtx && uploadCtx.dataplaneUrl && uploadCtx.authConfig ? uploadCtx : null;
103
107
  }
104
108
 
105
109
  /* eslint-disable max-lines-per-function, max-statements -- Load context, then loop over keys */
@@ -116,7 +120,12 @@ async function syncLocalIfRequested(systemKey, options) {
116
120
  * @param {boolean} [options.noSync] - When true, skip upload (E2E uses dataplane config already deployed)
117
121
  * @returns {Promise<{ success: boolean, results: Array<{ key: string, success: boolean, error?: string }> }>}
118
122
  */
119
- async function runTestE2EForExternalSystem(externalSystem, options = {}) {
123
+ /**
124
+ * Resolve integration folder, system key, and datasource keys for system-level tests.
125
+ * @param {string} externalSystem
126
+ * @returns {{ systemKey: string, keys: string[] }}
127
+ */
128
+ function resolveExternalIntegrationContext(externalSystem) {
120
129
  if (!externalSystem || typeof externalSystem !== 'string') {
121
130
  throw new Error('External system name is required');
122
131
  }
@@ -140,9 +149,9 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
140
149
  );
141
150
  const systemPath = path.join(appPath, systemFiles[0]);
142
151
  const systemParsed = loadConfigFile(systemPath);
143
- const systemKey = systemParsed.key ||
152
+ const systemKey =
153
+ systemParsed.key ||
144
154
  path.basename(systemFiles[0], path.extname(systemFiles[0])).replace(/-system$/, '');
145
-
146
155
  const keys = getDatasourceKeys(
147
156
  appPath,
148
157
  configPath,
@@ -151,12 +160,30 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
151
160
  systemParsed,
152
161
  datasourceFiles
153
162
  );
163
+ return { systemKey, keys };
164
+ }
165
+
166
+ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
167
+ const { systemKey, keys } = resolveExternalIntegrationContext(externalSystem);
154
168
  if (keys.length === 0) {
155
169
  logger.log(chalk.yellow(`No datasources found for ${externalSystem}. Add datasource files and run aifabrix repair.`));
156
170
  return { success: true, results: [] };
157
171
  }
158
172
 
159
- await syncLocalIfRequested(systemKey, options);
173
+ const uploadCtx = await syncLocalIfRequested(systemKey, options);
174
+
175
+ let authConfig;
176
+ let dataplaneUrl;
177
+ if (uploadCtx) {
178
+ ({ authConfig, dataplaneUrl } = uploadCtx);
179
+ } else {
180
+ const configObj = await getConfig();
181
+ ({ authConfig, dataplaneUrl } = await setupIntegrationTestAuth(
182
+ externalSystem,
183
+ { environment: options.env },
184
+ configObj
185
+ ));
186
+ }
160
187
 
161
188
  const results = [];
162
189
  const opts = {
@@ -164,7 +191,9 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
164
191
  environment: options.env,
165
192
  debug: options.debug,
166
193
  verbose: options.verbose,
167
- async: options.async !== false
194
+ async: options.async !== false,
195
+ authConfig,
196
+ dataplaneUrl
168
197
  };
169
198
  for (const key of keys) {
170
199
  try {
@@ -187,5 +216,7 @@ async function runTestE2EForExternalSystem(externalSystem, options = {}) {
187
216
 
188
217
  module.exports = {
189
218
  runTestE2EForExternalSystem,
190
- getDatasourceKeys
219
+ getDatasourceKeys,
220
+ resolveExternalIntegrationContext,
221
+ syncLocalIfRequested
191
222
  };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * @fileoverview Normalize test-governance Commander flags
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
10
+
11
+ /**
12
+ * @param {string[]} [raw]
13
+ * @param {string[]} [fallback]
14
+ * @returns {string[]|undefined}
15
+ */
16
+ function collectScenarioIds(raw, fallback) {
17
+ const list = Array.isArray(raw) && raw.length > 0 ? raw : fallback;
18
+ if (!list || list.length === 0) {
19
+ return undefined;
20
+ }
21
+ return list.map(id => String(id).trim()).filter(Boolean);
22
+ }
23
+
24
+ /**
25
+ * @param {Object} options
26
+ * @param {import('commander').Command} [cmd]
27
+ * @returns {Object}
28
+ */
29
+ function normalizeTestGovernanceCliOptions(options, cmd) {
30
+ const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
31
+ const has = flag => raw.includes(flag);
32
+ return {
33
+ ...options,
34
+ env: options.env || 'dev',
35
+ verbose: options.verbose === true || has('-v') || has('--verbose'),
36
+ json: options.json === true || has('--json'),
37
+ noSync: cliOptsSkipSync(options, cmd),
38
+ pack: options.pack,
39
+ app: options.app,
40
+ scenarioIds: collectScenarioIds(options.scenario)
41
+ };
42
+ }
43
+
44
+ module.exports = {
45
+ normalizeTestGovernanceCliOptions,
46
+ collectScenarioIds
47
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @fileoverview CLI action for `aifabrix test-governance` (plan 406)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { handleCommandError } = require('../utils/cli-utils');
10
+ const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
11
+ const { normalizeTestGovernanceCliOptions } = require('./test-governance-cli-options');
12
+ const {
13
+ displayGovernanceRunTTY,
14
+ printGovernanceRunJson,
15
+ exitCodeFromGovernanceSummary
16
+ } = require('../governance/governance-run-display');
17
+
18
+ /**
19
+ * @async
20
+ * @param {string} appName
21
+ * @param {Object} options
22
+ * @param {import('commander').Command} [cmd]
23
+ */
24
+ async function runTestGovernanceCommandAction(appName, options, cmd) {
25
+ const opts = normalizeTestGovernanceCliOptions(options, cmd);
26
+ const { result, packPath, systemKey } = await runTestGovernanceForExternalSystem(appName, opts);
27
+
28
+ if (opts.json) {
29
+ printGovernanceRunJson(result);
30
+ } else {
31
+ displayGovernanceRunTTY(systemKey, result, {
32
+ verbose: opts.verbose,
33
+ packPath
34
+ });
35
+ }
36
+
37
+ const exitCode = exitCodeFromGovernanceSummary(result.summary);
38
+ if (exitCode !== 0) {
39
+ process.exit(exitCode);
40
+ }
41
+ }
42
+
43
+ async function testGovernanceCommandHandler(appName, options, cmd) {
44
+ try {
45
+ await runTestGovernanceCommandAction(appName, options, cmd);
46
+ } catch (error) {
47
+ handleCommandError(error, 'test-governance');
48
+ process.exit(3);
49
+ }
50
+ }
51
+
52
+ module.exports = {
53
+ runTestGovernanceCommandAction,
54
+ testGovernanceCommandHandler
55
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * @fileoverview test-governance — run governance scenario pack via dataplane API
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 { cliOptsSkipSync } = require('../utils/cli-sync-options');
12
+ const { getConfig } = require('../core/config');
13
+ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
14
+ const { runGovernanceScenarios } = require('../api/governance-scenarios.api');
15
+ const {
16
+ resolveGovernancePackPath,
17
+ loadGovernancePackYaml
18
+ } = 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
+ }
38
+
39
+ /**
40
+ * @async
41
+ * @param {string} externalSystem
42
+ * @param {Object} options
43
+ * @returns {Promise<{ result: Object, packPath: string, systemKey: string }>}
44
+ */
45
+ async function runTestGovernanceForExternalSystem(externalSystem, options = {}) {
46
+ const pathsUtil = require('../utils/paths');
47
+ const appType = await pathsUtil.detectAppType(externalSystem).catch(() => null);
48
+ if (!appType || appType.baseDir !== 'integration') {
49
+ throw new Error(
50
+ 'test-governance applies to external integration folders only (integration/<systemKey>/).'
51
+ );
52
+ }
53
+
54
+ const systemKey = externalSystem;
55
+ const packPath = resolveGovernancePackPath(systemKey, {
56
+ pack: options.pack,
57
+ app: options.app
58
+ });
59
+ const pack = loadGovernancePackYaml(packPath);
60
+
61
+ const uploadCtx = await syncLocalIfRequested(systemKey, options);
62
+
63
+ let authConfig;
64
+ let dataplaneUrl;
65
+ if (uploadCtx) {
66
+ ({ authConfig, dataplaneUrl } = uploadCtx);
67
+ } else {
68
+ const configObj = await getConfig();
69
+ ({ authConfig, dataplaneUrl } = await setupIntegrationTestAuth(
70
+ externalSystem,
71
+ { environment: options.env },
72
+ configObj
73
+ ));
74
+ }
75
+
76
+ const body = {
77
+ systemKey,
78
+ pack,
79
+ scenarios: options.scenarioIds
80
+ };
81
+ const result = await runGovernanceScenarios(dataplaneUrl, authConfig, body);
82
+ return { result, packPath, systemKey };
83
+ }
84
+
85
+ module.exports = {
86
+ runTestGovernanceForExternalSystem,
87
+ syncLocalIfRequested
88
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @fileoverview Normalize test-trust Commander flags (defensive for -d/-v/--revalidate).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
8
+
9
+ /**
10
+ * @param {Object} options - Commander-parsed options
11
+ * @param {import('commander').Command} [cmd]
12
+ * @returns {Object}
13
+ */
14
+ function normalizeTestTrustCliOptions(options, cmd) {
15
+ const raw = cmd && Array.isArray(cmd.rawArgs) ? cmd.rawArgs : [];
16
+ const has = flag => raw.includes(flag);
17
+ return {
18
+ ...options,
19
+ debug: options.debug === true || has('-d') || has('--debug'),
20
+ verbose: options.verbose === true || has('-v') || has('--verbose'),
21
+ revalidate: options.revalidate === true || has('--revalidate'),
22
+ noSync: cliOptsSkipSync(options, cmd),
23
+ strict: options.strict === true || has('--strict'),
24
+ summary: options.summary === true || has('--summary'),
25
+ json: options.json === true || has('--json'),
26
+ warningsAsErrors: options.warningsAsErrors === true || has('--warnings-as-errors')
27
+ };
28
+ }
29
+
30
+ module.exports = {
31
+ normalizeTestTrustCliOptions
32
+ };
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @fileoverview CLI action for `aifabrix test-trust` (plan 143).
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 { handleCommandError } = require('../utils/cli-utils');
12
+ const { runTestTrustForExternalSystem } = require('./test-trust-external');
13
+ const {
14
+ displaySystemTrustRollupTTY,
15
+ displayAgentTrustRunTTY
16
+ } = require('../utils/agent-trust-run-display');
17
+ const { computeSystemExitCodeFromTrustRows } = require('../utils/agent-trust-run-exit');
18
+ const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-log');
19
+ const { normalizeTestTrustCliOptions } = require('./test-trust-cli-options');
20
+
21
+ /**
22
+ * @async
23
+ * @param {string} appName
24
+ * @param {Object} options
25
+ */
26
+ async function writeSystemTrustDebugLogs(appName, results, options) {
27
+ if (!options.debug) return;
28
+ logger.log('');
29
+ logger.log(chalk.gray('Debug logs:'));
30
+ for (const row of results) {
31
+ await writeTrustDebugLogAndPrint(appName, row.key, {
32
+ request: {
33
+ datasourceKey: row.key,
34
+ revalidate: options.revalidate === true,
35
+ noSync: options.noSync === true
36
+ },
37
+ response: row.trustRun,
38
+ error: row.error || null
39
+ });
40
+ }
41
+ }
42
+
43
+ function displaySystemTrustResults(systemKey, appName, results, options) {
44
+ if (options.json) {
45
+ logger.log(JSON.stringify(results, null, 2));
46
+ return;
47
+ }
48
+ if (options.summary) {
49
+ for (const row of results) {
50
+ const tr = row.trustRun;
51
+ const line = tr
52
+ ? `${row.key}: ${tr.trustDecision} (${tr.validationStatus})`
53
+ : `${row.key}: fail (${row.error || 'error'})`;
54
+ logger.log(line);
55
+ }
56
+ return;
57
+ }
58
+
59
+ const displayOpts = {
60
+ strict: options.strict === true,
61
+ showCache: options.verbose === true || options.revalidate === true
62
+ };
63
+ displaySystemTrustRollupTTY(systemKey || appName, results, displayOpts);
64
+
65
+ if (!options.verbose) return;
66
+
67
+ for (const row of results) {
68
+ if (!row.trustRun) continue;
69
+ displayAgentTrustRunTTY(row.trustRun, {
70
+ environment: options.env,
71
+ verbose: true,
72
+ noSync: options.noSync === true,
73
+ strict: options.strict === true
74
+ });
75
+ }
76
+ }
77
+
78
+ async function runTestTrustCommandAction(appName, options, cmd) {
79
+ const opts = normalizeTestTrustCliOptions(options, cmd);
80
+ const pathsUtil = require('../utils/paths');
81
+ const appType = await pathsUtil.detectAppType(appName).catch(() => null);
82
+ if (!appType || appType.baseDir !== 'integration') {
83
+ throw new Error(
84
+ 'test-trust applies to external integration folders only (integration/<systemKey>/).'
85
+ );
86
+ }
87
+ const { success, results, systemKey } = await runTestTrustForExternalSystem(appName, {
88
+ env: opts.env,
89
+ verbose: opts.verbose,
90
+ debug: opts.debug,
91
+ noSync: opts.noSync === true,
92
+ revalidate: opts.revalidate === true,
93
+ summary: opts.summary === true,
94
+ timeout: opts.timeout
95
+ });
96
+ displaySystemTrustResults(systemKey, appName, results, opts);
97
+ await writeSystemTrustDebugLogs(appName, results, opts);
98
+ const exitCode = computeSystemExitCodeFromTrustRows(results, {
99
+ warningsAsErrors: opts.warningsAsErrors === true,
100
+ strict: opts.strict === true
101
+ });
102
+ if (exitCode !== 0) process.exit(exitCode);
103
+ if (!success) process.exit(1);
104
+ }
105
+
106
+ async function testTrustCommandHandler(appName, options, cmd) {
107
+ try {
108
+ await runTestTrustCommandAction(appName, options, cmd);
109
+ } catch (error) {
110
+ handleCommandError(error, 'test-trust');
111
+ process.exit(3);
112
+ }
113
+ }
114
+
115
+ module.exports = {
116
+ runTestTrustCommandAction,
117
+ testTrustCommandHandler
118
+ };
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @fileoverview test-trust <systemKey> — semantic agent metadata validation for all datasources.
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 { cliOptsSkipSync } = require('../utils/cli-sync-options');
12
+ const { getConfig } = require('../core/config');
13
+ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
14
+ 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
+ }
33
+
34
+ function pushTrustResult(results, key, trustRun, apiError) {
35
+ const failed =
36
+ apiError ||
37
+ !trustRun ||
38
+ trustRun.trustDecision === 'notTrusted' ||
39
+ trustRun.validationStatus === 'failed';
40
+ results.push({
41
+ key,
42
+ success: !failed,
43
+ error: failed
44
+ ? apiError
45
+ ? apiError.message || String(apiError)
46
+ : trustRun.summary || 'Trust validation failed'
47
+ : undefined,
48
+ trustRun
49
+ });
50
+ }
51
+
52
+ /**
53
+ * @async
54
+ * @param {Object|null} uploadCtx
55
+ * @param {string} externalSystem
56
+ * @param {Object} options
57
+ * @returns {Promise<{ authConfig: Object, dataplaneUrl: string }>}
58
+ */
59
+ async function resolveTrustAuthContext(uploadCtx, externalSystem, options) {
60
+ if (uploadCtx) {
61
+ return { authConfig: uploadCtx.authConfig, dataplaneUrl: uploadCtx.dataplaneUrl };
62
+ }
63
+ const configObj = await getConfig();
64
+ return setupIntegrationTestAuth(externalSystem, { environment: options.env }, configObj);
65
+ }
66
+
67
+ /**
68
+ * @async
69
+ * @param {string[]} keys
70
+ * @param {Object} runOpts
71
+ * @param {Array<Object>} results
72
+ */
73
+ async function runTrustForDatasourceKeys(keys, runOpts, results) {
74
+ for (const key of keys) {
75
+ try {
76
+ const { trustRun, apiError } = await runDatasourceAgentTrust(key, runOpts);
77
+ pushTrustResult(results, key, trustRun, apiError);
78
+ } catch (err) {
79
+ results.push({ key, success: false, error: err.message, trustRun: null });
80
+ }
81
+ }
82
+ }
83
+
84
+ /**
85
+ * @async
86
+ * @param {string} externalSystem
87
+ * @param {Object} options
88
+ * @returns {Promise<{ success: boolean, results: Array<Object>, systemKey: string }>}
89
+ */
90
+ async function runTestTrustForExternalSystem(externalSystem, options = {}) {
91
+ const { systemKey, keys } = resolveExternalIntegrationContext(externalSystem);
92
+ if (keys.length === 0) {
93
+ logger.log(chalk.yellow(`No datasources found for ${externalSystem}.`));
94
+ return { success: true, results: [], systemKey };
95
+ }
96
+
97
+ const uploadCtx = await syncLocalIfRequested(systemKey, options);
98
+ if (options.revalidate === true) {
99
+ logger.log(chalk.cyan('Forcing revalidation (cache bypass) for each datasource…'));
100
+ }
101
+
102
+ const { authConfig, dataplaneUrl } = await resolveTrustAuthContext(
103
+ uploadCtx,
104
+ externalSystem,
105
+ options
106
+ );
107
+ const results = [];
108
+ await runTrustForDatasourceKeys(
109
+ keys,
110
+ {
111
+ app: externalSystem,
112
+ environment: options.env,
113
+ noSync: true,
114
+ revalidate: options.revalidate === true,
115
+ summary: options.summary === true,
116
+ timeout: options.timeout,
117
+ authConfig,
118
+ dataplaneUrl
119
+ },
120
+ results
121
+ );
122
+ return { success: results.every(r => r.success), results, systemKey };
123
+ }
124
+
125
+ module.exports = {
126
+ runTestTrustForExternalSystem
127
+ };