Skip to content

Conversation

@harv-aws
Copy link
Contributor

Add Automated PyPI Publishing Workflow

Overview

This PR implements a GitHub Actions workflow that automatically publishes the mcp-proxy-for-aws package to PyPI when a new release is created. The workflow ensures code quality through automated testing, validates version formatting, builds distribution packages, and securely publishes to PyPI using API token authentication.

Changes

New Files

  • .github/workflows/pypi-publish-on-release.yml - Main publishing workflow

Workflow Architecture

The workflow consists of three sequential jobs that create a fail-fast pipeline:

release.published event
        ↓
   call-test-lint (reuses python.yml)
        ↓
      build (validate version + create packages)
        ↓
     deploy (publish to PyPI)

Key Features

1. Automated Testing Integration

  • Reuses existing python.yml workflow to run unit tests before publishing
  • Passes release target commit SHA to ensure correct code is tested
  • Blocks publishing if any tests fail

2. Version Validation

  • Extracts version from pyproject.toml using Python's tomllib
  • Validates semantic versioning format (X.Y.Z)
  • Fails build if version format is invalid
  • Prevents publishing of improperly versioned releases

3. Secure Package Building

  • Uses uv package manager (consistent with existing workflows)
  • Creates both wheel and source distributions
  • Uploads packages as workflow artifacts for auditability
  • Runs on Python 3.10 (matches existing CI/CD)

4. PyPI Publishing with API Token

  • Uses pypa/gh-action-pypi-publish@release/v1 official action
  • Authenticates via PYPI_API_TOKEN secret
  • Publishes to https://pypi.org/p/mcp-proxy-for-aws
  • Includes environment configuration for deployment tracking

5. Security Best Practices

  • Minimal permissions per job (principle of least privilege)
  • Disables credential persistence during checkout
  • Uses stable action versions (v4, v5)
  • No hardcoded secrets or credentials in workflow files

Setup Requirements

Before this workflow can be used, the following setup is required:

1. PyPI API Token

  1. Generate a PyPI API token at https://pypi.org/manage/account/token/
  2. Add it as a repository secret named PYPI_API_TOKEN
  3. Scope: "Entire account" initially, then project-specific after first upload

2. GitHub Environment (Optional but Recommended)

  1. Go to Settings → Environments
  2. Create environment named pypi
  3. Optionally add protection rules (required reviewers, deployment branches)

Testing Strategy

Post-Release Verification

  1. Monitor workflow execution in Actions tab
  2. Verify package appears on PyPI
  3. Test installation: pip install mcp-proxy-for-aws
  4. Confirm installed version matches release tag

Usage

Creating a Release

  1. Update version in pyproject.toml:

    [project]
    version = "1.0.0"
  2. Commit and push changes:

    git add pyproject.toml
    git commit -m "Bump version to 1.0.0"
    git push origin main
  3. Create and publish a GitHub release:

    • Go to Releases → Draft a new release
    • Create tag: v1.0.0 (matching the version)
    • Fill in release notes
    • Click "Publish release"
  4. The workflow automatically:

    • Runs all tests
    • Validates version format
    • Builds distribution packages
    • Publishes to PyPI

Error Handling

The workflow handles various failure scenarios:

Scenario Behavior Resolution
Tests fail Build job doesn't start Fix tests and create new release
Invalid version format Build fails with error message Update version in pyproject.toml
Build failure Deploy job doesn't start Fix build configuration
PyPI auth failure Deploy fails with error Verify PYPI_API_TOKEN secret
Duplicate version PyPI rejects upload Bump version number

Design Decisions

Why API Token Instead of Trusted Publishing?

  • User preference for token-based authentication
  • Simpler initial setup (no PyPI publisher configuration needed)
  • Works immediately after adding secret
  • Can migrate to Trusted Publishing later if desired

Why Reuse python.yml?

  • DRY principle - single source of truth for tests
  • Automatic updates when test configuration changes
  • Consistent test environment across workflows

Why Sequential Jobs?

  • Fail-fast behavior saves compute resources
  • Logical dependency chain (can't deploy without building)
  • Clear workflow progression and debugging

Why uv for Building?

  • Consistent with existing workflows
  • Faster than traditional build tools
  • Already specified as build system in project

Requirements Satisfied

This implementation satisfies all requirements from the specification:

  • Req 1: Automatic triggering on release publication
  • Req 2: Integration with existing test workflows
  • Req 3: Version format validation (X.Y.Z)
  • Req 4: Distribution package building with uv
  • Req 5: Secure PyPI publishing with API token
  • Req 6: Security best practices (minimal permissions, pinned actions)

Related Documentation

Checklist

  • Workflow file created and tested
  • Test workflow for TestPyPI created
  • Security best practices implemented
  • Error handling documented
  • Setup instructions provided
  • All requirements satisfied
  • PYPI_API_TOKEN secret added (requires maintainer access)
  • PyPI environment created (optional)

Is this a breaking change? (Y/N)

  • Yes
  • No

Please add details about how this change was tested.

  • Did integration tests succeed?
  • If the feature is a new use case, is it necessary to add a new integration test case?

Acknowledgment

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

kyoncal and others added 4 commits November 11, 2025 17:40
* feat(sigv4_helper): inject AWS_REGION in _meta

* Override the sigv4 signature when adding _meta.

* feat(sigv4_helper): add region and service argument to _inject_metadata_hook to allow for proper resigning of sigv4 to work

* feat(server.py): add forwarding region as optional argument

* feat: replace forwarding region with metadata forwarding

* refactor: move the hooks from sigv4_helper.py into a new folder and add tests

* refactor(siv4_helper.py): move signing logic from client creation to an event hook

* test(test_hooks.py): add assertions

* refactor(sigv4_helper.py): remove hooks.py module and move hooks to sigv4_helper.py

This refactor was needed in order to avoid a circular depdency, which resulted in a mid-module import.

---------

Co-authored-by: Kyon Caldera <kyonc@amazon.com>
Co-authored-by: Leonardo Araneda Freccero <araneda@amazon.com>
@harv-aws harv-aws marked this pull request as ready for review November 11, 2025 21:48
@harv-aws harv-aws requested a review from a team as a code owner November 11, 2025 21:48
arangatang
arangatang previously approved these changes Nov 12, 2025
@arangatang arangatang merged commit 1ff8763 into aws:main Nov 13, 2025
3 checks passed
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.

4 participants