From cdb62ceae11de53b4090b4067af201b5c9b492bb Mon Sep 17 00:00:00 2001 From: Matthew Feickert Date: Wed, 17 Apr 2024 16:06:31 -0500 Subject: [PATCH 1/3] feat: Use Trusted Publishers with GitLab CI/CD * PyPI Trusted Publisher support now includes GitLab CI/CD, so use generated OIDC tokens to publish to TestPyPI or PyPI as needed in GitLab pipelines. - c.f. https://blog.pypi.org/posts/2024-04-17-expanding-trusted-publisher-support/ --- ...ter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} index 7d05d089..fff26c35 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} @@ -17,11 +17,11 @@ cache: image: python:3.8-buster before_script: # want to set up a virtualenv to cache - - apt-get install -y --no-install-recommends git + - apt-get install -y --no-install-recommends git jq - python -V - python -m venv .venv - source .venv/bin/activate - - python -m pip install -U pip pipx + - python -m pip install -U pip pipx id - python -m pipx ensurepath - python -m pip freeze @@ -152,7 +152,12 @@ make_wheels: - make_wheels {%- endif %} script: - - pipx run twine upload --verbose dist/*whl dist/*gz + # Retrieve the OIDC token from GitLab CI/CD and exchange it for a PyPI API token + - oidc_token=$(python -m id PYPI) + - response=$(curl -X POST "${OIDC_MINT_TOKEN_URL}" -d "{\"token\":\"${oidc_token}\"}") + - api_token=$(jq --raw-output '.token' <<< "${response}") + + - pipx run twine upload --password "${api_token}" --verbose dist/*whl dist/*gz deploy_staging: extends: .deploy @@ -162,7 +167,7 @@ deploy_staging: variables: TWINE_REPOSITORY: testpypi TWINE_USERNAME: __token__ - TWINE_PASSWORD: $TESTPYPI_TOKEN + OIDC_MINT_TOKEN_URL: "https://test.pypi.org/_/oidc/mint-token" deploy_production: extends: .deploy @@ -171,4 +176,4 @@ deploy_production: variables: TWINE_REPOSITORY: pypi TWINE_USERNAME: __token__ - TWINE_PASSWORD: $PYPI_TOKEN + OIDC_MINT_TOKEN_URL: "https://pypi.org/_/oidc/mint-token" From d8b6211ba6cf6ec18ea0401b2928487e89ac4537 Mon Sep 17 00:00:00 2001 From: Matthew Feickert Date: Wed, 17 Apr 2024 16:22:07 -0500 Subject: [PATCH 2/3] Add required id_tokens --- ... cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} index fff26c35..3d6fea47 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} @@ -164,6 +164,9 @@ deploy_staging: rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "push" + id_tokens: + PYPI_ID_TOKEN: + aud: testpypi variables: TWINE_REPOSITORY: testpypi TWINE_USERNAME: __token__ @@ -173,6 +176,9 @@ deploy_production: extends: .deploy only: - tags + id_tokens: + PYPI_ID_TOKEN: + aud: pypi variables: TWINE_REPOSITORY: pypi TWINE_USERNAME: __token__ From 14518cfbaad63b52a6c0fe4b5d3275aa5c5f7274 Mon Sep 17 00:00:00 2001 From: Matthew Feickert Date: Wed, 24 Apr 2024 17:57:04 -0500 Subject: [PATCH 3/3] feat: Use pipx to run id * Requires id v1.4.0+ --- ...if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} index 3d6fea47..a1fe0423 100644 --- a/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} +++ b/{{cookiecutter.project_name}}/{% if cookiecutter.__ci=='gitlab' %}.gitlab-ci.yml{% endif %} @@ -21,7 +21,7 @@ before_script: - python -V - python -m venv .venv - source .venv/bin/activate - - python -m pip install -U pip pipx id + - python -m pip install -U pip pipx - python -m pipx ensurepath - python -m pip freeze @@ -153,7 +153,7 @@ make_wheels: {%- endif %} script: # Retrieve the OIDC token from GitLab CI/CD and exchange it for a PyPI API token - - oidc_token=$(python -m id PYPI) + - oidc_token=$(pipx run id PYPI) - response=$(curl -X POST "${OIDC_MINT_TOKEN_URL}" -d "{\"token\":\"${oidc_token}\"}") - api_token=$(jq --raw-output '.token' <<< "${response}")