@aifabrix/builder 2.52.0 → 2.53.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/lib/api/datasources-extended.api.js +8 -8
- package/lib/api/keycloak.api.js +92 -0
- package/lib/api/token-providers.api.js +77 -0
- package/lib/api/types/keycloak.types.js +23 -0
- package/lib/api/types/token-providers.types.js +65 -0
- package/lib/app/deploy-config.js +3 -2
- package/lib/app/down.js +16 -1
- package/lib/channels/add-channel.js +134 -57
- package/lib/channels/approval-guides/chatgpt.js +1 -1
- package/lib/channels/approval-guides/index.js +3 -0
- package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
- package/lib/channels/channel-add-ensure.js +128 -0
- package/lib/channels/channel-add-existing.js +72 -0
- package/lib/channels/channel-artifact-generator.js +11 -1
- package/lib/channels/channel-branding.js +94 -0
- package/lib/channels/channel-credential.js +8 -0
- package/lib/channels/channel-discovery.js +330 -0
- package/lib/channels/channel-external-system.js +1 -1
- package/lib/channels/channel-runtime-resolver.js +107 -14
- package/lib/channels/channel-status-display.js +36 -3
- package/lib/channels/microsoft-copilot-channel-add.js +138 -0
- package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
- package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
- package/lib/channels/microsoft-copilot-icons.js +74 -0
- package/lib/channels/microsoft-copilot-limits.js +103 -0
- package/lib/channels/microsoft-copilot-package.js +178 -52
- package/lib/channels/microsoft-copilot-validate.js +227 -0
- package/lib/cli/attach-default-help-examples.js +102 -0
- package/lib/cli/index.js +4 -0
- package/lib/cli/infra-guided.js +13 -6
- package/lib/cli/setup-credential-deployment.js +7 -5
- package/lib/cli/setup-infra.js +31 -4
- package/lib/cli/setup-utility-validate.js +1 -0
- package/lib/commands/channel-add-setup.js +28 -9
- package/lib/commands/channel.js +14 -10
- package/lib/commands/credential-push.js +37 -5
- package/lib/commands/integration-definition.js +158 -0
- package/lib/commands/package-score.js +72 -0
- package/lib/commands/repair-auth-apply.js +19 -5
- package/lib/commands/repair-datasource-sync-operations.js +4 -1
- package/lib/commands/role-assistant-test-output.js +200 -0
- package/lib/commands/role-assistant.js +163 -166
- package/lib/datasource/capability/capability-resolve.js +15 -5
- package/lib/datasource/capability/copy-operations.js +14 -4
- package/lib/deployment/deployer-poll-run.js +2 -2
- package/lib/deployment/deployer.js +1 -1
- package/lib/deployment/environment.js +2 -2
- package/lib/external-system/deploy.js +11 -21
- package/lib/infrastructure/index.js +19 -4
- package/lib/integration-definition/apply.js +476 -0
- package/lib/integration-definition/canonical-json.js +51 -0
- package/lib/integration-definition/emit-suite-bid.js +94 -0
- package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
- package/lib/integration-definition/enrich-openapi-operations.js +433 -0
- package/lib/integration-definition/from-discovery.js +339 -0
- package/lib/integration-definition/hash.js +37 -0
- package/lib/integration-definition/index.js +37 -0
- package/lib/integration-definition/resource-type-catalog.js +59 -0
- package/lib/integration-definition/system-kind-enum.js +40 -0
- package/lib/integration-definition/validate.js +148 -0
- package/lib/lab/package-parity-score.js +417 -0
- package/lib/programmatic/builder-api-request.js +5 -1
- package/lib/programmatic/builder-help-governance.js +3 -2
- package/lib/programmatic/capability-registry.js +20 -0
- package/lib/programmatic/help-content/channel-onboarding.md +35 -0
- package/lib/programmatic/help-content/cip-overview.md +27 -0
- package/lib/programmatic/help-content/connected-system-ui.md +70 -0
- package/lib/programmatic/help-content/dimensions-guide.md +23 -0
- package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
- package/lib/programmatic/help-content/overview.md +25 -0
- package/lib/programmatic/help-content/subscription-guide.md +27 -0
- package/lib/programmatic/help-content/workflow.md +50 -0
- package/lib/programmatic/openapi-component-schemas.js +7 -1
- package/lib/programmatic/openapi-descriptions.js +46 -0
- package/lib/programmatic/openapi-envelope-examples.js +280 -0
- package/lib/programmatic/openapi-operation-bindings.js +50 -0
- package/lib/programmatic/openapi-request-schemas.js +40 -0
- package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
- package/lib/programmatic/openapi-result-schemas.js +76 -99
- package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
- package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
- package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
- package/lib/programmatic/openapi-schema-helpers.js +9 -9
- package/lib/programmatic/openapi-spec.js +11 -1
- package/lib/programmatic/orchestration-openapi-meta.js +10 -0
- package/lib/programmatic/persist-supplied-openapi.js +180 -0
- package/lib/programmatic/route-handler-map.js +35 -1
- package/lib/programmatic/run-channel-package.js +236 -0
- package/lib/programmatic/run-integration-definition.js +77 -0
- package/lib/role-assistant/evidence-sync.js +55 -7
- package/lib/role-assistant/knowledge-sync-logging.js +58 -0
- package/lib/role-assistant/knowledge-sync.js +88 -93
- package/lib/role-assistant/test-cases-bid.js +155 -0
- package/lib/role-assistant/test-cases-evaluate.js +9 -1
- package/lib/role-assistant/test-cases-honesty.js +24 -10
- package/lib/role-assistant/test-cases.js +28 -0
- package/lib/role-assistant/test-runner-attachments.js +118 -0
- package/lib/role-assistant/test-runner-bid-apply.js +201 -0
- package/lib/role-assistant/test-runner-bid-document.js +278 -0
- package/lib/role-assistant/test-runner-start-payload.js +96 -0
- package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
- package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
- package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
- package/lib/role-assistant/test-runner-workhub.js +152 -107
- package/lib/role-assistant/test-runner.js +5 -63
- package/lib/role-assistant/test-suite.js +112 -0
- package/lib/schema/application-schema.json +56 -6
- package/lib/schema/external-datasource.schema.json +103 -17
- package/lib/schema/external-system.schema.json +54 -3
- package/lib/schema/integration-definition.schema.json +195 -0
- package/lib/utils/authentication-shape.js +6 -0
- package/lib/utils/compose-generator.js +10 -1
- package/lib/utils/compose-traefik-extra-routes.js +107 -0
- package/lib/utils/docker-build.js +2 -2
- package/lib/utils/help-builder.js +3 -1
- package/lib/utils/promote-dev-docker-image.js +102 -18
- package/lib/utils/transient-developer-id.js +28 -0
- package/package.json +14 -16
- package/templates/README.md +12 -1
- package/templates/applications/dataplane/application.yaml +10 -2
- package/templates/applications/dataplane/env.template +7 -6
- package/templates/applications/miso-controller/application.yaml +23 -8
- package/templates/applications/miso-controller/env.template +8 -2
- package/templates/applications/miso-controller/rbac.yaml +1 -0
- package/templates/channels/README.md +11 -1
- package/templates/channels/brand/color-192.png +0 -0
- package/templates/channels/brand/dark/128.png +0 -0
- package/templates/channels/brand/dark/192.png +0 -0
- package/templates/channels/brand/dark/256.png +0 -0
- package/templates/channels/brand/dark/32.png +0 -0
- package/templates/channels/brand/dark/512.png +0 -0
- package/templates/channels/brand/dark/64.png +0 -0
- package/templates/channels/brand/light/128.png +0 -0
- package/templates/channels/brand/light/192.png +0 -0
- package/templates/channels/brand/light/256.png +0 -0
- package/templates/channels/brand/light/32.png +0 -0
- package/templates/channels/brand/light/512.png +0 -0
- package/templates/channels/brand/light/64.png +0 -0
- package/templates/channels/brand/mono-white/128.png +0 -0
- package/templates/channels/brand/mono-white/192.png +0 -0
- package/templates/channels/brand/mono-white/256.png +0 -0
- package/templates/channels/brand/mono-white/32.png +0 -0
- package/templates/channels/brand/mono-white/512.png +0 -0
- package/templates/channels/brand/mono-white/64.png +0 -0
- package/templates/channels/brand/outline-32.png +0 -0
- package/templates/channels/chatgpt/install.template.md.hbs +6 -4
- package/templates/channels/chatgpt/integration/README.md +4 -5
- package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
- package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
- package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
- package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
- package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
- package/templates/channels/microsoft-copilot/integration/README.md +2 -3
- package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
- package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
- package/templates/channels/slack/integration/README.md +2 -4
- package/templates/channels/teams-bot/install.template.md.hbs +4 -0
- package/templates/channels/teams-bot/integration/README.md +3 -5
- package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
- package/templates/python/docker-compose.hbs +36 -0
- package/templates/typescript/docker-compose.hbs +36 -0
- package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
- package/.cursor/process/README.md +0 -9
- package/.cursor/rules/anchor-docs.mdc +0 -15
- package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
- package/.cursor/rules/cli-layout.mdc +0 -81
- package/.cursor/rules/cli-product-neutral.mdc +0 -43
- package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
- package/.cursor/rules/docs-rules.mdc +0 -32
- package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
- package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
- package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
- package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
- package/.cursor/rules/project-rules.mdc +0 -913
- package/.cursor/skills/README.md +0 -15
- package/.dockerignore +0 -52
- package/.eslintignore +0 -22
- package/.markdownlint.json +0 -14
- package/anchor-docs/README.md +0 -10
- package/anchor-docs/_TEMPLATE +0 -24
- package/babel.config.js +0 -6
- package/bin/builder-api-cleanup.js +0 -26
- package/bin/builder-api-nest.js +0 -10
- package/bin/builder-api-spike.js +0 -19
- package/enterprise-knowledge/README.md +0 -50
- package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
- package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
- package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
- package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
- package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
- package/integration/README.md +0 -81
- package/integration/github/README.md +0 -53
- package/integration/github/application.json +0 -21
- package/integration/github/deploy.js +0 -72
- package/integration/github/env.template +0 -11
- package/integration/github/github-datasource-issue-comments.json +0 -239
- package/integration/github/github-datasource-issues.json +0 -399
- package/integration/github/github-datasource-repository.json +0 -354
- package/integration/github/github-deploy.json +0 -1202
- package/integration/github/github-system.json +0 -82
- package/integration/hubspot-test/README.md +0 -159
- package/integration/hubspot-test/application.json +0 -54
- package/integration/hubspot-test/companies.json +0 -2048
- package/integration/hubspot-test/create-hubspot.js +0 -523
- package/integration/hubspot-test/env.template +0 -4
- package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
- package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
- package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
- package/integration/hubspot-test/hubspot-test-system.json +0 -74
- package/integration/hubspot-test/rbac.json +0 -166
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
- package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
- package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
- package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
- package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
- package/integration/hubspot-test/test-dataplane-down.js +0 -209
- package/integration/hubspot-test/test.js +0 -1588
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
- package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
- package/integration/roundtrip-test-local/README.md +0 -143
- package/integration/roundtrip-test-local/application.yaml +0 -13
- package/integration/roundtrip-test-local/env.template +0 -15
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
- package/integration/roundtrip-test-local2/README.md +0 -143
- package/integration/roundtrip-test-local2/application.yaml +0 -13
- package/integration/roundtrip-test-local2/env.template +0 -15
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
- package/integration/test/wizard.yaml +0 -8
- package/jest.config.coverage.js +0 -37
- package/jest.config.default.js +0 -11
- package/jest.config.integration.fixtures.js +0 -22
- package/jest.config.integration.js +0 -33
- package/jest.config.isolated.js +0 -11
- package/jest.config.manual.js +0 -30
- package/jest.global-live-fabrix-hooks.js +0 -36
- package/jest.isolated-projects.js +0 -260
- package/jest.projects.js +0 -76
- package/packages/builder-api/README.md +0 -120
- package/packages/builder-api/package.json +0 -30
- package/packages/builder-api/src/app.module.ts +0 -7
- package/packages/builder-api/src/auth/auth.module.ts +0 -5
- package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
- package/packages/builder-api/src/main.ts +0 -16
- package/packages/builder-api/tsconfig.json +0 -15
- package/scripts/check-builder-api-architecture-grep.js +0 -79
- package/scripts/check-datasource-test-run-schema-sync.js +0 -34
- package/scripts/ci-fix.sh +0 -19
- package/scripts/ci-simulate.sh +0 -19
- package/scripts/diagnose-cli.js +0 -150
- package/scripts/docker_image_content_gate.js +0 -47
- package/scripts/docker_image_content_gate.sh +0 -5
- package/scripts/export-builder-api-evidence.js +0 -262
- package/scripts/install-local.js +0 -490
- package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
- package/scripts/lib/builder-api-docker-staging-core.js +0 -183
- package/scripts/lib/docker-image-content-gate-core.js +0 -166
- package/scripts/lib/plan-actor.js +0 -109
- package/scripts/lib/plan-config.js +0 -20
- package/scripts/lib/plan-gates.js +0 -154
- package/scripts/lib/plan-meta.js +0 -104
- package/scripts/lib/plan-parse.js +0 -162
- package/scripts/lib/plan-prevalidate-gates.js +0 -337
- package/scripts/lib/plan-run-core.js +0 -125
- package/scripts/lib/plan-run-report.js +0 -119
- package/scripts/plan-approve.js +0 -24
- package/scripts/plan-archive.js +0 -49
- package/scripts/plan-run.js +0 -13
- package/scripts/plan-set-actor.js +0 -21
- package/scripts/plan-validate.js +0 -80
- package/scripts/pnpm/af.mjs +0 -110
- package/scripts/pnpm/check-quiet.mjs +0 -32
- package/scripts/pnpm/dev-install.mjs +0 -29
- package/scripts/pnpm/dev-reload.mjs +0 -18
- package/scripts/pnpm/help.mjs +0 -55
- package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
- package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
- package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
- package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
- package/scripts/pnpm/lib/spinner.mjs +0 -42
- package/scripts/pnpm-global-remove.js +0 -48
- package/scripts/stage_builder_api_for_docker.js +0 -65
- package/scripts/sync-builder-api-template.js +0 -44
- package/scripts/test-dataplane-bootstrap.js +0 -331
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-level parity score between a reference integration dir and a candidate.
|
|
3
|
+
* Lab/DoD aid only — reference packages are score baselines, never generation input.
|
|
4
|
+
*
|
|
5
|
+
* @fileoverview Structured parity facets for two integration package directories
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const fs = require('../internal/fs-real-sync');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
13
|
+
|
|
14
|
+
const DATASOURCE_FILE_RE = /datasource/i;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} dir
|
|
18
|
+
* @returns {string[]}
|
|
19
|
+
*/
|
|
20
|
+
function listJsonFiles(dir) {
|
|
21
|
+
if (!dir || !fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
return fs
|
|
25
|
+
.readdirSync(dir)
|
|
26
|
+
.filter((name) => name.endsWith('.json') || name.endsWith('.yaml') || name.endsWith('.yml'))
|
|
27
|
+
.map((name) => path.join(dir, name))
|
|
28
|
+
.sort();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {string} dir
|
|
33
|
+
* @returns {Object[]}
|
|
34
|
+
*/
|
|
35
|
+
function loadDatasourceManifests(dir) {
|
|
36
|
+
const out = [];
|
|
37
|
+
for (const filePath of listJsonFiles(dir)) {
|
|
38
|
+
const base = path.basename(filePath);
|
|
39
|
+
if (!DATASOURCE_FILE_RE.test(base)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const parsed = loadConfigFile(filePath);
|
|
44
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
45
|
+
out.push({ filePath, base, manifest: parsed });
|
|
46
|
+
}
|
|
47
|
+
} catch (_err) {
|
|
48
|
+
// Skip unreadable files; facet will report incomplete package
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return out;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {Object} manifest
|
|
56
|
+
* @returns {string}
|
|
57
|
+
*/
|
|
58
|
+
function datasourceKey(manifest) {
|
|
59
|
+
return String(manifest.key || '').trim();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {Object} manifest
|
|
64
|
+
* @returns {string[]}
|
|
65
|
+
*/
|
|
66
|
+
function capabilityKeys(manifest) {
|
|
67
|
+
const caps = manifest.capabilities;
|
|
68
|
+
if (!Array.isArray(caps)) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
return caps
|
|
72
|
+
.map((row) => (row && typeof row === 'object' ? String(row.key || '').trim() : ''))
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.sort();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @param {string} dir
|
|
79
|
+
* @returns {string[]}
|
|
80
|
+
*/
|
|
81
|
+
function openapiBasenames(dir) {
|
|
82
|
+
const openapiDir = path.join(dir, 'openapi');
|
|
83
|
+
if (!fs.existsSync(openapiDir) || !fs.statSync(openapiDir).isDirectory()) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
return fs
|
|
87
|
+
.readdirSync(openapiDir)
|
|
88
|
+
.filter((name) => /\.(json|yaml|yml)$/i.test(name))
|
|
89
|
+
.map((name) => name.toLowerCase())
|
|
90
|
+
.sort();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @param {Object} manifest
|
|
95
|
+
* @returns {{ metadataSchema: boolean, fieldMappings: boolean, foreignKeys: boolean, exposed: boolean, cip: boolean }}
|
|
96
|
+
*/
|
|
97
|
+
function contractSurfaceFlags(manifest) {
|
|
98
|
+
const execution = manifest.execution && typeof manifest.execution === 'object' ? manifest.execution : {};
|
|
99
|
+
const cip = execution.cip && typeof execution.cip === 'object' ? execution.cip : null;
|
|
100
|
+
return {
|
|
101
|
+
metadataSchema: Boolean(manifest.metadataSchema),
|
|
102
|
+
fieldMappings: Boolean(manifest.fieldMappings),
|
|
103
|
+
foreignKeys: Boolean(manifest.foreignKeys),
|
|
104
|
+
exposed: Boolean(manifest.exposed),
|
|
105
|
+
cip: Boolean(cip && cip.operations)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {boolean} ok
|
|
111
|
+
* @param {string} id
|
|
112
|
+
* @param {string} detail
|
|
113
|
+
* @param {Object} [extra]
|
|
114
|
+
* @returns {Object}
|
|
115
|
+
*/
|
|
116
|
+
function facet(ok, id, detail, extra = {}) {
|
|
117
|
+
return { id, ok: Boolean(ok), detail, ...extra };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* @param {string} absDir
|
|
122
|
+
* @returns {boolean}
|
|
123
|
+
*/
|
|
124
|
+
function isPackageDir(absDir) {
|
|
125
|
+
return fs.existsSync(absDir) && fs.statSync(absDir).isDirectory();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @param {Object[]} rows
|
|
130
|
+
* @returns {Map<string, Object>}
|
|
131
|
+
*/
|
|
132
|
+
function indexDatasourcesByKey(rows) {
|
|
133
|
+
const byKey = new Map();
|
|
134
|
+
for (const row of rows) {
|
|
135
|
+
const key = datasourceKey(row.manifest);
|
|
136
|
+
if (key) {
|
|
137
|
+
byKey.set(key, row);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return byKey;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @param {string} refAbs
|
|
145
|
+
* @param {string} candAbs
|
|
146
|
+
* @param {Object[]} facets
|
|
147
|
+
*/
|
|
148
|
+
function pushPresenceFacets(refAbs, candAbs, facets) {
|
|
149
|
+
const refExists = isPackageDir(refAbs);
|
|
150
|
+
const candExists = isPackageDir(candAbs);
|
|
151
|
+
facets.push(
|
|
152
|
+
facet(refExists, 'referencePackagePresent', refExists ? 'Reference package directory found' : 'Reference package directory missing')
|
|
153
|
+
);
|
|
154
|
+
facets.push(
|
|
155
|
+
facet(candExists, 'candidatePackagePresent', candExists ? 'Candidate package directory found' : 'Candidate package directory missing')
|
|
156
|
+
);
|
|
157
|
+
return { refExists, candExists };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* @param {string} refAbs
|
|
162
|
+
* @param {string} candAbs
|
|
163
|
+
* @param {Object[]} facets
|
|
164
|
+
*/
|
|
165
|
+
function pushSystemManifestFacet(refAbs, candAbs, facets) {
|
|
166
|
+
const refHasSystem = listJsonFiles(refAbs).some((f) => /system/i.test(path.basename(f)));
|
|
167
|
+
const candHasSystem = listJsonFiles(candAbs).some((f) => /system/i.test(path.basename(f)));
|
|
168
|
+
facets.push(
|
|
169
|
+
facet(
|
|
170
|
+
!refHasSystem || candHasSystem,
|
|
171
|
+
'systemManifest',
|
|
172
|
+
candHasSystem ? 'Candidate has a system manifest file' : 'Candidate missing system manifest while reference has one'
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @param {Map<string, Object>} refByKey
|
|
179
|
+
* @param {Map<string, Object>} candByKey
|
|
180
|
+
* @param {Object[]} facets
|
|
181
|
+
* @returns {string[]}
|
|
182
|
+
*/
|
|
183
|
+
function pushDatasourceCoverageFacet(refByKey, candByKey, facets) {
|
|
184
|
+
const missingDatasourceKeys = [...refByKey.keys()].filter((key) => !candByKey.has(key)).sort();
|
|
185
|
+
facets.push(
|
|
186
|
+
facet(
|
|
187
|
+
missingDatasourceKeys.length === 0 && refByKey.size > 0,
|
|
188
|
+
'datasourceKeyCoverage',
|
|
189
|
+
missingDatasourceKeys.length === 0
|
|
190
|
+
? `Candidate covers ${refByKey.size} reference datasource key(s)`
|
|
191
|
+
: `Missing datasource keys: ${missingDatasourceKeys.join(', ')}`,
|
|
192
|
+
{ missingDatasourceKeys, referenceCount: refByKey.size, candidateCount: candByKey.size }
|
|
193
|
+
)
|
|
194
|
+
);
|
|
195
|
+
return missingDatasourceKeys;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {string} refAbs
|
|
200
|
+
* @param {string} candAbs
|
|
201
|
+
* @param {Object[]} facets
|
|
202
|
+
*/
|
|
203
|
+
function pushOpenapiFacet(refAbs, candAbs, facets) {
|
|
204
|
+
const refOpenapi = openapiBasenames(refAbs);
|
|
205
|
+
const candOpenapi = new Set(openapiBasenames(candAbs));
|
|
206
|
+
const missingOpenapi = refOpenapi.filter((name) => !candOpenapi.has(name));
|
|
207
|
+
facets.push(
|
|
208
|
+
facet(
|
|
209
|
+
refOpenapi.length === 0 || missingOpenapi.length === 0,
|
|
210
|
+
'openapiDir',
|
|
211
|
+
refOpenapi.length === 0
|
|
212
|
+
? 'Reference has no openapi/ files — facet skipped'
|
|
213
|
+
: missingOpenapi.length === 0
|
|
214
|
+
? `Candidate has ${refOpenapi.length} matching openapi basename(s)`
|
|
215
|
+
: `Missing openapi files: ${missingOpenapi.join(', ')}`,
|
|
216
|
+
{ missingOpenapi }
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* @param {string} key
|
|
223
|
+
* @param {Object} refManifest
|
|
224
|
+
* @param {Object} candManifest
|
|
225
|
+
* @param {Object[]} capabilityGaps
|
|
226
|
+
* @returns {boolean}
|
|
227
|
+
*/
|
|
228
|
+
function collectCapabilityGaps(key, refManifest, candManifest, capabilityGaps) {
|
|
229
|
+
const refCaps = new Set(capabilityKeys(refManifest));
|
|
230
|
+
const candCaps = new Set(capabilityKeys(candManifest));
|
|
231
|
+
const missingCaps = [...refCaps].filter((c) => !candCaps.has(c)).sort();
|
|
232
|
+
if (!missingCaps.length) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
capabilityGaps.push({ datasourceKey: key, missingCapabilityKeys: missingCaps });
|
|
236
|
+
return false;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @param {string} key
|
|
241
|
+
* @param {Object} refManifest
|
|
242
|
+
* @param {Object} candManifest
|
|
243
|
+
* @param {Object[]} resourceTypeGaps
|
|
244
|
+
* @returns {boolean}
|
|
245
|
+
*/
|
|
246
|
+
function collectResourceTypeGaps(key, refManifest, candManifest, resourceTypeGaps) {
|
|
247
|
+
const refRt = String(refManifest.resourceType || '').trim();
|
|
248
|
+
const candRt = String(candManifest.resourceType || '').trim();
|
|
249
|
+
if (!(refRt && candRt && refRt !== candRt)) {
|
|
250
|
+
return true;
|
|
251
|
+
}
|
|
252
|
+
resourceTypeGaps.push({ datasourceKey: key, reference: refRt, candidate: candRt });
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* @param {string} key
|
|
258
|
+
* @param {Object} refManifest
|
|
259
|
+
* @param {Object} candManifest
|
|
260
|
+
* @param {Object[]} surfaceGaps
|
|
261
|
+
* @returns {boolean}
|
|
262
|
+
*/
|
|
263
|
+
function collectSurfaceGaps(key, refManifest, candManifest, surfaceGaps) {
|
|
264
|
+
const refFlags = contractSurfaceFlags(refManifest);
|
|
265
|
+
const candFlags = contractSurfaceFlags(candManifest);
|
|
266
|
+
let ok = true;
|
|
267
|
+
for (const [surface, needed] of Object.entries(refFlags)) {
|
|
268
|
+
if (needed && !candFlags[surface]) {
|
|
269
|
+
ok = false;
|
|
270
|
+
surfaceGaps.push({ datasourceKey: key, surface });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return ok;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* @param {Map<string, Object>} refByKey
|
|
278
|
+
* @param {Map<string, Object>} candByKey
|
|
279
|
+
* @returns {{ capabilityOk: boolean, capabilityGaps: Object[], resourceTypeOk: boolean, resourceTypeGaps: Object[], surfacesOk: boolean, surfaceGaps: Object[] }}
|
|
280
|
+
*/
|
|
281
|
+
function compareSharedDatasources(refByKey, candByKey) {
|
|
282
|
+
const capabilityGaps = [];
|
|
283
|
+
const resourceTypeGaps = [];
|
|
284
|
+
const surfaceGaps = [];
|
|
285
|
+
let capabilityOk = true;
|
|
286
|
+
let resourceTypeOk = true;
|
|
287
|
+
let surfacesOk = true;
|
|
288
|
+
|
|
289
|
+
for (const [key, refRow] of refByKey.entries()) {
|
|
290
|
+
const candRow = candByKey.get(key);
|
|
291
|
+
if (!candRow) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (!collectCapabilityGaps(key, refRow.manifest, candRow.manifest, capabilityGaps)) {
|
|
295
|
+
capabilityOk = false;
|
|
296
|
+
}
|
|
297
|
+
if (!collectResourceTypeGaps(key, refRow.manifest, candRow.manifest, resourceTypeGaps)) {
|
|
298
|
+
resourceTypeOk = false;
|
|
299
|
+
}
|
|
300
|
+
if (!collectSurfaceGaps(key, refRow.manifest, candRow.manifest, surfaceGaps)) {
|
|
301
|
+
surfacesOk = false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return { capabilityOk, capabilityGaps, resourceTypeOk, resourceTypeGaps, surfacesOk, surfaceGaps };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @param {ReturnType<typeof compareSharedDatasources>} compared
|
|
310
|
+
* @param {Object[]} facets
|
|
311
|
+
*/
|
|
312
|
+
function pushSharedDatasourceFacets(compared, facets) {
|
|
313
|
+
facets.push(
|
|
314
|
+
facet(
|
|
315
|
+
compared.capabilityOk,
|
|
316
|
+
'capabilityKeys',
|
|
317
|
+
compared.capabilityOk ? 'Capability keys cover reference on shared datasources' : 'Missing capability keys on shared datasources',
|
|
318
|
+
{ gaps: compared.capabilityGaps }
|
|
319
|
+
)
|
|
320
|
+
);
|
|
321
|
+
facets.push(
|
|
322
|
+
facet(
|
|
323
|
+
compared.resourceTypeOk,
|
|
324
|
+
'resourceTypes',
|
|
325
|
+
compared.resourceTypeOk ? 'resourceType matches on shared datasources' : 'resourceType mismatches on shared datasources',
|
|
326
|
+
{ gaps: compared.resourceTypeGaps }
|
|
327
|
+
)
|
|
328
|
+
);
|
|
329
|
+
facets.push(
|
|
330
|
+
facet(
|
|
331
|
+
compared.surfacesOk,
|
|
332
|
+
'contractSurfaces',
|
|
333
|
+
compared.surfacesOk ? 'Contract surfaces present where reference declares them' : 'Missing contract surfaces vs reference',
|
|
334
|
+
{ gaps: compared.surfaceGaps }
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @param {Object[]} facets
|
|
341
|
+
* @param {string[]} missingDatasourceKeys
|
|
342
|
+
* @param {string} refAbs
|
|
343
|
+
* @param {string} candAbs
|
|
344
|
+
* @returns {Object}
|
|
345
|
+
*/
|
|
346
|
+
function buildParityReport(facets, missingDatasourceKeys, refAbs, candAbs) {
|
|
347
|
+
const scored = facets.filter((f) => f.id !== 'referencePackagePresent');
|
|
348
|
+
const passed = scored.filter((f) => f.ok).length;
|
|
349
|
+
const score = scored.length === 0 ? 0 : Math.round((passed / scored.length) * 100);
|
|
350
|
+
const identical = facets.every((f) => f.ok) && missingDatasourceKeys.length === 0;
|
|
351
|
+
return {
|
|
352
|
+
score,
|
|
353
|
+
maxScore: 100,
|
|
354
|
+
identical,
|
|
355
|
+
referenceDir: refAbs,
|
|
356
|
+
candidateDir: candAbs,
|
|
357
|
+
goldIsScoreOnly: true,
|
|
358
|
+
facets,
|
|
359
|
+
missingDatasourceKeys,
|
|
360
|
+
summary: identical
|
|
361
|
+
? 'Candidate matches reference facets (score baseline only — not generation input)'
|
|
362
|
+
: `Parity score ${score}/100 — reference is score-only, never generation input`
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Score candidate integration package directory against a reference package directory.
|
|
368
|
+
*
|
|
369
|
+
* @param {string} referenceDir Absolute or relative path to reference package (score baseline only)
|
|
370
|
+
* @param {string} candidateDir Absolute or relative path to candidate package
|
|
371
|
+
* @returns {{
|
|
372
|
+
* score: number,
|
|
373
|
+
* maxScore: number,
|
|
374
|
+
* identical: boolean,
|
|
375
|
+
* referenceDir: string,
|
|
376
|
+
* candidateDir: string,
|
|
377
|
+
* goldIsScoreOnly: true,
|
|
378
|
+
* facets: Object[],
|
|
379
|
+
* missingDatasourceKeys: string[],
|
|
380
|
+
* summary: string
|
|
381
|
+
* }}
|
|
382
|
+
*/
|
|
383
|
+
function scorePackageParity(referenceDir, candidateDir) {
|
|
384
|
+
const refAbs = path.resolve(referenceDir);
|
|
385
|
+
const candAbs = path.resolve(candidateDir);
|
|
386
|
+
const facets = [];
|
|
387
|
+
const { refExists, candExists } = pushPresenceFacets(refAbs, candAbs, facets);
|
|
388
|
+
|
|
389
|
+
if (!refExists || !candExists) {
|
|
390
|
+
return {
|
|
391
|
+
score: 0,
|
|
392
|
+
maxScore: 100,
|
|
393
|
+
identical: false,
|
|
394
|
+
referenceDir: refAbs,
|
|
395
|
+
candidateDir: candAbs,
|
|
396
|
+
goldIsScoreOnly: true,
|
|
397
|
+
facets,
|
|
398
|
+
missingDatasourceKeys: [],
|
|
399
|
+
summary: 'Package directories incomplete — score 0 (no silent 100%)'
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
pushSystemManifestFacet(refAbs, candAbs, facets);
|
|
404
|
+
const refByKey = indexDatasourcesByKey(loadDatasourceManifests(refAbs));
|
|
405
|
+
const candByKey = indexDatasourcesByKey(loadDatasourceManifests(candAbs));
|
|
406
|
+
const missingDatasourceKeys = pushDatasourceCoverageFacet(refByKey, candByKey, facets);
|
|
407
|
+
pushOpenapiFacet(refAbs, candAbs, facets);
|
|
408
|
+
pushSharedDatasourceFacets(compareSharedDatasources(refByKey, candByKey), facets);
|
|
409
|
+
return buildParityReport(facets, missingDatasourceKeys, refAbs, candAbs);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
module.exports = {
|
|
413
|
+
scorePackageParity,
|
|
414
|
+
loadDatasourceManifests,
|
|
415
|
+
openapiBasenames,
|
|
416
|
+
contractSurfaceFlags
|
|
417
|
+
};
|
|
@@ -19,7 +19,11 @@ const { withRequestTimeout } = require('./request-timeout');
|
|
|
19
19
|
* @returns {boolean}
|
|
20
20
|
*/
|
|
21
21
|
function requiresAuth(capability) {
|
|
22
|
-
return
|
|
22
|
+
return (
|
|
23
|
+
capability.handlerId !== 'health' &&
|
|
24
|
+
capability.handlerId !== 'ready' &&
|
|
25
|
+
capability.handlerId !== 'getBuilderHelp'
|
|
26
|
+
);
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
/**
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const fs = require('fs');
|
|
11
|
+
const fs = require('../internal/fs-real-sync');
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const { buildHelpEnvelope } = require('./builder-help-envelope');
|
|
14
14
|
const { listPlatformRoles } = require('./platform-rbac-catalog');
|
|
@@ -168,5 +168,6 @@ module.exports = {
|
|
|
168
168
|
buildPlatformRolesTopic,
|
|
169
169
|
buildResourceTypeCatalogTopic,
|
|
170
170
|
buildDimensionsGuideTopic,
|
|
171
|
-
buildChannelOnboardingTopic
|
|
171
|
+
buildChannelOnboardingTopic,
|
|
172
|
+
loadResourceTypeCatalog
|
|
172
173
|
};
|
|
@@ -12,9 +12,17 @@
|
|
|
12
12
|
const CAPABILITIES = Object.freeze([
|
|
13
13
|
{ method: 'GET', route: '/workspaces/me/systems', handlerId: 'listSystems', operationType: 'workspace.read', mutating: false },
|
|
14
14
|
{ method: 'POST', route: '/workspaces/me/systems', handlerId: 'createSystem', operationType: 'workspace.write', mutating: true },
|
|
15
|
+
{ method: 'POST', route: '/systems/:systemKey/openapi/persist-supplied', handlerId: 'persistSuppliedOpenApi', operationType: 'workspace.write', mutating: true },
|
|
15
16
|
{ method: 'GET', route: '/workspaces/me/systems/:systemKey', handlerId: 'getSystemManifest', operationType: 'workspace.read', mutating: false },
|
|
16
17
|
{ method: 'DELETE', route: '/workspaces/me/systems/:systemKey', handlerId: 'deleteSystem', operationType: 'workspace.write', mutating: true },
|
|
17
18
|
{ method: 'POST', route: '/systems/:systemKey/wizard', handlerId: 'runWizard', operationType: 'plan', mutating: true },
|
|
19
|
+
{
|
|
20
|
+
method: 'POST',
|
|
21
|
+
route: '/systems/:systemKey/integration-definition/apply',
|
|
22
|
+
handlerId: 'applyIntegrationDefinition',
|
|
23
|
+
operationType: 'plan',
|
|
24
|
+
mutating: true
|
|
25
|
+
},
|
|
18
26
|
{ method: 'POST', route: '/systems/:systemKey/repair', handlerId: 'runRepair', operationType: 'plan', mutating: true },
|
|
19
27
|
{ method: 'GET', route: '/systems/:systemKey/manifest/sections', handlerId: 'listManifestSections', operationType: 'workspace.read', mutating: false },
|
|
20
28
|
{ method: 'GET', route: '/systems/:systemKey/manifest/section/:sectionKey', handlerId: 'getManifestSection', operationType: 'workspace.read', mutating: false },
|
|
@@ -63,8 +71,20 @@ const CAPABILITIES = Object.freeze([
|
|
|
63
71
|
{ method: 'POST', route: '/systems/:systemKey/repository/create-review', handlerId: 'runRepositoryCreateReview', operationType: 'repository', mutating: true },
|
|
64
72
|
{ method: 'GET', route: '/systems/:systemKey/repository/status', handlerId: 'getRepositoryStatus', operationType: 'repository.read', mutating: false },
|
|
65
73
|
{ method: 'POST', route: '/systems/:systemKey/repository/dispatch-pipeline', handlerId: 'runRepositoryDispatchPipeline', operationType: 'repository', mutating: true },
|
|
74
|
+
{ method: 'POST', route: '/systems/:systemKey/channels/package', handlerId: 'buildChannelPackage', operationType: 'channel', mutating: true },
|
|
75
|
+
{ method: 'GET', route: '/systems/:systemKey/channels/package', handlerId: 'getChannelPackageSummary', operationType: 'channel.read', mutating: false },
|
|
76
|
+
{ method: 'GET', route: '/systems/:systemKey/channels/package/zip', handlerId: 'getChannelPackageZip', operationType: 'channel.read', mutating: false },
|
|
77
|
+
{ method: 'GET', route: '/systems/:systemKey/channels/branding', handlerId: 'getChannelBranding', operationType: 'channel.read', mutating: false },
|
|
78
|
+
{ method: 'PATCH', route: '/systems/:systemKey/channels/branding', handlerId: 'patchChannelBranding', operationType: 'channel', mutating: true },
|
|
66
79
|
{ method: 'GET', route: '/health', handlerId: 'health', operationType: 'infra', mutating: false },
|
|
67
80
|
{ method: 'GET', route: '/health/ready', handlerId: 'ready', operationType: 'infra', mutating: false },
|
|
81
|
+
{
|
|
82
|
+
method: 'GET',
|
|
83
|
+
route: '/help',
|
|
84
|
+
handlerId: 'getBuilderHelp',
|
|
85
|
+
operationType: 'help.read',
|
|
86
|
+
mutating: false
|
|
87
|
+
},
|
|
68
88
|
{ method: 'GET', route: '/evidence/:roleKey/metadata', handlerId: 'getEvidenceMetadata', operationType: 'evidence.read', mutating: false },
|
|
69
89
|
{ method: 'GET', route: '/evidence/:roleKey/download', handlerId: 'downloadEvidence', operationType: 'evidence.read', mutating: false },
|
|
70
90
|
{ method: 'POST', route: '/evidence/:roleKey/upload', handlerId: 'uploadEvidenceCandidates', operationType: 'evidence.write', mutating: true },
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Channel onboarding from your work list
|
|
2
|
+
|
|
3
|
+
Onboard an assistant channel after your external system is published from a Builder workspace.
|
|
4
|
+
|
|
5
|
+
## Work list
|
|
6
|
+
|
|
7
|
+
Call GET workspaces/me/systems to list integration keys in your authenticated workspace. Each entry is a draft or published external system you are building.
|
|
8
|
+
|
|
9
|
+
## Publish before channel
|
|
10
|
+
|
|
11
|
+
Complete validate and upload for the target systemKey so the dataplane exposes MCP tools and connected-system UI. Use repair with bearer-forward auth for facade APIs. Apply platform RBAC when the integration is a platform orchestration API.
|
|
12
|
+
|
|
13
|
+
## Choose a channel target
|
|
14
|
+
|
|
15
|
+
| Target | Use when |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| teams-bot | Microsoft Teams employee assistant |
|
|
18
|
+
| slack | Slack workspace assistant |
|
|
19
|
+
| microsoft-copilot | Microsoft Copilot package (runtime-orchestration MCP) |
|
|
20
|
+
| chatgpt | ChatGPT custom MCP app (runtime-orchestration) |
|
|
21
|
+
| web-embed | Experimental embedded web assistant |
|
|
22
|
+
|
|
23
|
+
Each target requires credentials and deploy approval. Read topic connectedSystemUi after upload for dataplane handoff paths.
|
|
24
|
+
|
|
25
|
+
## Recommended sequence
|
|
26
|
+
|
|
27
|
+
1. GET help topic overview and platformRoles when scoping RBAC.
|
|
28
|
+
2. GET workspaces/me/systems — pick or create systemKey.
|
|
29
|
+
3. Run wizard, repair, validate, upload via Builder API.
|
|
30
|
+
4. Scaffold channel integration with the CLI channel scaffold command for the chosen target.
|
|
31
|
+
5. Register the channel on the deployed application with channel add.
|
|
32
|
+
|
|
33
|
+
## Governance before go-live
|
|
34
|
+
|
|
35
|
+
Confirm resourceType catalog keys match business entities. Add dimensions on record and document datasources before protection. Scope system.subscriptions to business resource types, not generic placeholders.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# CIP execution overview
|
|
2
|
+
|
|
3
|
+
Composable Integration Pipeline is the declarative execution engine for datasource operations. Most external datasources use engine cip under the datasource.execution section.
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
Each operation under execution.cip.operations is a named map entry such as list, get, create, update, or delete. Custom operation names are allowed when they match capability keys.
|
|
8
|
+
|
|
9
|
+
Every operation contains an ordered steps array. Each step is a single keyed object: fetch, paginate, map, filter, output, or pythonInline.
|
|
10
|
+
|
|
11
|
+
## Common step patterns
|
|
12
|
+
|
|
13
|
+
Fetch resolves data from OpenAPI references, raw HTTP, or another datasource. Map applies fieldMappings to normalize vendor payloads. Filter applies optional ABAC or JMESPath expressions. Output emits records for sync and storage.
|
|
14
|
+
|
|
15
|
+
Paginate handles cursor, page, or offset strategies for list operations. Python inline runs sandboxed transforms when declarative steps are insufficient.
|
|
16
|
+
|
|
17
|
+
## Quality practices
|
|
18
|
+
|
|
19
|
+
Choose entityType and resourceType before authoring execution steps. Align openapi.operations keys with capabilities and fetch openapiRef values.
|
|
20
|
+
|
|
21
|
+
After changing metadata or capabilities, run repair hooks for fieldMappings, expose, and rbac before validate and test.
|
|
22
|
+
|
|
23
|
+
Use validate responses as the authoritative guide when step properties fail schema checks. Request topic schemaCatalog for property indexes, then topic section for governed fragments.
|
|
24
|
+
|
|
25
|
+
## Related sections
|
|
26
|
+
|
|
27
|
+
datasource.execution, datasource.capabilities, datasource.fieldMappings, datasource.openapiOperations, datasource.metadata
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Connected Systems UI navigation
|
|
2
|
+
|
|
3
|
+
Use this topic after validate, test, test-integration, and upload succeed without resolved integration secrets in Builder API scope.
|
|
4
|
+
|
|
5
|
+
## Post-upload authentication handoff
|
|
6
|
+
|
|
7
|
+
Upload publishes the external system manifest. The user adds **live secrets only** in the dataplane Connected Systems Authentication tab — not by pasting tokens into Builder API or workspace files.
|
|
8
|
+
|
|
9
|
+
Authentication is declared on the **external system** manifest (`authentications[]` with usage slots, or legacy `authentication` normalized by repair), not on individual datasource manifests. Datasources inherit linked system credentials at sync and CIP runtime.
|
|
10
|
+
|
|
11
|
+
### Variables vs secrets (manifest split)
|
|
12
|
+
|
|
13
|
+
| Manifest path | When to set | After upload |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `authentication.credential.variables` | During manifest editing (Builder API) | Published and **pre-filled** in Authentication UI — user does not re-enter |
|
|
16
|
+
| `authentication.credential.security` | kv:// placeholders in manifest only | User adds **live secret values** in Authentication UI (for example token, apiKey, clientSecret) |
|
|
17
|
+
|
|
18
|
+
**Enterprise-ready pattern:** put baseUrl, headerName, tokenUrl, prefix, testEndpoint, and similar non-secrets in `variables` before upload. After upload, the user opens Authentication and adds only the token or other required secret.
|
|
19
|
+
|
|
20
|
+
Before prompting the user:
|
|
21
|
+
|
|
22
|
+
1. Read `authentications[]` usage slots from the published system manifest (prefer over legacy `authentication`).
|
|
23
|
+
2. For each slot, read `authType` and `credential.method` when applicable.
|
|
24
|
+
3. Confirm `variables` are already complete in the manifest — do not ask the user to supply them again.
|
|
25
|
+
4. Tell the user which **secret keys only** they must add in the UI (`requiredSecretKeys`).
|
|
26
|
+
5. When webhook or syncBridge is enabled, also hand off to datasource **Sync** tab (`tab=sync`) for activation guide URLs.
|
|
27
|
+
|
|
28
|
+
## Authentication modes (authType)
|
|
29
|
+
|
|
30
|
+
| authType | Where in manifest | User action in UI |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `credential` | `authentication.credential` | Add secret values only; variables already pre-filled |
|
|
33
|
+
| `apiProvider` | `authentication.apiProvider.apiProviderKey` | Link the Miso API Provider — no local vendor secrets |
|
|
34
|
+
| `none` | `authentication.authType` only | No credential handoff unless live tests fail for other reasons |
|
|
35
|
+
|
|
36
|
+
## Credential methods (when authType is credential)
|
|
37
|
+
|
|
38
|
+
Methods come from `external-system.schema.json` (`authentication.credential.method`). User adds **secrets only** after upload:
|
|
39
|
+
|
|
40
|
+
| method | User adds in UI (secrets only) | Already in manifest variables |
|
|
41
|
+
| --- | --- | --- |
|
|
42
|
+
| `oauth2` | clientSecret (clientId if empty) | baseUrl, tokenUrl, grantType, scope |
|
|
43
|
+
| `aad` | clientSecret (clientId if empty) | baseUrl, tokenUrl, tenantId, grantType |
|
|
44
|
+
| `apikey` | apiKey (token) | baseUrl, headerName, prefix, testEndpoint |
|
|
45
|
+
| `bearerToken` | token | baseUrl, headerName, prefix, testEndpoint |
|
|
46
|
+
| `basic` | username, password | baseUrl, testEndpoint |
|
|
47
|
+
| `queryParam` | paramValue | baseUrl, paramName, testEndpoint |
|
|
48
|
+
| `oidc` | any remaining OIDC secrets shown | openIdConfigUrl, clientId |
|
|
49
|
+
| `hmac` | signingSecret | algorithm, signature headers |
|
|
50
|
+
| `none` | none | — |
|
|
51
|
+
|
|
52
|
+
Use optional query params `authType` and `credentialMethod` on this topic to get `manifestHandoff.promptHints` tailored to the manifest.
|
|
53
|
+
|
|
54
|
+
## URL structure
|
|
55
|
+
|
|
56
|
+
Combine `{dataplanePublicBase}` with a relative path:
|
|
57
|
+
|
|
58
|
+
- System: `/connected-systems/{systemKey}?tab=authentication`
|
|
59
|
+
- Datasource: `/connected-systems/{systemKey}/datasources/{datasourceKey}?tab={tab}`
|
|
60
|
+
|
|
61
|
+
Omit `?tab=` for the default Overview tab on each level. Tab values are case-insensitive; aliases are listed in the structured `systemTabs` and `datasourceTabs` arrays on this topic.
|
|
62
|
+
|
|
63
|
+
## Typical tabs after publish
|
|
64
|
+
|
|
65
|
+
| Goal | System tab value |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| Add token / secrets | `authentication` |
|
|
68
|
+
| Review datasources | `datasources` or `business-entities` |
|
|
69
|
+
| Sync / webhook activation | Open datasource path with `tab=sync` |
|
|
70
|
+
| Execution logs | Open datasource path with `tab=logs` |
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Dimensions and ABAC grounding
|
|
2
|
+
|
|
3
|
+
Dimensions are governance attributes on datasource manifests. They map normalized metadata paths to ABAC policies, protection rules, and subscription filters.
|
|
4
|
+
|
|
5
|
+
## When dimensions apply
|
|
6
|
+
|
|
7
|
+
Use dimensions on recordStorage, documentStorage, and serviceContract datasources. entityType none orchestration datasources must not declare fieldMappings.dimensions.
|
|
8
|
+
|
|
9
|
+
## Authoring rules
|
|
10
|
+
|
|
11
|
+
Declare dimensions at fieldMappings.dimensions with values pointing to metadata paths, such as metadata.country or metadata.owner. Match metadataSchema properties so protection and sync can evaluate grants.
|
|
12
|
+
|
|
13
|
+
Ask the user for business context before patching datasource.dimensions. Common dimensions include country, region, department, owner, sensitivity, siteId, and lifecycleStage.
|
|
14
|
+
|
|
15
|
+
## Challenge patterns
|
|
16
|
+
|
|
17
|
+
If a datasource uses resourceType customer but has no country or region dimension, ask whether geographic protection is required. If document libraries lack owner or sensitivity, ask before enabling protection.
|
|
18
|
+
|
|
19
|
+
When foreignKeys link a child datasource to a parent, confirm whether dimensions should inherit from the parent record metadata.
|
|
20
|
+
|
|
21
|
+
## Related sections
|
|
22
|
+
|
|
23
|
+
datasource.dimensions, datasource.metadata, datasource.foreignKeys, datasource.governance, system.subscriptions
|