@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,181 @@
1
+ /**
2
+ * Slack Manifest API via documented `slack api` methods.
3
+ *
4
+ * @fileoverview create / update / validate — signing_secret only on create
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { runSlackApi, runNativeAppInstall } = require('./cli');
10
+ const { slackProvisioningError } = require('./errors');
11
+ const { pickSlackClientId } = require('./remaining-urls');
12
+ const {
13
+ developerInstallApp,
14
+ pickInstalledSlackTokens
15
+ } = require('./developer-install');
16
+
17
+ /**
18
+ * @param {Object} body
19
+ * @returns {Object}
20
+ */
21
+ function requireOk(body) {
22
+ if (body && body.ok === true) {
23
+ return body;
24
+ }
25
+ const detail = body && body.error ? String(body.error) : 'unknown_error';
26
+ const notes = Array.isArray(body && body.errors)
27
+ ? body.errors.map((row) => row && row.message).filter(Boolean).join('; ')
28
+ : '';
29
+ const suffix = notes ? ` (${notes})` : '';
30
+ throw slackProvisioningError(`Slack Manifest API failed: ${detail}${suffix}`, 'SLACK_API');
31
+ }
32
+
33
+ /**
34
+ * @param {Object} manifest
35
+ * @returns {Object}
36
+ */
37
+ function manifestPayload(manifest) {
38
+ return { manifest: JSON.stringify(manifest) };
39
+ }
40
+
41
+ /**
42
+ * @param {Object} manifest
43
+ * @param {Object} [deps]
44
+ * @returns {Promise<Object>}
45
+ */
46
+ async function validateManifestRemote(manifest, deps = {}) {
47
+ const payload = manifestPayload(manifest);
48
+ if (typeof deps.appId === 'string' && deps.appId.trim()) {
49
+ payload.app_id = deps.appId.trim();
50
+ }
51
+ const body = await runSlackApi('apps.manifest.validate', payload, deps);
52
+ return requireOk(body);
53
+ }
54
+
55
+ /**
56
+ * @param {string} appId
57
+ * @param {Object} [deps]
58
+ * @returns {Promise<Object|null>}
59
+ */
60
+ async function exportManifestApp(appId, deps = {}) {
61
+ const result = await exportManifestLookup(appId, deps);
62
+ return result.manifest;
63
+ }
64
+
65
+ /**
66
+ * @param {string} appId
67
+ * @param {Object} [deps]
68
+ * @returns {Promise<{ missing: boolean, manifest: Object|null }>}
69
+ */
70
+ async function exportManifestLookup(appId, deps = {}) {
71
+ if (!appId) {
72
+ return { missing: true, manifest: null };
73
+ }
74
+ const body = await runSlackApi('apps.manifest.export', { app_id: appId }, deps);
75
+ if (body && body.ok === false && body.error === 'app_not_found') {
76
+ return { missing: true, manifest: null };
77
+ }
78
+ if (!body || body.ok === false) {
79
+ return { missing: false, manifest: null };
80
+ }
81
+ return { missing: false, manifest: body.manifest || null };
82
+ }
83
+
84
+ /**
85
+ * @param {Object} manifest
86
+ * @param {Object} [deps]
87
+ * @returns {Promise<Object>}
88
+ */
89
+ async function createManifestApp(manifest, deps = {}) {
90
+ const body = await runSlackApi('apps.manifest.create', manifestPayload(manifest), deps);
91
+ const created = requireOk(body);
92
+ const createdAppId = created.app_id || created.appId;
93
+ if (!createdAppId) {
94
+ throw slackProvisioningError('Slack create did not return an app id.', 'SLACK_API');
95
+ }
96
+ created.app_id = createdAppId;
97
+ return created;
98
+ }
99
+
100
+ /**
101
+ * @param {string} appId
102
+ * @param {Object} manifest
103
+ * @param {Object} [deps]
104
+ * @returns {Promise<Object>}
105
+ */
106
+ async function updateManifestApp(appId, manifest, deps = {}) {
107
+ const body = await runSlackApi(
108
+ 'apps.manifest.update',
109
+ { app_id: appId, ...manifestPayload(manifest) },
110
+ deps
111
+ );
112
+ return requireOk(body);
113
+ }
114
+
115
+ /**
116
+ * Recover public client id when create response omitted it.
117
+ * @param {Object} [captured]
118
+ * @param {Object} [deps]
119
+ * @returns {Promise<string>}
120
+ */
121
+ async function resolveSlackClientId(captured, deps = {}) {
122
+ const existing = pickSlackClientId(captured);
123
+ if (existing) {
124
+ return existing;
125
+ }
126
+ const appId = captured && (captured.appId || captured.app_id);
127
+ if (!appId) {
128
+ return '';
129
+ }
130
+ const exported = await runSlackApi('apps.manifest.export', { app_id: appId }, deps);
131
+ const fromExport = pickSlackClientId(exported);
132
+ if (fromExport) {
133
+ return fromExport;
134
+ }
135
+ const info = await runSlackApi('apps.info', { app: appId }, deps);
136
+ return pickSlackClientId(info && (info.app || info));
137
+ }
138
+
139
+ /**
140
+ * Native Slack CLI `app install` (TTY). Portal quiet mode must not call this.
141
+ * @param {string} appId
142
+ * @param {Object} [deps]
143
+ * @returns {Promise<{ botToken?: string, teamId?: string, botId?: string }>}
144
+ */
145
+ async function nativeInstallApp(appId, deps = {}) {
146
+ if (typeof deps.installApp === 'function') {
147
+ return deps.installApp(appId);
148
+ }
149
+ return pickInstalledSlackTokens(await runNativeAppInstall(appId, deps));
150
+ }
151
+
152
+ /**
153
+ * Workspace install. Prefer apps.developerInstall (HTTP, returns xoxb).
154
+ * @param {string} appId
155
+ * @param {Object} [deps]
156
+ * @returns {Promise<{ botToken?: string, teamId?: string, botId?: string }>}
157
+ */
158
+ async function installManifestApp(appId, deps = {}) {
159
+ const fromApi = await developerInstallApp(appId, deps);
160
+ if (fromApi.botToken) {
161
+ return fromApi;
162
+ }
163
+ if (deps.quiet === true) {
164
+ return fromApi;
165
+ }
166
+ try {
167
+ return (await nativeInstallApp(appId, deps)) || {};
168
+ } catch {
169
+ return {};
170
+ }
171
+ }
172
+
173
+ module.exports = {
174
+ validateManifestRemote,
175
+ exportManifestApp,
176
+ exportManifestLookup,
177
+ createManifestApp,
178
+ updateManifestApp,
179
+ installManifestApp,
180
+ resolveSlackClientId
181
+ };
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Slack CLI login store (`~/.slack/credentials.json`) and `auth list` text.
3
+ *
4
+ * @fileoverview Never log or return tokens from public auth lists
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const { slackCliHomeDir } = require('./install-cli');
12
+
13
+ /**
14
+ * @param {Object} [deps]
15
+ * @returns {string}
16
+ */
17
+ function slackCredentialsPath(deps = {}) {
18
+ return path.join(deps.homeDir || slackCliHomeDir(deps.env), '.slack', 'credentials.json');
19
+ }
20
+
21
+ /**
22
+ * @param {Object} data
23
+ * @returns {Object[]}
24
+ */
25
+ function entriesFromCredentialsObject(data) {
26
+ if (!data || typeof data !== 'object' || Array.isArray(data)) {
27
+ return [];
28
+ }
29
+ return Object.entries(data).map(([teamId, row]) => ({
30
+ team_id: String((row && (row.team_id || row.teamId)) || teamId),
31
+ team_domain: (row && (row.team_domain || row.teamDomain)) || undefined,
32
+ user_id: (row && (row.user_id || row.userId)) || undefined,
33
+ token: row && row.token ? String(row.token) : undefined
34
+ }));
35
+ }
36
+
37
+ /**
38
+ * @param {Object} [deps]
39
+ * @returns {Object[]}
40
+ */
41
+ function readSlackCredentialEntries(deps = {}) {
42
+ if (typeof deps.readCredentials === 'function') {
43
+ const listed = deps.readCredentials();
44
+ return Array.isArray(listed) ? listed : [];
45
+ }
46
+ const filePath = slackCredentialsPath(deps);
47
+ if (!fs.existsSync(filePath)) {
48
+ return [];
49
+ }
50
+ try {
51
+ return entriesFromCredentialsObject(JSON.parse(fs.readFileSync(filePath, 'utf8')));
52
+ } catch {
53
+ return [];
54
+ }
55
+ }
56
+
57
+ /**
58
+ * @param {Object[]} entries
59
+ * @returns {Object[]}
60
+ */
61
+ function publicSlackAuths(entries) {
62
+ return (Array.isArray(entries) ? entries : []).map((row) => ({
63
+ team_id: row.team_id,
64
+ team_domain: row.team_domain,
65
+ user_id: row.user_id
66
+ }));
67
+ }
68
+
69
+ /**
70
+ * @param {Object[]} entries
71
+ * @param {string} [teamId]
72
+ * @returns {string|null}
73
+ */
74
+ function slackUserTokenForTeam(entries, teamId) {
75
+ const rows = Array.isArray(entries) ? entries : [];
76
+ const match = teamId
77
+ ? rows.find((row) => String(row.team_id || '') === String(teamId))
78
+ : (rows.length === 1 ? rows[0] : null);
79
+ const token = match && match.token;
80
+ return typeof token === 'string' && token.trim() ? token.trim() : null;
81
+ }
82
+
83
+ /**
84
+ * Slack CLI 4.x `auth list` is human text, not JSON.
85
+ * @param {string} text
86
+ * @returns {Object[]}
87
+ */
88
+ function parseAuthListText(text) {
89
+ const source = String(text || '');
90
+ const auths = [];
91
+ const re = /([A-Za-z0-9._-]+)\s+\(Team ID:\s*(T[A-Z0-9]+)\)[\s\S]*?User ID:\s*(U[A-Z0-9]+)/gi;
92
+ let match = re.exec(source);
93
+ while (match) {
94
+ auths.push({
95
+ team_domain: match[1],
96
+ team_id: match[2],
97
+ user_id: match[3]
98
+ });
99
+ match = re.exec(source);
100
+ }
101
+ return auths;
102
+ }
103
+
104
+ module.exports = {
105
+ slackCredentialsPath,
106
+ readSlackCredentialEntries,
107
+ publicSlackAuths,
108
+ slackUserTokenForTeam,
109
+ parseAuthListText
110
+ };
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Slack CLI ticket handshake for portal channel install.
3
+ *
4
+ * @fileoverview Server runs `slack auth token --no-prompt`; user runs the slash command
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { promisify } = require('util');
10
+ const execFileDefault = promisify(require('child_process').execFile);
11
+ const { slackProvisioningError, wrapSlackCliError } = require('./errors');
12
+ const { resolveSlackBinary, shouldSkipLiveSlackCli } = require('./cli');
13
+ const { withSlackCliPath, installOfficialSlackCli } = require('./install-cli');
14
+
15
+ const SLASH_RE = /\/slackauthticket\s+(\S+)/i;
16
+ const ACCESS_TOKEN_RE = /\b(xox[peba]-[A-Za-z0-9-]+)\b/i;
17
+ const TICKET_LINE_RE = /^[A-Za-z0-9._-]{16,}$/;
18
+ const AUTH_DEAD_RE = /token_revoked|token_expired|invalid_auth|not_authed|account_inactive/i;
19
+
20
+ /**
21
+ * @param {string} value
22
+ * @returns {boolean}
23
+ */
24
+ function looksLikeSlackAccessToken(value) {
25
+ return ACCESS_TOKEN_RE.test(String(value || '').trim());
26
+ }
27
+
28
+ /**
29
+ * @param {Error|Object|null} error
30
+ * @returns {boolean}
31
+ */
32
+ function isSlackAuthDeadError(error) {
33
+ const message = String((error && error.message) || '');
34
+ return AUTH_DEAD_RE.test(message);
35
+ }
36
+
37
+ /**
38
+ * @param {string} ticket
39
+ * @returns {string}
40
+ */
41
+ function slashCommandForTicket(ticket) {
42
+ const value = String(ticket || '').trim();
43
+ return value ? `/slackauthticket ${value}` : '';
44
+ }
45
+
46
+ /**
47
+ * @param {string} stdout
48
+ * @returns {{ ticket: string, slashCommand: string }}
49
+ */
50
+ function parseAuthTicketStart(stdout) {
51
+ const text = String(stdout || '');
52
+ const slash = text.match(SLASH_RE);
53
+ if (slash) {
54
+ return { ticket: slash[1], slashCommand: slashCommandForTicket(slash[1]) };
55
+ }
56
+ const ticket = firstTicketLine(text);
57
+ if (!ticket) {
58
+ throw slackProvisioningError('Slack CLI did not return an auth ticket.', 'SLACK_CLI');
59
+ }
60
+ return { ticket, slashCommand: slashCommandForTicket(ticket) };
61
+ }
62
+
63
+ /**
64
+ * @param {string} text
65
+ * @returns {string}
66
+ */
67
+ function firstTicketLine(text) {
68
+ for (const line of String(text || '').split(/\r?\n/)) {
69
+ const trimmed = line.trim();
70
+ if (!trimmed || trimmed.startsWith('/') || /challenge|enter|copy/i.test(trimmed)) {
71
+ continue;
72
+ }
73
+ if (TICKET_LINE_RE.test(trimmed) && !looksLikeSlackAccessToken(trimmed)) {
74
+ return trimmed;
75
+ }
76
+ }
77
+ return '';
78
+ }
79
+
80
+ /**
81
+ * @param {string} stdout
82
+ * @returns {string}
83
+ */
84
+ function parseAuthTicketComplete(stdout) {
85
+ const match = String(stdout || '').match(ACCESS_TOKEN_RE);
86
+ if (!match) {
87
+ throw slackProvisioningError('Slack CLI did not return a session token.', 'SLACK_CLI');
88
+ }
89
+ return match[1];
90
+ }
91
+
92
+ /**
93
+ * @param {Object} [deps]
94
+ * @returns {Promise<string>}
95
+ */
96
+ async function ensureSlackCliForTicket(deps = {}) {
97
+ const existing = await resolveSlackBinary(deps);
98
+ if (existing) {
99
+ return existing;
100
+ }
101
+ if (shouldSkipLiveSlackCli(deps)) {
102
+ throw slackProvisioningError(
103
+ 'Slack CLI (`slack`) is not installed or not on PATH.',
104
+ 'SLACK_CLI_MISSING'
105
+ );
106
+ }
107
+ await installOfficialSlackCli(deps);
108
+ const installed = await resolveSlackBinary(deps);
109
+ if (!installed) {
110
+ throw slackProvisioningError(
111
+ 'Slack CLI (`slack`) is not installed or not on PATH.',
112
+ 'SLACK_CLI_MISSING'
113
+ );
114
+ }
115
+ return installed;
116
+ }
117
+
118
+ /**
119
+ * @param {Object} [deps]
120
+ * @returns {Promise<{ ticket: string, slashCommand: string }>}
121
+ */
122
+ async function startSlackAuthTicket(deps = {}) {
123
+ if (typeof deps.startAuthTicket === 'function') {
124
+ return deps.startAuthTicket();
125
+ }
126
+ const bin = await ensureSlackCliForTicket(deps);
127
+ const execFileImpl = deps.execFile || execFileDefault;
128
+ try {
129
+ const result = await execFileImpl(bin, ['auth', 'token', '--no-prompt', '--no-color', '-s'], {
130
+ timeout: deps.timeout || 30000,
131
+ killSignal: 'SIGKILL',
132
+ maxBuffer: 1024 * 1024,
133
+ env: withSlackCliPath(deps.env || process.env)
134
+ });
135
+ return parseAuthTicketStart(result && result.stdout);
136
+ } catch (error) {
137
+ if (error && error.code === 'SLACK_CLI_MISSING') {
138
+ throw error;
139
+ }
140
+ throw wrapSlackCliError(error);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * @param {{ ticket: string, challenge: string }} params
146
+ * @param {Object} [deps]
147
+ * @returns {Promise<string>}
148
+ */
149
+ async function completeSlackAuthTicket(params, deps = {}) {
150
+ if (typeof deps.completeAuthTicket === 'function') {
151
+ return deps.completeAuthTicket(params);
152
+ }
153
+ const ticket = String(params && params.ticket ? params.ticket : '').trim();
154
+ const challenge = String(params && params.challenge ? params.challenge : '').trim();
155
+ if (!ticket || !challenge) {
156
+ throw slackProvisioningError('Challenge code and auth ticket are required.', 'SLACK_CLI');
157
+ }
158
+ const bin = await ensureSlackCliForTicket(deps);
159
+ const execFileImpl = deps.execFile || execFileDefault;
160
+ try {
161
+ const result = await execFileImpl(
162
+ bin,
163
+ ['auth', 'token', '--no-prompt', '--challenge', challenge, '--ticket', ticket, '--no-color', '-s'],
164
+ {
165
+ timeout: deps.timeout || 45000,
166
+ killSignal: 'SIGKILL',
167
+ maxBuffer: 1024 * 1024,
168
+ env: withSlackCliPath(deps.env || process.env)
169
+ }
170
+ );
171
+ return parseAuthTicketComplete(result && result.stdout);
172
+ } catch (error) {
173
+ throw wrapSlackCliError(error);
174
+ }
175
+ }
176
+
177
+ module.exports = {
178
+ looksLikeSlackAccessToken,
179
+ isSlackAuthDeadError,
180
+ slashCommandForTicket,
181
+ parseAuthTicketStart,
182
+ parseAuthTicketComplete,
183
+ startSlackAuthTicket,
184
+ completeSlackAuthTicket
185
+ };
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Slack workspace identity from login store or `slack auth list`.
3
+ *
4
+ * @fileoverview Fail closed when multiple workspaces cannot be proven
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { promisify } = require('util');
10
+ const execFileDefault = promisify(require('child_process').execFile);
11
+ const { slackProvisioningError, wrapSlackCliError } = require('./errors');
12
+ const { resolveSlackBinary, runSlackApi, shouldSkipLiveSlackCli } = require('./cli');
13
+ const { withSlackCliPath } = require('./install-cli');
14
+ const {
15
+ readSlackCredentialEntries,
16
+ publicSlackAuths,
17
+ parseAuthListText
18
+ } = require('./auth-store');
19
+
20
+ /**
21
+ * @param {Object} [deps]
22
+ * @returns {Promise<Object[]>}
23
+ */
24
+ async function listSlackAuthsFromCli(deps = {}) {
25
+ const bin = await resolveSlackBinary(deps);
26
+ if (!bin) {
27
+ return [];
28
+ }
29
+ const execFileImpl = deps.execFile || execFileDefault;
30
+ try {
31
+ const result = await execFileImpl(bin, ['auth', 'list', '--no-color', '-s'], {
32
+ timeout: 30000,
33
+ maxBuffer: 1024 * 1024,
34
+ env: withSlackCliPath(deps.env || process.env)
35
+ });
36
+ return parseAuthListText(result && result.stdout);
37
+ } catch (error) {
38
+ throw wrapSlackCliError(error);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * @param {Object} [deps]
44
+ * @returns {Promise<Object[]>}
45
+ */
46
+ async function listSlackAuths(deps = {}) {
47
+ if (typeof deps.listAuths === 'function') {
48
+ const listed = await deps.listAuths();
49
+ return Array.isArray(listed) ? listed : [];
50
+ }
51
+ const fromFile = publicSlackAuths(readSlackCredentialEntries(deps));
52
+ if (fromFile.length > 0) {
53
+ return fromFile;
54
+ }
55
+ if (shouldSkipLiveSlackCli(deps) && typeof deps.execFile !== 'function') {
56
+ return [];
57
+ }
58
+ return listSlackAuthsFromCli(deps);
59
+ }
60
+
61
+ /**
62
+ * Prove workspace identity from a short-lived session token for this run only.
63
+ * @param {Object} [deps]
64
+ * @returns {Promise<Object|null>}
65
+ */
66
+ async function workspaceFromSessionToken(deps = {}) {
67
+ const token = typeof deps.slackUserToken === 'string' ? deps.slackUserToken.trim() : '';
68
+ if (!token) {
69
+ return null;
70
+ }
71
+ if (typeof deps.authTest === 'function') {
72
+ const listed = await deps.authTest();
73
+ if (!listed || !(listed.team_id || listed.teamId)) {
74
+ throw slackProvisioningError('Session token was not accepted.', 'UNPROVEN_IDENTITY');
75
+ }
76
+ return listed;
77
+ }
78
+ const body = await runSlackApi('auth.test', {}, deps);
79
+ if (!body || body.ok !== true || !(body.team_id || body.teamId)) {
80
+ throw slackProvisioningError('Session token was not accepted.', 'UNPROVEN_IDENTITY');
81
+ }
82
+ return { team_id: body.team_id || body.teamId, team: body.team };
83
+ }
84
+
85
+ /**
86
+ * @param {Object[]} auths
87
+ * @param {string} [expectedTeamId]
88
+ * @returns {Object}
89
+ */
90
+ function pickSlackWorkspace(auths, expectedTeamId) {
91
+ const rows = Array.isArray(auths) ? auths : [];
92
+ if (expectedTeamId) {
93
+ const match = rows.find((row) => String(row.team_id || row.teamId || '') === expectedTeamId);
94
+ if (!match) {
95
+ throw slackProvisioningError(
96
+ `Signed-in Slack workspace does not match expected team "${expectedTeamId}".`,
97
+ 'UNPROVEN_IDENTITY'
98
+ );
99
+ }
100
+ return match;
101
+ }
102
+ if (rows.length > 1) {
103
+ throw slackProvisioningError(
104
+ 'Multiple Slack workspaces are signed in. Pass the expected team id rather than guessing.',
105
+ 'UNPROVEN_IDENTITY'
106
+ );
107
+ }
108
+ return rows[0] || null;
109
+ }
110
+
111
+ module.exports = {
112
+ listSlackAuths,
113
+ pickSlackWorkspace,
114
+ workspaceFromSessionToken
115
+ };
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Fail before Slack create when callback URLs are missing or not public HTTPS.
3
+ *
4
+ * @fileoverview Events / interactivity / commands Request URLs
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { REQUIRED_CALLBACK_KEYS } = require('./constants');
10
+ const { slackProvisioningError } = require('./errors');
11
+ const { isPublicHttpsUrl } = require('../vendor-dataplane-url');
12
+
13
+ /**
14
+ * @param {Object} runtimeValues
15
+ * @returns {void}
16
+ */
17
+ function assertSlackCallbackUrls(runtimeValues) {
18
+ const missing = REQUIRED_CALLBACK_KEYS.filter((key) => {
19
+ const value = runtimeValues && runtimeValues[key];
20
+ return typeof value !== 'string' || !value.trim();
21
+ });
22
+ if (missing.length > 0) {
23
+ throw slackProvisioningError(
24
+ `Slack callback URLs are missing: ${missing.join(', ')}. ` +
25
+ 'Generate the channel package against a public HTTPS dataplane before create.',
26
+ 'CALLBACKS'
27
+ );
28
+ }
29
+ const unusable = REQUIRED_CALLBACK_KEYS.filter((key) => !isPublicHttpsUrl(runtimeValues[key]));
30
+ if (unusable.length > 0) {
31
+ throw slackProvisioningError(
32
+ `Slack callback URLs must be public HTTPS: ${unusable.join(', ')}.`,
33
+ 'CALLBACKS'
34
+ );
35
+ }
36
+ }
37
+
38
+ module.exports = {
39
+ isPublicHttpsUrl,
40
+ assertSlackCallbackUrls
41
+ };