Skip to content

build(docker): run as non-root and pin base images by digest - #47

Merged
wikithoughts merged 1 commit into
mainfrom
overnight/dockerfile-nonroot
Oct 11, 2026
Merged

wikithoughts merged 1 commit into
mainfrom
overnight/dockerfile-nonroot

Conversation

@wikithoughts

Copy link
Copy Markdown
Owner

What changed

Review F23 (task T15): the image ran as root, used an editable install, and both base images floated (python:3.12-slim, searxng/searxng:latest).

Dockerfile

  • FROM python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1. This is the multi-arch index digest, so amd64 and arm64 both resolve. The tag stays for readability.
  • Regular, non-editable pip install --no-cache-dir '.[extract]'. The package now sits in site-packages, root-owned and read-only to the runtime user.
  • A pw user and group (UID/GID 1000, matching compose's PW_UID/PW_GID default) and USER 1000:1000. The ID is numeric so runAsNonRoot-style checks can verify it.
  • /app/data is pre-created pw:pw 0700, so a fresh named volume mounted there (the coordinator's PW_DB) inherits a writable owner.

docker-compose.yml

  • searxng/searxng:latest@sha256:85492ba800a861e3e8ff6014c430e81369fe6ca766a9990595f616d1ce95b272 (index digest).
  • Rewrote the stale note "the image has no USER, so it runs as root" and documented how to refresh a pin.
  • Documented a one-time chown for coordinator volumes created by the old root image. Without it, an existing pw-coordinator-db volume stays root-owned and the non-root coordinator can't write its DB.

Digest provenance

Both digests were read from Docker Hub on 2026-10-11 with docker buildx imagetools inspect python:3.12-slim and docker buildx imagetools inspect searxng/searxng:latest (top-level Digest:, media type application/vnd.oci.image.index.v1+json). The python index resolves to 3.12.15-slim-trixie (created 2026-10-06T01:55:50Z, docker-library/python@2a3b794). None of the digests were typed from memory.

Verification (this VPS, rootless Docker 29.9.0 / buildx 0.38.0)

  • docker build --pull -t <probe> . → exit 0. Rebuilt after the hadolint fixes → exit 0.
  • docker run --rm <probe> id → uid=1000(pw) gid=1000(pw). HOME=/home/pw. Config.User=1000:1000. pworkers --help OK. Writing /app fails with Permission denied (expected).
  • Desk: docker run -p 127.0.0.1:<port>:8770 <probe> then curl / → 200.
  • Coordinator on a fresh named volume (python -m passiveworkers.net.coordinator_app, a random 48-hex PW_TOKEN, PW_HOST=0.0.0.0): /healthz → 200, / → 200. coordinator.db was created owned by 1000:1000.
  • Upgrade path: I made the compose volume root-owned (simulating the old image), then ran the documented docker compose run --rm --user root --entrypoint chown coordinator -R pw:pw /app/data. Afterwards /app/data and coordinator.db were owned by 1000 and writable by the default user.
  • PW_TOKEN=<placeholder> docker compose config -q → exit 0.
  • hadolint (hadolint/hadolint@sha256:32dac941… via docker run --rm -i) → exit 0. The first pass flagged DL3066 (non-numeric USER), now fixed, and DL3013 (pin pip versions). DL3013 is suppressed inline because the install target is the local project, not a registry package.
  • ruff check . && pytest tests/ -q --cov=passiveworkers --cov-fail-under=75 → exit 0 (740 passed, 1 skipped, Total coverage: 83.38%). No Python changed.
  • I removed every probe image, container and volume afterwards.

Not verified / notes

🤖 Generated with Claude Code

Review F23: the image ran as root, used an editable install, and both
python:3.12-slim and searxng/searxng:latest floated.

- Dockerfile: base pinned to the python:3.12-slim multi-arch index
  digest; regular (non-editable) `pip install '.[extract]'`; a `pw`
  user (UID/GID 1000, matching compose's PW_UID/PW_GID default) and
  `USER 1000:1000`; /app/data pre-created pw-owned so a fresh named
  volume (the coordinator DB) is writable.
- docker-compose.yml: searxng pinned to the latest index digest; the
  stale "image has no USER" note rewritten; a one-time chown command
  documented for coordinator volumes created by the old root image.

Digests were read from the registry with
`docker buildx imagetools inspect <image>:<tag>` on 2026-10-11.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wikithoughts
wikithoughts merged commit af2e814 into main Oct 11, 2026
11 checks passed
@wikithoughts
wikithoughts deleted the overnight/dockerfile-nonroot branch October 11, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant