Sync upstream and build images / sync-and-build (push) Successful in 2m4s
- Dockerfile: install pnpm (pinned via PNPM_VERSION arg) alongside dsh so 'dsh plugin --profile web add|update|remove' works in-container. Plain 'npm i -g' instead of corepack: corepack shims resolve versions at runtime and write to a root-owned cache, breaking the uid-1000/read-only contract. All pnpm writable dirs (store via PNPM_HOME, cache/state via XDG vars) point into the /home/node/.dsh volume - verified zero rootfs writes. - Dockerfile: ENTRYPOINT ['dsh'], CMD carries the patch flag AND --no-open (a headless server must not open a browser; on 0.1.2+ that can burn the one-time launch token). DSH_VERSION default pinned to 0.1.1-rc.2. - CI: never publishes or moves 'latest' (deleted from the registry). Builds only missing immutable version tags; a toolchain freshness check rebuilds the pinned version as <ver>-rN when a newer pnpm or node base image ships. Every build passes a smoke test before push: dsh/pnpm versions match and the server boots with the baked patch, answering on the container's non-loopback interface (200 pre-token, 303/401 on 0.1.2+). - README: operating contract - pinned version rationale, PostArgs-replace-CMD warning, 0.1.2 launch-token behavior, plugin management, lanmode incompatibility, template pinned to :0.1.1-rc.2. Co-Authored-By: Claude Fable 5 <[email protected]>
76 lines
3.6 KiB
Docker
76 lines
3.6 KiB
Docker
# Trusted container build of DeepSeek Harness (dsh).
|
|
#
|
|
# Upstream (https://github.com/deepseek-ai/deepseek-harness) publishes no
|
|
# official container image — only the @deepseek-ai/dsh npm package, released
|
|
# from the tagged source mirrored in this repository's `master` branch. This
|
|
# image installs that exact pinned release from registry.npmjs.org, so its
|
|
# provenance chain is: upstream tag -> upstream npm release -> this Dockerfile.
|
|
#
|
|
# No upstream code is patched. The all-interfaces bind goes through upstream's
|
|
# supported `--patch` launcher layer (/opt/deepseek-harness/web.cordis.patch.yml);
|
|
# the UI is only reachable through ports you explicitly publish on the host.
|
|
|
|
FROM node:22-bookworm-slim
|
|
|
|
# DSH_VERSION default is the pinned, known-good deployment version: 0.1.2+
|
|
# introduced launch-token auth and the @Remote gateway (breaks lanmode).
|
|
# Moving off it is a deliberate template edit, never a side effect of CI.
|
|
ARG DSH_VERSION=0.1.1-rc.2
|
|
# pnpm is required on PATH by dsh's plugin manager (`dsh plugin --profile web
|
|
# add|update|remove`). CI passes the current release; the scheduled freshness
|
|
# check rebuilds a -rN revision tag when a newer pnpm or base image ships.
|
|
ARG PNPM_VERSION=12.3.4
|
|
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends ca-certificates git \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# pnpm is a fixed npm global rather than a corepack shim: corepack resolves
|
|
# versions at runtime and can attempt downloads/writes outside the state
|
|
# volume (its cache is root-owned), which breaks the non-root uid-1000 /
|
|
# read-only-rootfs contract. A pinned global install is deterministic,
|
|
# offline, and readable by uid 1000.
|
|
RUN npm install -g "@deepseek-ai/dsh@${DSH_VERSION}" "pnpm@${PNPM_VERSION}" \
|
|
&& npm cache clean --force
|
|
|
|
COPY web.cordis.patch.yml /opt/deepseek-harness/web.cordis.patch.yml
|
|
|
|
# /workspace: the agent's working directory (mount your project here);
|
|
# /home/node/.dsh: dsh state (settings, credentials, sessions, plugins).
|
|
RUN mkdir -p /workspace /home/node/.dsh \
|
|
&& chown node:node /workspace /home/node/.dsh
|
|
|
|
# Everything writable at runtime (dsh state, pnpm store/cache for plugin
|
|
# installs) lives inside the mounted state volume, never the rootfs.
|
|
ENV DSH_HOME=/home/node/.dsh \
|
|
PNPM_HOME=/home/node/.dsh/.pnpm \
|
|
XDG_CACHE_HOME=/home/node/.dsh/.cache \
|
|
XDG_STATE_HOME=/home/node/.dsh/.state
|
|
|
|
EXPOSE 3080
|
|
|
|
USER node
|
|
WORKDIR /workspace
|
|
|
|
ARG DSH_VERSION
|
|
ARG PNPM_VERSION
|
|
# BASE_DIGEST: resolved digest of the FROM image at build time; the scheduled
|
|
# freshness check compares it (and pnpm-version) against current releases.
|
|
ARG BASE_DIGEST=""
|
|
LABEL org.opencontainers.image.title="deepseek-harness" \
|
|
org.opencontainers.image.description="DeepSeek Harness (dsh) web UI, built from the official npm release" \
|
|
org.opencontainers.image.version="${DSH_VERSION}" \
|
|
org.opencontainers.image.source="https://gitea.milesward.dev/mward4/deepseek-harness" \
|
|
org.opencontainers.image.url="https://github.com/deepseek-ai/deepseek-harness" \
|
|
org.opencontainers.image.licenses="MIT" \
|
|
dev.milesward.dsh-version="${DSH_VERSION}" \
|
|
dev.milesward.pnpm-version="${PNPM_VERSION}" \
|
|
dev.milesward.base-digest="${BASE_DIGEST}"
|
|
|
|
ENTRYPOINT ["dsh"]
|
|
# --patch must come immediately after `web` (launcher flag), --no-open so a
|
|
# headless server never launches a browser (on 0.1.2+ an in-container browser
|
|
# could consume the one-time launch token). Unraid Post Arguments REPLACE this
|
|
# CMD entirely — operators must repeat the patch flag and --no-open.
|
|
CMD ["web", "--patch", "/opt/deepseek-harness/web.cordis.patch.yml", "--no-open"]
|