@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,226 @@
1
+ /**
2
+ * Spawn Slack CLI (`slack api …`) without scattering argv.
3
+ *
4
+ * @fileoverview Documented CLI only; skipped under Jest unless deps allow it
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const path = require('path');
10
+ const { promisify } = require('util');
11
+ const execFileDefault = promisify(require('child_process').execFile);
12
+ const { SLACK_BINARIES } = require('./constants');
13
+ const { slackProvisioningError, wrapSlackCliError } = require('./errors');
14
+ const { withSlackCliPath, slackCliLocalBinDir } = require('./install-cli');
15
+ const { readSlackCredentialEntries, slackUserTokenForTeam } = require('./auth-store');
16
+
17
+ /**
18
+ * @returns {boolean}
19
+ */
20
+ function isJestWorker() {
21
+ return Boolean(process.env.JEST_WORKER_ID);
22
+ }
23
+
24
+ /**
25
+ * @param {Object} [deps]
26
+ * @returns {boolean}
27
+ */
28
+ function shouldSkipLiveSlackCli(deps = {}) {
29
+ if (deps.allowInTests === true) {
30
+ return false;
31
+ }
32
+ return isJestWorker();
33
+ }
34
+
35
+ /**
36
+ * @returns {string[]}
37
+ */
38
+ function slackBinaryCandidates() {
39
+ const local = path.join(slackCliLocalBinDir(), 'slack');
40
+ return [local, ...SLACK_BINARIES];
41
+ }
42
+
43
+ /**
44
+ * @param {typeof execFileDefault} execFileImpl
45
+ * @param {string} bin
46
+ * @param {Object} [deps]
47
+ * @returns {Promise<boolean>}
48
+ */
49
+ async function binaryResponds(execFileImpl, bin, deps = {}) {
50
+ try {
51
+ await execFileImpl(bin, ['--version'], {
52
+ timeout: 20000,
53
+ env: withSlackCliPath(deps.env || process.env)
54
+ });
55
+ return true;
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * @param {Object} [deps]
63
+ * @returns {Promise<string|null>}
64
+ */
65
+ async function resolveSlackBinary(deps = {}) {
66
+ if (typeof deps.slackBinary === 'string' && deps.slackBinary.trim()) {
67
+ return deps.slackBinary.trim();
68
+ }
69
+ if (shouldSkipLiveSlackCli(deps)) {
70
+ return null;
71
+ }
72
+ const execFileImpl = deps.execFile || execFileDefault;
73
+ for (const bin of slackBinaryCandidates()) {
74
+ if (await binaryResponds(execFileImpl, bin, deps)) {
75
+ return bin;
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+
81
+ /**
82
+ * Slack CLI `api` does not load ~/.slack/credentials.json unless a token is set.
83
+ * @param {Object} [deps]
84
+ * @returns {NodeJS.ProcessEnv}
85
+ */
86
+ function slackApiChildEnv(deps = {}) {
87
+ const env = withSlackCliPath(deps.env || process.env);
88
+ if (env.SLACK_USER_TOKEN || env.SLACK_BOT_TOKEN) {
89
+ return env;
90
+ }
91
+ if (typeof deps.slackUserToken === 'string' && deps.slackUserToken.trim()) {
92
+ return { ...env, SLACK_USER_TOKEN: deps.slackUserToken.trim() };
93
+ }
94
+ const token = slackUserTokenForTeam(readSlackCredentialEntries(deps), deps.teamId);
95
+ return token ? { ...env, SLACK_USER_TOKEN: token } : env;
96
+ }
97
+
98
+ /**
99
+ * Slack CLI 4.x: `slack api <method> --json '{...}' [-w team]`.
100
+ * @param {string} method
101
+ * @param {Object} [payload]
102
+ * @param {Object} [deps]
103
+ * @returns {string[]}
104
+ */
105
+ function buildSlackApiArgs(method, payload = {}, deps = {}) {
106
+ const args = ['api', method, '--json', JSON.stringify(payload || {}), '--no-color', '-s'];
107
+ if (typeof deps.teamId === 'string' && deps.teamId.trim()) {
108
+ args.push('-w', deps.teamId.trim());
109
+ }
110
+ return args;
111
+ }
112
+
113
+ /**
114
+ * @param {string} stdout
115
+ * @returns {Object}
116
+ */
117
+ function parseJsonStdout(stdout) {
118
+ const text = String(stdout || '').trim();
119
+ if (!text) {
120
+ return {};
121
+ }
122
+ try {
123
+ return JSON.parse(text);
124
+ } catch {
125
+ const start = text.indexOf('{');
126
+ const end = text.lastIndexOf('}');
127
+ if (start >= 0 && end > start) {
128
+ return JSON.parse(text.slice(start, end + 1));
129
+ }
130
+ throw wrapSlackCliError(new Error('Slack CLI returned non-JSON output'));
131
+ }
132
+ }
133
+
134
+ /**
135
+ * @param {unknown} error
136
+ * @returns {Object|null}
137
+ */
138
+ function jsonBodyFromCliError(error) {
139
+ const stdout = error && error.stdout;
140
+ if (!stdout) {
141
+ return null;
142
+ }
143
+ try {
144
+ const body = parseJsonStdout(stdout);
145
+ return body && typeof body === 'object' ? body : null;
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+
151
+ /**
152
+ * Documented `slack api <method>` with a JSON payload.
153
+ * @param {string} method
154
+ * @param {Object} [payload]
155
+ * @param {Object} [deps]
156
+ * @returns {Promise<Object>}
157
+ */
158
+ async function runSlackApi(method, payload = {}, deps = {}) {
159
+ if (typeof deps.slackApi === 'function') {
160
+ return deps.slackApi(method, payload);
161
+ }
162
+ const bin = await resolveSlackBinary(deps);
163
+ if (!bin) {
164
+ throw slackProvisioningError(
165
+ 'Slack CLI (`slack`) is not installed or not on PATH.',
166
+ 'SLACK_CLI_MISSING'
167
+ );
168
+ }
169
+ const execFileImpl = deps.execFile || execFileDefault;
170
+ try {
171
+ const result = await execFileImpl(bin, buildSlackApiArgs(method, payload, deps), {
172
+ cwd: deps.cwd,
173
+ env: slackApiChildEnv(deps),
174
+ timeout: deps.timeout || 180000,
175
+ maxBuffer: 2 * 1024 * 1024
176
+ });
177
+ return parseJsonStdout(result && result.stdout);
178
+ } catch (error) {
179
+ const body = jsonBodyFromCliError(error);
180
+ if (body) {
181
+ return body;
182
+ }
183
+ throw wrapSlackCliError(error);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Native Slack CLI install (project-based; may no-op without a Slack app project).
189
+ * @param {string} appId
190
+ * @param {Object} [deps]
191
+ * @returns {Promise<Object>}
192
+ */
193
+ async function runNativeAppInstall(appId, deps = {}) {
194
+ const bin = await resolveSlackBinary(deps);
195
+ if (!bin || !appId) {
196
+ return {};
197
+ }
198
+ const execFileImpl = deps.execFile || execFileDefault;
199
+ const args = ['app', 'install', '-a', String(appId), '--no-color', '-s', '-f'];
200
+ if (typeof deps.teamId === 'string' && deps.teamId.trim()) {
201
+ args.push('-w', deps.teamId.trim());
202
+ }
203
+ try {
204
+ const result = await execFileImpl(bin, args, {
205
+ cwd: deps.cwd,
206
+ env: slackApiChildEnv(deps),
207
+ timeout: deps.timeout || 180000,
208
+ killSignal: 'SIGKILL',
209
+ maxBuffer: 2 * 1024 * 1024
210
+ });
211
+ return parseJsonStdout(result && result.stdout);
212
+ } catch {
213
+ return {};
214
+ }
215
+ }
216
+
217
+ module.exports = {
218
+ isJestWorker,
219
+ shouldSkipLiveSlackCli,
220
+ resolveSlackBinary,
221
+ runSlackApi,
222
+ runNativeAppInstall,
223
+ parseJsonStdout,
224
+ buildSlackApiArgs,
225
+ slackApiChildEnv
226
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Slack channel provisioning constants.
3
+ *
4
+ * @fileoverview Shared keys — never persist Slack tokens
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const STATE_KIND = 'slack-channel';
10
+ const STATE_FILE = 'provisioning-state.json';
11
+ const SLACK_BINARIES = ['slack'];
12
+ const SECRET_KEY_RE =
13
+ /^(accessToken|refreshToken|botToken|bot_token|signingSecret|signing_secret|client_secret|clientSecret|password)$/i;
14
+ const KV_SIGNING_SECRET = 'kv://slack/signingSecret';
15
+ const KV_BOT_TOKEN = 'kv://slack/botToken';
16
+ const KV_CLIENT_SECRET = 'kv://slack/clientSecret';
17
+ /** Slack create/install writes these into integration .env, then dataplane push. */
18
+ const SLACK_PROVISIONED_KV_KEYS = [KV_SIGNING_SECRET, KV_BOT_TOKEN, KV_CLIENT_SECRET];
19
+ const SLACK_APPS_URL = 'https://api.slack.com/apps';
20
+ const SLACK_CLI_DOCS_URL = 'https://docs.slack.dev/tools/slack-cli';
21
+ const SLACK_CLI_INSTALL_SCRIPT_URL = 'https://downloads.slack-edge.com/slack-cli/install.sh';
22
+ const REQUIRED_CALLBACK_KEYS = ['eventsUrl', 'interactionUrl', 'commandUrl'];
23
+
24
+ module.exports = {
25
+ STATE_KIND,
26
+ STATE_FILE,
27
+ SLACK_BINARIES,
28
+ SECRET_KEY_RE,
29
+ KV_SIGNING_SECRET,
30
+ KV_BOT_TOKEN,
31
+ KV_CLIENT_SECRET,
32
+ SLACK_PROVISIONED_KV_KEYS,
33
+ SLACK_APPS_URL,
34
+ SLACK_CLI_DOCS_URL,
35
+ SLACK_CLI_INSTALL_SCRIPT_URL,
36
+ REQUIRED_CALLBACK_KEYS
37
+ };
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Store Slack secrets locally (secret set) then publish to dataplane.
3
+ *
4
+ * @fileoverview Never log or persist secret values in dist /
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { storeCredentialSecrets } = require('../../api/credential.api');
10
+ const { KV_BOT_TOKEN, KV_CLIENT_SECRET, KV_SIGNING_SECRET } = require('./constants');
11
+ const { writeSlackSecretsEnvFiles } = require('./env-file');
12
+
13
+ /**
14
+ * @param {string} [value]
15
+ * @returns {boolean}
16
+ */
17
+ function hasSecretValue(value) {
18
+ return typeof value === 'string' && Boolean(value.trim());
19
+ }
20
+
21
+ /**
22
+ * @param {string} kvPath
23
+ * @returns {string}
24
+ */
25
+ function kvPathToSecretSetKey(kvPath) {
26
+ return String(kvPath || '').replace(/^kv:\/\//, '');
27
+ }
28
+
29
+ /**
30
+ * @param {Object} captured
31
+ * @param {Object} credentials
32
+ * @param {string[]} names
33
+ * @returns {string|undefined}
34
+ */
35
+ function pickNamedSecret(captured, credentials, names) {
36
+ for (const name of names) {
37
+ if (hasSecretValue(captured[name])) return captured[name];
38
+ if (hasSecretValue(credentials[name])) return credentials[name];
39
+ }
40
+ return undefined;
41
+ }
42
+
43
+ /**
44
+ * @param {unknown} value
45
+ * @returns {Object}
46
+ */
47
+ function asSecretMap(value) {
48
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
49
+ return value;
50
+ }
51
+ if (typeof value === 'string' && value.trim().startsWith('{')) {
52
+ try {
53
+ const parsed = JSON.parse(value);
54
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
55
+ } catch {
56
+ return {};
57
+ }
58
+ }
59
+ return {};
60
+ }
61
+
62
+ /**
63
+ * @param {Object} captured
64
+ * @returns {{ signingSecret?: string, botToken?: string, clientSecret?: string }}
65
+ */
66
+ function pickSlackSecrets(captured) {
67
+ const source = captured || {};
68
+ const nested = asSecretMap(source.body || source.data);
69
+ const credentials = asSecretMap(source.credentials || nested.credentials);
70
+ const fromSource = pickNamedSecret(source, credentials, ['signingSecret', 'signing_secret']);
71
+ const fromNested = pickNamedSecret(nested, credentials, ['signingSecret', 'signing_secret']);
72
+ return {
73
+ signingSecret: fromSource || fromNested,
74
+ botToken: pickNamedSecret(source, credentials, ['botToken', 'bot_token', 'access_token'])
75
+ || pickNamedSecret(nested, credentials, ['botToken', 'bot_token', 'access_token']),
76
+ clientSecret: pickNamedSecret(source, credentials, ['clientSecret', 'client_secret'])
77
+ || pickNamedSecret(nested, credentials, ['clientSecret', 'client_secret'])
78
+ };
79
+ }
80
+
81
+ /**
82
+ * @param {{ signingSecret?: string, botToken?: string, clientSecret?: string }} secrets
83
+ * @returns {Array<{ key: string, value: string }>}
84
+ */
85
+ function slackSecretItems(secrets) {
86
+ const pairs = [
87
+ [KV_SIGNING_SECRET, secrets && secrets.signingSecret],
88
+ [KV_BOT_TOKEN, secrets && secrets.botToken],
89
+ [KV_CLIENT_SECRET, secrets && secrets.clientSecret]
90
+ ];
91
+ return pairs
92
+ .filter(([, value]) => hasSecretValue(value))
93
+ .map(([key, value]) => ({ key, value: String(value).trim() }));
94
+ }
95
+
96
+ /**
97
+ * @param {Array<{ key: string, value: string }>} items
98
+ * @param {Object} deps
99
+ * @returns {Promise<void>}
100
+ */
101
+ async function writeSlackSecretsLocal(items, deps) {
102
+ const setSecret =
103
+ deps.setSecretInStore || require('../../core/secrets-ensure').setSecretInStore;
104
+ for (const item of items) {
105
+ await setSecret(kvPathToSecretSetKey(item.key), item.value);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * @param {Object} [deps]
111
+ * @returns {Promise<boolean>}
112
+ */
113
+ async function localSlackSigningPresent(deps = {}) {
114
+ if (typeof deps.hasLocalSlackSigningSecret === 'function') {
115
+ return deps.hasLocalSlackSigningSecret();
116
+ }
117
+ try {
118
+ const { loadSecrets } = require('../../core/secrets');
119
+ const secrets = await loadSecrets();
120
+ return hasSecretValue(secrets && secrets['slack/signingSecret']);
121
+ } catch {
122
+ return false;
123
+ }
124
+ }
125
+
126
+ /**
127
+ * @param {Array<{ key: string }>} items
128
+ * @returns {{ stored: boolean, storedSigningSecret: boolean, storedBotToken: boolean,
129
+ * storedClientSecret: boolean }}
130
+ */
131
+ function slackStoreFlags(items) {
132
+ const keys = new Set(items.map((item) => item.key));
133
+ return {
134
+ stored: items.length > 0,
135
+ storedSigningSecret: keys.has(KV_SIGNING_SECRET),
136
+ storedBotToken: keys.has(KV_BOT_TOKEN),
137
+ storedClientSecret: keys.has(KV_CLIENT_SECRET)
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Write Slack create/install secrets to local store and integration .env, then push.
143
+ *
144
+ * @param {Object} ctx
145
+ * @param {{ signingSecret?: string, botToken?: string, clientSecret?: string }} secrets
146
+ * @returns {Promise<{ stored: boolean, storedSigningSecret: boolean, storedBotToken: boolean,
147
+ * storedClientSecret: boolean }>}
148
+ */
149
+ async function storeSlackChannelSecrets(ctx, secrets, deps = {}) {
150
+ const items = slackSecretItems(secrets);
151
+ const flags = slackStoreFlags(items);
152
+ if (!flags.stored) {
153
+ return flags;
154
+ }
155
+ await writeSlackSecretsLocal(items, deps);
156
+ writeSlackSecretsEnvFiles(ctx, items, deps);
157
+ const store = deps.storeCredentialSecrets || storeCredentialSecrets;
158
+ await store(ctx.dataplaneUrl, ctx.authConfig, items);
159
+ return flags;
160
+ }
161
+
162
+ module.exports = {
163
+ hasSecretValue,
164
+ kvPathToSecretSetKey,
165
+ pickSlackSecrets,
166
+ slackSecretItems,
167
+ localSlackSigningPresent,
168
+ storeSlackChannelSecrets
169
+ };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Minimal curl stand-in for hosts where `curl` is not installed.
3
+ * Supports URL download to stdout or `-o` / `--output` (including clustered `-fLo`).
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const https = require('https');
10
+ const http = require('http');
11
+
12
+ const MAX_REDIRECTS = 5;
13
+
14
+ function isHttpUrl(value) {
15
+ return /^https?:\/\//i.test(String(value || ''));
16
+ }
17
+
18
+ /**
19
+ * Consume `-o FILE`, `--output FILE`, `-fLo FILE`, or `-oFILE`.
20
+ * @returns {number} last consumed argv index
21
+ */
22
+ function applyOutputFlag(arg, argv, index, state) {
23
+ if (arg === '-o' || arg === '--output') {
24
+ state.output = argv[index + 1] || '';
25
+ return index + 1;
26
+ }
27
+ if (!arg.startsWith('-') || arg.startsWith('--') || arg === '-') {
28
+ return index;
29
+ }
30
+ const body = arg.slice(1);
31
+ const outputAt = body.indexOf('o');
32
+ if (outputAt < 0) {
33
+ return index;
34
+ }
35
+ const inline = body.slice(outputAt + 1);
36
+ if (inline) {
37
+ state.output = inline;
38
+ return index;
39
+ }
40
+ state.output = argv[index + 1] || '';
41
+ return index + 1;
42
+ }
43
+
44
+ function parseCurlArgs(argv) {
45
+ const state = { output: '', positionals: [] };
46
+ for (let i = 0; i < argv.length; i += 1) {
47
+ const arg = argv[i];
48
+ if (arg === '--url') {
49
+ state.positionals.push(argv[i + 1] || '');
50
+ i += 1;
51
+ continue;
52
+ }
53
+ if (typeof arg === 'string' && arg.startsWith('--url=')) {
54
+ state.positionals.push(arg.slice('--url='.length));
55
+ continue;
56
+ }
57
+ const next = applyOutputFlag(arg, argv, i, state);
58
+ if (next !== i) {
59
+ i = next;
60
+ continue;
61
+ }
62
+ if (typeof arg === 'string' && arg.startsWith('-')) {
63
+ continue;
64
+ }
65
+ state.positionals.push(arg);
66
+ }
67
+ const url = state.positionals.find(isHttpUrl) || state.positionals[0] || '';
68
+ return { output: state.output, url };
69
+ }
70
+
71
+ function followRedirect(url, res, redirects, output, resolve, reject) {
72
+ const status = res.statusCode || 0;
73
+ if (!(status >= 300 && status < 400 && res.headers.location)) {
74
+ return false;
75
+ }
76
+ res.resume();
77
+ if (redirects >= MAX_REDIRECTS) {
78
+ reject(new Error('Too many redirects.'));
79
+ return true;
80
+ }
81
+ const nextUrl = new URL(res.headers.location, url).toString();
82
+ download(nextUrl, output, redirects + 1).then(resolve, reject);
83
+ return true;
84
+ }
85
+
86
+ function download(url, output, redirects) {
87
+ return new Promise((resolve, reject) => {
88
+ if (!isHttpUrl(url)) {
89
+ reject(new Error('URL is required.'));
90
+ return;
91
+ }
92
+ const client = url.startsWith('https:') ? https : http;
93
+ const req = client.get(url, { timeout: 60000 }, (res) => {
94
+ if (followRedirect(url, res, redirects, output, resolve, reject)) {
95
+ return;
96
+ }
97
+ if ((res.statusCode || 0) !== 200) {
98
+ res.resume();
99
+ reject(new Error(`Download failed (${res.statusCode || 0}).`));
100
+ return;
101
+ }
102
+ const dest = output ? fs.createWriteStream(output) : process.stdout;
103
+ res.pipe(dest);
104
+ dest.on('finish', () => {
105
+ if (output && typeof dest.close === 'function') {
106
+ dest.close(() => resolve());
107
+ return;
108
+ }
109
+ resolve();
110
+ });
111
+ dest.on('error', reject);
112
+ });
113
+ req.on('error', reject);
114
+ });
115
+ }
116
+
117
+ async function main(argv) {
118
+ const { output, url } = parseCurlArgs(argv);
119
+ if (!url) {
120
+ throw new Error('URL is required.');
121
+ }
122
+ await download(url, output, 0);
123
+ }
124
+
125
+ module.exports = { parseCurlArgs, download, main, isHttpUrl };
126
+
127
+ if (require.main === module) {
128
+ main(process.argv.slice(2)).catch((error) => {
129
+ process.stderr.write(`${error.message}\n`);
130
+ process.exit(1);
131
+ });
132
+ }
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Slack workspace install via apps.developerInstall (bot token).
3
+ *
4
+ * @fileoverview HTTP install for portal; signing secret still comes from create only
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { runSlackApi } = require('./cli');
10
+
11
+ /**
12
+ * @param {unknown} value
13
+ * @returns {string}
14
+ */
15
+ function trimmedString(value) {
16
+ return typeof value === 'string' && value.trim() ? value.trim() : '';
17
+ }
18
+
19
+ /**
20
+ * @param {...unknown} values
21
+ * @returns {string}
22
+ */
23
+ function firstTrimmed(...values) {
24
+ for (const value of values) {
25
+ const text = trimmedString(value);
26
+ if (text) {
27
+ return text;
28
+ }
29
+ }
30
+ return '';
31
+ }
32
+
33
+ /**
34
+ * @param {Object} [manifest]
35
+ * @returns {string[]}
36
+ */
37
+ function botScopesFromManifest(manifest) {
38
+ const scopes = manifest && manifest.oauth_config && manifest.oauth_config.scopes;
39
+ const bot = scopes && scopes.bot;
40
+ if (!Array.isArray(bot)) {
41
+ return [];
42
+ }
43
+ return bot.map((scope) => trimmedString(scope)).filter(Boolean);
44
+ }
45
+
46
+ /**
47
+ * @param {unknown} value
48
+ * @returns {Object}
49
+ */
50
+ function asObject(value) {
51
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
52
+ }
53
+
54
+ /**
55
+ * @param {Object} [body]
56
+ * @returns {{ botToken?: string, teamId?: string, botId?: string }}
57
+ */
58
+ function pickInstalledSlackTokens(body) {
59
+ if (!body || body.ok === false) {
60
+ return {};
61
+ }
62
+ const tokens = asObject(body.api_access_tokens);
63
+ const botToken = firstTrimmed(tokens.bot, body.bot_token, body.access_token, body.botToken);
64
+ if (!botToken) {
65
+ return {};
66
+ }
67
+ const teamId = firstTrimmed(body.team_id, asObject(body.team).id);
68
+ const botId = firstTrimmed(body.bot_id, asObject(body.bot).id);
69
+ return {
70
+ botToken,
71
+ ...(teamId ? { teamId } : {}),
72
+ ...(botId ? { botId } : {})
73
+ };
74
+ }
75
+
76
+ /**
77
+ * @param {string} appId
78
+ * @param {Object} [deps]
79
+ * @returns {Object}
80
+ */
81
+ function developerInstallPayload(appId, deps = {}) {
82
+ const payload = { app_id: appId };
83
+ const scopes = Array.isArray(deps.botScopes)
84
+ ? deps.botScopes.map((scope) => trimmedString(scope)).filter(Boolean)
85
+ : [];
86
+ if (scopes.length) {
87
+ payload.bot_scopes = scopes;
88
+ }
89
+ return payload;
90
+ }
91
+
92
+ /**
93
+ * Same method Slack CLI uses. Returns bot token without hanging on `app install`.
94
+ * @param {string} appId
95
+ * @param {Object} [deps]
96
+ * @returns {Promise<{ botToken?: string, teamId?: string, botId?: string }>}
97
+ */
98
+ async function developerInstallApp(appId, deps = {}) {
99
+ if (!appId) {
100
+ return {};
101
+ }
102
+ try {
103
+ const body = await runSlackApi(
104
+ 'apps.developerInstall',
105
+ developerInstallPayload(appId, deps),
106
+ deps
107
+ );
108
+ return pickInstalledSlackTokens(body);
109
+ } catch {
110
+ return {};
111
+ }
112
+ }
113
+
114
+ module.exports = {
115
+ botScopesFromManifest,
116
+ pickInstalledSlackTokens,
117
+ developerInstallApp
118
+ };