@aifabrix/builder 2.49.2 → 2.51.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 (459) hide show
  1. package/.cursor/plans/157.1-security-quality-violations-by-type.csv +374 -0
  2. package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
  3. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
  4. package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
  5. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
  6. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
  7. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
  8. package/.cursor/skills/README.md +1 -0
  9. package/.dockerignore +52 -0
  10. package/.eslintignore +22 -0
  11. package/README.md +2 -0
  12. package/bin/builder-api-cleanup.js +26 -0
  13. package/bin/builder-api-nest.js +10 -0
  14. package/bin/builder-api-spike.js +19 -0
  15. package/enterprise-knowledge/README.md +50 -0
  16. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
  17. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
  18. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
  19. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
  20. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
  21. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
  22. package/integration/README.md +81 -0
  23. package/integration/github/README.md +53 -0
  24. package/integration/github/application.json +21 -0
  25. package/integration/github/deploy.js +72 -0
  26. package/integration/github/env.template +11 -0
  27. package/integration/github/github-datasource-issue-comments.json +239 -0
  28. package/integration/github/github-datasource-issues.json +399 -0
  29. package/integration/github/github-datasource-repository.json +354 -0
  30. package/integration/github/github-deploy.json +1202 -0
  31. package/integration/github/github-system.json +82 -0
  32. package/integration/hubspot-test/README.md +1 -1
  33. package/integration/hubspot-test/create-hubspot.js +1 -16
  34. package/jest.isolated-projects.js +31 -1
  35. package/jest.projects.js +87 -1
  36. package/lib/api/dev-server-https.js +1 -1
  37. package/lib/api/enterprise-knowledge.api.js +63 -0
  38. package/lib/api/evidence-kinds.api.js +128 -0
  39. package/lib/api/evidence.api.js +172 -0
  40. package/lib/api/external-systems.api.js +8 -2
  41. package/lib/api/pipeline.api.js +5 -1
  42. package/lib/api/resource-types.api.js +5 -4
  43. package/lib/api/roles.api.js +121 -0
  44. package/lib/api/types/enterprise-knowledge.types.js +46 -0
  45. package/lib/api/types/evidence-kinds.types.js +42 -0
  46. package/lib/api/types/evidence.types.js +67 -0
  47. package/lib/api/types/resource-types.types.js +2 -0
  48. package/lib/api/types/roles.types.js +36 -0
  49. package/lib/app/certification-verify-rows.js +1 -1
  50. package/lib/app/controller-application-filter.js +36 -0
  51. package/lib/app/deploy.js +1 -1
  52. package/lib/app/list-external-systems.js +130 -0
  53. package/lib/app/list.js +20 -8
  54. package/lib/app/run.js +3 -1
  55. package/lib/app/show-display.js +8 -3
  56. package/lib/app/show-online.js +178 -0
  57. package/lib/app/show.js +39 -90
  58. package/lib/build/builder-api-docker-staging.js +47 -0
  59. package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
  60. package/lib/build/standard-docker-build.js +2 -0
  61. package/lib/certification/merge-certification-from-artifact.js +1 -1
  62. package/lib/certification/post-unified-cert-sync.js +4 -31
  63. package/lib/certification/sync-after-external-command.js +0 -1
  64. package/lib/certification/sync-system-certification.js +0 -3
  65. package/lib/channels/add-channel.js +40 -34
  66. package/lib/channels/approval-guides/chatgpt.js +33 -0
  67. package/lib/channels/approval-guides/credential-portal.js +38 -0
  68. package/lib/channels/approval-guides/index.js +110 -0
  69. package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
  70. package/lib/channels/approval-guides/slack.js +34 -0
  71. package/lib/channels/approval-guides/teams-bot.js +35 -0
  72. package/lib/channels/approval-guides/web-embed.js +32 -0
  73. package/lib/channels/channel-approval-guide.js +11 -0
  74. package/lib/channels/channel-artifact-generator.js +18 -5
  75. package/lib/channels/channel-audit.js +3 -0
  76. package/lib/channels/channel-auth-context.js +1 -1
  77. package/lib/channels/channel-description.js +59 -0
  78. package/lib/channels/channel-integration-generator.js +13 -230
  79. package/lib/channels/channel-integration-template.js +94 -0
  80. package/lib/channels/channel-runtime-resolver.js +43 -3
  81. package/lib/channels/channel-status-display.js +66 -26
  82. package/lib/channels/channel-targets.js +3 -3
  83. package/lib/cli/index.js +31 -3
  84. package/lib/cli/infra-guided.js +5 -1
  85. package/lib/cli/setup-app-external-create.js +111 -0
  86. package/lib/cli/setup-app.help.js +1 -1
  87. package/lib/cli/setup-app.js +60 -130
  88. package/lib/cli/setup-app.test-commands.js +26 -52
  89. package/lib/cli/setup-certification-commands.js +4 -4
  90. package/lib/cli/setup-certification.help.js +9 -9
  91. package/lib/cli/setup-dev.js +30 -9
  92. package/lib/cli/setup-external-system-help.js +4 -6
  93. package/lib/cli/setup-external-system.js +58 -52
  94. package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
  95. package/lib/cli/setup-infra-up-platform-action.js +3 -1
  96. package/lib/cli/setup-infra.js +15 -0
  97. package/lib/cli/setup-list.js +43 -0
  98. package/lib/cli/setup-utility-help-after.js +12 -0
  99. package/lib/cli/setup-utility-repair.js +26 -7
  100. package/lib/cli/setup-utility-validate.js +41 -2
  101. package/lib/cli/setup-utility.js +5 -3
  102. package/lib/commands/app.js +15 -43
  103. package/lib/commands/channel-add-setup.js +110 -0
  104. package/lib/commands/channel.js +42 -8
  105. package/lib/commands/datasource-sync-display.js +96 -0
  106. package/lib/commands/datasource-sync-policy.js +210 -0
  107. package/lib/commands/datasource-test-trust-cli.js +6 -6
  108. package/lib/commands/datasource-unified-test-cli.js +2 -1
  109. package/lib/commands/datasource-unified-test-cli.options.js +33 -23
  110. package/lib/commands/deploy-gate-failure-details.js +184 -0
  111. package/lib/commands/deploy-gate-orchestrator.js +368 -0
  112. package/lib/commands/dev-cli-handlers.js +7 -62
  113. package/lib/commands/dev-host-ops-params.js +91 -0
  114. package/lib/commands/dev-host-ops-poll.js +111 -0
  115. package/lib/commands/dev-host-ops.js +107 -94
  116. package/lib/commands/dev-init.js +6 -106
  117. package/lib/commands/dev-refresh.js +197 -0
  118. package/lib/commands/enterprise-knowledge.js +284 -0
  119. package/lib/commands/evidence-cli-leaves.js +250 -0
  120. package/lib/commands/evidence-kind.js +428 -0
  121. package/lib/commands/evidence.js +51 -0
  122. package/lib/commands/governance-cli-shared.js +2 -2
  123. package/lib/commands/governance-command-action.js +5 -3
  124. package/lib/commands/governance-fixture-subjects.js +85 -0
  125. package/lib/commands/governance.js +1 -1
  126. package/lib/commands/lifecycle-command-action.js +2 -2
  127. package/lib/commands/lifecycle-external.js +3 -3
  128. package/lib/commands/manifest-cli-auth.js +29 -0
  129. package/lib/commands/manifest-cli-commands.js +170 -0
  130. package/lib/commands/manifest-cli-integration-path.js +63 -0
  131. package/lib/commands/manifest.js +21 -0
  132. package/lib/commands/protection-cli-leaves.js +3 -3
  133. package/lib/commands/repair-auth-apply.js +15 -1
  134. package/lib/commands/repair-authentications-454.js +169 -0
  135. package/lib/commands/repair-capability-openapi-warnings.js +126 -0
  136. package/lib/commands/repair-datasource-apply.js +135 -0
  137. package/lib/commands/repair-datasource-auto-rbac.js +62 -1
  138. package/lib/commands/repair-datasource-http-service-contract.js +239 -0
  139. package/lib/commands/repair-datasource-operation-security.js +180 -0
  140. package/lib/commands/repair-datasource-run.js +7 -2
  141. package/lib/commands/repair-datasource-sync-operations.js +177 -0
  142. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
  143. package/lib/commands/repair-datasource.js +12 -68
  144. package/lib/commands/repair-env-template.js +11 -1
  145. package/lib/commands/repair-external-run.js +121 -31
  146. package/lib/commands/repair-internal.js +1 -1
  147. package/lib/commands/repair-openapi-export.js +156 -0
  148. package/lib/commands/repair-openapi-sync.js +33 -8
  149. package/lib/commands/repair-orchestration-datasource-split.js +259 -0
  150. package/lib/commands/repair-persist.js +22 -1
  151. package/lib/commands/repair-rbac-platform-preset.js +204 -0
  152. package/lib/commands/repair-rbac-reader-roles.js +191 -0
  153. package/lib/commands/repair-rbac.js +163 -86
  154. package/lib/commands/repair-steps.js +83 -18
  155. package/lib/commands/repair-system-permissions.js +1 -0
  156. package/lib/commands/repair.js +1 -1
  157. package/lib/commands/resource-type.js +166 -44
  158. package/lib/commands/role.js +452 -0
  159. package/lib/commands/run-post-publish-data-sync.js +68 -0
  160. package/lib/commands/setup-modes.js +1 -1
  161. package/lib/commands/setup.js +1 -1
  162. package/lib/commands/test-e2e-external.js +21 -8
  163. package/lib/commands/test-governance-cli-options.js +2 -2
  164. package/lib/commands/test-trust-cli-options.js +2 -2
  165. package/lib/commands/up-builder-api-bootstrap.js +71 -0
  166. package/lib/commands/up-builder-api-provision.js +241 -0
  167. package/lib/commands/up-builder-api.js +88 -0
  168. package/lib/commands/up-common.js +25 -1
  169. package/lib/commands/upload-credential-push-log.js +117 -0
  170. package/lib/commands/upload-data-sync-finalize.js +60 -0
  171. package/lib/commands/upload-probe.js +66 -0
  172. package/lib/commands/upload-publish-context.js +4 -1
  173. package/lib/commands/upload-sidecar-followups.js +55 -27
  174. package/lib/commands/upload.js +116 -157
  175. package/lib/commands/validate-json.js +230 -0
  176. package/lib/commands/verify-governance-combined-external.js +1 -1
  177. package/lib/commands/verify-governance-db.js +2 -2
  178. package/lib/commands/verify-operations-command-action.js +2 -2
  179. package/lib/commands/verify-operations-step-plan.js +79 -41
  180. package/lib/commands/verify-operations-steps.js +2 -2
  181. package/lib/commands/verify-trust-command-action.js +1 -1
  182. package/lib/commands/wizard-core.js +1 -1
  183. package/lib/commands/wizard-headless.js +2 -1
  184. package/lib/core/admin-secrets.js +2 -6
  185. package/lib/core/audit-logger.js +1 -1
  186. package/lib/core/secrets-env-content.js +10 -4
  187. package/lib/core/secrets-env-write.js +2 -13
  188. package/lib/core/secrets-load.js +1 -3
  189. package/lib/datasource/agent-trust-run.js +3 -3
  190. package/lib/datasource/capability/relate-operations.js +1 -1
  191. package/lib/datasource/deploy.js +3 -1
  192. package/lib/datasource/test-e2e.js +6 -1
  193. package/lib/datasource/unified-validation-run-body.js +4 -1
  194. package/lib/datasource/unified-validation-run.js +1 -1
  195. package/lib/deployment/deploy-poll-ui.js +73 -12
  196. package/lib/deployment/deployer-poll-run.js +113 -0
  197. package/lib/deployment/deployer.js +17 -87
  198. package/lib/evidence/dataplane-context.js +21 -0
  199. package/lib/evidence/evidence-display.js +78 -0
  200. package/lib/evidence/evidence-service.js +392 -0
  201. package/lib/external-system/deploy.js +290 -112
  202. package/lib/external-system/download.js +7 -3
  203. package/lib/external-system/test-execution.js +1 -1
  204. package/lib/external-system/test-system-level.js +8 -10
  205. package/lib/external-system/test.js +12 -6
  206. package/lib/generator/deploy-script.js +73 -0
  207. package/lib/generator/external.js +2 -1
  208. package/lib/generator/helpers.js +13 -5
  209. package/lib/generator/index.js +17 -2
  210. package/lib/generator/split-variables.js +9 -3
  211. package/lib/generator/wizard.js +3 -36
  212. package/lib/infrastructure/helpers-docker-check.js +6 -0
  213. package/lib/infrastructure/helpers.js +1 -1
  214. package/lib/internal/fs-real-sync.js +22 -1
  215. package/lib/internal/node-fs.js +2 -0
  216. package/lib/lifecycle/lifecycle-governance-options.js +1 -1
  217. package/lib/lifecycle/verify-step-progress.js +1 -1
  218. package/lib/programmatic/access-log.js +26 -0
  219. package/lib/programmatic/auth-config.js +45 -0
  220. package/lib/programmatic/bearer-auth.js +176 -0
  221. package/lib/programmatic/builder-api-request.js +175 -0
  222. package/lib/programmatic/builder-api-route-dispatch.js +82 -0
  223. package/lib/programmatic/builder-api-runtime-config.js +42 -0
  224. package/lib/programmatic/builder-api-server.js +230 -0
  225. package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
  226. package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
  227. package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
  228. package/lib/programmatic/builder-help-envelope.js +36 -0
  229. package/lib/programmatic/builder-help-fixtures.js +200 -0
  230. package/lib/programmatic/builder-help-governance.js +172 -0
  231. package/lib/programmatic/builder-help-schema-catalog.js +92 -0
  232. package/lib/programmatic/builder-help.js +361 -0
  233. package/lib/programmatic/capability-registry.js +77 -0
  234. package/lib/programmatic/command-options.js +32 -0
  235. package/lib/programmatic/enterprise-mcp-client.js +114 -0
  236. package/lib/programmatic/http-problem-details.js +99 -0
  237. package/lib/programmatic/http-route-match.js +40 -0
  238. package/lib/programmatic/idempotency-cache.js +69 -0
  239. package/lib/programmatic/index.js +53 -0
  240. package/lib/programmatic/integration-path-scope.js +39 -0
  241. package/lib/programmatic/log-redaction.js +66 -0
  242. package/lib/programmatic/manifest-get-section.js +146 -0
  243. package/lib/programmatic/manifest-patch-section.js +252 -0
  244. package/lib/programmatic/manifest-repair.js +122 -0
  245. package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
  246. package/lib/programmatic/manifest-section-io.js +225 -0
  247. package/lib/programmatic/manifest-section-quality.js +171 -0
  248. package/lib/programmatic/manifest-section-registry-data.js +269 -0
  249. package/lib/programmatic/manifest-section-registry.js +222 -0
  250. package/lib/programmatic/nest-http-bridge.js +34 -0
  251. package/lib/programmatic/openapi-component-schemas.js +68 -0
  252. package/lib/programmatic/openapi-description-enricher.js +117 -0
  253. package/lib/programmatic/openapi-descriptions.js +190 -0
  254. package/lib/programmatic/openapi-docs-serving.js +123 -0
  255. package/lib/programmatic/openapi-help-schemas.js +63 -0
  256. package/lib/programmatic/openapi-manifest-schemas.js +141 -0
  257. package/lib/programmatic/openapi-operation-bindings.js +274 -0
  258. package/lib/programmatic/openapi-request-schemas.js +155 -0
  259. package/lib/programmatic/openapi-result-schemas.js +493 -0
  260. package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
  261. package/lib/programmatic/openapi-schema-descriptions-core.js +162 -0
  262. package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
  263. package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
  264. package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
  265. package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
  266. package/lib/programmatic/openapi-schema-helpers.js +108 -0
  267. package/lib/programmatic/openapi-spec.js +203 -0
  268. package/lib/programmatic/orchestration-openapi-meta.js +159 -0
  269. package/lib/programmatic/platform-rbac-catalog.js +90 -0
  270. package/lib/programmatic/request-timeout.js +53 -0
  271. package/lib/programmatic/route-handler-map.js +143 -0
  272. package/lib/programmatic/route-handlers-context.js +29 -0
  273. package/lib/programmatic/route-handlers.js +33 -0
  274. package/lib/programmatic/run-certify.js +57 -0
  275. package/lib/programmatic/run-enterprise-mcp.js +32 -0
  276. package/lib/programmatic/run-lifecycle.js +29 -0
  277. package/lib/programmatic/run-repair.js +41 -0
  278. package/lib/programmatic/run-repository-emcp.js +62 -0
  279. package/lib/programmatic/run-template-workspace.js +74 -0
  280. package/lib/programmatic/run-test.js +49 -0
  281. package/lib/programmatic/run-upload.js +63 -0
  282. package/lib/programmatic/run-validate.js +53 -0
  283. package/lib/programmatic/run-wizard.js +40 -0
  284. package/lib/programmatic/system-key.js +48 -0
  285. package/lib/programmatic/wizard-config-normalize.js +118 -0
  286. package/lib/programmatic/workspace-cleanup.js +128 -0
  287. package/lib/programmatic/workspace-context.js +145 -0
  288. package/lib/programmatic/workspace-lock.js +75 -0
  289. package/lib/programmatic/workspace-meta.js +64 -0
  290. package/lib/programmatic/workspace-ops.js +149 -0
  291. package/lib/protection/run-commands-upload-sync.js +35 -0
  292. package/lib/protection/run-commands.js +2 -20
  293. package/lib/protection/upload-batch.js +11 -7
  294. package/lib/resolvers/evidence-kind-file.js +230 -0
  295. package/lib/resolvers/resource-type-file.js +58 -1
  296. package/lib/resolvers/role-file.js +227 -0
  297. package/lib/schema/application-schema.json +22 -2
  298. package/lib/schema/external-datasource.schema.json +245 -2
  299. package/lib/schema/external-system.schema.json +259 -119
  300. package/lib/schema/flag-map-validation-run.json +3 -0
  301. package/lib/schema/infra.parameter.yaml +25 -1
  302. package/lib/schema/type/credential-field-registry.json +21 -5
  303. package/lib/schema/type/document-storage.json +9 -0
  304. package/lib/utils/agent-trust-run-display.js +1 -1
  305. package/lib/utils/api.js +8 -2
  306. package/lib/utils/app-path-resolve.js +168 -0
  307. package/lib/utils/app-register-config.js +4 -3
  308. package/lib/utils/authentication-env-template.js +222 -0
  309. package/lib/utils/cli-sync-options.js +62 -10
  310. package/lib/utils/cli-utils.js +15 -3
  311. package/lib/utils/cli-workspace-options.js +29 -0
  312. package/lib/utils/compose-generate-docker-compose.js +102 -0
  313. package/lib/utils/configuration-env-resolver.js +203 -27
  314. package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
  315. package/lib/utils/datasource-test-run-certification-debug.js +130 -0
  316. package/lib/utils/datasource-test-run-debug-display.js +2 -0
  317. package/lib/utils/datasource-test-run-debug-slice.js +7 -0
  318. package/lib/utils/datasource-test-run-display.js +2 -1
  319. package/lib/utils/dev-ca-install.js +5 -6
  320. package/lib/utils/dev-config.js +2 -2
  321. package/lib/utils/dev-init-ssh-merge.js +165 -23
  322. package/lib/utils/dev-list-sort.js +145 -0
  323. package/lib/utils/dev-pin-share-instructions.js +110 -0
  324. package/lib/utils/dev-platform-tls.js +0 -63
  325. package/lib/utils/dev-ssh-config-helper.js +177 -33
  326. package/lib/utils/docker-build.js +46 -27
  327. package/lib/utils/docker-daemon-tls-ca.js +1 -1
  328. package/lib/utils/docker-exec.js +91 -6
  329. package/lib/utils/enterprise-knowledge-paths.js +142 -0
  330. package/lib/utils/env-copy.js +3 -4
  331. package/lib/utils/env-dotenv-format.js +103 -0
  332. package/lib/utils/error-formatters/error-parser.js +0 -3
  333. package/lib/utils/external-env-template.js +5 -2
  334. package/lib/utils/external-system-display.js +5 -1
  335. package/lib/utils/external-system-readiness-compact-blocks.js +248 -0
  336. package/lib/utils/external-system-readiness-compact-display.js +324 -0
  337. package/lib/utils/external-system-readiness-core.js +16 -0
  338. package/lib/utils/external-system-readiness-deploy-display.js +29 -11
  339. package/lib/utils/external-system-readiness-display-internals.js +3 -1
  340. package/lib/utils/external-system-readiness-display.js +20 -30
  341. package/lib/utils/external-system-system-test-tty-certification.js +135 -0
  342. package/lib/utils/external-system-system-test-tty.js +5 -41
  343. package/lib/utils/health-check-request.js +2 -3
  344. package/lib/utils/help-builder.js +9 -1
  345. package/lib/utils/host-ops-job-labels.js +236 -0
  346. package/lib/utils/host-ops-job-result.js +61 -0
  347. package/lib/utils/host-ops-poll-ui.js +163 -0
  348. package/lib/utils/image-name.js +22 -4
  349. package/lib/utils/integration-path-resolve.js +112 -0
  350. package/lib/utils/logger.js +37 -4
  351. package/lib/utils/manifest-source-emit.js +1 -1
  352. package/lib/utils/paths-reload-source.js +148 -0
  353. package/lib/utils/paths-system-builder-keys.js +25 -0
  354. package/lib/utils/paths.js +183 -30
  355. package/lib/utils/pipeline-upload-auth-retry.js +4 -0
  356. package/lib/utils/postgres-platform-bootstrap.js +24 -17
  357. package/lib/utils/postgres-wipe.js +5 -2
  358. package/lib/utils/remote-dev-auth.js +39 -4
  359. package/lib/utils/resolve-docker-image-ref.js +36 -6
  360. package/lib/utils/runtime-configuration-values.js +64 -2
  361. package/lib/utils/secrets-helpers.js +5 -1
  362. package/lib/utils/ssh-known-hosts.js +130 -0
  363. package/lib/utils/test-target-cli-options.js +75 -0
  364. package/lib/utils/token-manager.js +16 -0
  365. package/lib/utils/upload-sync-options.js +20 -2
  366. package/lib/utils/validation-run-request.js +11 -2
  367. package/lib/validation/external-manifest-validator.js +11 -1
  368. package/lib/validation/openapi-contract-surface-validator.js +430 -0
  369. package/lib/validation/openapi-contract-vendor-validation.js +238 -0
  370. package/lib/validation/validate-external-file.js +160 -0
  371. package/lib/validation/validate.js +6 -117
  372. package/lib/validation/validator.js +6 -5
  373. package/package.json +76 -37
  374. package/packages/builder-api/README.md +120 -0
  375. package/packages/builder-api/package.json +30 -0
  376. package/packages/builder-api/src/app.module.ts +7 -0
  377. package/packages/builder-api/src/auth/auth.module.ts +5 -0
  378. package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
  379. package/packages/builder-api/src/main.ts +16 -0
  380. package/packages/builder-api/tsconfig.json +15 -0
  381. package/scripts/check-builder-api-architecture-grep.js +79 -0
  382. package/scripts/docker_image_content_gate.js +47 -0
  383. package/scripts/docker_image_content_gate.sh +5 -0
  384. package/scripts/export-builder-api-evidence.js +262 -0
  385. package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
  386. package/scripts/lib/builder-api-docker-staging-core.js +183 -0
  387. package/scripts/lib/docker-image-content-gate-core.js +166 -0
  388. package/scripts/lib/plan-actor.js +109 -0
  389. package/scripts/lib/plan-config.js +20 -0
  390. package/scripts/lib/plan-gates.js +154 -0
  391. package/scripts/lib/plan-meta.js +104 -0
  392. package/scripts/lib/plan-parse.js +162 -0
  393. package/scripts/lib/plan-prevalidate-gates.js +337 -0
  394. package/scripts/lib/plan-run-core.js +125 -0
  395. package/scripts/lib/plan-run-report.js +119 -0
  396. package/scripts/plan-approve.js +24 -0
  397. package/scripts/plan-archive.js +49 -0
  398. package/scripts/plan-run.js +13 -0
  399. package/scripts/plan-set-actor.js +21 -0
  400. package/scripts/plan-validate.js +80 -0
  401. package/scripts/pnpm/af.mjs +110 -0
  402. package/scripts/pnpm/check-quiet.mjs +32 -0
  403. package/scripts/pnpm/dev-install.mjs +29 -0
  404. package/scripts/pnpm/dev-reload.mjs +18 -0
  405. package/scripts/pnpm/help.mjs +55 -0
  406. package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
  407. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
  408. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
  409. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
  410. package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
  411. package/scripts/pnpm/lib/spinner.mjs +42 -0
  412. package/scripts/stage_builder_api_for_docker.js +65 -0
  413. package/scripts/sync-builder-api-template.js +44 -0
  414. package/templates/README.md +3 -0
  415. package/templates/applications/builder-api/Dockerfile +38 -0
  416. package/templates/applications/builder-api/application.yaml +75 -0
  417. package/templates/applications/builder-api/env.template +48 -0
  418. package/templates/applications/dataplane/application.yaml +27 -5
  419. package/templates/applications/dataplane/env.template +38 -15
  420. package/templates/applications/dataplane/rbac.yaml +85 -3
  421. package/templates/applications/miso-controller/application.yaml +10 -1
  422. package/templates/applications/miso-controller/env.template +11 -10
  423. package/templates/applications/miso-controller/rbac.yaml +72 -0
  424. package/templates/channels/README.md +18 -0
  425. package/templates/channels/ai-fabrix-icon.jpg +0 -0
  426. package/templates/channels/chatgpt/install.template.md.hbs +21 -24
  427. package/templates/channels/chatgpt/integration/README.md +11 -0
  428. package/templates/channels/chatgpt/integration/application.json +15 -0
  429. package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
  430. package/templates/channels/chatgpt/integration/env.template +4 -0
  431. package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
  432. package/templates/channels/microsoft-copilot/integration/README.md +11 -0
  433. package/templates/channels/microsoft-copilot/integration/application.json +15 -0
  434. package/templates/channels/microsoft-copilot/integration/env.template +6 -0
  435. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
  436. package/templates/channels/slack/install.template.md.hbs +48 -18
  437. package/templates/channels/slack/integration/README.md +38 -0
  438. package/templates/channels/slack/integration/application.json +18 -0
  439. package/templates/channels/slack/integration/env.template +29 -0
  440. package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
  441. package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
  442. package/templates/channels/slack/integration/slack-system.json +144 -0
  443. package/templates/channels/slack/manifest.template.json.hbs +20 -10
  444. package/templates/channels/teams-bot/install.template.md.hbs +31 -17
  445. package/templates/channels/teams-bot/integration/README.md +18 -0
  446. package/templates/channels/teams-bot/integration/application.json +17 -0
  447. package/templates/channels/teams-bot/integration/env.template +5 -0
  448. package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
  449. package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
  450. package/templates/channels/web-embed/install.template.md.hbs +16 -26
  451. package/templates/channels/web-embed/integration/README.md +11 -0
  452. package/templates/channels/web-embed/integration/application.json +15 -0
  453. package/templates/channels/web-embed/integration/env.template +4 -0
  454. package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
  455. package/templates/openapi/redoc_page.html +86 -0
  456. package/templates/python/docker-compose.hbs +11 -0
  457. package/templates/python/requirements.txt +2 -2
  458. package/templates/typescript/docker-compose.hbs +11 -0
  459. package/lib/certification/cli-cert-sync-skip.js +0 -21
@@ -17,6 +17,7 @@ const { formatValidationErrors } = require('../utils/error-formatter');
17
17
  const { validateFieldReferences } = require('../datasource/field-reference-validator');
18
18
  const { validateAbac } = require('../datasource/abac-validator');
19
19
  const { validateManifestRuntimeConfiguration } = require('./runtime-configuration-rules');
20
+ const { validateAppContractSurface } = require('./openapi-contract-surface-validator');
20
21
 
21
22
  /**
22
23
  * Load and normalize external-system + external-datasource schema objects for manifest AJV.
@@ -223,6 +224,7 @@ function validateDatasourceSystemKeyAlignment(manifest, errors) {
223
224
  * @async
224
225
  * @function validateControllerManifest
225
226
  * @param {Object} manifest - Controller manifest object
227
+ * @param {Object} [options] - Optional context (appPath for contract-surface checks)
226
228
  * @returns {Promise<Object>} Validation result
227
229
  * @throws {Error} If validation fails critically
228
230
  *
@@ -230,7 +232,7 @@ function validateDatasourceSystemKeyAlignment(manifest, errors) {
230
232
  * const result = await validateControllerManifest(manifest);
231
233
  * // Returns: { valid: true, errors: [], warnings: [] }
232
234
  */
233
- async function validateControllerManifest(manifest) {
235
+ async function validateControllerManifest(manifest, options = {}) {
234
236
  if (!manifest || typeof manifest !== 'object') {
235
237
  return {
236
238
  valid: false,
@@ -249,6 +251,14 @@ async function validateControllerManifest(manifest) {
249
251
  validateDatasources(manifest, ajv, externalDatasourceSchema, errors, warnings);
250
252
  validateDatasourceSystemKeyAlignment(manifest, errors);
251
253
  errors.push(...validateManifestRuntimeConfiguration(manifest));
254
+ if (manifest.type === 'external' && Array.isArray(manifest.dataSources) && manifest.system?.key) {
255
+ const appPath = options.appPath;
256
+ if (typeof appPath === 'string' && appPath) {
257
+ const contract = validateAppContractSurface(appPath, manifest.system.key, manifest.dataSources);
258
+ errors.push(...contract.errors);
259
+ warnings.push(...contract.warnings);
260
+ }
261
+ }
252
262
  validateConditionalRequirements(manifest, errors, warnings);
253
263
  validateRequiredFields(manifest, errors);
254
264
 
@@ -0,0 +1,430 @@
1
+ /**
2
+ * Validate that OpenAPI / MCP contract surfaces are meaningful (not dataplane stubs).
3
+ *
4
+ * @fileoverview Contract surface validation for orchestration vs record datasources
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { buildOpenApiSpec } = require('../programmatic/openapi-spec');
14
+ const {
15
+ documentKeyToLocalOpenApiPath,
16
+ isProgrammaticOrchestrationSystem,
17
+ specHasComponentSchemas
18
+ } = require('../commands/repair-openapi-export');
19
+ const {
20
+ validateVendorOperationContract,
21
+ findVendorOperation,
22
+ validateOrchestrationDatasourceContracts
23
+ } = require('./openapi-contract-vendor-validation');
24
+
25
+ const JSON_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options']);
26
+
27
+ /**
28
+ * @param {Object} ds
29
+ * @returns {boolean}
30
+ */
31
+ function isServiceContractDatasource(ds) {
32
+ const entity = String(ds?.entityType || '').trim().toLowerCase();
33
+ return entity === 'servicecontract';
34
+ }
35
+
36
+ /**
37
+ * @param {Object} ds
38
+ * @returns {boolean}
39
+ */
40
+ function isCompositionNoneDatasource(ds) {
41
+ return String(ds?.entityType || '').trim().toLowerCase() === 'none';
42
+ }
43
+
44
+ /**
45
+ * @param {Object} ds
46
+ * @returns {boolean}
47
+ */
48
+ function hasVendorOpenapiOnManifest(ds) {
49
+ const openapi = ds?.openapi;
50
+ if (!openapi || typeof openapi !== 'object' || openapi.enabled === false) {
51
+ return false;
52
+ }
53
+ const operations = openapi.operations;
54
+ if (operations && typeof operations === 'object' && Object.keys(operations).length > 0) {
55
+ return true;
56
+ }
57
+ const documentKey =
58
+ typeof openapi.documentKey === 'string' ? openapi.documentKey.trim() : '';
59
+ return Boolean(documentKey) || openapi.enabled === true;
60
+ }
61
+
62
+ /**
63
+ * @deprecated use isServiceContractDatasource — kept for tests importing legacy name
64
+ * @param {Object} ds
65
+ * @returns {boolean}
66
+ */
67
+ function isOrchestrationDatasource(ds) {
68
+ return isServiceContractDatasource(ds);
69
+ }
70
+
71
+ /**
72
+ * @param {Object|undefined} op
73
+ * @returns {boolean}
74
+ */
75
+ function operationHasRequestOrResponseSchema(op) {
76
+ if (!op || typeof op !== 'object') {
77
+ return false;
78
+ }
79
+ if (op.requestBody) {
80
+ return true;
81
+ }
82
+ const responses = op.responses;
83
+ if (!responses || typeof responses !== 'object') {
84
+ return false;
85
+ }
86
+ for (const response of Object.values(responses)) {
87
+ if (response && typeof response === 'object' && response.content) {
88
+ return true;
89
+ }
90
+ }
91
+ return false;
92
+ }
93
+
94
+ /**
95
+ * @param {Object|undefined} paths
96
+ * @returns {boolean}
97
+ */
98
+ function pathsHaveRequestOrResponseSchemas(paths) {
99
+ if (!paths || typeof paths !== 'object') {
100
+ return false;
101
+ }
102
+ for (const pathItem of Object.values(paths)) {
103
+ if (!pathItem || typeof pathItem !== 'object') {
104
+ continue;
105
+ }
106
+ for (const [method, op] of Object.entries(pathItem)) {
107
+ if (!JSON_METHODS.has(method)) {
108
+ continue;
109
+ }
110
+ if (operationHasRequestOrResponseSchema(op)) {
111
+ return true;
112
+ }
113
+ }
114
+ }
115
+ return false;
116
+ }
117
+
118
+ /**
119
+ * @param {unknown} spec
120
+ * @returns {boolean}
121
+ */
122
+ function isThinOpenApiSpec(spec) {
123
+ if (!spec || typeof spec !== 'object') {
124
+ return true;
125
+ }
126
+ if (specHasComponentSchemas(spec)) {
127
+ return false;
128
+ }
129
+ return !pathsHaveRequestOrResponseSchemas(spec.paths);
130
+ }
131
+
132
+ /**
133
+ * @param {string} filePath
134
+ * @returns {Object|null}
135
+ */
136
+ function readJsonIfExists(filePath) {
137
+ if (!filePath || !fs.existsSync(filePath)) {
138
+ return null;
139
+ }
140
+ try {
141
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * @param {string} appPath
149
+ * @param {string} systemKey
150
+ * @param {string} documentKey
151
+ * @returns {{ spec: Object|null, localPath: string, fromMemory: boolean }}
152
+ */
153
+ function resolveVendorOpenApiSpec(appPath, systemKey, documentKey) {
154
+ const localPath = documentKeyToLocalOpenApiPath(appPath, systemKey, documentKey);
155
+ const fromDisk = readJsonIfExists(localPath);
156
+ if (fromDisk) {
157
+ return { spec: fromDisk, localPath, fromMemory: false };
158
+ }
159
+ if (isProgrammaticOrchestrationSystem(systemKey)) {
160
+ const spec = buildOpenApiSpec();
161
+ return { spec, localPath, fromMemory: true };
162
+ }
163
+ return { spec: null, localPath, fromMemory: false };
164
+ }
165
+
166
+ /**
167
+ * @param {Object} ds
168
+ * @param {string} prefix
169
+ * @returns {string[]}
170
+ */
171
+ function collectServiceContractFieldMappingErrors(ds, prefix) {
172
+ const fieldMappings = ds.fieldMappings;
173
+ const attributes =
174
+ fieldMappings && typeof fieldMappings === 'object' ? fieldMappings.attributes : null;
175
+ const hasAttributes =
176
+ attributes && typeof attributes === 'object' && Object.keys(attributes).length > 0;
177
+ if (hasAttributes) {
178
+ return [];
179
+ }
180
+ return [
181
+ `${prefix}serviceContract requires fieldMappings.attributes — public contract must be testable`
182
+ ];
183
+ }
184
+
185
+ /**
186
+ * @param {Object} ds
187
+ * @param {string} prefix
188
+ * @returns {{ errors: string[], warnings: string[] }}
189
+ */
190
+ function collectServiceContractExposedIssues(ds, prefix) {
191
+ const errors = [];
192
+ const warnings = [];
193
+ const exposed = ds.exposed;
194
+ const schema = exposed && typeof exposed === 'object' ? exposed.schema : null;
195
+ if (!schema || typeof schema !== 'object' || Object.keys(schema).length === 0) {
196
+ errors.push(`${prefix}serviceContract requires exposed.schema for MCP/REST contract`);
197
+ }
198
+ const profiles = exposed && typeof exposed === 'object' ? exposed.profiles : null;
199
+ if (!profiles || typeof profiles !== 'object' || Object.keys(profiles).length === 0) {
200
+ warnings.push(`${prefix}serviceContract missing exposed.profiles — add default envelope`);
201
+ }
202
+ return { errors, warnings };
203
+ }
204
+
205
+ /**
206
+ * @param {Object} ds
207
+ * @param {string} prefix
208
+ * @returns {{ errors: string[], warnings: string[] }}
209
+ */
210
+ function validateServiceContractDatasourceContracts(ds, prefix) {
211
+ const errors = collectServiceContractFieldMappingErrors(ds, prefix);
212
+ const exposed = collectServiceContractExposedIssues(ds, prefix);
213
+ errors.push(...exposed.errors);
214
+ return { errors, warnings: exposed.warnings };
215
+ }
216
+
217
+ /**
218
+ * @param {Object} ds
219
+ * @param {string} prefix
220
+ * @returns {{ errors: string[], warnings: string[] }}
221
+ */
222
+ function validateRecordDatasourceContracts(ds, prefix) {
223
+ const errors = [];
224
+ const warnings = [];
225
+ const caps = ds.capabilities;
226
+ const capList = Array.isArray(caps) ? caps.map((c) => String(c).toLowerCase()) : [];
227
+ const needsExposed = capList.some((c) => ['create', 'update', 'list', 'get'].includes(c));
228
+ const fieldMappings = ds.fieldMappings;
229
+ const attributes =
230
+ fieldMappings && typeof fieldMappings === 'object' ? fieldMappings.attributes : null;
231
+ const hasAttributes =
232
+ attributes && typeof attributes === 'object' && Object.keys(attributes).length > 0;
233
+ if (!hasAttributes) {
234
+ errors.push(
235
+ `${prefix}fieldMappings.attributes is missing or empty — record entities need mapped fields for sync and MCP schemas`
236
+ );
237
+ }
238
+ const exposed = ds.exposed;
239
+ const profiles = exposed && typeof exposed === 'object' ? exposed.profiles : null;
240
+ const hasProfiles =
241
+ profiles && typeof profiles === 'object' && Object.keys(profiles).length > 0;
242
+ if (needsExposed && !hasProfiles) {
243
+ errors.push(
244
+ `${prefix}exposed.profiles is missing or empty — record entities need exposed schema profiles for MCP/OpenAPI`
245
+ );
246
+ }
247
+ return { errors, warnings };
248
+ }
249
+
250
+ /**
251
+ * @param {Object} ds
252
+ * @param {string} prefix
253
+ * @returns {{ errors: string[], warnings: string[] }}
254
+ */
255
+ function validateNoneDatasourceContract(ds, prefix) {
256
+ const errors = [];
257
+ const warnings = [];
258
+ if (hasVendorOpenapiOnManifest(ds)) {
259
+ warnings.push(
260
+ `${prefix}entityType none must not bind vendor OpenAPI — run repair to migrate to serviceContract`
261
+ );
262
+ }
263
+ return { errors, warnings };
264
+ }
265
+
266
+ /**
267
+ * @param {string} documentKey
268
+ * @param {string} prefix
269
+ * @param {string} appPath
270
+ * @param {string} systemKey
271
+ * @param {Map<string, Object|null>} vendorCache
272
+ * @returns {{ errors: string[], warnings: string[] }}
273
+ */
274
+ function resolveCachedVendorSpec(documentKey, prefix, appPath, systemKey, vendorCache) {
275
+ const errors = [];
276
+ const warnings = [];
277
+ const resolved = resolveVendorOpenApiSpec(appPath, systemKey, documentKey);
278
+ vendorCache.set(documentKey, resolved.spec);
279
+ if (!resolved.spec) {
280
+ errors.push(
281
+ `${prefix}missing vendor OpenAPI at ${resolved.localPath} — run: aifabrix repair ${systemKey} --api`
282
+ );
283
+ return { errors, warnings, spec: null };
284
+ }
285
+ if (isThinOpenApiSpec(resolved.spec)) {
286
+ errors.push(
287
+ `${prefix}vendor OpenAPI "${documentKey}" is a thin stub (no component schemas / body schemas) — run: aifabrix repair ${systemKey} --api`
288
+ );
289
+ return { errors, warnings, spec: null };
290
+ }
291
+ if (resolved.fromMemory) {
292
+ warnings.push(
293
+ `${prefix}vendor OpenAPI "${documentKey}" not on disk; validated from in-memory programmatic spec — run: aifabrix repair ${systemKey} --api to materialize openapi/`
294
+ );
295
+ }
296
+ return { errors, warnings, spec: resolved.spec };
297
+ }
298
+
299
+ /**
300
+ * @param {Object} ds
301
+ * @param {string} prefix
302
+ * @param {string} appPath
303
+ * @param {string} systemKey
304
+ * @param {Map<string, Object|null>} vendorCache
305
+ * @returns {{ errors: string[], warnings: string[] }}
306
+ */
307
+ function validateServiceContractVendorOpenApi(ds, prefix, appPath, systemKey, vendorCache) {
308
+ const errors = [];
309
+ const warnings = [];
310
+ // Python/CIP handlers without a vendor OpenAPI binding are valid serviceContracts.
311
+ if (!hasVendorOpenapiOnManifest(ds)) {
312
+ return { errors, warnings };
313
+ }
314
+ const documentKey =
315
+ typeof ds.openapi?.documentKey === 'string' ? ds.openapi.documentKey.trim() : '';
316
+ if (!documentKey) {
317
+ errors.push(`${prefix}serviceContract with OpenAPI upstream requires openapi.documentKey`);
318
+ return { errors, warnings };
319
+ }
320
+ if (!vendorCache.has(documentKey)) {
321
+ const cached = resolveCachedVendorSpec(documentKey, prefix, appPath, systemKey, vendorCache);
322
+ errors.push(...cached.errors);
323
+ warnings.push(...cached.warnings);
324
+ if (!cached.spec) {
325
+ return { errors, warnings };
326
+ }
327
+ }
328
+ const vendorSpec = vendorCache.get(documentKey);
329
+ const orch = validateOrchestrationDatasourceContracts(ds, vendorSpec, prefix);
330
+ errors.push(...orch.errors);
331
+ warnings.push(...orch.warnings);
332
+ return { errors, warnings };
333
+ }
334
+
335
+ /**
336
+ * @param {Object} ds
337
+ * @param {string} appPath
338
+ * @param {string} systemKey
339
+ * @param {Map<string, Object|null>} vendorCache
340
+ * @returns {{ errors: string[], warnings: string[] }}
341
+ */
342
+ function validateDatasourceContractSurface(ds, appPath, systemKey, vendorCache) {
343
+ const prefix = `Datasource "${ds.key || '(unknown)'}": `;
344
+ if (isCompositionNoneDatasource(ds)) {
345
+ return validateNoneDatasourceContract(ds, prefix);
346
+ }
347
+ if (isServiceContractDatasource(ds)) {
348
+ const sc = validateServiceContractDatasourceContracts(ds, prefix);
349
+ const vendor = validateServiceContractVendorOpenApi(
350
+ ds,
351
+ prefix,
352
+ appPath,
353
+ systemKey,
354
+ vendorCache
355
+ );
356
+ return {
357
+ errors: [...sc.errors, ...vendor.errors],
358
+ warnings: [...sc.warnings, ...vendor.warnings]
359
+ };
360
+ }
361
+ return validateRecordDatasourceContracts(ds, prefix);
362
+ }
363
+
364
+ /**
365
+ * @param {string} appPath
366
+ * @param {string} systemKey
367
+ * @param {Object[]} datasources
368
+ * @returns {{ errors: string[], warnings: string[] }}
369
+ */
370
+ function validateAppContractSurface(appPath, systemKey, datasources) {
371
+ const errors = [];
372
+ const warnings = [];
373
+ const vendorCache = new Map();
374
+ for (const ds of datasources || []) {
375
+ if (!ds || typeof ds !== 'object') {
376
+ continue;
377
+ }
378
+ const result = validateDatasourceContractSurface(ds, appPath, systemKey, vendorCache);
379
+ errors.push(...result.errors);
380
+ warnings.push(...result.warnings);
381
+ }
382
+ return { errors, warnings };
383
+ }
384
+
385
+ /**
386
+ * @param {string} filePath
387
+ * @returns {{ appPath: string, systemKey: string }|null}
388
+ */
389
+ function inferIntegrationContextFromPath(filePath) {
390
+ const normalized = path.normalize(filePath);
391
+ const parts = normalized.split(path.sep);
392
+ const integrationIdx = parts.lastIndexOf('integration');
393
+ if (integrationIdx < 0 || integrationIdx + 1 >= parts.length) {
394
+ return null;
395
+ }
396
+ const systemKey = parts[integrationIdx + 1];
397
+ const appPath = parts.slice(0, integrationIdx + 2).join(path.sep);
398
+ return { appPath, systemKey };
399
+ }
400
+
401
+ /**
402
+ * @param {Object} parsedDatasource
403
+ * @param {string} filePath
404
+ * @returns {{ errors: string[], warnings: string[] }}
405
+ */
406
+ function validateDatasourceFileContractSurface(parsedDatasource, filePath) {
407
+ const ctx = inferIntegrationContextFromPath(filePath);
408
+ if (!ctx) {
409
+ return { errors: [], warnings: [] };
410
+ }
411
+ return validateDatasourceContractSurface(
412
+ parsedDatasource,
413
+ ctx.appPath,
414
+ ctx.systemKey,
415
+ new Map()
416
+ );
417
+ }
418
+
419
+ module.exports = {
420
+ isOrchestrationDatasource,
421
+ isServiceContractDatasource,
422
+ isCompositionNoneDatasource,
423
+ hasVendorOpenapiOnManifest,
424
+ isThinOpenApiSpec,
425
+ validateAppContractSurface,
426
+ validateDatasourceFileContractSurface,
427
+ validateVendorOperationContract,
428
+ validateServiceContractDatasourceContracts,
429
+ findVendorOperation
430
+ };
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Vendor OpenAPI operation contract checks for serviceContract datasources.
3
+ *
4
+ * @fileoverview Extracted from openapi-contract-surface-validator (max-lines split)
5
+ * @author AI Fabrix Team
6
+ * @version 1.0.0
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const MUTATING_METHODS = new Set(['post', 'put', 'patch']);
12
+
13
+ /**
14
+ * @param {Object|undefined} content
15
+ * @returns {boolean}
16
+ */
17
+ function hasJsonSchemaContent(content) {
18
+ if (!content || typeof content !== 'object') {
19
+ return false;
20
+ }
21
+ const json = content['application/json'];
22
+ if (!json || typeof json !== 'object') {
23
+ return false;
24
+ }
25
+ const schema = json.schema;
26
+ return Boolean(schema && typeof schema === 'object' && Object.keys(schema).length > 0);
27
+ }
28
+
29
+ /**
30
+ * @param {Object|undefined} op
31
+ * @returns {boolean}
32
+ */
33
+ function operationHasParameters(op) {
34
+ const params = op?.parameters;
35
+ return Array.isArray(params) && params.length > 0;
36
+ }
37
+
38
+ /**
39
+ * @param {Object|undefined} opCfg
40
+ * @returns {{ requestBody: boolean, responseBody: boolean }}
41
+ */
42
+ function readContractExempt(opCfg) {
43
+ const raw = opCfg?.contractExempt || opCfg?.contractSurfaceExempt;
44
+ if (!raw || typeof raw !== 'object') {
45
+ return { requestBody: false, responseBody: false };
46
+ }
47
+ return {
48
+ requestBody: raw.requestBody === true,
49
+ responseBody: raw.responseBody === true
50
+ };
51
+ }
52
+
53
+ /**
54
+ * @param {Object|undefined} vendorOp
55
+ * @param {Object|undefined} opCfg
56
+ * @param {string} opKey
57
+ * @returns {{ errors: string[], warnings: string[] }}
58
+ */
59
+ function validateVendorOperationContract(vendorOp, opCfg, opKey) {
60
+ const errors = [];
61
+ const warnings = [];
62
+ const exempt = readContractExempt(opCfg);
63
+ const method = String(opCfg?.method || 'get').trim().toLowerCase();
64
+ if (!vendorOp || typeof vendorOp !== 'object') {
65
+ errors.push(
66
+ `openapi.operations.${opKey}: no matching operation in vendor OpenAPI (check path, method, operationId)`
67
+ );
68
+ return { errors, warnings };
69
+ }
70
+ validateRequestSurface(vendorOp, method, opKey, exempt, errors, warnings);
71
+ validateResponseSurface(vendorOp, method, opKey, exempt, errors, warnings);
72
+ return { errors, warnings };
73
+ }
74
+
75
+ /**
76
+ * @param {Object} vendorOp
77
+ * @param {string} method
78
+ * @param {string} opKey
79
+ * @param {{ requestBody: boolean, responseBody: boolean }} exempt
80
+ * @param {string[]} errors
81
+ * @param {string[]} warnings
82
+ */
83
+ function validateRequestSurface(vendorOp, method, opKey, exempt, errors, warnings) {
84
+ if (!MUTATING_METHODS.has(method) || exempt.requestBody) {
85
+ return;
86
+ }
87
+ const hasBody = hasJsonSchemaContent(vendorOp.requestBody?.content);
88
+ const hasParams = operationHasParameters(vendorOp);
89
+ if (hasBody || hasParams) {
90
+ if (!hasBody && hasParams) {
91
+ warnings.push(
92
+ `openapi.operations.${opKey}: POST/PUT/PATCH uses query/path parameters only (no requestBody schema) — allowed for edge cases like eventStart?id=`
93
+ );
94
+ }
95
+ return;
96
+ }
97
+ errors.push(
98
+ `openapi.operations.${opKey}: mutating operation has no requestBody schema and no parameters — agents cannot send inputs`
99
+ );
100
+ }
101
+
102
+ /**
103
+ * @param {Object} vendorOp
104
+ * @param {string} method
105
+ * @param {string} opKey
106
+ * @param {{ requestBody: boolean, responseBody: boolean }} exempt
107
+ * @param {string[]} errors
108
+ * @param {string[]} warnings
109
+ */
110
+ function validateResponseSurface(vendorOp, method, opKey, exempt, errors, warnings) {
111
+ if (exempt.responseBody) {
112
+ return;
113
+ }
114
+ const responses = vendorOp.responses;
115
+ if (!responses || typeof responses !== 'object') {
116
+ pushResponseIssue(method, opKey, errors, warnings);
117
+ return;
118
+ }
119
+ if (responses['204']) {
120
+ return;
121
+ }
122
+ for (const status of ['200', '201', '202']) {
123
+ const response = responses[status];
124
+ if (response && hasJsonSchemaContent(response.content)) {
125
+ return;
126
+ }
127
+ }
128
+ pushResponseIssue(method, opKey, errors, warnings);
129
+ }
130
+
131
+ /**
132
+ * @param {string} method
133
+ * @param {string} opKey
134
+ * @param {string[]} errors
135
+ * @param {string[]} warnings
136
+ */
137
+ function pushResponseIssue(method, opKey, errors, warnings) {
138
+ const msg =
139
+ `openapi.operations.${opKey}: no JSON response schema on 200/201/202 — ` +
140
+ 'MCP outputSchema and live validation will be empty';
141
+ if (MUTATING_METHODS.has(method)) {
142
+ errors.push(msg);
143
+ return;
144
+ }
145
+ warnings.push(msg);
146
+ }
147
+
148
+ /**
149
+ * @param {Object|undefined} paths
150
+ * @param {string} pathKey
151
+ * @param {string} method
152
+ * @returns {Object|null}
153
+ */
154
+ function findVendorOperationByPath(paths, pathKey, method) {
155
+ if (!pathKey || !paths || typeof paths !== 'object') {
156
+ return null;
157
+ }
158
+ const pathItem = paths[pathKey];
159
+ if (!pathItem || typeof pathItem !== 'object') {
160
+ return null;
161
+ }
162
+ return pathItem[method] || null;
163
+ }
164
+
165
+ /**
166
+ * @param {Object|undefined} paths
167
+ * @param {string} operationId
168
+ * @returns {Object|null}
169
+ */
170
+ function findVendorOperationById(paths, operationId) {
171
+ if (!operationId || !paths || typeof paths !== 'object') {
172
+ return null;
173
+ }
174
+ for (const pathItem of Object.values(paths)) {
175
+ if (!pathItem || typeof pathItem !== 'object') {
176
+ continue;
177
+ }
178
+ for (const op of Object.values(pathItem)) {
179
+ if (op && typeof op === 'object' && String(op.operationId || '').trim() === operationId) {
180
+ return op;
181
+ }
182
+ }
183
+ }
184
+ return null;
185
+ }
186
+
187
+ /**
188
+ * @param {Object|undefined} vendorSpec
189
+ * @param {Object|undefined} opCfg
190
+ * @returns {Object|null}
191
+ */
192
+ function findVendorOperation(vendorSpec, opCfg) {
193
+ if (!vendorSpec || typeof vendorSpec !== 'object' || !opCfg || typeof opCfg !== 'object') {
194
+ return null;
195
+ }
196
+ const paths = vendorSpec.paths;
197
+ const pathKey = typeof opCfg.path === 'string' ? opCfg.path.trim() : '';
198
+ const method = String(opCfg.method || 'get').trim().toLowerCase();
199
+ const byPath = findVendorOperationByPath(paths, pathKey, method);
200
+ if (byPath) {
201
+ return byPath;
202
+ }
203
+ const operationId = typeof opCfg.operationId === 'string' ? opCfg.operationId.trim() : '';
204
+ return findVendorOperationById(paths, operationId);
205
+ }
206
+
207
+ /**
208
+ * @param {Object} ds
209
+ * @param {Object|null} vendorSpec
210
+ * @param {string} prefix
211
+ * @returns {{ errors: string[], warnings: string[] }}
212
+ */
213
+ function validateOrchestrationDatasourceContracts(ds, vendorSpec, prefix) {
214
+ const errors = [];
215
+ const warnings = [];
216
+ const openapi = ds.openapi;
217
+ if (!openapi || openapi.enabled !== true) {
218
+ return { errors, warnings };
219
+ }
220
+ const operations = openapi.operations;
221
+ if (!operations || typeof operations !== 'object') {
222
+ errors.push(`${prefix}openapi.enabled but openapi.operations is missing`);
223
+ return { errors, warnings };
224
+ }
225
+ for (const [opKey, opCfg] of Object.entries(operations)) {
226
+ const vendorOp = findVendorOperation(vendorSpec, opCfg);
227
+ const result = validateVendorOperationContract(vendorOp, opCfg, opKey);
228
+ result.errors.forEach((e) => errors.push(`${prefix}${e}`));
229
+ result.warnings.forEach((w) => warnings.push(`${prefix}${w}`));
230
+ }
231
+ return { errors, warnings };
232
+ }
233
+
234
+ module.exports = {
235
+ validateVendorOperationContract,
236
+ findVendorOperation,
237
+ validateOrchestrationDatasourceContracts
238
+ };