Skip to content

feat(docker): add python development image#349

Closed
andreygaag wants to merge 1 commit into
umputun:masterfrom
andreygaag:add_docker_image_for_python
Closed

feat(docker): add python development image#349
andreygaag wants to merge 1 commit into
umputun:masterfrom
andreygaag:add_docker_image_for_python

Conversation

@andreygaag
Copy link
Copy Markdown

@andreygaag andreygaag commented May 17, 2026

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

    • Released a new Python development Docker image with pre-installed development tools and multi-architecture support for x86_64 and ARM64 platforms
  • Documentation

    • Updated documentation with instructions for using the Python development image

Review Change Stack

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.
@andreygaag andreygaag requested a review from umputun as a code owner May 17, 2026 16:12
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a new Python development Docker image (ralphex-python) with integrated development tools. The Dockerfile extends the base ralphex image and installs uv, ruff, mypy, and pytest. A GitHub Actions CI/CD pipeline builds multi-architecture images for linux/amd64 and linux/arm64, publishes them to GHCR, and merges digests into a multi-arch manifest. Local build support is added via a Makefile target, and documentation is updated in README and llms.txt.

Changes

Python Development Image Support

Layer / File(s) Summary
Python Development Image Definition
Dockerfile-python
Parameterized Dockerfile extending the ralphex base image, installing uv package manager into /usr/local/bin, and configuring Python development utilities via uv tool install (ruff, mypy, pytest).
CI/CD Pipeline for Multi-Arch Build and Publish
.github/workflows/docker.yml
Adds IMAGE_PYTHON environment variable, build-python job that builds and pushes Dockerfile-python for two architectures with computed base image tags and digest artifacts, and merge-python job that verifies digest counts, generates semver-based Docker tags (or falls back to branch name), and creates/pushes the multi-architecture manifest.
Local Build Integration
Makefile
Adds docker-build-python target that builds the Python image with -f Dockerfile-python and updates .PHONY declarations.
Documentation Updates
README.md, llms.txt
Updates README "Available images" section to include ghcr.io/umputun/ralphex-python:latest, adds Python projects subsection with environment variable usage example, and adds entry to llms.txt Docker images table describing the Python image contents.

Sequence Diagram

sequenceDiagram
  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
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A Python image hops into view,
With tools of the trade bundled through,
uv, ruff, mypy align,
Multi-arch builds so fine,
Developers rejoice—ralphex works for you! 📦

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(docker): add python development image' accurately describes the main change: introducing a new Python development Docker image. It is specific, clear, and directly reflects the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
Dockerfile-python (1)

12-14: ⚡ Quick win

Pin Python tool versions for deterministic image builds.

Unpinned ruff, mypy, and pytest make 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

📥 Commits

Reviewing files that changed from the base of the PR and between 5d07e2b and 593309c.

📒 Files selected for processing (5)
  • .github/workflows/docker.yml
  • Dockerfile-python
  • Makefile
  • README.md
  • llms.txt

Comment on lines +412 to +420
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

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
           fi

Also 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).

Comment thread Dockerfile-python
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# Locate and examine the Dockerfile-python file
find . -name "Dockerfile-python" -o -name "*Dockerfile*python*" | head -20

Repository: umputun/ralphex

Length of output: 79


🏁 Script executed:

# Get the content of the Dockerfile
git ls-files | grep -i dockerfile | head -20

Repository: umputun/ralphex

Length of output: 224


🏁 Script executed:

# Search for Dockerfile files
fd -t f "Dockerfile" | head -20

Repository: 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:


🏁 Script executed:

cat -n ./Dockerfile-python

Repository: 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.

Copy link
Copy Markdown
Owner

@umputun umputun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@umputun umputun closed this May 17, 2026
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.

2 participants