@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
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Bounded poll until audit execution rows are captured (407.3)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { executionRowCaptured } = require('./audit-evidence-matrix-rows');
10
+
11
+ const DEFAULT_MAX_WAIT_MS = 15000;
12
+ const DEFAULT_INTERVAL_MS = 2000;
13
+
14
+ /**
15
+ * @param {number} ms
16
+ * @returns {Promise<void>}
17
+ */
18
+ function sleep(ms) {
19
+ return new Promise(resolve => setTimeout(resolve, ms));
20
+ }
21
+
22
+ /**
23
+ * @param {Array} executions
24
+ * @param {number} minExpected
25
+ * @returns {boolean}
26
+ */
27
+ function executionsReady(executions, minExpected) {
28
+ if (!Array.isArray(executions) || executions.length < minExpected) return false;
29
+ const captured = executions.filter(executionRowCaptured).length;
30
+ return captured >= minExpected;
31
+ }
32
+
33
+ /**
34
+ * @param {Array} executions
35
+ * @param {string[]} executionIds
36
+ * @returns {boolean}
37
+ */
38
+ function allEnvelopeIdsPresent(executions, executionIds) {
39
+ if (!Array.isArray(executionIds) || !executionIds.length) return true;
40
+ const found = new Set(
41
+ (executions || []).map(e => (e && e.id ? String(e.id) : '')).filter(Boolean)
42
+ );
43
+ return executionIds.every(id => found.has(String(id)));
44
+ }
45
+
46
+ /**
47
+ * E2E: wait until envelope executionIds are visible and captured in list API.
48
+ * @param {Array} executions
49
+ * @param {number} minExpected
50
+ * @param {string[]} [executionIds]
51
+ * @returns {boolean}
52
+ */
53
+ function executionsReadyForVerify(executions, minExpected, executionIds) {
54
+ const min = Math.max(1, minExpected || 1);
55
+ if (Array.isArray(executionIds) && executionIds.length) {
56
+ const need = Math.min(min, executionIds.length);
57
+ if (!allEnvelopeIdsPresent(executions, executionIds)) return false;
58
+ const captured = executionIds.filter(id =>
59
+ (executions || []).some(
60
+ e => String(e.id) === String(id) && executionRowCaptured(e)
61
+ )
62
+ ).length;
63
+ return captured >= need;
64
+ }
65
+ return executionsReady(executions, min);
66
+ }
67
+
68
+ /**
69
+ * @async
70
+ * @param {Object} opts
71
+ * @param {() => Promise<{ data: Array, meta: Object|null }>} opts.fetchExecutions
72
+ * @param {number} opts.minExpected
73
+ * @param {number} [opts.maxWaitMs]
74
+ * @param {number} [opts.intervalMs]
75
+ * @returns {Promise<{ data: Array, meta: Object|null, timedOut: boolean }>}
76
+ */
77
+ async function pollExecutionsUntilReady(opts) {
78
+ const minExpected = Math.max(1, opts.minExpected || 1);
79
+ const executionIds = Array.isArray(opts.executionIds) ? opts.executionIds : [];
80
+ const maxWaitMs =
81
+ opts.maxWaitMs !== undefined && opts.maxWaitMs !== null ? opts.maxWaitMs : DEFAULT_MAX_WAIT_MS;
82
+ const intervalMs =
83
+ opts.intervalMs !== undefined && opts.intervalMs !== null
84
+ ? opts.intervalMs
85
+ : DEFAULT_INTERVAL_MS;
86
+ const deadline = Date.now() + maxWaitMs;
87
+ let last = { data: [], meta: null };
88
+
89
+ while (Date.now() <= deadline) {
90
+ last = await opts.fetchExecutions();
91
+ if (executionsReadyForVerify(last.data, minExpected, executionIds)) {
92
+ return { ...last, timedOut: false };
93
+ }
94
+ if (Date.now() + intervalMs > deadline) break;
95
+ await sleep(intervalMs);
96
+ }
97
+
98
+ return { ...last, timedOut: true };
99
+ }
100
+
101
+ module.exports = {
102
+ DEFAULT_MAX_WAIT_MS,
103
+ DEFAULT_INTERVAL_MS,
104
+ sleep,
105
+ executionsReady,
106
+ allEnvelopeIdsPresent,
107
+ executionsReadyForVerify,
108
+ pollExecutionsUntilReady
109
+ };
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @fileoverview Orchestrate audit evidence verification after E2E or from saved logs
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { resolveAppKeyForDatasource } = require('./resolve-app');
10
+ const { setupIntegrationTestAuth } = require('../external-system/test-auth');
11
+ const { getConfig } = require('../core/config');
12
+ const {
13
+ extractAuditEvidenceContext,
14
+ loadEnvelopeFromLatestE2eLog
15
+ } = require('./audit-evidence-extract');
16
+ const { verifyAuditEvidenceMatrix } = require('./audit-evidence-verify');
17
+ const {
18
+ displayAuditEvidenceMatrixTTY,
19
+ printAuditEvidenceVerificationJson
20
+ } = require('./audit-evidence-display');
21
+
22
+ /**
23
+ * @param {string} datasourceKey
24
+ * @param {Object} options
25
+ * @returns {Promise<{ authConfig: Object, dataplaneUrl: string }>}
26
+ */
27
+ async function resolveAuditVerifyAuth(datasourceKey, options) {
28
+ if (options.authConfig && options.dataplaneUrl) {
29
+ return { authConfig: options.authConfig, dataplaneUrl: options.dataplaneUrl };
30
+ }
31
+ const { appKey } = await resolveAppKeyForDatasource(datasourceKey, options.app);
32
+ const configObj = await getConfig();
33
+ const auth = await setupIntegrationTestAuth(appKey, options, configObj);
34
+ return { authConfig: auth.authConfig, dataplaneUrl: auth.dataplaneUrl };
35
+ }
36
+
37
+ /**
38
+ * @param {Object} envelope
39
+ * @param {string} datasourceKey
40
+ * @param {Object} [opts]
41
+ * @returns {Object}
42
+ */
43
+ function buildVerifyContext(envelope, datasourceKey, opts = {}) {
44
+ const ctx = extractAuditEvidenceContext(envelope);
45
+ if (datasourceKey) ctx.datasourceKey = String(datasourceKey).trim();
46
+ if (opts.correlationId) ctx.correlationId = String(opts.correlationId).trim();
47
+ if (opts.executionId) {
48
+ const id = String(opts.executionId).trim();
49
+ if (id && !ctx.executionIds.includes(id)) ctx.executionIds.unshift(id);
50
+ }
51
+ return ctx;
52
+ }
53
+
54
+ /**
55
+ * @async
56
+ * @param {string} datasourceKey
57
+ * @param {Object} envelope - DatasourceTestRun
58
+ * @param {Object} options
59
+ * @returns {Promise<{ verification: import('../api/types/audit.types').AuditEvidenceVerification, exitCode: number }>}
60
+ */
61
+ async function runAuditEvidenceVerification(datasourceKey, envelope, options = {}) {
62
+ const ctx = buildVerifyContext(envelope, datasourceKey, options);
63
+ if (!ctx.executionIds.length && !ctx.correlationId) {
64
+ const verification = failedVerification(
65
+ datasourceKey,
66
+ ctx,
67
+ 'missing audit.executionIds and testRunId/correlationId',
68
+ 'auditIdsMissing'
69
+ );
70
+ emitVerificationOutput(verification, options);
71
+ return { verification, exitCode: 1 };
72
+ }
73
+ let auth;
74
+ try {
75
+ auth = await resolveAuditVerifyAuth(datasourceKey, options);
76
+ } catch (err) {
77
+ const verification = failedVerification(datasourceKey, ctx, err.message, 'authFailed');
78
+ emitVerificationOutput(verification, options);
79
+ return { verification, exitCode: 3 };
80
+ }
81
+
82
+ try {
83
+ const verification = await verifyAuditEvidenceMatrix({
84
+ dataplaneUrl: auth.dataplaneUrl,
85
+ authConfig: auth.authConfig,
86
+ datasourceKey: ctx.datasourceKey,
87
+ correlationId: ctx.correlationId,
88
+ executionIds: ctx.executionIds,
89
+ expectedOperations: ctx.expectedOperations,
90
+ maxWaitMs: options.auditPollMaxWaitMs,
91
+ intervalMs: options.auditPollIntervalMs
92
+ });
93
+ emitVerificationOutput(verification, options);
94
+ return { verification, exitCode: verification.status === 'passed' ? 0 : 1 };
95
+ } catch (err) {
96
+ const verification = failedVerification(datasourceKey, ctx, err.message, 'verifyError');
97
+ emitVerificationOutput(verification, options);
98
+ const code = err.status === 401 || err.status === 403 ? 3 : 1;
99
+ return { verification, exitCode: code };
100
+ }
101
+ }
102
+
103
+ /**
104
+ * @param {string} datasourceKey
105
+ * @param {Object} ctx
106
+ * @param {string} message
107
+ * @param {string} code
108
+ * @returns {import('../api/types/audit.types').AuditEvidenceVerification}
109
+ */
110
+ function failedVerification(datasourceKey, ctx, message, code) {
111
+ return {
112
+ status: 'failed',
113
+ datasourceKey,
114
+ correlationId: ctx.correlationId || null,
115
+ executionIds: ctx.executionIds || [],
116
+ matrix: [{ row: 0, status: 'failed', detail: message, code }]
117
+ };
118
+ }
119
+
120
+ /**
121
+ * @param {import('../api/types/audit.types').AuditEvidenceVerification} verification
122
+ * @param {Object} options
123
+ */
124
+ function emitVerificationOutput(verification, options) {
125
+ if (options.json) {
126
+ printAuditEvidenceVerificationJson(verification);
127
+ return;
128
+ }
129
+ if (!options.quiet) {
130
+ displayAuditEvidenceMatrixTTY(verification, options.verbose === true);
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Run audit matrix when E2E succeeded and --verify-audit is set.
136
+ * @param {number} e2eExitCode
137
+ * @param {string} datasourceKey
138
+ * @param {Object|null} envelope
139
+ * @param {Object} options
140
+ * @returns {Promise<number>}
141
+ */
142
+ async function maybeVerifyAuditAfterE2E(e2eExitCode, datasourceKey, envelope, options = {}) {
143
+ const enabled =
144
+ options.verifyAudit === true && options.noVerifyAudit !== true;
145
+ if (!enabled || e2eExitCode !== 0 || !envelope) {
146
+ return e2eExitCode;
147
+ }
148
+ const pollMsRaw = parseInt(String(options.auditPollMs || options.auditPollMaxWaitMs || '15000'), 10);
149
+ const pollInterval = parseInt(
150
+ String(options.auditPollIntervalMs || '2000'),
151
+ 10
152
+ );
153
+ const ctx = buildVerifyContext(envelope, datasourceKey, options);
154
+ const pollMs = Math.max(
155
+ Number.isFinite(pollMsRaw) ? pollMsRaw : 15000,
156
+ (ctx.executionIds && ctx.executionIds.length >= 7) ? 30000 : 0
157
+ );
158
+ const { exitCode } = await runAuditEvidenceVerification(datasourceKey, envelope, {
159
+ app: options.app,
160
+ env: options.env,
161
+ verbose: options.verbose,
162
+ json: options.json,
163
+ authConfig: options.authConfig,
164
+ dataplaneUrl: options.dataplaneUrl,
165
+ auditPollMaxWaitMs: pollMs,
166
+ auditPollIntervalMs: Number.isFinite(pollInterval) ? pollInterval : 2000
167
+ });
168
+ return exitCode;
169
+ }
170
+
171
+ module.exports = {
172
+ runAuditEvidenceVerification,
173
+ maybeVerifyAuditAfterE2E,
174
+ loadEnvelopeFromLatestE2eLog,
175
+ buildVerifyContext,
176
+ resolveAuditVerifyAuth
177
+ };
@@ -0,0 +1,167 @@
1
+ /**
2
+ * @fileoverview Helpers for audit evidence matrix verification (sub-resource validators, rows 8–9)
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { checkPerExecutionRow } = require('./audit-evidence-matrix-rows');
10
+ const {
11
+ normalizeAuditOperation,
12
+ executionsCoverExpectedOperations
13
+ } = require('./audit-evidence-operation-aliases');
14
+
15
+ /**
16
+ * @param {Object} input
17
+ * @returns {import('../api/types/audit.types').AuditEvidenceMatrixRow}
18
+ */
19
+ function checkRow8CorrelationGroup(input) {
20
+ const row = { row: 8, status: 'failed', detail: '', code: 'correlationGroup' };
21
+ const items = input.executions || [];
22
+ if (!items.length) {
23
+ return {
24
+ ...row,
25
+ detail: input.correlationId
26
+ ? 'no executions for correlation or datasource filter'
27
+ : 'no correlationId and no executions',
28
+ code: 'correlationEmpty'
29
+ };
30
+ }
31
+ const expected = (input.expectedOperations || [])
32
+ .map(normalizeAuditOperation)
33
+ .filter(Boolean);
34
+ if (expected.length && !executionsCoverExpectedOperations(items, expected)) {
35
+ const ops = new Set(
36
+ items.map(e => normalizeAuditOperation(e && e.operation)).filter(Boolean)
37
+ );
38
+ const missing = expected.filter(op => !ops.has(op));
39
+ return {
40
+ ...row,
41
+ detail: `missing ops: ${missing.join(', ')}`,
42
+ code: 'correlationOpsMissing'
43
+ };
44
+ }
45
+ const opCount = new Set(
46
+ items.map(e => normalizeAuditOperation(e && e.operation)).filter(Boolean)
47
+ ).size;
48
+ return {
49
+ ...row,
50
+ status: 'passed',
51
+ detail: `correlation ops=${opCount || items.length}`,
52
+ code: 'correlationGroup'
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Prefer executions tied to this run (by id), then correlation query, then datasource list.
58
+ * @param {Object} ctx
59
+ * @param {Array} executions
60
+ * @param {Array} corrQueryRows
61
+ * @returns {Array}
62
+ */
63
+ function resolveRow8Executions(ctx, executions, corrQueryRows) {
64
+ const idSet = new Set(
65
+ (ctx.executionIds || []).map(id => String(id).trim()).filter(Boolean)
66
+ );
67
+ let byId = [];
68
+ if (idSet.size && executions && executions.length) {
69
+ byId = executions.filter(e => e && e.id && idSet.has(String(e.id)));
70
+ }
71
+ const expected = ctx.expectedOperations || [];
72
+ if (byId.length && executionsCoverExpectedOperations(byId, expected)) {
73
+ return byId;
74
+ }
75
+ if (corrQueryRows && corrQueryRows.length && executionsCoverExpectedOperations(corrQueryRows, expected)) {
76
+ return corrQueryRows;
77
+ }
78
+ if (byId.length) return byId;
79
+ if (corrQueryRows && corrQueryRows.length) return corrQueryRows;
80
+ return executions || [];
81
+ }
82
+
83
+ /**
84
+ * @param {Set<string>} traceIds
85
+ * @param {string[]} execIds
86
+ * @returns {import('../api/types/audit.types').AuditEvidenceMatrixRow}
87
+ */
88
+ function checkRow9Traces(traceIds, execIds) {
89
+ const row = { row: 9, status: 'failed', detail: '', code: 'traceMismatch' };
90
+ if (!execIds.length) {
91
+ return { ...row, detail: 'no execution ids', code: 'auditIdsMissing' };
92
+ }
93
+ if (traceIds.size < 1) {
94
+ return { ...row, detail: 'no trace payloads resolved', code: 'traceEmpty' };
95
+ }
96
+ if (traceIds.size < execIds.length) {
97
+ return {
98
+ ...row,
99
+ detail: `distinct traces=${traceIds.size} executionIds=${execIds.length}`,
100
+ code: 'traceCountLow'
101
+ };
102
+ }
103
+ return { ...row, status: 'passed', detail: `traces=${traceIds.size} ids=${execIds.length}` };
104
+ }
105
+
106
+ function isRbacSubResourceValid(body) {
107
+ return !!(body && typeof body === 'object' && (body.id || body.decision || body.summary));
108
+ }
109
+
110
+ function isAbacSubResourceValid(body) {
111
+ return !!(body && typeof body === 'object' && (body.id || body.decision || body.traceId));
112
+ }
113
+
114
+ function isErrorsValid(body) {
115
+ if (Array.isArray(body)) return true;
116
+ if (body && typeof body === 'object' && Array.isArray(body.data)) return true;
117
+ return body && typeof body === 'object';
118
+ }
119
+
120
+ function isStepsValid(body) {
121
+ if (Array.isArray(body) && body.length > 0) return true;
122
+ if (body && Array.isArray(body.steps) && body.steps.length > 0) return true;
123
+ return body && typeof body === 'object' && Object.keys(body).length > 0;
124
+ }
125
+
126
+ /**
127
+ * @param {Array} executions
128
+ * @param {string[]} fallbackIds
129
+ * @returns {string[]}
130
+ */
131
+ function resolveExecutionIdsForChecks(executions, fallbackIds) {
132
+ const fromRows = (executions || [])
133
+ .map(e => (e && e.id ? String(e.id).trim() : ''))
134
+ .filter(Boolean);
135
+ return [...new Set(fromRows.concat(fallbackIds || []))];
136
+ }
137
+
138
+ /**
139
+ * @param {Object} opts
140
+ * @returns {Promise<import('../api/types/audit.types').AuditEvidenceMatrixRow>}
141
+ */
142
+ async function checkPerExecutionSub(opts) {
143
+ const { dataplaneUrl, authConfig, executionId, rowNum, label, fetcher, isValid } = opts;
144
+ try {
145
+ const body = await fetcher(dataplaneUrl, authConfig, executionId);
146
+ return checkPerExecutionRow(rowNum, `${label}Null`, label, body, isValid);
147
+ } catch (err) {
148
+ return {
149
+ row: rowNum,
150
+ status: 'failed',
151
+ detail: `${label}: ${err.message}`,
152
+ code: `${label}Error`
153
+ };
154
+ }
155
+ }
156
+
157
+ module.exports = {
158
+ checkRow8CorrelationGroup,
159
+ resolveRow8Executions,
160
+ checkRow9Traces,
161
+ isRbacSubResourceValid,
162
+ isAbacSubResourceValid,
163
+ isErrorsValid,
164
+ isStepsValid,
165
+ resolveExecutionIdsForChecks,
166
+ checkPerExecutionSub
167
+ };
@@ -0,0 +1,177 @@
1
+ /**
2
+ * @fileoverview Build matrix rows 1–9 for audit evidence verification
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const {
10
+ queryExecutions,
11
+ queryRbacDecisions,
12
+ queryAbacTraces,
13
+ getExecutionRbac,
14
+ getExecutionAbac,
15
+ getExecutionErrors,
16
+ getExecutionSteps,
17
+ getExecutionTrace
18
+ } = require('../api/audit.api');
19
+ const {
20
+ checkRow1ExecutionsByDatasource,
21
+ checkRow2RbacDecisionsList,
22
+ checkRow3AbacTracesList
23
+ } = require('./audit-evidence-matrix-rows');
24
+ const {
25
+ operationQueryVariants,
26
+ executionsCoverExpectedOperations
27
+ } = require('./audit-evidence-operation-aliases');
28
+ const {
29
+ checkRow8CorrelationGroup,
30
+ resolveRow8Executions,
31
+ checkRow9Traces,
32
+ isRbacSubResourceValid,
33
+ isAbacSubResourceValid,
34
+ isErrorsValid,
35
+ isStepsValid,
36
+ resolveExecutionIdsForChecks,
37
+ checkPerExecutionSub
38
+ } = require('./audit-evidence-verify-helpers');
39
+
40
+ /**
41
+ * @param {string} dataplaneUrl
42
+ * @param {Object} authConfig
43
+ * @param {string} correlationId
44
+ * @param {string[]} expectedOperations
45
+ * @returns {Promise<Array>}
46
+ */
47
+ async function fetchCorrelationExecutionsByOperation(
48
+ dataplaneUrl,
49
+ authConfig,
50
+ correlationId,
51
+ expectedOperations
52
+ ) {
53
+ const deduped = new Map();
54
+ for (const rawOp of expectedOperations) {
55
+ const variants = operationQueryVariants(rawOp);
56
+ for (const op of variants) {
57
+ const res = await queryExecutions(dataplaneUrl, authConfig, {
58
+ correlationId,
59
+ operation: op,
60
+ pageSize: 20
61
+ });
62
+ for (const row of res.data || []) {
63
+ if (row && row.id) deduped.set(String(row.id), row);
64
+ }
65
+ }
66
+ }
67
+ const merged = [...deduped.values()];
68
+ return executionsCoverExpectedOperations(merged, expectedOperations) ? merged : [];
69
+ }
70
+
71
+ /**
72
+ * @param {Object} ctx
73
+ * @param {Object} polled
74
+ * @param {number} minExpected
75
+ * @returns {Promise<import('../api/types/audit.types').AuditEvidenceMatrixRow[]>}
76
+ */
77
+ async function buildListMatrixRows(ctx, polled, minExpected) {
78
+ const executions = polled.data || [];
79
+ const { dataplaneUrl, authConfig } = ctx;
80
+ const totalItems =
81
+ polled.meta && polled.meta.totalItems !== undefined
82
+ ? polled.meta.totalItems
83
+ : executions.length;
84
+ const rows = [
85
+ checkRow1ExecutionsByDatasource({
86
+ executions,
87
+ totalItems,
88
+ minExpected
89
+ })
90
+ ];
91
+ const rbacList = await queryRbacDecisions(dataplaneUrl, authConfig, {
92
+ targetDatasourceKey: ctx.datasourceKey,
93
+ pageSize: 100
94
+ });
95
+ rows.push(
96
+ checkRow2RbacDecisionsList({
97
+ rbacItems: rbacList.data,
98
+ totalItems: rbacList.meta && rbacList.meta.totalItems
99
+ })
100
+ );
101
+ const abacList = await queryAbacTraces(dataplaneUrl, authConfig, {
102
+ datasourceKey: ctx.datasourceKey,
103
+ pageSize: 100
104
+ });
105
+ rows.push(
106
+ checkRow3AbacTracesList({
107
+ abacItems: abacList.data,
108
+ totalItems: abacList.meta && abacList.meta.totalItems
109
+ })
110
+ );
111
+ return rows;
112
+ }
113
+
114
+ /**
115
+ * @param {Object} ctx
116
+ * @param {Array} executions
117
+ * @param {string[]} executionIds
118
+ * @returns {Promise<{ rows: import('../api/types/audit.types').AuditEvidenceMatrixRow[], execIds: string[] }>}
119
+ */
120
+ async function buildPerExecutionAndTailRows(ctx, executions, executionIds) {
121
+ const { dataplaneUrl, authConfig } = ctx;
122
+ const execIds = resolveExecutionIdsForChecks(executions, executionIds);
123
+ const sampleId = execIds[0];
124
+ const base = { dataplaneUrl, authConfig, executionId: sampleId };
125
+ const rows = await Promise.all([
126
+ checkPerExecutionSub({ ...base, rowNum: 4, label: 'rbac', fetcher: getExecutionRbac, isValid: isRbacSubResourceValid }),
127
+ checkPerExecutionSub({ ...base, rowNum: 5, label: 'abac', fetcher: getExecutionAbac, isValid: isAbacSubResourceValid }),
128
+ checkPerExecutionSub({ ...base, rowNum: 6, label: 'errors', fetcher: getExecutionErrors, isValid: isErrorsValid }),
129
+ checkPerExecutionSub({ ...base, rowNum: 7, label: 'steps', fetcher: getExecutionSteps, isValid: isStepsValid })
130
+ ]);
131
+
132
+ let corrQueryRows = [];
133
+ if (ctx.correlationId) {
134
+ const corr = await queryExecutions(dataplaneUrl, authConfig, {
135
+ correlationId: ctx.correlationId,
136
+ pageSize: 100
137
+ });
138
+ corrQueryRows = corr.data || [];
139
+ }
140
+ let row8Pool = corrQueryRows.length ? corrQueryRows : executions;
141
+ const expected = ctx.expectedOperations || [];
142
+ if (expected.length && ctx.correlationId) {
143
+ const byOp = await fetchCorrelationExecutionsByOperation(
144
+ dataplaneUrl,
145
+ authConfig,
146
+ ctx.correlationId,
147
+ expected
148
+ );
149
+ if (byOp.length) row8Pool = byOp;
150
+ }
151
+ const row8Executions = resolveRow8Executions(ctx, executions, row8Pool);
152
+ rows.push(
153
+ checkRow8CorrelationGroup({
154
+ correlationId: ctx.correlationId,
155
+ executions: row8Executions,
156
+ expectedOperations: ctx.expectedOperations
157
+ })
158
+ );
159
+
160
+ const traceIds = new Set();
161
+ for (const id of execIds.slice(0, Math.min(execIds.length, 12))) {
162
+ try {
163
+ const tr = await getExecutionTrace(dataplaneUrl, authConfig, id);
164
+ if (tr && tr.executionId) traceIds.add(String(tr.executionId));
165
+ else if (tr && tr.id) traceIds.add(String(tr.id));
166
+ } catch {
167
+ /* row 9 may fail */
168
+ }
169
+ }
170
+ rows.push(checkRow9Traces(traceIds, execIds));
171
+ return { rows, execIds };
172
+ }
173
+
174
+ module.exports = {
175
+ buildListMatrixRows,
176
+ buildPerExecutionAndTailRows
177
+ };