@aifabrix/builder 2.45.0 → 2.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/.cursor/rules/cli-layout.mdc +2 -0
  2. package/.cursor/rules/cli-product-neutral.mdc +43 -0
  3. package/.cursor/rules/docs-rules.mdc +3 -1
  4. package/.cursor/rules/project-rules.mdc +1 -0
  5. package/README.md +43 -17
  6. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
  7. package/jest.config.default.js +2 -1
  8. package/jest.config.isolated.js +2 -1
  9. package/jest.global-live-fabrix-hooks.js +36 -0
  10. package/jest.isolated-projects.js +130 -0
  11. package/jest.projects.js +69 -121
  12. package/lib/api/agent-metadata-validation.api.js +93 -0
  13. package/lib/api/api-response-errors.js +124 -0
  14. package/lib/api/audit-api-helpers.js +68 -0
  15. package/lib/api/audit.api.js +119 -0
  16. package/lib/api/auth-cache.api.js +44 -0
  17. package/lib/api/certificates.api.js +4 -4
  18. package/lib/api/credential.api.js +2 -2
  19. package/lib/api/dataplane-health.api.js +137 -0
  20. package/lib/api/dataplane-sync.api.js +27 -0
  21. package/lib/api/datasources-core.api.js +21 -18
  22. package/lib/api/datasources-extended.api.js +22 -22
  23. package/lib/api/dimensions.api.js +3 -0
  24. package/lib/api/external-systems.api.js +13 -13
  25. package/lib/api/governance-scenario-pack.api.js +159 -0
  26. package/lib/api/governance-scenarios.api.js +39 -0
  27. package/lib/api/groups.api.js +79 -0
  28. package/lib/api/index.js +88 -5
  29. package/lib/api/lifecycle.api.js +77 -0
  30. package/lib/api/pipeline.api.js +7 -5
  31. package/lib/api/protection.api.js +157 -0
  32. package/lib/api/records-bulk.api.js +43 -0
  33. package/lib/api/records-search-parse.js +49 -0
  34. package/lib/api/records-search.api.js +29 -0
  35. package/lib/api/types/agent-metadata-validation.types.js +67 -0
  36. package/lib/api/types/audit.types.js +72 -0
  37. package/lib/api/types/dataplane-health.types.js +27 -0
  38. package/lib/api/types/dimensions.types.js +2 -0
  39. package/lib/api/types/governance-scenarios.types.js +39 -0
  40. package/lib/api/types/protection.types.js +69 -0
  41. package/lib/api/types/records-bulk.types.js +35 -0
  42. package/lib/api/types/records-search.types.js +28 -0
  43. package/lib/api/user-groups.api.js +50 -0
  44. package/lib/api/users.api.js +95 -0
  45. package/lib/api/validation-run.api.js +3 -3
  46. package/lib/api/validation-runner.js +5 -3
  47. package/lib/api/wizard-platform.api.js +3 -3
  48. package/lib/api/wizard.api.js +21 -21
  49. package/lib/app/deploy-config.js +4 -1
  50. package/lib/app/deploy.js +34 -19
  51. package/lib/app/down.js +20 -1
  52. package/lib/app/push.js +4 -5
  53. package/lib/app/register.js +7 -4
  54. package/lib/app/run-env-compose.js +84 -30
  55. package/lib/build/index.js +5 -0
  56. package/lib/certification/sync-system-certification.js +13 -6
  57. package/lib/cli/index.js +8 -2
  58. package/lib/cli/infra-guided-auth.js +109 -0
  59. package/lib/cli/infra-guided.js +91 -69
  60. package/lib/cli/setup-app.help.js +19 -2
  61. package/lib/cli/setup-app.js +58 -23
  62. package/lib/cli/setup-app.test-commands.js +28 -21
  63. package/lib/cli/setup-auth.js +55 -3
  64. package/lib/cli/setup-certification-commands.js +147 -0
  65. package/lib/cli/setup-certification.help.js +141 -0
  66. package/lib/cli/setup-environment.js +19 -2
  67. package/lib/cli/setup-external-system-help.js +62 -0
  68. package/lib/cli/setup-external-system.js +62 -6
  69. package/lib/cli/setup-infra.js +9 -1
  70. package/lib/cli/setup-platform.js +6 -1
  71. package/lib/cli/setup-secrets.js +33 -1
  72. package/lib/cli/setup-utility-help-after.js +65 -0
  73. package/lib/cli/setup-utility-repair.js +198 -0
  74. package/lib/cli/setup-utility-resolve.js +42 -6
  75. package/lib/cli/setup-utility-validate.js +197 -0
  76. package/lib/cli/setup-utility.js +41 -258
  77. package/lib/commands/auth-status-client-tokens.js +214 -0
  78. package/lib/commands/auth-status-dataplane-version.js +269 -0
  79. package/lib/commands/auth-status-display.js +94 -0
  80. package/lib/commands/auth-status.js +111 -53
  81. package/lib/commands/credential-push.js +10 -5
  82. package/lib/commands/datasource-load-export-cli.js +178 -0
  83. package/lib/commands/datasource-test-trust-cli.js +118 -0
  84. package/lib/commands/datasource-unified-test-cli.js +31 -20
  85. package/lib/commands/datasource-unified-test-cli.options.js +22 -3
  86. package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
  87. package/lib/commands/datasource-verify-audit-cli.js +96 -0
  88. package/lib/commands/datasource.js +68 -1
  89. package/lib/commands/dev-show-display.js +8 -1
  90. package/lib/commands/dimension-value.js +43 -13
  91. package/lib/commands/dimension.js +38 -7
  92. package/lib/commands/governance-cli-shared.js +94 -0
  93. package/lib/commands/governance-command-action.js +132 -0
  94. package/lib/commands/governance-download-external.js +34 -0
  95. package/lib/commands/governance-generate-external.js +71 -0
  96. package/lib/commands/governance-upload-external.js +36 -0
  97. package/lib/commands/governance-verify-external.js +64 -0
  98. package/lib/commands/governance.js +144 -0
  99. package/lib/commands/identity-apply-sync.js +131 -0
  100. package/lib/commands/identity-group-cli.js +146 -0
  101. package/lib/commands/identity-membership-role-cache.js +175 -0
  102. package/lib/commands/identity-shared.js +94 -0
  103. package/lib/commands/identity-user-cli.js +158 -0
  104. package/lib/commands/identity.js +43 -0
  105. package/lib/commands/lifecycle-command-action.js +123 -0
  106. package/lib/commands/lifecycle-external.js +268 -0
  107. package/lib/commands/login.js +56 -17
  108. package/lib/commands/protection-cli-leaves.js +286 -0
  109. package/lib/commands/protection.js +50 -0
  110. package/lib/commands/repair-auth-apply.js +127 -0
  111. package/lib/commands/repair-changed-files.js +41 -0
  112. package/lib/commands/repair-datasource-keys.js +4 -1
  113. package/lib/commands/repair-datasource-run.js +59 -0
  114. package/lib/commands/repair-datasource-test-payload.js +259 -0
  115. package/lib/commands/repair-datasource.js +1 -51
  116. package/lib/commands/repair-env-template.js +64 -13
  117. package/lib/commands/repair-external-run.js +216 -0
  118. package/lib/commands/repair-openapi-sync.js +23 -0
  119. package/lib/commands/repair-persist.js +4 -0
  120. package/lib/commands/repair-rbac.js +52 -1
  121. package/lib/commands/repair-steps.js +145 -0
  122. package/lib/commands/repair.js +29 -286
  123. package/lib/commands/secrets-get.js +184 -0
  124. package/lib/commands/secrets-remove-all.js +3 -1
  125. package/lib/commands/setup-image-refresh.js +146 -0
  126. package/lib/commands/setup-modes.js +158 -162
  127. package/lib/commands/setup-platform-auth.js +76 -0
  128. package/lib/commands/setup-prompts-admin.js +244 -0
  129. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  130. package/lib/commands/setup-prompts-validators.js +36 -0
  131. package/lib/commands/setup-prompts.js +24 -76
  132. package/lib/commands/setup-run-context.js +45 -0
  133. package/lib/commands/setup-spinners.js +39 -0
  134. package/lib/commands/setup.js +27 -5
  135. package/lib/commands/teardown.js +39 -0
  136. package/lib/commands/test-e2e-external.js +61 -14
  137. package/lib/commands/test-governance-cli-options.js +47 -0
  138. package/lib/commands/test-governance-external.js +67 -0
  139. package/lib/commands/test-trust-cli-options.js +32 -0
  140. package/lib/commands/test-trust-external.js +126 -0
  141. package/lib/commands/up-common.js +25 -13
  142. package/lib/commands/up-dataplane.js +50 -13
  143. package/lib/commands/upload-publish-context.js +75 -0
  144. package/lib/commands/upload-sidecar-followups.js +89 -0
  145. package/lib/commands/upload.js +108 -105
  146. package/lib/commands/verify-governance-combined-external.js +61 -0
  147. package/lib/commands/verify-governance-command-action.js +64 -0
  148. package/lib/commands/verify-governance-db.js +102 -0
  149. package/lib/commands/verify-governance-external.js +77 -0
  150. package/lib/commands/verify-governance-result-builders.js +71 -0
  151. package/lib/commands/verify-operations-command-action.js +68 -0
  152. package/lib/commands/verify-operations-external.js +268 -0
  153. package/lib/commands/verify-operations-persist.js +75 -0
  154. package/lib/commands/verify-operations-step-plan.js +68 -0
  155. package/lib/commands/verify-operations-steps.js +111 -0
  156. package/lib/commands/verify-trust-command-action.js +70 -0
  157. package/lib/commands/verify-trust-external.js +67 -0
  158. package/lib/commands/wizard-config-normalizer.js +43 -23
  159. package/lib/commands/wizard-core.js +5 -0
  160. package/lib/core/admin-password-generator.js +38 -0
  161. package/lib/core/admin-secrets-bundle.js +111 -0
  162. package/lib/core/admin-secrets-env-overlay.js +62 -0
  163. package/lib/core/admin-secrets.js +32 -4
  164. package/lib/core/config-attach-extensions.js +3 -0
  165. package/lib/core/config-device-dataplane.js +185 -0
  166. package/lib/core/config-platform-controller.js +44 -0
  167. package/lib/core/config-setup-installation-profile.js +42 -0
  168. package/lib/core/config-setup-platform-mode.js +46 -0
  169. package/lib/core/config.js +46 -36
  170. package/lib/core/secrets-admin-env.js +6 -2
  171. package/lib/core/secrets-ensure.js +4 -0
  172. package/lib/core/secrets-env-content.js +54 -48
  173. package/lib/core/secrets-env-write.js +10 -1
  174. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  175. package/lib/core/setup-installation-profile.js +43 -0
  176. package/lib/core/setup-platform-mode.js +55 -0
  177. package/lib/datasource/agent-trust-debug-log.js +45 -0
  178. package/lib/datasource/agent-trust-fetch.js +115 -0
  179. package/lib/datasource/agent-trust-map.js +101 -0
  180. package/lib/datasource/agent-trust-mock.js +44 -0
  181. package/lib/datasource/agent-trust-run.js +95 -0
  182. package/lib/datasource/agent-trust-timeout.js +25 -0
  183. package/lib/datasource/audit-evidence-display.js +80 -0
  184. package/lib/datasource/audit-evidence-extract-debug.js +115 -0
  185. package/lib/datasource/audit-evidence-extract.js +180 -0
  186. package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
  187. package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
  188. package/lib/datasource/audit-evidence-poll.js +109 -0
  189. package/lib/datasource/audit-evidence-run.js +177 -0
  190. package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
  191. package/lib/datasource/audit-evidence-verify-matrix.js +205 -0
  192. package/lib/datasource/audit-evidence-verify.js +108 -0
  193. package/lib/datasource/bulk-loader-run-batches.js +100 -0
  194. package/lib/datasource/bulk-loader-service-retry.js +52 -0
  195. package/lib/datasource/bulk-loader-service.js +127 -0
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -1
  197. package/lib/datasource/datasource-exporter-resolve.js +82 -0
  198. package/lib/datasource/datasource-exporter-service.js +144 -0
  199. package/lib/datasource/datasource-identifier.js +148 -0
  200. package/lib/datasource/datasource-load-export-context.js +95 -0
  201. package/lib/datasource/integration-context.js +6 -4
  202. package/lib/datasource/local-data-paths.js +145 -0
  203. package/lib/datasource/log-cleaner.js +241 -0
  204. package/lib/datasource/log-viewer.js +111 -6
  205. package/lib/datasource/record-file-parser.js +85 -0
  206. package/lib/datasource/record-mapper.js +129 -0
  207. package/lib/datasource/resolve-app.js +74 -55
  208. package/lib/datasource/test-e2e.js +29 -2
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run-resolve.js +45 -12
  211. package/lib/datasource/unified-validation-run.js +47 -18
  212. package/lib/datasource/validate.js +37 -20
  213. package/lib/deployment/environment-poll-status.js +138 -0
  214. package/lib/deployment/environment.js +42 -34
  215. package/lib/external-system/download.js +21 -20
  216. package/lib/external-system/generator.js +5 -1
  217. package/lib/external-system/integration-auth-context.js +45 -0
  218. package/lib/external-system/test-auth.js +12 -5
  219. package/lib/external-system/test-system-level.js +25 -4
  220. package/lib/external-system/test.js +9 -7
  221. package/lib/generator/external-controller-manifest.js +15 -0
  222. package/lib/governance/governance-cli-errors.js +96 -0
  223. package/lib/governance/governance-download-display.js +38 -0
  224. package/lib/governance/governance-pack-loader.js +70 -0
  225. package/lib/governance/governance-run-display.js +309 -0
  226. package/lib/identity/identity-apply-core.js +108 -0
  227. package/lib/identity/identity-apply-phases.js +244 -0
  228. package/lib/identity/identity-apply-service.js +77 -0
  229. package/lib/identity/identity-csv-parser.js +114 -0
  230. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  231. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  232. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  233. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  234. package/lib/infrastructure/helpers.js +23 -129
  235. package/lib/infrastructure/index.js +5 -6
  236. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  237. package/lib/internal/fs-real-sync.js +29 -1
  238. package/lib/lifecycle/certification-progress.js +231 -0
  239. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  240. package/lib/lifecycle/exit-codes.js +24 -0
  241. package/lib/lifecycle/json-envelope.js +25 -0
  242. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  243. package/lib/lifecycle/logger-quiet.js +29 -0
  244. package/lib/lifecycle/open-api-published.js +59 -0
  245. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  246. package/lib/lifecycle/product-model.js +196 -0
  247. package/lib/lifecycle/report-display.js +471 -0
  248. package/lib/lifecycle/scenario-upload.js +191 -0
  249. package/lib/lifecycle/verify-step-progress.js +87 -0
  250. package/lib/parameters/infra-kv-discovery.js +27 -2
  251. package/lib/protection/auth-context.js +51 -0
  252. package/lib/protection/convert-batch.js +90 -0
  253. package/lib/protection/load.js +41 -0
  254. package/lib/protection/paths.js +158 -0
  255. package/lib/protection/preflight-datasource-ready.js +46 -0
  256. package/lib/protection/protection-create-probe-lines.js +142 -0
  257. package/lib/protection/protection-create-probes.js +95 -0
  258. package/lib/protection/protection-create-scaffold.js +281 -0
  259. package/lib/protection/protection-display-helpers.js +445 -0
  260. package/lib/protection/protection-display.js +215 -0
  261. package/lib/protection/protection-preset-registry.js +97 -0
  262. package/lib/protection/report-exit.js +62 -0
  263. package/lib/protection/resolve.js +202 -0
  264. package/lib/protection/run-commands-validate.js +130 -0
  265. package/lib/protection/run-commands.js +216 -0
  266. package/lib/protection/run-protection-create-helpers.js +134 -0
  267. package/lib/protection/run-protection-create-probes-flow.js +43 -0
  268. package/lib/protection/run-protection-create.js +191 -0
  269. package/lib/protection/scope.js +22 -0
  270. package/lib/protection/sync-after-upload.js +64 -0
  271. package/lib/protection/upload-batch.js +127 -0
  272. package/lib/protection/validate-batch.js +113 -0
  273. package/lib/protection/validate-local.js +65 -0
  274. package/lib/resolvers/dimension-file.js +29 -4
  275. package/lib/schema/application-schema.json +1 -1
  276. package/lib/schema/datasource-test-run.schema.json +89 -6
  277. package/lib/schema/external-datasource.schema.json +2636 -2588
  278. package/lib/schema/external-system.schema.json +1089 -761
  279. package/lib/schema/flag-map-validation-run.json +2 -2
  280. package/lib/schema/infra.parameter.yaml +45 -0
  281. package/lib/schema/protection.schema.json +374 -0
  282. package/lib/schema/type/credential-field-registry.json +642 -0
  283. package/lib/schema/wizard-config.schema.json +1 -1
  284. package/lib/utils/agent-trust-run-display.js +231 -0
  285. package/lib/utils/agent-trust-run-exit.js +59 -0
  286. package/lib/utils/agent-trust-wait-ui.js +94 -0
  287. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  288. package/lib/utils/api.js +55 -31
  289. package/lib/utils/app-relative-path-env.js +112 -0
  290. package/lib/utils/cli-exit-codes.js +30 -0
  291. package/lib/utils/cli-secrets-error-format.js +83 -21
  292. package/lib/utils/cli-sync-options.js +33 -0
  293. package/lib/utils/cli-utils.js +16 -4
  294. package/lib/utils/compose-generate-docker-compose.js +4 -0
  295. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  296. package/lib/utils/config-secrets-path.js +46 -0
  297. package/lib/utils/controller-url.js +88 -1
  298. package/lib/utils/credential-push-ui.js +90 -0
  299. package/lib/utils/credential-secrets-env.js +137 -9
  300. package/lib/utils/dataplane-cli-version-gate.js +202 -0
  301. package/lib/utils/dataplane-cli-version-help.js +74 -0
  302. package/lib/utils/dataplane-resolver.js +129 -2
  303. package/lib/utils/datasource-export-display.js +137 -0
  304. package/lib/utils/datasource-load-display.js +174 -0
  305. package/lib/utils/datasource-load-export-ui.js +120 -0
  306. package/lib/utils/datasource-test-run-capability-scope.js +3 -3
  307. package/lib/utils/datasource-test-run-display.js +3 -3
  308. package/lib/utils/datasource-test-run-tty-log.js +5 -1
  309. package/lib/utils/declarative-url-ports.js +3 -3
  310. package/lib/utils/deployment-auth-mode.js +41 -0
  311. package/lib/utils/developer-volume-id.js +33 -0
  312. package/lib/utils/env-copy.js +14 -9
  313. package/lib/utils/env-kv-orphan-lines.js +43 -0
  314. package/lib/utils/error-formatters/network-errors.js +13 -4
  315. package/lib/utils/external-env-template.js +1 -0
  316. package/lib/utils/external-system-readiness-core.js +10 -0
  317. package/lib/utils/external-system-readiness-display.js +80 -23
  318. package/lib/utils/health-check.js +4 -1
  319. package/lib/utils/help-builder.js +35 -26
  320. package/lib/utils/keycloak-realm-ready.js +101 -0
  321. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  322. package/lib/utils/manifest-source-emit.js +24 -0
  323. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  324. package/lib/utils/platform-controller-url.js +156 -0
  325. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  326. package/lib/utils/postgres-wipe.js +9 -2
  327. package/lib/utils/resolve-env-mode.js +47 -0
  328. package/lib/utils/secrets-generator.js +31 -25
  329. package/lib/utils/secrets-missing-error.js +164 -0
  330. package/lib/utils/semver-compare.js +127 -0
  331. package/lib/utils/service-url-label.js +81 -0
  332. package/lib/utils/setup-quiet-output.js +25 -0
  333. package/lib/utils/template-helpers.js +15 -0
  334. package/lib/utils/token-manager-client-credentials.js +201 -0
  335. package/lib/utils/token-manager-messages.js +8 -0
  336. package/lib/utils/token-manager-refresh.js +12 -2
  337. package/lib/utils/token-manager.js +86 -105
  338. package/lib/utils/upload-pipeline-ui.js +98 -0
  339. package/lib/utils/upload-sync-options.js +42 -0
  340. package/lib/utils/url-declarative-public-base.js +21 -3
  341. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  342. package/lib/utils/validation-poll-ui.js +22 -7
  343. package/lib/utils/validation-run-stage.js +45 -0
  344. package/lib/validation/wizard-config-validator.js +58 -19
  345. package/package.json +1 -1
  346. package/templates/applications/dataplane/application.yaml +2 -1
  347. package/templates/applications/dataplane/env.template +36 -1
  348. package/templates/applications/dataplane/rbac.yaml +4 -0
  349. package/templates/applications/miso-controller/env.template +16 -0
  350. package/templates/external-system/README.md.hbs +116 -11
  351. package/templates/python/docker-compose.hbs +19 -18
  352. package/templates/typescript/docker-compose.hbs +18 -17
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @fileoverview TTY summary when governance download finds no active packs.
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const chalk = require('chalk');
8
+ const { failureGlyph } = require('../utils/cli-test-layout-chalk');
9
+ const logger = require('../utils/logger');
10
+
11
+ /**
12
+ * @param {Array<{ datasourceKey: string, reason: string }>} missing
13
+ */
14
+ function printGovernanceDownloadMisses(missing) {
15
+ if (!missing || missing.length === 0) {
16
+ return;
17
+ }
18
+ for (const row of missing) {
19
+ logger.log(
20
+ chalk.white(`${row.datasourceKey}: ${failureGlyph()} ${row.reason}`)
21
+ );
22
+ }
23
+ logger.log('');
24
+ logger.log(chalk.gray('Next steps:'));
25
+ logger.log(
26
+ chalk.gray(
27
+ ' • Run: aifabrix governance generate <systemKey> --subject-email <email>'
28
+ )
29
+ );
30
+ logger.log(
31
+ chalk.gray(' • Or use: aifabrix verify-governance <systemKey> --subject-email <email>')
32
+ );
33
+ logger.log(chalk.gray(' • Ensure protection is published and identity sync has run'));
34
+ }
35
+
36
+ module.exports = {
37
+ printGovernanceDownloadMisses
38
+ };
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Load governance scenario pack YAML from integration folder
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const yaml = require('js-yaml');
12
+ const { getIntegrationPath } = require('../utils/paths');
13
+
14
+ /**
15
+ * Resolve pack file path for test-governance.
16
+ * @param {string} systemKey
17
+ * @param {Object} options
18
+ * @param {string} [options.pack] - Explicit path (absolute or relative to integration root)
19
+ * @param {string} [options.app] - Integration folder override
20
+ * @returns {string}
21
+ */
22
+ function resolveGovernancePackPath(systemKey, options = {}) {
23
+ const integrationPath = options.app
24
+ ? path.isAbsolute(options.app)
25
+ ? options.app
26
+ : path.resolve(process.cwd(), options.app)
27
+ : getIntegrationPath(systemKey);
28
+
29
+ if (options.pack) {
30
+ const packPath = path.isAbsolute(options.pack)
31
+ ? options.pack
32
+ : path.join(integrationPath, options.pack);
33
+ if (!fs.existsSync(packPath)) {
34
+ throw new Error(`Scenario pack not found: ${packPath}`);
35
+ }
36
+ return packPath;
37
+ }
38
+
39
+ const candidates = [
40
+ path.join(integrationPath, 'scenarios', 'default.yaml'),
41
+ path.join(integrationPath, 'scenarios', `${systemKey}-v1.yaml`)
42
+ ];
43
+ for (const candidate of candidates) {
44
+ if (fs.existsSync(candidate)) {
45
+ return candidate;
46
+ }
47
+ }
48
+ throw new Error(
49
+ `No scenario pack found under ${path.join(integrationPath, 'scenarios')}. ` +
50
+ 'Use --pack <path> (e.g. scenarios/test-protection-v1.yaml).'
51
+ );
52
+ }
53
+
54
+ /**
55
+ * @param {string} packPath
56
+ * @returns {Object}
57
+ */
58
+ function loadGovernancePackYaml(packPath) {
59
+ const raw = fs.readFileSync(packPath, 'utf8');
60
+ const doc = yaml.load(raw);
61
+ if (!doc || typeof doc !== 'object') {
62
+ throw new Error(`Invalid scenario pack YAML: ${packPath}`);
63
+ }
64
+ return doc;
65
+ }
66
+
67
+ module.exports = {
68
+ resolveGovernancePackPath,
69
+ loadGovernancePackYaml
70
+ };
@@ -0,0 +1,309 @@
1
+ /**
2
+ * @fileoverview TTY display for governance scenario acceptance runs
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 {
12
+ sectionTitle,
13
+ headerKeyValue,
14
+ metadata: metaGray,
15
+ formatSuccessParagraph,
16
+ formatBlockingError
17
+ } = require('../utils/cli-test-layout-chalk');
18
+
19
+ const SEP = '────────────────────────';
20
+ const MAX_SAMPLE_KEYS = 5;
21
+
22
+ /**
23
+ * @param {Object|null|undefined} packDocument
24
+ * @returns {Map<string, { mustIncludeKeys: string[], mustExcludeKeys: string[] }>}
25
+ */
26
+ function buildScenarioExpectMap(packDocument) {
27
+ const map = new Map();
28
+ const scenarios = packDocument?.spec?.scenarios;
29
+ if (!Array.isArray(scenarios)) {
30
+ return map;
31
+ }
32
+ for (const scenario of scenarios) {
33
+ if (!scenario || typeof scenario.id !== 'string') {
34
+ continue;
35
+ }
36
+ const expect = scenario.expect || {};
37
+ map.set(scenario.id, {
38
+ mustIncludeKeys: Array.isArray(expect.mustIncludeKeys) ? expect.mustIncludeKeys : [],
39
+ mustExcludeKeys: Array.isArray(expect.mustExcludeKeys) ? expect.mustExcludeKeys : []
40
+ });
41
+ }
42
+ return map;
43
+ }
44
+
45
+ /**
46
+ * @param {string[]} keys
47
+ * @param {number} [maxKeys]
48
+ * @returns {string}
49
+ */
50
+ function formatKeySample(keys, maxKeys = MAX_SAMPLE_KEYS) {
51
+ if (!Array.isArray(keys) || keys.length === 0) {
52
+ return '—';
53
+ }
54
+ const slice = keys.slice(0, maxKeys);
55
+ const suffix = keys.length > maxKeys ? ` (+${keys.length - maxKeys} more)` : '';
56
+ return `${slice.join(', ')}${suffix}`;
57
+ }
58
+
59
+ /**
60
+ * @param {'pass'|'fail'} status
61
+ * @returns {string}
62
+ */
63
+ function scenarioGlyph(status) {
64
+ return status === 'pass' ? chalk.green('✔') : chalk.red('✖');
65
+ }
66
+
67
+ /**
68
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenarioResult} scenario
69
+ */
70
+ function logGovernanceScenarioSubjectLines(scenario) {
71
+ logger.log(` ${scenarioGlyph(scenario.status)} ${scenario.id}`);
72
+ logger.log(metaGray(` Subject email: ${scenario.subjectEmail || '—'}`));
73
+ if (scenario.subjectDisplayName) {
74
+ logger.log(
75
+ metaGray(
76
+ ` Subject: ${scenario.subjectDisplayName} (${scenario.subjectUserId || '—'})`
77
+ )
78
+ );
79
+ }
80
+ logger.log(metaGray(` Verdict: ${scenario.verdict || '—'}`));
81
+ }
82
+
83
+ /**
84
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenarioResult} scenario
85
+ */
86
+ function logGovernanceScenarioCounts(scenario) {
87
+ const visible = typeof scenario.visibleKeyCount === 'number' ? scenario.visibleKeyCount : 0;
88
+ const abac = typeof scenario.excludedAbac === 'number' ? scenario.excludedAbac : 0;
89
+ const filter = typeof scenario.excludedFilter === 'number' ? scenario.excludedFilter : 0;
90
+ logger.log(metaGray(` Visible keys: ${visible} allowed`));
91
+ logger.log(metaGray(` Declined: ${abac} by ABAC · ${filter} by filter`));
92
+ }
93
+
94
+ /**
95
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenarioResult} scenario
96
+ * @param {{ mustIncludeKeys: string[], mustExcludeKeys: string[] }} expect
97
+ */
98
+ function logGovernanceScenarioPassSamples(expect) {
99
+ const allowed =
100
+ expect.mustIncludeKeys.length > 0 ? formatKeySample(expect.mustIncludeKeys) : '—';
101
+ const blocked =
102
+ expect.mustExcludeKeys.length > 0 ? formatKeySample(expect.mustExcludeKeys) : '—';
103
+ logger.log(metaGray(` Sample allowed: ${allowed}`));
104
+ logger.log(metaGray(` Sample blocked: ${blocked}`));
105
+ }
106
+
107
+ /**
108
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenarioResult} scenario
109
+ */
110
+ function logGovernanceScenarioFailSamples(scenario) {
111
+ if (scenario.missingRequiredKeys?.length) {
112
+ logger.log(
113
+ metaGray(` Missing keys: ${formatKeySample(scenario.missingRequiredKeys)}`)
114
+ );
115
+ }
116
+ if (scenario.unexpectedVisibleKeys?.length) {
117
+ logger.log(
118
+ metaGray(` Unexpected: ${formatKeySample(scenario.unexpectedVisibleKeys)}`)
119
+ );
120
+ }
121
+ if (scenario.fixHint) {
122
+ logger.log(metaGray(` Fix: ${scenario.fixHint}`));
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenarioResult} scenario
128
+ * @param {Map<string, { mustIncludeKeys: string[], mustExcludeKeys: string[] }>} expectMap
129
+ */
130
+ function logGovernanceScenarioDetail(scenario, expectMap) {
131
+ const expect = expectMap.get(scenario.id) || {
132
+ mustIncludeKeys: [],
133
+ mustExcludeKeys: []
134
+ };
135
+ logGovernanceScenarioSubjectLines(scenario);
136
+ logGovernanceScenarioCounts(scenario);
137
+ if (scenario.status === 'pass') {
138
+ logGovernanceScenarioPassSamples(expect);
139
+ } else {
140
+ logGovernanceScenarioFailSamples(scenario);
141
+ }
142
+ if (scenario.subjectGroups?.length) {
143
+ logger.log(metaGray(` Groups: ${scenario.subjectGroups.join(', ')}`));
144
+ }
145
+ if (scenario.auditRef) {
146
+ logger.log(metaGray(` Audit: ${scenario.auditRef}`));
147
+ }
148
+ }
149
+
150
+ /**
151
+ * One datasource block for verify-governance -v.
152
+ * @param {Object} row
153
+ * @param {string} row.datasourceKey
154
+ * @param {Object} [row.result]
155
+ * @param {Object} [row.packDocument]
156
+ * @param {string} [row.packPath]
157
+ * @param {string} [row.error]
158
+ */
159
+ function displayGovernanceDatasourceVerbose(row) {
160
+ logger.log('');
161
+ logger.log(chalk.white(`Datasource: ${row.datasourceKey}`));
162
+ if (row.error) {
163
+ logger.log(formatBlockingError(row.error));
164
+ return;
165
+ }
166
+ const run = row.result;
167
+ if (!run || !run.summary) {
168
+ logger.log(metaGray(' No scenario run result (pack missing or run skipped).'));
169
+ return;
170
+ }
171
+ logger.log(headerKeyValue('Pack:', run.packKey || '—'));
172
+ if (row.packPath) {
173
+ logger.log(metaGray(` File: ${row.packPath}`));
174
+ }
175
+ const summary = run.summary;
176
+ logger.log(
177
+ headerKeyValue('Scenarios:', `${summary.passed || 0}/${summary.total || 0} passed`)
178
+ );
179
+ const expectMap = buildScenarioExpectMap(row.packDocument);
180
+ for (const scenario of run.scenarios || []) {
181
+ logGovernanceScenarioDetail(scenario, expectMap);
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Verbose (-v) scenario breakdown for verify-governance / governance verify.
187
+ * @param {Object} result
188
+ */
189
+ function displayGovernanceVerboseDetails(result) {
190
+ if (!result) {
191
+ return;
192
+ }
193
+ logger.log('');
194
+ logger.log(chalk.white('Scenario results'));
195
+ logger.log(metaGray(SEP));
196
+ logger.log(metaGray('Key sets only — no record payloads.'));
197
+
198
+ if (result.legacyResult && result.legacyResult.summary) {
199
+ const dsKey =
200
+ result.packDatasourceKey ||
201
+ primaryDatasourceFromPack(result.packDocument) ||
202
+ 'scenario pack';
203
+ displayGovernanceDatasourceVerbose({
204
+ datasourceKey: dsKey,
205
+ result: result.legacyResult,
206
+ packDocument: result.packDocument,
207
+ packPath: result.packPath
208
+ });
209
+ logger.log('');
210
+ return;
211
+ }
212
+
213
+ const rows = result.datasourceRows || [];
214
+ if (rows.length === 0) {
215
+ logger.log(metaGray(' No datasource scenario packs were run.'));
216
+ logger.log('');
217
+ return;
218
+ }
219
+ for (const row of rows) {
220
+ displayGovernanceDatasourceVerbose(row);
221
+ }
222
+ logger.log('');
223
+ }
224
+
225
+ /**
226
+ * @param {string} systemKey
227
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenariosRunResponse} result
228
+ * @param {{ verbose?: boolean, packPath?: string }} opts
229
+ */
230
+ function displayGovernanceRunTTY(systemKey, result, opts = {}) {
231
+ const agg = result.summary.failed > 0 ? 'fail' : 'ok';
232
+ logger.log(SEP);
233
+ logger.log(sectionTitle('Governed search acceptance (key sets only — no record payload)'));
234
+ logger.log(headerKeyValue('System:', systemKey));
235
+ logger.log(headerKeyValue('Pack:', result.packKey));
236
+ if (opts.packPath) {
237
+ logger.log(metaGray(` File: ${opts.packPath}`));
238
+ }
239
+ logger.log(
240
+ headerKeyValue(
241
+ 'Summary:',
242
+ `${result.summary.passed}/${result.summary.total} passed`
243
+ )
244
+ );
245
+ logger.log(metaGray(' Does not call vendor APIs (use test-e2e for connectivity).'));
246
+ logger.log('');
247
+ const expectMap = buildScenarioExpectMap(opts.packDocument);
248
+ for (const scenario of result.scenarios || []) {
249
+ if (opts.verbose === true) {
250
+ logGovernanceScenarioDetail(scenario, expectMap);
251
+ } else {
252
+ logger.log(` ${scenarioGlyph(scenario.status)} ${scenario.verdict}`);
253
+ }
254
+ }
255
+ logger.log('');
256
+ if (agg === 'ok') {
257
+ logger.log(formatSuccessParagraph('All governance scenarios passed'));
258
+ } else {
259
+ logger.log(formatBlockingError(`${result.summary.failed} scenario(s) failed`));
260
+ }
261
+ logger.log(SEP);
262
+ }
263
+
264
+ /**
265
+ * @param {import('../api/types/governance-scenarios.types').GovernanceScenariosRunResponse} result
266
+ */
267
+ function printGovernanceRunJson(result) {
268
+ logger.log(JSON.stringify(result, null, 2));
269
+ }
270
+
271
+ /**
272
+ * @param {{ total: number, passed: number, failed: number }} summary
273
+ * @returns {number}
274
+ */
275
+ function exitCodeFromGovernanceSummary(summary) {
276
+ if (!summary || summary.failed > 0) {
277
+ return 1;
278
+ }
279
+ return 0;
280
+ }
281
+
282
+ /**
283
+ * @param {Object|null|undefined} packDocument
284
+ * @returns {string|null}
285
+ */
286
+ function primaryDatasourceFromPack(packDocument) {
287
+ const scenarios = packDocument?.spec?.scenarios;
288
+ if (!Array.isArray(scenarios)) {
289
+ return null;
290
+ }
291
+ for (const scenario of scenarios) {
292
+ const keys = scenario?.search?.datasourceKeys;
293
+ if (Array.isArray(keys) && keys.length > 0 && typeof keys[0] === 'string') {
294
+ return keys[0];
295
+ }
296
+ }
297
+ return null;
298
+ }
299
+
300
+ module.exports = {
301
+ buildScenarioExpectMap,
302
+ formatKeySample,
303
+ displayGovernanceDatasourceVerbose,
304
+ displayGovernanceVerboseDetails,
305
+ displayGovernanceRunTTY,
306
+ printGovernanceRunJson,
307
+ exitCodeFromGovernanceSummary,
308
+ primaryDatasourceFromPack
309
+ };
@@ -0,0 +1,108 @@
1
+ /**
2
+ * @fileoverview Shared helpers for identity apply
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getUser, listUsers } = require('../api/users.api');
10
+
11
+ /**
12
+ * @param {Object} response
13
+ * @returns {any}
14
+ */
15
+ function unwrapControllerData(response) {
16
+ if (!response || response.success === false) {
17
+ return null;
18
+ }
19
+ return response?.data?.data ?? response?.data ?? response;
20
+ }
21
+
22
+ /**
23
+ * @param {Object} response
24
+ * @returns {string}
25
+ */
26
+ function apiErrorMessage(response) {
27
+ if (!response) {
28
+ return 'Request failed';
29
+ }
30
+ const err = response.error;
31
+ if (typeof err === 'string') {
32
+ return err;
33
+ }
34
+ if (err && typeof err === 'object') {
35
+ return err.formattedError || err.message || err.error || 'Request failed';
36
+ }
37
+ return response.formattedError || response.message || 'Request failed';
38
+ }
39
+
40
+ /**
41
+ * @param {Object} response
42
+ * @throws {Error}
43
+ */
44
+ function throwIfApiFailed(response) {
45
+ if (!response || response.success === false) {
46
+ throw new Error(apiErrorMessage(response));
47
+ }
48
+ }
49
+
50
+ /**
51
+ * @param {Object|null|undefined} stats
52
+ * @param {{ allowEmptySync?: boolean }} [opts]
53
+ * @throws {Error}
54
+ */
55
+ function assertSyncStatsOk(stats, opts = {}) {
56
+ const syncErrors = Number(stats?.errors ?? 0);
57
+ if (syncErrors > 0) {
58
+ throw new Error(
59
+ `Dataplane full sync reported ${syncErrors} error(s). ` +
60
+ `usersProcessed=${stats?.usersProcessed ?? 0} groupsProcessed=${stats?.groupsProcessed ?? 0}. ` +
61
+ 'Check miso-controller logs for the sync request.'
62
+ );
63
+ }
64
+ const processed = Number(stats?.usersProcessed ?? 0);
65
+ if (processed === 0 && !opts.allowEmptySync) {
66
+ throw new Error(
67
+ 'Dataplane full sync completed with usersProcessed=0. Use --allow-empty-sync to accept, or fix identity on the controller.'
68
+ );
69
+ }
70
+ }
71
+
72
+ /**
73
+ * @async
74
+ * @param {string} controllerUrl
75
+ * @param {Object} authConfig
76
+ * @param {{ csvId?: string, email: string }} userSpec
77
+ * @returns {Promise<Object|null>}
78
+ */
79
+ async function findExistingUser(controllerUrl, authConfig, userSpec) {
80
+ const csvId = String(userSpec.csvId || '').trim();
81
+ if (csvId) {
82
+ const byId = await getUser(controllerUrl, authConfig, csvId);
83
+ const row = unwrapControllerData(byId);
84
+ if (row && row.id) {
85
+ return row;
86
+ }
87
+ }
88
+ const email = String(userSpec.email || '').trim();
89
+ const listed = await listUsers(controllerUrl, authConfig, {
90
+ search: email,
91
+ pageSize: 10,
92
+ page: 1
93
+ });
94
+ const items = unwrapControllerData(listed);
95
+ const list = Array.isArray(items) ? items : items?.data;
96
+ if (!Array.isArray(list)) {
97
+ return null;
98
+ }
99
+ return list.find((u) => String(u.email || '').toLowerCase() === email.toLowerCase()) || null;
100
+ }
101
+
102
+ module.exports = {
103
+ unwrapControllerData,
104
+ apiErrorMessage,
105
+ throwIfApiFailed,
106
+ assertSyncStatsOk,
107
+ findExistingUser
108
+ };