@aifabrix/builder 2.53.0 → 2.54.1

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 (321) hide show
  1. package/bin/aifabrix.js +2 -2
  2. package/lib/api/assistants.api.js +8 -5
  3. package/lib/api/channel-identity.api.js +41 -0
  4. package/lib/api/evidence-authoring.api.js +5 -1
  5. package/lib/api/evidence.api.js +2 -0
  6. package/lib/api/types/evidence.types.js +2 -0
  7. package/lib/api/work-search.api.js +136 -0
  8. package/lib/channels/add-channel.js +163 -126
  9. package/lib/channels/approval-guides/chatgpt.js +14 -18
  10. package/lib/channels/approval-guides/claude.js +29 -0
  11. package/lib/channels/approval-guides/index.js +88 -22
  12. package/lib/channels/approval-guides/mcp-client.js +27 -0
  13. package/lib/channels/approval-guides/microsoft-copilot.js +52 -3
  14. package/lib/channels/approval-guides/slack.js +10 -10
  15. package/lib/channels/approval-guides/teams-bot.js +8 -12
  16. package/lib/channels/channel-add-continuations.js +91 -0
  17. package/lib/channels/channel-add-ensure.js +124 -27
  18. package/lib/channels/channel-add-existing.js +160 -28
  19. package/lib/channels/channel-add-failure.js +60 -0
  20. package/lib/channels/channel-add-remaining.js +486 -0
  21. package/lib/channels/channel-add-tty.js +190 -0
  22. package/lib/channels/channel-add-wizard-config.js +138 -0
  23. package/lib/channels/channel-add-wizard.js +250 -0
  24. package/lib/channels/channel-artifact-generator.js +27 -13
  25. package/lib/channels/channel-cardinality.js +83 -0
  26. package/lib/channels/channel-catalog-icon.js +45 -0
  27. package/lib/channels/channel-cli-instructions.js +75 -0
  28. package/lib/channels/channel-configuration-map.js +213 -0
  29. package/lib/channels/channel-credential.js +11 -14
  30. package/lib/channels/channel-definition-project.js +101 -0
  31. package/lib/channels/channel-definition-registry.js +154 -0
  32. package/lib/channels/channel-description.js +59 -2
  33. package/lib/channels/channel-discovery.js +16 -2
  34. package/lib/channels/channel-external-system.js +86 -9
  35. package/lib/channels/channel-install-envelope-actions.js +88 -0
  36. package/lib/channels/channel-install-envelope-microsoft.js +155 -0
  37. package/lib/channels/channel-install-envelope.js +356 -0
  38. package/lib/channels/channel-install-help-md.js +172 -0
  39. package/lib/channels/channel-install-http-payload.js +62 -0
  40. package/lib/channels/channel-install-inventory.js +115 -0
  41. package/lib/channels/channel-install-profiles.js +90 -0
  42. package/lib/channels/channel-instance-collision.js +118 -0
  43. package/lib/channels/channel-instance-key.js +100 -0
  44. package/lib/channels/channel-instance-materialize.js +240 -0
  45. package/lib/channels/channel-integration-generator.js +16 -9
  46. package/lib/channels/channel-integration-template.js +101 -22
  47. package/lib/channels/channel-inventory-fetch.js +79 -0
  48. package/lib/channels/channel-oauth-preflight.js +104 -0
  49. package/lib/channels/channel-package-version.js +76 -0
  50. package/lib/channels/channel-predefined-client.js +154 -0
  51. package/lib/channels/channel-probe.js +7 -2
  52. package/lib/channels/channel-runtime-resolver.js +180 -72
  53. package/lib/channels/channel-status-display.js +86 -16
  54. package/lib/channels/channel-targets.js +106 -92
  55. package/lib/channels/chatgpt-callback.js +318 -0
  56. package/lib/channels/chatgpt-channel-add.js +229 -0
  57. package/lib/channels/chatgpt-preflight.js +396 -0
  58. package/lib/channels/chatgpt-runtime-contract.js +17 -0
  59. package/lib/channels/chatgpt-setup-values.js +124 -0
  60. package/lib/channels/claude-callback.js +67 -0
  61. package/lib/channels/claude-channel-add.js +254 -0
  62. package/lib/channels/claude-runtime-contract.js +40 -0
  63. package/lib/channels/claude-runtime.js +58 -0
  64. package/lib/channels/claude-setup-values.js +89 -0
  65. package/lib/channels/mcp-client/config-merge.js +148 -0
  66. package/lib/channels/mcp-client/ensure-client.js +231 -0
  67. package/lib/channels/mcp-client/paths.js +53 -0
  68. package/lib/channels/mcp-client/profiles.js +122 -0
  69. package/lib/channels/mcp-client/redirect-uris.js +99 -0
  70. package/lib/channels/mcp-client/runtime.js +59 -0
  71. package/lib/channels/mcp-client-channel-add.js +186 -0
  72. package/lib/channels/microsoft-copilot-channel-add.js +117 -7
  73. package/lib/channels/microsoft-copilot-entra-identifier-uris.js +187 -0
  74. package/lib/channels/microsoft-copilot-entra-sso-form.js +106 -18
  75. package/lib/channels/microsoft-copilot-entra-sso.js +31 -2
  76. package/lib/channels/microsoft-copilot-package-prior.js +107 -0
  77. package/lib/channels/microsoft-copilot-package.js +29 -28
  78. package/lib/channels/microsoft-provisioning/a365.js +80 -0
  79. package/lib/channels/microsoft-provisioning/auth-config.js +240 -0
  80. package/lib/channels/microsoft-provisioning/auth.js +179 -0
  81. package/lib/channels/microsoft-provisioning/cli.js +71 -0
  82. package/lib/channels/microsoft-provisioning/constants.js +75 -0
  83. package/lib/channels/microsoft-provisioning/errors.js +117 -0
  84. package/lib/channels/microsoft-provisioning/index.js +55 -0
  85. package/lib/channels/microsoft-provisioning/install-atk.js +158 -0
  86. package/lib/channels/microsoft-provisioning/install-teams.js +115 -0
  87. package/lib/channels/microsoft-provisioning/login-portal-device.js +236 -0
  88. package/lib/channels/microsoft-provisioning/login-portal-parse.js +71 -0
  89. package/lib/channels/microsoft-provisioning/login-portal-teams.js +193 -0
  90. package/lib/channels/microsoft-provisioning/login-portal.js +230 -0
  91. package/lib/channels/microsoft-provisioning/persist.js +110 -0
  92. package/lib/channels/microsoft-provisioning/teams-bot-args.js +119 -0
  93. package/lib/channels/microsoft-provisioning/teams-bot-controller.js +123 -0
  94. package/lib/channels/microsoft-provisioning/teams-bot-parse.js +134 -0
  95. package/lib/channels/microsoft-provisioning/teams-bot-persist.js +113 -0
  96. package/lib/channels/microsoft-provisioning/teams-bot-provision.js +234 -0
  97. package/lib/channels/microsoft-provisioning/teams-bot-secrets.js +45 -0
  98. package/lib/channels/microsoft-provisioning/teams-cli.js +82 -0
  99. package/lib/channels/runtime-tool-catalog.js +5 -2
  100. package/lib/channels/slack-channel-add-portal.js +130 -0
  101. package/lib/channels/slack-channel-add-tty-auth.js +95 -0
  102. package/lib/channels/slack-channel-add.js +258 -0
  103. package/lib/channels/slack-provisioning/apps.js +181 -0
  104. package/lib/channels/slack-provisioning/auth-store.js +110 -0
  105. package/lib/channels/slack-provisioning/auth-ticket.js +185 -0
  106. package/lib/channels/slack-provisioning/auth.js +115 -0
  107. package/lib/channels/slack-provisioning/callbacks.js +41 -0
  108. package/lib/channels/slack-provisioning/cli.js +226 -0
  109. package/lib/channels/slack-provisioning/constants.js +37 -0
  110. package/lib/channels/slack-provisioning/credentials.js +169 -0
  111. package/lib/channels/slack-provisioning/curl-shim.js +132 -0
  112. package/lib/channels/slack-provisioning/developer-install.js +118 -0
  113. package/lib/channels/slack-provisioning/env-file.js +120 -0
  114. package/lib/channels/slack-provisioning/errors.js +47 -0
  115. package/lib/channels/slack-provisioning/go-ca-bundle.js +137 -0
  116. package/lib/channels/slack-provisioning/index.js +250 -0
  117. package/lib/channels/slack-provisioning/install-cli.js +323 -0
  118. package/lib/channels/slack-provisioning/manifest.js +89 -0
  119. package/lib/channels/slack-provisioning/oauth-lock.js +33 -0
  120. package/lib/channels/slack-provisioning/offer-cli.js +113 -0
  121. package/lib/channels/slack-provisioning/onboard-members.js +122 -0
  122. package/lib/channels/slack-provisioning/onboard.js +89 -0
  123. package/lib/channels/slack-provisioning/persist.js +95 -0
  124. package/lib/channels/slack-provisioning/remaining-urls.js +158 -0
  125. package/lib/channels/slack-provisioning/with-curl-on-path.js +48 -0
  126. package/lib/channels/teams-bot-channel-add.js +94 -0
  127. package/lib/channels/vendor-dataplane-url.js +249 -0
  128. package/lib/cli/setup-certification.help.js +2 -0
  129. package/lib/cli/setup-external-system-help.js +2 -0
  130. package/lib/cli/setup-external-system.js +1 -1
  131. package/lib/commands/channel-add-help.js +366 -0
  132. package/lib/commands/channel-add-setup.js +162 -80
  133. package/lib/commands/channel-configure.js +118 -0
  134. package/lib/commands/channel.js +10 -1
  135. package/lib/commands/governance-upload-external.js +6 -3
  136. package/lib/commands/lifecycle-command-action.js +2 -5
  137. package/lib/commands/lifecycle-external.js +93 -21
  138. package/lib/commands/repair-datasource-test-payload.js +4 -2
  139. package/lib/commands/repair-datasource-webhooks-sync-bridge.js +23 -2
  140. package/lib/commands/repair-datasource.js +3 -0
  141. package/lib/commands/repair-external-run.js +59 -25
  142. package/lib/commands/repair-openapi-rest-runtime.js +127 -0
  143. package/lib/commands/repair-orchestration-tag-merge.js +339 -0
  144. package/lib/commands/repair-rbac-catalog-defaults.js +96 -0
  145. package/lib/commands/repair-rbac-platform-preset.js +26 -15
  146. package/lib/commands/repair-rbac-reader-roles.js +8 -21
  147. package/lib/commands/repair-rbac.js +10 -34
  148. package/lib/commands/repair-system-permissions.js +24 -22
  149. package/lib/commands/role-assistant-test-output.js +14 -0
  150. package/lib/commands/role-assistant.js +59 -21
  151. package/lib/commands/test-e2e-external.js +148 -21
  152. package/lib/commands/upload-credential-push-log.js +2 -1
  153. package/lib/commands/upload-publish-context.js +1 -1
  154. package/lib/commands/upload-role-assistant-shell.js +124 -0
  155. package/lib/commands/upload-sidecar-followups.js +6 -3
  156. package/lib/commands/upload.js +18 -3
  157. package/lib/core/secrets-docker-env.js +4 -1
  158. package/lib/core/secrets-env-content.js +17 -3
  159. package/lib/datasource/capability/capability-manifest.js +0 -3
  160. package/lib/datasource/capability/copy-test-payload.js +3 -0
  161. package/lib/external-system/deploy-helpers.js +26 -1
  162. package/lib/external-system/deploy.js +10 -6
  163. package/lib/external-system/download-helpers.js +29 -2
  164. package/lib/external-system/download-role-assistant.js +83 -4
  165. package/lib/external-system/download.js +40 -30
  166. package/lib/external-system/sync-deploy-manifest.js +3 -2
  167. package/lib/external-system/upload-identity.js +42 -0
  168. package/lib/generator/index.js +19 -15
  169. package/lib/generator/split.js +13 -2
  170. package/lib/lifecycle/role-assistant-governance.js +146 -0
  171. package/lib/lifecycle/scenario-upload.js +181 -30
  172. package/lib/programmatic/builder-api-cors.js +143 -0
  173. package/lib/programmatic/builder-api-request.js +6 -0
  174. package/lib/programmatic/builder-api-route-dispatch.js +56 -42
  175. package/lib/programmatic/builder-api-server.js +8 -1
  176. package/lib/programmatic/capability-registry.js +54 -0
  177. package/lib/programmatic/channel-install-help-resolve.js +359 -0
  178. package/lib/programmatic/channel-install-session.js +218 -0
  179. package/lib/programmatic/help-content/channel-onboarding.md +2 -0
  180. package/lib/programmatic/help-content/cip-overview.md +3 -1
  181. package/lib/programmatic/http-raw-response.js +62 -0
  182. package/lib/programmatic/openapi-channel-install-bindings.js +179 -0
  183. package/lib/programmatic/openapi-channel-install-schemas.js +286 -0
  184. package/lib/programmatic/openapi-component-schemas.js +18 -1
  185. package/lib/programmatic/openapi-description-enricher.js +3 -1
  186. package/lib/programmatic/openapi-descriptions.js +74 -3
  187. package/lib/programmatic/openapi-envelope-examples.js +117 -0
  188. package/lib/programmatic/openapi-operation-bindings.js +4 -1
  189. package/lib/programmatic/openapi-schema-descriptions-channel.js +316 -0
  190. package/lib/programmatic/openapi-spec.js +12 -8
  191. package/lib/programmatic/platform-rbac-catalog.js +36 -18
  192. package/lib/programmatic/route-handler-map.js +51 -1
  193. package/lib/programmatic/route-handlers-context.js +2 -1
  194. package/lib/programmatic/run-auth-permissions.js +54 -0
  195. package/lib/programmatic/run-channel-catalog.js +196 -0
  196. package/lib/programmatic/run-channel-install-artifacts.js +137 -0
  197. package/lib/programmatic/run-channel-install-copilot.js +353 -0
  198. package/lib/programmatic/run-channel-install-options.js +232 -0
  199. package/lib/programmatic/run-channel-install-teams-bot.js +204 -0
  200. package/lib/programmatic/run-channel-install.js +346 -0
  201. package/lib/programmatic/run-channel-package.js +87 -7
  202. package/lib/programmatic/workspace-context.js +2 -0
  203. package/lib/role-assistant/evidence-sync.js +4 -2
  204. package/lib/role-assistant/evidence-validation-issues.js +51 -0
  205. package/lib/role-assistant/knowledge-sync.js +10 -4
  206. package/lib/role-assistant/settings.js +49 -2
  207. package/lib/role-assistant/test-cases-evaluate.js +30 -2
  208. package/lib/role-assistant/test-cases-evidence.js +175 -0
  209. package/lib/role-assistant/test-cases-search.js +229 -0
  210. package/lib/role-assistant/test-cases.js +37 -4
  211. package/lib/role-assistant/test-runner-search.js +149 -0
  212. package/lib/role-assistant/test-runner-workhub-helpers.js +40 -2
  213. package/lib/role-assistant/test-runner-workhub-soft.js +9 -3
  214. package/lib/role-assistant/test-runner-workhub.js +29 -11
  215. package/lib/role-assistant/test-runner.js +16 -1
  216. package/lib/schema/external-datasource.schema.json +119 -16
  217. package/lib/schema/external-system.schema.json +159 -2
  218. package/lib/schema/mcp-client-profile.schema.json +103 -0
  219. package/lib/utils/app-path-resolve.js +4 -0
  220. package/lib/utils/authentication-env-template.js +44 -6
  221. package/lib/utils/credential-secrets-env.js +6 -1
  222. package/lib/utils/env-copy.js +19 -7
  223. package/lib/utils/external-env-template.js +20 -2
  224. package/lib/utils/paths.js +18 -1
  225. package/lib/utils/platform-shell-package.js +69 -0
  226. package/lib/utils/port-resolver.js +50 -1
  227. package/lib/utils/rewrite-name-flag.js +20 -0
  228. package/lib/utils/role-assistant-paths.js +13 -10
  229. package/lib/utils/schema-resolver.js +11 -1
  230. package/lib/utils/secrets-helpers.js +12 -21
  231. package/lib/utils/token-manager.js +10 -5
  232. package/lib/validation/validate.js +40 -0
  233. package/package.json +1 -1
  234. package/templates/README.md +1 -1
  235. package/templates/applications/builder-api/Dockerfile +1 -1
  236. package/templates/applications/builder-api/env.template +7 -0
  237. package/templates/applications/dataplane/application.yaml +6 -5
  238. package/templates/applications/dataplane/env.template +2 -2
  239. package/templates/applications/dataplane/rbac.yaml +7 -2
  240. package/templates/applications/keycloak/Dockerfile +30 -4
  241. package/templates/applications/keycloak/application.yaml +2 -2
  242. package/templates/applications/keycloak/cimd-lenient-parse/AbstractClientIdMetadataDocumentExecutor.java +896 -0
  243. package/templates/applications/keycloak/cimd-lenient-parse/SOURCE.md +19 -0
  244. package/templates/applications/keycloak/env.template +3 -0
  245. package/templates/applications/miso-controller/application.yaml +1 -2
  246. package/templates/applications/miso-controller/env.template +2 -0
  247. package/templates/channels/README.md +5 -5
  248. package/templates/channels/chatgpt/TROUBLESHOOTING.md +51 -0
  249. package/templates/channels/chatgpt/channel.json +59 -0
  250. package/templates/channels/chatgpt/icon.svg +1 -0
  251. package/templates/channels/chatgpt/install.template.md.hbs +20 -95
  252. package/templates/channels/chatgpt/integration/README.md +1 -1
  253. package/templates/channels/chatgpt/integration/application.json +2 -2
  254. package/templates/channels/chatgpt/integration/chatgpt-system.json +49 -4
  255. package/templates/channels/chatgpt/integration/env.template +2 -4
  256. package/templates/channels/chatgpt/integration/rbac.json +13 -0
  257. package/templates/channels/claude/TROUBLESHOOTING.md +41 -0
  258. package/templates/channels/claude/channel.json +59 -0
  259. package/templates/channels/claude/icon.svg +1 -0
  260. package/templates/channels/claude/install.template.md.hbs +21 -0
  261. package/templates/channels/claude/integration/README.md +14 -0
  262. package/templates/channels/claude/integration/application.json +15 -0
  263. package/templates/channels/claude/integration/claude-system.json +59 -0
  264. package/templates/channels/claude/integration/env.template +2 -0
  265. package/templates/channels/claude/integration/rbac.json +13 -0
  266. package/templates/channels/claude/manifest.template.json.hbs +40 -0
  267. package/templates/channels/mcp-client/channel.json +72 -0
  268. package/templates/channels/mcp-client/icon.svg +1 -0
  269. package/templates/channels/mcp-client/install.template.md.hbs +24 -0
  270. package/templates/channels/mcp-client/integration/README.md +13 -0
  271. package/templates/channels/mcp-client/integration/application.json +15 -0
  272. package/templates/channels/mcp-client/integration/env.template +2 -0
  273. package/templates/channels/mcp-client/integration/mcp-client-system.json +72 -0
  274. package/templates/channels/mcp-client/integration/rbac.json +13 -0
  275. package/templates/channels/mcp-client/manifest.template.json.hbs +41 -0
  276. package/templates/channels/mcp-client/profiles/cursor.json +26 -0
  277. package/templates/channels/mcp-client/profiles/github-copilot.json +29 -0
  278. package/templates/channels/mcp-client/profiles/vscode.json +29 -0
  279. package/templates/channels/microsoft-copilot/channel.json +73 -0
  280. package/templates/channels/microsoft-copilot/declarative-agent.template.json.hbs +8 -4
  281. package/templates/channels/microsoft-copilot/entra-sso-registration.template.md.hbs +65 -5
  282. package/templates/channels/microsoft-copilot/icon.svg +1 -0
  283. package/templates/channels/microsoft-copilot/install.template.md.hbs +9 -9
  284. package/templates/channels/microsoft-copilot/integration/README.md +1 -1
  285. package/templates/channels/microsoft-copilot/integration/application.json +2 -2
  286. package/templates/channels/microsoft-copilot/integration/env.template +3 -6
  287. package/templates/channels/microsoft-copilot/integration/microsoft-copilot-system.json +63 -4
  288. package/templates/channels/microsoft-copilot/integration/rbac.json +13 -0
  289. package/templates/channels/microsoft-copilot/oauth-plugin-vault-required.template.md.hbs +5 -5
  290. package/templates/channels/slack/channel.json +223 -0
  291. package/templates/channels/slack/icon.svg +1 -0
  292. package/templates/channels/slack/install.template.md.hbs +36 -28
  293. package/templates/channels/slack/integration/README.md +245 -22
  294. package/templates/channels/slack/integration/application.json +44 -7
  295. package/templates/channels/slack/integration/env.template +15 -6
  296. package/templates/channels/slack/integration/openapi/openapi.json +126 -0
  297. package/templates/channels/slack/integration/rbac.json +84 -0
  298. package/templates/channels/slack/integration/slack-datasource-commands.json +154 -0
  299. package/templates/channels/slack/integration/slack-datasource-conversations.json +28 -3
  300. package/templates/channels/slack/integration/slack-datasource-events.json +154 -0
  301. package/templates/channels/slack/integration/slack-datasource-interactive.json +154 -0
  302. package/templates/channels/slack/integration/slack-datasource-messages.json +40 -2
  303. package/templates/channels/slack/integration/slack-system.json +155 -77
  304. package/templates/channels/slack/manifest.template.json.hbs +5 -2
  305. package/templates/channels/teams-bot/channel.json +161 -0
  306. package/templates/channels/teams-bot/icon.svg +1 -0
  307. package/templates/channels/teams-bot/install.template.md.hbs +12 -13
  308. package/templates/channels/teams-bot/integration/README.md +5 -4
  309. package/templates/channels/teams-bot/integration/application.json +6 -4
  310. package/templates/channels/teams-bot/integration/env.template +5 -4
  311. package/templates/channels/teams-bot/integration/openapi/openapi.json +68 -0
  312. package/templates/channels/teams-bot/integration/rbac.json +21 -0
  313. package/templates/channels/teams-bot/integration/teams-bot-datasource-activities.json +154 -0
  314. package/templates/channels/teams-bot/integration/teams-bot-system.json +128 -23
  315. package/templates/channels/web-embed/channel.json +60 -0
  316. package/templates/channels/web-embed/install.template.md.hbs +1 -1
  317. package/templates/channels/web-embed/integration/README.md +2 -2
  318. package/templates/channels/web-embed/integration/application.json +2 -2
  319. package/templates/channels/web-embed/integration/env.template +1 -1
  320. package/templates/channels/web-embed/integration/rbac.json +13 -0
  321. package/templates/channels/web-embed/integration/web-embed-system.json +50 -4
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Optional Slack user onboard after channel add (email join).
3
+ *
4
+ * @fileoverview One yes/no question; no member dump on default TTY
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { isChannelAddInteractive } = require('../channel-add-wizard');
10
+ const { upsertChannelIdentityMappings } = require('../../api/channel-identity.api');
11
+ const { confirmYesNo } = require('./offer-cli');
12
+ const { listSlackWorkspaceMembers, matchSlackMembersToUsers } = require('./onboard-members');
13
+
14
+ /**
15
+ * @param {Object} [options]
16
+ * @returns {boolean}
17
+ */
18
+ function shouldSkipOnboard(options = {}) {
19
+ if (options.dryRun === true) {
20
+ return true;
21
+ }
22
+ if (options.onboardUsers === false) {
23
+ return true;
24
+ }
25
+ return false;
26
+ }
27
+
28
+ /**
29
+ * @param {Object} [options]
30
+ * @param {Object} [deps]
31
+ * @returns {Promise<boolean>}
32
+ */
33
+ async function shouldOnboardUsers(options = {}, deps = {}) {
34
+ if (shouldSkipOnboard(options)) {
35
+ return false;
36
+ }
37
+ if (options.onboardUsers === true) {
38
+ return true;
39
+ }
40
+ if (!isChannelAddInteractive(options)) {
41
+ return false;
42
+ }
43
+ return confirmYesNo('Onboard users?', deps);
44
+ }
45
+
46
+ /**
47
+ * @param {number} unmatched
48
+ * @returns {string|null}
49
+ */
50
+ function unmatchedRemainingStep(unmatched) {
51
+ const count = Number(unmatched) || 0;
52
+ if (count <= 0) {
53
+ return null;
54
+ }
55
+ return `${count} Slack users still use Link account (no email match)`;
56
+ }
57
+
58
+ /**
59
+ * @param {Object} params
60
+ * @param {Object} [deps]
61
+ * @returns {Promise<{ ran: boolean, linked: number, unmatched: number }>}
62
+ */
63
+ async function maybeOnboardSlackUsers(params = {}, deps = {}) {
64
+ const options = params.options || {};
65
+ const ctx = params.ctx || {};
66
+ if (ctx.slackConnected !== true && options.onboardUsers !== true) {
67
+ return { ran: false, linked: 0, unmatched: 0 };
68
+ }
69
+ if (!(await shouldOnboardUsers(options, deps))) {
70
+ return { ran: false, linked: 0, unmatched: 0 };
71
+ }
72
+ const members = await listSlackWorkspaceMembers(deps);
73
+ const matched = await matchSlackMembersToUsers(members, ctx, deps);
74
+ if (matched.items.length > 0) {
75
+ const upsert = deps.upsertChannelIdentityMappings || upsertChannelIdentityMappings;
76
+ await upsert(ctx.dataplaneUrl, ctx.authConfig, {
77
+ sourceChannel: 'slack',
78
+ items: matched.items
79
+ });
80
+ }
81
+ return { ran: true, linked: matched.items.length, unmatched: matched.unmatched };
82
+ }
83
+
84
+ module.exports = {
85
+ shouldSkipOnboard,
86
+ shouldOnboardUsers,
87
+ unmatchedRemainingStep,
88
+ maybeOnboardSlackUsers
89
+ };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Persist non-secret Slack app / workspace IDs only.
3
+ *
4
+ * @fileoverview Never store bot tokens or signing secrets
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const fs = require('../../internal/fs-real-sync');
11
+ const { STATE_FILE, STATE_KIND, SECRET_KEY_RE } = require('./constants');
12
+ const { slackProvisioningError } = require('./errors');
13
+
14
+ /**
15
+ * @param {string} projectRoot
16
+ * @returns {string}
17
+ */
18
+ function provisioningStatePath(projectRoot) {
19
+ const root = projectRoot || process.cwd();
20
+ return path.join(root, 'dist', 'channels', 'slack', STATE_FILE);
21
+ }
22
+
23
+ /**
24
+ * @param {Object} record
25
+ * @returns {void}
26
+ */
27
+ function assertNoSecrets(record) {
28
+ const keys = record && typeof record === 'object' ? Object.keys(record) : [];
29
+ const hit = keys.find((key) => SECRET_KEY_RE.test(key));
30
+ if (hit) {
31
+ throw slackProvisioningError(`Refusing to persist Slack secret field "${hit}".`, 'SECRET');
32
+ }
33
+ const blob = JSON.stringify(record || {});
34
+ if (/xox[baprs]-/i.test(blob)) {
35
+ throw slackProvisioningError('Refusing to persist a Slack token value.', 'SECRET');
36
+ }
37
+ }
38
+
39
+ /**
40
+ * @param {string} projectRoot
41
+ * @returns {Object|null}
42
+ */
43
+ function readProvisioningState(projectRoot) {
44
+ const filePath = provisioningStatePath(projectRoot);
45
+ if (!fs.existsSync(filePath)) {
46
+ return null;
47
+ }
48
+ try {
49
+ const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
50
+ if (!parsed || parsed.kind !== STATE_KIND) {
51
+ return null;
52
+ }
53
+ assertNoSecrets(parsed);
54
+ return parsed;
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ /**
61
+ * @param {Object|null} state
62
+ * @returns {boolean}
63
+ */
64
+ function hasProvenAppIdentity(state) {
65
+ return Boolean(state && typeof state.appId === 'string' && state.appId.trim());
66
+ }
67
+
68
+ /**
69
+ * @param {string} projectRoot
70
+ * @param {Object} state
71
+ * @returns {void}
72
+ */
73
+ function writeProvisioningState(projectRoot, state) {
74
+ const record = {
75
+ kind: STATE_KIND,
76
+ environment: state.environment,
77
+ appId: state.appId,
78
+ clientId: state.clientId || null,
79
+ teamId: state.teamId || null,
80
+ botId: state.botId || null,
81
+ secretsStored: state.secretsStored === true
82
+ };
83
+ assertNoSecrets(record);
84
+ const filePath = provisioningStatePath(projectRoot);
85
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
86
+ fs.writeFileSync(filePath, `${JSON.stringify(record, null, 2)}\n`, 'utf8');
87
+ }
88
+
89
+ module.exports = {
90
+ provisioningStatePath,
91
+ readProvisioningState,
92
+ writeProvisioningState,
93
+ hasProvenAppIdentity,
94
+ assertNoSecrets
95
+ };
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Slack post-create consent URLs (app, Install App, workspace approve).
3
+ *
4
+ * @fileoverview App id and team id are public; never include client_secret
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ /**
10
+ * @param {string} [appId]
11
+ * @returns {string}
12
+ */
13
+ function slackAppRootUrl(appId) {
14
+ if (typeof appId !== 'string' || !appId.trim()) {
15
+ return '';
16
+ }
17
+ return `https://api.slack.com/apps/${encodeURIComponent(appId.trim())}`;
18
+ }
19
+
20
+ /**
21
+ * @param {string} [appId]
22
+ * @param {string} page
23
+ * @returns {string}
24
+ */
25
+ function slackAppPageUrl(appId, page) {
26
+ const root = slackAppRootUrl(appId);
27
+ if (!root || typeof page !== 'string' || !page.trim()) {
28
+ return root;
29
+ }
30
+ return `${root}/${page}`;
31
+ }
32
+
33
+ /**
34
+ * @param {string} [appId]
35
+ * @returns {string}
36
+ */
37
+ function slackAppGeneralUrl(appId) {
38
+ return slackAppPageUrl(appId, 'general');
39
+ }
40
+
41
+ /**
42
+ * Workspace install URL that actually adds the app (`/install-on-team`).
43
+ * @param {string} [appId]
44
+ * @returns {string}
45
+ */
46
+ function slackAppInstallOnTeamUrl(appId) {
47
+ return slackAppPageUrl(appId, 'install-on-team');
48
+ }
49
+
50
+ /**
51
+ * Slack workspace admin approval for this app.
52
+ * @param {string} [teamId]
53
+ * @param {string} [appId]
54
+ * @returns {string}
55
+ */
56
+ function buildSlackWorkspaceApproveUrl(teamId, appId) {
57
+ if (typeof teamId !== 'string' || !teamId.trim()) {
58
+ return '';
59
+ }
60
+ if (typeof appId !== 'string' || !appId.trim()) {
61
+ return '';
62
+ }
63
+ const team = encodeURIComponent(teamId.trim());
64
+ const app = encodeURIComponent(appId.trim());
65
+ return `https://app.slack.com/apps-manage/${team}/integrations/profile/${app}/permissions`;
66
+ }
67
+
68
+ /**
69
+ * @param {string} [url]
70
+ * @returns {string}
71
+ */
72
+ function clientIdFromAuthorizeUrl(url) {
73
+ if (typeof url !== 'string' || !url.includes('client_id=')) {
74
+ return '';
75
+ }
76
+ try {
77
+ return String(new URL(url).searchParams.get('client_id') || '').trim();
78
+ } catch {
79
+ return '';
80
+ }
81
+ }
82
+
83
+ /**
84
+ * @param {Object} [captured]
85
+ * @returns {string}
86
+ */
87
+ function pickSlackClientId(captured) {
88
+ const credentials = (captured && captured.credentials) || {};
89
+ const nested = captured && captured.data && typeof captured.data === 'object' ? captured.data : {};
90
+ const candidates = [
91
+ captured && captured.clientId,
92
+ captured && captured.client_id,
93
+ credentials.clientId,
94
+ credentials.client_id,
95
+ nested.clientId,
96
+ nested.client_id
97
+ ];
98
+ const direct = candidates.find((value) => typeof value === 'string' && value.trim());
99
+ if (direct) {
100
+ return String(direct).trim();
101
+ }
102
+ return clientIdFromAuthorizeUrl(
103
+ (captured && captured.oauth_authorize_url) || credentials.oauth_authorize_url
104
+ );
105
+ }
106
+
107
+ /**
108
+ * @param {Object} [captured]
109
+ * @returns {string}
110
+ */
111
+ function pickSlackTeamId(captured) {
112
+ const credentials = (captured && captured.credentials) || {};
113
+ const candidates = [
114
+ captured && captured.teamId,
115
+ captured && captured.team_id,
116
+ credentials.teamId,
117
+ credentials.team_id
118
+ ];
119
+ const hit = candidates.find((value) => typeof value === 'string' && value.trim());
120
+ return hit ? String(hit).trim() : '';
121
+ }
122
+
123
+ /**
124
+ * @param {Object} [captured]
125
+ * @returns {{ slackAppSettingsUrl: string, slackInstallAppUrl: string,
126
+ * slackWorkspaceApproveUrl: string }}
127
+ */
128
+ function slackConsentUrls(captured) {
129
+ const appId = captured && captured.appId;
130
+ return {
131
+ slackAppSettingsUrl: slackAppRootUrl(appId),
132
+ slackInstallAppUrl: slackAppInstallOnTeamUrl(appId),
133
+ slackWorkspaceApproveUrl: buildSlackWorkspaceApproveUrl(pickSlackTeamId(captured), appId)
134
+ };
135
+ }
136
+
137
+ /**
138
+ * @param {{ storedSigningSecret?: boolean }} [stored]
139
+ * @returns {string[]}
140
+ */
141
+ function slackConsentRemaining(stored) {
142
+ const steps = ['Upload your logo (Basic Information)', 'Activate the application'];
143
+ if (!stored || stored.storedSigningSecret !== true) {
144
+ steps.push('Store the signing secret in Authentication (Slack cannot re-read it after create)');
145
+ }
146
+ return steps;
147
+ }
148
+
149
+ module.exports = {
150
+ slackAppRootUrl,
151
+ slackAppGeneralUrl,
152
+ slackAppInstallOnTeamUrl,
153
+ buildSlackWorkspaceApproveUrl,
154
+ pickSlackClientId,
155
+ pickSlackTeamId,
156
+ slackConsentUrls,
157
+ slackConsentRemaining
158
+ };
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Ensure `curl` is on PATH for Slack CLI install.sh (Node shim when missing).
3
+ */
4
+
5
+ 'use strict';
6
+
7
+ const { execFile } = require('child_process');
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+ const path = require('path');
11
+ const { promisify } = require('util');
12
+
13
+ const execFileAsync = promisify(execFile);
14
+
15
+ async function curlExists(env) {
16
+ try {
17
+ await execFileAsync('curl', ['--version'], { env, timeout: 5000 });
18
+ return true;
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+
24
+ function writeCurlShim(dir) {
25
+ const runtime = path.join(__dirname, 'curl-shim.js');
26
+ const wrapper = `#!/bin/sh\nexec "${process.execPath}" "${runtime}" "$@"\n`;
27
+ fs.writeFileSync(path.join(dir, 'curl'), wrapper, { mode: 0o755 });
28
+ }
29
+
30
+ /**
31
+ * @param {NodeJS.ProcessEnv} [env]
32
+ * @param {{ curlExists?: Function }} [deps]
33
+ * @returns {Promise<NodeJS.ProcessEnv>}
34
+ */
35
+ async function withCurlOnPath(env = process.env, deps = {}) {
36
+ const exists = deps.curlExists || curlExists;
37
+ if (await exists(env)) {
38
+ return env;
39
+ }
40
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'aifabrix-curl-'));
41
+ writeCurlShim(dir);
42
+ return {
43
+ ...env,
44
+ PATH: `${dir}${path.delimiter}${env.PATH || ''}`
45
+ };
46
+ }
47
+
48
+ module.exports = { curlExists, withCurlOnPath };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Teams Bot channel-add provisioning hook.
3
+ *
4
+ * @fileoverview Keep add-channel.js free of Teams Developer CLI argv
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { provisionTeamsBot, TEAMS_CLI_MISSING_REMAINING } = require('./microsoft-provisioning/teams-bot-provision');
10
+ const { redactTeamsSecrets } = require('./microsoft-provisioning/errors');
11
+
12
+ const FAIL_CLOSED_CODES = new Set(['WRONG_TENANT', 'TEAMS_MANAGED', 'SECRET', 'SCAFFOLD']);
13
+
14
+ /**
15
+ * @param {Error} error
16
+ * @returns {string[]}
17
+ */
18
+ function remainingFromError(error) {
19
+ const code = error && error.code;
20
+ if (code === 'TEAMS_CLI_MISSING') {
21
+ return TEAMS_CLI_MISSING_REMAINING;
22
+ }
23
+ if (code === 'MISSING_AZURE') {
24
+ return [
25
+ 'Azure subscription and resource group were not found on the controller environment',
26
+ 'Deploy the environment, then re-run aifabrix channel add teams-bot'
27
+ ];
28
+ }
29
+ if (code === 'ENDPOINT') {
30
+ return ['Use a public HTTPS dataplane URL for the Teams Bot messaging endpoint'];
31
+ }
32
+ const detail = redactTeamsSecrets(
33
+ (error && error.message) || 'Teams Bot provisioning failed'
34
+ );
35
+ return [detail];
36
+ }
37
+
38
+ /**
39
+ * @param {Error} error
40
+ * @returns {boolean}
41
+ */
42
+ function shouldFailClosed(error) {
43
+ return FAIL_CLOSED_CODES.has(error && error.code);
44
+ }
45
+
46
+ /**
47
+ * @param {Error} error
48
+ * @returns {Object}
49
+ */
50
+ function recoveryFromError(error) {
51
+ return {
52
+ connected: false,
53
+ skipped: true,
54
+ remaining: remainingFromError(error)
55
+ };
56
+ }
57
+
58
+ /**
59
+ * @param {Object} params
60
+ * @returns {Promise<Object|null>}
61
+ */
62
+ async function maybeProvisionTeamsBotChannel(params) {
63
+ if (!params || params.channelTarget !== 'teams-bot') {
64
+ return null;
65
+ }
66
+ if (params.options && params.options.dryRun === true) {
67
+ return null;
68
+ }
69
+ const ctx = params.ctx || {};
70
+ const options = params.options || {};
71
+ const deps = options.teamsBotProvisioningDeps || {};
72
+ try {
73
+ return await provisionTeamsBot(
74
+ {
75
+ projectRoot: options.projectRoot || process.cwd(),
76
+ runtimeValues: params.runtimeValues,
77
+ ctx,
78
+ environment: ctx.environment,
79
+ options
80
+ },
81
+ deps
82
+ );
83
+ } catch (error) {
84
+ if (shouldFailClosed(error)) {
85
+ throw error;
86
+ }
87
+ return recoveryFromError(error);
88
+ }
89
+ }
90
+
91
+ module.exports = {
92
+ maybeProvisionTeamsBotChannel,
93
+ remainingFromError
94
+ };