-
Notifications
You must be signed in to change notification settings - Fork 807
add all workflows for gated release #934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| name: "Artifactory OIDC Auth" | ||
| description: "Exchange GitHub OIDC token for Artifactory access and configure pip indexes" | ||
|
|
||
| inputs: | ||
| artifactory-url: | ||
| description: "Base Artifactory platform URL. Falls back to ARTIFACTORY_URL env var if not provided." | ||
| required: false | ||
| default: "" | ||
| oidc-provider-name: | ||
| description: "OIDC provider name configured in Artifactory" | ||
| required: false | ||
| default: "github-actions" | ||
| pypi-repo: | ||
| description: "Artifactory virtual PyPI repository name" | ||
| required: false | ||
| default: "virtual-pypi-thirdparty" | ||
|
|
||
| runs: | ||
| using: "composite" | ||
| steps: | ||
| - name: Exchange GitHub OIDC token for Artifactory token | ||
| shell: bash | ||
| env: | ||
| INPUT_ARTIFACTORY_URL: ${{ inputs.artifactory-url }} | ||
| OIDC_PROVIDER_NAME: ${{ inputs.oidc-provider-name }} | ||
| PYPI_REPO: ${{ inputs.pypi-repo }} | ||
| run: | | ||
| set -euo pipefail | ||
| ARTIFACTORY_URL="${INPUT_ARTIFACTORY_URL:-${ARTIFACTORY_URL:-}}" | ||
| if [ -z "${ARTIFACTORY_URL}" ]; then | ||
| echo "::error::ARTIFACTORY_URL is not set (pass as input or set as env var)"; exit 1 | ||
| fi | ||
|
|
||
| OIDC_JWT=$(curl -sS \ | ||
| "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${ARTIFACTORY_URL}" \ | ||
| -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" | jq -r '.value') | ||
|
|
||
| if [ -z "$OIDC_JWT" ] || [ "$OIDC_JWT" = "null" ]; then | ||
| echo "::error::Failed to obtain GitHub OIDC token"; exit 1 | ||
| fi | ||
|
|
||
| decode_seg() { local s="${1}"; local m=$(( ${#s} % 4 )); [ $m -ne 0 ] && s="${s}$(printf '=%.0s' $(seq 1 $((4-m))))"; echo "$s" | tr '_-' '/+' | base64 -d 2>/dev/null; } | ||
| PAYLOAD=$(decode_seg "$(echo "$OIDC_JWT" | cut -d. -f2)") | ||
| echo "OIDC token claims:" | ||
| echo " sub = $(echo "$PAYLOAD" | jq -r '.sub')" | ||
| echo " aud = $(echo "$PAYLOAD" | jq -r '.aud')" | ||
| echo " iss = $(echo "$PAYLOAD" | jq -r '.iss')" | ||
|
|
||
| RESP=$(curl -sS "${ARTIFACTORY_URL}/access/api/v1/oidc/token" \ | ||
| -H 'Content-Type: application/json' \ | ||
| -d "{\"grant_type\":\"urn:ietf:params:oauth:grant-type:token-exchange\", | ||
| \"subject_token_type\":\"urn:ietf:params:oauth:token-type:id_token\", | ||
| \"subject_token\":\"${OIDC_JWT}\", | ||
| \"provider_name\":\"${OIDC_PROVIDER_NAME}\"}") | ||
|
|
||
| ART_TOKEN=$(echo "$RESP" | jq -r '.access_token // empty') | ||
|
|
||
| if [ -z "$ART_TOKEN" ]; then | ||
| echo "::error::OIDC token exchange failed. Raw response (token field redacted):" | ||
| echo "$RESP" | jq 'if .access_token then .access_token="<redacted>" else . end' 2>/dev/null || echo "$RESP" | ||
| exit 1 | ||
| fi | ||
| echo "::add-mask::$ART_TOKEN" | ||
|
|
||
| HOST=$(echo "${ARTIFACTORY_URL}" | sed -E 's#^https?://##') | ||
| INDEX_URL="https://:${ART_TOKEN}@${HOST}/artifactory/api/pypi/${PYPI_REPO}/simple/" | ||
|
|
||
| echo "::add-mask::${INDEX_URL}" | ||
| echo "PIP_INDEX_URL=${INDEX_URL}" >> "$GITHUB_ENV" | ||
| echo "PIP_TRUSTED_HOST=${HOST}" >> "$GITHUB_ENV" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| name: Test and Deploy to PyPI | ||
|
|
||
| on: | ||
| release: | ||
| types: [published] | ||
| workflow_dispatch: | ||
|
|
||
| env: | ||
| ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }} | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test - Python ${{ matrix.python-version }} | ||
| runs-on: ${{ github.repository_owner == 'twilio-internal' && 'ubuntu-x64' || 'ubuntu-latest' }} | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] | ||
| steps: | ||
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Authenticate with Artifactory | ||
| uses: ./.github/actions/artifactory-oidc | ||
|
|
||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pip install virtualenv --upgrade | ||
| make install test-install | ||
|
|
||
| - name: Run tests | ||
| run: make test-with-coverage | ||
|
|
||
| deploy: | ||
| name: Publish to PyPI | ||
| needs: [test] | ||
| runs-on: ${{ github.repository_owner == 'twilio-internal' && 'ubuntu-x64' || 'ubuntu-latest' }} | ||
| environment: pypi | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| attestations: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🥳 Fixed in commit 8741919 🥳 |
||
|
|
||
| - name: Authenticate with Artifactory | ||
| uses: ./.github/actions/artifactory-oidc | ||
|
|
||
| - uses: actions/setup-python@v5 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🍰 Fixed in commit 8741919 🍰 |
||
| with: | ||
| python-version: "3.12" | ||
|
|
||
| - name: Validate tag matches package version | ||
| run: | | ||
| TAG="${GITHUB_REF#refs/tags/}" | ||
| # Strip leading 'v' if present | ||
| VERSION="${TAG#v}" | ||
| PKG_VERSION=$(python setup.py --version) | ||
| if [ "$VERSION" != "$PKG_VERSION" ]; then | ||
| echo "::error::Tag $TAG does not match setup.py version $PKG_VERSION" | ||
| exit 1 | ||
| fi | ||
|
|
||
| - name: Build package | ||
| run: | | ||
| pip install build | ||
| python -m build | ||
|
|
||
| - name: Verify package | ||
| run: | | ||
| pip install twine | ||
| twine check dist/* | ||
|
|
||
| - name: Publish to PyPI | ||
| uses: pypa/gh-action-pypi-publish@v1 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🚀 Fixed in commit 8741919 🚀 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✨ Fixed in commit 8741919 ✨ |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| name: Test Release (Dry Run) | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| python-version: | ||
| description: "Python version to test with (or 'all' for full matrix)" | ||
| required: false | ||
| default: "3.12" | ||
|
|
||
| env: | ||
| ARTIFACTORY_URL: ${{ vars.ARTIFACTORY_URL }} | ||
|
|
||
| jobs: | ||
| test: | ||
| name: Test - Python ${{ matrix.python-version }} | ||
| runs-on: ${{ github.repository_owner == 'twilio-internal' && 'ubuntu-x64' || 'ubuntu-latest' }} | ||
| timeout-minutes: 20 | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| python-version: ${{ github.event.inputs.python-version == 'all' && fromJson('["3.8","3.9","3.10","3.11","3.12","3.13"]') || fromJson(format('["{0}"]', github.event.inputs.python-version)) }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Authenticate with Artifactory | ||
| uses: ./.github/actions/artifactory-oidc | ||
|
|
||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ matrix.python-version }} | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pip install virtualenv --upgrade | ||
| make install test-install | ||
|
|
||
| - name: Run tests | ||
| run: make test-with-coverage | ||
|
|
||
| deploy-dry-run: | ||
| name: Deploy (Dry Run - No Publish) | ||
| needs: [test] | ||
| runs-on: ${{ github.repository_owner == 'twilio-internal' && 'ubuntu-x64' || 'ubuntu-latest' }} | ||
| environment: pypi | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| attestations: write | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Authenticate with Artifactory | ||
| uses: ./.github/actions/artifactory-oidc | ||
|
|
||
| - uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.12" | ||
|
|
||
| - name: Validate version in setup.py | ||
| run: | | ||
| PKG_VERSION=$(python setup.py --version) | ||
| echo "Package version: $PKG_VERSION" | ||
| echo "PKG_VERSION=$PKG_VERSION" >> "$GITHUB_ENV" | ||
|
|
||
| - name: Build package | ||
| run: | | ||
| pip install build | ||
| python -m build | ||
|
|
||
| - name: Verify package | ||
| run: | | ||
| pip install twine | ||
| twine check dist/* | ||
|
|
||
| - name: List built artifacts | ||
| run: | | ||
| echo "Built artifacts:" | ||
| ls -lh dist/ | ||
| echo "" | ||
| echo "Package version: $PKG_VERSION" | ||
| echo "" | ||
| echo "--- DRY RUN COMPLETE ---" | ||
| echo "To publish for real, create a GitHub Release with a matching tag" | ||
| echo "and use the deploy.yml workflow." |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| pygments>=2.7.4 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| requests>=2.32.2 | ||
| PyJWT>=2.0.0, <3.0.0 | ||
| aiohttp>=3.10.2 | ||
| aiohttp-retry==2.8.3 | ||
| certifi>=2023.7.22 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| urllib3>=2.2.2 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,54 @@ | ||
| pygments>=2.7.4 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| requests>=2.32.2 | ||
| PyJWT>=2.0.0, <3.0.0 | ||
| aiohttp>=3.10.2 | ||
| # | ||
| # This file is autogenerated by pip-compile with Python 3.14 | ||
| # by the following command: | ||
| # | ||
| # pip-compile --output-file=requirements.txt requirements.in | ||
| # | ||
| aiohappyeyeballs==2.6.2 | ||
| # via aiohttp | ||
| aiohttp==3.14.1 | ||
| # via | ||
| # -r requirements.in | ||
| # aiohttp-retry | ||
| aiohttp-retry==2.8.3 | ||
| certifi>=2023.7.22 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| urllib3>=2.2.2 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability | ||
| # via -r requirements.in | ||
| aiosignal==1.4.0 | ||
| # via aiohttp | ||
| attrs==26.1.0 | ||
| # via aiohttp | ||
| certifi==2026.5.20 | ||
| # via | ||
| # -r requirements.in | ||
| # requests | ||
| charset-normalizer==3.4.7 | ||
| # via requests | ||
| frozenlist==1.8.0 | ||
| # via | ||
| # aiohttp | ||
| # aiosignal | ||
| idna==3.18 | ||
| # via | ||
| # requests | ||
| # yarl | ||
| multidict==6.7.1 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| propcache==0.5.2 | ||
| # via | ||
| # aiohttp | ||
| # yarl | ||
| pygments==2.20.0 | ||
| # via -r requirements.in | ||
| pyjwt==2.13.0 | ||
| # via -r requirements.in | ||
| requests==2.34.2 | ||
| # via -r requirements.in | ||
| urllib3==2.7.0 | ||
| # via | ||
| # -r requirements.in | ||
| # requests | ||
| yarl==1.24.2 | ||
| # via aiohttp | ||
| zipp==4.1.0 | ||
| # via -r requirements.in |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g.uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.🎈 Fixed in commit 8741919 🎈