Files
deepseek-harness/Dockerfile
T
Miles WardandClaude Fable 5 ca70b61844
Sync upstream and build images / sync-and-build (push) Successful in 2m35s
Build npm next too; release generator with upstream notes + provenance; tags cleanup
- CI plan: candidates are npm latest AND next (release candidates), plus an
  optional workflow_dispatch 'version' input for any exact version. This is
  what was holding back 0.1.5-rc.2 (published as next, not latest).
- Upstream dsh-v* tags are no longer mirrored into this repo (deleted the
  existing ones); master stays an exact branch mirror and every release links
  to its upstream tag. This repo's tags are now exclusively v<image tag>.
- Dockerfile: build-provenance labels (org.opencontainers.image.revision /
  .created, dev.milesward.ci-run) so releases cite the commit and CI run that
  actually built the image instead of whatever HEAD is at publish time.
- Releases: shell template replaced by .gitea/scripts/publish-releases.js,
  run on the node:22 base image (no runner deps). It pulls the upstream
  GitHub release's English notes, adds version-dependent caveats (launch
  token from 0.1.2, Session format V3 from 0.1.5), image facts and Unraid
  deploy steps. Existing v* tags re-pointed to 2d033c3 (the commit that
  built those images); their releases are regenerated in this format.
- README: dynamic badges (shields Gitea release, Gitea workflow status),
  0.1.5-rc.2 row, pipeline/tag-namespace docs updated.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-09-10 17:04:16 -04:00

84 lines
3.9 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.
# GIT_SHA / CI_RUN / BUILD_DATE: build provenance, read back by the release
# publisher so each release points at the commit that actually built it.
ARG BASE_DIGEST=""
ARG GIT_SHA=""
ARG CI_RUN=""
ARG BUILD_DATE=""
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.revision="${GIT_SHA}" \
org.opencontainers.image.created="${BUILD_DATE}" \
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}" \
dev.milesward.ci-run="${CI_RUN}"
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"]