1
0
Fork 0
mirror of https://github.com/imjasonh/terraform-playground synced 2026-07-07 23:35:16 +00:00

ci: build & run a real uv project (compiled wheels numpy/pydantic-core, console scripts) and assert imports/metadata/dev-exclusion; docs: note uv export delegation + conformance

Co-authored-by: Jason Hall <imjasonh@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-06-11 02:40:21 +00:00
parent 80ff593fc9
commit cb303c1577
No known key found for this signature in database
3 changed files with 78 additions and 2 deletions

View file

@ -184,3 +184,66 @@ jobs:
exit 1
fi
echo "Confirmed: adding a dependency reused all existing layers and added exactly one."
# Build a real uv project with *compiled* wheels (numpy, pydantic-core) and
# a console-script package, then actually run the image: import the native
# extensions, read installed metadata, and check the generated launcher.
# This exercises the `uv export` resolution path and install fidelity
# end-to-end against a real Docker runtime.
- name: Build & run a real uv project (compiled wheels + metadata)
if: runner.os == 'Linux'
working-directory: pymage
run: |
set -euo pipefail
rm -rf realapp && mkdir -p realapp/src/realapp
cat > realapp/pyproject.toml <<'TOML'
[project]
name = "realapp"
version = "0.1.0"
requires-python = ">=3.12,<3.13"
dependencies = ["numpy==2.1.3", "pydantic==2.9.2", "rich==13.9.4", "cowsay==6.1"]
[dependency-groups]
dev = ["ruff==0.7.4"]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
TOML
echo "" > realapp/src/realapp/__init__.py
uv lock --project realapp
go run . build ./realapp \
--base python:3.12-slim --platform linux/amd64 \
--repo "$REGISTRY/realapp" -t v1 --insecure \
--entrypoint python --entrypoint -c --entrypoint "print('ok')"
# dev-group tool must NOT be in the image (uv export --no-dev)
if crane manifest --insecure "$REGISTRY/realapp:v1" \
| jq -r '.layers[].annotations["dev.pymage.wheels"] // empty' | grep -qi '^ruff=='; then
echo "::error::dev dependency 'ruff' leaked into the runtime image"
exit 1
fi
crane pull --insecure --platform linux/amd64 "$REGISTRY/realapp:v1" /tmp/realapp.tar
loaded=$(docker load -i /tmp/realapp.tar | sed -E 's/^Loaded image( ID)?: //' | tail -1)
echo "loaded image: $loaded"
# Import compiled extensions, exercise them, and read installed metadata.
docker run --rm --entrypoint python "$loaded" -c "
import numpy as np, pydantic, rich # compiled + pure imports
assert np.zeros(3).sum() == 0.0 # runs the numpy C ext
from pydantic import BaseModel
class M(BaseModel):
x: int
assert M(x=2).x == 2 # runs pydantic-core (Rust ext)
import importlib.metadata as md
for p in ('numpy', 'pydantic', 'rich', 'cowsay'):
print(p, md.version(p)) # installed metadata present
assert 'ruff' not in {d.metadata['Name'].lower() for d in md.distributions()}
print('runtime import + metadata OK')
"
# The console-script launcher was generated and is a valid script.
docker run --rm --entrypoint sh "$loaded" -c \
'ls /app/.venv/bin && test -s /app/.venv/bin/cowsay && head -1 /app/.venv/bin/cowsay'
echo "Confirmed: compiled wheels import, metadata is present, dev tools excluded, launcher generated."

View file

@ -31,7 +31,14 @@ because it exploits content-addressed layering:
When a lock has no compatible wheel, pymage fails fast and directs the user to
pre-build a wheel out-of-band and supply it via `--find-links`.
- Replacing dependency *resolution*. We delegate resolution to existing,
correct tools (`uv` / `pip`) and consume their lockfile output.
correct tools and consume their output: for uv projects we shell out to
`uv export --frozen --no-dev` (when uv is available) to get the exact
per-target requirement set — closure, extras, groups, and workspace selection
are uv's responsibility, not ours. pymage only evaluates the markers uv emits
and maps each pin to a wheel. A built-in lock walker remains as a fallback for
environments without uv. Likewise, install layout is validated against a real
`uv pip install` in a conformance test (installing a wheel runs no code, so
there is no RCE risk in using it as an oracle).
- A general-purpose Dockerfile interpreter. This is a focused Python app builder
(think `ko`, but for Python wheels).

View file

@ -159,7 +159,13 @@ pymage build \
### Optional dependencies, workspaces, and markers (uv.lock)
pymage installs the project's **runtime closure** from `uv.lock` (the deps you'd
get from `uv sync --no-dev`), not every package in the lock:
get from `uv sync --no-dev`), not every package in the lock. When `uv` is
installed and a `pyproject.toml` is present, resolution is delegated to
`uv export --frozen --no-dev` — uv is the source of truth for the closure,
extras, groups, and workspace selection, so pymage doesn't reimplement its
resolver. pymage then evaluates the environment markers uv emits for the target
and attaches wheel URLs from the lock. (Without uv, a built-in closure walker is
used as a fallback.) The selectors below map onto `uv export` flags:
- `--extra <group>` enables one of the project's own
`[project.optional-dependencies]` groups (repeatable). Extras requested *by*