diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index c08a32ff..00aa7835 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -1,4 +1,4 @@
-name: Integration Tests for Exosphere
+name: Integration Tests
on:
push:
@@ -8,9 +8,21 @@ on:
- 'state-manager/**'
- 'python-sdk/**'
- '.github/workflows/integration-tests.yml'
+ pull_request:
+ branches: [main]
+ paths:
+ - 'integration-tests/**'
+ - 'state-manager/**'
+ - 'python-sdk/**'
+ - '.github/workflows/integration-tests.yml'
+
jobs:
test:
+ defaults:
+ run:
+ working-directory: integration-tests
+ if: github.repository == 'exospherehost/exospherehost'
runs-on: ubuntu-latest
services:
mongodb:
diff --git a/.github/workflows/publish-python-sdk.yml b/.github/workflows/publish-python-sdk.yml
index ea08fe12..1c5a891c 100644
--- a/.github/workflows/publish-python-sdk.yml
+++ b/.github/workflows/publish-python-sdk.yml
@@ -90,6 +90,64 @@ jobs:
print(f'Version {version} is valid for PyPI publishing (contains beta indicator)')
"
+ - name: Generate requirements file for SBOM
+ run: |
+ uv export --locked --format=requirements-txt --output-file=requirements.txt
+ echo "Generated requirements.txt for SBOM creation from lockfile"
+
+ - name: Install SBOM generation tools
+ run: |
+ uv tool install cyclonedx-bom
+ echo "Installed cyclonedx-bom version:"
+ uv tool run cyclonedx-bom --version
+ uv tool install pip-audit
+ echo "Installed pip-audit version:"
+ uv tool run pip-audit --version
+
+ - name: Generate SBOM with CycloneDX
+ run: |
+ uv tool run cyclonedx-py requirements --format json --output-file sbom-cyclonedx.json requirements.txt
+ echo "Generated CycloneDX SBOM in JSON format"
+
+ - name: Generate vulnerability report with pip-audit
+ run: |
+ uv tool run pip-audit --format json --output vulnerability-report.json --requirement requirements.txt || true
+ echo "Generated vulnerability report (non-blocking)"
+
- run: uv build
- - run: uv publish
+ - name: Publish to PyPI with provenance
+ run: |
+ # Get the current version
+ VERSION=$(uv run python -c "
+ import sys
+ sys.path.append('.')
+ from exospherehost._version import version
+ print(version)
+ ")
+
+ echo "Checking if exospherehost version $VERSION already exists on PyPI..."
+
+ # Query PyPI JSON API to check if version exists
+ HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/exospherehost/$VERSION/json")
+
+ if [ "$HTTP_STATUS" = "200" ]; then
+ echo "Version $VERSION already exists on PyPI. Skipping publish."
+ exit 0
+ elif [ "$HTTP_STATUS" = "404" ]; then
+ echo "Version $VERSION not found on PyPI. Proceeding with publish."
+ uv publish --provenance
+ else
+ echo "Unexpected HTTP status $HTTP_STATUS when checking PyPI. Proceeding with publish."
+ uv publish --provenance
+ fi
+
+ - name: Upload SBOM artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: sbom-artifacts-beta-${{ github.sha }}
+ path: |
+ python-sdk/sbom-cyclonedx.json
+ python-sdk/requirements.txt
+ python-sdk/vulnerability-report.json
+ retention-days: 30
diff --git a/.github/workflows/release-python-sdk.yml b/.github/workflows/release-python-sdk.yml
index b62061cc..eac8025f 100644
--- a/.github/workflows/release-python-sdk.yml
+++ b/.github/workflows/release-python-sdk.yml
@@ -122,6 +122,73 @@ jobs:
print(f'Version {version} is valid for release publishing')
"
+ - name: Generate requirements file for SBOM
+ run: |
+ uv export --locked --format=requirements-txt --output-file=requirements.txt
+ echo "Generated requirements.txt for SBOM creation from lockfile"
+
+ - name: Install SBOM generation tools
+ run: |
+ uv tool install cyclonedx-bom
+ uv tool install pip-audit
+
+ - name: Generate SBOM with CycloneDX
+ run: |
+ uv tool run cyclonedx-py requirements --format json --output-file sbom-cyclonedx.json requirements.txt
+ uv tool run cyclonedx-py requirements --format xml --output-file sbom-cyclonedx.xml requirements.txt
+ echo "Generated CycloneDX SBOM in JSON and XML formats"
+
+ - name: Generate vulnerability report with pip-audit
+ run: |
+ uv tool run pip-audit --format json --output vulnerability-report.json --requirement requirements.txt || true
+ echo "Generated vulnerability report (non-blocking)"
+
+ - name: Create SBOM summary
+ run: |
+ echo "## Software Bill of Materials (SBOM)" > sbom-summary.md
+ echo "" >> sbom-summary.md
+ echo "This release includes the following supply chain security artifacts:" >> sbom-summary.md
+ echo "" >> sbom-summary.md
+ echo "- **Provenance**: Cryptographic proof of build integrity using GitHub's OIDC tokens" >> sbom-summary.md
+ echo "- **SBOM**: Complete dependency inventory in CycloneDX format" >> sbom-summary.md
+ echo "- **Vulnerability Report**: Security scan results for all dependencies" >> sbom-summary.md
+ echo "" >> sbom-summary.md
+ echo "### Dependencies Count:" >> sbom-summary.md
+ echo "- Direct dependencies: $(grep -c '^[^#]' requirements.txt || echo '0')" >> sbom-summary.md
+ echo "- Total dependencies (including transitive): $(wc -l < requirements.txt)" >> sbom-summary.md
+ echo "" >> sbom-summary.md
+ echo "### Verification:" >> sbom-summary.md
+ echo "You can verify this package's provenance on PyPI using:" >> sbom-summary.md
+ echo '```bash' >> sbom-summary.md
+ echo 'pip install sigstore' >> sbom-summary.md
+ echo 'python -m sigstore verify --bundle
+