ADR-070: PLAYWRIGHT_BROWSERS_PATH for Non-Root Docker Execution
Status: Accepted Date: 2026-02-25
Context
PDF generation in StorePredict uses Playwright (headless Chromium) to render the
print-optimised NiceGUI page and export it as a PDF. The Dockerfile installs
Chromium during the build phase (as root) and then switches to a non-root
appuser for the runtime process.
By default, Playwright stores browser binaries under ~/.cache/ms-playwright.
When installed as root this resolves to /root/.cache/ms-playwright. At runtime,
appuser looks in /home/appuser/.cache/ms-playwright, which does not exist,
causing every PDF export to fail with a browser-not-found error.
Decision
Set the PLAYWRIGHT_BROWSERS_PATH environment variable to /ms-playwright in the
Dockerfile before the playwright install step. After installation, grant world
read+execute on that directory with chmod -R o+rX /ms-playwright.
ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
RUN .venv/bin/playwright install chromium --with-deps \
&& chmod -R o+rX /ms-playwright
The ENV directive persists into the runtime container so the Playwright Python
API discovers the correct path automatically — no application code change required.
Rationale
- A fixed, non-home-relative path is independent of which user runs the process.
ENVpropagates to every subsequent layer and to the final running container.chmod o+rXis the minimum permission grant: read and directory-traverse for "other", without making binaries writable.- No alternative (e.g. keeping the
rootuser, or copying the cache into the home directory) is as clean or as secure.
Alternatives Considered
- Run as root: Avoids the permission problem but violates container security best-practices and is rejected by hardened Kubernetes/OpenShift environments.
- Copy
/root/.cache/ms-playwrightto/home/appuser/.cache/: Works but is fragile (the copy must happen afteruseradd) and duplicates disk usage. --with-depsalready called — skip chmod:--with-depsinstalls system packages but does not change the755/700permissions of the browser cache directory itself, which is still owned by root with mode700.
Consequences
- All PDF exports (DRR report, layout report, concerns report) work correctly in
the production container under
appuser. - The
/ms-playwrightdirectory adds ~200 MB to the image; this was already present in the layer — the fix merely makes it accessible. - Rebuilding the image is required to apply this fix to existing deployments.