From 9f066fae3581ff75625035faf914c38a5c3a4308 Mon Sep 17 00:00:00 2001 From: Ryan Gentry Date: Fri, 24 Jul 2026 22:37:04 -0500 Subject: [PATCH] fix(cli): accept text and octet-stream in the upload allowlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `buzz upload file` rejects any file whose sniffed MIME is not an image or mp4, but it uploads to the relay's BUD-02 `/upload` endpoint, and that endpoint routes non-media attachments — docs, archives, text, data — through `process_file_upload` and stores them. The CLI is stricter than the endpoint it posts to, so a plain-text file the relay would accept fails client-side with "unsupported file type: application/octet-stream" and never leaves the machine. `infer` has no plain-text matcher, so a text file arrives at the check as `application/octet-stream`; that entry is what unblocks it, and `text/plain` is added alongside for the paths where a text MIME is known. Adds a unit test asserting both entries so the widening is not silently reverted. Co-Authored-By: Claude Opus 5 --- crates/buzz-cli/src/client.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/crates/buzz-cli/src/client.rs b/crates/buzz-cli/src/client.rs index d0dd2677a9e..a77496d82e7 100644 --- a/crates/buzz-cli/src/client.rs +++ b/crates/buzz-cli/src/client.rs @@ -61,12 +61,21 @@ pub fn build_imeta_tag(d: &BlobDescriptor) -> Vec { } /// MIME types accepted for upload. +/// +/// Includes `text/plain` and `application/octet-stream` because the relay's +/// `upload_blob` routes non-media attachments (docs, archives, text, data) +/// through its generic-file path. Without them this allowlist is stricter than +/// the endpoint it posts to, and the CLI rejects files the relay would store. +/// `infer` cannot identify plain text, so text files arrive here as +/// `application/octet-stream`. const ALLOWED_MIMES: &[&str] = &[ "image/jpeg", "image/png", "image/gif", "image/webp", "video/mp4", + "text/plain", + "application/octet-stream", ]; /// Maximum file size for image uploads (50 MB). @@ -1431,6 +1440,21 @@ pub fn normalize_write_response(raw: &str) -> String { raw.to_string() } +#[cfg(test)] +mod upload_mime_tests { + use super::ALLOWED_MIMES; + + // The allowlist must accept text and the generic octet-stream fallback, or + // the CLI rejects files the relay's generic-file path would store. `infer` + // returns no type for plain text, so a text file reaches the check as + // `application/octet-stream` — both entries are needed. + #[test] + fn allowlist_accepts_text_and_octet_stream() { + assert!(ALLOWED_MIMES.contains(&"text/plain")); + assert!(ALLOWED_MIMES.contains(&"application/octet-stream")); + } +} + #[cfg(test)] mod retry_tests { use std::time::Duration;