@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.
- package/.cursor/plans/157.1-security-quality-violations-by-type.csv +374 -0
- package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +49 -0
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +30 -0
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +35 -0
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +31 -0
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +34 -0
- package/.cursor/skills/README.md +1 -0
- package/.dockerignore +52 -0
- package/.eslintignore +22 -0
- package/README.md +2 -0
- package/bin/builder-api-cleanup.js +26 -0
- package/bin/builder-api-nest.js +10 -0
- package/bin/builder-api-spike.js +19 -0
- package/enterprise-knowledge/README.md +50 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +22 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +15 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +69 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +52 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +29 -0
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +2 -0
- package/integration/README.md +81 -0
- package/integration/github/README.md +53 -0
- package/integration/github/application.json +21 -0
- package/integration/github/deploy.js +72 -0
- package/integration/github/env.template +11 -0
- package/integration/github/github-datasource-issue-comments.json +239 -0
- package/integration/github/github-datasource-issues.json +399 -0
- package/integration/github/github-datasource-repository.json +354 -0
- package/integration/github/github-deploy.json +1202 -0
- package/integration/github/github-system.json +82 -0
- package/integration/hubspot-test/README.md +1 -1
- package/integration/hubspot-test/create-hubspot.js +1 -16
- package/jest.isolated-projects.js +31 -1
- package/jest.projects.js +87 -1
- package/lib/api/dev-server-https.js +1 -1
- package/lib/api/enterprise-knowledge.api.js +63 -0
- package/lib/api/evidence-kinds.api.js +128 -0
- package/lib/api/evidence.api.js +172 -0
- package/lib/api/external-systems.api.js +8 -2
- package/lib/api/pipeline.api.js +5 -1
- package/lib/api/resource-types.api.js +5 -4
- package/lib/api/roles.api.js +121 -0
- package/lib/api/types/enterprise-knowledge.types.js +46 -0
- package/lib/api/types/evidence-kinds.types.js +42 -0
- package/lib/api/types/evidence.types.js +67 -0
- package/lib/api/types/resource-types.types.js +2 -0
- package/lib/api/types/roles.types.js +36 -0
- package/lib/app/certification-verify-rows.js +1 -1
- package/lib/app/controller-application-filter.js +36 -0
- package/lib/app/deploy.js +1 -1
- package/lib/app/list-external-systems.js +130 -0
- package/lib/app/list.js +20 -8
- package/lib/app/run.js +3 -1
- package/lib/app/show-display.js +8 -3
- package/lib/app/show-online.js +178 -0
- package/lib/app/show.js +39 -90
- package/lib/build/builder-api-docker-staging.js +47 -0
- package/lib/build/miso-controller-npm-sdk-guard.js +2 -2
- package/lib/build/standard-docker-build.js +2 -0
- package/lib/certification/merge-certification-from-artifact.js +1 -1
- package/lib/certification/post-unified-cert-sync.js +4 -31
- package/lib/certification/sync-after-external-command.js +0 -1
- package/lib/certification/sync-system-certification.js +0 -3
- package/lib/channels/add-channel.js +40 -34
- package/lib/channels/approval-guides/chatgpt.js +33 -0
- package/lib/channels/approval-guides/credential-portal.js +38 -0
- package/lib/channels/approval-guides/index.js +110 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +34 -0
- package/lib/channels/approval-guides/slack.js +34 -0
- package/lib/channels/approval-guides/teams-bot.js +35 -0
- package/lib/channels/approval-guides/web-embed.js +32 -0
- package/lib/channels/channel-approval-guide.js +11 -0
- package/lib/channels/channel-artifact-generator.js +18 -5
- package/lib/channels/channel-audit.js +3 -0
- package/lib/channels/channel-auth-context.js +1 -1
- package/lib/channels/channel-description.js +59 -0
- package/lib/channels/channel-integration-generator.js +13 -230
- package/lib/channels/channel-integration-template.js +94 -0
- package/lib/channels/channel-runtime-resolver.js +43 -3
- package/lib/channels/channel-status-display.js +66 -26
- package/lib/channels/channel-targets.js +3 -3
- package/lib/cli/index.js +31 -3
- package/lib/cli/infra-guided.js +5 -1
- package/lib/cli/setup-app-external-create.js +111 -0
- package/lib/cli/setup-app.help.js +1 -1
- package/lib/cli/setup-app.js +60 -130
- package/lib/cli/setup-app.test-commands.js +26 -52
- package/lib/cli/setup-certification-commands.js +4 -4
- package/lib/cli/setup-certification.help.js +9 -9
- package/lib/cli/setup-dev.js +30 -9
- package/lib/cli/setup-external-system-help.js +4 -6
- package/lib/cli/setup-external-system.js +58 -52
- package/lib/cli/setup-infra-up-builder-api-action.js +64 -0
- package/lib/cli/setup-infra-up-platform-action.js +3 -1
- package/lib/cli/setup-infra.js +15 -0
- package/lib/cli/setup-list.js +43 -0
- package/lib/cli/setup-utility-help-after.js +12 -0
- package/lib/cli/setup-utility-repair.js +26 -7
- package/lib/cli/setup-utility-validate.js +41 -2
- package/lib/cli/setup-utility.js +5 -3
- package/lib/commands/app.js +15 -43
- package/lib/commands/channel-add-setup.js +110 -0
- package/lib/commands/channel.js +42 -8
- package/lib/commands/datasource-sync-display.js +96 -0
- package/lib/commands/datasource-sync-policy.js +210 -0
- package/lib/commands/datasource-test-trust-cli.js +6 -6
- package/lib/commands/datasource-unified-test-cli.js +2 -1
- package/lib/commands/datasource-unified-test-cli.options.js +33 -23
- package/lib/commands/deploy-gate-failure-details.js +184 -0
- package/lib/commands/deploy-gate-orchestrator.js +368 -0
- package/lib/commands/dev-cli-handlers.js +7 -62
- package/lib/commands/dev-host-ops-params.js +91 -0
- package/lib/commands/dev-host-ops-poll.js +111 -0
- package/lib/commands/dev-host-ops.js +107 -94
- package/lib/commands/dev-init.js +6 -106
- package/lib/commands/dev-refresh.js +197 -0
- package/lib/commands/enterprise-knowledge.js +284 -0
- package/lib/commands/evidence-cli-leaves.js +250 -0
- package/lib/commands/evidence-kind.js +428 -0
- package/lib/commands/evidence.js +51 -0
- package/lib/commands/governance-cli-shared.js +2 -2
- package/lib/commands/governance-command-action.js +5 -3
- package/lib/commands/governance-fixture-subjects.js +85 -0
- package/lib/commands/governance.js +1 -1
- package/lib/commands/lifecycle-command-action.js +2 -2
- package/lib/commands/lifecycle-external.js +3 -3
- package/lib/commands/manifest-cli-auth.js +29 -0
- package/lib/commands/manifest-cli-commands.js +170 -0
- package/lib/commands/manifest-cli-integration-path.js +63 -0
- package/lib/commands/manifest.js +21 -0
- package/lib/commands/protection-cli-leaves.js +3 -3
- package/lib/commands/repair-auth-apply.js +15 -1
- package/lib/commands/repair-authentications-454.js +169 -0
- package/lib/commands/repair-capability-openapi-warnings.js +126 -0
- package/lib/commands/repair-datasource-apply.js +135 -0
- package/lib/commands/repair-datasource-auto-rbac.js +62 -1
- package/lib/commands/repair-datasource-http-service-contract.js +239 -0
- package/lib/commands/repair-datasource-operation-security.js +180 -0
- package/lib/commands/repair-datasource-run.js +7 -2
- package/lib/commands/repair-datasource-sync-operations.js +177 -0
- package/lib/commands/repair-datasource-webhooks-sync-bridge.js +133 -0
- package/lib/commands/repair-datasource.js +12 -68
- package/lib/commands/repair-env-template.js +11 -1
- package/lib/commands/repair-external-run.js +121 -31
- package/lib/commands/repair-internal.js +1 -1
- package/lib/commands/repair-openapi-export.js +156 -0
- package/lib/commands/repair-openapi-sync.js +33 -8
- package/lib/commands/repair-orchestration-datasource-split.js +259 -0
- package/lib/commands/repair-persist.js +22 -1
- package/lib/commands/repair-rbac-platform-preset.js +204 -0
- package/lib/commands/repair-rbac-reader-roles.js +191 -0
- package/lib/commands/repair-rbac.js +163 -86
- package/lib/commands/repair-steps.js +83 -18
- package/lib/commands/repair-system-permissions.js +1 -0
- package/lib/commands/repair.js +1 -1
- package/lib/commands/resource-type.js +166 -44
- package/lib/commands/role.js +452 -0
- package/lib/commands/run-post-publish-data-sync.js +68 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup.js +1 -1
- package/lib/commands/test-e2e-external.js +21 -8
- package/lib/commands/test-governance-cli-options.js +2 -2
- package/lib/commands/test-trust-cli-options.js +2 -2
- package/lib/commands/up-builder-api-bootstrap.js +71 -0
- package/lib/commands/up-builder-api-provision.js +241 -0
- package/lib/commands/up-builder-api.js +88 -0
- package/lib/commands/up-common.js +25 -1
- package/lib/commands/upload-credential-push-log.js +117 -0
- package/lib/commands/upload-data-sync-finalize.js +60 -0
- package/lib/commands/upload-probe.js +66 -0
- package/lib/commands/upload-publish-context.js +4 -1
- package/lib/commands/upload-sidecar-followups.js +55 -27
- package/lib/commands/upload.js +116 -157
- package/lib/commands/validate-json.js +230 -0
- package/lib/commands/verify-governance-combined-external.js +1 -1
- package/lib/commands/verify-governance-db.js +2 -2
- package/lib/commands/verify-operations-command-action.js +2 -2
- package/lib/commands/verify-operations-step-plan.js +79 -41
- package/lib/commands/verify-operations-steps.js +2 -2
- package/lib/commands/verify-trust-command-action.js +1 -1
- package/lib/commands/wizard-core.js +1 -1
- package/lib/commands/wizard-headless.js +2 -1
- package/lib/core/admin-secrets.js +2 -6
- package/lib/core/audit-logger.js +1 -1
- package/lib/core/secrets-env-content.js +10 -4
- package/lib/core/secrets-env-write.js +2 -13
- package/lib/core/secrets-load.js +1 -3
- package/lib/datasource/agent-trust-run.js +3 -3
- package/lib/datasource/capability/relate-operations.js +1 -1
- package/lib/datasource/deploy.js +3 -1
- package/lib/datasource/test-e2e.js +6 -1
- package/lib/datasource/unified-validation-run-body.js +4 -1
- package/lib/datasource/unified-validation-run.js +1 -1
- package/lib/deployment/deploy-poll-ui.js +73 -12
- package/lib/deployment/deployer-poll-run.js +113 -0
- package/lib/deployment/deployer.js +17 -87
- package/lib/evidence/dataplane-context.js +21 -0
- package/lib/evidence/evidence-display.js +78 -0
- package/lib/evidence/evidence-service.js +392 -0
- package/lib/external-system/deploy.js +290 -112
- package/lib/external-system/download.js +7 -3
- package/lib/external-system/test-execution.js +1 -1
- package/lib/external-system/test-system-level.js +8 -10
- package/lib/external-system/test.js +12 -6
- package/lib/generator/deploy-script.js +73 -0
- package/lib/generator/external.js +2 -1
- package/lib/generator/helpers.js +13 -5
- package/lib/generator/index.js +17 -2
- package/lib/generator/split-variables.js +9 -3
- package/lib/generator/wizard.js +3 -36
- package/lib/infrastructure/helpers-docker-check.js +6 -0
- package/lib/infrastructure/helpers.js +1 -1
- package/lib/internal/fs-real-sync.js +22 -1
- package/lib/internal/node-fs.js +2 -0
- package/lib/lifecycle/lifecycle-governance-options.js +1 -1
- package/lib/lifecycle/verify-step-progress.js +1 -1
- package/lib/programmatic/access-log.js +26 -0
- package/lib/programmatic/auth-config.js +45 -0
- package/lib/programmatic/bearer-auth.js +176 -0
- package/lib/programmatic/builder-api-request.js +175 -0
- package/lib/programmatic/builder-api-route-dispatch.js +82 -0
- package/lib/programmatic/builder-api-runtime-config.js +42 -0
- package/lib/programmatic/builder-api-server.js +230 -0
- package/lib/programmatic/builder-help-authentication-catalog.js +282 -0
- package/lib/programmatic/builder-help-connected-system-ui.js +266 -0
- package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +60 -0
- package/lib/programmatic/builder-help-envelope.js +36 -0
- package/lib/programmatic/builder-help-fixtures.js +200 -0
- package/lib/programmatic/builder-help-governance.js +172 -0
- package/lib/programmatic/builder-help-schema-catalog.js +92 -0
- package/lib/programmatic/builder-help.js +361 -0
- package/lib/programmatic/capability-registry.js +77 -0
- package/lib/programmatic/command-options.js +32 -0
- package/lib/programmatic/enterprise-mcp-client.js +114 -0
- package/lib/programmatic/http-problem-details.js +99 -0
- package/lib/programmatic/http-route-match.js +40 -0
- package/lib/programmatic/idempotency-cache.js +69 -0
- package/lib/programmatic/index.js +53 -0
- package/lib/programmatic/integration-path-scope.js +39 -0
- package/lib/programmatic/log-redaction.js +66 -0
- package/lib/programmatic/manifest-get-section.js +146 -0
- package/lib/programmatic/manifest-patch-section.js +252 -0
- package/lib/programmatic/manifest-repair.js +122 -0
- package/lib/programmatic/manifest-section-dependency-graph.js +160 -0
- package/lib/programmatic/manifest-section-io.js +225 -0
- package/lib/programmatic/manifest-section-quality.js +171 -0
- package/lib/programmatic/manifest-section-registry-data.js +269 -0
- package/lib/programmatic/manifest-section-registry.js +222 -0
- package/lib/programmatic/nest-http-bridge.js +34 -0
- package/lib/programmatic/openapi-component-schemas.js +68 -0
- package/lib/programmatic/openapi-description-enricher.js +117 -0
- package/lib/programmatic/openapi-descriptions.js +190 -0
- package/lib/programmatic/openapi-docs-serving.js +123 -0
- package/lib/programmatic/openapi-help-schemas.js +63 -0
- package/lib/programmatic/openapi-manifest-schemas.js +141 -0
- package/lib/programmatic/openapi-operation-bindings.js +274 -0
- package/lib/programmatic/openapi-request-schemas.js +155 -0
- package/lib/programmatic/openapi-result-schemas.js +493 -0
- package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +162 -0
- package/lib/programmatic/openapi-schema-descriptions-help.js +40 -0
- package/lib/programmatic/openapi-schema-descriptions-manifest.js +143 -0
- package/lib/programmatic/openapi-schema-descriptions-mcp.js +118 -0
- package/lib/programmatic/openapi-schema-descriptions-operations.js +281 -0
- package/lib/programmatic/openapi-schema-helpers.js +108 -0
- package/lib/programmatic/openapi-spec.js +203 -0
- package/lib/programmatic/orchestration-openapi-meta.js +159 -0
- package/lib/programmatic/platform-rbac-catalog.js +90 -0
- package/lib/programmatic/request-timeout.js +53 -0
- package/lib/programmatic/route-handler-map.js +143 -0
- package/lib/programmatic/route-handlers-context.js +29 -0
- package/lib/programmatic/route-handlers.js +33 -0
- package/lib/programmatic/run-certify.js +57 -0
- package/lib/programmatic/run-enterprise-mcp.js +32 -0
- package/lib/programmatic/run-lifecycle.js +29 -0
- package/lib/programmatic/run-repair.js +41 -0
- package/lib/programmatic/run-repository-emcp.js +62 -0
- package/lib/programmatic/run-template-workspace.js +74 -0
- package/lib/programmatic/run-test.js +49 -0
- package/lib/programmatic/run-upload.js +63 -0
- package/lib/programmatic/run-validate.js +53 -0
- package/lib/programmatic/run-wizard.js +40 -0
- package/lib/programmatic/system-key.js +48 -0
- package/lib/programmatic/wizard-config-normalize.js +118 -0
- package/lib/programmatic/workspace-cleanup.js +128 -0
- package/lib/programmatic/workspace-context.js +145 -0
- package/lib/programmatic/workspace-lock.js +75 -0
- package/lib/programmatic/workspace-meta.js +64 -0
- package/lib/programmatic/workspace-ops.js +149 -0
- package/lib/protection/run-commands-upload-sync.js +35 -0
- package/lib/protection/run-commands.js +2 -20
- package/lib/protection/upload-batch.js +11 -7
- package/lib/resolvers/evidence-kind-file.js +230 -0
- package/lib/resolvers/resource-type-file.js +58 -1
- package/lib/resolvers/role-file.js +227 -0
- package/lib/schema/application-schema.json +22 -2
- package/lib/schema/external-datasource.schema.json +245 -2
- package/lib/schema/external-system.schema.json +259 -119
- package/lib/schema/flag-map-validation-run.json +3 -0
- package/lib/schema/infra.parameter.yaml +25 -1
- package/lib/schema/type/credential-field-registry.json +21 -5
- package/lib/schema/type/document-storage.json +9 -0
- package/lib/utils/agent-trust-run-display.js +1 -1
- package/lib/utils/api.js +8 -2
- package/lib/utils/app-path-resolve.js +168 -0
- package/lib/utils/app-register-config.js +4 -3
- package/lib/utils/authentication-env-template.js +222 -0
- package/lib/utils/cli-sync-options.js +62 -10
- package/lib/utils/cli-utils.js +15 -3
- package/lib/utils/cli-workspace-options.js +29 -0
- package/lib/utils/compose-generate-docker-compose.js +102 -0
- package/lib/utils/configuration-env-resolver.js +203 -27
- package/lib/utils/datasource-test-run-certificate-tty.js +28 -2
- package/lib/utils/datasource-test-run-certification-debug.js +130 -0
- package/lib/utils/datasource-test-run-debug-display.js +2 -0
- package/lib/utils/datasource-test-run-debug-slice.js +7 -0
- package/lib/utils/datasource-test-run-display.js +2 -1
- package/lib/utils/dev-ca-install.js +5 -6
- package/lib/utils/dev-config.js +2 -2
- package/lib/utils/dev-init-ssh-merge.js +165 -23
- package/lib/utils/dev-list-sort.js +145 -0
- package/lib/utils/dev-pin-share-instructions.js +110 -0
- package/lib/utils/dev-platform-tls.js +0 -63
- package/lib/utils/dev-ssh-config-helper.js +177 -33
- package/lib/utils/docker-build.js +46 -27
- package/lib/utils/docker-daemon-tls-ca.js +1 -1
- package/lib/utils/docker-exec.js +91 -6
- package/lib/utils/enterprise-knowledge-paths.js +142 -0
- package/lib/utils/env-copy.js +3 -4
- package/lib/utils/env-dotenv-format.js +103 -0
- package/lib/utils/error-formatters/error-parser.js +0 -3
- package/lib/utils/external-env-template.js +5 -2
- package/lib/utils/external-system-display.js +5 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +248 -0
- package/lib/utils/external-system-readiness-compact-display.js +324 -0
- package/lib/utils/external-system-readiness-core.js +16 -0
- package/lib/utils/external-system-readiness-deploy-display.js +29 -11
- package/lib/utils/external-system-readiness-display-internals.js +3 -1
- package/lib/utils/external-system-readiness-display.js +20 -30
- package/lib/utils/external-system-system-test-tty-certification.js +135 -0
- package/lib/utils/external-system-system-test-tty.js +5 -41
- package/lib/utils/health-check-request.js +2 -3
- package/lib/utils/help-builder.js +9 -1
- package/lib/utils/host-ops-job-labels.js +236 -0
- package/lib/utils/host-ops-job-result.js +61 -0
- package/lib/utils/host-ops-poll-ui.js +163 -0
- package/lib/utils/image-name.js +22 -4
- package/lib/utils/integration-path-resolve.js +112 -0
- package/lib/utils/logger.js +37 -4
- package/lib/utils/manifest-source-emit.js +1 -1
- package/lib/utils/paths-reload-source.js +148 -0
- package/lib/utils/paths-system-builder-keys.js +25 -0
- package/lib/utils/paths.js +183 -30
- package/lib/utils/pipeline-upload-auth-retry.js +4 -0
- package/lib/utils/postgres-platform-bootstrap.js +24 -17
- package/lib/utils/postgres-wipe.js +5 -2
- package/lib/utils/remote-dev-auth.js +39 -4
- package/lib/utils/resolve-docker-image-ref.js +36 -6
- package/lib/utils/runtime-configuration-values.js +64 -2
- package/lib/utils/secrets-helpers.js +5 -1
- package/lib/utils/ssh-known-hosts.js +130 -0
- package/lib/utils/test-target-cli-options.js +75 -0
- package/lib/utils/token-manager.js +16 -0
- package/lib/utils/upload-sync-options.js +20 -2
- package/lib/utils/validation-run-request.js +11 -2
- package/lib/validation/external-manifest-validator.js +11 -1
- package/lib/validation/openapi-contract-surface-validator.js +430 -0
- package/lib/validation/openapi-contract-vendor-validation.js +238 -0
- package/lib/validation/validate-external-file.js +160 -0
- package/lib/validation/validate.js +6 -117
- package/lib/validation/validator.js +6 -5
- package/package.json +76 -37
- package/packages/builder-api/README.md +120 -0
- package/packages/builder-api/package.json +30 -0
- package/packages/builder-api/src/app.module.ts +7 -0
- package/packages/builder-api/src/auth/auth.module.ts +5 -0
- package/packages/builder-api/src/external-system/external-system.module.ts +5 -0
- package/packages/builder-api/src/main.ts +16 -0
- package/packages/builder-api/tsconfig.json +15 -0
- package/scripts/check-builder-api-architecture-grep.js +79 -0
- package/scripts/docker_image_content_gate.js +47 -0
- package/scripts/docker_image_content_gate.sh +5 -0
- package/scripts/export-builder-api-evidence.js +262 -0
- package/scripts/lib/builder-api-docker-staging-copy.js +60 -0
- package/scripts/lib/builder-api-docker-staging-core.js +183 -0
- package/scripts/lib/docker-image-content-gate-core.js +166 -0
- package/scripts/lib/plan-actor.js +109 -0
- package/scripts/lib/plan-config.js +20 -0
- package/scripts/lib/plan-gates.js +154 -0
- package/scripts/lib/plan-meta.js +104 -0
- package/scripts/lib/plan-parse.js +162 -0
- package/scripts/lib/plan-prevalidate-gates.js +337 -0
- package/scripts/lib/plan-run-core.js +125 -0
- package/scripts/lib/plan-run-report.js +119 -0
- package/scripts/plan-approve.js +24 -0
- package/scripts/plan-archive.js +49 -0
- package/scripts/plan-run.js +13 -0
- package/scripts/plan-set-actor.js +21 -0
- package/scripts/plan-validate.js +80 -0
- package/scripts/pnpm/af.mjs +110 -0
- package/scripts/pnpm/check-quiet.mjs +32 -0
- package/scripts/pnpm/dev-install.mjs +29 -0
- package/scripts/pnpm/dev-reload.mjs +18 -0
- package/scripts/pnpm/help.mjs +55 -0
- package/scripts/pnpm/lib/dev-reload-core.mjs +189 -0
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +67 -0
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +32 -0
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +124 -0
- package/scripts/pnpm/lib/resolve-app-url.mjs +183 -0
- package/scripts/pnpm/lib/spinner.mjs +42 -0
- package/scripts/stage_builder_api_for_docker.js +65 -0
- package/scripts/sync-builder-api-template.js +44 -0
- package/templates/README.md +3 -0
- package/templates/applications/builder-api/Dockerfile +38 -0
- package/templates/applications/builder-api/application.yaml +75 -0
- package/templates/applications/builder-api/env.template +48 -0
- package/templates/applications/dataplane/application.yaml +27 -5
- package/templates/applications/dataplane/env.template +38 -15
- package/templates/applications/dataplane/rbac.yaml +85 -3
- package/templates/applications/miso-controller/application.yaml +10 -1
- package/templates/applications/miso-controller/env.template +11 -10
- package/templates/applications/miso-controller/rbac.yaml +72 -0
- package/templates/channels/README.md +18 -0
- package/templates/channels/ai-fabrix-icon.jpg +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +21 -24
- package/templates/channels/chatgpt/integration/README.md +11 -0
- package/templates/channels/chatgpt/integration/application.json +15 -0
- package/templates/channels/chatgpt/integration/chatgpt-system.json +29 -0
- package/templates/channels/chatgpt/integration/env.template +4 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +20 -25
- package/templates/channels/microsoft-copilot/integration/README.md +11 -0
- package/templates/channels/microsoft-copilot/integration/application.json +15 -0
- package/templates/channels/microsoft-copilot/integration/env.template +6 -0
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +34 -0
- package/templates/channels/slack/install.template.md.hbs +48 -18
- package/templates/channels/slack/integration/README.md +38 -0
- package/templates/channels/slack/integration/application.json +18 -0
- package/templates/channels/slack/integration/env.template +29 -0
- package/templates/channels/slack/integration/slack-datasource-conversations.json +226 -0
- package/templates/channels/slack/integration/slack-datasource-messages.json +269 -0
- package/templates/channels/slack/integration/slack-system.json +144 -0
- package/templates/channels/slack/manifest.template.json.hbs +20 -10
- package/templates/channels/teams-bot/install.template.md.hbs +31 -17
- package/templates/channels/teams-bot/integration/README.md +18 -0
- package/templates/channels/teams-bot/integration/application.json +17 -0
- package/templates/channels/teams-bot/integration/env.template +5 -0
- package/templates/channels/teams-bot/integration/teams-bot-system.json +55 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +27 -0
- package/templates/channels/web-embed/install.template.md.hbs +16 -26
- package/templates/channels/web-embed/integration/README.md +11 -0
- package/templates/channels/web-embed/integration/application.json +15 -0
- package/templates/channels/web-embed/integration/env.template +4 -0
- package/templates/channels/web-embed/integration/web-embed-system.json +29 -0
- package/templates/openapi/redoc_page.html +86 -0
- package/templates/python/docker-compose.hbs +11 -0
- package/templates/python/requirements.txt +2 -2
- package/templates/typescript/docker-compose.hbs +11 -0
- 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
|
+
};
|