@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,46 @@
1
+ /**
2
+ * @fileoverview Preflight: datasource must exist on dataplane before protection upload.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getDatasource } = require('../api/datasources-core.api');
10
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
11
+
12
+ /**
13
+ * @param {string} dataplaneUrl
14
+ * @param {Object} authConfig
15
+ * @param {string} datasourceKey
16
+ * @returns {Promise<void>}
17
+ */
18
+ async function assertDatasourceExistsOnDataplane(dataplaneUrl, authConfig, datasourceKey) {
19
+ const key = String(datasourceKey || '').trim();
20
+ if (!key) {
21
+ throw new Error('spec.datasourceKey is required');
22
+ }
23
+ const res = await getDatasource(dataplaneUrl, key, authConfig);
24
+ const row = unwrapApiData(res);
25
+ if (!row || (res && res.success === false)) {
26
+ throw new Error(
27
+ `Datasource "${key}" is not deployed on the dataplane. Run aifabrix deploy <app> first.`
28
+ );
29
+ }
30
+ }
31
+
32
+ /**
33
+ * @param {string} dataplaneUrl
34
+ * @param {Object} authConfig
35
+ * @param {Object} manifest
36
+ * @returns {Promise<void>}
37
+ */
38
+ async function preflightDatasourceReady(dataplaneUrl, authConfig, manifest) {
39
+ const ds = String(manifest?.spec?.datasourceKey || '').trim();
40
+ await assertDatasourceExistsOnDataplane(dataplaneUrl, authConfig, ds);
41
+ }
42
+
43
+ module.exports = {
44
+ assertDatasourceExistsOnDataplane,
45
+ preflightDatasourceReady
46
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * @fileoverview TTY line builders for protection create probes (keeps probe async functions small).
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
+ formatProgress,
15
+ formatSuccessLine
16
+ } = require('../utils/cli-test-layout-chalk');
17
+
18
+ const SEP = chalk.gray('────────────────────────────────────────');
19
+
20
+ /**
21
+ * @param {string} key
22
+ * @returns {string[]}
23
+ */
24
+ function startDatasourceProbeLines(key) {
25
+ return [sectionTitle('Datasource (dataplane)'), SEP, formatProgress(`Fetching datasource "${key}"…`)];
26
+ }
27
+
28
+ /**
29
+ * @param {string[]} lines
30
+ * @param {Object} row
31
+ * @param {string} key
32
+ * @param {string} dataplaneUrl
33
+ */
34
+ function appendDatasourceCoreFields(lines, row, key, dataplaneUrl) {
35
+ lines.push(formatSuccessLine(`Datasource "${key}" found`));
36
+ lines.push(metadata(`Dataplane: ${dataplaneUrl}`));
37
+ lines.push(headerKeyValue('Key:', row.key ?? key));
38
+ lines.push(headerKeyValue('Display name:', row.displayName ?? '—'));
39
+ lines.push(headerKeyValue('System key:', row.systemKey ?? '—'));
40
+ const ver = row.version;
41
+ lines.push(headerKeyValue('Version:', ver !== undefined && ver !== null ? String(ver) : '—'));
42
+ lines.push(headerKeyValue('Enabled:', String(row.enabled !== false)));
43
+ }
44
+
45
+ /**
46
+ * @param {string[]} lines
47
+ * @param {Object} row
48
+ */
49
+ function appendDatasourceOptionalTypes(lines, row) {
50
+ if (row.entityType) {
51
+ lines.push(headerKeyValue('Entity type:', String(row.entityType)));
52
+ }
53
+ if (row.resourceType) {
54
+ lines.push(headerKeyValue('Resource type:', String(row.resourceType)));
55
+ }
56
+ }
57
+
58
+ /**
59
+ * @param {string[]} lines
60
+ * @param {Object} row
61
+ */
62
+ function appendDatasourceVerboseBlock(lines, row) {
63
+ const pick = ['id', 'key', 'displayName', 'systemKey', 'version', 'enabled', 'entityType', 'resourceType'];
64
+ const extra = {};
65
+ for (const p of pick) {
66
+ if (row[p] !== undefined) {
67
+ extra[p] = row[p];
68
+ }
69
+ }
70
+ lines.push('');
71
+ lines.push(chalk.gray('Verbose (subset):'));
72
+ lines.push(chalk.gray(JSON.stringify(extra, null, 2)));
73
+ }
74
+
75
+ /**
76
+ * @param {string[]} lines
77
+ * @param {Object} row
78
+ * @param {string} key
79
+ * @param {string} dataplaneUrl
80
+ * @param {Object} opts
81
+ */
82
+ function appendDatasourceSuccessDetail(lines, row, key, dataplaneUrl, opts) {
83
+ appendDatasourceCoreFields(lines, row, key, dataplaneUrl);
84
+ appendDatasourceOptionalTypes(lines, row);
85
+ if (opts.verbose && row) {
86
+ appendDatasourceVerboseBlock(lines, row);
87
+ }
88
+ lines.push('');
89
+ }
90
+
91
+ /**
92
+ * @param {string} key
93
+ * @returns {string[]}
94
+ */
95
+ function startDimensionProbeLines(key) {
96
+ return [
97
+ sectionTitle('Dimension (Controller catalog)'),
98
+ SEP,
99
+ formatProgress(`Fetching dimension "${key}"…`)
100
+ ];
101
+ }
102
+
103
+ /**
104
+ * @param {string[]} lines
105
+ * @param {Object} row
106
+ * @param {string} controllerUrl
107
+ * @param {Object} opts
108
+ */
109
+ function appendDimensionSuccessDetail(lines, row, controllerUrl, opts) {
110
+ lines.push(formatSuccessLine(`Dimension "${row.key}" found`));
111
+ lines.push(metadata(`Controller: ${controllerUrl}`));
112
+ lines.push(headerKeyValue('Key:', row.key));
113
+ lines.push(headerKeyValue('Display:', row.displayName ?? '—'));
114
+ lines.push(headerKeyValue('Data type:', row.dataType ?? '—'));
115
+ lines.push(headerKeyValue('Value type:', row.valueType ?? 'static'));
116
+ lines.push(headerKeyValue('Required:', String(row.isRequired === true)));
117
+ if (Array.isArray(row.dimensionValues) && row.dimensionValues.length > 0) {
118
+ lines.push(
119
+ headerKeyValue('Catalog values:', `${row.dimensionValues.length} (static/baseline)`)
120
+ );
121
+ } else if (row.valueType === 'dynamic' || row.valueType === 'both') {
122
+ lines.push(headerKeyValue('Catalog values:', '— (dynamic / projection)'));
123
+ }
124
+ if (opts.verbose && Array.isArray(row.dimensionValues) && row.dimensionValues.length) {
125
+ lines.push('');
126
+ lines.push(chalk.gray('Sample values (first 5):'));
127
+ row.dimensionValues.slice(0, 5).forEach((v) => {
128
+ const val = v && v.value !== undefined && v.value !== null ? String(v.value) : '—';
129
+ const dn = v?.displayName ? ` (${v.displayName})` : '';
130
+ lines.push(chalk.gray(` ${val}${dn}`));
131
+ });
132
+ }
133
+ lines.push('');
134
+ }
135
+
136
+ module.exports = {
137
+ SEP,
138
+ startDatasourceProbeLines,
139
+ appendDatasourceSuccessDetail,
140
+ startDimensionProbeLines,
141
+ appendDimensionSuccessDetail
142
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @fileoverview Online probes for `protection create` (dataplane datasource + Controller dimension).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { getDatasource } = require('../api/datasources-core.api');
10
+ const { getDimension } = require('../api/dimensions.api');
11
+ const { unwrapApiData } = require('../utils/external-system-readiness-core');
12
+ const {
13
+ startDatasourceProbeLines,
14
+ appendDatasourceSuccessDetail,
15
+ startDimensionProbeLines,
16
+ appendDimensionSuccessDetail
17
+ } = require('./protection-create-probe-lines');
18
+
19
+ /**
20
+ * @param {*} response
21
+ * @returns {*}
22
+ */
23
+ function unwrapControllerDimension(response) {
24
+ const d = response?.data?.data ?? response?.data ?? response;
25
+ return d;
26
+ }
27
+
28
+ /**
29
+ * @param {string[]} lines
30
+ * @param {string} msg
31
+ * @returns {never}
32
+ */
33
+ function throwProbe(lines, msg) {
34
+ const err = new Error(msg);
35
+ err.probeLines = lines;
36
+ throw err;
37
+ }
38
+
39
+ /**
40
+ * @param {string} dataplaneUrl
41
+ * @param {Object} authConfig
42
+ * @param {string} datasourceKey
43
+ * @param {Object} opts
44
+ * @returns {Promise<Object>}
45
+ */
46
+ async function probeDatasourceForProtectionCreate(dataplaneUrl, authConfig, datasourceKey, opts = {}) {
47
+ const key = String(datasourceKey || '').trim();
48
+ const lines = startDatasourceProbeLines(key);
49
+ const res = await getDatasource(dataplaneUrl, key, authConfig);
50
+ if (res && res.success === false) {
51
+ const msg = res.formattedError || res.error || `Datasource "${key}" request failed`;
52
+ throwProbe(lines, typeof msg === 'string' ? msg : 'Datasource probe failed');
53
+ }
54
+ const row = unwrapApiData(res);
55
+ if (!row) {
56
+ throwProbe(
57
+ lines,
58
+ `Datasource "${key}" not found or not readable on the dataplane. Deploy the integration first.`
59
+ );
60
+ }
61
+ appendDatasourceSuccessDetail(lines, row, key, dataplaneUrl, opts);
62
+ return { row, lines };
63
+ }
64
+
65
+ /**
66
+ * @param {string} controllerUrl
67
+ * @param {Object} authConfig
68
+ * @param {string} dimensionKey
69
+ * @param {Object} opts
70
+ * @returns {Promise<Object>}
71
+ */
72
+ async function probeDimensionForProtectionCreate(controllerUrl, authConfig, dimensionKey, opts = {}) {
73
+ const key = String(dimensionKey || '').trim();
74
+ const lines = startDimensionProbeLines(key);
75
+ const res = await getDimension(controllerUrl, authConfig, key, { includeValues: opts.verbose === true });
76
+ if (res && res.success === false) {
77
+ const msg = res.formattedError || res.error || `Dimension "${key}" request failed`;
78
+ throwProbe(lines, typeof msg === 'string' ? msg : 'Dimension probe failed');
79
+ }
80
+ const row = unwrapControllerDimension(res);
81
+ if (!row || !row.key) {
82
+ throwProbe(
83
+ lines,
84
+ `Dimension "${key}" not found in the Controller catalog. Create it with: aifabrix dimension create …`
85
+ );
86
+ }
87
+ appendDimensionSuccessDetail(lines, row, controllerUrl, opts);
88
+ return { row, lines };
89
+ }
90
+
91
+ module.exports = {
92
+ probeDatasourceForProtectionCreate,
93
+ probeDimensionForProtectionCreate,
94
+ unwrapControllerDimension
95
+ };
@@ -0,0 +1,281 @@
1
+ /**
2
+ * @fileoverview Build protection manifest objects for `protection create`.
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { requireProtectionPreset } = require('./protection-preset-registry');
10
+
11
+ const PROTECTION_KEY_RE = /^[a-z0-9][a-z0-9-]*$/;
12
+ const DIMENSION_KEY_RE = /^[a-zA-Z][a-zA-Z0-9-_]*$/;
13
+
14
+ /**
15
+ * @param {string} raw
16
+ * @returns {string}
17
+ */
18
+ function requireDatasourceKey(raw) {
19
+ const k = String(raw || '').trim();
20
+ if (!k) {
21
+ throw new Error('Datasource key is required');
22
+ }
23
+ if (!PROTECTION_KEY_RE.test(k)) {
24
+ throw new Error(
25
+ `Datasource key must match ${PROTECTION_KEY_RE}: got "${k}"`
26
+ );
27
+ }
28
+ return k;
29
+ }
30
+
31
+ /**
32
+ * @param {string} raw
33
+ * @returns {string}
34
+ */
35
+ function requireDimensionKey(raw) {
36
+ const k = String(raw || '').trim();
37
+ if (!k) {
38
+ throw new Error('--dimension-key is required for protection create');
39
+ }
40
+ if (!DIMENSION_KEY_RE.test(k)) {
41
+ throw new Error(
42
+ 'Dimension key must start with a letter and contain letters, numbers, hyphens, underscores only.'
43
+ );
44
+ }
45
+ return k;
46
+ }
47
+
48
+ /**
49
+ * @param {string} raw
50
+ * @param {string} fallback
51
+ * @returns {string}
52
+ */
53
+ function protectionMetadataKey(raw, fallback) {
54
+ const k = String(raw || '').trim();
55
+ if (k) {
56
+ if (!PROTECTION_KEY_RE.test(k)) {
57
+ throw new Error(`--protection-key must match ${PROTECTION_KEY_RE}: got "${k}"`);
58
+ }
59
+ return k;
60
+ }
61
+ return fallback;
62
+ }
63
+
64
+ /**
65
+ * @param {Object} vars
66
+ * @param {string} vars.datasourceKey
67
+ * @param {string} vars.dimensionKey
68
+ * @param {string} [vars.protectionKey]
69
+ * @param {string} [vars.displayName]
70
+ * @param {string} [vars.ruleKey]
71
+ * @param {Object} vars.principal
72
+ * @param {string} vars.valueExpression
73
+ * @param {Object} [vars.when]
74
+ * @returns {Object}
75
+ */
76
+ function buildProtectionManifest(vars) {
77
+ const datasourceKey = requireDatasourceKey(vars.datasourceKey);
78
+ const dimensionKey = requireDimensionKey(vars.dimensionKey);
79
+ const presetPart = vars.type ? `-${vars.type}` : '';
80
+ const protectionKey = protectionMetadataKey(
81
+ vars.protectionKey,
82
+ `${datasourceKey}-${dimensionKey}${presetPart}-access`
83
+ );
84
+ const ruleKey = String(vars.ruleKey || '').trim() || `${dimensionKey}${presetPart || '-access'}`;
85
+ const rule = {
86
+ key: ruleKey,
87
+ principal: vars.principal,
88
+ grants: [{ dimensionKey, valueExpression: vars.valueExpression }]
89
+ };
90
+ if (vars.when) {
91
+ rule.when = JSON.parse(JSON.stringify(vars.when));
92
+ }
93
+ return {
94
+ apiVersion: 'dataplane.aifabrix.ai/v1',
95
+ kind: 'Protection',
96
+ metadata: {
97
+ key: protectionKey,
98
+ displayName: String(vars.displayName || '').trim() || `${datasourceKey} — ${dimensionKey}`
99
+ },
100
+ spec: {
101
+ enabled: vars.enabled !== false,
102
+ datasourceKey,
103
+ mode: 'replaceForSource',
104
+ rules: [rule]
105
+ }
106
+ };
107
+ }
108
+
109
+ /**
110
+ * @param {Object} datasource
111
+ * @param {string} field
112
+ * @returns {boolean}
113
+ */
114
+ function hasMetadataField(datasource, field) {
115
+ const props = datasource?.metadataSchema?.properties;
116
+ if (!props || typeof props !== 'object' || Array.isArray(props)) {
117
+ return true;
118
+ }
119
+ return Object.prototype.hasOwnProperty.call(props, field);
120
+ }
121
+
122
+ /**
123
+ * @param {Object} datasource
124
+ * @param {string} name
125
+ * @returns {Object|null}
126
+ */
127
+ function findForeignKey(datasource, name) {
128
+ const fks = Array.isArray(datasource?.foreignKeys) ? datasource.foreignKeys : [];
129
+ return fks.find((fk) => fk && fk.name === name) || null;
130
+ }
131
+
132
+ /**
133
+ * @param {Object} datasource
134
+ * @param {string} field
135
+ */
136
+ function assertMetadataField(datasource, field) {
137
+ if (!hasMetadataField(datasource, field)) {
138
+ throw new Error(`Preset field not found in datasource metadataSchema.properties: ${field}`);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * @param {Object} preset
144
+ * @param {Object} dimension
145
+ */
146
+ function assertDimensionValueType(preset, dimension) {
147
+ const valueType = String(dimension?.valueType || '').trim();
148
+ if (preset.staticOnly && valueType === 'dynamic') {
149
+ throw new Error(`Protection type "${preset.type}" requires a static or both dimension.`);
150
+ }
151
+ if (preset.dynamicOnly && valueType === 'static') {
152
+ throw new Error(`Protection type "${preset.type}" requires a dynamic or both dimension.`);
153
+ }
154
+ }
155
+
156
+ /**
157
+ * @param {Object} vars
158
+ * @param {Object} preset
159
+ * @returns {{ principal: Object, valueExpression: string, when: Object|undefined }}
160
+ */
161
+ function resolveStandardPresetSpec(vars, preset) {
162
+ const field = String(vars.field || preset.valueField || preset.dimensionKey).trim();
163
+ assertMetadataField(vars.datasource, field);
164
+ const principal = vars.principalExpression
165
+ ? { type: 'group', expression: String(vars.principalExpression).trim() }
166
+ : principalFromPreset(vars, preset);
167
+ const valueExpression =
168
+ String(vars.valueExpression || '').trim() || preset.valueTemplate || `{{metadata.${field}}}`;
169
+ return { principal, valueExpression, when: preset.when };
170
+ }
171
+
172
+ /**
173
+ * @param {Object} vars
174
+ * @param {Object} preset
175
+ * @returns {Object}
176
+ */
177
+ function principalFromPreset(vars, preset) {
178
+ if (preset.type === 'static-region') {
179
+ const displayField = hasMetadataField(vars.datasource, 'regionDisplayName') ? 'regionDisplayName' : 'region';
180
+ return { type: 'group', expression: `{{metadata.${displayField}}} Users` };
181
+ }
182
+ if (preset.principalType === 'user') {
183
+ assertMetadataField(vars.datasource, String(preset.principalField).replace(/^metadata\./, ''));
184
+ return { type: 'user', field: preset.principalField };
185
+ }
186
+ return { type: 'group', expression: preset.principalTemplate };
187
+ }
188
+
189
+ /**
190
+ * @param {Object} vars
191
+ * @param {Object} preset
192
+ * @returns {{ principal: Object, valueExpression: string }}
193
+ */
194
+ function resolveCountrySalesSpec(vars, preset) {
195
+ const dimensionKey = vars.dimensionKey;
196
+ const fkName = String(vars.fkName || dimensionKey).trim();
197
+ const explicitField = String(vars.field || '').trim();
198
+ const fk = explicitField ? null : findForeignKey(vars.datasource, fkName);
199
+ if (vars.fkName && !fk) {
200
+ throw new Error(`Preset FK not found in datasource foreignKeys[].name: ${fkName}`);
201
+ }
202
+ if (fk) {
203
+ return {
204
+ principal: { type: 'group', expression: `Sales {{fk.${fkName}.metadata.iso3}} Users` },
205
+ valueExpression: String(vars.valueExpression || '').trim() || `{{fk.${fkName}.metadata.iso2}}`
206
+ };
207
+ }
208
+ const field = explicitField || preset.dimensionKey;
209
+ assertMetadataField(vars.datasource, field);
210
+ return {
211
+ principal: { type: 'group', expression: `Sales {{metadata.${field}}} Users` },
212
+ valueExpression: String(vars.valueExpression || '').trim() || `{{metadata.${field}}}`
213
+ };
214
+ }
215
+
216
+ /**
217
+ * @param {Object} vars
218
+ * @returns {Object}
219
+ */
220
+ function buildPresetProtectionManifest(vars) {
221
+ const preset = requireProtectionPreset(vars.type);
222
+ if (!preset) {
223
+ return buildDynamicFkProtectionManifest(vars);
224
+ }
225
+ const dimensionKey = requireDimensionKey(vars.dimensionKey || preset.dimensionKey);
226
+ assertDimensionValueType(preset, vars.dimension);
227
+ const resolved = preset.type === 'country-sales'
228
+ ? resolveCountrySalesSpec({ ...vars, dimensionKey }, preset)
229
+ : resolveStandardPresetSpec({ ...vars, dimensionKey }, preset);
230
+ return buildProtectionManifest({
231
+ ...vars,
232
+ type: preset.type,
233
+ dimensionKey,
234
+ principal: resolved.principal,
235
+ valueExpression: resolved.valueExpression,
236
+ when: resolved.when
237
+ });
238
+ }
239
+
240
+ /**
241
+ * Build v1 "country-from-FK" style manifest (dynamic dimension from one-hop FK metadata).
242
+ *
243
+ * @param {Object} vars
244
+ * @param {string} vars.datasourceKey
245
+ * @param {string} vars.dimensionKey
246
+ * @param {string} [vars.fkName] - defaults to dimensionKey
247
+ * @param {string} [vars.protectionKey]
248
+ * @param {string} [vars.displayName]
249
+ * @param {string} [vars.ruleKey]
250
+ * @param {string} [vars.principalExpression]
251
+ * @param {string} [vars.valueExpression]
252
+ * @returns {Object}
253
+ */
254
+ function buildDynamicFkProtectionManifest(vars) {
255
+ const datasourceKey = requireDatasourceKey(vars.datasourceKey);
256
+ const dimensionKey = requireDimensionKey(vars.dimensionKey);
257
+ const fkName = String(vars.fkName || dimensionKey).trim() || dimensionKey;
258
+ const principalExpression =
259
+ String(vars.principalExpression || '').trim() ||
260
+ `Sales {{fk.${fkName}.metadata.iso3}} Users`;
261
+ const valueExpression =
262
+ String(vars.valueExpression || '').trim() ||
263
+ `{{fk.${fkName}.metadata.iso2}}`;
264
+ return buildProtectionManifest({
265
+ ...vars,
266
+ datasourceKey,
267
+ dimensionKey,
268
+ ruleKey: vars.ruleKey || `${dimensionKey}-from-fk-users`,
269
+ displayName: vars.displayName || `${datasourceKey} — ${dimensionKey} (FK projection)`,
270
+ principal: { type: 'group', expression: principalExpression },
271
+ valueExpression
272
+ });
273
+ }
274
+
275
+ module.exports = {
276
+ buildPresetProtectionManifest,
277
+ buildDynamicFkProtectionManifest,
278
+ buildProtectionManifest,
279
+ requireDatasourceKey,
280
+ requireDimensionKey
281
+ };