@aifabrix/builder 2.45.0 → 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 (180) hide show
  1. package/.cursor/rules/docs-rules.mdc +3 -1
  2. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  3. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  4. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  5. package/jest.projects.js +44 -1
  6. package/lib/api/agent-metadata-validation.api.js +93 -0
  7. package/lib/api/audit-api-helpers.js +68 -0
  8. package/lib/api/audit.api.js +119 -0
  9. package/lib/api/auth-cache.api.js +44 -0
  10. package/lib/api/certificates.api.js +4 -4
  11. package/lib/api/credential.api.js +2 -2
  12. package/lib/api/dataplane-health.api.js +137 -0
  13. package/lib/api/dataplane-sync.api.js +27 -0
  14. package/lib/api/datasources-core.api.js +21 -18
  15. package/lib/api/datasources-extended.api.js +22 -22
  16. package/lib/api/dimensions.api.js +3 -0
  17. package/lib/api/external-systems.api.js +13 -13
  18. package/lib/api/governance-scenarios.api.js +39 -0
  19. package/lib/api/groups.api.js +79 -0
  20. package/lib/api/index.js +45 -2
  21. package/lib/api/pipeline.api.js +4 -4
  22. package/lib/api/protection.api.js +157 -0
  23. package/lib/api/records-bulk.api.js +30 -0
  24. package/lib/api/records-search-parse.js +49 -0
  25. package/lib/api/records-search.api.js +29 -0
  26. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  27. package/lib/api/types/audit.types.js +72 -0
  28. package/lib/api/types/dataplane-health.types.js +27 -0
  29. package/lib/api/types/dimensions.types.js +2 -0
  30. package/lib/api/types/governance-scenarios.types.js +39 -0
  31. package/lib/api/types/protection.types.js +69 -0
  32. package/lib/api/types/records-bulk.types.js +35 -0
  33. package/lib/api/types/records-search.types.js +28 -0
  34. package/lib/api/user-groups.api.js +50 -0
  35. package/lib/api/users.api.js +95 -0
  36. package/lib/api/validation-run.api.js +3 -3
  37. package/lib/api/validation-runner.js +3 -3
  38. package/lib/api/wizard-platform.api.js +3 -3
  39. package/lib/api/wizard.api.js +21 -21
  40. package/lib/app/deploy.js +34 -19
  41. package/lib/cli/index.js +4 -2
  42. package/lib/cli/infra-guided.js +22 -3
  43. package/lib/cli/setup-app.help.js +50 -2
  44. package/lib/cli/setup-app.js +33 -24
  45. package/lib/cli/setup-app.test-commands.js +80 -21
  46. package/lib/cli/setup-auth.js +30 -3
  47. package/lib/cli/setup-external-system.js +37 -3
  48. package/lib/cli/setup-utility-help-after.js +45 -0
  49. package/lib/cli/setup-utility-resolve.js +2 -2
  50. package/lib/cli/setup-utility.js +99 -81
  51. package/lib/commands/auth-status-dataplane-version.js +231 -0
  52. package/lib/commands/auth-status-display.js +94 -0
  53. package/lib/commands/auth-status.js +70 -6
  54. package/lib/commands/credential-push.js +10 -5
  55. package/lib/commands/datasource-load-export-cli.js +178 -0
  56. package/lib/commands/datasource-test-trust-cli.js +114 -0
  57. package/lib/commands/datasource-unified-test-cli.js +25 -17
  58. package/lib/commands/datasource-unified-test-cli.options.js +18 -3
  59. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  60. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  61. package/lib/commands/datasource.js +68 -1
  62. package/lib/commands/dimension-value.js +43 -13
  63. package/lib/commands/dimension.js +38 -7
  64. package/lib/commands/identity-apply-sync.js +131 -0
  65. package/lib/commands/identity-group-cli.js +146 -0
  66. package/lib/commands/identity-membership-role-cache.js +175 -0
  67. package/lib/commands/identity-shared.js +94 -0
  68. package/lib/commands/identity-user-cli.js +158 -0
  69. package/lib/commands/identity.js +43 -0
  70. package/lib/commands/login.js +46 -16
  71. package/lib/commands/protection-cli-leaves.js +286 -0
  72. package/lib/commands/protection.js +50 -0
  73. package/lib/commands/repair.js +13 -3
  74. package/lib/commands/test-e2e-external.js +40 -9
  75. package/lib/commands/test-governance-cli-options.js +47 -0
  76. package/lib/commands/test-governance-command-action.js +55 -0
  77. package/lib/commands/test-governance-external.js +88 -0
  78. package/lib/commands/test-trust-cli-options.js +32 -0
  79. package/lib/commands/test-trust-command-action.js +118 -0
  80. package/lib/commands/test-trust-external.js +127 -0
  81. package/lib/commands/upload.js +34 -13
  82. package/lib/commands/wizard-core.js +3 -0
  83. package/lib/core/config-device-dataplane.js +185 -0
  84. package/lib/datasource/agent-trust-debug-log.js +45 -0
  85. package/lib/datasource/agent-trust-fetch.js +115 -0
  86. package/lib/datasource/agent-trust-map.js +101 -0
  87. package/lib/datasource/agent-trust-mock.js +44 -0
  88. package/lib/datasource/agent-trust-run.js +93 -0
  89. package/lib/datasource/agent-trust-timeout.js +25 -0
  90. package/lib/datasource/audit-evidence-display.js +80 -0
  91. package/lib/datasource/audit-evidence-extract-debug.js +103 -0
  92. package/lib/datasource/audit-evidence-extract.js +177 -0
  93. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  94. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  95. package/lib/datasource/audit-evidence-poll.js +109 -0
  96. package/lib/datasource/audit-evidence-run.js +177 -0
  97. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  98. package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
  99. package/lib/datasource/audit-evidence-verify.js +108 -0
  100. package/lib/datasource/bulk-loader-run-batches.js +88 -0
  101. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  102. package/lib/datasource/bulk-loader-service.js +127 -0
  103. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  104. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  105. package/lib/datasource/datasource-exporter-service.js +144 -0
  106. package/lib/datasource/datasource-identifier.js +148 -0
  107. package/lib/datasource/datasource-load-export-context.js +92 -0
  108. package/lib/datasource/integration-context.js +6 -4
  109. package/lib/datasource/local-data-paths.js +145 -0
  110. package/lib/datasource/log-cleaner.js +241 -0
  111. package/lib/datasource/log-viewer.js +111 -6
  112. package/lib/datasource/record-file-parser.js +85 -0
  113. package/lib/datasource/record-mapper.js +129 -0
  114. package/lib/datasource/resolve-app.js +74 -55
  115. package/lib/datasource/test-e2e.js +26 -2
  116. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  117. package/lib/datasource/unified-validation-run.js +43 -17
  118. package/lib/datasource/validate.js +37 -20
  119. package/lib/external-system/test-system-level.js +25 -4
  120. package/lib/external-system/test.js +3 -1
  121. package/lib/governance/governance-pack-loader.js +70 -0
  122. package/lib/governance/governance-run-display.js +119 -0
  123. package/lib/identity/identity-apply-core.js +108 -0
  124. package/lib/identity/identity-apply-phases.js +244 -0
  125. package/lib/identity/identity-apply-service.js +77 -0
  126. package/lib/identity/identity-csv-parser.js +114 -0
  127. package/lib/internal/fs-real-sync.js +29 -1
  128. package/lib/protection/auth-context.js +45 -0
  129. package/lib/protection/convert-batch.js +90 -0
  130. package/lib/protection/load.js +41 -0
  131. package/lib/protection/paths.js +158 -0
  132. package/lib/protection/preflight-datasource-ready.js +46 -0
  133. package/lib/protection/protection-create-probe-lines.js +142 -0
  134. package/lib/protection/protection-create-probes.js +95 -0
  135. package/lib/protection/protection-create-scaffold.js +281 -0
  136. package/lib/protection/protection-display-helpers.js +445 -0
  137. package/lib/protection/protection-display.js +215 -0
  138. package/lib/protection/protection-preset-registry.js +97 -0
  139. package/lib/protection/report-exit.js +62 -0
  140. package/lib/protection/resolve.js +202 -0
  141. package/lib/protection/run-commands-validate.js +130 -0
  142. package/lib/protection/run-commands.js +216 -0
  143. package/lib/protection/run-protection-create-helpers.js +134 -0
  144. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  145. package/lib/protection/run-protection-create.js +191 -0
  146. package/lib/protection/scope.js +22 -0
  147. package/lib/protection/sync-after-upload.js +64 -0
  148. package/lib/protection/upload-batch.js +127 -0
  149. package/lib/protection/validate-batch.js +113 -0
  150. package/lib/protection/validate-local.js +65 -0
  151. package/lib/resolvers/dimension-file.js +29 -4
  152. package/lib/schema/external-datasource.schema.json +47 -13
  153. package/lib/schema/flag-map-validation-run.json +2 -2
  154. package/lib/schema/protection.schema.json +374 -0
  155. package/lib/schema/type/credential-field-registry.json +636 -0
  156. package/lib/schema/wizard-config.schema.json +1 -1
  157. package/lib/utils/agent-trust-run-display.js +231 -0
  158. package/lib/utils/agent-trust-run-exit.js +59 -0
  159. package/lib/utils/agent-trust-wait-ui.js +94 -0
  160. package/lib/utils/cli-exit-codes.js +30 -0
  161. package/lib/utils/cli-sync-options.js +33 -0
  162. package/lib/utils/credential-push-ui.js +90 -0
  163. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  164. package/lib/utils/dataplane-cli-version-help.js +74 -0
  165. package/lib/utils/datasource-export-display.js +137 -0
  166. package/lib/utils/datasource-load-display.js +174 -0
  167. package/lib/utils/datasource-load-export-ui.js +120 -0
  168. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  169. package/lib/utils/datasource-test-run-display.js +3 -3
  170. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  171. package/lib/utils/help-builder.js +30 -24
  172. package/lib/utils/manifest-source-emit.js +22 -0
  173. package/lib/utils/semver-compare.js +127 -0
  174. package/lib/utils/upload-pipeline-ui.js +91 -0
  175. package/lib/utils/validation-poll-ui.js +14 -7
  176. package/lib/validation/wizard-config-validator.js +58 -19
  177. package/package.json +1 -1
  178. package/templates/applications/dataplane/env.template +13 -1
  179. package/templates/applications/dataplane/rbac.yaml +4 -0
  180. package/templates/external-system/README.md.hbs +56 -8
@@ -16,6 +16,7 @@ const { getDeploymentAuth, requireBearerForDataplanePipeline } = require('../uti
16
16
  const { resolveDataplaneUrl } = require('../utils/dataplane-resolver');
17
17
  const { getIntegrationPath } = require('../utils/paths');
18
18
  const { pushCredentialSecrets } = require('../utils/credential-secrets-env');
19
+ const { runWithCredentialPushSpinner } = require('../utils/credential-push-ui');
19
20
  const { generateControllerManifest } = require('../generator/external-controller-manifest');
20
21
 
21
22
  /**
@@ -84,11 +85,15 @@ async function runCredentialPush(systemKey) {
84
85
  const dataplaneUrl = await resolveDataplaneUrl(controllerUrl, environment, authConfig);
85
86
 
86
87
  const payload = await buildPayload(systemKey);
87
- const pushResult = await pushCredentialSecrets(dataplaneUrl, authConfig, {
88
- envFilePath,
89
- appName: systemKey,
90
- payload
91
- });
88
+ const pushResult = await runWithCredentialPushSpinner(
89
+ () =>
90
+ pushCredentialSecrets(dataplaneUrl, authConfig, {
91
+ envFilePath,
92
+ appName: systemKey,
93
+ payload
94
+ }),
95
+ { systemKey }
96
+ );
92
97
 
93
98
  logPushResult(pushResult);
94
99
  return { pushed: pushResult.pushed || 0 };
@@ -0,0 +1,178 @@
1
+ /**
2
+ * @fileoverview CLI for `datasource load` and `datasource export` (plan 144)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const logger = require('../utils/logger');
10
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
11
+ const { runDatasourceLoad } = require('../datasource/bulk-loader-service');
12
+ const { runDatasourceExport } = require('../datasource/datasource-exporter-service');
13
+ const { displayDatasourceLoadTTY } = require('../utils/datasource-load-display');
14
+ const { displayDatasourceExportTTY } = require('../utils/datasource-export-display');
15
+
16
+ function loadHelpAfter() {
17
+ return `
18
+ Examples:
19
+ $ aifabrix datasource load hubspot-test-datasource-company
20
+ $ aifabrix datasource load hubspot-test-company --file ./fixtures/rows.ndjson -v
21
+ $ aifabrix datasource load hubspot-test-company --dry-run
22
+ $ af ds load hubspot-test-company --batch-size 50 --sync-type incremental
23
+
24
+ Notes:
25
+ - Imports local JSON/NDJSON via dataplane bulk record sync (not direct DB).
26
+ - Default file: integration/.data/<systemKey>-data-<entity>.json or .ndjson
27
+ - External integration folders only (integration/<systemKey>/).
28
+ `;
29
+ }
30
+
31
+ function exportHelpAfter() {
32
+ return `
33
+ Examples:
34
+ $ aifabrix datasource export hubspot-test-datasource-company
35
+ $ aifabrix datasource export hubspot-test-company --format ndjson --limit 500
36
+ $ aifabrix datasource export hubspot-test-company --filter '{"status":{"eq":"active"}}' -v
37
+ $ af ds export hubspot-test-company --fields email,name --strict
38
+
39
+ Notes:
40
+ - Exports governed records search results (ABAC applied), not a raw DB dump.
41
+ - Default output: integration/.data/<systemKey>-data-<entity>.json or .ndjson
42
+ - Maximum 10000 rows per run (dataplane search limit).
43
+ `;
44
+ }
45
+
46
+ /**
47
+ * @param {Object} result
48
+ * @returns {number}
49
+ */
50
+ function computeLoadExitCode(result) {
51
+ if (result.dryRun) {
52
+ return 0;
53
+ }
54
+ return (result.totals.failedCount || 0) > 0 ? 1 : 0;
55
+ }
56
+
57
+ /**
58
+ * @param {Object} result
59
+ * @param {Object} options
60
+ * @returns {number}
61
+ */
62
+ function computeExportExitCode(result, options) {
63
+ if (options.strict === true && result.recordCount === 0) {
64
+ return 1;
65
+ }
66
+ return 0;
67
+ }
68
+
69
+ async function datasourceLoadAction(datasourceKey, options) {
70
+ try {
71
+ const result = await runDatasourceLoad(datasourceKey, {
72
+ app: options.app,
73
+ env: options.env,
74
+ file: options.file,
75
+ verbose: options.verbose,
76
+ dryRun: options.dryRun,
77
+ batchSize: options.batchSize,
78
+ syncType: options.syncType,
79
+ format: options.format
80
+ });
81
+
82
+ if (options.json) {
83
+ const { context: _ctx, ...payload } = result;
84
+ logger.log(JSON.stringify(payload, null, 2));
85
+ } else {
86
+ displayDatasourceLoadTTY(result, { environment: options.env, verbose: options.verbose });
87
+ }
88
+
89
+ process.exit(computeLoadExitCode(result));
90
+ } catch (err) {
91
+ logger.error(formatBlockingError(`Load failed: ${err.message}`));
92
+ const code = err.message && /auth|login|token|version|unreachable/i.test(err.message) ? 3 : 1;
93
+ process.exit(code);
94
+ }
95
+ }
96
+
97
+ async function datasourceExportAction(datasourceKey, options) {
98
+ try {
99
+ const result = await runDatasourceExport(datasourceKey, {
100
+ app: options.app,
101
+ env: options.env,
102
+ file: options.file,
103
+ verbose: options.verbose,
104
+ format: options.format,
105
+ filter: options.filter,
106
+ fields: options.fields,
107
+ limit: options.limit,
108
+ intent: options.intent,
109
+ strict: options.strict
110
+ });
111
+
112
+ if (options.json) {
113
+ const { context: _ctx, ...payload } = result;
114
+ logger.log(JSON.stringify(payload, null, 2));
115
+ } else {
116
+ displayDatasourceExportTTY(result, { environment: options.env, verbose: options.verbose });
117
+ }
118
+
119
+ process.exit(computeExportExitCode(result, options));
120
+ } catch (err) {
121
+ logger.error(formatBlockingError(`Export failed: ${err.message}`));
122
+ const code = err.message && /auth|login|token|version|unreachable/i.test(err.message) ? 3 : 1;
123
+ process.exit(code);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * @param {import('commander').Command} datasource
129
+ */
130
+ function setupDatasourceLoadExportCommands(datasource) {
131
+ datasource
132
+ .command('load <datasourceKey>')
133
+ .description('Import local JSON/NDJSON records via dataplane bulk sync')
134
+ .option('-a, --app <app>', 'Integration folder name')
135
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro')
136
+ .option('--file <path>', 'Input file (default: integration/.data/...)')
137
+ .option('--format <json|ndjson>', 'File format when extension is ambiguous')
138
+ .option('--batch-size <n>', 'Records per bulk request', '100')
139
+ .option(
140
+ '--sync-type <incremental|bulk|validate>',
141
+ 'Dataplane syncType',
142
+ 'incremental'
143
+ )
144
+ .option('--dry-run', 'Parse and validate only; no upload')
145
+ .option('-v, --verbose', 'Per-batch progress')
146
+ .option('--json', 'Machine-readable result JSON')
147
+ .addHelpText('after', loadHelpAfter())
148
+ .action(datasourceLoadAction);
149
+
150
+ datasource
151
+ .command('export <datasourceKey>')
152
+ .description('Export governed records to local JSON/NDJSON via records search')
153
+ .option('-a, --app <app>', 'Integration folder name')
154
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro')
155
+ .option('--file <path>', 'Output file (default: integration/.data/...)')
156
+ .option('--format <json|ndjson>', 'Output format')
157
+ .option('--filter <json>', 'Records search filters (JSON object)')
158
+ .option('--fields <csv>', 'Project metadata keys in export rows')
159
+ .option('--limit <n>', 'Max records (1–10000)', '1000')
160
+ .option(
161
+ '--intent <retrieval|grounding|analytics|validation>',
162
+ 'Search intent',
163
+ 'validation'
164
+ )
165
+ .option('--strict', 'Exit 1 when zero rows are exported')
166
+ .option('-v, --verbose', 'Search stats and file size')
167
+ .option('--json', 'Machine-readable result JSON')
168
+ .addHelpText('after', exportHelpAfter())
169
+ .action(datasourceExportAction);
170
+ }
171
+
172
+ module.exports = {
173
+ setupDatasourceLoadExportCommands,
174
+ datasourceLoadAction,
175
+ datasourceExportAction,
176
+ computeLoadExitCode,
177
+ computeExportExitCode
178
+ };
@@ -0,0 +1,114 @@
1
+ /**
2
+ * @fileoverview CLI wiring for `datasource test-trust` (404.5 / plan 143).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const logger = require('../utils/logger');
10
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
11
+ const { runDatasourceAgentTrust } = require('../datasource/agent-trust-run');
12
+ const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-log');
13
+ const { displayAgentTrustRunTTY } = require('../utils/agent-trust-run-display');
14
+ const { computeExitCodeFromTrustRun } = require('../utils/agent-trust-run-exit');
15
+ const { attachDatasourceTestCommonOptions } = require('./datasource-unified-test-cli.options');
16
+ const { cliOptsSkipSync } = require('../utils/cli-sync-options');
17
+
18
+ function datasourceTestTrustHelpAfter() {
19
+ return `
20
+ Examples:
21
+ $ aifabrix datasource test-trust hubspot-companies
22
+ $ aifabrix datasource test-trust hubspot-companies --app test-e2e-hubspot -v
23
+ $ aifabrix datasource test-trust hubspot-companies --revalidate --strict
24
+ $ aifabrix test-trust test-e2e-hubspot
25
+
26
+ Notes:
27
+ - Semantic trust only (agent metadata validation). For live API proof use test-e2e.
28
+ - Local files are published before run unless --no-sync.
29
+ - With --debug, JSON is saved under integration/<app>/logs/ (test-trust-<key>-*.json). View with: aifabrix datasource log-trust <key>
30
+ `;
31
+ }
32
+
33
+ async function runDatasourceTestTrustOnce(datasourceKey, options) {
34
+ const { trustRun, apiError } = await runDatasourceAgentTrust(datasourceKey, {
35
+ app: options.app,
36
+ environment: options.env,
37
+ noSync: options.noSync === true,
38
+ revalidate: options.revalidate === true,
39
+ summary: options.summary === true,
40
+ timeout: options.timeout
41
+ });
42
+ return { trustRun, apiError };
43
+ }
44
+
45
+ async function finalizeDatasourceTestTrust(datasourceKey, options, result) {
46
+ const displayOpts = {
47
+ json: options.json,
48
+ verbose: options.verbose,
49
+ environment: options.env,
50
+ noSync: options.noSync === true,
51
+ strict: options.strict === true
52
+ };
53
+ if (options.json) {
54
+ logger.log(JSON.stringify(result.trustRun, null, 2));
55
+ } else if (options.summary) {
56
+ const tr = result.trustRun;
57
+ logger.log(
58
+ `${tr.datasourceKey}: ${tr.trustDecision} (${tr.validationStatus}, ${Math.round((tr.confidence || 0) * 100)}%)`
59
+ );
60
+ } else {
61
+ displayAgentTrustRunTTY(result.trustRun, displayOpts);
62
+ }
63
+ const exitOpts = {
64
+ warningsAsErrors: options.warningsAsErrors === true,
65
+ strict: options.strict === true
66
+ };
67
+ return computeExitCodeFromTrustRun(result.trustRun, exitOpts);
68
+ }
69
+
70
+ async function datasourceTestTrustAction(datasourceKey, options, cmd) {
71
+ try {
72
+ const merged = { ...options, noSync: cliOptsSkipSync(options, cmd) };
73
+ const result = await runDatasourceTestTrustOnce(datasourceKey, merged);
74
+ const { resolveAppKeyForDatasource } = require('../datasource/resolve-app');
75
+ const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
76
+ if (options.debug) {
77
+ await writeTrustDebugLogAndPrint(appKey, datasourceKey, {
78
+ request: { datasourceKey, revalidate: options.revalidate === true },
79
+ response: result.trustRun,
80
+ error: result.apiError ? result.apiError.message : null
81
+ });
82
+ }
83
+ const exitCode = await finalizeDatasourceTestTrust(datasourceKey, merged, result);
84
+ process.exit(exitCode);
85
+ } catch (err) {
86
+ logger.error(formatBlockingError('Agent trust validation failed:'), err.message);
87
+ process.exit(3);
88
+ }
89
+ }
90
+
91
+ function setupDatasourceTestTrustCommand(datasource) {
92
+ const cmd = datasource
93
+ .command('test-trust <datasourceKey>')
94
+ .description('Semantic agent metadata validation for one datasource (dataplane 404.5)');
95
+ attachDatasourceTestCommonOptions(cmd, {
96
+ includeNoAsync: false,
97
+ includePayload: false,
98
+ timeoutHelp: 'HTTP timeout for validate request (ms)',
99
+ timeoutDefault: '120000'
100
+ });
101
+ cmd
102
+ .option('--no-sync', 'Skip publishing local integration files before validate')
103
+ .option('--revalidate', 'Force new validation (ignore inputHash cache)')
104
+ .option('--strict', 'Exit 1 unless trustDecision is trusted')
105
+ .addHelpText('after', datasourceTestTrustHelpAfter())
106
+ .action(datasourceTestTrustAction);
107
+ }
108
+
109
+ module.exports = {
110
+ setupDatasourceTestTrustCommand,
111
+ runDatasourceTestTrustOnce,
112
+ finalizeDatasourceTestTrust,
113
+ datasourceTestTrustAction
114
+ };
@@ -28,6 +28,7 @@ const {
28
28
  finalizeDatasourceTestE2ELegacyPath,
29
29
  displayDatasourceTestE2EEnvelopeResults
30
30
  } = require('./datasource-unified-test-e2e-cli-helpers');
31
+ const { maybeVerifyAuditAfterE2E } = require('../datasource/audit-evidence-run');
31
32
  const {
32
33
  datasourceTestHelpAfter,
33
34
  datasourceTestIntegrationHelpAfter,
@@ -333,7 +334,7 @@ async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
333
334
  minProcessed: options.minProcessed,
334
335
  minRecordCount: options.minRecordCount,
335
336
  timeout: options.timeout,
336
- capabilityKey: options.capability,
337
+ capabilityKey: options.capabilityKey,
337
338
  sync: options.sync === true
338
339
  });
339
340
  const unifiedModes =
@@ -352,7 +353,7 @@ async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
352
353
  warningsAsErrors: options.warningsAsErrors,
353
354
  requireCert: options.requireCert,
354
355
  debug: options.debug,
355
- requestedCapabilityKey: options.capability,
356
+ requestedCapabilityKey: options.capabilityKey,
356
357
  strictCapabilityScope: options.strictCapabilityScope === true
357
358
  }
358
359
  );
@@ -370,24 +371,24 @@ async function runDatasourceTestE2ECliOnce(datasourceKey, options) {
370
371
 
371
372
  async function runDatasourceTestE2ECliAction(datasourceKey, options) {
372
373
  const { exitCode, envelope } = await runDatasourceTestE2ECliOnce(datasourceKey, options);
373
- await afterUnifiedValidationCertSync(exitCode, datasourceKey, options, 'datasource test-e2e', envelope);
374
- process.exit(exitCode);
374
+ const finalExit = await maybeVerifyAuditAfterE2E(exitCode, datasourceKey, envelope, options);
375
+ await afterUnifiedValidationCertSync(
376
+ finalExit,
377
+ datasourceKey,
378
+ options,
379
+ 'datasource test-e2e',
380
+ envelope
381
+ );
382
+ process.exit(finalExit);
375
383
  }
376
384
 
377
385
  async function e2eTestCommandAction(datasourceKey, capabilityKey, options) {
378
386
  const optObj = options && typeof options === 'object' ? options : {};
379
387
  const capFromArg = typeof capabilityKey === 'string' ? capabilityKey.trim() : '';
380
- const capFromFlag = optObj.capability !== undefined && optObj.capability !== null
381
- ? String(optObj.capability).trim()
382
- : '';
383
- const requestedCapability = capFromArg || capFromFlag;
384
- if (capFromArg && capFromFlag && capFromArg !== capFromFlag) {
385
- logger.warn(
386
- chalk.yellow('⚠ Capability mismatch:'),
387
- `using positional '${capFromArg}' instead of --capability '${capFromFlag}'.`
388
- );
389
- }
390
- const mergedOptions = { ...optObj, capability: requestedCapability || undefined };
388
+ const mergedOptions = {
389
+ ...optObj,
390
+ capabilityKey: capFromArg || undefined
391
+ };
391
392
  try {
392
393
  if (mergedOptions.watch) {
393
394
  const { appKey } = await resolveAppKeyForDatasource(datasourceKey, mergedOptions.app);
@@ -400,14 +401,20 @@ async function e2eTestCommandAction(datasourceKey, capabilityKey, options) {
400
401
  runOnce: async() => {
401
402
  try {
402
403
  const r = await runDatasourceTestE2ECliOnce(datasourceKey, mergedOptions);
403
- await afterUnifiedValidationCertSync(
404
+ const finalExit = await maybeVerifyAuditAfterE2E(
404
405
  r.exitCode,
405
406
  datasourceKey,
407
+ r.envelope,
408
+ mergedOptions
409
+ );
410
+ await afterUnifiedValidationCertSync(
411
+ finalExit,
412
+ datasourceKey,
406
413
  mergedOptions,
407
414
  'datasource test-e2e (watch)',
408
415
  r.envelope
409
416
  );
410
- return r;
417
+ return { exitCode: finalExit, envelope: r.envelope };
411
418
  } catch (err) {
412
419
  logger.error(formatBlockingError('E2E test failed:'), err.message);
413
420
  return { exitCode: 3, envelope: null };
@@ -459,5 +466,6 @@ module.exports = {
459
466
  runIntegrationOnceForWatch,
460
467
  integrationTestCommandAction,
461
468
  runDatasourceTestE2ECliOnce,
469
+ maybeVerifyAuditAfterE2E,
462
470
  e2eTestCommandAction
463
471
  };
@@ -44,6 +44,7 @@ Examples:
44
44
  $ aifabrix datasource test-e2e hubspot-users --app test-e2e-hubspot -v --debug
45
45
  $ aifabrix datasource test-e2e my-documents-ds --min-vector-hits 7 -v --debug
46
46
  $ aifabrix datasource test-e2e hubspot-users -a test-e2e-hubspot --no-async
47
+ $ aifabrix datasource test-e2e hubspot-users --sync --verify-audit -v
47
48
  $ aifabrix datasource test-e2e hubspot-users read
48
49
 
49
50
  Notes:
@@ -53,6 +54,7 @@ Notes:
53
54
  aifabrix datasource test-integration <datasourceKey>
54
55
  - For system-level E2E rollup across datasources, use:
55
56
  aifabrix test-e2e <systemKey>
57
+ - To prove governance audit evidence after a green E2E, add --verify-audit (see verify-audit command).
56
58
  `;
57
59
  }
58
60
 
@@ -175,11 +177,24 @@ function attachDatasourceTestE2eExclusiveOptions(cmd) {
175
177
  '--primary-key-value <value|@path>',
176
178
  'Primary key value or path to JSON file (e.g. @pk.json) for e2eOptions.primaryKeyValue'
177
179
  )
178
- .option('--capability <key>', 'Capability drill-down (deprecated; use positional [capabilityKey])')
179
180
  .option(
180
181
  '--strict-capability-scope',
181
- 'Exit 1 if a capability drill-down is requested but the report lists more than one capabilities[] row (plan §2.3)'
182
- );
182
+ 'Exit 1 when positional [capabilityKey] is set but the report lists more than one capabilities[] row'
183
+ )
184
+ .option(
185
+ '--verify-audit',
186
+ 'After successful E2E, verify the nine-row audit evidence matrix on the dataplane (requires audit:read)'
187
+ )
188
+ .option(
189
+ '--no-verify-audit',
190
+ 'Skip audit evidence verification even if enabled by default in a future release'
191
+ )
192
+ .option(
193
+ '--audit-poll-ms <ms>',
194
+ 'Max wait for audit rows after E2E when using --verify-audit (default 15000)',
195
+ '15000'
196
+ )
197
+ .option('--audit-poll-interval-ms <ms>', 'Audit poll interval when using --verify-audit (default 2000)', '2000');
183
198
  }
184
199
 
185
200
  module.exports = {
@@ -46,7 +46,7 @@ function exitCodeFromDatasourceTestRunEnvelope(env, options) {
46
46
  warningsAsErrors: options.warningsAsErrors === true,
47
47
  requireCert: options.requireCert === true
48
48
  });
49
- const scope = analyzeCapabilityScope(env, options.capability);
49
+ const scope = analyzeCapabilityScope(env, options.capabilityKey);
50
50
  if (options.strictCapabilityScope === true && scope.violated) {
51
51
  code = Math.max(code, 1);
52
52
  }
@@ -62,10 +62,10 @@ function exitCodeFromDatasourceTestRunEnvelope(env, options) {
62
62
  function finalizeDatasourceTestE2ELegacyPath(data, options) {
63
63
  displayE2EResults(data, options.verbose);
64
64
  logDatasourceTestRunDebugAppendix(data.datasourceTestRun, options.debug);
65
- logE2eCapabilityFocusFromEnvelope(data.datasourceTestRun, options.capability);
65
+ logE2eCapabilityFocusFromEnvelope(data.datasourceTestRun, options.capabilityKey);
66
66
  const env = data.datasourceTestRun;
67
67
  if (env) {
68
- emitCapabilityScopeDiagnostics(env, { requestedCapabilityKey: options.capability });
68
+ emitCapabilityScopeDiagnostics(env, { requestedCapabilityKey: options.capabilityKey });
69
69
  const code = exitCodeFromDatasourceTestRunEnvelope(env, options);
70
70
  return code === null ? 1 : code;
71
71
  }
@@ -91,10 +91,10 @@ function displayDatasourceTestE2EEnvelopeResults(datasourceKey, env, options) {
91
91
  {
92
92
  debug: options.debug,
93
93
  runType: 'e2e',
94
- requestedCapabilityKey: options.capability
94
+ requestedCapabilityKey: options.capabilityKey
95
95
  }
96
96
  );
97
- logE2eCapabilityFocusFromEnvelope(env, options.capability);
97
+ logE2eCapabilityFocusFromEnvelope(env, options.capabilityKey);
98
98
  }
99
99
 
100
100
  module.exports = {
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @fileoverview `aifabrix datasource verify-audit` — re-run 407.1 matrix from last E2E log
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const logger = require('../utils/logger');
10
+ const { formatBlockingError } = require('../utils/cli-test-layout-chalk');
11
+ const { runAuditEvidenceVerification } = require('../datasource/audit-evidence-run');
12
+ const { loadEnvelopeFromLatestE2eLog } = require('../datasource/audit-evidence-extract');
13
+
14
+ const VERIFY_AUDIT_HELP_AFTER = `
15
+ Examples:
16
+ $ aifabrix datasource verify-audit test-e2e-hubspot-companies
17
+ $ aifabrix datasource verify-audit test-e2e-hubspot-companies --app test-e2e-hubspot -v
18
+ $ aifabrix datasource verify-audit test-e2e-hubspot-companies --correlation-id <testRunId>
19
+ $ aifabrix datasource verify-audit test-e2e-hubspot-companies --json
20
+
21
+ Notes:
22
+ - Re-checks audit evidence from the latest test-e2e debug log (or --file) without re-running E2E.
23
+ - Requires audit:read on the dataplane (same login as test-e2e).
24
+ - Pair with: aifabrix datasource test-e2e <datasourceKey> --verify-audit
25
+ `;
26
+
27
+ /**
28
+ * @param {string} datasourceKey
29
+ * @param {Object} options
30
+ */
31
+ async function verifyAuditCommandAction(datasourceKey, options) {
32
+ const envelope = await loadEnvelopeFromLatestE2eLog(datasourceKey, options);
33
+ if (!envelope) {
34
+ logger.error(
35
+ formatBlockingError('verify-audit failed:'),
36
+ 'No test-e2e debug log found (run test-e2e with --debug first)'
37
+ );
38
+ process.exit(3);
39
+ return;
40
+ }
41
+ const pollMs = parseInt(String(options.auditPollMs || '15000'), 10);
42
+ const pollInterval = parseInt(String(options.auditPollIntervalMs || '2000'), 10);
43
+ const { exitCode } = await runAuditEvidenceVerification(datasourceKey, envelope, {
44
+ app: options.app,
45
+ env: options.env,
46
+ verbose: options.verbose,
47
+ json: options.json,
48
+ correlationId: options.correlationId,
49
+ executionId: options.executionId,
50
+ quiet: false,
51
+ auditPollMaxWaitMs: Number.isFinite(pollMs) ? pollMs : 15000,
52
+ auditPollIntervalMs: Number.isFinite(pollInterval) ? pollInterval : 2000
53
+ });
54
+ process.exit(exitCode);
55
+ }
56
+
57
+ /**
58
+ * @param {import('commander').Command} datasource
59
+ */
60
+ function setupDatasourceVerifyAuditCommand(datasource) {
61
+ datasource
62
+ .command('verify-audit <datasourceKey>')
63
+ .description(
64
+ 'Verify audit evidence matrix from latest E2E log (or --file) without re-running E2E'
65
+ )
66
+ .option(
67
+ '-a, --app <app>',
68
+ 'Integration folder name (optional: resolve from cwd or datasource key if single match)'
69
+ )
70
+ .option('-e, --env <env>', 'Environment: dev, tst, or pro')
71
+ .option('-v, --verbose', 'Show matrix row codes and execution id count')
72
+ .option('--json', 'Print auditEvidenceVerification JSON block')
73
+ .option('-f, --file <path>', 'Path to test-e2e debug log JSON')
74
+ .option('--correlation-id <id>', 'Override correlation/testRunId filter')
75
+ .option('--execution-id <id>', 'Include execution id for sub-resource checks')
76
+ .option(
77
+ '--audit-poll-ms <ms>',
78
+ 'Max wait for audit rows to appear (default 15000)',
79
+ '15000'
80
+ )
81
+ .option('--audit-poll-interval-ms <ms>', 'Poll interval (default 2000)', '2000')
82
+ .addHelpText('after', VERIFY_AUDIT_HELP_AFTER)
83
+ .action(async(datasourceKey, options) => {
84
+ try {
85
+ await verifyAuditCommandAction(datasourceKey, options);
86
+ } catch (error) {
87
+ logger.error(formatBlockingError('verify-audit failed:'), error.message);
88
+ process.exit(3);
89
+ }
90
+ });
91
+ }
92
+
93
+ module.exports = {
94
+ setupDatasourceVerifyAuditCommand,
95
+ verifyAuditCommandAction
96
+ };