Skip to content

feat: add Python pip & pipx to the base image (#121)#122

Merged
GordonBeeming merged 3 commits into
mainfrom
gb/121-pip-base-image
Jun 28, 2026
Merged

feat: add Python pip & pipx to the base image (#121)#122
GordonBeeming merged 3 commits into
mainfrom
gb/121-pip-base-image

Conversation

@GordonBeeming

Copy link
Copy Markdown
Owner

Closes #121.

What

python3 was already present in the images (pulled in transitively by software-properties-common), but there was no pip, so pip-distributed CLIs like APM couldn't be installed. This adds python3-pip, python3-venv and pipx to the shared system-packages snippet, so every image variant gets them in one place.

Why pipx + PATH

The base is Debian 12 (bookworm), which enforces PEP 668 — a bare pip install <tool> fails with externally-managed-environment. pipx is the supported way to install CLI apps (it drops each into its own venv); pip still works inside venvs.

pipx installs to ~/.local/bin, which isn't on PATH by default. Since the entrypoint always runs as appuser with HOME=/home/appuser, I put that dir on PATH two ways so it's reachable everywhere:

  • ENV PATH=... — covers the exec'd run command and non-login shells.
  • /etc/profile.d/copilot-local-bin.sh — re-adds it for login shells, which otherwise reset PATH via /etc/profile (Debian zsh sources it too).

End result: pipx install apm then apm just works, no pipx ensurepath needed.

Changes

  • docker/snippets/system-packages.Dockerfile — add the three packages + PATH wiring.
  • Regenerated docker/generated/* (copilot variants). The claude-* variants live on the still-open feat: add Claude Code as a CLI provider with published images #120 branch; their regen lands when the branches combine (CI auto-regenerates Dockerfiles).
  • README.md + docs/docker-images.md — note Python/pip/pipx in the base image.

Test plan

Built Dockerfile.default and verified:

$ python3 --version   # Python 3.11.2
$ pip --version       # pip 23.0.1
$ pipx --version      # 1.1.0
$ pipx install apm && command -v apm   # /home/appuser/.local/bin/apm

Confirmed apm is on PATH in bash -lc, zsh -lc, and non-login shells. pwsh docker/verify-generated.ps1 reports the generated Dockerfiles are up to date.

Note: the PyPI package literally named apm (v0.0.1) is ancient Python-2 code and unrelated to the issue author's "Agent Package Manager" — confirming the package name is up to the user. This PR's job is making pip/pipx available, which is verified.

🤖 Generated with Claude Code

Every image already carried python3 transitively (via software-properties-common)
but shipped no pip, so pip-distributed CLIs like APM couldn't be installed. Add
python3-pip, python3-venv and pipx to the shared system-packages snippet, so all
22 image variants pick them up.

Debian 12 enforces PEP 668, so pipx is the supported way to install CLI apps;
pip still works inside venvs. Put ~/.local/bin on PATH (ENV for the run command
and non-login shells, plus an /etc/profile.d drop-in for login shells) so
pipx-installed tools are reachable without a per-session 'pipx ensurepath'.

Regenerated all docker/generated Dockerfiles and updated README plus
docs/docker-images.md.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds Python tooling (pip, venv, and pipx) to the base Docker image and updates the corresponding documentation. It also configures the environment path to include the local bin directory for pipx-installed CLIs. The review feedback suggests explicitly declaring python3 in the package list to avoid relying on transitive dependencies, and using standard POSIX parameter expansion when modifying PATH to prevent security risks associated with an empty PATH variable.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread docker/snippets/system-packages.Dockerfile
Comment thread docker/snippets/system-packages.Dockerfile Outdated
@GordonBeeming GordonBeeming marked this pull request as ready for review June 28, 2026 23:41
Copilot AI review requested due to automatic review settings June 28, 2026 23:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds Python packaging support (pip, venv, pipx) to the shared Docker image base so pip-distributed CLI tools can be installed in a PEP 668-compliant way across all image variants, with documentation updates reflecting the new base capabilities.

Changes:

  • Add python3-pip, python3-venv, and pipx to the shared system-packages snippet and wire ~/.local/bin onto PATH.
  • Regenerate all docker/generated/* Dockerfiles to pick up the shared snippet changes.
  • Update README and Docker image docs to mention Python/pip/pipx availability in the base image.

Reviewed changes

Copilot reviewed 3 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
README.md Documents Python (pip & pipx) as part of the base image and updates the image table description.
docs/docker-images.md Notes Python/pipx availability and the PEP 668 rationale in the base image documentation.
docker/snippets/system-packages.Dockerfile Installs pip/pipx tooling and adjusts PATH behavior for pipx-installed CLIs.
docker/generated/Dockerfile.default Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet-8 Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet-9 Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet-10 Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.playwright Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet-playwright Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.rust Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.dotnet-rust Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.golang Regenerated to include the updated system-packages snippet.
docker/generated/Dockerfile.java Regenerated to include the updated system-packages snippet.

Comment thread docker/snippets/system-packages.Dockerfile Outdated
GordonBeeming and others added 2 commits June 29, 2026 09:44
- Declare python3 explicitly in the apt list instead of relying on it being
  pulled in transitively by software-properties-common, so the Python tooling
  install is self-contained and won't break if that transitive dep changes.
- Use POSIX ${PATH:+:${PATH}} expansion in the profile.d drop-in so an empty or
  unset PATH doesn't produce a trailing colon (which would implicitly add the
  cwd to the search path).

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>
The entrypoint runs as root and resolves tools (getent, groupadd, node, ...)
via PATH before dropping to appuser. Prepending the user-writable (and possibly
bind-mounted) /home/appuser/.local/bin meant a planted binary there could be
executed as root. Append it instead so system binaries always take precedence;
pipx-installed apps still resolve since their names don't collide with system
binaries.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>
@GordonBeeming GordonBeeming merged commit 70e3a73 into main Jun 28, 2026
34 of 35 checks passed
@GordonBeeming GordonBeeming deleted the gb/121-pip-base-image branch June 28, 2026 23:58
@GordonBeeming GordonBeeming mentioned this pull request Jun 29, 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.

No pip installed

2 participants