@aifabrix/builder 2.45.5 → 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 (231) 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/README.md +43 -17
  5. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
  6. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.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 +41 -136
  12. package/lib/api/api-response-errors.js +124 -0
  13. package/lib/api/governance-scenario-pack.api.js +159 -0
  14. package/lib/api/index.js +43 -3
  15. package/lib/api/lifecycle.api.js +77 -0
  16. package/lib/api/pipeline.api.js +3 -1
  17. package/lib/api/records-bulk.api.js +14 -1
  18. package/lib/api/validation-runner.js +3 -1
  19. package/lib/app/deploy-config.js +4 -1
  20. package/lib/app/down.js +20 -1
  21. package/lib/app/push.js +4 -5
  22. package/lib/app/register.js +7 -4
  23. package/lib/app/run-env-compose.js +84 -30
  24. package/lib/build/index.js +5 -0
  25. package/lib/certification/sync-system-certification.js +13 -6
  26. package/lib/cli/index.js +4 -0
  27. package/lib/cli/infra-guided-auth.js +109 -0
  28. package/lib/cli/infra-guided.js +84 -81
  29. package/lib/cli/setup-app.help.js +0 -31
  30. package/lib/cli/setup-app.js +28 -2
  31. package/lib/cli/setup-app.test-commands.js +5 -57
  32. package/lib/cli/setup-auth.js +25 -0
  33. package/lib/cli/setup-certification-commands.js +147 -0
  34. package/lib/cli/setup-certification.help.js +141 -0
  35. package/lib/cli/setup-environment.js +19 -2
  36. package/lib/cli/setup-external-system-help.js +62 -0
  37. package/lib/cli/setup-external-system.js +25 -3
  38. package/lib/cli/setup-infra.js +9 -1
  39. package/lib/cli/setup-platform.js +6 -1
  40. package/lib/cli/setup-secrets.js +33 -1
  41. package/lib/cli/setup-utility-help-after.js +22 -2
  42. package/lib/cli/setup-utility-repair.js +198 -0
  43. package/lib/cli/setup-utility-resolve.js +40 -4
  44. package/lib/cli/setup-utility-validate.js +197 -0
  45. package/lib/cli/setup-utility.js +4 -239
  46. package/lib/commands/auth-status-client-tokens.js +214 -0
  47. package/lib/commands/auth-status-dataplane-version.js +58 -20
  48. package/lib/commands/auth-status.js +41 -47
  49. package/lib/commands/datasource-test-trust-cli.js +27 -23
  50. package/lib/commands/datasource-unified-test-cli.js +6 -3
  51. package/lib/commands/datasource-unified-test-cli.options.js +5 -1
  52. package/lib/commands/datasource.js +7 -7
  53. package/lib/commands/dev-show-display.js +8 -1
  54. package/lib/commands/governance-cli-shared.js +94 -0
  55. package/lib/commands/governance-command-action.js +132 -0
  56. package/lib/commands/governance-download-external.js +34 -0
  57. package/lib/commands/governance-generate-external.js +71 -0
  58. package/lib/commands/governance-upload-external.js +36 -0
  59. package/lib/commands/governance-verify-external.js +64 -0
  60. package/lib/commands/governance.js +144 -0
  61. package/lib/commands/lifecycle-command-action.js +123 -0
  62. package/lib/commands/lifecycle-external.js +268 -0
  63. package/lib/commands/login.js +11 -2
  64. package/lib/commands/repair-auth-apply.js +127 -0
  65. package/lib/commands/repair-changed-files.js +41 -0
  66. package/lib/commands/repair-datasource-keys.js +4 -1
  67. package/lib/commands/repair-datasource-run.js +59 -0
  68. package/lib/commands/repair-datasource-test-payload.js +259 -0
  69. package/lib/commands/repair-datasource.js +1 -51
  70. package/lib/commands/repair-env-template.js +64 -13
  71. package/lib/commands/repair-external-run.js +216 -0
  72. package/lib/commands/repair-openapi-sync.js +23 -0
  73. package/lib/commands/repair-persist.js +4 -0
  74. package/lib/commands/repair-rbac.js +52 -1
  75. package/lib/commands/repair-steps.js +145 -0
  76. package/lib/commands/repair.js +29 -296
  77. package/lib/commands/secrets-get.js +184 -0
  78. package/lib/commands/secrets-remove-all.js +3 -1
  79. package/lib/commands/setup-image-refresh.js +146 -0
  80. package/lib/commands/setup-modes.js +158 -162
  81. package/lib/commands/setup-platform-auth.js +76 -0
  82. package/lib/commands/setup-prompts-admin.js +244 -0
  83. package/lib/commands/setup-prompts-platform-mode.js +67 -0
  84. package/lib/commands/setup-prompts-validators.js +36 -0
  85. package/lib/commands/setup-prompts.js +24 -76
  86. package/lib/commands/setup-run-context.js +45 -0
  87. package/lib/commands/setup-spinners.js +39 -0
  88. package/lib/commands/setup.js +27 -5
  89. package/lib/commands/teardown.js +39 -0
  90. package/lib/commands/test-e2e-external.js +24 -8
  91. package/lib/commands/test-governance-external.js +3 -24
  92. package/lib/commands/test-trust-external.js +20 -21
  93. package/lib/commands/up-common.js +25 -13
  94. package/lib/commands/up-dataplane.js +50 -13
  95. package/lib/commands/upload-publish-context.js +75 -0
  96. package/lib/commands/upload-sidecar-followups.js +89 -0
  97. package/lib/commands/upload.js +90 -108
  98. package/lib/commands/verify-governance-combined-external.js +61 -0
  99. package/lib/commands/verify-governance-command-action.js +64 -0
  100. package/lib/commands/verify-governance-db.js +102 -0
  101. package/lib/commands/verify-governance-external.js +77 -0
  102. package/lib/commands/verify-governance-result-builders.js +71 -0
  103. package/lib/commands/verify-operations-command-action.js +68 -0
  104. package/lib/commands/verify-operations-external.js +268 -0
  105. package/lib/commands/verify-operations-persist.js +75 -0
  106. package/lib/commands/verify-operations-step-plan.js +68 -0
  107. package/lib/commands/verify-operations-steps.js +111 -0
  108. package/lib/commands/verify-trust-command-action.js +70 -0
  109. package/lib/commands/verify-trust-external.js +67 -0
  110. package/lib/commands/wizard-config-normalizer.js +43 -23
  111. package/lib/commands/wizard-core.js +2 -0
  112. package/lib/core/admin-password-generator.js +38 -0
  113. package/lib/core/admin-secrets-bundle.js +111 -0
  114. package/lib/core/admin-secrets-env-overlay.js +62 -0
  115. package/lib/core/admin-secrets.js +32 -4
  116. package/lib/core/config-attach-extensions.js +3 -0
  117. package/lib/core/config-platform-controller.js +44 -0
  118. package/lib/core/config-setup-installation-profile.js +42 -0
  119. package/lib/core/config-setup-platform-mode.js +46 -0
  120. package/lib/core/config.js +46 -36
  121. package/lib/core/secrets-admin-env.js +6 -2
  122. package/lib/core/secrets-ensure.js +4 -0
  123. package/lib/core/secrets-env-content.js +54 -48
  124. package/lib/core/secrets-env-write.js +10 -1
  125. package/lib/core/secrets-infra-placeholder-sync.js +2 -0
  126. package/lib/core/setup-installation-profile.js +43 -0
  127. package/lib/core/setup-platform-mode.js +55 -0
  128. package/lib/datasource/agent-trust-debug-log.js +1 -1
  129. package/lib/datasource/agent-trust-run.js +5 -3
  130. package/lib/datasource/audit-evidence-extract-debug.js +30 -18
  131. package/lib/datasource/audit-evidence-extract.js +7 -4
  132. package/lib/datasource/audit-evidence-verify-matrix.js +54 -26
  133. package/lib/datasource/bulk-loader-run-batches.js +15 -3
  134. package/lib/datasource/datasource-load-export-context.js +3 -0
  135. package/lib/datasource/log-cleaner.js +2 -2
  136. package/lib/datasource/log-viewer.js +8 -8
  137. package/lib/datasource/test-e2e.js +4 -1
  138. package/lib/datasource/unified-validation-run-body.js +3 -1
  139. package/lib/datasource/unified-validation-run.js +5 -2
  140. package/lib/deployment/environment-poll-status.js +138 -0
  141. package/lib/deployment/environment.js +42 -34
  142. package/lib/external-system/download.js +21 -20
  143. package/lib/external-system/generator.js +5 -1
  144. package/lib/external-system/integration-auth-context.js +45 -0
  145. package/lib/external-system/test-auth.js +12 -5
  146. package/lib/external-system/test.js +6 -6
  147. package/lib/generator/external-controller-manifest.js +15 -0
  148. package/lib/governance/governance-cli-errors.js +96 -0
  149. package/lib/governance/governance-download-display.js +38 -0
  150. package/lib/governance/governance-run-display.js +215 -25
  151. package/lib/infrastructure/admin-secrets-apply.js +84 -0
  152. package/lib/infrastructure/admin-secrets-ensure.js +130 -0
  153. package/lib/infrastructure/admin-secrets-resolve.js +95 -0
  154. package/lib/infrastructure/admin-secrets-sync.js +91 -0
  155. package/lib/infrastructure/helpers.js +23 -129
  156. package/lib/infrastructure/index.js +5 -6
  157. package/lib/infrastructure/orphan-infra-docker-teardown.js +11 -5
  158. package/lib/lifecycle/certification-progress.js +231 -0
  159. package/lib/lifecycle/dataplane-ui-url.js +145 -0
  160. package/lib/lifecycle/exit-codes.js +24 -0
  161. package/lib/lifecycle/json-envelope.js +25 -0
  162. package/lib/lifecycle/lifecycle-governance-options.js +51 -0
  163. package/lib/lifecycle/logger-quiet.js +29 -0
  164. package/lib/lifecycle/open-api-published.js +59 -0
  165. package/lib/lifecycle/operations-readiness-metrics.js +101 -0
  166. package/lib/lifecycle/product-model.js +196 -0
  167. package/lib/lifecycle/report-display.js +471 -0
  168. package/lib/lifecycle/scenario-upload.js +191 -0
  169. package/lib/lifecycle/verify-step-progress.js +87 -0
  170. package/lib/parameters/infra-kv-discovery.js +27 -2
  171. package/lib/protection/auth-context.js +10 -4
  172. package/lib/schema/application-schema.json +1 -1
  173. package/lib/schema/datasource-test-run.schema.json +89 -6
  174. package/lib/schema/external-datasource.schema.json +2636 -2622
  175. package/lib/schema/external-system.schema.json +1089 -761
  176. package/lib/schema/infra.parameter.yaml +45 -0
  177. package/lib/schema/type/credential-field-registry.json +103 -97
  178. package/lib/utils/aifabrix-test-runtime-guard.js +125 -0
  179. package/lib/utils/api.js +55 -31
  180. package/lib/utils/app-relative-path-env.js +112 -0
  181. package/lib/utils/cli-secrets-error-format.js +83 -21
  182. package/lib/utils/cli-utils.js +16 -4
  183. package/lib/utils/compose-generate-docker-compose.js +4 -0
  184. package/lib/utils/compose-traefik-ingress-base.js +16 -1
  185. package/lib/utils/config-secrets-path.js +46 -0
  186. package/lib/utils/controller-url.js +88 -1
  187. package/lib/utils/credential-secrets-env.js +137 -9
  188. package/lib/utils/dataplane-resolver.js +129 -2
  189. package/lib/utils/declarative-url-ports.js +3 -3
  190. package/lib/utils/deployment-auth-mode.js +41 -0
  191. package/lib/utils/developer-volume-id.js +33 -0
  192. package/lib/utils/env-copy.js +14 -9
  193. package/lib/utils/env-kv-orphan-lines.js +43 -0
  194. package/lib/utils/error-formatters/network-errors.js +13 -4
  195. package/lib/utils/external-env-template.js +1 -0
  196. package/lib/utils/external-system-readiness-core.js +10 -0
  197. package/lib/utils/external-system-readiness-display.js +80 -23
  198. package/lib/utils/health-check.js +4 -1
  199. package/lib/utils/help-builder.js +11 -8
  200. package/lib/utils/keycloak-realm-ready.js +101 -0
  201. package/lib/utils/load-cip-capacity-display-config.js +61 -15
  202. package/lib/utils/manifest-source-emit.js +2 -0
  203. package/lib/utils/pipeline-upload-auth-retry.js +82 -0
  204. package/lib/utils/platform-controller-url.js +156 -0
  205. package/lib/utils/postgres-platform-bootstrap.js +199 -0
  206. package/lib/utils/postgres-wipe.js +9 -2
  207. package/lib/utils/resolve-env-mode.js +47 -0
  208. package/lib/utils/secrets-generator.js +31 -25
  209. package/lib/utils/secrets-missing-error.js +164 -0
  210. package/lib/utils/service-url-label.js +81 -0
  211. package/lib/utils/setup-quiet-output.js +25 -0
  212. package/lib/utils/template-helpers.js +15 -0
  213. package/lib/utils/token-manager-client-credentials.js +201 -0
  214. package/lib/utils/token-manager-messages.js +8 -0
  215. package/lib/utils/token-manager-refresh.js +12 -2
  216. package/lib/utils/token-manager.js +86 -105
  217. package/lib/utils/upload-pipeline-ui.js +12 -5
  218. package/lib/utils/upload-sync-options.js +42 -0
  219. package/lib/utils/url-declarative-public-base.js +21 -3
  220. package/lib/utils/url-declarative-vdir-inactive-env.js +14 -4
  221. package/lib/utils/validation-poll-ui.js +8 -0
  222. package/lib/utils/validation-run-stage.js +45 -0
  223. package/package.json +1 -1
  224. package/templates/applications/dataplane/application.yaml +2 -1
  225. package/templates/applications/dataplane/env.template +24 -1
  226. package/templates/applications/miso-controller/env.template +16 -0
  227. package/templates/external-system/README.md.hbs +74 -17
  228. package/templates/python/docker-compose.hbs +19 -18
  229. package/templates/typescript/docker-compose.hbs +18 -17
  230. package/lib/commands/test-governance-command-action.js +0 -55
  231. package/lib/commands/test-trust-command-action.js +0 -118
@@ -15,6 +15,7 @@ const yaml = require('js-yaml');
15
15
  const { existsSync, readFileSync } = require('../internal/fs-real-sync');
16
16
  const { DECLARATIVE_URL_INFRA_DEFAULTS } = require('./infra-env-defaults');
17
17
  const { computePathActive } = require('./url-declarative-url-flags');
18
+ const { resolveInactiveVdirRewriteEnvKeys } = require('./app-relative-path-env');
18
19
 
19
20
  /**
20
21
  * Treat common YAML / string forms as enabled (strict `=== true` alone missed some parsers).
@@ -52,16 +53,22 @@ const INACTIVE_VDIR_PUBLIC_ENV_FALLBACK =
52
53
  /**
53
54
  * @param {string} content - .env template fragment
54
55
  * @param {string} replacement
56
+ * @param {ReadonlySet<string>} rewriteKeys
55
57
  * @returns {string}
56
58
  */
57
- function applyInactiveVdirPublicTokenRewrite(content, replacement) {
59
+ function applyInactiveVdirPublicTokenRewrite(content, replacement, rewriteKeys) {
58
60
  if (!content || !content.includes(URL_DECLARATIVE_VDIR_PUBLIC_TOKEN)) {
59
61
  return content;
60
62
  }
61
63
  const escaped = URL_DECLARATIVE_VDIR_PUBLIC_TOKEN.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
62
64
  // End line with [ \t]* only — \s would consume \n and strip line endings from the file.
63
- const lineRe = new RegExp(`^(\\s*[A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
64
- return content.replace(lineRe, (_, lhs) => `${lhs}=${replacement}`);
65
+ const lineRe = new RegExp(`^(\\s*)([A-Z][A-Z0-9_]*)\\s*=\\s*${escaped}[ \t]*$`, 'gm');
66
+ return content.replace(lineRe, (match, indent, key) => {
67
+ if (!rewriteKeys.has(key)) {
68
+ return match;
69
+ }
70
+ return `${indent}${key}=${replacement}`;
71
+ });
65
72
  }
66
73
 
67
74
  /**
@@ -88,12 +95,15 @@ function rewriteInactiveDeclarativeVdirPublicContent(content, variablesPath, use
88
95
  if (pathActive) {
89
96
  return content;
90
97
  }
91
- return applyInactiveVdirPublicTokenRewrite(content, INACTIVE_VDIR_PUBLIC_ENV_FALLBACK);
98
+ const appKey = doc && doc.app && doc.app.key;
99
+ const rewriteKeys = resolveInactiveVdirRewriteEnvKeys(appKey);
100
+ return applyInactiveVdirPublicTokenRewrite(content, INACTIVE_VDIR_PUBLIC_ENV_FALLBACK, rewriteKeys);
92
101
  }
93
102
 
94
103
  module.exports = {
95
104
  URL_DECLARATIVE_VDIR_PUBLIC_TOKEN,
96
105
  INACTIVE_VDIR_PUBLIC_ENV_FALLBACK,
106
+ loadApplicationYamlDoc,
97
107
  applyInactiveVdirPublicTokenRewrite,
98
108
  rewriteInactiveDeclarativeVdirPublicContent,
99
109
  isFrontDoorRoutingEnabledInDoc
@@ -48,6 +48,14 @@ const NON_TTY_THROTTLE_MS = 5000;
48
48
  * @returns {{ usesSpinner: boolean, onPollProgress: Function, finish: () => void }}
49
49
  */
50
50
  function createValidationPollHandlers(deadlineMs, opts = {}) {
51
+ if (opts.quiet === true) {
52
+ return {
53
+ usesSpinner: false,
54
+ onPollProgress: () => {},
55
+ finish: () => {}
56
+ };
57
+ }
58
+
51
59
  const subject = opts.subject;
52
60
  if (shouldUseValidationPollSpinner()) {
53
61
  const ora = require('ora');
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @fileoverview Map legacy validation runType to contract stage (dataplane 370.07).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ /** @typedef {'readiness'|'simulation'|'integration'|'e2e'} ValidationRunStage */
8
+
9
+ /** @type {Record<string, ValidationRunStage>} */
10
+ const RUN_TYPE_TO_STAGE = {
11
+ test: 'readiness',
12
+ integration: 'integration',
13
+ e2e: 'e2e'
14
+ };
15
+
16
+ /**
17
+ * Contract stage for a CLI/API runType (default product mapping).
18
+ * @param {string} runType - test | integration | e2e
19
+ * @returns {ValidationRunStage}
20
+ */
21
+ function stageForRunType(runType) {
22
+ const key = String(runType || 'test');
23
+ return RUN_TYPE_TO_STAGE[key] || 'readiness';
24
+ }
25
+
26
+ /**
27
+ * Attach stage to a validation/run POST body when absent.
28
+ * @param {Object} body
29
+ * @param {string} [runType]
30
+ * @returns {Object}
31
+ */
32
+ function withStageOnValidationRunBody(body, runType) {
33
+ const out = { ...body };
34
+ const rt = runType || out.runType || 'test';
35
+ if (!out.stage) {
36
+ out.stage = stageForRunType(rt);
37
+ }
38
+ return out;
39
+ }
40
+
41
+ module.exports = {
42
+ RUN_TYPE_TO_STAGE,
43
+ stageForRunType,
44
+ withStageOnValidationRunBody
45
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aifabrix/builder",
3
- "version": "2.45.5",
3
+ "version": "2.46.0",
4
4
  "description": "AI Fabrix Local Fabric & Deployment SDK",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -64,7 +64,8 @@ build:
64
64
  dockerfile: builder/dataplane/Dockerfile # Dockerfile path (relative to project root)
65
65
  envOutputPath: ../../.env # Copy to repo root for local dev
66
66
  language: python # Runtime language for template selection (typescript or python)
67
- reloadStart: uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-3001} --reload # PORT set from port above at run time; default 3001 must match port
67
+ # Dev reload: polling + watch /app/app only (avoids EMFILE on full repo bind-mount). See run_local.py, make af-reload.
68
+ reloadStart: WATCHFILES_FORCE_POLLING=1 uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-3001} --reload --reload-dir /app/app
68
69
  # Pulled-image local compose (no bind-mount): drives `command` in generated docker-compose. Override for non-standard images (e.g. stub ACR tags).
69
70
  imageRun: exec python -m uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-3001}
70
71
 
@@ -32,10 +32,12 @@ API_V1_STR=/api/v1
32
32
  VERSION=1.9.5
33
33
  # Minimum supported aifabrix-builder CLI semver (advertised on /health and /api/v1/health; empty = no gate)
34
34
  # MIN_BUILDER_CLI_VERSION=2.45.0
35
- MIN_BUILDER_CLI_VERSION=2.45.0
35
+ MIN_BUILDER_CLI_VERSION=2.45.5
36
36
  # Base URL for the dataplane web server (used for default OAuth2 callback URL when redirectUri is omitted)
37
37
  # url:// resolves after kv://; includes front-door path from application.yaml (e.g. /data)
38
38
  DATAPLANE_WEB_SERVER_URL=url://public
39
+ # Relative URL path where dataplane is served by reverse proxy (for prefixed deployments, e.g. /data).
40
+ DATAPLANE_RELATIVE_PATH=url://vdir-public
39
41
  DATAPLANE_INTERNAL_URL=url://internal
40
42
 
41
43
  # CORS Configuration
@@ -177,6 +179,14 @@ AUDIT_ASYNC_SHADOW_ENQUEUE=false
177
179
  # Set true for local dev policy CRUD; pair with VITE_POLICY_MANAGEMENT_ENABLED=true in app-ui.
178
180
  POLICY_MANAGEMENT_API_ENABLED=false
179
181
 
182
+ # First-party HTTP internal SpecFile (398.2 / plan 397). When true, lifespan upserts
183
+ # internal:dataplane-first-party-http from the live COM-merged OpenAPI schema.
184
+ FIRST_PARTY_HTTP_INTERNAL_SPEC_SYNC_ON_STARTUP=false
185
+ # Upsert internal:dataplane-first-party-http after pipeline external-system publish.
186
+ FIRST_PARTY_HTTP_INTERNAL_SPEC_SYNC_ON_PUBLISH=false
187
+ # Optional external_systems.id for spec_files FK; empty uses first row when startup sync is on.
188
+ FIRST_PARTY_HTTP_INTERNAL_SPEC_EXTERNAL_SYSTEM_ID=
189
+
180
190
  # =============================================================================
181
191
  # OBSERVABILITY CONFIGURATION
182
192
  # =============================================================================
@@ -198,6 +208,19 @@ CERTIFICATE_PUBLIC_KEY=
198
208
  # Optional public key identifier for issued certificates; default if unset: dataplane-signing-key
199
209
  CERTIFICATE_PUBLIC_KEY_ID=
200
210
 
211
+ # =============================================================================
212
+ # VALIDATION ENGINE — YAML CONTRACTS
213
+ # =============================================================================
214
+ # Load rules from repo contracts/ and schedule hybrid YAML tasks (see docs/adr/0001-validation-engine-yaml-contracts.md).
215
+ # Code defaults when unset: VALIDATION_CONTRACTS_ENABLED=false, VALIDATION_RULESET=legacy.
216
+ # hybrid = legacy Python categories + YAML rules; yaml = YAML/hybrid only (requires contracts enabled).
217
+ # Optional override for contract bundle root (default: <dataplane-repo>/contracts):
218
+ # VALIDATION_CONTRACTS_ROOT=
219
+ VALIDATION_CONTRACTS_ENABLED=true
220
+ VALIDATION_RULESET=hybrid
221
+ # Attach advisory yamlSuggestedLevel + contract metadata on certification details (does not change ICC/PDS level selection).
222
+ VALIDATION_CERTIFICATION_YAML_ENABLED=true
223
+
201
224
  # After a successful POST /api/v1/validation/run (validation engine with certification passed, or E2E success),
202
225
  # persist an active integration certificate without a separate issue call. Set false to require explicit issue only.
203
226
  VALIDATION_AUTO_ISSUE_INTEGRATION_CERTIFICATE=true
@@ -167,6 +167,22 @@ MISO_CLIENTSECRET=kv://miso-controller-client-secretKeyVault
167
167
  # Unset = use DB only.
168
168
  CONTROLLER_EVALUATION=
169
169
 
170
+ # =============================================================================
171
+ # ENTRA ID ONBOARDING (vendor multi-tenant app — admin consent)
172
+ # =============================================================================
173
+ # AI Fabrix vendor app for TA-1 admin consent and Entra ID configure flows.
174
+ # Customer SSO after configure uses a separate enterprise app (AI Fabrix Miso);
175
+ # Keycloak broker redirect is on that customer app, not ENTRA_ID_CLIENT_ID.
176
+ #
177
+ # ENTRA_ID_CENTRAL_CALLBACK_URI — Web redirect on the vendor app; must point at
178
+ # Mori (e.g. …/entra-id-concent/callback), not the SPA or controller.
179
+ # ENTRA_CALLBACK_STATE_SECRET — Shared HMAC secret (min 16 chars) for OAuth state
180
+ # between controller and Mori callback service; same value on Mori and controller.
181
+ ENTRA_CALLBACK_STATE_SECRET=kv://entra-callback-state-secret
182
+ ENTRA_ID_CENTRAL_CALLBACK_URI=kv://entra-callback-uri
183
+ ENTRA_ID_CLIENT_ID=kv://entra-client-idKeyVault
184
+ ENTRA_ID_CLIENT_SECRET=kv://entra-client-secretKeyVault
185
+
170
186
  # =============================================================================
171
187
  # TENANT ACTIVATION (TA-3) — EXISTING LLM CATALOG
172
188
  # =============================================================================
@@ -23,6 +23,7 @@
23
23
  | `{{systemKey}}-deploy.json` | Deploy manifest (`aifabrix json {{appName}}`) |
24
24
  | `deploy.js` | Deploy helper |
25
25
  | `wizard.yaml` | Wizard input |
26
+ | `scenarios/*.yaml` | Governance scenario packs (optional; dataplane-first via `verify-governance` / `governance generate`; expert YAML via `governance download` / `upload`) |
26
27
  | `{{rbacOptionalFile}}` | Roles and permissions |
27
28
 
28
29
  ## Typical workflow
@@ -33,7 +34,8 @@
33
34
  4. **Check locally** — `aifabrix validate {{appName}}` and `aifabrix datasource validate` on files you touched.
34
35
  5. **Align manifest** — `aifabrix repair {{appName}}` after bigger edits.
35
36
  6. **Publish** — see [Publish and credentials](#publish-and-credentials) (`upload`, `deploy`, or `credential push`).
36
- 7. **Protection** (optional) — dimension grants in `integration/.protection/` — see [Protection manifests](#protection-manifests).
37
+ 7. **Certify** — run [Enterprise AI Certification](#enterprise-ai-certification) (`verify-operations` → `verify-trust` → `verify-governance` → `lifecycle`).
38
+ 8. **Protection** (optional) — dimension grants in `integration/.protection/` — see [Protection manifests](#protection-manifests).
37
39
 
38
40
  Rollback an experiment: `datasource capability remove …` → validate → upload/deploy again.
39
41
 
@@ -41,7 +43,8 @@ Rollback an experiment: `datasource capability remove …` → validate → uplo
41
43
 
42
44
  | Command | What it does |
43
45
  | --- | --- |
44
- | `aifabrix upload {{appName}}` | Publishes local integration files to the dataplane and pushes credential secrets from `integration/{{appName}}/.env` (when present). |
46
+ | `aifabrix upload {{appName}}` | Publishes local integration files to the dataplane (refreshes `{{systemKey}}-deploy.json` from sources) and pushes credential secrets from `integration/{{appName}}/.env` (when present). |
47
+ | `aifabrix upload {{appName}} --force` | Same publish path when the interface or datasource schema changed in ways **deploy cannot accept yet**; bypasses active-schema replacement guards. Read the CLI warning before use. |
45
48
  | `aifabrix deploy {{appName}}` | Deploys via the controller pipeline. Does **not** replace a full upload for credential secrets — run `upload` or `credential push` when `.env` changed. |
46
49
  | `aifabrix credential push {{appName}}` | Pushes `KV_*` values from `.env` only (no manifest publish). |
47
50
 
@@ -49,6 +52,10 @@ Rollback an experiment: `datasource capability remove …` → validate → uplo
49
52
  aifabrix upload {{appName}}
50
53
  # or secrets only:
51
54
  aifabrix credential push {{appName}}
55
+
56
+ # Breaking schema / interface change — deploy blocked; publish for dev iteration
57
+ aifabrix validate {{appName}}
58
+ aifabrix upload {{appName}} --force
52
59
  ```
53
60
 
54
61
  ## Protection manifests
@@ -103,9 +110,9 @@ af ds cap remove {{#if hasDatasources}}{{datasources.[0].datasourceKey}}{{else}}
103
110
 
104
111
  For flags, run `af ds cap <command> --help`.
105
112
 
106
- ## Single datasource lifecycle (production-ready)
113
+ ## Per-datasource debug ladder
107
114
 
108
- Start with one datasource and iterate until it’s stable.
115
+ Start with one datasource and iterate until it’s stable (architect / CI — use [Enterprise AI Certification](#enterprise-ai-certification) for the product path).
109
116
 
110
117
  ```bash
111
118
  af ds validate {{#if hasDatasources}}{{datasources.[0].datasourceKey}}{{else}}<datasource-key>{{/if}}
@@ -137,7 +144,62 @@ aifabrix repair {{appName}}
137
144
 
138
145
  Useful flags: `--dry-run`, `--auth <method>`, `--rbac`, `--expose`, `--sync`, `--test`.
139
146
 
140
- ## Validate and test
147
+ ## Enterprise AI Certification
148
+
149
+ Product-facing commands that prove operational readiness, AI trust, governance enforcement, and an **Enterprise AI Certification** report. Run after [publish](#publish-and-credentials).
150
+
151
+ | Command | What it proves |
152
+ | --- | --- |
153
+ | `aifabrix verify-operations {{appName}}` | Operational readiness — orchestrates validate, unit test, integration, and E2E for the whole system |
154
+ | `aifabrix verify-trust {{appName}}` | AI business context confidence (semantic agent metadata; not live vendor API calls) |
155
+ | `aifabrix verify-governance {{appName}}` | **Recommended** — publish (unless `--no-sync`), generate scenario packs on the dataplane, then verify ABAC visibility per subject |
156
+ | `aifabrix governance generate {{appName}}` | Granular: generate packs only (after protection + sync) |
157
+ | `aifabrix governance verify {{appName}}` | Granular: verify only (active packs on dataplane, or `--pack` for local YAML override) |
158
+ | `aifabrix lifecycle {{appName}}` | Certification report from persisted pillar results on the dataplane |
159
+
160
+ **Recommended order:** `upload` → `verify-operations` → `verify-trust` → `verify-governance` → `lifecycle`
161
+
162
+ Integration validation packs live under `integration/{{appName}}/scenarios/` (YAML per datasource). Prefer **`verify-governance`** (dataplane-first) after identity sync, protection upload, and `datasource load`. Granular: `governance generate` then `governance verify`. Expert YAML: `governance download` / `governance upload` (424.0 schema; pre-424 files fail with a hint to regenerate). **`governance download`** is read-only and does not publish this folder.
163
+
164
+ ```bash
165
+ aifabrix upload {{appName}}
166
+
167
+ aifabrix verify-operations {{appName}}
168
+ aifabrix verify-operations {{appName}} -v
169
+
170
+ aifabrix verify-trust {{appName}} -v
171
+ aifabrix verify-trust {{appName}} --no-sync --revalidate
172
+
173
+ # Governance pillar (replace <email> with a subject from your scenario pack)
174
+ aifabrix verify-governance {{appName}} --subject-email <email> -v
175
+ aifabrix verify-governance {{appName}} --subject-email <email> --no-sync
176
+
177
+ # Granular governance (debugging)
178
+ aifabrix governance generate {{appName}} --subject-email <email>
179
+ aifabrix governance verify {{appName}} -v
180
+
181
+ # Report only (GET persisted results)
182
+ aifabrix lifecycle {{appName}}
183
+ aifabrix lifecycle {{appName}} -v
184
+
185
+ # Run missing verify steps, publish local files, then print report
186
+ aifabrix lifecycle {{appName}} --run
187
+ aifabrix lifecycle {{appName}} --run --no-sync
188
+ ```
189
+
190
+ **Prerequisites:** `aifabrix login`, dataplane reachable, config published (`upload`). Governance also needs identity sync, protection upload, `datasource load` for fixture records, at least one `--subject-email` or `--subject-user-id`, and `governance:evaluate` on your token. Run `aifabrix verify-governance --help` for flags.
191
+
192
+ **Single-datasource trust** (same semantic check as system `verify-trust`, one key):
193
+
194
+ ```bash
195
+ aifabrix datasource verify-trust {{#if hasDatasources}}{{datasources.[0].datasourceKey}}{{else}}<datasource-key>{{/if}} --app {{appName}} -v
196
+ ```
197
+
198
+ Common flags: `-v` / `--verbose`, `-d` / `--debug` (trust), `--no-sync` (skip pre-run upload), `--json` (machine-readable envelope).
199
+
200
+ ## Debug and low-level tests
201
+
202
+ Advanced commands for architects and CI. Prefer [Enterprise AI Certification](#enterprise-ai-certification) for integrator proof unless you need step-by-step debugging.
141
203
 
142
204
  | Command | Network | Notes |
143
205
  | --- | --- | --- |
@@ -145,14 +207,11 @@ Useful flags: `--dry-run`, `--auth <method>`, `--rbac`, `--expose`, `--sync`, `-
145
207
  | `aifabrix test {{appName}}` | Off | Local checks |
146
208
  | `aifabrix test-integration {{appName}}` | On | Needs login + dataplane |
147
209
  | `aifabrix test-e2e {{appName}}` | On | E2E for every datasource; uploads local files first unless `--no-sync` |
148
- | `aifabrix test-trust {{appName}}` | On | Semantic agent metadata trust (not live API E2E); uploads first unless `--no-sync` |
149
210
 
150
211
  System-level tests publish local integration files before the run (same path as `upload`). Use **`--no-sync`** to validate against config already on the dataplane.
151
212
 
152
213
  ```bash
153
- aifabrix test-trust {{appName}}
154
- aifabrix test-trust {{appName}} --no-sync
155
- aifabrix test-e2e {{appName}} --no-sync
214
+ aifabrix test-e2e {{appName}} --no-sync -d
156
215
  ```
157
216
 
158
217
  Single datasource E2E:
@@ -171,14 +230,9 @@ aifabrix datasource test-e2e <datasource-key> --app {{appName}}
171
230
  ```
172
231
  {{/if}}
173
232
 
174
- Common flags: `-v` / `--verbose`, `-d` / `--debug`, `--no-async` (datasource E2E only), `--no-sync` (skip pre-run upload on system `test-e2e` / `test-trust`).
233
+ Common flags: `-v` / `--verbose`, `-d` / `--debug`, `--no-async` (datasource E2E only), `--no-sync` (skip pre-run upload on system `test-e2e`).
175
234
 
176
- Datasource trust (one key; uploads before run unless `--no-sync`):
177
-
178
- ```bash
179
- aifabrix datasource test-trust {{#if hasDatasources}}{{datasources.[0].datasourceKey}}{{else}}<datasource-key>{{/if}} --app {{appName}}
180
- aifabrix datasource test-trust {{#if hasDatasources}}{{datasources.[0].datasourceKey}}{{else}}<datasource-key>{{/if}} --app {{appName}} --no-sync --revalidate
181
- ```
235
+ Debug logs (when using `--debug` on datasource commands) are written under `integration/{{appName}}/logs/` — use `aifabrix datasource log-test`, `log-integration`, `log-e2e`, or `log-trust` to inspect the latest file for each type.
182
236
 
183
237
  ## Deploy
184
238
 
@@ -195,5 +249,8 @@ aifabrix delete {{appName}}
195
249
  ## When something fails
196
250
 
197
251
  - **Validation errors** — Fix JSON/schema issues; run `aifabrix validate {{appName}}` and `aifabrix datasource validate` on the file you changed.
198
- - **Auth** — `aifabrix auth config` + `aifabrix login` before upload, deploy, or remote tests.
252
+ - **Deploy blocked by schema changes** — When the interface changed and deploy rejects the update, validate locally then `aifabrix upload {{appName}} --force` to publish for dev iteration (see [Publish and credentials](#publish-and-credentials)).
253
+ - **Auth** — `aifabrix auth config` + `aifabrix login` before upload, deploy, remote tests, or certification.
254
+ - **Certification gaps** — Run pillars in order (`verify-operations` → `verify-trust` → `verify-governance`), then `aifabrix lifecycle {{appName}} -v` for per-datasource breakdown; use `lifecycle --run` to execute missing steps and refresh the report.
255
+ - **Governance upload rejected** — Local `scenarios/*.yaml` must meet the 424.0 pack schema; use `verify-governance` or `governance generate` instead of hand-editing old YAML.
199
256
  - **Wrong folder** — Run CLI from the project root (where `integration/{{appName}}/` lives).
@@ -51,7 +51,7 @@ services:
51
51
  env_file:
52
52
  - {{envFile}}
53
53
  {{#if reloadStartCommand}}
54
- command: ["sh", "-c", "cd /app && {{reloadStartCommand}}"]
54
+ command: ["sh", "-c", "cd /app && {{{reloadStartCommand}}}"]
55
55
  {{/if}}
56
56
  ports:
57
57
  - "{{hostPort}}:{{containerPort}}"
@@ -134,27 +134,28 @@ services:
134
134
  done &&
135
135
  {{#if databases}}
136
136
  {{#each databases}}
137
- echo 'Creating {{name}} database and user...' &&
138
- if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1$$'; then
139
- echo 'Database "{{name}}" already exists, syncing user password...' &&
140
- psql -d postgres -c "ALTER USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
141
- echo 'Database "{{name}}" ok.'
137
+ echo "Creating $${DB_{{@index}}_NAME} database and user..." &&
138
+ if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '$${DB_{{@index}}_NAME}'" 2>/dev/null | grep -q '^1$$'; then
139
+ echo "Database \"$${DB_{{@index}}_NAME}\" already exists, syncing user password..." &&
140
+ psql -d postgres -c "ALTER USER \"$${DB_{{@index}}_USER}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
141
+ echo "Database \"$${DB_{{@index}}_NAME}\" ok."
142
142
  else
143
- echo 'Creating database "{{name}}"...' &&
144
- psql -d postgres -c "CREATE DATABASE \"{{name}}\";" &&
145
- echo 'Dropping old user if exists...' &&
143
+ echo "Creating database \"$${DB_{{@index}}_NAME}\"..." &&
144
+ psql -d postgres -c "CREATE DATABASE \"$${DB_{{@index}}_NAME}\";" &&
145
+ echo "Dropping old user if exists..." &&
146
146
  psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld name}}\";" || true &&
147
- echo 'Creating user "{{pgUserName name}}"...' &&
148
- psql -d postgres -c "CREATE USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
149
- echo 'Granting privileges...' &&
150
- psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{name}}\" TO \"{{pgUserName name}}\";" &&
151
- psql -d {{name}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName name}}\";" &&
152
- psql -d {{name}} -c "GRANT ALL ON SCHEMA public TO \"{{pgUserName name}}\";" &&
153
- echo 'Database "{{name}}" created successfully!'
147
+ psql -d postgres -c "DROP USER IF EXISTS \"$${DB_{{@index}}_USER}\";" || true &&
148
+ echo "Creating user \"$${DB_{{@index}}_USER}\"..." &&
149
+ psql -d postgres -c "CREATE USER \"$${DB_{{@index}}_USER}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
150
+ echo "Granting privileges..." &&
151
+ psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"$${DB_{{@index}}_NAME}\" TO \"$${DB_{{@index}}_USER}\";" &&
152
+ psql -d "$${DB_{{@index}}_NAME}" -c "ALTER SCHEMA public OWNER TO \"$${DB_{{@index}}_USER}\";" &&
153
+ psql -d "$${DB_{{@index}}_NAME}" -c "GRANT ALL ON SCHEMA public TO \"$${DB_{{@index}}_USER}\";" &&
154
+ echo "Database \"$${DB_{{@index}}_NAME}\" created successfully!"
154
155
  fi &&
155
156
  {{#each (extensionsForDb this)}}
156
- (psql -d {{../name}} -c 'CREATE EXTENSION IF NOT EXISTS {{pgQuote this}};' || echo 'Warning: could not create extension {{this}}') &&
157
- echo 'Extension "{{this}}" enabled on "{{../name}}".' &&
157
+ (psql -d "$${DB_{{@../index}}_NAME}" -c 'CREATE EXTENSION IF NOT EXISTS {{pgQuote this}};' || echo "Warning: could not create extension {{this}}") &&
158
+ echo "Extension \"{{this}}\" enabled on \"$${DB_{{@../index}}_NAME}\"." &&
158
159
  {{/each}}
159
160
  {{/each}}
160
161
  {{else}}
@@ -134,27 +134,28 @@ services:
134
134
  done &&
135
135
  {{#if databases}}
136
136
  {{#each databases}}
137
- echo 'Creating {{name}} database and user...' &&
138
- if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '{{name}}'" 2>/dev/null | grep -q '^1$$'; then
139
- echo 'Database "{{name}}" already exists, syncing user password...' &&
140
- psql -d postgres -c "ALTER USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
141
- echo 'Database "{{name}}" ok.'
137
+ echo "Creating $${DB_{{@index}}_NAME} database and user..." &&
138
+ if psql -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname = '$${DB_{{@index}}_NAME}'" 2>/dev/null | grep -q '^1$$'; then
139
+ echo "Database \"$${DB_{{@index}}_NAME}\" already exists, syncing user password..." &&
140
+ psql -d postgres -c "ALTER USER \"$${DB_{{@index}}_USER}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
141
+ echo "Database \"$${DB_{{@index}}_NAME}\" ok."
142
142
  else
143
- echo 'Creating database "{{name}}"...' &&
144
- psql -d postgres -c "CREATE DATABASE \"{{name}}\";" &&
145
- echo 'Dropping old user if exists...' &&
143
+ echo "Creating database \"$${DB_{{@index}}_NAME}\"..." &&
144
+ psql -d postgres -c "CREATE DATABASE \"$${DB_{{@index}}_NAME}\";" &&
145
+ echo "Dropping old user if exists..." &&
146
146
  psql -d postgres -c "DROP USER IF EXISTS \"{{pgUserOld name}}\";" || true &&
147
- echo 'Creating user "{{pgUserName name}}"...' &&
148
- psql -d postgres -c "CREATE USER \"{{pgUserName name}}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
149
- echo 'Granting privileges...' &&
150
- psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"{{name}}\" TO \"{{pgUserName name}}\";" &&
151
- psql -d {{name}} -c "ALTER SCHEMA public OWNER TO \"{{pgUserName name}}\";" &&
152
- psql -d {{name}} -c "GRANT ALL ON SCHEMA public TO \"{{pgUserName name}}\";" &&
153
- echo 'Database "{{name}}" created successfully!'
147
+ psql -d postgres -c "DROP USER IF EXISTS \"$${DB_{{@index}}_USER}\";" || true &&
148
+ echo "Creating user \"$${DB_{{@index}}_USER}\"..." &&
149
+ psql -d postgres -c "CREATE USER \"$${DB_{{@index}}_USER}\" WITH PASSWORD '"$${DB_{{@index}}_PASSWORD}"';" &&
150
+ echo "Granting privileges..." &&
151
+ psql -d postgres -c "GRANT ALL PRIVILEGES ON DATABASE \"$${DB_{{@index}}_NAME}\" TO \"$${DB_{{@index}}_USER}\";" &&
152
+ psql -d "$${DB_{{@index}}_NAME}" -c "ALTER SCHEMA public OWNER TO \"$${DB_{{@index}}_USER}\";" &&
153
+ psql -d "$${DB_{{@index}}_NAME}" -c "GRANT ALL ON SCHEMA public TO \"$${DB_{{@index}}_USER}\";" &&
154
+ echo "Database \"$${DB_{{@index}}_NAME}\" created successfully!"
154
155
  fi &&
155
156
  {{#each (extensionsForDb this)}}
156
- (psql -d {{../name}} -c 'CREATE EXTENSION IF NOT EXISTS {{pgQuote this}};' || echo 'Warning: could not create extension {{this}}') &&
157
- echo 'Extension "{{this}}" enabled on "{{../name}}".' &&
157
+ (psql -d "$${DB_{{@../index}}_NAME}" -c 'CREATE EXTENSION IF NOT EXISTS {{pgQuote this}};' || echo "Warning: could not create extension {{this}}") &&
158
+ echo "Extension \"{{this}}\" enabled on \"$${DB_{{@../index}}_NAME}\"." &&
158
159
  {{/each}}
159
160
  {{/each}}
160
161
  {{else}}
@@ -1,55 +0,0 @@
1
- /**
2
- * @fileoverview CLI action for `aifabrix test-governance` (plan 406)
3
- * @author AI Fabrix Team
4
- * @version 1.0.0
5
- */
6
-
7
- 'use strict';
8
-
9
- const { handleCommandError } = require('../utils/cli-utils');
10
- const { runTestGovernanceForExternalSystem } = require('./test-governance-external');
11
- const { normalizeTestGovernanceCliOptions } = require('./test-governance-cli-options');
12
- const {
13
- displayGovernanceRunTTY,
14
- printGovernanceRunJson,
15
- exitCodeFromGovernanceSummary
16
- } = require('../governance/governance-run-display');
17
-
18
- /**
19
- * @async
20
- * @param {string} appName
21
- * @param {Object} options
22
- * @param {import('commander').Command} [cmd]
23
- */
24
- async function runTestGovernanceCommandAction(appName, options, cmd) {
25
- const opts = normalizeTestGovernanceCliOptions(options, cmd);
26
- const { result, packPath, systemKey } = await runTestGovernanceForExternalSystem(appName, opts);
27
-
28
- if (opts.json) {
29
- printGovernanceRunJson(result);
30
- } else {
31
- displayGovernanceRunTTY(systemKey, result, {
32
- verbose: opts.verbose,
33
- packPath
34
- });
35
- }
36
-
37
- const exitCode = exitCodeFromGovernanceSummary(result.summary);
38
- if (exitCode !== 0) {
39
- process.exit(exitCode);
40
- }
41
- }
42
-
43
- async function testGovernanceCommandHandler(appName, options, cmd) {
44
- try {
45
- await runTestGovernanceCommandAction(appName, options, cmd);
46
- } catch (error) {
47
- handleCommandError(error, 'test-governance');
48
- process.exit(3);
49
- }
50
- }
51
-
52
- module.exports = {
53
- runTestGovernanceCommandAction,
54
- testGovernanceCommandHandler
55
- };
@@ -1,118 +0,0 @@
1
- /**
2
- * @fileoverview CLI action for `aifabrix test-trust` (plan 143).
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 { handleCommandError } = require('../utils/cli-utils');
12
- const { runTestTrustForExternalSystem } = require('./test-trust-external');
13
- const {
14
- displaySystemTrustRollupTTY,
15
- displayAgentTrustRunTTY
16
- } = require('../utils/agent-trust-run-display');
17
- const { computeSystemExitCodeFromTrustRows } = require('../utils/agent-trust-run-exit');
18
- const { writeTrustDebugLogAndPrint } = require('../datasource/agent-trust-debug-log');
19
- const { normalizeTestTrustCliOptions } = require('./test-trust-cli-options');
20
-
21
- /**
22
- * @async
23
- * @param {string} appName
24
- * @param {Object} options
25
- */
26
- async function writeSystemTrustDebugLogs(appName, results, options) {
27
- if (!options.debug) return;
28
- logger.log('');
29
- logger.log(chalk.gray('Debug logs:'));
30
- for (const row of results) {
31
- await writeTrustDebugLogAndPrint(appName, row.key, {
32
- request: {
33
- datasourceKey: row.key,
34
- revalidate: options.revalidate === true,
35
- noSync: options.noSync === true
36
- },
37
- response: row.trustRun,
38
- error: row.error || null
39
- });
40
- }
41
- }
42
-
43
- function displaySystemTrustResults(systemKey, appName, results, options) {
44
- if (options.json) {
45
- logger.log(JSON.stringify(results, null, 2));
46
- return;
47
- }
48
- if (options.summary) {
49
- for (const row of results) {
50
- const tr = row.trustRun;
51
- const line = tr
52
- ? `${row.key}: ${tr.trustDecision} (${tr.validationStatus})`
53
- : `${row.key}: fail (${row.error || 'error'})`;
54
- logger.log(line);
55
- }
56
- return;
57
- }
58
-
59
- const displayOpts = {
60
- strict: options.strict === true,
61
- showCache: options.verbose === true || options.revalidate === true
62
- };
63
- displaySystemTrustRollupTTY(systemKey || appName, results, displayOpts);
64
-
65
- if (!options.verbose) return;
66
-
67
- for (const row of results) {
68
- if (!row.trustRun) continue;
69
- displayAgentTrustRunTTY(row.trustRun, {
70
- environment: options.env,
71
- verbose: true,
72
- noSync: options.noSync === true,
73
- strict: options.strict === true
74
- });
75
- }
76
- }
77
-
78
- async function runTestTrustCommandAction(appName, options, cmd) {
79
- const opts = normalizeTestTrustCliOptions(options, cmd);
80
- const pathsUtil = require('../utils/paths');
81
- const appType = await pathsUtil.detectAppType(appName).catch(() => null);
82
- if (!appType || appType.baseDir !== 'integration') {
83
- throw new Error(
84
- 'test-trust applies to external integration folders only (integration/<systemKey>/).'
85
- );
86
- }
87
- const { success, results, systemKey } = await runTestTrustForExternalSystem(appName, {
88
- env: opts.env,
89
- verbose: opts.verbose,
90
- debug: opts.debug,
91
- noSync: opts.noSync === true,
92
- revalidate: opts.revalidate === true,
93
- summary: opts.summary === true,
94
- timeout: opts.timeout
95
- });
96
- displaySystemTrustResults(systemKey, appName, results, opts);
97
- await writeSystemTrustDebugLogs(appName, results, opts);
98
- const exitCode = computeSystemExitCodeFromTrustRows(results, {
99
- warningsAsErrors: opts.warningsAsErrors === true,
100
- strict: opts.strict === true
101
- });
102
- if (exitCode !== 0) process.exit(exitCode);
103
- if (!success) process.exit(1);
104
- }
105
-
106
- async function testTrustCommandHandler(appName, options, cmd) {
107
- try {
108
- await runTestTrustCommandAction(appName, options, cmd);
109
- } catch (error) {
110
- handleCommandError(error, 'test-trust');
111
- process.exit(3);
112
- }
113
- }
114
-
115
- module.exports = {
116
- runTestTrustCommandAction,
117
- testTrustCommandHandler
118
- };