Skip to content

Implement Python build type#156

Open
TomHennen wants to merge 7 commits intomainfrom
implement-python-build
Open

Implement Python build type#156
TomHennen wants to merge 7 commits intomainfrom
implement-python-build

Conversation

@TomHennen
Copy link
Copy Markdown
Owner

Summary

Implements the Python build type spec from #151. Three-job architecture with minimal permissions on the build step, PEP 740 attestations on publish, and SLSA L3 provenance.

Files

File Purpose
build/actions/python/action.yml Composite action: validate, detect uv, install deps, test, build, SBOM, hash
.github/workflows/build_and_publish_python.yml Reusable workflow: build → publish → provenance
build/actions/python/test.bats 19 structural tests
gh_workflow_examples/build_python.yml Adopter example workflow

Manual steps required before end-to-end testing

  1. Create a test package on TestPyPI — register wrangle-test-fixture (or similar) at https://test.pypi.org
  2. Configure Trusted Publisher on TestPyPI — project settings → Publishing → add GitHub. Specify:
    • Repository: TomHennen/wrangle-test
    • Workflow: test-wrangle.yml (the generated workflow on integration branches)
  3. Add Python fixture to companion repo (tomhennen/wrangle-test):
    python/
    ├── pyproject.toml      # minimal project, hatchling backend
    ├── src/example/__init__.py
    └── tests/test_example.py
    
  4. Update companion template — add test-python job pointing at build_and_publish_python.yml with repository-url: https://test.pypi.org/legacy/
  5. After merging: update the hardcoded SHA in build_and_publish_python.yml to include the composite action (one-commit-lag, same as other build types)

What this PR does NOT include

  • Companion repo fixture (step 3-4 above — separate PR on wrangle-test)
  • TestPyPI Trusted Publisher config (manual, step 1-2)
  • End-to-end integration test verification (requires the above)

Test plan

  • ./test.sh passes (164 tests — 19 new)
  • End-to-end: requires companion repo setup (follow-up)

🤖 Generated with Claude Code

Composite action (build/actions/python/action.yml):
- Input validation with globbing disabled
- uv detection (uv.lock → uv sync/build/run) with PEP 517 fallback
- Python version auto-detected from pyproject.toml via setup-python
- pytest gating (skips gracefully if no tests found)
- SPDX SBOM via syft
- Artifact hash computation for SLSA generator

Reusable workflow (build_and_publish_python.yml):
- Three-job architecture: build (contents:read only) → publish
  (id-token:write, non-PR) → provenance (SLSA L3, non-PR)
- PyPI Trusted Publishing via OIDC (no secrets)
- PEP 740 Sigstore attestations on publish
- SLSA L3 provenance via slsa-github-generator (tag ref per #147)

Also adds:
- 19 structural tests (build/actions/python/test.bats)
- Workflow example (gh_workflow_examples/build_python.yml)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous commit added the action but the workflow referenced
the parent SHA where the action didn't exist yet. Update to the
commit that contains the action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@TomHennen
Copy link
Copy Markdown
Owner Author

Integration test results

Almost everything works — major progress:

Job Result
test-shell
test-scan
test-container (build + provenance)
test-python / build
test-python / provenance (SLSA L3)
test-python / publish

Publish failure: PyPI Trusted Publishing does not support reusable workflows

The claims in this token suggest that the calling workflow is a reusable workflow.
Reusable workflows are **not currently supported** by PyPI's Trusted Publishing

PyPI's OIDC token validation rejects tokens from reusable workflows — the claims differ from direct workflows. This means pypa/gh-action-pypi-publish cannot run inside wrangle's reusable workflow with Trusted Publishing.

This is a fundamental architectural constraint: the publish step cannot live inside the reusable workflow. It needs to run directly in the adopter's workflow, or PyPI needs to add reusable workflow support.

Investigating options.

PyPI Trusted Publishing does not support reusable workflows — the
OIDC token's workflow_ref must point to the adopter's own workflow.
(pypi/warehouse#11096, open since 2022, no timeline)

Changes:
- Reusable workflow is now build-only: build, test, SBOM, hash
  computation. Exports hashes and version outputs.
- Remove publish and provenance jobs from reusable workflow.
- Workflow example (gh_workflow_examples/build_python.yml) includes
  publish + SLSA provenance jobs directly — adopters copy this and
  configure their Trusted Publisher against their own workflow file.
- Update structural tests to verify build-only architecture.
- Update companion template to build-only with minimal permissions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Document the PyPI Trusted Publishing limitation and the split
architecture: wrangle owns build/test/SBOM, adopter owns publish.
Reference #157 for when to revisit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@TomHennen TomHennen temporarily deployed to integration-test April 24, 2026 02:04 — with GitHub Actions Inactive
@TomHennen TomHennen deployed to integration-test April 24, 2026 02:21 — with GitHub Actions Active
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