Skip to content

Commit 850b003

Browse files
committed
fix(slack): tighten upload-file validation
1 parent 352e8d2 commit 850b003

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

extensions/slack/src/message-action-dispatch.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,22 @@ describe("handleSlackMessageAction", () => {
104104
);
105105
});
106106

107+
it("requires filePath, path, or media for upload-file", async () => {
108+
await expect(
109+
handleSlackMessageAction({
110+
providerId: "slack",
111+
ctx: {
112+
action: "upload-file",
113+
cfg: {},
114+
params: {
115+
to: "channel:C1",
116+
},
117+
} as never,
118+
invoke: createInvokeSpy() as never,
119+
}),
120+
).rejects.toThrow(/upload-file requires filePath, path, or media/i);
121+
});
122+
107123
it("maps download-file to the internal downloadFile action", async () => {
108124
const invoke = createInvokeSpy();
109125

extensions/slack/src/message-action-dispatch.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,10 @@ export async function handleSlackMessageAction(params: {
204204
const filePath =
205205
readStringParam(actionParams, "filePath", { trim: false }) ??
206206
readStringParam(actionParams, "path", { trim: false }) ??
207-
readStringParam(actionParams, "media", { required: true, trim: false });
207+
readStringParam(actionParams, "media", { trim: false });
208+
if (!filePath) {
209+
throw new Error("upload-file requires filePath, path, or media");
210+
}
208211
const threadId =
209212
readStringParam(actionParams, "threadId") ?? readStringParam(actionParams, "replyTo");
210213
return await invoke(

extensions/slack/src/send.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ async function uploadSlackFile(params: {
244244
localRoots: params.mediaLocalRoots,
245245
});
246246
const uploadFileName = params.uploadFileName ?? fileName ?? "upload";
247-
const uploadTitle = params.uploadTitle ?? params.uploadFileName ?? fileName ?? "upload";
247+
const uploadTitle = params.uploadTitle ?? uploadFileName;
248248
// Use the 3-step upload flow (getUploadURLExternal -> POST -> completeUploadExternal)
249249
// instead of files.uploadV2 which relies on the deprecated files.upload endpoint
250250
// and can fail with missing_scope even when files:write is granted.

extensions/slack/src/send.upload.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,25 @@ describe("sendMessageSlack file upload with user IDs", () => {
250250
}),
251251
);
252252
});
253+
254+
it("uses uploadFileName as the title fallback when uploadTitle is omitted", async () => {
255+
const client = createUploadTestClient();
256+
257+
await sendMessageSlack("channel:C123CHAN", "caption", {
258+
token: "xoxb-test",
259+
client,
260+
mediaUrl: "/tmp/threaded.png",
261+
uploadFileName: "custom-name.bin",
262+
});
263+
264+
expect(client.files.getUploadURLExternal).toHaveBeenCalledWith({
265+
filename: "custom-name.bin",
266+
length: Buffer.from("fake-image").length,
267+
});
268+
expect(client.files.completeUploadExternal).toHaveBeenCalledWith(
269+
expect.objectContaining({
270+
files: [expect.objectContaining({ id: "F001", title: "custom-name.bin" })],
271+
}),
272+
);
273+
});
253274
});

0 commit comments

Comments
 (0)