Skip to content

Commit 4d3e0d3

Browse files
committed
fix: Address critical security and logic issues in workflow
Fixes all issues identified in Claude Code review: 🚨 Critical Fixes: 1. Remove redundant condition in deploy-prod job - Was checking github.event_name == 'release' twice - Simplified to: !inputs.docker_only 2. Fix Docker job condition logic - Removed flawed always() + needs dependency - Now runs independently for release or manual triggers - Docker builds don't require PyPI deployment success 🔐 Security Improvements: 3. Add tag format validation - Validates semver format: v1.2.3 or v1.2.3-alpha - Prevents arbitrary git ref injection 4. Add tag existence verification - Verifies tag exists before building - Provides clear error messages 🔧 Best Practice Improvements: 5. Normalize tag value extraction - Creates normalized tag output for metadata - Handles both release and manual trigger sources 6. Remove needs dependency from docker job - Docker builds are independent of PyPI - Allows manual Docker-only builds without test deploy All changes maintain backward compatibility with release events while enabling secure manual Docker builds.
1 parent 0b8e3b1 commit 4d3e0d3

File tree

1 file changed

+34
-8
lines changed

1 file changed

+34
-8
lines changed

.github/workflows/publish.yml

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
needs: deploy-test
5656
runs-on: ubuntu-latest
5757
# Only deploy to PyPI for non-prerelease versions and skip when manually triggered with docker_only
58-
if: ${{ github.event_name == 'release' && !github.event.release.prerelease && (github.event_name == 'release' || !inputs.docker_only) }}
58+
if: ${{ github.event_name == 'release' && !github.event.release.prerelease && !inputs.docker_only }}
5959
environment: pypi
6060
permissions:
6161
id-token: write
@@ -83,8 +83,8 @@ jobs:
8383

8484
docker:
8585
# Run if: (1) release event after test deploy, or (2) manual trigger
86-
needs: [deploy-test]
87-
if: ${{ always() && (github.event_name == 'release' && needs.deploy-test.result == 'success') || (github.event_name == 'workflow_dispatch') }}
86+
# Note: Docker builds are independent and don't strictly require PyPI deployment
87+
if: ${{ github.event_name == 'release' || github.event_name == 'workflow_dispatch' }}
8888
runs-on: ubuntu-latest
8989
permissions:
9090
packages: write
@@ -93,7 +93,33 @@ jobs:
9393
- uses: actions/checkout@v4
9494
with:
9595
ref: ${{ inputs.tag || github.ref }}
96-
96+
97+
- name: Validate tag format
98+
if: github.event_name == 'workflow_dispatch'
99+
run: |
100+
if [[ ! "${{ inputs.tag }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9\-\.]+)?$ ]]; then
101+
echo "❌ Invalid tag format. Expected: v1.2.3 or v1.2.3-alpha"
102+
exit 1
103+
fi
104+
105+
- name: Verify tag exists
106+
if: github.event_name == 'workflow_dispatch'
107+
run: |
108+
if ! git rev-parse --verify "refs/tags/${{ inputs.tag }}" >/dev/null 2>&1; then
109+
echo "❌ Tag ${{ inputs.tag }} does not exist"
110+
exit 1
111+
fi
112+
echo "✓ Tag ${{ inputs.tag }} verified"
113+
114+
- name: Normalize tag
115+
id: tag
116+
run: |
117+
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
118+
echo "tag=${{ inputs.tag }}" >> $GITHUB_OUTPUT
119+
else
120+
echo "tag=${{ github.ref_name }}" >> $GITHUB_OUTPUT
121+
fi
122+
97123
- name: Set up QEMU
98124
uses: docker/setup-qemu-action@v3
99125

@@ -105,7 +131,7 @@ jobs:
105131
with:
106132
username: ${{ secrets.DOCKERHUB_USERNAME }}
107133
password: ${{ secrets.DOCKERHUB_TOKEN }}
108-
134+
109135
- name: Login to GitHub Container Registry
110136
uses: docker/login-action@v3
111137
with:
@@ -124,11 +150,11 @@ jobs:
124150
# Latest tag for stable releases (not for prereleases)
125151
type=raw,value=latest,enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
126152
# Version tag from release or manual input
127-
type=semver,pattern={{version}},value=${{ inputs.tag || github.ref_name }}
153+
type=semver,pattern={{version}},value=${{ steps.tag.outputs.tag }}
128154
# Major.minor tag
129-
type=semver,pattern={{major}}.{{minor}},value=${{ inputs.tag || github.ref_name }}
155+
type=semver,pattern={{major}}.{{minor}},value=${{ steps.tag.outputs.tag }}
130156
# Major tag (only for stable releases)
131-
type=semver,pattern={{major}},value=${{ inputs.tag || github.ref_name }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
157+
type=semver,pattern={{major}},value=${{ steps.tag.outputs.tag }},enable=${{ github.event_name == 'release' && !github.event.release.prerelease || github.event_name == 'workflow_dispatch' }}
132158
133159
- name: Build and push Docker image
134160
uses: docker/build-push-action@v6

0 commit comments

Comments
 (0)