Files
Theo Gregory dc2dca42f1 fix(upload): default attachments to private, add --public opt-in
Image attachments uploaded via `issue attach` and `issue comment add
--attach` were sent with makePublic auto-detected to true for raster
images, producing a public.linear.app URL readable by anyone,
unauthenticated, with no way to opt out. This silently published
screenshots of internal data from private workspaces.

Default all uploads to private (uploads.linear.app), matching the Linear
web app. Add a --public flag to both commands to opt into a public URL,
which is only valid for raster images; requesting it for other types is
now an error rather than a silent downgrade. Print a warning whenever an
upload lands on a public URL.

Also document the attachment commands and their privacy behaviour in the
README (previously undocumented) and regenerate the skill reference.

Fixes #233

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 12:45:00 -07:00

48 lines
1.4 KiB
TypeScript

import { assertEquals, assertThrows } from "@std/assert"
import { resolveMakePublic } from "../../src/utils/upload.ts"
import { ValidationError } from "../../src/utils/errors.ts"
Deno.test("resolveMakePublic - defaults to private when not requested", () => {
assertEquals(resolveMakePublic("image/png"), false)
assertEquals(resolveMakePublic("image/png", undefined), false)
})
Deno.test("resolveMakePublic - defaults to private for non-image types", () => {
assertEquals(resolveMakePublic("application/pdf"), false)
})
Deno.test("resolveMakePublic - allows public for raster images when requested", () => {
for (
const type of [
"image/png",
"image/jpeg",
"image/gif",
"image/webp",
"image/bmp",
"image/tiff",
]
) {
assertEquals(resolveMakePublic(type, true), true)
}
})
Deno.test("resolveMakePublic - explicit false stays private even for images", () => {
assertEquals(resolveMakePublic("image/png", false), false)
})
Deno.test("resolveMakePublic - rejects public for non-public-capable types", () => {
// SVG is an image but not allowed to be public by Linear
assertThrows(
() => resolveMakePublic("image/svg+xml", true),
ValidationError,
)
assertThrows(
() => resolveMakePublic("application/pdf", true),
ValidationError,
)
assertThrows(
() => resolveMakePublic("application/octet-stream", true),
ValidationError,
)
})