fix: resolve 18 QA-discovered bugs across tools, previews, and the AI pipeline (#242)

Exhaustive QA sweep of all 157 tools. Fixes: CSP blob media, csv-excel ExcelJS interop, ocr-pdf segfault, chart-maker upload, non-PDF doc preview, RAW decode, merge-tool multi-file path, html-to-image chromium, ogv/wma/amr/ac3 preview fallbacks, meme/gif/stabilize codecs, nav+home a11y. Plus orphan-format and test-debt cleanup, the AI bundle build script, and a reusable Playwright QA harness under tests/qa/.
This commit is contained in:
SnapOtter
2026-06-15 22:26:24 +08:00
committed by GitHub
parent 25babfae15
commit d8cf979d4b
83 changed files with 16014 additions and 112 deletions
+3 -3
View File
@@ -13,17 +13,17 @@ const SCALAR_FONT_ORIGIN = "https://fonts.scalar.com";
* would require forking the Scalar plugin, which is not practical.
*/
export function buildCsp(isDocs: boolean): string {
const connectSrc = ["'self'", "data:", ...POSTHOG_ORIGINS, ...SENTRY_ORIGINS].join(" ");
const connectSrc = ["'self'", "blob:", "data:", ...POSTHOG_ORIGINS, ...SENTRY_ORIGINS].join(" ");
const fontSrc = isDocs ? `'self' data: ${SCALAR_FONT_ORIGIN}` : "'self' data:";
const scriptSrc = isDocs
? "'self' 'unsafe-inline' https://us-assets.i.posthog.com"
: "'self' https://us-assets.i.posthog.com";
if (isDocs) {
return `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; connect-src ${connectSrc}; font-src ${fontSrc}; object-src 'none'; base-uri 'self'; form-action 'self'`;
return `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; media-src 'self' blob:; connect-src ${connectSrc}; font-src ${fontSrc}; object-src 'none'; base-uri 'self'; form-action 'self'`;
}
return `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data: https://tile.openstreetmap.org; connect-src ${connectSrc}; font-src ${fontSrc}; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'`;
return `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data: https://tile.openstreetmap.org; media-src 'self' blob:; connect-src ${connectSrc}; font-src ${fontSrc}; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'`;
}
export function getSecurityHeaders(): Record<string, string> {
+7
View File
@@ -243,6 +243,13 @@ export async function validateImageBuffer(
detectedFormat = "png";
}
// RAW formats with non-TIFF magic bytes (Panasonic RW2, some Olympus ORF,
// Pentax PEF, etc.) are not caught by MAGIC_BYTES. Fall back to
// extension-based detection for known Camera RAW extensions.
if (!detectedFormat && ext && isRawExtension(ext)) {
detectedFormat = "raw";
}
if (!detectedFormat) {
return { valid: false, reason: "Unrecognized image format" };
}
+35 -1
View File
@@ -211,7 +211,41 @@ async function decodeRaw(buffer: Buffer, ext?: string): Promise<Buffer> {
// ExifTool not available or no embedded JPEG -- fall through
}
// Attempt 2: ImageMagick + LibRaw delegate (full decode)
// Attempt 1b: ExifTool PreviewImage extraction (some formats store
// preview under a different tag than JpgFromRaw).
try {
const { stdout } = await execFileAsync("exiftool", ["-b", "-PreviewImage", inputPath], {
encoding: "buffer",
maxBuffer: 50 * 1024 * 1024,
timeout: 30_000,
} as never);
const previewBuf = stdout as unknown as Buffer;
if (previewBuf && previewBuf.length > 1000) {
if (previewBuf[0] === 0xff && previewBuf[1] === 0xd8) {
return previewBuf;
}
}
} catch {
// fall through
}
// Attempt 2: dcraw_emu from libraw-bin (direct LibRaw decode to TIFF).
// More reliable than ImageMagick's delegate chain for Camera RAW.
try {
await execFileAsync("dcraw_emu", ["-T", "-w", "-o", "1", inputPath], { timeout: 120_000 });
// dcraw_emu writes output next to the input with a .tiff extension
const dcrawOutput = inputPath.replace(/\.[^.]+$/, ".tiff");
const tiffBuf = await readFile(dcrawOutput);
await rm(dcrawOutput, { force: true }).catch(() => {});
if (tiffBuf.length > 0) {
// Convert TIFF to PNG via Sharp (Sharp handles TIFF natively)
return await sharp(tiffBuf).png().toBuffer();
}
} catch {
// dcraw_emu not available or unsupported format -- fall through
}
// Attempt 3: ImageMagick + LibRaw delegate (full decode)
const cmd = await findMagickCmd();
await execFileAsync(
cmd,