From 0fac49e60a1c53a6212839009b9f6d4a496ba87e Mon Sep 17 00:00:00 2001 From: ZDDC Date: Wed, 13 May 2026 13:10:01 -0500 Subject: [PATCH] fix(convert): chromium needs --disable-dev-shm-usage + larger /tmp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTML→PDF stage failed with: Creating shared memory in /dev/shm/.org.chromium.Chromium.XXXXXX failed: Read-only file system (30) Unable to access(W_OK|X_OK) /dev/shm: Read-only file system (30) Chromium tries to put its IPC shared-memory segments under /dev/shm by default. Our container runs --read-only with /dev/shm inherited from the image (which makes it read-only too). The well-known fix is the --disable-dev-shm-usage chromium flag, which routes those allocations to /tmp instead. /tmp is a writable tmpfs we already set up. Bump its size from 128 MiB to 256 MiB so chromium has room for both its user-data-dir and the redirected shared-memory segments. A small PDF flow used ~64 MiB free of 128 MiB available; doubling gives headroom without materially changing the pod's memory footprint (tmpfs only consumes RAM for bytes actually written). The discardable_shared_memory_manager warning ("Less than 64MB of free space in temporary directory") in the prior chromium log was a symptom of this same /tmp-too-small condition; the bump quiets it too. Other warnings in the log (dbus connect failures) are not load- bearing — chromium falls back gracefully when dbus is absent. No fix needed there. --- zddc/internal/convert/convert.go | 7 +++++++ zddc/internal/convert/runner.go | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/zddc/internal/convert/convert.go b/zddc/internal/convert/convert.go index 702bd76..5a9782d 100644 --- a/zddc/internal/convert/convert.go +++ b/zddc/internal/convert/convert.go @@ -210,10 +210,17 @@ func ToPDF(ctx context.Context, source []byte, m Metadata) ([]byte, error) { // required because the container drops CAP_SYS_ADMIN; the threat // model is "malicious markdown drives chromium RCE", contained by // --network=none + --cap-drop=ALL + --read-only + tmpfs. + // + // --disable-dev-shm-usage: without this, chromium tries to allocate + // shared memory under /dev/shm, which our --read-only container + // can't write to. The flag tells chromium to fall back to /tmp, + // which is a writable tmpfs (sized in runner.go). Standard fix for + // chromium-in-container; required by every CI/headless setup. cmd := []string{ "--headless", "--disable-gpu", "--no-sandbox", + "--disable-dev-shm-usage", "--user-data-dir=/tmp/chrome", "--no-pdf-header-footer", "--virtual-time-budget=10000", diff --git a/zddc/internal/convert/runner.go b/zddc/internal/convert/runner.go index 2fdb53e..550129b 100644 --- a/zddc/internal/convert/runner.go +++ b/zddc/internal/convert/runner.go @@ -244,7 +244,11 @@ func (cr *containerRunner) Run(ctx context.Context, image string, stdin []byte, args = append(args, "--network=none", "--read-only", - "--tmpfs=/tmp:size=128m,exec", + // /tmp must be large enough to host chromium's shared-memory + // fallback (--disable-dev-shm-usage redirects /dev/shm writes + // here) plus the user-data-dir. 256 MiB is plenty for the + // HTML→PDF flow; pandoc itself uses almost none. + "--tmpfs=/tmp:size=256m,exec", "--tmpfs=/run:size=4m", fmt.Sprintf("--memory=%dm", memMiB), fmt.Sprintf("--cpus=%s", cpus),