Files
shelfmark/Dockerfile
T
dependabot[bot] 22aa59e567 build(deps): bump the docker-base-image-digests group with 2 updates (#1306)
> [!WARNING]
> Cooldown could not be applied because no publication date was
available from the registry.
>

Bumps the docker-base-image-digests group with 2 updates: node and
[astral-sh/uv](https://github.com/astral-sh/uv).

Updates `node` from `d32cdf6` to `e67514e`

Updates `astral-sh/uv` from 0.12.5 to 0.12.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/releases">astral-sh/uv's
releases</a>.</em></p>
<blockquote>
<h2>0.12.9</h2>
<h2>Release Notes</h2>
<p>Released on 2026-09-01.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21413">#21413</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/21415">#21415</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--no-locked</code> and <code>--no-frozen</code> to disable
lock modes enabled by <code>UV_LOCKED</code> and <code>UV_FROZEN</code>
for a single invocation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21408">#21408</a>)</li>
<li>Report the exact command-line lock-mode flag in warnings and errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21402">#21402</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up cold wheel installs by extracting each streaming ZIP
archive in a single blocking task and reusing buffers across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21372">#21372</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Update <code>async_http_range_reader</code> to 0.11.1 to address a
potential memory-safety issue when reading metadata ranges from
untrusted wheels (<a
href="https://redirect.github.com/astral-sh/uv/pull/21401">#21401</a>)</li>
<li>Remove sensitive headers when redirects cross authentication realms,
including same-host redirects that change URL schemes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21382">#21382</a>)</li>
<li>Redact secrets in signed URLs from retry diagnostics, including
nested request errors (<a
href="https://redirect.github.com/astral-sh/uv/pull/21381">#21381</a>)</li>
<li>Give <code>--locked</code>, <code>--frozen</code>,
<code>--check</code>, and <code>--check-exists</code> precedence over
conflicting <code>UV_LOCKED</code> and <code>UV_FROZEN</code> values (<a
href="https://redirect.github.com/astral-sh/uv/pull/21396">#21396</a>)</li>
<li>Prevent concurrent uv processes from redundantly extracting the same
local or source-built wheel (<a
href="https://redirect.github.com/astral-sh/uv/pull/21400">#21400</a>)</li>
</ul>
<h2>Install uv 0.12.9</h2>
<h3>Install prebuilt binaries via shell script</h3>
<pre lang="sh"><code>curl --proto '=https' --tlsv1.2 -LsSf
https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-installer.sh
| sh
</code></pre>
<h3>Install prebuilt binaries via powershell script</h3>
<pre lang="sh"><code>powershell -ExecutionPolicy Bypass -c &quot;irm
https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-installer.ps1
| iex&quot;
</code></pre>
<h2>Download uv 0.12.9</h2>
<table>
<thead>
<tr>
<th>File</th>
<th>Platform</th>
<th>Checksum</th>
</tr>
</thead>
<tbody>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-apple-darwin.tar.gz">uv-aarch64-apple-darwin.tar.gz</a></td>
<td>Apple Silicon macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-apple-darwin.tar.gz">uv-x86_64-apple-darwin.tar.gz</a></td>
<td>Intel macOS</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-apple-darwin.tar.gz.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-pc-windows-msvc.zip">uv-aarch64-pc-windows-msvc.zip</a></td>
<td>ARM64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-i686-pc-windows-msvc.zip">uv-i686-pc-windows-msvc.zip</a></td>
<td>x86 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-i686-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-pc-windows-msvc.zip">uv-x86_64-pc-windows-msvc.zip</a></td>
<td>x64 Windows</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-x86_64-pc-windows-msvc.zip.sha256">checksum</a></td>
</tr>
<tr>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-unknown-linux-gnu.tar.gz">uv-aarch64-unknown-linux-gnu.tar.gz</a></td>
<td>ARM64 Linux</td>
<td><a
href="https://releases.astral.sh/github/uv/releases/download/0.12.9/uv-aarch64-unknown-linux-gnu.tar.gz.sha256">checksum</a></td>
</tr>
</tbody>
</table>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/astral-sh/uv/blob/main/CHANGELOG.md">astral-sh/uv's
changelog</a>.</em></p>
<blockquote>
<h2>0.12.9</h2>
<p>Released on 2026-09-01.</p>
<h3>Python</h3>
<ul>
<li>Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/pull/21413">#21413</a>,
<a
href="https://redirect.github.com/astral-sh/uv/pull/21415">#21415</a>)</li>
</ul>
<h3>Enhancements</h3>
<ul>
<li>Add <code>--no-locked</code> and <code>--no-frozen</code> to disable
lock modes enabled by <code>UV_LOCKED</code> and <code>UV_FROZEN</code>
for a single invocation (<a
href="https://redirect.github.com/astral-sh/uv/pull/21408">#21408</a>)</li>
<li>Report the exact command-line lock-mode flag in warnings and errors
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21402">#21402</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Speed up cold wheel installs by extracting each streaming ZIP
archive in a single blocking task and reusing buffers across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21372">#21372</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Update <code>async_http_range_reader</code> to 0.11.1 to address a
potential memory-safety issue when reading metadata ranges from
untrusted wheels (<a
href="https://redirect.github.com/astral-sh/uv/pull/21401">#21401</a>)</li>
<li>Remove sensitive headers when redirects cross authentication realms,
including same-host redirects that change URL schemes (<a
href="https://redirect.github.com/astral-sh/uv/pull/21382">#21382</a>)</li>
<li>Redact secrets in signed URLs from retry diagnostics, including
nested request errors (<a
href="https://redirect.github.com/astral-sh/uv/pull/21381">#21381</a>)</li>
<li>Give <code>--locked</code>, <code>--frozen</code>,
<code>--check</code>, and <code>--check-exists</code> precedence over
conflicting <code>UV_LOCKED</code> and <code>UV_FROZEN</code> values (<a
href="https://redirect.github.com/astral-sh/uv/pull/21396">#21396</a>)</li>
<li>Prevent concurrent uv processes from redundantly extracting the same
local or source-built wheel (<a
href="https://redirect.github.com/astral-sh/uv/pull/21400">#21400</a>)</li>
</ul>
<h2>0.12.8</h2>
<p>Released on 2026-08-31.</p>
<h3>Enhancements</h3>
<ul>
<li>Warn about invalid tool directories and continue upgrading valid
tools with <code>uv tool upgrade --all</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21368">#21368</a>)</li>
</ul>
<h3>Preview features</h3>
<ul>
<li>Deduplicate identical files within and across cached wheels with the
<code>content-addressed-cache</code> preview feature (<a
href="https://redirect.github.com/astral-sh/uv/pull/21327">#21327</a>)</li>
<li>Reduce allocations while extracting content-addressed wheels by
reusing the hashing buffer across files (<a
href="https://redirect.github.com/astral-sh/uv/pull/21340">#21340</a>)</li>
<li>Speed up content-addressed cache cleanup on macOS by reading
hard-link counts in bulk (<a
href="https://redirect.github.com/astral-sh/uv/pull/21344">#21344</a>)</li>
</ul>
<h3>Performance</h3>
<ul>
<li>Prevent concurrent uv processes from downloading and extracting the
same remote wheel more than once (<a
href="https://redirect.github.com/astral-sh/uv/pull/21379">#21379</a>)</li>
<li>Speed up dependency graph construction from large lockfiles by
indexing packages during traversal (<a
href="https://redirect.github.com/astral-sh/uv/pull/21373">#21373</a>)</li>
<li>Extend indexed lockfile traversal to exports, dependency trees,
audits, and freshness checks (<a
href="https://redirect.github.com/astral-sh/uv/pull/21377">#21377</a>)</li>
<li>Speed up warm resolutions by reducing repeated marker interner work
(<a
href="https://redirect.github.com/astral-sh/uv/pull/21300">#21300</a>)</li>
</ul>
<h3>Bug fixes</h3>
<ul>
<li>Do not trust hashes from direct URLs discovered only in wheel
metadata when installing with <code>--require-hashes</code> (<a
href="https://redirect.github.com/astral-sh/uv/pull/21348">#21348</a>)</li>
<li>Use a compatible Azure Storage API version for anonymous and
authenticated requests, allowing credential retries when public access
is disabled (<a
href="https://redirect.github.com/astral-sh/uv/pull/21366">#21366</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/astral-sh/uv/commit/9f928602938ac5cf1cd6b294a725833c16f5720e"><code>9f92860</code></a>
Bump version to 0.12.9 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21422">#21422</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/29c546228ed6ba8970bb063960c9a767fae19236"><code>29c5462</code></a>
Skip invalid scripts in <code>uv workspace list --scripts</code> (<a
href="https://redirect.github.com/astral-sh/uv/issues/21416">#21416</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/bf1d7e8049017a363565185a7df7e86f33041452"><code>bf1d7e8</code></a>
Encapsulate wheel extraction directory ownership (<a
href="https://redirect.github.com/astral-sh/uv/issues/21419">#21419</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6dacee042f58cea9184267ffb70c6960582bb210"><code>6dacee0</code></a>
Run streaming ZIP extraction in a blocking task (<a
href="https://redirect.github.com/astral-sh/uv/issues/21372">#21372</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/91d1ebf1b4ea1fc00928b412a9da23639aacb086"><code>91d1ebf</code></a>
Sync latest Python releases (<a
href="https://redirect.github.com/astral-sh/uv/issues/21415">#21415</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/6a61ddb2c094ab44e55a2cc5bb4a88b7c08d733a"><code>6a61ddb</code></a>
Revert &quot;Limit CI planner checkout depth&quot; (<a
href="https://redirect.github.com/astral-sh/uv/issues/21414">#21414</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/e9d1816b538468e7deb8f267f28775007706b866"><code>e9d1816</code></a>
Add CPython 3.15.0rc2 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21413">#21413</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/e888329afc22fa3e34f93d5ae5e23fbc87328952"><code>e888329</code></a>
Remove unreachable lock configuration sources (<a
href="https://redirect.github.com/astral-sh/uv/issues/21409">#21409</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/bf041f9245952ba7c9e3c29aebe0a8acc2bc983d"><code>bf041f9</code></a>
Allow negating locked and frozen modes (<a
href="https://redirect.github.com/astral-sh/uv/issues/21408">#21408</a>)</li>
<li><a
href="https://github.com/astral-sh/uv/commit/feffc0b5bbf8aeca1dff4a6f042a58e44a5daf09"><code>feffc0b</code></a>
Bump async_http_range_reader to 0.11.1 (<a
href="https://redirect.github.com/astral-sh/uv/issues/21401">#21401</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/astral-sh/uv/compare/0.12.5...0.12.9">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-04 11:03:26 -04:00

248 lines
10 KiB
Docker

ARG TARGETPLATFORM
ARG TARGETARCH
ARG BUILDPLATFORM
ARG BUILDARCH
# Frontend build stage.
FROM --platform=$BUILDPLATFORM node:24-alpine@sha256:e67514e5d0f6c46656005e1b693b2ec9d52e80b641307de684d4a015ba7a4eaf AS frontend-builder
# Helpful debug output to see what platforms BuildKit thinks it's using
RUN echo "BUILDPLATFORM=$BUILDPLATFORM BUILDARCH=$BUILDARCH TARGETPLATFORM=$TARGETPLATFORM TARGETARCH=$TARGETARCH"
WORKDIR /frontend
# Copy frontend package files
COPY src/frontend/package*.json ./
# Install dependencies (cache mount for faster rebuilds)
RUN --mount=type=cache,target=/root/.npm \
npm ci
# Copy frontend source
COPY src/frontend/ ./
# Build the frontend
RUN npm run build
# uv is a build-time tool only, so it is mounted into the RUNs that need it rather
# than copied into the image. A COPY here would land ~24 MB in a `base` layer that
# every published image inherits, and a later `rm` cannot take it back out again --
# a RUN adds a layer, it does not rewrite the one underneath.
FROM ghcr.io/astral-sh/uv:0.12.9@sha256:8b940d3a9d65bed080436972241af2e21c84b5e8c9193f7014ed71479ee795ff AS uv
# Use python-slim as the base image
FROM python:3.14.7-slim@sha256:cad9a2c871761c413caa6fdd6441c783451e740a48aaeba60ae62a8b53525ef6 AS base
# Add build argument for version
ARG BUILD_VERSION
ENV BUILD_VERSION=${BUILD_VERSION}
ARG RELEASE_VERSION
ENV RELEASE_VERSION=${RELEASE_VERSION}
# Set shell to bash with pipefail option
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
# Consistent environment variables grouped together
ENV DEBIAN_FRONTEND=noninteractive \
DOCKERMODE=true \
UV_LINK_MODE=copy \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONIOENCODING=UTF-8 \
NAME=Shelfmark \
PATH=/app/.venv/bin:$PATH \
PYTHONPATH=/app \
# PUID/PGID will be handled by entrypoint script, but TZ/Locale are still needed
LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8
# Set ARG for build-time expansion (FLASK_PORT), ENV for runtime access
ENV FLASK_PORT=8084
# Configure locale, timezone, and perform initial cleanup in a single layer
RUN apt-get update && \
apt-get install -y --no-install-recommends \
# For building C-extensions (cffi, gevent, etc.)
gcc \
g++ \
libffi-dev \
python3-dev \
# For locale
locales tzdata \
# For healthcheck
curl \
# For entrypoint
dumb-init \
# For debug
zip iputils-ping \
# For user switching
gosu \
# --- Tor support (activated via USING_TOR=true) ---
tor \
supervisor \
iptables \
# --- WireGuard support (activated via USING_WIREGUARD=true) ---
wireguard-tools \
iproute2 \
procps \
ca-certificates && \
# Configure iptables alternatives for tor.sh compatibility
update-alternatives --set iptables /usr/sbin/iptables-legacy && \
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy && \
# Cleanup APT cache *after* all installs in this layer
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
# Default to UTC timezone but will be overridden by the entrypoint script
ln -snf /usr/share/zoneinfo/UTC /etc/localtime && echo UTC > /etc/timezone && \
# Configure locale
sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \
locale-gen en_US.UTF-8 && \
echo "LC_ALL=en_US.UTF-8" >> /etc/environment && \
echo "LANG=en_US.UTF-8" > /etc/locale.conf
# Create a fixed runtime user/group so hardened Docker/Kubernetes deployments
# can start the container directly as a non-root user with a passwd entry.
RUN groupadd -g 1000 shelfmark && \
useradd -u 1000 -g shelfmark -d /home/shelfmark -s /usr/sbin/nologin shelfmark && \
mkdir -p /home/shelfmark && \
chown 1000:1000 /home/shelfmark
# Set working directory
WORKDIR /app
# Install core Python dependencies first for better layer caching
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv sync --locked --no-default-groups
# Runtime dependencies are installed into /app/.venv during the build. Remove the
# base image's system pip so stale installer CVEs do not ship in the final image.
RUN rm -rf \
/usr/local/bin/pip \
/usr/local/bin/pip3 \
/usr/local/bin/pip3.* \
/usr/local/lib/python*/site-packages/pip \
/usr/local/lib/python*/site-packages/pip-*.dist-info
# Copy application code *after* dependencies are installed
COPY . .
# Copy built frontend from frontend-builder stage
COPY --from=frontend-builder /frontend/dist /app/frontend-dist
# Final setup: create image-owned runtime paths for the fixed non-root user.
# Root/PUID mode still re-homes ownership at startup when needed.
RUN mkdir -p \
/config \
/books \
/var/log/shelfmark \
/tmp/shelfmark/seleniumbase/downloaded_files \
/tmp/shelfmark/seleniumbase/archived_files && \
rm -rf /app/downloaded_files /app/archived_files && \
ln -s /tmp/shelfmark/seleniumbase/downloaded_files /app/downloaded_files && \
ln -s /tmp/shelfmark/seleniumbase/archived_files /app/archived_files && \
chown -R 1000:1000 /config /books /home/shelfmark /tmp/shelfmark /var/log/shelfmark && \
chmod -R a+rX /app && \
chmod +x /app/entrypoint.sh /app/tor.sh /app/wireguard.sh /app/genDebug.sh
# Expose the application port
EXPOSE ${FLASK_PORT}
# Add healthcheck for container status
# Uses /api/health which doesn't require authentication.
# curl needs -f so an HTTP error status fails the probe instead of passing it:
# plain `curl -s` exits 0 on a 500, which reported a broken app as healthy.
# timeout stays well under interval so a hung probe cannot occupy a whole cycle.
# --start-interval matches the daemon default (5s), made explicit so startup
# probing does not depend on that default staying put.
HEALTHCHECK --interval=30s --timeout=10s --start-period=90s --start-interval=5s --retries=3 \
CMD curl -fsS http://localhost:${FLASK_PORT}/api/health > /dev/null || exit 1
# Use dumb-init as the entrypoint to handle signals properly
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
FROM base AS shelfmark
# --- Chromium (PINNED to 149.0.7827.196) ---
# Debian's chromium 150.0.7871.46-1~deb13u1 security update (trixie-security,
# 2026-07-05) no longer opens the DevTools remote-debugging TCP port at all
# (no listener, no DevToolsActivePort file, even with a custom --user-data-dir;
# the RemoteDebuggingAllowed policy does not restore it). The SeleniumBase
# Pure-CDP driver connects through that port (/json/version), so with 150 every
# internal bypass dies with "Pure CDP browser startup failed" and all
# CF-gated downloads fail. Install the last working version from
# snapshot.debian.org until the bypasser can talk to Chromium >= 150 (e.g.
# pipe-based DevTools / UC mode) or seleniumbase ships a fix.
# Chrome 144+ requires --enable-unsafe-swiftshader for WebGL in Docker.
# This flag is set in internal_bypasser.py _get_browser_args()
ARG CHROMIUM_VERSION=149.0.7827.196-1~deb13u1
ARG CHROMIUM_SNAPSHOT=20260704T000000Z
RUN echo "deb [check-valid-until=no] https://snapshot.debian.org/archive/debian-security/${CHROMIUM_SNAPSHOT}/ trixie-security main" \
> /etc/apt/sources.list.d/chromium-pin-snapshot.list && \
apt-get update -o Acquire::Retries=5 && \
apt-get install -y --no-install-recommends -o Acquire::Retries=5 \
# For dumb display
xvfb \
# For screen recording
ffmpeg \
chromium=${CHROMIUM_VERSION} \
chromium-common=${CHROMIUM_VERSION} \
# For tkinter (pyautogui)
python3-tk \
# For RAR extraction
unrar-free && \
# Keep apt from "upgrading" chromium past the pin inside derived images
printf 'Package: chromium chromium-common\nPin: version %s\nPin-Priority: 1001\n' "${CHROMIUM_VERSION}" \
> /etc/apt/preferences.d/chromium-pin && \
rm /etc/apt/sources.list.d/chromium-pin-snapshot.list && \
# Create symlink so rarfile library can find unrar
ln -sf /usr/bin/unrar-free /usr/bin/unrar && \
# Cleanup APT cache
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install the browser automation stack used by the full image
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv sync --locked --no-default-groups --extra browser
# Deterministically resolve the Xlib namespace collision.
# pyautogui/mouseinfo pull the stale `python3-xlib` (0.15, 2014), while the
# `--extra browser` set pulls `python-xlib` (0.33). Both packages install into
# the same top-level `Xlib/` namespace, so whichever lands last wins. When the
# 2014 build wins, `Xlib.X` is missing `FamilyServerInterpreted`, which the
# SeleniumBase Pure-CDP driver requires at browser startup -> every bypass fails
# with "module 'Xlib.X' has no attribute 'FamilyServerInterpreted'" and no
# Cloudflare/DDoS-Guard protected download can complete. Drop the stale package
# and force python-xlib 0.33 to own the namespace. pyautogui runs fine against
# 0.33 (superset API).
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=from=uv,source=/uv,target=/usr/local/bin/uv \
uv pip uninstall --python /app/.venv/bin/python python3-xlib && \
uv pip install --python /app/.venv/bin/python --reinstall python-xlib==0.33 && \
/app/.venv/bin/python -c "import Xlib.X; assert hasattr(Xlib.X, 'FamilyServerInterpreted'), 'Xlib.X.FamilyServerInterpreted missing after fix'; print('Xlib namespace OK:', Xlib.__version__)"
# Keep SeleniumBase's bundled driver cache writable for the fixed non-root user.
RUN SELENIUMBASE_DRIVERS_DIR=$(/app/.venv/bin/python -c "import pathlib, seleniumbase; print(pathlib.Path(seleniumbase.__file__).resolve().parent / 'drivers')") && \
chown -R 1000:1000 "${SELENIUMBASE_DRIVERS_DIR}" && \
chmod -R u+rwX,go+rX "${SELENIUMBASE_DRIVERS_DIR}" && \
if [ -f "${SELENIUMBASE_DRIVERS_DIR}/uc_driver" ]; then chmod +x "${SELENIUMBASE_DRIVERS_DIR}/uc_driver"; fi
# Grant read/execute permissions to others
RUN chmod -R o+rx /usr/bin/chromium
# Default command to run the application entrypoint script
CMD ["/app/entrypoint.sh"]
FROM base AS shelfmark-lite
ENV USING_EXTERNAL_BYPASSER=true
CMD ["/app/entrypoint.sh"]