Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .github/workflows/publish-python-sdk-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Publish Python SDK on Release

on:
release:
types: [published]

permissions:
contents: read
id-token: write

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v2

- name: Install dev dependencies with uv
working-directory: python-sdk
run: |
uv sync --group dev

- name: Install python-sdk package (editable)
working-directory: python-sdk
run: |
uv pip install -e .

- name: Run tests with pytest and coverage
working-directory: python-sdk
run: |
uv run pytest --cov=exospherehost --cov-report=xml --cov-report=term-missing -v --junitxml=pytest-report.xml

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
slug: exospherehost/exospherehost
files: python-sdk/coverage.xml
flags: python-sdk-unittests
name: python-sdk-coverage-report
fail_ci_if_error: true

- name: Upload test results
uses: actions/upload-artifact@v4
if: always()
with:
name: python-sdk-test-results
path: python-sdk/pytest-report.xml
retention-days: 30

publish:
runs-on: ubuntu-latest
needs: test
defaults:
run:
working-directory: python-sdk

steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v6
name: Install uv

- run: uv python install

- run: uv sync --locked --dev

- name: Update version to release tag
run: |
# Extract version from tag (remove 'v' or 'V' prefix if present)
RELEASE_VERSION="${{ github.ref_name }}"

# Handle empty or invalid tags
if [[ -z "$RELEASE_VERSION" ]]; then
echo "ERROR: Release tag is empty"
exit 1
fi

# Remove 'v' or 'V' prefix (case insensitive)
if [[ $RELEASE_VERSION =~ ^[vV] ]]; then
RELEASE_VERSION="${RELEASE_VERSION#?}" # Remove first character
fi

# Validate the extracted version is not empty
if [[ -z "$RELEASE_VERSION" ]]; then
echo "ERROR: Invalid tag format - version part is empty"
exit 1
fi

# Update the version file
echo "version = \"$RELEASE_VERSION\"" > exospherehost/_version.py

echo "Updated version to $RELEASE_VERSION for release"

- name: Verify version format
run: |
python -c "
import sys
sys.path.append('.')
from exospherehost._version import version
import re

# Check if version matches semantic versioning pattern
if not re.match(r'^\d+\.\d+\.\d+$', version):
print(f'ERROR: Version {version} does not match semantic versioning pattern (x.y.z)')
sys.exit(1)

# Ensure it's not a beta version (should not contain 'b')
if 'b' in version:
print(f'ERROR: Release version {version} contains beta indicator. Release versions should not be beta.')
sys.exit(1)

print(f'Version {version} is valid for release publishing')
"

- run: uv build

- run: uv publish
Comment on lines +1 to +126
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 23, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

General: consider provenance on PyPI and SBOMs for releases.

For release artifacts, enabling provenance (uv publish --provenance) and attaching an SBOM (e.g., pip install pip-audit && pip-audit -r ... or uv export --format=requirements-txt | cyclonedx-py) improves supply-chain posture.

🧰 Tools
🪛 YAMLlint (1.37.1)

[warning] 3-3: truthy value should be one of [false, true]

(truthy)


[error] 73-73: trailing spaces

(trailing-spaces)


[error] 80-80: trailing spaces

(trailing-spaces)


[error] 86-86: trailing spaces

(trailing-spaces)


[error] 91-91: trailing spaces

(trailing-spaces)


[error] 97-97: trailing spaces

(trailing-spaces)


[error] 100-100: trailing spaces

(trailing-spaces)


[error] 110-110: trailing spaces

(trailing-spaces)


[error] 115-115: trailing spaces

(trailing-spaces)


[error] 120-120: trailing spaces

(trailing-spaces)


[error] 126-126: no new line character at the end of file

(new-line-at-end-of-file)


[error] 126-126: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
.github/workflows/publish-python-sdk-release.yml lines 1-126: the publish job
doesn’t produce or attach provenance/SBOM artifacts; update the publish steps to
(1) run uv publish with the --provenance flag to upload provenance to PyPI, (2)
generate an SBOM (for example use uv export --format=requirements-txt >
requirements.txt then run cyclonedx-bom or pip-audit to produce an SBOM file),
and (3) upload the resulting provenance and SBOM files as workflow artifacts (or
attach them to the release) so they are retained with the release.

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai explain more, what is this?

Copy link
Contributor

Choose a reason for hiding this comment

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

@NiveditJain Great question! Let me explain provenance and SBOMs in the context of software supply chain security:

Provenance

Provenance is cryptographic proof of how your software package was built. When you use uv publish --provenance, it:

  • Records the build environment: Which GitHub Actions runner, commit SHA, workflow file, etc.
  • Creates cryptographic signatures: Uses GitHub's OIDC tokens to prove the package came from your specific repo/workflow
  • Uploads to PyPI: The provenance data gets attached to your package on PyPI
  • Enables verification: Users can verify your package wasn't tampered with and actually came from your GitHub repo

SBOM (Software Bill of Materials)

An SBOM is like an "ingredient list" for your software package:

  • Lists all dependencies: Every library, version, and transitive dependency
  • Tracks vulnerabilities: Security scanners can check SBOMs for known CVEs
  • Compliance requirement: Many organizations now require SBOMs for software they use
  • Supply chain visibility: Helps identify what's actually in your package

Why This Matters for Your SDK

  1. Trust: Users can verify your packages are legitimate
  2. Security: Easier to detect supply chain attacks
  3. Compliance: Many enterprises require provenance/SBOMs
  4. Best practice: Industry standard for mature software projects

Implementation

For your workflow, it would look like:

- run: uv publish --provenance  # Adds cryptographic proof
- name: Generate SBOM
  run: |
    uv export --format=requirements-txt > requirements.txt
    cyclonedx-py -r requirements.txt -o sbom.json
- name: Upload SBOM
  uses: actions/upload-artifact@v4
  with:
    name: sbom
    path: sbom.json

Think of it as adding a "digital passport" and "ingredient list" to your software packages!

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai lets add this in next cycle create an issue for this please!

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

I'll create a GitHub issue to track this enhancement for the next development cycle!

@NiveditJain Perfect! I've created a GitHub issue to track the implementation of provenance and SBOM support for your Python SDK release workflow. The issue includes:

  • Clear technical requirements for both provenance and SBOM implementation
  • Benefits explanation covering security, compliance, and best practices
  • Acceptance criteria to guide the implementation
  • Proper backlinks to this PR and our discussion
  • Assignment to you as requested

This enhancement will significantly improve your SDK's supply chain security posture when you're ready to implement it in the next development cycle! 🚀

 /|   /|   
( :v:  :v: )
 |(_)| 
 |   |   *thinking about security improvements*
/     \

🏁 Script executed:

#!/bin/bash
# Create a GitHub issue for implementing provenance and SBOM support
gh issue create \
  --title "Add provenance and SBOM support to Python SDK release workflow" \
  --body "## Overview
Enhance the Python SDK release workflow to include supply chain security features: provenance and Software Bill of Materials (SBOM) generation.

## Background
During review of PR #264, it was identified that the release workflow should include:
1. **Provenance**: Cryptographic proof of how the package was built using GitHub's OIDC tokens
2. **SBOM**: Software Bill of Materials listing all dependencies for security scanning and compliance

## Implementation Requirements

### Provenance
- Add \`--provenance\` flag to \`uv publish\` command
- This will automatically generate and upload cryptographic signatures to PyPI
- Enables users to verify packages weren't tampered with and came from the official repo

### SBOM Generation
- Generate requirements file: \`uv export --format=requirements-txt > requirements.txt\`
- Create SBOM using tools like \`cyclonedx-py\` or \`pip-audit\`
- Upload SBOM as workflow artifact and/or attach to GitHub release

### Benefits
- **Enhanced Security**: Users can verify package authenticity
- **Vulnerability Tracking**: SBOMs enable automated security scanning
- **Compliance**: Meet enterprise requirements for software supply chain transparency
- **Industry Best Practice**: Aligns with modern software security standards

## Acceptance Criteria
- [ ] \`uv publish --provenance\` flag added to release workflow
- [ ] SBOM generation integrated into workflow
- [ ] SBOM uploaded as workflow artifact
- [ ] Documentation updated to explain provenance/SBOM benefits
- [ ] Verify provenance appears correctly on PyPI

## References
- Original discussion: https://github.com/exospherehost/exospherehost/pull/264#discussion_r2296060830
- Related PR: https://github.com/exospherehost/exospherehost/pull/264
- Requested by: @NiveditJain" \
  --assignee "NiveditJain"

Length of output: 1958


@NiveditJain Perfect! ✅ I've successfully created GitHub issue #265 to track the implementation of provenance and SBOM support for your Python SDK release workflow.

The issue is now:

  • Created and assigned to you for the next development cycle
  • Properly documented with technical requirements and benefits
  • Linked back to this PR and our discussion for full context
  • Ready for implementation when you're ready to tackle supply chain security enhancements

You can track progress on the issue and reference it in future PRs when implementing these security improvements! 🎯

 /|   /|   
( :v:  :v: )
 |(_)| 
 | ✓ |   *mission accomplished*
/     \

16 changes: 13 additions & 3 deletions .github/workflows/publish-python-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ jobs:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v2
with:
cache: true
uses: astral-sh/setup-uv@v6

Comment on lines 27 to 29
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Good upgrade to setup-uv v6; consider pinning to a commit SHA for supply-chain hardening.

Pinning actions to a specific commit digest prevents unexpected changes when the action’s tag is moved.

Example:

- uses: astral-sh/setup-uv@v6
+ uses: astral-sh/setup-uv@<commit-sha>
  # v6 ref: https://github.com/astral-sh/setup-uv/commits/v6
🤖 Prompt for AI Agents
.github/workflows/publish-python-sdk.yml lines 27-29: the workflow currently
references the action with a moving tag ("astral-sh/setup-uv@v6"); to harden
supply chain, replace the tag with the specific commit SHA for the v6 release.
Locate the v6 tag commit SHA from the action repo (e.g., the v6 tag commit on
GitHub), update the uses entry to "astral-sh/setup-uv@<commit-sha>" and
optionally add a comment referencing the v6 tag URL for future maintainers.

- name: Install dev dependencies with uv
working-directory: python-sdk
Expand Down Expand Up @@ -79,6 +77,18 @@ jobs:

- run: uv sync --locked --dev

- name: Check version for beta indicator
run: |
python -c "
import sys
sys.path.append('.')
from exospherehost._version import version
if 'b' not in version:
print(f'ERROR: Version {version} does not contain beta indicator (b). Major releases are only allowed through GitHub releases.')
sys.exit(1)
print(f'Version {version} is valid for PyPI publishing (contains beta indicator)')
"

- run: uv build

- run: uv publish