@open-everywhere/provider-slack 0.1.3 → 0.1.4

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 (95) hide show
  1. package/agent/access/slack-attachment-fetch.ts +3 -1
  2. package/agent/app-manifest.ts +48 -10
  3. package/agent/channels/slack-commands.ts +5 -1
  4. package/agent/channels/slack-events.ts +13 -4
  5. package/agent/channels/slack-front.ts +21 -6
  6. package/agent/channels/slack-read.ts +9 -3
  7. package/agent/channels/slack-setup-page.ts +20 -0
  8. package/agent/channels/slack-web-api.ts +34 -7
  9. package/agent/channels/slack.ts +11 -3
  10. package/agent/contributions.ts +1 -0
  11. package/agent/docs-generated.ts +1 -1
  12. package/agent/ops.ts +29 -61
  13. package/agent/register.ts +27 -1
  14. package/agent/setup/claim.ts +343 -0
  15. package/agent/setup/credentials.ts +265 -0
  16. package/agent/setup/eve-credentials.ts +77 -0
  17. package/agent/setup/install-state.ts +248 -0
  18. package/agent/setup/page.ts +579 -0
  19. package/agent/setup/slack-api-setup.ts +176 -0
  20. package/agent/status.ts +81 -0
  21. package/dist/agent/access/slack-attachment-fetch.d.ts.map +1 -1
  22. package/dist/agent/access/slack-attachment-fetch.js +3 -1
  23. package/dist/agent/access/slack-attachment-fetch.js.map +1 -1
  24. package/dist/agent/app-manifest.d.ts +4 -4
  25. package/dist/agent/app-manifest.d.ts.map +1 -1
  26. package/dist/agent/app-manifest.js +48 -10
  27. package/dist/agent/app-manifest.js.map +1 -1
  28. package/dist/agent/channels/slack-commands.d.ts.map +1 -1
  29. package/dist/agent/channels/slack-commands.js +5 -1
  30. package/dist/agent/channels/slack-commands.js.map +1 -1
  31. package/dist/agent/channels/slack-events.d.ts +1 -1
  32. package/dist/agent/channels/slack-events.d.ts.map +1 -1
  33. package/dist/agent/channels/slack-events.js +13 -4
  34. package/dist/agent/channels/slack-events.js.map +1 -1
  35. package/dist/agent/channels/slack-front.d.ts +1 -1
  36. package/dist/agent/channels/slack-front.d.ts.map +1 -1
  37. package/dist/agent/channels/slack-front.js +20 -5
  38. package/dist/agent/channels/slack-front.js.map +1 -1
  39. package/dist/agent/channels/slack-read.d.ts +6 -1
  40. package/dist/agent/channels/slack-read.d.ts.map +1 -1
  41. package/dist/agent/channels/slack-read.js +9 -3
  42. package/dist/agent/channels/slack-read.js.map +1 -1
  43. package/dist/agent/channels/slack-setup-page.d.ts +3 -0
  44. package/dist/agent/channels/slack-setup-page.d.ts.map +1 -0
  45. package/dist/agent/channels/slack-setup-page.js +13 -0
  46. package/dist/agent/channels/slack-setup-page.js.map +1 -0
  47. package/dist/agent/channels/slack-web-api.d.ts +3 -0
  48. package/dist/agent/channels/slack-web-api.d.ts.map +1 -1
  49. package/dist/agent/channels/slack-web-api.js +26 -6
  50. package/dist/agent/channels/slack-web-api.js.map +1 -1
  51. package/dist/agent/channels/slack.d.ts.map +1 -1
  52. package/dist/agent/channels/slack.js +11 -3
  53. package/dist/agent/channels/slack.js.map +1 -1
  54. package/dist/agent/contributions.d.ts +5 -0
  55. package/dist/agent/contributions.d.ts.map +1 -1
  56. package/dist/agent/contributions.js +1 -0
  57. package/dist/agent/contributions.js.map +1 -1
  58. package/dist/agent/docs-generated.js +1 -1
  59. package/dist/agent/docs-generated.js.map +1 -1
  60. package/dist/agent/ops.d.ts +1 -1
  61. package/dist/agent/ops.d.ts.map +1 -1
  62. package/dist/agent/ops.js +29 -47
  63. package/dist/agent/ops.js.map +1 -1
  64. package/dist/agent/register.d.ts.map +1 -1
  65. package/dist/agent/register.js +26 -2
  66. package/dist/agent/register.js.map +1 -1
  67. package/dist/agent/setup/claim.d.ts +73 -0
  68. package/dist/agent/setup/claim.d.ts.map +1 -0
  69. package/dist/agent/setup/claim.js +298 -0
  70. package/dist/agent/setup/claim.js.map +1 -0
  71. package/dist/agent/setup/credentials.d.ts +56 -0
  72. package/dist/agent/setup/credentials.d.ts.map +1 -0
  73. package/dist/agent/setup/credentials.js +214 -0
  74. package/dist/agent/setup/credentials.js.map +1 -0
  75. package/dist/agent/setup/eve-credentials.d.ts +22 -0
  76. package/dist/agent/setup/eve-credentials.d.ts.map +1 -0
  77. package/dist/agent/setup/eve-credentials.js +73 -0
  78. package/dist/agent/setup/eve-credentials.js.map +1 -0
  79. package/dist/agent/setup/install-state.d.ts +139 -0
  80. package/dist/agent/setup/install-state.d.ts.map +1 -0
  81. package/dist/agent/setup/install-state.js +196 -0
  82. package/dist/agent/setup/install-state.js.map +1 -0
  83. package/dist/agent/setup/page.d.ts +29 -0
  84. package/dist/agent/setup/page.d.ts.map +1 -0
  85. package/dist/agent/setup/page.js +460 -0
  86. package/dist/agent/setup/page.js.map +1 -0
  87. package/dist/agent/setup/slack-api-setup.d.ts +62 -0
  88. package/dist/agent/setup/slack-api-setup.d.ts.map +1 -0
  89. package/dist/agent/setup/slack-api-setup.js +138 -0
  90. package/dist/agent/setup/slack-api-setup.js.map +1 -0
  91. package/dist/agent/status.d.ts +4 -0
  92. package/dist/agent/status.d.ts.map +1 -0
  93. package/dist/agent/status.js +79 -0
  94. package/dist/agent/status.js.map +1 -0
  95. package/package.json +36 -3
@@ -0,0 +1,196 @@
1
+ // THE SLACK INSTALL RECORD (OPE-2231) — what a `/setup` run captured, and the ONE predicate the
2
+ // rest of the deployment asks about it.
3
+ //
4
+ // WHERE IT LIVES. Every field sits in the encrypted KV vault (core `credentials/kv-vault.ts`) under
5
+ // the reserved `slack-app:` namespace, so the outbound credential resolver refuses all of it — see
6
+ // `SLACK_APP_REF_NAMESPACE`'s own doc comment for why the bot token is reserved too. Four refs hold
7
+ // SECRET material and one holds the non-secret record:
8
+ //
9
+ // slack-app:client_secret the app's OAuth client secret (apps.manifest.create returned it)
10
+ // slack-app:signing_secret the app's request-signing secret (apps.manifest.create returned it)
11
+ // slack-app:bot_token the workspace bot token (oauth.v2.access returned it)
12
+ // slack-app:cookie_key the HMAC key for the claim cookie (this deployment minted it)
13
+ // slack-app:install the record below, as JSON (ids and timestamps only)
14
+ //
15
+ // 🔴 THE RECORD CARRIES NO SECRET, AND THAT IS WHAT MAKES IT READABLE. {@link slackInstallState} is
16
+ // the seam a STATUS ENDPOINT reads (OPE-2230 builds that endpoint; this function is its whole
17
+ // contract with Slack). A status endpoint is a place where a value gets rendered to whoever can
18
+ // reach it, so the thing it reads must be unable to carry one. Hence the split: ids and timestamps
19
+ // in `slack-app:install`, every secret under its own ref, and no function here that returns both.
20
+ // Adding a field to {@link SlackInstallState} means asking "would I publish this?" — if the answer
21
+ // is no, it belongs in its own ref instead.
22
+ //
23
+ // 🔴 THE RECORD IS THE LOCK. `/setup` is open while no record exists and closed once one does
24
+ // (`agent/setup/claim.ts` reads exactly this). So writing the record is the LAST act of a
25
+ // successful install, after both secrets are stored — a record written first would lock the page
26
+ // against a run that had not finished, with no way back in but the reopen call.
27
+ import { encryptedKvVault, SLACK_APP_REF_NAMESPACE } from "@open-everywhere/core/agent/adapter-api.js";
28
+ /** The ref holding the app's OAuth client secret. SECRET — never rendered, never logged. */
29
+ export const SLACK_CLIENT_SECRET_REF = `${SLACK_APP_REF_NAMESPACE}client_secret`;
30
+ /** The ref holding the app's request-signing secret. SECRET. */
31
+ export const SLACK_SIGNING_SECRET_REF = `${SLACK_APP_REF_NAMESPACE}signing_secret`;
32
+ /** The ref holding the workspace bot token (`xoxb-…`). SECRET. */
33
+ export const SLACK_BOT_TOKEN_REF = `${SLACK_APP_REF_NAMESPACE}bot_token`;
34
+ /**
35
+ * The ref holding a PENDING app's signing secret, between the create and the OAuth callback.
36
+ *
37
+ * 🔴 WHY A SECOND REF AND NOT JUST {@link SLACK_SIGNING_SECRET_REF}. That ref is LIVE — it is what
38
+ * verifies every inbound Slack request. Writing the new app's secret straight into it at the create
39
+ * step would swap the running deployment's signing key before the install existed, so an ABANDONED
40
+ * run (wrong workspace, expired token, closed tab) left an installed deployment unable to verify its
41
+ * own workspace's requests: every cold start from then on 401s, staggered by the per-process memo, with
42
+ * nothing in the logs saying a different secret had been picked. The callback promotes this to the live
43
+ * ref immediately before it records the install, so the live secret changes only when a run COMPLETES.
44
+ */
45
+ export const SLACK_PENDING_SIGNING_SECRET_REF = `${SLACK_APP_REF_NAMESPACE}pending_signing_secret`;
46
+ /** The ref holding the HMAC key for the claim cookie. SECRET, and minted here — see claim.ts. */
47
+ export const SLACK_COOKIE_KEY_REF = `${SLACK_APP_REF_NAMESPACE}cookie_key`;
48
+ /** The ref holding the one-time setup code a human reads out of the deployment's logs. SECRET. */
49
+ export const SLACK_SETUP_CODE_REF = `${SLACK_APP_REF_NAMESPACE}setup_code`;
50
+ /** The ref holding {@link SlackInstallState} as JSON. The ONLY ref here with no secret in it. */
51
+ export const SLACK_INSTALL_REF = `${SLACK_APP_REF_NAMESPACE}install`;
52
+ /** The ref holding the PENDING app record (`agent/setup/page.ts` writes and spends it). Declared here
53
+ * so one module owns the ref vocabulary — `reopenSlackSetup` has to clear it, and a ref it could not
54
+ * name is a ref it would leave behind. */
55
+ export const SLACK_PENDING_REF = `${SLACK_APP_REF_NAMESPACE}pending`;
56
+ function vaultOf(deps) {
57
+ return deps.vault ?? encryptedKvVault();
58
+ }
59
+ /**
60
+ * The recorded Slack install, or `undefined` when this deployment has none.
61
+ *
62
+ * 🔴 THIS IS THE SEAM OPE-2230's STATUS ENDPOINT READS, and the only one it should: it returns the
63
+ * whole non-secret truth about whether Slack is installed and where, and it can return nothing
64
+ * else. Call it; do not read `slack-app:install` directly, or the status endpoint and the claim lock
65
+ * end up with two readings of one record.
66
+ *
67
+ * FAIL-SOFT TO "NOT INSTALLED". An unreachable vault, a disarmed credential key, a malformed row or
68
+ * a record of an unknown version all answer `undefined`. For a STATUS READER that is the safe
69
+ * direction and the honest one: it reports Slack as not installed, which is true as far as this
70
+ * process can tell, and it cannot report an install that is not there.
71
+ *
72
+ * 🔴 THE CLAIM LOCK MUST NOT USE THIS FUNCTION. For the lock, the same collapse is a hole — a store
73
+ * fault would reopen `/setup`. The lock reads {@link readInstallRecord} instead, which tells the
74
+ * three cases apart. See its doc comment.
75
+ */
76
+ export async function slackInstallState(deps = {}) {
77
+ return (await readInstallRecord(deps)).state;
78
+ }
79
+ /** Read the install record, reporting WHICH of the three outcomes happened. The lock reads this. */
80
+ export async function readInstallRecord(deps = {}) {
81
+ let raw;
82
+ try {
83
+ raw = await vaultOf(deps).read(SLACK_INSTALL_REF);
84
+ }
85
+ catch {
86
+ return { kind: "unreadable", state: undefined };
87
+ }
88
+ if (raw === null)
89
+ return { kind: "absent", state: undefined };
90
+ const state = parseInstallState(raw);
91
+ // A row that exists but will not parse is the `unreadable` case, NOT `absent`: something is stored.
92
+ if (state === undefined)
93
+ return { kind: "unreadable", state: undefined };
94
+ return { kind: "present", state };
95
+ }
96
+ /** Parse + validate a stored record. Exported for the suite; `undefined` for anything unreadable. */
97
+ export function parseInstallState(raw) {
98
+ let parsed;
99
+ try {
100
+ parsed = JSON.parse(raw);
101
+ }
102
+ catch {
103
+ return undefined;
104
+ }
105
+ if (typeof parsed !== "object" || parsed === null)
106
+ return undefined;
107
+ const r = parsed;
108
+ if (r.v !== 1)
109
+ return undefined;
110
+ const str = (k) => (typeof r[k] === "string" && r[k].length > 0 ? r[k] : undefined);
111
+ const appId = str("appId");
112
+ const clientId = str("clientId");
113
+ const teamId = str("teamId");
114
+ const installerUserId = str("installerUserId");
115
+ const installedAt = str("installedAt");
116
+ if (!appId || !clientId || !teamId || !installerUserId || !installedAt)
117
+ return undefined;
118
+ const teamName = str("teamName");
119
+ return {
120
+ v: 1,
121
+ appId,
122
+ clientId,
123
+ teamId,
124
+ installerUserId,
125
+ installedAt,
126
+ ...(teamName ? { teamName } : {}),
127
+ };
128
+ }
129
+ /**
130
+ * Record a completed install. THE LAST WRITE OF A SUCCESSFUL `/setup` RUN — it is what closes the
131
+ * page, so every secret the install captured must already be stored when this is called.
132
+ *
133
+ * Throws whatever the vault throws (a disarmed credential key, an unreachable store). The caller
134
+ * must NOT swallow it: a run that stored the credentials but failed to record the install has to
135
+ * say so, because the page is still open and a second run would mint a second Slack app.
136
+ */
137
+ export async function recordSlackInstall(state, deps = {}) {
138
+ await vaultOf(deps).write(SLACK_INSTALL_REF, JSON.stringify(state), { connector: "slack", createdBy: "host:slack-setup" });
139
+ }
140
+ /**
141
+ * REOPEN the setup page: destroy the install record, keeping every stored credential.
142
+ *
143
+ * WHY THE LIVE CREDENTIALS STAY. A reopen is "let me run setup again", not "forget this workspace".
144
+ * The running deployment is still serving Slack with the stored bot token and signing secret while the
145
+ * admin walks the page, and a reopen that deleted them would take the agent off Slack the moment it
146
+ * was called. A COMPLETED second run replaces them, at its callback; an abandoned one leaves the
147
+ * working install untouched, which is true because the create step stages the new signing secret under
148
+ * {@link SLACK_PENDING_SIGNING_SECRET_REF} rather than writing the live ref.
149
+ *
150
+ * What DOES go, besides the record: the setup code (so the reopened page needs a fresh one — see
151
+ * below) and any stale pending-app material.
152
+ *
153
+ * THROWS on a failure to rotate the setup code or the claim cookie key, and leaves the install record
154
+ * in place when it does — see the body. A reopen that could not rotate must not open the page.
155
+ *
156
+ * NO REOPEN HISTORY SURVIVES THIS, deliberately. The record IS the lock, so reopening means
157
+ * destroying it, and a field recording "reopened at" would have to live on a record that no longer
158
+ * exists. The audit row is where the history lives (`slack.setup_reopened`, audit/action-registry.ts)
159
+ * — a hash-chained row naming the admin who called it, which is a better home for that fact than a
160
+ * field on a row the next install overwrites.
161
+ *
162
+ * Returns true iff a record went (false when the page was already open) — idempotent either way.
163
+ */
164
+ export async function reopenSlackSetup(deps = {}) {
165
+ const vault = vaultOf(deps);
166
+ return vault.withLock(SLACK_INSTALL_REF, async () => {
167
+ // 🔴 THE CLAIM CREDENTIALS DIE BEFORE THE LOCK DOES, and the order is the whole safety property.
168
+ //
169
+ // The record IS the lock, so deleting it is what opens the page. An earlier draft deleted it FIRST
170
+ // and then rotated these two with `.catch(() => undefined)`, returning `true` either way — the
171
+ // exact inverse of the rule `setup/page.ts` states for the install path. That left a real hole: if
172
+ // the setup-code delete failed, or the lambda was cut between the two, the page was OPEN with the
173
+ // PRE-INSTALL code still matching, and that code is in the deployment's log lines from before the
174
+ // install. Whoever read them could then claim the run.
175
+ //
176
+ // So: rotate first, open second, and let a rotation failure THROW. `vault.delete` answers `false`
177
+ // for an absent row rather than throwing, so the only thing that propagates here is a real store
178
+ // failure — and on one the record survives, the page stays shut, and the control verb reports the
179
+ // error instead of a reopen that left the door open.
180
+ //
181
+ // `slackSetupCode` returns the STORED value when one exists, so dropping the ref is what makes the
182
+ // next boot mint and log a fresh code. The cookie key goes with it: a claim cookie minted before
183
+ // the reopen is signed with that key, so leaving it would let a browser still holding one walk
184
+ // straight past the code prompt and undo the rotation.
185
+ await vault.delete(SLACK_SETUP_CODE_REF);
186
+ await vault.delete(SLACK_COOKIE_KEY_REF);
187
+ const reopened = await vault.delete(SLACK_INSTALL_REF);
188
+ // Stale pending-app material, AFTER the record. These two are not credentials and not the lock:
189
+ // the worst a leftover does is offer the install screen for an app the previous run abandoned, and
190
+ // a new run overwrites both. So a failure here is swallowed rather than failing the reopen.
191
+ await vault.delete(SLACK_PENDING_SIGNING_SECRET_REF).catch(() => undefined);
192
+ await vault.delete(SLACK_PENDING_REF).catch(() => undefined);
193
+ return reopened;
194
+ });
195
+ }
196
+ //# sourceMappingURL=install-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-state.js","sourceRoot":"","sources":["../../../agent/setup/install-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { type EncryptedKvVault } from "@open-everywhere/core/agent/adapter-api.js";
2
+ import { type SlackClaimDeps } from "./claim.js";
3
+ import { createSlackApp, exchangeSlackOauthCode } from "./slack-api-setup.js";
4
+ /** The page's route path. */
5
+ export declare const SLACK_SETUP_PATH = "/setup";
6
+ /** The OAuth install redirect's path. Declared in the shipped manifest's `oauth_config.redirect_urls`. */
7
+ export declare const SLACK_SETUP_CALLBACK_PATH = "/setup/callback";
8
+ /** Injectable seams for the suite. */
9
+ export interface SlackSetupPageDeps extends SlackClaimDeps {
10
+ readonly vault?: EncryptedKvVault;
11
+ readonly env?: NodeJS.ProcessEnv;
12
+ readonly createApp?: typeof createSlackApp;
13
+ readonly exchangeCode?: typeof exchangeSlackOauthCode;
14
+ readonly keyArmed?: () => boolean;
15
+ }
16
+ /** Render whichever screen this deployment is up to. Every refusal is {@link notAvailable}. */
17
+ export declare function handleSlackSetupGet(req: Request, deps?: SlackSetupPageDeps): Promise<Response>;
18
+ /** Screen 1 and screen 2's submits. */
19
+ export declare function handleSlackSetupPost(req: Request, deps?: SlackSetupPageDeps): Promise<Response>;
20
+ /**
21
+ * Slack's install redirect. Takes `code` + `state`, exchanges the code, records the install, and
22
+ * renders screen 4.
23
+ *
24
+ * This is the ONE render that happens after the lock closes, and it has to be: recording the install
25
+ * IS closing the page, and the operator still needs the two config lines. So the handler does its
26
+ * work and renders, rather than redirecting to a `/setup` that would now 404.
27
+ */
28
+ export declare function handleSlackSetupCallback(req: Request, deps?: SlackSetupPageDeps): Promise<Response>;
29
+ //# sourceMappingURL=page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../agent/setup/page.ts"],"names":[],"mappings":"AA4CA,OAAO,EAWL,KAAK,gBAAgB,EACtB,MAAM,4CAA4C,CAAC;AAGpD,OAAO,EAQL,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AAYpB,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAsB,MAAM,sBAAsB,CAAC;AAElG,6BAA6B;AAC7B,eAAO,MAAM,gBAAgB,WAAW,CAAC;AACzC,0GAA0G;AAC1G,eAAO,MAAM,yBAAyB,oBAAoB,CAAC;AAoC3D,sCAAsC;AACtC,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACtD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC;CACnC;AAsMD,+FAA+F;AAC/F,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoBxG;AAID,uCAAuC;AACvC,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAuFzG;AAID;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA+H7G"}