penpot/media-processor/esbuild.config.mjs
Andrey Antukh fc500d1102 🐛 Harden SVG sanitization: workers, limits and error mapping
Address the review findings on the DOMPurify SVG sanitization.

F1: sanitizeSvg was synchronous and blocked the service's only event
loop: a ~30 MiB SVG (the old cap) froze media-processor for ~20 s and
peaked at ~3.4 GiB. The sanitizer now runs in a worker_threads pool
(sanitizeSvgSync is the CPU-bound core), each worker has a
resourceLimits heap cap so an OOM kills the worker and not the process,
and a stuck job is terminated by a timeout and respawned. The default
SVG cap drops to 2 MiB and is enforced in both modes (the backend
validates the declared and the real size on upload, and the real bytes
on import), so a file is accepted or rejected the same way with and
without media-processor.

F2: an unexpected sanitizer failure is logged and reported as 503
svg-sanitization-failed instead of 400 invalid-svg-file, so a service
fault is not blamed on the user's file and no internal detail leaks in
the hint.

F4: the remote backend rejects a 2xx response that is not an SVG
instead of storing it.

Also pin the backend/service wire contract with a test that posts the
exact multipart the JVM builds, and pin the data: URI behavior.

AI-assisted-by: deepseek-v4.1-flash
2026-10-07 17:49:38 +00:00

18 lines
401 B
JavaScript

import { build } from "esbuild";
await build({
entryPoints: ["src/index.ts", "src/svg-worker.ts"],
bundle: true,
platform: "node",
target: "node24",
format: "esm",
outdir: "dist",
external: ["sharp", "pino", "pino-pretty", "pino-loki", "dompurify", "jsdom"],
banner: {
js: `
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
`,
},
});