feat(docker): add python development image#349
Conversation
Publishes ghcr.io/umputun/ralphex-python (extends base with uv, ruff, mypy, pytest) alongside the existing base and Go images. Adds matching build/merge jobs to docker.yml for both linux/amd64 and linux/arm64, a docker-build-python make target, and documentation in README and llms.txt.
📝 WalkthroughWalkthroughThis pull request introduces a new Python development Docker image ( ChangesPython Development Image Support
Sequence DiagramsequenceDiagram
participant GitHub as GitHub Actions
participant Build as build-python Job
participant Arch1 as linux/amd64
participant Arch2 as linux/arm64
participant Merge as merge-python Job
participant GHCR as GHCR Registry
GitHub->>Build: Trigger build-python
Build->>Arch1: Build for linux/amd64
Arch1->>GHCR: Push image, export digest
Build->>Arch2: Build for linux/arm64
Arch2->>GHCR: Push image, export digest
Build->>Build: Upload digest artifacts
Merge->>Merge: Download per-arch digests
Merge->>Merge: Generate semver/branch tags
Merge->>GHCR: Create and push multi-arch manifest
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
Dockerfile-python (1)
12-14: ⚡ Quick winPin Python tool versions for deterministic image builds.
Unpinned
ruff,mypy, andpytestmake image contents drift over time. Pin explicit versions (or ARG-driven versions) to keep builds reproducible.Suggested change
+ARG RUFF_VERSION=<pin> +ARG MYPY_VERSION=<pin> +ARG PYTEST_VERSION=<pin> RUN uv tool install ruff && \ - uv tool install mypy && \ - uv tool install pytest + uv tool install "ruff==${RUFF_VERSION}" && \ + uv tool install "mypy==${MYPY_VERSION}" && \ + uv tool install "pytest==${PYTEST_VERSION}"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Dockerfile-python` around lines 12 - 14, The RUN lines invoking "uv tool install ruff", "uv tool install mypy", and "uv tool install pytest" should pin explicit versions (or accept build ARGs) to ensure deterministic images; update these invocations to include version specifiers (e.g. ruff==X.Y.Z, mypy==A.B.C, pytest==M.N.O) or replace each literal with an ARG (e.g. $RUFF_VERSION) and provide sensible defaults via ARG declarations so the Docker build uses fixed tool versions unless overridden.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/docker.yml:
- Around line 412-420: The workflow only sets latest=true for semver branches,
so pushes from master never publish :latest; update the branch-tagging logic
around HEAD_BRANCH and GITHUB_OUTPUT to treat master as a "latest" publish
target: change the conditional that sets tag/minor/latest (the block using
HEAD_BRANCH, BASH_REMATCH and writing to GITHUB_OUTPUT) to include an elseif for
HEAD_BRANCH == "master" (or "main" if desired) that sets echo "tag=master" >>
$GITHUB_OUTPUT, echo "minor=" >> $GITHUB_OUTPUT, and echo "latest=true" >>
$GITHUB_OUTPUT (and mirror the same change in the second copy of the block
currently at the later location).
In `@Dockerfile-python`:
- Line 8: The Dockerfile currently pipes the uv installer (RUN wget -qO-
https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh) which
verifies tarball checksums, but the downstream tool installs for ruff, mypy, and
pytest are unpinned; update those install commands to pin exact versions (or use
environment variables like RUFF_VERSION, MYPY_VERSION, PYTEST_VERSION) and
install specific releases (e.g., ruff==X.Y.Z, mypy==A.B.C, pytest==P.Q.R) to
ensure reproducible builds and deterministic images, updating the corresponding
install lines referenced in this Dockerfile.
---
Nitpick comments:
In `@Dockerfile-python`:
- Around line 12-14: The RUN lines invoking "uv tool install ruff", "uv tool
install mypy", and "uv tool install pytest" should pin explicit versions (or
accept build ARGs) to ensure deterministic images; update these invocations to
include version specifiers (e.g. ruff==X.Y.Z, mypy==A.B.C, pytest==M.N.O) or
replace each literal with an ARG (e.g. $RUFF_VERSION) and provide sensible
defaults via ARG declarations so the Docker build uses fixed tool versions
unless overridden.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: fcca49be-d8fa-4e9c-9dfc-e63422535581
📒 Files selected for processing (5)
.github/workflows/docker.ymlDockerfile-pythonMakefileREADME.mdllms.txt
| if [[ "$HEAD_BRANCH" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then | ||
| # semver tag: v0.7.2 -> tags: 0.7.2, 0.7, latest | ||
| echo "tag=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" >> $GITHUB_OUTPUT | ||
| echo "minor=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" >> $GITHUB_OUTPUT | ||
| echo "latest=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "tag=${HEAD_BRANCH}" >> $GITHUB_OUTPUT | ||
| echo "minor=" >> $GITHUB_OUTPUT | ||
| echo "latest=false" >> $GITHUB_OUTPUT |
There was a problem hiding this comment.
latest is never published from master for the Python image.
Current logic only sets latest=true for semver branches. On master, this job pushes :master but not :latest, which conflicts with the documented .../ralphex-python:latest usage.
Suggested fix
- name: set docker tags
id: tags
env:
HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
if [[ "$HEAD_BRANCH" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
# semver tag: v0.7.2 -> tags: 0.7.2, 0.7, latest
echo "tag=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}" >> $GITHUB_OUTPUT
echo "minor=${BASH_REMATCH[1]}.${BASH_REMATCH[2]}" >> $GITHUB_OUTPUT
echo "latest=true" >> $GITHUB_OUTPUT
+ elif [ "$HEAD_BRANCH" = "master" ]; then
+ echo "tag=${HEAD_BRANCH}" >> $GITHUB_OUTPUT
+ echo "minor=" >> $GITHUB_OUTPUT
+ echo "latest=true" >> $GITHUB_OUTPUT
else
echo "tag=${HEAD_BRANCH}" >> $GITHUB_OUTPUT
echo "minor=" >> $GITHUB_OUTPUT
echo "latest=false" >> $GITHUB_OUTPUT
fiAlso applies to: 434-436
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/docker.yml around lines 412 - 420, The workflow only sets
latest=true for semver branches, so pushes from master never publish :latest;
update the branch-tagging logic around HEAD_BRANCH and GITHUB_OUTPUT to treat
master as a "latest" publish target: change the conditional that sets
tag/minor/latest (the block using HEAD_BRANCH, BASH_REMATCH and writing to
GITHUB_OUTPUT) to include an elseif for HEAD_BRANCH == "master" (or "main" if
desired) that sets echo "tag=master" >> $GITHUB_OUTPUT, echo "minor=" >>
$GITHUB_OUTPUT, and echo "latest=true" >> $GITHUB_OUTPUT (and mirror the same
change in the second copy of the block currently at the later location).
| LABEL org.opencontainers.image.description="Autonomous plan execution with Claude Code - Python development" | ||
|
|
||
| # install uv - modern Python package and project manager | ||
| RUN wget -qO- https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Locate and examine the Dockerfile-python file
find . -name "Dockerfile-python" -o -name "*Dockerfile*python*" | head -20Repository: umputun/ralphex
Length of output: 79
🏁 Script executed:
# Get the content of the Dockerfile
git ls-files | grep -i dockerfile | head -20Repository: umputun/ralphex
Length of output: 224
🏁 Script executed:
# Search for Dockerfile files
fd -t f "Dockerfile" | head -20Repository: umputun/ralphex
Length of output: 224
🌐 Web query:
uv installer security checksum verification astral
💡 Result:
As of May 2026, the uv installer includes security features to ensure the integrity of the binaries it installs. For users installing uv via the standalone shell script (install.sh), the installer embeds checksums directly into the script's source code [1]. This allows the installer to verify the integrity of the downloaded tarball before proceeding with the installation [2][1]. This mechanism was introduced to provide security benefits for users who vendor the installer script into their own build or CI/CD processes [1]. For broader security, Astral also generates Sigstore-based attestations for uv binary and Docker image releases [1]. These attestations create a cryptographically verifiable link between the released artifact and the workflow that produced it, allowing users to verify that their build of uv originated from Astral's official release processes [1]. Users can verify these attestations using the GitHub CLI [3][4][5]: gh attestation verify --repo astral-sh/uv Regarding the uv self update command, it is designed to work only for installations performed via the standalone installation scripts [6][7]. While the installer script itself has been updated to include checksum verification, users should be aware that uv self update relies on the underlying update infrastructure (axoupdater) to manage the replacement of the binary [8][9]. For environments where security is a primary concern, such as CI/CD pipelines, users are encouraged to use the official, cryptographically verifiable release artifacts and, where applicable, verify them using the provided Sigstore attestations [1][3].
Citations:
- 1: https://astral.sh/blog/open-source-security-at-astral
- 2: Verify checksum in installer script astral-sh/uv#13074
- 3: https://newreleases.io/project/github/astral-sh/uv/release/0.11.2
- 4: https://newreleases.io/project/github/astral-sh/uv/release/0.10.11
- 5: https://newreleases.io/project/github/astral-sh/uv/release/0.11.1
- 6: uv self update not working for fresh install (also uvw.exe quarantined by Windows Defender) astral-sh/uv#17417
- 7: uv self update does not update astral-sh/uv#5514
- 8:
uv self updatemay leave uv unusable if interrupted astral-sh/uv#12142 - 9: Allow running uv self update behind firewalls astral-sh/uv#8069
🏁 Script executed:
cat -n ./Dockerfile-pythonRepository: umputun/ralphex
Length of output: 675
The uv installer already includes integrity verification; however, consider pinning tool versions.
The uv install.sh script embeds checksums and verifies the integrity of downloaded tarballs before installation, mitigating the primary supply-chain risk. However, the subsequent tool installations (lines 12–14) lack version constraints, reducing reproducibility. Pin versions for ruff, mypy, and pytest to ensure deterministic builds:
-RUN uv tool install ruff && \
- uv tool install mypy && \
- uv tool install pytest
+RUN uv tool install ruff==0.X.X && \
+ uv tool install mypy==1.X.X && \
+ uv tool install pytest==8.X.X🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Dockerfile-python` at line 8, The Dockerfile currently pipes the uv installer
(RUN wget -qO- https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin
sh) which verifies tarball checksums, but the downstream tool installs for ruff,
mypy, and pytest are unpinned; update those install commands to pin exact
versions (or use environment variables like RUFF_VERSION, MYPY_VERSION,
PYTEST_VERSION) and install specific releases (e.g., ruff==X.Y.Z, mypy==A.B.C,
pytest==P.Q.R) to ensure reproducible builds and deterministic images, updating
the corresponding install lines referenced in this Dockerfile.
umputun
left a comment
There was a problem hiding this comment.
i don't think we should add this image.
Go image works as a reasonably universal reference: one Go version, go test, and a few common global tools. Python doesn't have the same shape. Real Python projects usually need their own Python version, native deps, lockfile/project deps, pytest plugins, and sometimes poetry/pdm instead of uv. A global uv + ruff + mypy + pytest image looks more like a template than a reusable runtime.
We already have documentation showing how to make a custom image, with the Go image as the example. Adding another template-like image doesn't improve that. It adds CI/release/GHCR surface and makes ralphex-python look like a supported artifact, while most Python users will still need to customize it.
There is also a concrete runtime bug in the current Dockerfile: uv tool install runs as root and leaves tool envs under /root/.local/share/uv/tools, while the container runs as app. The image builds, but ruff fails with permission denied in a normal container run. CodeRabbit's latest tag and unpinned-tool comments are valid too.
Declining this PR as an official Python image.
Adds and publishes the ghcr.io/umputun/ralphex-python image with Python tooling (uv, ruff, mypy, pytest). Includes multi-arch build/merge jobs in docker.yml, a docker-build-python make target, and documentation updates in README and llms.txt.
Summary by CodeRabbit
New Features
Documentation