@aifabrix/builder 2.45.5 → 2.47.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 (355) 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/project-rules.mdc +1 -0
  4. package/.npmrc.token +1 -0
  5. package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
  6. package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
  7. package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
  8. package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
  9. package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
  10. package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
  11. package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
  12. package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
  13. package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
  14. package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
  15. package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
  16. package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
  17. package/.temp/validation/summary.txt +5 -0
  18. package/README.md +43 -17
  19. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  20. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
  21. package/jest.config.default.js +2 -1
  22. package/jest.config.isolated.js +2 -1
  23. package/jest.global-live-fabrix-hooks.js +36 -0
  24. package/jest.isolated-projects.js +146 -0
  25. package/jest.projects.js +65 -136
  26. package/lib/api/api-response-errors.js +124 -0
  27. package/lib/api/dataplane-health.api.js +19 -7
  28. package/lib/api/governance-scenario-pack.api.js +159 -0
  29. package/lib/api/index.js +43 -3
  30. package/lib/api/lifecycle.api.js +98 -0
  31. package/lib/api/pipeline.api.js +3 -1
  32. package/lib/api/records-bulk.api.js +14 -1
  33. package/lib/api/resource-types.api.js +107 -0
  34. package/lib/api/runtime-configuration.api.js +72 -0
  35. package/lib/api/types/resource-types.types.js +45 -0
  36. package/lib/api/user-groups.api.js +9 -9
  37. package/lib/api/users.api.js +8 -8
  38. package/lib/api/validation-runner.js +3 -1
  39. package/lib/api/wizard.api.js +10 -2
  40. package/lib/app/deploy-config.js +4 -1
  41. package/lib/app/down.js +78 -27
  42. package/lib/app/index.js +2 -2
  43. package/lib/app/push.js +4 -5
  44. package/lib/app/register.js +7 -4
  45. package/lib/app/run-env-compose.js +84 -30
  46. package/lib/app/run-resolve-image.js +2 -1
  47. package/lib/app/run-stop-containers.js +113 -0
  48. package/lib/app/run.js +1 -31
  49. package/lib/app/show-display.js +35 -0
  50. package/lib/app/show.js +32 -1
  51. package/lib/build/index.js +22 -5
  52. package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
  53. package/lib/certification/sync-system-certification.js +13 -6
  54. package/lib/channels/add-channel.js +348 -0
  55. package/lib/channels/channel-artifact-generator.js +141 -0
  56. package/lib/channels/channel-audit.js +101 -0
  57. package/lib/channels/channel-auth-context.js +37 -0
  58. package/lib/channels/channel-credential.js +200 -0
  59. package/lib/channels/channel-display-name.js +64 -0
  60. package/lib/channels/channel-external-system.js +106 -0
  61. package/lib/channels/channel-integration-generator.js +274 -0
  62. package/lib/channels/channel-probe.js +89 -0
  63. package/lib/channels/channel-runtime-resolver.js +152 -0
  64. package/lib/channels/channel-status-display.js +141 -0
  65. package/lib/channels/channel-targets.js +115 -0
  66. package/lib/cli/index.js +20 -4
  67. package/lib/cli/infra-guided-auth.js +109 -0
  68. package/lib/cli/infra-guided.js +84 -81
  69. package/lib/cli/setup-app.help.js +0 -31
  70. package/lib/cli/setup-app.js +82 -5
  71. package/lib/cli/setup-app.test-commands.js +5 -57
  72. package/lib/cli/setup-auth.js +25 -0
  73. package/lib/cli/setup-certification-commands.js +147 -0
  74. package/lib/cli/setup-certification.help.js +141 -0
  75. package/lib/cli/setup-environment.js +19 -2
  76. package/lib/cli/setup-external-system-help.js +62 -0
  77. package/lib/cli/setup-external-system.js +25 -3
  78. package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
  79. package/lib/cli/setup-infra-up-platform-action.js +2 -1
  80. package/lib/cli/setup-infra.js +9 -1
  81. package/lib/cli/setup-platform.js +6 -1
  82. package/lib/cli/setup-secrets.js +33 -1
  83. package/lib/cli/setup-utility-help-after.js +25 -2
  84. package/lib/cli/setup-utility-repair.js +198 -0
  85. package/lib/cli/setup-utility-resolve.js +44 -5
  86. package/lib/cli/setup-utility-validate.js +197 -0
  87. package/lib/cli/setup-utility.js +4 -239
  88. package/lib/commands/app-logs.js +54 -26
  89. package/lib/commands/app.js +41 -0
  90. package/lib/commands/auth-status-client-tokens.js +214 -0
  91. package/lib/commands/auth-status-dataplane-version.js +142 -68
  92. package/lib/commands/auth-status.js +43 -54
  93. package/lib/commands/channel.js +58 -0
  94. package/lib/commands/datasource-test-trust-cli.js +27 -23
  95. package/lib/commands/datasource-unified-test-cli.js +6 -3
  96. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  97. package/lib/commands/datasource.js +8 -8
  98. package/lib/commands/dev-show-display.js +8 -1
  99. package/lib/commands/governance-cli-shared.js +94 -0
  100. package/lib/commands/governance-command-action.js +132 -0
  101. package/lib/commands/governance-download-external.js +34 -0
  102. package/lib/commands/governance-generate-external.js +71 -0
  103. package/lib/commands/governance-upload-external.js +36 -0
  104. package/lib/commands/governance-verify-external.js +64 -0
  105. package/lib/commands/governance.js +144 -0
  106. package/lib/commands/identity-apply-sync.js +49 -8
  107. package/lib/commands/identity-group-cli.js +66 -26
  108. package/lib/commands/identity-membership-role-cache.js +58 -37
  109. package/lib/commands/identity-shared.js +22 -1
  110. package/lib/commands/identity-user-cli.js +80 -34
  111. package/lib/commands/lifecycle-command-action.js +123 -0
  112. package/lib/commands/lifecycle-external.js +268 -0
  113. package/lib/commands/login.js +11 -2
  114. package/lib/commands/repair-auth-apply.js +153 -0
  115. package/lib/commands/repair-auth-config.js +8 -13
  116. package/lib/commands/repair-changed-files.js +41 -0
  117. package/lib/commands/repair-datasource-com-v2.js +15 -0
  118. package/lib/commands/repair-datasource-keys.js +4 -1
  119. package/lib/commands/repair-datasource-run.js +59 -0
  120. package/lib/commands/repair-datasource-service-contract.js +206 -0
  121. package/lib/commands/repair-datasource-test-payload.js +259 -0
  122. package/lib/commands/repair-datasource.js +49 -64
  123. package/lib/commands/repair-env-template.js +76 -25
  124. package/lib/commands/repair-external-run.js +216 -0
  125. package/lib/commands/repair-openapi-sync.js +49 -4
  126. package/lib/commands/repair-persist.js +4 -0
  127. package/lib/commands/repair-rbac.js +52 -1
  128. package/lib/commands/repair-steps.js +160 -0
  129. package/lib/commands/repair-system-alignment.js +7 -4
  130. package/lib/commands/repair.js +29 -296
  131. package/lib/commands/resource-type.js +371 -0
  132. package/lib/commands/secrets-get.js +184 -0
  133. package/lib/commands/secrets-remove-all.js +3 -1
  134. package/lib/commands/setup-image-refresh.js +146 -0
  135. package/lib/commands/setup-modes.js +158 -162
  136. package/lib/commands/setup-platform-auth.js +76 -0
  137. package/lib/commands/setup-prompts-admin.js +244 -0
  138. package/lib/commands/setup-prompts-platform-mode.js +70 -0
  139. package/lib/commands/setup-prompts-validators.js +36 -0
  140. package/lib/commands/setup-prompts.js +24 -76
  141. package/lib/commands/setup-run-context.js +45 -0
  142. package/lib/commands/setup-spinners.js +39 -0
  143. package/lib/commands/setup.js +27 -5
  144. package/lib/commands/teardown.js +39 -0
  145. package/lib/commands/test-e2e-external.js +24 -8
  146. package/lib/commands/test-governance-external.js +3 -24
  147. package/lib/commands/test-trust-external.js +48 -100
  148. package/lib/commands/up-common.js +57 -13
  149. package/lib/commands/up-dataplane.js +56 -15
  150. package/lib/commands/upload-publish-context.js +75 -0
  151. package/lib/commands/upload-sidecar-followups.js +89 -0
  152. package/lib/commands/upload.js +113 -110
  153. package/lib/commands/verify-governance-combined-external.js +61 -0
  154. package/lib/commands/verify-governance-command-action.js +64 -0
  155. package/lib/commands/verify-governance-db.js +102 -0
  156. package/lib/commands/verify-governance-external.js +77 -0
  157. package/lib/commands/verify-governance-result-builders.js +71 -0
  158. package/lib/commands/verify-operations-command-action.js +68 -0
  159. package/lib/commands/verify-operations-external.js +268 -0
  160. package/lib/commands/verify-operations-persist.js +75 -0
  161. package/lib/commands/verify-operations-step-plan.js +68 -0
  162. package/lib/commands/verify-operations-steps.js +111 -0
  163. package/lib/commands/verify-trust-command-action.js +73 -0
  164. package/lib/commands/verify-trust-external.js +59 -0
  165. package/lib/commands/wizard-config-normalizer.js +43 -23
  166. package/lib/commands/wizard-core.js +2 -0
  167. package/lib/core/admin-password-generator.js +38 -0
  168. package/lib/core/admin-secrets-bundle.js +111 -0
  169. package/lib/core/admin-secrets-env-overlay.js +62 -0
  170. package/lib/core/admin-secrets.js +32 -4
  171. package/lib/core/config-attach-extensions.js +3 -0
  172. package/lib/core/config-platform-controller.js +44 -0
  173. package/lib/core/config-setup-installation-profile.js +42 -0
  174. package/lib/core/config-setup-platform-mode.js +46 -0
  175. package/lib/core/config.js +46 -36
  176. package/lib/core/secrets-admin-env.js +6 -2
  177. package/lib/core/secrets-ensure.js +4 -0
  178. package/lib/core/secrets-env-content.js +54 -48
  179. package/lib/core/secrets-env-write.js +10 -1
  180. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  181. package/lib/core/setup-installation-profile.js +43 -0
  182. package/lib/core/setup-platform-mode.js +90 -0
  183. package/lib/datasource/agent-trust-debug-log.js +1 -1
  184. package/lib/datasource/agent-trust-run.js +5 -3
  185. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  186. package/lib/datasource/audit-evidence-extract.js +7 -4
  187. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  188. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  189. package/lib/datasource/capability/capability-diff-slice.js +2 -2
  190. package/lib/datasource/capability/capability-manifest.js +254 -0
  191. package/lib/datasource/capability/capability-resolve.js +3 -4
  192. package/lib/datasource/capability/copy-operations.js +5 -3
  193. package/lib/datasource/capability/remove-operations.js +2 -1
  194. package/lib/datasource/capability/run-capability-copy.js +32 -4
  195. package/lib/datasource/capability/run-capability-diff.js +3 -3
  196. package/lib/datasource/capability/run-capability-dimension.js +2 -4
  197. package/lib/datasource/capability/run-capability-edit.js +4 -7
  198. package/lib/datasource/capability/run-capability-relate.js +2 -4
  199. package/lib/datasource/capability/run-capability-remove.js +2 -4
  200. package/lib/datasource/capability/validate-capability-slice.js +2 -1
  201. package/lib/datasource/datasource-identifier.js +2 -1
  202. package/lib/datasource/datasource-load-export-context.js +3 -0
  203. package/lib/datasource/datasource-validate-display.js +1 -1
  204. package/lib/datasource/field-reference-validator.js +24 -3
  205. package/lib/datasource/log-cleaner.js +2 -2
  206. package/lib/datasource/log-viewer.js +8 -8
  207. package/lib/datasource/orphan-profiles-validator.js +98 -0
  208. package/lib/datasource/test-e2e.js +4 -1
  209. package/lib/datasource/unified-validation-run-body.js +3 -1
  210. package/lib/datasource/unified-validation-run.js +5 -2
  211. package/lib/datasource/validate.js +41 -23
  212. package/lib/deployment/environment-poll-status.js +138 -0
  213. package/lib/deployment/environment.js +42 -34
  214. package/lib/external-system/download-helpers.js +87 -0
  215. package/lib/external-system/download.js +78 -138
  216. package/lib/external-system/generator.js +1 -55
  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.js +16 -21
  220. package/lib/generator/builders.js +11 -1
  221. package/lib/generator/external-controller-manifest.js +18 -0
  222. package/lib/generator/split.js +3 -1
  223. package/lib/generator/wizard.js +1 -28
  224. package/lib/governance/governance-cli-errors.js +96 -0
  225. package/lib/governance/governance-download-display.js +38 -0
  226. package/lib/governance/governance-run-display.js +215 -25
  227. package/lib/identity/fk-reference.js +65 -0
  228. package/lib/identity/identity-apply-core.js +13 -58
  229. package/lib/identity/identity-apply-phases.js +5 -1
  230. package/lib/identity/identity-display.js +243 -0
  231. package/lib/identity/identity-response-helpers.js +52 -0
  232. package/lib/identity/identity-sync-errors.js +62 -0
  233. package/lib/identity/resolve-user-id.js +129 -0
  234. package/lib/identity/username-default.js +31 -0
  235. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  236. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  237. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  238. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  239. package/lib/infrastructure/helpers.js +23 -129
  240. package/lib/infrastructure/index.js +5 -6
  241. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  242. package/lib/lifecycle/certification-progress.js +231 -0
  243. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  244. package/lib/lifecycle/exit-codes.js +24 -0
  245. package/lib/lifecycle/json-envelope.js +25 -0
  246. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  247. package/lib/lifecycle/logger-quiet.js +29 -0
  248. package/lib/lifecycle/open-api-published.js +59 -0
  249. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  250. package/lib/lifecycle/product-model.js +196 -0
  251. package/lib/lifecycle/report-display-trust.js +70 -0
  252. package/lib/lifecycle/report-display.js +472 -0
  253. package/lib/lifecycle/scenario-upload.js +191 -0
  254. package/lib/lifecycle/verify-step-progress.js +87 -0
  255. package/lib/parameters/infra-kv-discovery.js +27 -2
  256. package/lib/protection/auth-context.js +10 -4
  257. package/lib/resolvers/datasource-resolver.js +2 -3
  258. package/lib/resolvers/resource-type-file.js +159 -0
  259. package/lib/schema/application-schema.json +17 -1
  260. package/lib/schema/datasource-test-run.schema.json +89 -6
  261. package/lib/schema/deployment-rules.yaml +2 -1
  262. package/lib/schema/external-datasource.schema.json +2947 -2619
  263. package/lib/schema/external-system.schema.json +1418 -761
  264. package/lib/schema/infra.parameter.yaml +45 -0
  265. package/lib/schema/type/credential-field-registry.json +103 -97
  266. package/lib/schema/type/document-storage.json +9 -5
  267. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  268. package/lib/utils/api.js +55 -31
  269. package/lib/utils/app-relative-path-env.js +112 -0
  270. package/lib/utils/app-run-containers.js +25 -2
  271. package/lib/utils/authentication-shape.js +224 -0
  272. package/lib/utils/build-copy.js +36 -5
  273. package/lib/utils/build-resolve-image.js +66 -12
  274. package/lib/utils/celery-companion-apps.js +53 -0
  275. package/lib/utils/cli-secrets-error-format.js +83 -21
  276. package/lib/utils/cli-utils.js +20 -4
  277. package/lib/utils/compose-celery-worker.js +23 -0
  278. package/lib/utils/compose-generate-docker-compose.js +13 -1
  279. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  280. package/lib/utils/config-secrets-path.js +46 -0
  281. package/lib/utils/configuration-env-resolver.js +36 -0
  282. package/lib/utils/controller-url.js +88 -1
  283. package/lib/utils/credential-secrets-env-kv.js +216 -0
  284. package/lib/utils/credential-secrets-env.js +175 -257
  285. package/lib/utils/dataplane-resolver.js +18 -2
  286. package/lib/utils/declarative-url-ports.js +27 -4
  287. package/lib/utils/deployment-auth-mode.js +41 -0
  288. package/lib/utils/developer-volume-id.js +33 -0
  289. package/lib/utils/docker-build.js +1 -4
  290. package/lib/utils/env-copy.js +14 -9
  291. package/lib/utils/env-kv-orphan-lines.js +43 -0
  292. package/lib/utils/error-formatters/network-errors.js +13 -4
  293. package/lib/utils/external-env-template.js +11 -3
  294. package/lib/utils/external-system-readiness-core.js +10 -0
  295. package/lib/utils/external-system-readiness-display.js +80 -23
  296. package/lib/utils/external-system-validators.js +8 -2
  297. package/lib/utils/health-check.js +4 -1
  298. package/lib/utils/help-builder.js +13 -8
  299. package/lib/utils/keycloak-realm-ready.js +101 -0
  300. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  301. package/lib/utils/manifest-source-emit.js +2 -0
  302. package/lib/utils/paths.js +25 -0
  303. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  304. package/lib/utils/platform-controller-url.js +157 -0
  305. package/lib/utils/platform-kv-ref.js +57 -0
  306. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  307. package/lib/utils/postgres-wipe.js +9 -2
  308. package/lib/utils/resolve-env-mode.js +47 -0
  309. package/lib/utils/runtime-configuration-download.js +189 -0
  310. package/lib/utils/runtime-configuration-values.js +119 -0
  311. package/lib/utils/schema-loader.js +19 -4
  312. package/lib/utils/secrets-generator.js +31 -25
  313. package/lib/utils/secrets-missing-error.js +164 -0
  314. package/lib/utils/service-url-label.js +81 -0
  315. package/lib/utils/setup-quiet-output.js +25 -0
  316. package/lib/utils/template-helpers.js +15 -0
  317. package/lib/utils/token-manager-client-credentials.js +201 -0
  318. package/lib/utils/token-manager-messages.js +8 -0
  319. package/lib/utils/token-manager-refresh.js +12 -2
  320. package/lib/utils/token-manager.js +86 -105
  321. package/lib/utils/upload-pipeline-ui.js +12 -5
  322. package/lib/utils/upload-sync-options.js +42 -0
  323. package/lib/utils/url-declarative-public-base.js +21 -3
  324. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  325. package/lib/utils/validation-poll-ui.js +8 -0
  326. package/lib/utils/validation-run-stage.js +45 -0
  327. package/lib/utils/worker-sidecars.js +142 -0
  328. package/lib/validation/external-manifest-validator.js +2 -0
  329. package/lib/validation/runtime-configuration-rules.js +98 -0
  330. package/lib/validation/validate-display-dimensions.js +154 -0
  331. package/lib/validation/validate-display-sections.js +276 -0
  332. package/lib/validation/validate-display-steps.js +67 -0
  333. package/lib/validation/validate-display.js +24 -402
  334. package/package.json +1 -1
  335. package/templates/applications/dataplane/application.yaml +7 -1
  336. package/templates/applications/dataplane/env.template +50 -14
  337. package/templates/applications/dataplane/rbac.yaml +108 -1
  338. package/templates/applications/miso-controller/application.yaml +2 -2
  339. package/templates/applications/miso-controller/env.template +53 -122
  340. package/templates/applications/miso-controller/rbac.yaml +28 -13
  341. package/templates/channels/chatgpt/install.template.md.hbs +49 -0
  342. package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
  343. package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
  344. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
  345. package/templates/channels/slack/install.template.md.hbs +49 -0
  346. package/templates/channels/slack/manifest.template.json.hbs +66 -0
  347. package/templates/channels/teams-bot/install.template.md.hbs +49 -0
  348. package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
  349. package/templates/channels/web-embed/install.template.md.hbs +49 -0
  350. package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
  351. package/templates/external-system/README.md.hbs +74 -17
  352. package/templates/python/docker-compose.hbs +75 -18
  353. package/templates/typescript/docker-compose.hbs +70 -17
  354. package/lib/commands/test-governance-command-action.js +0 -55
  355. package/lib/commands/test-trust-command-action.js +0 -118
@@ -0,0 +1,472 @@
1
+ /**
2
+ * @fileoverview TTY display for Enterprise AI Certification verify + lifecycle commands.
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
+ formatSuccessParagraph,
14
+ formatBlockingError,
15
+ formatWarningLine,
16
+ successGlyph,
17
+ failureGlyph,
18
+ metadata: metaGray
19
+ } = require('../utils/cli-test-layout-chalk');
20
+ const {
21
+ VERDICT,
22
+ formatCertificationStatusDisplay,
23
+ actionHint,
24
+ formatRecommendationAction
25
+ } = require('./product-model');
26
+ const {
27
+ METRIC_KEYS,
28
+ OPERATIONS_METRIC_LABELS
29
+ } = require('./operations-readiness-metrics');
30
+ const { displayGovernanceVerboseDetails } = require('../governance/governance-run-display');
31
+ const {
32
+ formatCertificationLevel,
33
+ formatCriterionCurrentHint,
34
+ resolveNextStepCommand,
35
+ formatProgressBar
36
+ } = require('./certification-progress');
37
+ const {
38
+ displaySubMetricLine,
39
+ displayTrustFindings,
40
+ displayTrustDatasourceRows
41
+ } = require('./report-display-trust');
42
+
43
+ const SEP = '────────────────────────';
44
+
45
+ function displayPillarHeader(systemKey, pillarLabel) {
46
+ logger.log('');
47
+ logger.log(sectionTitle(`${String(systemKey).toUpperCase()} — ${pillarLabel}`));
48
+ }
49
+
50
+ function displayHeroMetric(label, percent) {
51
+ logger.log('');
52
+ logger.log(chalk.white(label));
53
+ if (typeof percent === 'number') {
54
+ logger.log(chalk.cyan.bold(`${percent}%`));
55
+ } else {
56
+ logger.log(chalk.gray('—'));
57
+ }
58
+ logger.log('');
59
+ }
60
+
61
+ function displayVerdictLine(verdict, verifiedLabel, failedLabel) {
62
+ if (verdict === VERDICT.VERIFIED) {
63
+ logger.log(formatSuccessParagraph(verifiedLabel));
64
+ } else {
65
+ logger.log(formatBlockingError(failedLabel));
66
+ }
67
+ }
68
+
69
+ /**
70
+ * @param {string} systemKey
71
+ * @param {Array<{ code: string, action?: string }>} warnings
72
+ */
73
+ function displayPillarWarnings(systemKey, warnings) {
74
+ if (!warnings || warnings.length === 0) return;
75
+ logger.log('');
76
+ for (const w of warnings) {
77
+ const action = w.action || actionHint(systemKey, w.suggestedCommand || 'verify-trust');
78
+ logger.log(formatWarningLine(`${w.message || w.code}. Run: ${action}`));
79
+ }
80
+ }
81
+
82
+ /**
83
+ * @param {Record<string, number>|null} readinessMetrics
84
+ */
85
+ function displayOperationsReadinessMetrics(readinessMetrics) {
86
+ if (!readinessMetrics || typeof readinessMetrics !== 'object') {
87
+ return;
88
+ }
89
+ logger.log('');
90
+ logger.log(chalk.white('Readiness breakdown'));
91
+ logger.log(chalk.gray(SEP));
92
+ for (const key of METRIC_KEYS) {
93
+ const label = OPERATIONS_METRIC_LABELS[key] || key;
94
+ const pct = readinessMetrics[key];
95
+ const value =
96
+ typeof pct === 'number' ? chalk.cyan.bold(`${pct}%`) : chalk.gray('—');
97
+ logger.log(` ${label.padEnd(34)}${value}`);
98
+ }
99
+ }
100
+
101
+ /**
102
+ * @param {Record<string, Record<string, boolean>>} detailsGrouped
103
+ */
104
+ function displayOperationsVerificationSteps(detailsGrouped) {
105
+ logger.log('');
106
+ logger.log(chalk.white('Verification steps'));
107
+ logger.log(chalk.gray(SEP));
108
+ const groups = [
109
+ ['Connectivity', ['credentials', 'authentication', 'authorization']],
110
+ ['Contracts', ['openApi', 'mappings']],
111
+ ['Runtime', ['sync', 'crud', 'execution']],
112
+ ['Reliability', ['validation', 'unitTests', 'integrationTests', 'e2eTests']]
113
+ ];
114
+ const labels = {
115
+ credentials: 'Credentials',
116
+ authentication: 'Authentication',
117
+ authorization: 'Authorization',
118
+ openApi: 'OpenAPI',
119
+ mappings: 'Mappings',
120
+ sync: 'Sync',
121
+ crud: 'CRUD',
122
+ execution: 'Execution',
123
+ validation: 'Validation',
124
+ unitTests: 'Unit Tests',
125
+ integrationTests: 'Integration Tests',
126
+ e2eTests: 'E2E Tests'
127
+ };
128
+ for (const [groupName, keys] of groups) {
129
+ logger.log(chalk.white(groupName));
130
+ for (const key of keys) {
131
+ const passed = detailsGrouped[groupName.toLowerCase()]?.[key] ?? detailsGrouped[key];
132
+ const glyph = passed ? successGlyph() : failureGlyph();
133
+ logger.log(` ${labels[key] || key}`.padEnd(24) + glyph);
134
+ }
135
+ }
136
+ }
137
+
138
+ /**
139
+ * @param {string} systemKey
140
+ * @param {Object} result
141
+ * @param {{ details?: boolean, warnings?: Array }} opts
142
+ */
143
+ function displayVerifyOperationsTTY(systemKey, result, opts = {}) {
144
+ displayPillarHeader(systemKey, 'OPERATIONS');
145
+ displayHeroMetric('Operational Readiness', result.operationalReadinessPercent);
146
+ displayVerdictLine(
147
+ result.verdict,
148
+ 'OPERATIONS VERIFIED',
149
+ 'OPERATIONS FAILED'
150
+ );
151
+ displayPillarWarnings(systemKey, result.warnings);
152
+ if (opts.details === true) {
153
+ displayOperationsReadinessMetrics(result.readinessMetrics);
154
+ if (result.details) {
155
+ displayOperationsVerificationSteps(result.details);
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * @param {string} systemKey
162
+ * @param {Object} result
163
+ * @param {{ details?: boolean }} opts
164
+ */
165
+ function displayVerifyTrustTTY(systemKey, result, opts = {}) {
166
+ displayPillarHeader(systemKey, 'AI TRUST REPORT');
167
+ displayHeroMetric('Overall', result.aiTrustPercent);
168
+ logger.log('');
169
+ displaySubMetricLine('Access Confidence', result.accessConfidencePercent);
170
+ displaySubMetricLine('Business Confidence', result.businessConfidencePercent);
171
+ displayVerdictLine(result.verdict, 'AI TRUST VERIFIED', 'AI TRUST FAILED');
172
+ displayTrustFindings(result.findings);
173
+ if (opts.details === true) {
174
+ displayTrustDatasourceRows(result.datasourceRows);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * @param {string} systemKey
180
+ * @param {Object} result
181
+ * @param {{ details?: boolean }} opts
182
+ */
183
+ function displayVerifyGovernanceTTY(systemKey, result, opts = {}) {
184
+ displayPillarHeader(systemKey, 'GOVERNANCE');
185
+ displayHeroMetric('Policy Coverage', result.policyCoveragePercent);
186
+ logger.log(chalk.white('Dimension Coverage'));
187
+ logger.log(
188
+ typeof result.dimensionCoveragePercent === 'number'
189
+ ? chalk.cyan.bold(`${result.dimensionCoveragePercent}%`)
190
+ : chalk.gray('—')
191
+ );
192
+ logger.log('');
193
+ const scenarios = result.enforcementScenarios || {};
194
+ const total = scenarios.total || 0;
195
+ const passed = scenarios.passed || 0;
196
+ logger.log(chalk.white('Enforcement Scenarios'));
197
+ logger.log(chalk.cyan.bold(`${passed}/${total} Passed`));
198
+ logger.log('');
199
+ displayVerdictLine(result.verdict, 'GOVERNANCE VERIFIED', 'GOVERNANCE FAILED');
200
+ if (opts.details === true) {
201
+ displayGovernanceVerboseDetails(result);
202
+ }
203
+ }
204
+
205
+ function formatPillarLine(label, verdict) {
206
+ if (verdict === VERDICT.VERIFIED) {
207
+ return `${label.padEnd(24)}${successGlyph()} VERIFIED`;
208
+ }
209
+ if (verdict === VERDICT.FAILED) {
210
+ return `${label.padEnd(24)}${failureGlyph()} FAILED`;
211
+ }
212
+ return `${label.padEnd(24)}— NOT VERIFIED`;
213
+ }
214
+
215
+ /**
216
+ * @param {string} label
217
+ * @param {number|undefined} percent
218
+ * @param {string|undefined} verdict
219
+ * @returns {string}
220
+ */
221
+ function formatPillarScoreLine(label, percent, verdict) {
222
+ const COL_LABEL = 22;
223
+ const COL_PCT = 10;
224
+ const pctPlain =
225
+ typeof percent === 'number' && Number.isFinite(percent)
226
+ ? `${Math.round(percent)}%`
227
+ : '—';
228
+ const pctStr =
229
+ typeof percent === 'number' && Number.isFinite(percent)
230
+ ? chalk.cyan.bold(pctPlain)
231
+ : chalk.gray(pctPlain);
232
+ const verdictPart = formatPillarLine('', verdict).trim();
233
+ const pctGap = Math.max(2, COL_PCT - pctPlain.length);
234
+ return `${label.padEnd(COL_LABEL)}${pctStr}${' '.repeat(pctGap)}${verdictPart}`;
235
+ }
236
+
237
+ /** Longest Silver→Gold criterion label ("Operational Readiness ≥ 90%"). */
238
+ const CRITERION_LABEL_COL = 32;
239
+
240
+ /**
241
+ * @param {string} glyph
242
+ * @param {string} label
243
+ * @param {string|null|undefined} hintPlain
244
+ * @returns {string}
245
+ */
246
+ function formatCriterionProgressLine(glyph, label, hintPlain) {
247
+ const prefix = ` ${glyph} `;
248
+ if (!hintPlain) {
249
+ return `${prefix}${label}`;
250
+ }
251
+ const gap = Math.max(2, CRITERION_LABEL_COL - label.length);
252
+ return `${prefix}${label}${' '.repeat(gap)}${metaGray(hintPlain)}`;
253
+ }
254
+
255
+ /**
256
+ * @param {Object} report
257
+ */
258
+ function displayPillarScores(report) {
259
+ logger.log(chalk.white('Pillar scores'));
260
+ logger.log(chalk.gray(SEP));
261
+ logger.log(
262
+ formatPillarScoreLine(
263
+ 'Operations',
264
+ report.operations?.operationalReadinessPercent,
265
+ report.operations?.verdict
266
+ )
267
+ );
268
+ logger.log(
269
+ formatPillarScoreLine(
270
+ 'AI Trust',
271
+ report.trust?.aiTrustPercent,
272
+ report.trust?.verdict
273
+ )
274
+ );
275
+ logger.log(
276
+ formatPillarScoreLine(
277
+ 'Governance',
278
+ report.governance?.policyCoveragePercent,
279
+ report.governance?.verdict
280
+ )
281
+ );
282
+ logger.log('');
283
+ }
284
+
285
+ /**
286
+ * @param {import('./certification-progress').CertificationProgressViewModel} progress
287
+ */
288
+ function displayHighestTierAchieved(progress) {
289
+ logger.log(
290
+ metaGray(
291
+ `Current: ${formatCertificationLevel(progress.currentLevel)} — highest tier achieved`
292
+ )
293
+ );
294
+ logger.log('');
295
+ }
296
+
297
+ /**
298
+ * @param {import('./certification-progress').CertificationProgressViewModel} progress
299
+ */
300
+ function displayProgressTargetHeader(progress) {
301
+ const targetLabel = formatCertificationLevel(progress.targetLevel);
302
+ const headerSuffix =
303
+ progress.mode === 'progress' && typeof progress.progressPercent === 'number'
304
+ ? ` (${progress.progressPercent}%)`
305
+ : '';
306
+ logger.log(
307
+ chalk.white(
308
+ `Current: ${formatCertificationLevel(progress.currentLevel).toUpperCase()} → Progress to ${targetLabel.toUpperCase()}${headerSuffix}`
309
+ )
310
+ );
311
+ logger.log('');
312
+ }
313
+
314
+ /**
315
+ * @param {Object} report
316
+ * @param {import('./certification-progress').CertificationProgressViewModel} progress
317
+ * @param {boolean} openApiPublished
318
+ */
319
+ function displayProgressCriteriaRows(report, progress, openApiPublished) {
320
+ if (progress.criteria.length === 0) {
321
+ logger.log(
322
+ metaGray(
323
+ `Progress criteria for ${formatCertificationLevel(progress.targetLevel)} are not configured yet.`
324
+ )
325
+ );
326
+ logger.log('');
327
+ return;
328
+ }
329
+ for (const row of progress.criteria) {
330
+ const glyph = row.met ? successGlyph() : failureGlyph();
331
+ const hintPlain = row.met
332
+ ? null
333
+ : formatCriterionCurrentHint(row.id, report, openApiPublished);
334
+ logger.log(formatCriterionProgressLine(glyph, row.label, hintPlain));
335
+ }
336
+ }
337
+
338
+ /**
339
+ * @param {import('./certification-progress').CertificationProgressViewModel} progress
340
+ */
341
+ function displayProgressBarRow(progress) {
342
+ if (progress.mode !== 'progress' || typeof progress.progressPercent !== 'number') {
343
+ return;
344
+ }
345
+ logger.log('');
346
+ const targetLabel = formatCertificationLevel(progress.targetLevel);
347
+ const barPlain = formatProgressBar(progress.progressPercent);
348
+ const pctPlain = `${progress.progressPercent}%`;
349
+ const progressLabel = `${targetLabel} progress`;
350
+ logger.log(
351
+ ` ${progressLabel.padEnd(18)} ${chalk.cyan(barPlain)} ${chalk.cyan.bold(pctPlain)}`
352
+ );
353
+ }
354
+
355
+ /**
356
+ * @param {string} systemKey
357
+ * @param {Object} report
358
+ * @param {import('./certification-progress').CertificationProgressViewModel|null} progress
359
+ * @param {boolean} openApiPublished
360
+ * @param {string|null} dataplaneUrl
361
+ * @param {string|null} [dataplaneUiBaseUrl]
362
+ */
363
+ function displayCertificationProgressBlock(
364
+ systemKey,
365
+ report,
366
+ progress,
367
+ openApiPublished,
368
+ dataplaneUrl,
369
+ dataplaneUiBaseUrl = null
370
+ ) {
371
+ if (!progress) {
372
+ return;
373
+ }
374
+ logger.log(chalk.white('Certification progress'));
375
+ logger.log(chalk.gray(SEP));
376
+ if (progress.highestTierAchieved) {
377
+ displayHighestTierAchieved(progress);
378
+ return;
379
+ }
380
+ displayProgressTargetHeader(progress);
381
+ displayProgressCriteriaRows(report, progress, openApiPublished);
382
+ displayProgressBarRow(progress);
383
+ const nextStep = resolveNextStepCommand(systemKey, progress, {
384
+ dataplaneUrl,
385
+ dataplaneUiBaseUrl
386
+ });
387
+ if (nextStep) {
388
+ logger.log('');
389
+ logger.log(chalk.white('Next step:') + ` ${nextStep}`);
390
+ }
391
+ logger.log('');
392
+ }
393
+
394
+ function displayCertificationSummary(report) {
395
+ const level = report.certification?.level || 'NONE';
396
+ const status = report.certification?.status || 'NOT_CERTIFIED';
397
+ logger.log(chalk.white('Certification'));
398
+ logger.log(chalk.gray(SEP));
399
+ logger.log(chalk.cyan.bold(level));
400
+ logger.log('');
401
+ logger.log(chalk.white('Status'));
402
+ logger.log(chalk.gray(SEP));
403
+ logger.log(formatCertificationStatusDisplay(status));
404
+ logger.log('');
405
+ }
406
+
407
+ /**
408
+ * @param {string} systemKey
409
+ * @param {Array<{ code: string, action?: string }>} recs
410
+ */
411
+ function displayRecommendationsBlock(systemKey, recs) {
412
+ if (recs.length === 0) {
413
+ return;
414
+ }
415
+ logger.log('');
416
+ logger.log(chalk.white('Recommendations'));
417
+ logger.log(chalk.gray(SEP));
418
+ logger.log(metaGray(`${recs.length} improvement${recs.length === 1 ? '' : 's'} available`));
419
+ for (const rec of recs) {
420
+ logger.log(` • ${formatRecommendationAction(systemKey, rec)}`);
421
+ }
422
+ }
423
+
424
+ /**
425
+ * @param {Array<Object>} datasources
426
+ */
427
+ function displayDatasourceBreakdown(datasources) {
428
+ logger.log('');
429
+ logger.log(chalk.white('Datasource breakdown'));
430
+ logger.log(chalk.gray(SEP));
431
+ for (const ds of datasources) {
432
+ logger.log(chalk.white(` ${ds.datasourceKey}`));
433
+ logger.log(` ${formatPillarLine('Operations', ds.operations?.verdict).trim()}`);
434
+ logger.log(` ${formatPillarLine('AI Trust', ds.trust?.verdict).trim()}`);
435
+ logger.log(` ${formatPillarLine('Governance', ds.governance?.verdict).trim()}`);
436
+ }
437
+ }
438
+
439
+ /**
440
+ * @param {string} systemKey
441
+ * @param {Object} report - SystemLifecycleReport shape
442
+ * @param {{ details?: boolean, certificationProgress?: Object|null, openApiPublished?: boolean, dataplaneUrl?: string|null, dataplaneUiBaseUrl?: string|null }} opts
443
+ */
444
+ function displayLifecycleReportTTY(systemKey, report, opts = {}) {
445
+ logger.log('');
446
+ logger.log(sectionTitle(`${String(systemKey).toUpperCase()} CERTIFICATION REPORT`));
447
+ logger.log('');
448
+ displayCertificationSummary(report);
449
+ displayPillarScores(report);
450
+ displayCertificationProgressBlock(
451
+ systemKey,
452
+ report,
453
+ opts.certificationProgress ?? null,
454
+ opts.openApiPublished === true,
455
+ opts.dataplaneUrl ?? null,
456
+ opts.dataplaneUiBaseUrl ?? null
457
+ );
458
+ displayRecommendationsBlock(systemKey, report.recommendations || []);
459
+ if (opts.details === true && Array.isArray(report.datasources) && report.datasources.length > 0) {
460
+ displayDatasourceBreakdown(report.datasources);
461
+ }
462
+ logger.log('');
463
+ }
464
+
465
+ module.exports = {
466
+ displayVerifyOperationsTTY,
467
+ displayVerifyTrustTTY,
468
+ displayVerifyGovernanceTTY,
469
+ displayLifecycleReportTTY,
470
+ displayOperationsReadinessMetrics,
471
+ displayOperationsVerificationSteps
472
+ };
@@ -0,0 +1,191 @@
1
+ /**
2
+ * @fileoverview Upload local governance scenario YAML packs to dataplane (419.0).
3
+ * @author AI Fabrix Team
4
+ * @version 1.0.0
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const {
11
+ existsSync,
12
+ readFileSync,
13
+ readdirSync,
14
+ mkdirSync,
15
+ writeFileSync
16
+ } = require('../internal/fs-real-sync');
17
+ const yaml = require('js-yaml');
18
+ const logger = require('../utils/logger');
19
+ const { getIntegrationPath } = require('../utils/paths');
20
+ const { upsertDatasourceGovernancePack } = require('../api/governance-scenario-pack.api');
21
+ const { formatSuccessLine, formatWarningLine } = require('../utils/cli-test-layout-chalk');
22
+ const { shortGovernanceApiError } = require('../governance/governance-cli-errors');
23
+ const { printGovernanceDownloadMisses } = require('../governance/governance-download-display');
24
+
25
+ /**
26
+ * @param {string} scenariosDir
27
+ * @returns {string[]}
28
+ */
29
+ function listScenarioYamlFiles(scenariosDir) {
30
+ if (!existsSync(scenariosDir)) return [];
31
+ return readdirSync(scenariosDir)
32
+ .filter(name => name.endsWith('.yaml') || name.endsWith('.yml'))
33
+ .map(name => path.join(scenariosDir, name));
34
+ }
35
+
36
+ /**
37
+ * Extract datasource keys referenced in a pack document.
38
+ * @param {Object} pack
39
+ * @returns {string[]}
40
+ */
41
+ function datasourceKeysFromPack(pack) {
42
+ const keys = new Set();
43
+ const scenarios = pack?.spec?.scenarios || [];
44
+ for (const scenario of scenarios) {
45
+ const dsKeys = scenario?.search?.datasourceKeys || [];
46
+ for (const k of dsKeys) {
47
+ if (k && typeof k === 'string') keys.add(k.trim());
48
+ }
49
+ }
50
+ return [...keys];
51
+ }
52
+
53
+ /**
54
+ * @param {string} filePath
55
+ * @returns {Object}
56
+ */
57
+ function loadPackFromFile(filePath) {
58
+ const raw = readFileSync(filePath, 'utf8');
59
+ const doc = yaml.load(raw);
60
+ if (!doc || typeof doc !== 'object') {
61
+ throw new Error(`Invalid scenario pack YAML: ${filePath}`);
62
+ }
63
+ return doc;
64
+ }
65
+
66
+ /**
67
+ * Upload scenario packs under integration/<systemKey>/scenarios/ to dataplane.
68
+ * @async
69
+ * @param {string} systemKey
70
+ * @param {string} dataplaneUrl
71
+ * @param {Object} authConfig
72
+ * @param {{ silent?: boolean }} [opts]
73
+ * @returns {Promise<number>} count of packs uploaded
74
+ */
75
+ async function uploadGovernanceScenarioPacks(systemKey, dataplaneUrl, authConfig, opts = {}) {
76
+ const scenariosDir = path.join(getIntegrationPath(systemKey), 'scenarios');
77
+ const files = listScenarioYamlFiles(scenariosDir);
78
+ if (files.length === 0) return 0;
79
+
80
+ let uploaded = 0;
81
+ for (const filePath of files) {
82
+ const pack = loadPackFromFile(filePath);
83
+ const dsKeys = datasourceKeysFromPack(pack);
84
+ if (dsKeys.length === 0) {
85
+ if (!opts.silent) {
86
+ logger.log(
87
+ formatWarningLine(
88
+ `Skipping ${path.basename(filePath)} — no datasourceKeys in scenarios`
89
+ )
90
+ );
91
+ }
92
+ continue;
93
+ }
94
+ for (const dsKey of dsKeys) {
95
+ await upsertDatasourceGovernancePack(dataplaneUrl, authConfig, dsKey, pack);
96
+ uploaded += 1;
97
+ if (!opts.silent) {
98
+ logger.log(
99
+ formatSuccessLine(
100
+ `Governance scenario pack uploaded for ${dsKey} (${path.basename(filePath)})`
101
+ )
102
+ );
103
+ }
104
+ }
105
+ }
106
+ return uploaded;
107
+ }
108
+
109
+ /**
110
+ * Write governance scenario packs from dataplane to integration/<systemKey>/scenarios/.
111
+ * @async
112
+ * @param {string} systemKey
113
+ * @param {string[]} datasourceKeys
114
+ * @param {string} dataplaneUrl
115
+ * @param {Object} authConfig
116
+ * @returns {Promise<number>}
117
+ */
118
+ async function downloadGovernanceScenarioPacks(
119
+ systemKey,
120
+ datasourceKeys,
121
+ dataplaneUrl,
122
+ authConfig
123
+ ) {
124
+ const { getDatasourceGovernancePack } = require('../api/governance-scenario-pack.api');
125
+ const scenariosDir = path.join(getIntegrationPath(systemKey), 'scenarios');
126
+ if (!existsSync(scenariosDir)) {
127
+ mkdirSync(scenariosDir, { recursive: true });
128
+ }
129
+
130
+ let written = 0;
131
+ const missing = [];
132
+ for (const dsKey of datasourceKeys) {
133
+ try {
134
+ const row = await getDatasourceGovernancePack(dataplaneUrl, authConfig, dsKey);
135
+ if (!row || !row.pack) {
136
+ missing.push({
137
+ datasourceKey: dsKey,
138
+ reason: 'No active pack on dataplane'
139
+ });
140
+ continue;
141
+ }
142
+ const outPath = path.join(scenariosDir, `${dsKey}.yaml`);
143
+ writeFileSync(outPath, yaml.dump(row.pack, { lineWidth: 120 }), 'utf8');
144
+ written += 1;
145
+ logger.log(formatSuccessLine(`Scenario pack saved: ${outPath}`));
146
+ } catch (err) {
147
+ missing.push({
148
+ datasourceKey: dsKey,
149
+ reason: shortGovernanceApiError(err)
150
+ });
151
+ }
152
+ }
153
+ printGovernanceDownloadMisses(missing);
154
+ return written;
155
+ }
156
+
157
+ /**
158
+ * Download governance packs for all datasource keys on a running manifest.
159
+ * @async
160
+ * @param {string} systemKey
161
+ * @param {Object} manifest
162
+ * @param {string} dataplaneUrl
163
+ * @param {Object} authConfig
164
+ * @returns {Promise<number>}
165
+ */
166
+ async function downloadGovernanceScenarioPacksFromManifest(
167
+ systemKey,
168
+ manifest,
169
+ dataplaneUrl,
170
+ authConfig
171
+ ) {
172
+ const dsKeys = (manifest.dataSources || []).map((ds) => ds && ds.key).filter(Boolean);
173
+ if (dsKeys.length === 0) {
174
+ return 0;
175
+ }
176
+ try {
177
+ return await downloadGovernanceScenarioPacks(systemKey, dsKeys, dataplaneUrl, authConfig);
178
+ } catch (err) {
179
+ logger.log(formatWarningLine(`Governance scenario download skipped: ${err.message}`));
180
+ return 0;
181
+ }
182
+ }
183
+
184
+ module.exports = {
185
+ listScenarioYamlFiles,
186
+ datasourceKeysFromPack,
187
+ loadPackFromFile,
188
+ uploadGovernanceScenarioPacks,
189
+ downloadGovernanceScenarioPacks,
190
+ downloadGovernanceScenarioPacksFromManifest
191
+ };