@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.
Files changed (310) hide show
  1. package/lib/api/datasources-extended.api.js +8 -8
  2. package/lib/api/keycloak.api.js +92 -0
  3. package/lib/api/token-providers.api.js +77 -0
  4. package/lib/api/types/keycloak.types.js +23 -0
  5. package/lib/api/types/token-providers.types.js +65 -0
  6. package/lib/app/deploy-config.js +3 -2
  7. package/lib/app/down.js +16 -1
  8. package/lib/channels/add-channel.js +134 -57
  9. package/lib/channels/approval-guides/chatgpt.js +1 -1
  10. package/lib/channels/approval-guides/index.js +3 -0
  11. package/lib/channels/approval-guides/microsoft-copilot.js +27 -14
  12. package/lib/channels/channel-add-ensure.js +128 -0
  13. package/lib/channels/channel-add-existing.js +72 -0
  14. package/lib/channels/channel-artifact-generator.js +11 -1
  15. package/lib/channels/channel-branding.js +94 -0
  16. package/lib/channels/channel-credential.js +8 -0
  17. package/lib/channels/channel-discovery.js +330 -0
  18. package/lib/channels/channel-external-system.js +1 -1
  19. package/lib/channels/channel-runtime-resolver.js +107 -14
  20. package/lib/channels/channel-status-display.js +36 -3
  21. package/lib/channels/microsoft-copilot-channel-add.js +138 -0
  22. package/lib/channels/microsoft-copilot-entra-sso-form.js +251 -0
  23. package/lib/channels/microsoft-copilot-entra-sso.js +285 -0
  24. package/lib/channels/microsoft-copilot-icons.js +74 -0
  25. package/lib/channels/microsoft-copilot-limits.js +103 -0
  26. package/lib/channels/microsoft-copilot-package.js +178 -52
  27. package/lib/channels/microsoft-copilot-validate.js +227 -0
  28. package/lib/cli/attach-default-help-examples.js +102 -0
  29. package/lib/cli/index.js +4 -0
  30. package/lib/cli/infra-guided.js +13 -6
  31. package/lib/cli/setup-credential-deployment.js +7 -5
  32. package/lib/cli/setup-infra.js +31 -4
  33. package/lib/cli/setup-utility-validate.js +1 -0
  34. package/lib/commands/channel-add-setup.js +28 -9
  35. package/lib/commands/channel.js +14 -10
  36. package/lib/commands/credential-push.js +37 -5
  37. package/lib/commands/integration-definition.js +158 -0
  38. package/lib/commands/package-score.js +72 -0
  39. package/lib/commands/repair-auth-apply.js +19 -5
  40. package/lib/commands/repair-datasource-sync-operations.js +4 -1
  41. package/lib/commands/role-assistant-test-output.js +200 -0
  42. package/lib/commands/role-assistant.js +163 -166
  43. package/lib/datasource/capability/capability-resolve.js +15 -5
  44. package/lib/datasource/capability/copy-operations.js +14 -4
  45. package/lib/deployment/deployer-poll-run.js +2 -2
  46. package/lib/deployment/deployer.js +1 -1
  47. package/lib/deployment/environment.js +2 -2
  48. package/lib/external-system/deploy.js +11 -21
  49. package/lib/infrastructure/index.js +19 -4
  50. package/lib/integration-definition/apply.js +476 -0
  51. package/lib/integration-definition/canonical-json.js +51 -0
  52. package/lib/integration-definition/emit-suite-bid.js +94 -0
  53. package/lib/integration-definition/enrich-crm-field-mappings.js +240 -0
  54. package/lib/integration-definition/enrich-openapi-operations.js +433 -0
  55. package/lib/integration-definition/from-discovery.js +339 -0
  56. package/lib/integration-definition/hash.js +37 -0
  57. package/lib/integration-definition/index.js +37 -0
  58. package/lib/integration-definition/resource-type-catalog.js +59 -0
  59. package/lib/integration-definition/system-kind-enum.js +40 -0
  60. package/lib/integration-definition/validate.js +148 -0
  61. package/lib/lab/package-parity-score.js +417 -0
  62. package/lib/programmatic/builder-api-request.js +5 -1
  63. package/lib/programmatic/builder-help-governance.js +3 -2
  64. package/lib/programmatic/capability-registry.js +20 -0
  65. package/lib/programmatic/help-content/channel-onboarding.md +35 -0
  66. package/lib/programmatic/help-content/cip-overview.md +27 -0
  67. package/lib/programmatic/help-content/connected-system-ui.md +70 -0
  68. package/lib/programmatic/help-content/dimensions-guide.md +23 -0
  69. package/lib/programmatic/help-content/enterprise-sync-fabrix.md +123 -0
  70. package/lib/programmatic/help-content/overview.md +25 -0
  71. package/lib/programmatic/help-content/subscription-guide.md +27 -0
  72. package/lib/programmatic/help-content/workflow.md +50 -0
  73. package/lib/programmatic/openapi-component-schemas.js +7 -1
  74. package/lib/programmatic/openapi-descriptions.js +46 -0
  75. package/lib/programmatic/openapi-envelope-examples.js +280 -0
  76. package/lib/programmatic/openapi-operation-bindings.js +50 -0
  77. package/lib/programmatic/openapi-request-schemas.js +40 -0
  78. package/lib/programmatic/openapi-result-schemas-overflow.js +101 -0
  79. package/lib/programmatic/openapi-result-schemas.js +76 -99
  80. package/lib/programmatic/openapi-schema-descriptions-core.js +25 -4
  81. package/lib/programmatic/openapi-schema-descriptions-help.js +1 -1
  82. package/lib/programmatic/openapi-schema-descriptions-operations.js +43 -0
  83. package/lib/programmatic/openapi-schema-helpers.js +9 -9
  84. package/lib/programmatic/openapi-spec.js +11 -1
  85. package/lib/programmatic/orchestration-openapi-meta.js +10 -0
  86. package/lib/programmatic/persist-supplied-openapi.js +180 -0
  87. package/lib/programmatic/route-handler-map.js +35 -1
  88. package/lib/programmatic/run-channel-package.js +236 -0
  89. package/lib/programmatic/run-integration-definition.js +77 -0
  90. package/lib/role-assistant/evidence-sync.js +55 -7
  91. package/lib/role-assistant/knowledge-sync-logging.js +58 -0
  92. package/lib/role-assistant/knowledge-sync.js +88 -93
  93. package/lib/role-assistant/test-cases-bid.js +155 -0
  94. package/lib/role-assistant/test-cases-evaluate.js +9 -1
  95. package/lib/role-assistant/test-cases-honesty.js +24 -10
  96. package/lib/role-assistant/test-cases.js +28 -0
  97. package/lib/role-assistant/test-runner-attachments.js +118 -0
  98. package/lib/role-assistant/test-runner-bid-apply.js +201 -0
  99. package/lib/role-assistant/test-runner-bid-document.js +278 -0
  100. package/lib/role-assistant/test-runner-start-payload.js +96 -0
  101. package/lib/role-assistant/test-runner-workhub-answers.js +249 -20
  102. package/lib/role-assistant/test-runner-workhub-helpers.js +100 -0
  103. package/lib/role-assistant/test-runner-workhub-soft.js +86 -0
  104. package/lib/role-assistant/test-runner-workhub.js +152 -107
  105. package/lib/role-assistant/test-runner.js +5 -63
  106. package/lib/role-assistant/test-suite.js +112 -0
  107. package/lib/schema/application-schema.json +56 -6
  108. package/lib/schema/external-datasource.schema.json +103 -17
  109. package/lib/schema/external-system.schema.json +54 -3
  110. package/lib/schema/integration-definition.schema.json +195 -0
  111. package/lib/utils/authentication-shape.js +6 -0
  112. package/lib/utils/compose-generator.js +10 -1
  113. package/lib/utils/compose-traefik-extra-routes.js +107 -0
  114. package/lib/utils/docker-build.js +2 -2
  115. package/lib/utils/help-builder.js +3 -1
  116. package/lib/utils/promote-dev-docker-image.js +102 -18
  117. package/lib/utils/transient-developer-id.js +28 -0
  118. package/package.json +14 -16
  119. package/templates/README.md +12 -1
  120. package/templates/applications/dataplane/application.yaml +10 -2
  121. package/templates/applications/dataplane/env.template +7 -6
  122. package/templates/applications/miso-controller/application.yaml +23 -8
  123. package/templates/applications/miso-controller/env.template +8 -2
  124. package/templates/applications/miso-controller/rbac.yaml +1 -0
  125. package/templates/channels/README.md +11 -1
  126. package/templates/channels/brand/color-192.png +0 -0
  127. package/templates/channels/brand/dark/128.png +0 -0
  128. package/templates/channels/brand/dark/192.png +0 -0
  129. package/templates/channels/brand/dark/256.png +0 -0
  130. package/templates/channels/brand/dark/32.png +0 -0
  131. package/templates/channels/brand/dark/512.png +0 -0
  132. package/templates/channels/brand/dark/64.png +0 -0
  133. package/templates/channels/brand/light/128.png +0 -0
  134. package/templates/channels/brand/light/192.png +0 -0
  135. package/templates/channels/brand/light/256.png +0 -0
  136. package/templates/channels/brand/light/32.png +0 -0
  137. package/templates/channels/brand/light/512.png +0 -0
  138. package/templates/channels/brand/light/64.png +0 -0
  139. package/templates/channels/brand/mono-white/128.png +0 -0
  140. package/templates/channels/brand/mono-white/192.png +0 -0
  141. package/templates/channels/brand/mono-white/256.png +0 -0
  142. package/templates/channels/brand/mono-white/32.png +0 -0
  143. package/templates/channels/brand/mono-white/512.png +0 -0
  144. package/templates/channels/brand/mono-white/64.png +0 -0
  145. package/templates/channels/brand/outline-32.png +0 -0
  146. package/templates/channels/chatgpt/install.template.md.hbs +6 -4
  147. package/templates/channels/chatgpt/integration/README.md +4 -5
  148. package/templates/channels/chatgpt/integration/chatgpt-system.json +1 -16
  149. package/templates/channels/microsoft-copilot/ai-plugin.template.json.hbs +14 -16
  150. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +5 -3
  151. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +30 -0
  152. package/templates/channels/microsoft-copilot/fi-fi.template.json.hbs +7 -0
  153. package/templates/channels/microsoft-copilot/install.template.md.hbs +93 -22
  154. package/templates/channels/microsoft-copilot/integration/README.md +2 -3
  155. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +1 -22
  156. package/templates/channels/microsoft-copilot/manifest.template.json.hbs +34 -19
  157. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +15 -0
  158. package/templates/channels/slack/integration/README.md +2 -4
  159. package/templates/channels/teams-bot/install.template.md.hbs +4 -0
  160. package/templates/channels/teams-bot/integration/README.md +3 -5
  161. package/templates/channels/web-embed/integration/web-embed-system.json +1 -16
  162. package/templates/python/docker-compose.hbs +36 -0
  163. package/templates/typescript/docker-compose.hbs +36 -0
  164. package/.cursor/plans/Done/157.1-security-quality-violations-by-type.csv +0 -374
  165. package/.cursor/process/README.md +0 -9
  166. package/.cursor/rules/anchor-docs.mdc +0 -15
  167. package/.cursor/rules/assistant-driven-integration-build.mdc +0 -40
  168. package/.cursor/rules/cli-layout.mdc +0 -81
  169. package/.cursor/rules/cli-product-neutral.mdc +0 -43
  170. package/.cursor/rules/deploy-rules/docker-image-ip-policy.mdc +0 -49
  171. package/.cursor/rules/docs-rules.mdc +0 -32
  172. package/.cursor/rules/plan-rules/application-lifecycle.mdc +0 -30
  173. package/.cursor/rules/plan-rules/plan-frontmatter.mdc +0 -35
  174. package/.cursor/rules/plan-rules/plan-lifecycle.mdc +0 -31
  175. package/.cursor/rules/plan-rules/plan-validation-gate.mdc +0 -34
  176. package/.cursor/rules/project-rules.mdc +0 -913
  177. package/.cursor/skills/README.md +0 -15
  178. package/.dockerignore +0 -52
  179. package/.eslintignore +0 -22
  180. package/.markdownlint.json +0 -14
  181. package/anchor-docs/README.md +0 -10
  182. package/anchor-docs/_TEMPLATE +0 -24
  183. package/babel.config.js +0 -6
  184. package/bin/builder-api-cleanup.js +0 -26
  185. package/bin/builder-api-nest.js +0 -10
  186. package/bin/builder-api-spike.js +0 -19
  187. package/enterprise-knowledge/README.md +0 -50
  188. package/enterprise-knowledge/enterprise-integration-lifecycle/README.md +0 -22
  189. package/enterprise-knowledge/enterprise-integration-lifecycle/application.json +0 -15
  190. package/enterprise-knowledge/enterprise-integration-lifecycle/deploy.js +0 -69
  191. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-deploy.json +0 -52
  192. package/enterprise-knowledge/enterprise-integration-lifecycle/enterprise-integration-lifecycle-system.json +0 -29
  193. package/enterprise-knowledge/enterprise-integration-lifecycle/env.template +0 -2
  194. package/integration/README.md +0 -81
  195. package/integration/github/README.md +0 -53
  196. package/integration/github/application.json +0 -21
  197. package/integration/github/deploy.js +0 -72
  198. package/integration/github/env.template +0 -11
  199. package/integration/github/github-datasource-issue-comments.json +0 -239
  200. package/integration/github/github-datasource-issues.json +0 -399
  201. package/integration/github/github-datasource-repository.json +0 -354
  202. package/integration/github/github-deploy.json +0 -1202
  203. package/integration/github/github-system.json +0 -82
  204. package/integration/hubspot-test/README.md +0 -159
  205. package/integration/hubspot-test/application.json +0 -54
  206. package/integration/hubspot-test/companies.json +0 -2048
  207. package/integration/hubspot-test/create-hubspot.js +0 -523
  208. package/integration/hubspot-test/env.template +0 -4
  209. package/integration/hubspot-test/hubspot-test-datasource-company.json +0 -138
  210. package/integration/hubspot-test/hubspot-test-datasource-contact.json +0 -146
  211. package/integration/hubspot-test/hubspot-test-datasource-deal.json +0 -146
  212. package/integration/hubspot-test/hubspot-test-datasource-users.json +0 -76
  213. package/integration/hubspot-test/hubspot-test-deploy.json +0 -2160
  214. package/integration/hubspot-test/hubspot-test-system.json +0 -74
  215. package/integration/hubspot-test/rbac.json +0 -166
  216. package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +0 -20
  217. package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +0 -9
  218. package/integration/hubspot-test/test-artifacts/wizard-invalid-add-datasource.yaml +0 -5
  219. package/integration/hubspot-test/test-artifacts/wizard-invalid-app-name.yaml +0 -5
  220. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-create.yaml +0 -7
  221. package/integration/hubspot-test/test-artifacts/wizard-invalid-credential-select.yaml +0 -7
  222. package/integration/hubspot-test/test-artifacts/wizard-invalid-known-platform.yaml +0 -4
  223. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-app.yaml +0 -4
  224. package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
  225. package/integration/hubspot-test/test-artifacts/wizard-invalid-mode.yaml +0 -5
  226. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-file.yaml +0 -5
  227. package/integration/hubspot-test/test-artifacts/wizard-invalid-openapi-url.yaml +0 -4
  228. package/integration/hubspot-test/test-artifacts/wizard-invalid-source.yaml +0 -4
  229. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-array-test.yaml +0 -5
  230. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
  231. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
  232. package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-test.yaml +0 -5
  233. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-test.yaml +0 -5
  234. package/integration/hubspot-test/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +0 -5
  235. package/integration/hubspot-test/test-dataplane-down-helpers.js +0 -249
  236. package/integration/hubspot-test/test-dataplane-down-tests.js +0 -386
  237. package/integration/hubspot-test/test-dataplane-down.js +0 -209
  238. package/integration/hubspot-test/test.js +0 -1588
  239. package/integration/hubspot-test/wizard-hubspot-e2e.yaml +0 -16
  240. package/integration/hubspot-test/wizard-hubspot-platform.yaml +0 -8
  241. package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +0 -23
  242. package/integration/roundtrip-test-local/README.md +0 -143
  243. package/integration/roundtrip-test-local/application.yaml +0 -13
  244. package/integration/roundtrip-test-local/env.template +0 -15
  245. package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +0 -14
  246. package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +0 -61
  247. package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +0 -25
  248. package/integration/roundtrip-test-local2/README.md +0 -143
  249. package/integration/roundtrip-test-local2/application.yaml +0 -13
  250. package/integration/roundtrip-test-local2/env.template +0 -15
  251. package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +0 -31
  252. package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +0 -86
  253. package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +0 -25
  254. package/integration/test/wizard.yaml +0 -8
  255. package/jest.config.coverage.js +0 -37
  256. package/jest.config.default.js +0 -11
  257. package/jest.config.integration.fixtures.js +0 -22
  258. package/jest.config.integration.js +0 -33
  259. package/jest.config.isolated.js +0 -11
  260. package/jest.config.manual.js +0 -30
  261. package/jest.global-live-fabrix-hooks.js +0 -36
  262. package/jest.isolated-projects.js +0 -260
  263. package/jest.projects.js +0 -76
  264. package/packages/builder-api/README.md +0 -120
  265. package/packages/builder-api/package.json +0 -30
  266. package/packages/builder-api/src/app.module.ts +0 -7
  267. package/packages/builder-api/src/auth/auth.module.ts +0 -5
  268. package/packages/builder-api/src/external-system/external-system.module.ts +0 -5
  269. package/packages/builder-api/src/main.ts +0 -16
  270. package/packages/builder-api/tsconfig.json +0 -15
  271. package/scripts/check-builder-api-architecture-grep.js +0 -79
  272. package/scripts/check-datasource-test-run-schema-sync.js +0 -34
  273. package/scripts/ci-fix.sh +0 -19
  274. package/scripts/ci-simulate.sh +0 -19
  275. package/scripts/diagnose-cli.js +0 -150
  276. package/scripts/docker_image_content_gate.js +0 -47
  277. package/scripts/docker_image_content_gate.sh +0 -5
  278. package/scripts/export-builder-api-evidence.js +0 -262
  279. package/scripts/install-local.js +0 -490
  280. package/scripts/lib/builder-api-docker-staging-copy.js +0 -60
  281. package/scripts/lib/builder-api-docker-staging-core.js +0 -183
  282. package/scripts/lib/docker-image-content-gate-core.js +0 -166
  283. package/scripts/lib/plan-actor.js +0 -109
  284. package/scripts/lib/plan-config.js +0 -20
  285. package/scripts/lib/plan-gates.js +0 -154
  286. package/scripts/lib/plan-meta.js +0 -104
  287. package/scripts/lib/plan-parse.js +0 -162
  288. package/scripts/lib/plan-prevalidate-gates.js +0 -337
  289. package/scripts/lib/plan-run-core.js +0 -125
  290. package/scripts/lib/plan-run-report.js +0 -119
  291. package/scripts/plan-approve.js +0 -24
  292. package/scripts/plan-archive.js +0 -49
  293. package/scripts/plan-run.js +0 -13
  294. package/scripts/plan-set-actor.js +0 -21
  295. package/scripts/plan-validate.js +0 -80
  296. package/scripts/pnpm/af.mjs +0 -110
  297. package/scripts/pnpm/check-quiet.mjs +0 -32
  298. package/scripts/pnpm/dev-install.mjs +0 -29
  299. package/scripts/pnpm/dev-reload.mjs +0 -18
  300. package/scripts/pnpm/help.mjs +0 -55
  301. package/scripts/pnpm/lib/dev-reload-core.mjs +0 -189
  302. package/scripts/pnpm/lib/dev-reload-log-capture.mjs +0 -67
  303. package/scripts/pnpm/lib/dev-reload-log-utils.mjs +0 -32
  304. package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +0 -124
  305. package/scripts/pnpm/lib/resolve-app-url.mjs +0 -183
  306. package/scripts/pnpm/lib/spinner.mjs +0 -42
  307. package/scripts/pnpm-global-remove.js +0 -48
  308. package/scripts/stage_builder_api_for_docker.js +0 -65
  309. package/scripts/sync-builder-api-template.js +0 -44
  310. 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 capability.handlerId !== 'health' && capability.handlerId !== 'ready';
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