@aifabrix/builder 2.49.2 → 2.50.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/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/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.api.js +172 -0
- package/lib/api/external-systems.api.js +8 -2
- package/lib/api/resource-types.api.js +1 -0
- package/lib/api/types/enterprise-knowledge.types.js +46 -0
- package/lib/api/types/evidence.types.js +67 -0
- package/lib/api/types/resource-types.types.js +2 -0
- 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 +37 -88
- 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/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 +16 -4
- 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 +27 -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 +38 -125
- 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 +7 -2
- 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-repair.js +26 -7
- 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 +163 -0
- package/lib/commands/deploy-gate-orchestrator.js +322 -0
- package/lib/commands/dev-cli-handlers.js +1 -59
- 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 +3 -1
- package/lib/commands/enterprise-knowledge.js +284 -0
- package/lib/commands/evidence-cli-leaves.js +250 -0
- package/lib/commands/evidence.js +51 -0
- package/lib/commands/governance-cli-shared.js +2 -2
- package/lib/commands/governance-command-action.js +2 -2
- 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 +19 -2
- 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 +65 -26
- package/lib/commands/run-post-publish-data-sync.js +68 -0
- package/lib/commands/setup-modes.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/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 +2 -2
- 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/secrets-env-content.js +10 -4
- package/lib/core/secrets-env-write.js +2 -13
- package/lib/datasource/agent-trust-run.js +3 -3
- 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/index.js +17 -2
- package/lib/generator/wizard.js +3 -36
- 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 +44 -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 +98 -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 +205 -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 +476 -0
- package/lib/programmatic/openapi-schema-descriptions-certify.js +139 -0
- package/lib/programmatic/openapi-schema-descriptions-core.js +159 -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 +93 -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 +54 -0
- package/lib/programmatic/run-template-workspace.js +61 -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/resource-type-file.js +22 -0
- package/lib/schema/external-datasource.schema.json +161 -1
- package/lib/schema/external-system.schema.json +244 -118
- package/lib/schema/flag-map-validation-run.json +3 -0
- package/lib/schema/type/credential-field-registry.json +2 -2
- package/lib/schema/type/document-storage.json +9 -0
- package/lib/utils/agent-trust-run-display.js +1 -1
- package/lib/utils/app-path-resolve.js +168 -0
- package/lib/utils/authentication-env-template.js +222 -0
- package/lib/utils/cli-sync-options.js +7 -11
- package/lib/utils/cli-utils.js +4 -0
- 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-init-ssh-merge.js +165 -23
- package/lib/utils/dev-pin-share-instructions.js +110 -0
- package/lib/utils/dev-ssh-config-helper.js +177 -33
- package/lib/utils/enterprise-knowledge-paths.js +142 -0
- package/lib/utils/env-copy.js +2 -1
- package/lib/utils/env-dotenv-format.js +103 -0
- package/lib/utils/external-env-template.js +4 -1
- package/lib/utils/external-system-display.js +5 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +221 -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/help-builder.js +6 -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/integration-path-resolve.js +112 -0
- package/lib/utils/paths-reload-source.js +148 -0
- package/lib/utils/paths-system-builder-keys.js +25 -0
- package/lib/utils/paths.js +151 -26
- 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/upload-sync-options.js +4 -0
- 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 +426 -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/package.json +46 -29
- 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 +326 -0
- package/scripts/lib/plan-run-core.js +125 -0
- package/scripts/lib/plan-run-report.js +108 -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 +1 -1
- package/templates/applications/dataplane/env.template +10 -6
- package/templates/applications/dataplane/rbac.yaml +21 -1
- package/templates/applications/miso-controller/application.yaml +1 -1
- package/templates/applications/miso-controller/env.template +1 -3
- 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 +86 -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 +1 -1
- package/templates/typescript/docker-compose.hbs +11 -0
- package/lib/certification/cli-cert-sync-skip.js +0 -21
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate integration deploy.js from Handlebars template.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview ESLint-clean deploy script for external integrations
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('../internal/fs-real-sync');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const Handlebars = require('handlebars');
|
|
14
|
+
|
|
15
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
16
|
+
const logger = require('../utils/logger');
|
|
17
|
+
|
|
18
|
+
const templatesExternalDir = path.join(__dirname, '..', '..', 'templates', 'external-system');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {string} templateName
|
|
22
|
+
* @param {string} outputPath
|
|
23
|
+
* @param {Object} context
|
|
24
|
+
*/
|
|
25
|
+
async function writeDeployScriptFromTemplate(templateName, outputPath, context) {
|
|
26
|
+
const templatePath = path.join(templatesExternalDir, templateName);
|
|
27
|
+
const content = Handlebars.compile(fs.readFileSync(templatePath, 'utf8'))(context);
|
|
28
|
+
fs.writeFileSync(outputPath, content, { mode: 0o644, encoding: 'utf8' });
|
|
29
|
+
logger.log(formatSuccessLine(`Generated ${path.basename(outputPath)}`));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} appPath
|
|
34
|
+
* @param {string} systemKey
|
|
35
|
+
* @param {string} systemFileName
|
|
36
|
+
* @param {string[]} datasourceFileNames
|
|
37
|
+
* @returns {Promise<{ deployJsPath: string }>}
|
|
38
|
+
*/
|
|
39
|
+
async function generateDeployScripts(appPath, systemKey, systemFileName, datasourceFileNames) {
|
|
40
|
+
try {
|
|
41
|
+
const allJsonFiles = [systemFileName, ...datasourceFileNames];
|
|
42
|
+
const context = { systemKey, allJsonFiles, datasourceFileNames };
|
|
43
|
+
const deployJsPath = path.join(appPath, 'deploy.js');
|
|
44
|
+
await writeDeployScriptFromTemplate('deploy.js.hbs', deployJsPath, context);
|
|
45
|
+
return { deployJsPath };
|
|
46
|
+
} catch (error) {
|
|
47
|
+
throw new Error(`Failed to generate deployment scripts: ${error.message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Regenerate deploy.js from integration manifest file lists.
|
|
53
|
+
*
|
|
54
|
+
* @param {Object} params
|
|
55
|
+
* @param {string} params.appPath
|
|
56
|
+
* @param {string} params.systemKey
|
|
57
|
+
* @param {string[]} params.systemFiles
|
|
58
|
+
* @param {string[]} params.datasourceFiles
|
|
59
|
+
* @returns {Promise<{ deployJsPath: string }>}
|
|
60
|
+
*/
|
|
61
|
+
async function regenerateDeployScriptFromIntegration(params) {
|
|
62
|
+
const { appPath, systemKey, systemFiles, datasourceFiles } = params;
|
|
63
|
+
if (!systemFiles?.length) {
|
|
64
|
+
throw new Error('externalIntegration.systems is empty — cannot generate deploy.js');
|
|
65
|
+
}
|
|
66
|
+
return generateDeployScripts(appPath, systemKey, systemFiles[0], datasourceFiles || []);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
writeDeployScriptFromTemplate,
|
|
71
|
+
generateDeployScripts,
|
|
72
|
+
regenerateDeployScriptFromIntegration
|
|
73
|
+
};
|
package/lib/generator/index.js
CHANGED
|
@@ -302,7 +302,22 @@ async function generateDeployJson(appName, options = {}) {
|
|
|
302
302
|
if (!appName || typeof appName !== 'string') {
|
|
303
303
|
throw new Error('App name is required and must be a string');
|
|
304
304
|
}
|
|
305
|
-
|
|
305
|
+
let appPath;
|
|
306
|
+
let isExternal;
|
|
307
|
+
let appType;
|
|
308
|
+
if (options.appPath) {
|
|
309
|
+
appPath = path.resolve(options.appPath);
|
|
310
|
+
const configPath = resolveApplicationConfigPath(appPath);
|
|
311
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
312
|
+
const variables = loadConfigFile(configPath);
|
|
313
|
+
appType = variables?.app?.type || 'external';
|
|
314
|
+
isExternal = appType === 'external';
|
|
315
|
+
} else {
|
|
316
|
+
const detected = await detectAppType(appName, options);
|
|
317
|
+
appPath = detected.appPath;
|
|
318
|
+
isExternal = detected.isExternal;
|
|
319
|
+
appType = detected.appType;
|
|
320
|
+
}
|
|
306
321
|
logOfflinePathWhenType(appPath);
|
|
307
322
|
if (isExternal) {
|
|
308
323
|
return writeExternalDeployJson(appName, appPath, options);
|
|
@@ -315,7 +330,7 @@ async function generateDeployJsonWithValidation(appName, options = {}) {
|
|
|
315
330
|
const jsonContent = fs.readFileSync(jsonPath, 'utf8');
|
|
316
331
|
const deployment = JSON.parse(jsonContent);
|
|
317
332
|
|
|
318
|
-
const { isExternal } = await detectAppType(appName);
|
|
333
|
+
const { isExternal } = await detectAppType(appName, options);
|
|
319
334
|
|
|
320
335
|
// For external systems, skip deployment JSON validation (they use external system JSON structure)
|
|
321
336
|
if (isExternal) {
|
package/lib/generator/wizard.js
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
12
12
|
const fs = require('fs').promises;
|
|
13
13
|
const path = require('path');
|
|
14
|
-
const Handlebars = require('handlebars');
|
|
15
14
|
const logger = require('../utils/logger');
|
|
16
15
|
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
17
16
|
const { loadConfigFile, writeConfigFile } = require('../utils/config-format');
|
|
@@ -178,7 +177,8 @@ async function generateConfigFilesForWizard(params) {
|
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
async function prepareWizardContext(appName, systemConfig, datasourceConfigs) {
|
|
181
|
-
const
|
|
180
|
+
const { getIntegrationPath } = require('../utils/paths');
|
|
181
|
+
const appPath = getIntegrationPath(appName);
|
|
182
182
|
await fs.mkdir(appPath, { recursive: true });
|
|
183
183
|
const finalSystemKey = appName;
|
|
184
184
|
const originalSystemKey = systemConfig.key || finalSystemKey;
|
|
@@ -430,40 +430,7 @@ async function _generateEnvTemplate(appPath, systemConfig, finalSystemKey) {
|
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
-
|
|
434
|
-
* Generate deployment script (deploy.js) from template
|
|
435
|
-
* @async
|
|
436
|
-
* @function generateDeployScripts
|
|
437
|
-
* @param {string} appPath - Application directory path
|
|
438
|
-
* @param {string} systemKey - System key
|
|
439
|
-
* @param {string} systemFileName - System file name
|
|
440
|
-
* @param {string[]} datasourceFileNames - Array of datasource file names
|
|
441
|
-
* @returns {Promise<Object>} Object with deployJsPath
|
|
442
|
-
* @throws {Error} If generation fails
|
|
443
|
-
*/
|
|
444
|
-
const templatesExternalDir = path.join(__dirname, '..', '..', 'templates', 'external-system');
|
|
445
|
-
|
|
446
|
-
async function writeDeployScriptFromTemplate(templateName, outputPath, context) {
|
|
447
|
-
const templatePath = path.join(templatesExternalDir, templateName);
|
|
448
|
-
const content = Handlebars.compile(await fs.readFile(templatePath, 'utf8'))(context);
|
|
449
|
-
await fs.writeFile(outputPath, content, 'utf8');
|
|
450
|
-
logger.log(formatSuccessLine(`Generated ${path.basename(outputPath)}`));
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
async function generateDeployScripts(appPath, systemKey, systemFileName, datasourceFileNames) {
|
|
454
|
-
try {
|
|
455
|
-
const allJsonFiles = [systemFileName, ...datasourceFileNames];
|
|
456
|
-
const context = { systemKey, allJsonFiles, datasourceFileNames };
|
|
457
|
-
|
|
458
|
-
await writeDeployScriptFromTemplate('deploy.js.hbs', path.join(appPath, 'deploy.js'), context);
|
|
459
|
-
|
|
460
|
-
return {
|
|
461
|
-
deployJsPath: path.join(appPath, 'deploy.js')
|
|
462
|
-
};
|
|
463
|
-
} catch (error) {
|
|
464
|
-
throw new Error(`Failed to generate deployment scripts: ${error.message}`);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
433
|
+
const { generateDeployScripts } = require('./deploy-script');
|
|
467
434
|
|
|
468
435
|
module.exports = {
|
|
469
436
|
generateWizardFiles,
|
|
@@ -118,6 +118,25 @@ function unlinkSync(p) {
|
|
|
118
118
|
return delegate('unlinkSync', [p]);
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* @param {string} src
|
|
123
|
+
* @param {string} dest
|
|
124
|
+
* @returns {void}
|
|
125
|
+
*/
|
|
126
|
+
function copyFileSync(src, dest) {
|
|
127
|
+
return delegate('copyFileSync', [src, dest]);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {string} p
|
|
132
|
+
* @param {string|Buffer} data
|
|
133
|
+
* @param {object|string} [opts]
|
|
134
|
+
* @returns {void}
|
|
135
|
+
*/
|
|
136
|
+
function appendFileSync(p, data, opts) {
|
|
137
|
+
return delegate('appendFileSync', opts !== undefined ? [p, data, opts] : [p, data]);
|
|
138
|
+
}
|
|
139
|
+
|
|
121
140
|
module.exports = {
|
|
122
141
|
existsSync,
|
|
123
142
|
readFileSync,
|
|
@@ -128,5 +147,7 @@ module.exports = {
|
|
|
128
147
|
readdirSync,
|
|
129
148
|
mkdtempSync,
|
|
130
149
|
rmSync,
|
|
131
|
-
unlinkSync
|
|
150
|
+
unlinkSync,
|
|
151
|
+
copyFileSync,
|
|
152
|
+
appendFileSync
|
|
132
153
|
};
|
package/lib/internal/node-fs.js
CHANGED
|
@@ -73,6 +73,7 @@ function buildBoundFs() {
|
|
|
73
73
|
readdirSync: snap.readdirSync,
|
|
74
74
|
statSync: snap.statSync,
|
|
75
75
|
renameSync: snap.renameSync,
|
|
76
|
+
copyFileSync: snap.copyFileSync,
|
|
76
77
|
watch: (...args) => live.watch(...args),
|
|
77
78
|
promises: boundPromises
|
|
78
79
|
};
|
|
@@ -85,6 +86,7 @@ function buildBoundFs() {
|
|
|
85
86
|
readdirSync: bindSync(rf, 'readdirSync'),
|
|
86
87
|
statSync: bindSync(rf, 'statSync'),
|
|
87
88
|
renameSync: bindSync(rf, 'renameSync'),
|
|
89
|
+
copyFileSync: bindSync(rf, 'copyFileSync'),
|
|
88
90
|
watch: (...args) => live.watch(...args),
|
|
89
91
|
promises: boundPromises
|
|
90
92
|
};
|
|
@@ -34,7 +34,7 @@ function buildGovernanceOptsFromLifecycle(options, context = {}) {
|
|
|
34
34
|
env: options.env || 'dev',
|
|
35
35
|
verbose: options.verbose === true,
|
|
36
36
|
debug: options.debug === true,
|
|
37
|
-
|
|
37
|
+
noPublish: true,
|
|
38
38
|
force: options.force === true,
|
|
39
39
|
certificationProfile: options.certificationProfile || 'bronze',
|
|
40
40
|
subjectEmails: options.subjectEmail || options.subjectEmails || [],
|
|
@@ -53,7 +53,7 @@ function formatVerifyStepLabel(label) {
|
|
|
53
53
|
* @returns {Promise<T>}
|
|
54
54
|
*/
|
|
55
55
|
async function runWithVerifyStepProgress(label, work, options = {}) {
|
|
56
|
-
if (!shouldShowVerifyStepProgress(options)) {
|
|
56
|
+
if (options.quietProgress === true || !shouldShowVerifyStepProgress(options)) {
|
|
57
57
|
return withQuietLogs(() => work({ setLabel: () => {} }));
|
|
58
58
|
}
|
|
59
59
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured access logging for builder-api requests.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview JSON logs without tokens or manifest bodies
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { redactForLog } = require('./log-redaction');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object} entry
|
|
15
|
+
*/
|
|
16
|
+
function writeAccessLog(entry) {
|
|
17
|
+
const payload = redactForLog({
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
...entry
|
|
20
|
+
});
|
|
21
|
+
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
writeAccessLog
|
|
26
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bearer auth config for programmatic Dataplane calls.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Build authConfig from user Bearer token (no device token store)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} bearerToken
|
|
13
|
+
* @returns {{ type: 'bearer', token: string }}
|
|
14
|
+
*/
|
|
15
|
+
function buildBearerAuthConfig(bearerToken) {
|
|
16
|
+
if (!bearerToken || typeof bearerToken !== 'string') {
|
|
17
|
+
throw new Error('Bearer token is required');
|
|
18
|
+
}
|
|
19
|
+
const token = bearerToken.startsWith('Bearer ') ? bearerToken.slice(7).trim() : bearerToken.trim();
|
|
20
|
+
if (!token) {
|
|
21
|
+
throw new Error('Bearer token is required');
|
|
22
|
+
}
|
|
23
|
+
return { type: 'bearer', token };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('./workspace-context').WorkspaceContext} ctx
|
|
28
|
+
* @returns {{ authConfig: Object, dataplaneUrl: string, environment: string }}
|
|
29
|
+
*/
|
|
30
|
+
function buildProgrammaticAuthContext(ctx) {
|
|
31
|
+
if (!ctx.dataplaneUrl) {
|
|
32
|
+
throw new Error('dataplaneUrl is required on WorkspaceContext');
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
authConfig: buildBearerAuthConfig(ctx.bearerToken),
|
|
36
|
+
dataplaneUrl: ctx.dataplaneUrl,
|
|
37
|
+
environment: ctx.environment
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
buildBearerAuthConfig,
|
|
43
|
+
buildProgrammaticAuthContext
|
|
44
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bearer token validation for builder-api via @aifabrix/miso-client (controller-backed).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Same model as dataplane: registered app client + MISO_CONTROLLER_URL
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
/** @type {import('@aifabrix/miso-client').MisoClient | null} */
|
|
12
|
+
let misoClientSingleton = null;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {import('http').IncomingMessage} req
|
|
16
|
+
* @returns {string|null}
|
|
17
|
+
*/
|
|
18
|
+
function extractBearerToken(req) {
|
|
19
|
+
const auth = req.headers.authorization || req.headers.Authorization;
|
|
20
|
+
if (!auth || typeof auth !== 'string') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const match = auth.match(/^Bearer\s+(.+)$/i);
|
|
24
|
+
return match ? match[1].trim() : null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {import('http').IncomingMessage} req
|
|
29
|
+
*/
|
|
30
|
+
function assertNoForbiddenAuthHeaders(req) {
|
|
31
|
+
if (req.headers['x-client-token'] || req.headers['x-client-id']) {
|
|
32
|
+
const err = new Error('Client credential headers are not supported in builder-api V1');
|
|
33
|
+
err.statusCode = 401;
|
|
34
|
+
throw err;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @returns {string}
|
|
40
|
+
*/
|
|
41
|
+
function resolveControllerUrlFromEnv() {
|
|
42
|
+
const raw =
|
|
43
|
+
process.env.MISO_CONTROLLER_URL ||
|
|
44
|
+
process.env.CONTROLLER_URL ||
|
|
45
|
+
process.env.MISO_WEB_SERVER_URL ||
|
|
46
|
+
'';
|
|
47
|
+
const url = String(raw).trim().replace(/\/$/, '');
|
|
48
|
+
if (!url) {
|
|
49
|
+
throw new Error('MISO_CONTROLLER_URL (or CONTROLLER_URL) is required for token validation');
|
|
50
|
+
}
|
|
51
|
+
return url;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @returns {import('@aifabrix/miso-client/dist/types/config.types').MisoClientConfig}
|
|
56
|
+
*/
|
|
57
|
+
function buildMisoClientConfigFromEnv() {
|
|
58
|
+
const clientId = (process.env.MISO_CLIENTID || '').trim();
|
|
59
|
+
const clientSecret = (process.env.MISO_CLIENTSECRET || '').trim();
|
|
60
|
+
if (!clientId || !clientSecret) {
|
|
61
|
+
throw new Error('MISO_CLIENTID and MISO_CLIENTSECRET are required for builder-api auth');
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
clientId,
|
|
65
|
+
clientSecret,
|
|
66
|
+
controllerUrl: resolveControllerUrlFromEnv(),
|
|
67
|
+
logLevel: (process.env.LOG_LEVEL || 'info').toLowerCase()
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Test hook — reset cached MisoClient between Jest cases.
|
|
73
|
+
*/
|
|
74
|
+
function resetMisoClientForTests() {
|
|
75
|
+
misoClientSingleton = null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @returns {Promise<import('@aifabrix/miso-client').MisoClient>}
|
|
80
|
+
*/
|
|
81
|
+
async function getMisoClientForAuth() {
|
|
82
|
+
let MisoClient;
|
|
83
|
+
try {
|
|
84
|
+
({ MisoClient } = require('@aifabrix/miso-client'));
|
|
85
|
+
} catch {
|
|
86
|
+
const err = new Error('@aifabrix/miso-client is required for builder-api auth');
|
|
87
|
+
err.statusCode = 503;
|
|
88
|
+
throw err;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!misoClientSingleton) {
|
|
92
|
+
misoClientSingleton = new MisoClient(buildMisoClientConfigFromEnv());
|
|
93
|
+
}
|
|
94
|
+
if (!misoClientSingleton.isInitialized()) {
|
|
95
|
+
await misoClientSingleton.initialize();
|
|
96
|
+
}
|
|
97
|
+
return misoClientSingleton;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {import('@aifabrix/miso-client/dist/types/config.types').UserInfo} userInfo
|
|
102
|
+
* @returns {string}
|
|
103
|
+
*/
|
|
104
|
+
function userIdFromUserInfo(userInfo) {
|
|
105
|
+
const userId = userInfo?.id || userInfo?.username;
|
|
106
|
+
if (!userId) {
|
|
107
|
+
const err = new Error('Token validation returned no user id');
|
|
108
|
+
err.statusCode = 401;
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
return String(userId);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* @param {string} token
|
|
116
|
+
* @param {Object} [opts]
|
|
117
|
+
* @returns {Promise<{ userId: string, payload: Object }>}
|
|
118
|
+
*/
|
|
119
|
+
async function validateBearerToken(token, opts = {}) {
|
|
120
|
+
if (!token) {
|
|
121
|
+
const err = new Error('Missing Bearer token');
|
|
122
|
+
err.statusCode = 401;
|
|
123
|
+
throw err;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const client = opts.misoClient || (await getMisoClientForAuth());
|
|
127
|
+
const valid = await client.validateToken(token, opts.authStrategy);
|
|
128
|
+
if (!valid) {
|
|
129
|
+
const err = new Error('Invalid token');
|
|
130
|
+
err.statusCode = 401;
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const userInfo = await client.getUser(token, opts.authStrategy);
|
|
135
|
+
if (!userInfo) {
|
|
136
|
+
const err = new Error('Invalid token');
|
|
137
|
+
err.statusCode = 401;
|
|
138
|
+
throw err;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const payload = {
|
|
142
|
+
sub: userInfo.id,
|
|
143
|
+
preferredUsername: userInfo.username,
|
|
144
|
+
email: userInfo.email,
|
|
145
|
+
roles: userInfo.roles || []
|
|
146
|
+
};
|
|
147
|
+
return { userId: userIdFromUserInfo(userInfo), payload };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param {import('http').IncomingMessage} req
|
|
152
|
+
* @param {Object} [opts]
|
|
153
|
+
* @returns {Promise<{ userId: string, bearerToken: string, payload: Object }>}
|
|
154
|
+
*/
|
|
155
|
+
async function authenticateRequest(req, opts = {}) {
|
|
156
|
+
assertNoForbiddenAuthHeaders(req);
|
|
157
|
+
const bearerToken = extractBearerToken(req);
|
|
158
|
+
if (!bearerToken) {
|
|
159
|
+
const err = new Error('Authorization Bearer token required');
|
|
160
|
+
err.statusCode = 401;
|
|
161
|
+
throw err;
|
|
162
|
+
}
|
|
163
|
+
const { userId, payload } = await validateBearerToken(bearerToken, opts);
|
|
164
|
+
return { userId, bearerToken, payload };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = {
|
|
168
|
+
extractBearerToken,
|
|
169
|
+
assertNoForbiddenAuthHeaders,
|
|
170
|
+
resolveControllerUrlFromEnv,
|
|
171
|
+
buildMisoClientConfigFromEnv,
|
|
172
|
+
resetMisoClientForTests,
|
|
173
|
+
getMisoClientForAuth,
|
|
174
|
+
validateBearerToken,
|
|
175
|
+
authenticateRequest
|
|
176
|
+
};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authenticated capability execution for builder-api HTTP server.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Idempotency, workspace lock, dispatch
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { authenticateRequest } = require('./bearer-auth');
|
|
12
|
+
const { dispatchHandler } = require('./route-handlers');
|
|
13
|
+
const { withWorkspaceLock } = require('./workspace-lock');
|
|
14
|
+
const { getIdempotentResult, setIdempotentResult } = require('./idempotency-cache');
|
|
15
|
+
const { withRequestTimeout } = require('./request-timeout');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {Object} capability
|
|
19
|
+
* @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
function requiresAuth(capability) {
|
|
22
|
+
return capability.handlerId !== 'health' && capability.handlerId !== 'ready';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {Object} capability
|
|
27
|
+
* @returns {boolean}
|
|
28
|
+
*/
|
|
29
|
+
function isMutating(capability) {
|
|
30
|
+
return capability.mutating === true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {Object} params
|
|
35
|
+
* @param {Object} body
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function resolveIdempotencySystemKey(params, body) {
|
|
39
|
+
return params.systemKey || body.systemKey || '_workspace';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @param {Object} options
|
|
44
|
+
* @param {Object} options.auth
|
|
45
|
+
* @param {string|undefined} options.idempotencyKey
|
|
46
|
+
* @param {Object} options.capability
|
|
47
|
+
* @param {string} options.routeKey
|
|
48
|
+
* @param {Object} options.params
|
|
49
|
+
* @param {Object} options.body
|
|
50
|
+
* @param {string} options.requestId
|
|
51
|
+
* @returns {{ httpStatus: number, body: Object, requestId: string }|null}
|
|
52
|
+
*/
|
|
53
|
+
function lookupIdempotentResponse(options) {
|
|
54
|
+
const { auth, idempotencyKey, capability, routeKey, params, body, requestId } = options;
|
|
55
|
+
if (!idempotencyKey || !isMutating(capability)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const cached = getIdempotentResult({
|
|
59
|
+
userId: auth.userId,
|
|
60
|
+
idempotencyKey: String(idempotencyKey),
|
|
61
|
+
route: routeKey,
|
|
62
|
+
systemKey: resolveIdempotencySystemKey(params, body)
|
|
63
|
+
});
|
|
64
|
+
if (!cached) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return { httpStatus: cached.httpStatus, body: cached.body, requestId: cached.correlationId || requestId };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {Object} auth
|
|
72
|
+
* @param {Object} capability
|
|
73
|
+
* @param {Object} params
|
|
74
|
+
* @param {Object} body
|
|
75
|
+
* @param {Object} query
|
|
76
|
+
* @returns {Promise<*>}
|
|
77
|
+
*/
|
|
78
|
+
async function runHandler(auth, capability, params, body, query) {
|
|
79
|
+
const run = () =>
|
|
80
|
+
withRequestTimeout(capability.handlerId, () =>
|
|
81
|
+
dispatchHandler(capability.handlerId, params, auth, body, query)
|
|
82
|
+
);
|
|
83
|
+
const lockKey = params.systemKey || body.systemKey;
|
|
84
|
+
if (isMutating(capability) && lockKey) {
|
|
85
|
+
return withWorkspaceLock(auth.userId, lockKey, run);
|
|
86
|
+
}
|
|
87
|
+
return run();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {Object} options
|
|
92
|
+
* @param {Object} options.auth
|
|
93
|
+
* @param {string|undefined} options.idempotencyKey
|
|
94
|
+
* @param {Object} options.capability
|
|
95
|
+
* @param {string} options.routeKey
|
|
96
|
+
* @param {Object} options.params
|
|
97
|
+
* @param {Object} options.body
|
|
98
|
+
* @param {string} options.requestId
|
|
99
|
+
* @param {Object} options.result
|
|
100
|
+
* @returns {{ httpStatus: number, body: Object, requestId: string, userId: string }}
|
|
101
|
+
*/
|
|
102
|
+
function buildSuccessResponse(options) {
|
|
103
|
+
const { auth, idempotencyKey, capability, routeKey, params, body, requestId, result } = options;
|
|
104
|
+
const responseBody = { success: true, data: result, correlationId: requestId };
|
|
105
|
+
if (idempotencyKey && isMutating(capability)) {
|
|
106
|
+
setIdempotentResult(
|
|
107
|
+
{
|
|
108
|
+
userId: auth.userId,
|
|
109
|
+
idempotencyKey: String(idempotencyKey),
|
|
110
|
+
route: routeKey,
|
|
111
|
+
systemKey: resolveIdempotencySystemKey(params, body)
|
|
112
|
+
},
|
|
113
|
+
{ httpStatus: 200, body: responseBody, correlationId: requestId }
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
return { httpStatus: 200, body: responseBody, requestId, userId: auth.userId };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @typedef {Object} ExecuteCapabilityRequestOptions
|
|
121
|
+
* @property {import('http').IncomingMessage} req
|
|
122
|
+
* @property {Object} capability
|
|
123
|
+
* @property {Object} params
|
|
124
|
+
* @property {string} routeKey
|
|
125
|
+
* @property {string} requestId
|
|
126
|
+
* @property {Function} readJsonBody
|
|
127
|
+
* @property {Object} query
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {ExecuteCapabilityRequestOptions} options
|
|
132
|
+
* @returns {Promise<{ httpStatus: number, body: Object, requestId: string }>}
|
|
133
|
+
*/
|
|
134
|
+
async function executeCapabilityRequest(options) {
|
|
135
|
+
const { req, capability, params, routeKey, requestId, readJsonBody, query } = options;
|
|
136
|
+
const auth = requiresAuth(capability)
|
|
137
|
+
? await authenticateRequest(req)
|
|
138
|
+
: { userId: 'anonymous', bearerToken: '' };
|
|
139
|
+
|
|
140
|
+
const body = req.method === 'GET' || req.method === 'DELETE' ? {} : await readJsonBody(req);
|
|
141
|
+
|
|
142
|
+
const cached = lookupIdempotentResponse({
|
|
143
|
+
auth,
|
|
144
|
+
idempotencyKey: req.headers['idempotency-key'],
|
|
145
|
+
capability,
|
|
146
|
+
routeKey,
|
|
147
|
+
params,
|
|
148
|
+
body,
|
|
149
|
+
requestId
|
|
150
|
+
});
|
|
151
|
+
if (cached) {
|
|
152
|
+
return { ...cached, userId: auth.userId };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const result = await runHandler(auth, capability, params, body, query);
|
|
156
|
+
return buildSuccessResponse({
|
|
157
|
+
auth,
|
|
158
|
+
idempotencyKey: req.headers['idempotency-key'],
|
|
159
|
+
capability,
|
|
160
|
+
routeKey,
|
|
161
|
+
params,
|
|
162
|
+
body,
|
|
163
|
+
requestId,
|
|
164
|
+
result
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
executeCapabilityRequest,
|
|
170
|
+
requiresAuth,
|
|
171
|
+
isMutating,
|
|
172
|
+
lookupIdempotentResponse,
|
|
173
|
+
buildSuccessResponse,
|
|
174
|
+
resolveIdempotencySystemKey
|
|
175
|
+
};
|