@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,445 @@
1
+ /**
2
+ * @fileoverview Helpers for protection TTY formatters (keeps display module under limits).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const chalk = require('chalk');
10
+ const {
11
+ sectionTitle,
12
+ headerKeyValue,
13
+ metadata,
14
+ formatStatusKeyValue,
15
+ formatBlockingError,
16
+ formatSuccessLine,
17
+ formatWarningLine
18
+ } = require('../utils/cli-test-layout-chalk');
19
+
20
+ const SEP = chalk.gray('────────────────────────────────────────');
21
+
22
+ /**
23
+ * @param {Object} row
24
+ * @returns {string}
25
+ */
26
+ function taskStableCode(row) {
27
+ return String(row?.errorCode || row?.stableCode || row?.taskId || 'ISSUE');
28
+ }
29
+
30
+ /**
31
+ * @param {string[]} lines
32
+ * @param {Object[]} rows
33
+ * @param {'FAIL'|'WARN'|'PASS'} status
34
+ * @param {Object} opts
35
+ */
36
+ function appendTaskRows(lines, rows, status, opts = {}) {
37
+ const cap = opts.verbose ? rows.length : Math.min(rows.length, opts.maxIssues || 10);
38
+ const filtered = rows.filter((r) => String(r?.status || '').toUpperCase() === status);
39
+ if (!filtered.length) {
40
+ return;
41
+ }
42
+ const title =
43
+ status === 'FAIL'
44
+ ? 'Validation issues:'
45
+ : status === 'WARN'
46
+ ? 'Warnings:'
47
+ : 'Checks passed:';
48
+ lines.push(sectionTitle(title));
49
+ for (let i = 0; i < Math.min(cap, filtered.length); i += 1) {
50
+ const row = filtered[i];
51
+ const code = taskStableCode(row);
52
+ const msg = row?.message ? String(row.message) : '';
53
+ const prefix = status === 'FAIL' ? '✖' : status === 'WARN' ? '⚠' : '✔';
54
+ const lineFn = status === 'WARN' ? formatWarningLine : (t) => t;
55
+ lines.push(lineFn(` ${prefix} ${code} ${msg}`.trim()));
56
+ if (row?.hint) {
57
+ lines.push(chalk.gray(` hint: ${row.hint}`));
58
+ }
59
+ if (row?.schemaPath) {
60
+ lines.push(chalk.gray(` path: ${row.schemaPath}`));
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * @param {string[]} lines
67
+ * @param {Object} meta
68
+ */
69
+ function appendProtectionReportHeader(lines, meta) {
70
+ if (meta.protectionKey) {
71
+ lines.push(headerKeyValue('Protection:', meta.protectionKey));
72
+ }
73
+ if (meta.datasourceKey) {
74
+ lines.push(headerKeyValue('Datasource:', meta.datasourceKey));
75
+ }
76
+ }
77
+
78
+ /**
79
+ * @param {string[]} lines
80
+ * @param {Object} sim
81
+ */
82
+ function appendSimulationSection(lines, sim) {
83
+ lines.push(sectionTitle('Simulation:'));
84
+ if (sim.recordsSampled !== undefined && sim.recordsSampled !== null) {
85
+ lines.push(` Records sampled: ${sim.recordsSampled}`);
86
+ }
87
+ if (sim.grantsProjected !== undefined && sim.grantsProjected !== null) {
88
+ lines.push(` Grants projected: ${sim.grantsProjected}`);
89
+ }
90
+ if (sim.unresolvedPrincipals !== undefined && sim.unresolvedPrincipals !== null) {
91
+ lines.push(` Unresolved principals: ${sim.unresolvedPrincipals}`);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * @param {string[]} lines
97
+ * @param {number} failCount
98
+ * @param {number} warnCount
99
+ * @param {Object} opts
100
+ */
101
+ function appendValidationSummarySection(lines, failCount, warnCount, opts) {
102
+ lines.push(sectionTitle('Summary:'));
103
+ if (failCount > 0 || (opts.warningsAsErrors && warnCount > 0)) {
104
+ lines.push(formatBlockingError('Validation failed'));
105
+ lines.push(headerKeyValue('Overall:', 'Failed'));
106
+ return;
107
+ }
108
+ lines.push(formatSuccessLine('Validation passed'));
109
+ lines.push(headerKeyValue('Overall:', warnCount > 0 ? 'Warnings' : 'OK'));
110
+ }
111
+
112
+ /**
113
+ * @param {string[]} lines
114
+ * @param {Object[]} results
115
+ * @param {Object} opts
116
+ * @param {string} okLabel
117
+ */
118
+ function appendBatchResultRows(lines, results, okLabel) {
119
+ for (const row of results) {
120
+ if (row.ok) {
121
+ lines.push(`${row.datasourceKey}`);
122
+ lines.push(formatSuccessLine(` ${okLabel}`));
123
+ } else {
124
+ lines.push(`${row.datasourceKey}`);
125
+ lines.push(formatBlockingError(` ${row.error || 'Failed'}`));
126
+ }
127
+ lines.push('');
128
+ }
129
+ }
130
+
131
+ /**
132
+ * @param {string[]} lines
133
+ * @param {number} passed
134
+ * @param {number} failed
135
+ * @param {string} okMessage
136
+ */
137
+ function appendBatchSummary(lines, passed, failed, okMessage) {
138
+ lines.push(sectionTitle('Summary:'));
139
+ if (failed > 0) {
140
+ lines.push(formatBlockingError(`${passed} passed, ${failed} failed`));
141
+ lines.push(headerKeyValue('Overall:', 'Failed'));
142
+ return;
143
+ }
144
+ lines.push(formatSuccessLine(okMessage));
145
+ lines.push(headerKeyValue('Overall:', 'OK'));
146
+ }
147
+
148
+ /**
149
+ * @param {Object} manifest
150
+ * @param {Object} status
151
+ * @returns {string}
152
+ */
153
+ function protectionShowDatasourceKey(manifest, status) {
154
+ return manifest?.datasourceKey || status?.datasourceKey || '—';
155
+ }
156
+
157
+ /**
158
+ * Stacked label + value (wraps long protection keys and hashes cleanly).
159
+ * @param {string[]} lines
160
+ * @param {string} label
161
+ * @param {string|number|null|undefined} value
162
+ */
163
+ function appendProtectionShowField(lines, label, value) {
164
+ const text =
165
+ value === null || value === undefined || String(value).trim() === '' ? '—' : String(value);
166
+ lines.push(chalk.gray(label));
167
+ lines.push(` ${chalk.bold.white(text)}`);
168
+ }
169
+
170
+ /**
171
+ * @param {string[]} lines
172
+ * @param {string} title
173
+ */
174
+ function appendProtectionShowSection(lines, title) {
175
+ lines.push('');
176
+ lines.push(sectionTitle(title));
177
+ lines.push(SEP);
178
+ }
179
+
180
+ /**
181
+ * @param {string|undefined|null} iso
182
+ * @returns {string}
183
+ */
184
+ function formatProtectionShowTimestamp(iso) {
185
+ if (!iso || String(iso).trim() === '' || iso === '—') {
186
+ return '—';
187
+ }
188
+ const d = new Date(iso);
189
+ if (Number.isNaN(d.getTime())) {
190
+ return String(iso);
191
+ }
192
+ return d.toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, ' UTC');
193
+ }
194
+
195
+ /**
196
+ * @param {string|undefined|null} hash
197
+ * @param {boolean} [verbose]
198
+ * @returns {string}
199
+ */
200
+ function formatProtectionShowHash(hash, verbose) {
201
+ if (!hash || String(hash).trim() === '') {
202
+ return '—';
203
+ }
204
+ const s = String(hash);
205
+ if (verbose || s.length <= 24) {
206
+ return s;
207
+ }
208
+ return `${s.slice(0, 8)}…${s.slice(-6)}`;
209
+ }
210
+
211
+ /**
212
+ * @param {string[]} lines
213
+ * @param {Object} status
214
+ * @param {Object} manifest
215
+ */
216
+ function appendProtectionShowProjectionSection(lines, status, manifest) {
217
+ const grants = Array.isArray(status?.grants) ? status.grants : [];
218
+ const staticCount = grants.filter((g) => g.effectiveValueType === 'static').length;
219
+ const dynamicCount = grants.filter((g) => g.effectiveValueType === 'dynamic').length;
220
+ const ruleCount = Array.isArray(manifest?.spec?.rules) ? manifest.spec.rules.length : 0;
221
+ const grantTotal = status?.grantCount ?? grants.length;
222
+ const projectionAt =
223
+ status?.lastProjectionRunAt || status?.lastSuccessfulProjectionRunAt || '—';
224
+
225
+ appendProtectionShowSection(lines, 'Projection cache');
226
+ appendProtectionShowField(
227
+ lines,
228
+ 'Last run',
229
+ formatProtectionShowTimestamp(projectionAt === '—' ? null : projectionAt)
230
+ );
231
+ appendProtectionShowField(lines, 'Rules in manifest', String(ruleCount));
232
+ appendProtectionShowField(
233
+ lines,
234
+ 'Grants materialized',
235
+ `${grantTotal} (${staticCount} static, ${dynamicCount} dynamic)`
236
+ );
237
+ appendProtectionShowField(
238
+ lines,
239
+ 'Dynamic values materialized',
240
+ String(status?.dynamicValueCount ?? '—')
241
+ );
242
+ }
243
+
244
+ /**
245
+ * @param {string[]} lines
246
+ * @param {Object} payload
247
+ * @param {Object} [opts]
248
+ */
249
+ function appendProtectionShowHeader(lines, payload, opts = {}) {
250
+ const { manifest, status } = payload;
251
+ const datasourceKey = protectionShowDatasourceKey(manifest, status);
252
+ const enabled = manifest?.enabled !== false;
253
+ const protectionKey = manifest?.key || status?.protectionKey || '—';
254
+ const revision = String(manifest?.currentRevision ?? status?.currentRevision ?? '—');
255
+ const configHash = manifest?.configHash || status?.configHash || null;
256
+ const lastUpload = manifest?.lastDeployedAt || status?.lastDeployedAt || null;
257
+
258
+ lines.push(chalk.bold.white(datasourceKey));
259
+ lines.push(SEP);
260
+ appendProtectionShowField(lines, 'Status', enabled ? 'Enabled' : 'Disabled');
261
+
262
+ appendProtectionShowSection(lines, 'Manifest');
263
+ appendProtectionShowField(lines, 'Protection key', protectionKey);
264
+ appendProtectionShowField(lines, 'Datasource', datasourceKey);
265
+ appendProtectionShowField(lines, 'Revision', revision);
266
+
267
+ appendProtectionShowSection(lines, 'Deployment');
268
+ appendProtectionShowField(lines, 'Last upload', formatProtectionShowTimestamp(lastUpload));
269
+ appendProtectionShowField(
270
+ lines,
271
+ 'Content hash',
272
+ formatProtectionShowHash(configHash, opts.verbose === true)
273
+ );
274
+ if (opts.verbose && configHash) {
275
+ appendProtectionShowField(lines, 'Content hash (full)', configHash);
276
+ }
277
+
278
+ appendProtectionShowProjectionSection(lines, status, manifest);
279
+ }
280
+
281
+ /**
282
+ * @param {string[]} lines
283
+ * @param {Object} payload
284
+ */
285
+ function appendProtectionShowContextFooter(lines, payload) {
286
+ const environment = payload.environment || '—';
287
+ const dataplaneUrl = payload.dataplaneUrl || '';
288
+ lines.push('');
289
+ if (dataplaneUrl) {
290
+ lines.push(metadata(`Environment: ${environment} · Dataplane: ${dataplaneUrl}`));
291
+ } else {
292
+ lines.push(metadata(`Environment: ${environment}`));
293
+ }
294
+ }
295
+
296
+ /**
297
+ * @param {string[]} lines
298
+ * @param {Object} status
299
+ * @param {Object} manifest
300
+ * @deprecated Use appendProtectionShowProjectionSection via appendProtectionShowHeader
301
+ */
302
+ function appendProtectionShowCounts(lines, status, manifest) {
303
+ appendProtectionShowProjectionSection(lines, status, manifest);
304
+ }
305
+
306
+ /**
307
+ * @param {string[]} lines
308
+ * @param {Object[]} grants
309
+ */
310
+ /**
311
+ * @param {boolean|undefined} enabled
312
+ * @returns {string}
313
+ */
314
+ function formatProtectionEnabledLabel(enabled) {
315
+ if (enabled === true) {
316
+ return 'yes';
317
+ }
318
+ if (enabled === false) {
319
+ return 'no';
320
+ }
321
+ return '—';
322
+ }
323
+
324
+ /**
325
+ * @param {Object} row
326
+ * @returns {string}
327
+ */
328
+ function protectionListCardTitle(row) {
329
+ return String(row?.datasourceKey || row?.displayName || row?.key || '—').trim() || '—';
330
+ }
331
+
332
+ /**
333
+ * @param {string[]} lines
334
+ * @param {Object} row
335
+ * @param {Object} [opts]
336
+ */
337
+ function appendProtectionListCard(lines, row, opts = {}) {
338
+ lines.push(chalk.bold(protectionListCardTitle(row)));
339
+ lines.push(SEP);
340
+ lines.push(headerKeyValue('Protection key:', row?.key ?? '—'));
341
+ lines.push(headerKeyValue('Datasource:', row?.datasourceKey ?? '—'));
342
+ lines.push(headerKeyValue('Display name:', row?.displayName ?? '—'));
343
+ lines.push(headerKeyValue('Enabled:', formatProtectionEnabledLabel(row?.enabled)));
344
+ lines.push(
345
+ headerKeyValue('Revision:', String(row?.currentRevision ?? row?.revision ?? '—'))
346
+ );
347
+ if (opts.verbose && row?.lastDeployedAt) {
348
+ lines.push(headerKeyValue('Last deployed:', row.lastDeployedAt));
349
+ }
350
+ lines.push('');
351
+ }
352
+
353
+ /**
354
+ * @param {string[]} lines
355
+ * @param {Object[]} items
356
+ * @param {Object} [opts]
357
+ */
358
+ function appendProtectionListCards(lines, items, opts = {}) {
359
+ for (const row of items) {
360
+ appendProtectionListCard(lines, row, opts);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * @param {string[]} lines
366
+ * @param {Object} meta
367
+ * @param {number} shown
368
+ */
369
+ function appendProtectionListMetaFooter(lines, meta, shown) {
370
+ if (!meta || typeof meta.totalItems !== 'number') {
371
+ return;
372
+ }
373
+ const page = meta.currentPage ?? 1;
374
+ const pageSize = meta.pageSize ?? shown;
375
+ lines.push(
376
+ chalk.gray(` Showing ${shown} of ${meta.totalItems} (page ${page}, pageSize ${pageSize})`)
377
+ );
378
+ lines.push('');
379
+ }
380
+
381
+ /**
382
+ * @param {string[]} lines
383
+ * @param {Object} payload
384
+ * @param {Object} [opts]
385
+ */
386
+ function appendProtectionListTable(lines, payload, opts = {}) {
387
+ const environment = payload.environment || 'dev';
388
+ const dataplaneUrl = payload.dataplaneUrl || '';
389
+ const items = Array.isArray(payload.items) ? payload.items : [];
390
+ const meta = payload.meta || null;
391
+
392
+ lines.push(
393
+ sectionTitle(
394
+ `Protection manifests in ${environment} environment${dataplaneUrl ? ` (${dataplaneUrl})` : ''}:`
395
+ )
396
+ );
397
+ lines.push('');
398
+
399
+ if (!items.length) {
400
+ lines.push(chalk.gray(' No protection manifests found.\n'));
401
+ return;
402
+ }
403
+
404
+ appendProtectionListCards(lines, items, opts);
405
+ appendProtectionListMetaFooter(lines, meta, items.length);
406
+ }
407
+
408
+ function appendProtectionShowVerboseGrants(lines, grants) {
409
+ appendProtectionShowSection(lines, 'Grants by rule');
410
+ const byRule = new Map();
411
+ for (const g of grants) {
412
+ const rk = g.projectionRuleKey || '—';
413
+ if (!byRule.has(rk)) {
414
+ byRule.set(rk, []);
415
+ }
416
+ byRule.get(rk).push(g);
417
+ }
418
+ for (const [ruleKey, grantRows] of byRule) {
419
+ lines.push(` ${ruleKey}`);
420
+ for (const g of grantRows) {
421
+ lines.push(
422
+ chalk.gray(` ${g.dimensionKey} → ${g.effectiveValueType || g.valueType || '—'}`)
423
+ );
424
+ }
425
+ }
426
+ }
427
+
428
+ module.exports = {
429
+ taskStableCode,
430
+ appendTaskRows,
431
+ appendProtectionReportHeader,
432
+ appendSimulationSection,
433
+ appendValidationSummarySection,
434
+ appendBatchResultRows,
435
+ appendBatchSummary,
436
+ appendProtectionShowHeader,
437
+ appendProtectionShowContextFooter,
438
+ appendProtectionShowCounts,
439
+ appendProtectionShowVerboseGrants,
440
+ formatProtectionShowHash,
441
+ formatProtectionShowTimestamp,
442
+ appendProtectionListTable,
443
+ formatProtectionEnabledLabel,
444
+ formatStatusKeyValue
445
+ };
@@ -0,0 +1,215 @@
1
+ /**
2
+ * @fileoverview TTY formatters for protection CLI (layout-blocks / tty-summary).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const chalk = require('chalk');
11
+ const {
12
+ sectionTitle,
13
+ headerKeyValue,
14
+ metadata,
15
+ formatBlockingError,
16
+ formatSuccessLine,
17
+ formatWarningLine,
18
+ formatProgress,
19
+ formatNextActions
20
+ } = require('../utils/cli-test-layout-chalk');
21
+ const { reportTaskRows } = require('./report-exit');
22
+ const { describeProtectionRoot } = require('./paths');
23
+ const {
24
+ appendTaskRows,
25
+ appendProtectionReportHeader,
26
+ appendSimulationSection,
27
+ appendValidationSummarySection,
28
+ appendBatchResultRows,
29
+ appendBatchSummary,
30
+ appendProtectionShowHeader,
31
+ appendProtectionShowContextFooter,
32
+ appendProtectionShowVerboseGrants,
33
+ appendProtectionListTable,
34
+ formatStatusKeyValue
35
+ } = require('./protection-display-helpers');
36
+
37
+ const SEP = chalk.gray('────────────────────────────────────────');
38
+
39
+ /**
40
+ * @param {Object} report
41
+ * @param {Object} [opts]
42
+ * @returns {string}
43
+ */
44
+ function formatProtectionValidateTTY(report, opts = {}) {
45
+ const lines = [];
46
+ const meta = report?.metadata || {};
47
+ appendProtectionReportHeader(lines, meta);
48
+ const summary = report?.summary || {};
49
+ const failCount = Number(summary.fail || 0);
50
+ const warnCount = Number(summary.warn || 0);
51
+ const aggregate = failCount > 0 ? 'fail' : warnCount > 0 ? 'warn' : 'ok';
52
+ const glyph = aggregate === 'fail' ? '✖' : aggregate === 'warn' ? '⚠' : '✔';
53
+ lines.push(formatStatusKeyValue(aggregate, glyph));
54
+ const rows = reportTaskRows(report);
55
+ appendTaskRows(lines, rows, 'FAIL', opts);
56
+ appendTaskRows(lines, rows, 'WARN', opts);
57
+ if (opts.verbose) {
58
+ appendTaskRows(lines, rows, 'PASS', opts);
59
+ }
60
+ if (opts.simulationBlock) {
61
+ appendSimulationSection(lines, opts.simulationBlock);
62
+ }
63
+ appendValidationSummarySection(lines, failCount, warnCount, opts);
64
+ return lines.join('\n');
65
+ }
66
+
67
+ /**
68
+ * @param {Object} report
69
+ * @param {Object} opts
70
+ */
71
+ function printProtectionValidateReport(report, opts = {}) {
72
+ if (opts.json) {
73
+ process.stdout.write(`${JSON.stringify(report, null, 2)}\n`);
74
+ return;
75
+ }
76
+ const text = formatProtectionValidateTTY(report, opts);
77
+ if (text) {
78
+ opts.logger.log(text);
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {Object[]} results
84
+ * @param {Object} [opts]
85
+ * @returns {string}
86
+ */
87
+ function formatProtectionBatchFolderLine(opts = {}) {
88
+ const described = describeProtectionRoot();
89
+ const folderPath = opts.folder ? path.resolve(String(opts.folder)) : described.root;
90
+ const lines = [metadata(`Folder: ${described.label} — ${folderPath}`)];
91
+ if (described.migrationHint) {
92
+ lines.push(formatWarningLine(described.migrationHint));
93
+ }
94
+ return lines;
95
+ }
96
+
97
+ /**
98
+ * @param {Object[]} results
99
+ * @param {Object} [opts]
100
+ * @returns {string}
101
+ */
102
+ function formatProtectionBatchValidateTTY(results, opts = {}) {
103
+ const lines = [sectionTitle('Protection validate (batch)'), SEP, 'Scope: .protection'];
104
+ lines.push(...formatProtectionBatchFolderLine(opts));
105
+ lines.push('');
106
+ let passed = 0;
107
+ let failed = 0;
108
+ for (const row of results) {
109
+ if (row.ok) passed += 1;
110
+ else failed += 1;
111
+ }
112
+ appendBatchResultRows(lines, results, 'Validated');
113
+ appendBatchSummary(lines, passed, failed, `All ${passed} manifest(s) validated`);
114
+ return lines.join('\n');
115
+ }
116
+
117
+ /**
118
+ * @param {Object[]} results
119
+ * @param {Object} [opts]
120
+ * @returns {string}
121
+ */
122
+ function formatProtectionBatchUploadTTY(results, opts = {}) {
123
+ const lines = [sectionTitle('Protection upload (batch)'), SEP, 'Scope: .protection'];
124
+ lines.push(...formatProtectionBatchFolderLine(opts));
125
+ lines.push('');
126
+ let passed = 0;
127
+ let failed = 0;
128
+ for (const row of results) {
129
+ if (row.ok) passed += 1;
130
+ else failed += 1;
131
+ }
132
+ appendBatchResultRows(lines, results, 'Validated and uploaded');
133
+ appendBatchSummary(lines, passed, failed, `All ${passed} manifest(s) uploaded`);
134
+ return lines.join('\n');
135
+ }
136
+
137
+ /**
138
+ * @returns {string}
139
+ */
140
+ function formatDeployProtectionNotImplementedTTY() {
141
+ return [
142
+ formatBlockingError('deploy .protection is not supported.'),
143
+ '',
144
+ 'Protection manifests are uploaded to the dataplane directly, not via the Miso Controller deploy pipeline.',
145
+ '',
146
+ 'Use:',
147
+ ' aifabrix upload .protection',
148
+ ' aifabrix protection upload <datasourceKey>'
149
+ ].join('\n');
150
+ }
151
+
152
+ /**
153
+ * @param {Object} payload
154
+ * @param {Object} [opts]
155
+ * @returns {string}
156
+ */
157
+ function formatProtectionListTTY(payload, opts = {}) {
158
+ const lines = [];
159
+ appendProtectionListTable(lines, payload, opts);
160
+ return lines.join('\n');
161
+ }
162
+
163
+ /**
164
+ * @param {Object} payload
165
+ * @param {Object} [opts]
166
+ * @returns {string}
167
+ */
168
+ function formatProtectionShowTTY(payload, opts = {}) {
169
+ const lines = [];
170
+ appendProtectionShowHeader(lines, payload, opts);
171
+ const grants = Array.isArray(payload.status?.grants) ? payload.status.grants : [];
172
+ if (opts.verbose && grants.length) {
173
+ appendProtectionShowVerboseGrants(lines, grants);
174
+ }
175
+ appendProtectionShowContextFooter(lines, payload);
176
+ return lines.join('\n');
177
+ }
178
+
179
+ /**
180
+ * @param {Object} response
181
+ * @param {string} datasourceKey
182
+ * @returns {string}
183
+ */
184
+ function formatProtectionDeleteSummaryTTY(response, datasourceKey) {
185
+ const lines = [formatSuccessLine(`Protection for '${datasourceKey}' deleted`)];
186
+ if (response && typeof response === 'object') {
187
+ if (response.dynamicValuesRemoved !== null && response.dynamicValuesRemoved !== undefined) {
188
+ lines.push(` Dynamic values removed: ${response.dynamicValuesRemoved}`);
189
+ }
190
+ if (response.principalGrantsRemoved !== null && response.principalGrantsRemoved !== undefined) {
191
+ lines.push(` Principal grants removed: ${response.principalGrantsRemoved}`);
192
+ }
193
+ }
194
+ return lines.join('\n');
195
+ }
196
+
197
+ module.exports = {
198
+ SEP,
199
+ formatProtectionValidateTTY,
200
+ printProtectionValidateReport,
201
+ formatProtectionBatchValidateTTY,
202
+ formatProtectionBatchUploadTTY,
203
+ formatDeployProtectionNotImplementedTTY,
204
+ formatProtectionListTTY,
205
+ formatProtectionShowTTY,
206
+ formatProtectionDeleteSummaryTTY,
207
+ formatProgress,
208
+ formatSuccessLine,
209
+ formatBlockingError,
210
+ formatWarningLine,
211
+ formatNextActions,
212
+ metadata,
213
+ headerKeyValue,
214
+ sectionTitle
215
+ };