This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v3-2-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-2-test by this push:
     new f6ee186e1e2 Release docs: port airflowctl fixes and guidance to other 
components (#65576) (#65582)
f6ee186e1e2 is described below

commit f6ee186e1e2701459b3bbe579bce4d2471bc266d
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Sun Apr 26 14:06:25 2026 +0200

    Release docs: port airflowctl fixes and guidance to other components 
(#65576) (#65582)
    
    Apply fixes and additions that landed in the airflow-ctl release README to
    the airflow, providers, python-client, and helm-chart release READMEs:
    
    - Fix `rm -rf /tmp/apache/...-src` typo where the cleanup path did not match
      the subsequent `mkdir -p /tmp/apache-...-src` (providers, python-client).
    - Add defensive `cd "${AIRFLOW_REPO_ROOT}"` before `git fetch apache --tags`
      in the reproducible-build sections (providers, python-client).
    - Add "Collect ambiguities during the release" section encouraging release
      managers to keep a scratch file outside the repo for follow-up doc PRs
      (all four docs).
    - Add "Verify your GPG signing key is ready" preflight block so signing
      failures surface before artifact build (all four docs).
    - Add PyPI token single-use/deletion guidance before every upload step —
      create a short-lived token, run the upload, delete it immediately
      (airflow, providers, python-client).
    - Rename "Add tags in git" to "Add the final release tag in git" in the
      post-vote section where it was ambiguous with the RC-tag step (providers).
    
    Co-authored-by: Jarek Potiuk <[email protected]>
---
 dev/README_RELEASE_AIRFLOW.md       |  95 ++++++++++++++++++++++++++++++++
 dev/README_RELEASE_HELM_CHART.md    |  49 +++++++++++++++++
 dev/README_RELEASE_PROVIDERS.md     | 106 ++++++++++++++++++++++++++++++++++--
 dev/README_RELEASE_PYTHON_CLIENT.md | 102 +++++++++++++++++++++++++++++++++-
 4 files changed, 344 insertions(+), 8 deletions(-)

diff --git a/dev/README_RELEASE_AIRFLOW.md b/dev/README_RELEASE_AIRFLOW.md
index 28a032e5770..80beae13d76 100644
--- a/dev/README_RELEASE_AIRFLOW.md
+++ b/dev/README_RELEASE_AIRFLOW.md
@@ -20,6 +20,7 @@
 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
 **Table of contents**
 
+- [Collect ambiguities during the release (for a follow-up doc 
PR)](#collect-ambiguities-during-the-release-for-a-follow-up-doc-pr)
 - [Perform review of security issues that are marked for the 
release](#perform-review-of-security-issues-that-are-marked-for-the-release)
 - [Selecting what to put into the 
release](#selecting-what-to-put-into-the-release)
   - [i18n workflow](#i18n-workflow)
@@ -68,6 +69,21 @@
 
 You can find the prerequisites to release Apache Airflow in 
[README.md](README.md).
 
+# Collect ambiguities during the release (for a follow-up doc PR)
+
+These instructions are imperfect. Every release uncovers at least one command
+that has drifted, one step that is under-documented, or one automation that
+silently did the wrong thing. As you run through this document, jot down any
+such observations in a scratch file kept **outside** the repo (anywhere that
+is not tracked by git — a note in your home directory, a scratchpad, a
+gist). Once the release has landed, turn those notes into a follow-up PR
+against this document.
+
+Keeping the scratch file out of the repo avoids accidentally committing
+release-manager notes along with the release-prep PR, and makes it obvious
+that the notes are input to the next doc PR rather than something to keep
+around long-term.
+
 # Perform review of security issues that are marked for the release
 
 We are keeping track of security issues in the [Security 
Issues](https://github.com/airflow-s/airflow-s/issues)
@@ -377,6 +393,39 @@ export AIRFLOW_REPO_ROOT=$(pwd)
 uv tool install -e ./dev/breeze
 ```
 
+- Verify your GPG signing key is ready.
+
+  Before you spend 10+ minutes building artifacts only to discover that signing
+  fails, run these checks once:
+
+  ```shell script
+  # 1. The apache.org key has a secret signing subkey available locally.
+  gpg --list-secret-keys apache.org
+
+  # 2. Signing actually works (exits 0, writes a .asc, verifies cleanly).
+  echo test > /tmp/sign-check && \
+      gpg --yes --armor --local-user apache.org \
+          --output /tmp/sign-check.asc --detach-sig /tmp/sign-check && \
+      gpg --verify /tmp/sign-check.asc /tmp/sign-check && \
+      rm -f /tmp/sign-check /tmp/sign-check.asc && \
+      echo "GPG signing OK"
+
+  # 3. The fingerprint of your signing (sub)key appears in the Airflow KEYS 
file.
+  #    Without this, PMC verifiers cannot validate the release.
+  FINGERPRINT=$(gpg --list-keys --with-colons apache.org | awk -F: '/^fpr:/ 
{print $10; exit}')
+  curl -fsS https://dist.apache.org/repos/dist/release/airflow/KEYS | \
+      grep -q "${FINGERPRINT}" && echo "Key ${FINGERPRINT} is in KEYS" || \
+      echo "MISSING: add your key to KEYS before releasing"
+  ```
+
+  If any of these fail, fix them before the build step. For first-time release
+  managers, adding your key to the `KEYS` file is a separate PR against
+  `https://dist.apache.org/repos/dist/release/airflow/` (SVN).
+
+  `sign.sh` defaults to `SIGN_WITH=apache.org`. If your `apache.org` uid 
resolves
+  to multiple keys (rare), set `SIGN_WITH` explicitly to the fingerprint of the
+  key you want to use.
+
 - For major/minor version release, run the following commands to create the 
'test' and 'stable' branches.
 
     ```shell script
@@ -478,6 +527,30 @@ uv tool install -e ./dev/breeze
     export GITHUB_TOKEN="my_token"
     ```
 
+- Configure a short-lived PyPI token for this upload only. **Until Trusted
+  Publishing is deployed for apache-airflow on PyPI**, the recommended
+  practice is:
+
+  1. Log in to https://pypi.org and create an API token right before the
+     upload step. **Scope caveat:** you would ideally create a
+     project-scoped token for `apache-airflow` alone, but PyPI only
+     allows project-scoped tokens for projects you already own/maintain on
+     that account. Most Airflow release managers do not have per-project
+     owner rights on `apache-airflow`, so in practice you will need to
+     create an account-wide ("all projects") token. That is acceptable
+     **only if** you treat it as single-use and delete it immediately
+     after the upload (step 4 below). Never keep an all-projects token on
+     disk longer than the upload itself.
+  2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+     `TWINE_PASSWORD=pypi-...`).
+  3. Run the `start-rc-process` command (below) — it uploads to PyPI under
+     the hood.
+  4. **Immediately delete the token** from the PyPI web UI after the upload
+     completes. Do not keep long-lived release-manager tokens on disk.
+
+  This is a defence-in-depth practice: the RM machine becomes a one-time
+  release vehicle, not a persistent point of compromise.
+
 - Start the release candidate process by running the below command (If you 
have not generated a key yet, generate it by following instructions on
     http://www.apache.org/dev/openpgp.html#key-gen-generate-key):
 
@@ -1238,6 +1311,28 @@ https://dist.apache.org/repos/dist/release/airflow/
 
 The best way of doing this is to svn cp between the two repos (this avoids 
having to upload the binaries again, and gives a clearer history in the svn 
commit logs):
 
+Before running `start-release`, configure a short-lived PyPI token for this
+upload only. **Until Trusted Publishing is deployed for apache-airflow on
+PyPI**, the recommended practice is:
+
+1. Log in to https://pypi.org and create an API token right before the
+   upload step. **Scope caveat:** you would ideally create a project-scoped
+   token for `apache-airflow` alone, but PyPI only allows project-scoped
+   tokens for projects you already own/maintain on that account. Most
+   Airflow release managers do not have per-project owner rights on
+   `apache-airflow`, so in practice you will need to create an account-wide
+   ("all projects") token. That is acceptable **only if** you treat it as
+   single-use and delete it immediately after the upload (step 4 below).
+   Never keep an all-projects token on disk longer than the upload itself.
+2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+   `TWINE_PASSWORD=pypi-...`).
+3. Run the `start-release` command below — it uploads to PyPI under the hood.
+4. **Immediately delete the token** from the PyPI web UI after the upload
+   completes. Do not keep long-lived release-manager tokens on disk.
+
+This is a defence-in-depth practice: the RM machine becomes a one-time
+release vehicle, not a persistent point of compromise.
+
 ```shell script
 export VERSION=3.1.3
 export TASK_SDK_VERSION=1.1.3
diff --git a/dev/README_RELEASE_HELM_CHART.md b/dev/README_RELEASE_HELM_CHART.md
index 1c06a0be344..1c6dcaffc2a 100644
--- a/dev/README_RELEASE_HELM_CHART.md
+++ b/dev/README_RELEASE_HELM_CHART.md
@@ -20,6 +20,7 @@
 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
 **Table of contents**
 
+- [Collect ambiguities during the release (for a follow-up doc 
PR)](#collect-ambiguities-during-the-release-for-a-follow-up-doc-pr)
 - [Perform review of security issues that are marked for the 
release](#perform-review-of-security-issues-that-are-marked-for-the-release)
 - [Prepare the Apache Airflow Helm Chart Release 
Candidate](#prepare-the-apache-airflow-helm-chart-release-candidate)
   - [Pre-requisites](#pre-requisites)
@@ -65,6 +66,21 @@
 You can find the prerequisites to release Apache Airflow in 
[README.md](README.md). This document
 details the steps for releasing Helm Chart.
 
+# Collect ambiguities during the release (for a follow-up doc PR)
+
+These instructions are imperfect. Every release uncovers at least one command
+that has drifted, one step that is under-documented, or one automation that
+silently did the wrong thing. As you run through this document, jot down any
+such observations in a scratch file kept **outside** the repo (anywhere that
+is not tracked by git — a note in your home directory, a scratchpad, a
+gist). Once the release has landed, turn those notes into a follow-up PR
+against this document.
+
+Keeping the scratch file out of the repo avoids accidentally committing
+release-manager notes along with the release-prep PR, and makes it obvious
+that the notes are input to the next doc PR rather than something to keep
+around long-term.
+
 # Perform review of security issues that are marked for the release
 
 We are keeping track of security issues in the [Security 
Issues](https://github.com/airflow-s/airflow-s/issues)
@@ -228,6 +244,39 @@ git clean -fxd
 rm -rf dist/*
 ```
 
+- Verify your GPG signing key is ready.
+
+  Before you spend 10+ minutes building artifacts only to discover that signing
+  fails, run these checks once:
+
+  ```shell
+  # 1. The apache.org key has a secret signing subkey available locally.
+  gpg --list-secret-keys apache.org
+
+  # 2. Signing actually works (exits 0, writes a .asc, verifies cleanly).
+  echo test > /tmp/sign-check && \
+      gpg --yes --armor --local-user apache.org \
+          --output /tmp/sign-check.asc --detach-sig /tmp/sign-check && \
+      gpg --verify /tmp/sign-check.asc /tmp/sign-check && \
+      rm -f /tmp/sign-check /tmp/sign-check.asc && \
+      echo "GPG signing OK"
+
+  # 3. The fingerprint of your signing (sub)key appears in the Airflow KEYS 
file.
+  #    Without this, PMC verifiers cannot validate the release.
+  FINGERPRINT=$(gpg --list-keys --with-colons apache.org | awk -F: '/^fpr:/ 
{print $10; exit}')
+  curl -fsS https://dist.apache.org/repos/dist/release/airflow/KEYS | \
+      grep -q "${FINGERPRINT}" && echo "Key ${FINGERPRINT} is in KEYS" || \
+      echo "MISSING: add your key to KEYS before releasing"
+  ```
+
+  If any of these fail, fix them before the build step. For first-time release
+  managers, adding your key to the `KEYS` file is a separate PR against
+  `https://dist.apache.org/repos/dist/release/airflow/` (SVN).
+
+  `sign.sh` defaults to `SIGN_WITH=apache.org`. If your `apache.org` uid 
resolves
+  to multiple keys (rare), set `SIGN_WITH` explicitly to the fingerprint of the
+  key you want to use.
+
 - Generate the source tarball:
 
 ```shell
diff --git a/dev/README_RELEASE_PROVIDERS.md b/dev/README_RELEASE_PROVIDERS.md
index 74d806416b0..4cc353e3f4e 100644
--- a/dev/README_RELEASE_PROVIDERS.md
+++ b/dev/README_RELEASE_PROVIDERS.md
@@ -23,6 +23,7 @@
 - [Intro](#intro)
   - [What the provider distributions are](#what-the-provider-distributions-are)
   - [Decide when to release](#decide-when-to-release)
+- [Collect ambiguities during the release (for a follow-up doc 
PR)](#collect-ambiguities-during-the-release-for-a-follow-up-doc-pr)
 - [Special procedures (done very 
infrequently)](#special-procedures-done-very-infrequently)
   - [Bump min Airflow version for 
providers](#bump-min-airflow-version-for-providers)
   - [Move provider into remove state](#move-provider-into-remove-state)
@@ -48,7 +49,7 @@
   - [Summarize the voting for the Apache Airflow 
release](#summarize-the-voting-for-the-apache-airflow-release)
   - [Publish release to SVN](#publish-release-to-svn)
   - [Publish the packages to PyPI](#publish-the-packages-to-pypi)
-  - [Add tags in git](#add-tags-in-git)
+  - [Add the final release tag in git](#add-the-final-release-tag-in-git)
   - [Publish documentation](#publish-documentation)
   - [Update providers metadata](#update-providers-metadata)
   - [Notify developers of release](#notify-developers-of-release)
@@ -86,6 +87,21 @@ a given provider needs to be released due to new features or 
due to bug fixes.
 package separately, but due to voting and release overhead we try to group 
releases of Provider
 distributions together.
 
+# Collect ambiguities during the release (for a follow-up doc PR)
+
+These instructions are imperfect. Every release uncovers at least one command
+that has drifted, one step that is under-documented, or one automation that
+silently did the wrong thing. As you run through this document, jot down any
+such observations in a scratch file kept **outside** the repo (anywhere that
+is not tracked by git — a note in your home directory, a scratchpad, a
+gist). Once the release has landed, turn those notes into a follow-up PR
+against this document.
+
+Keeping the scratch file out of the repo avoids accidentally committing
+release-manager notes along with the release-prep PR, and makes it obvious
+that the notes are input to the next doc PR rather than something to keep
+around long-term.
+
 # Special procedures (done very infrequently)
 
 > [!NOTE]
@@ -340,6 +356,39 @@ Linux (Debian/Ubuntu):
 sudo apt-get install libassuan-dev gnupg
 ```
 
+### Verify your GPG signing key is ready
+
+Before you spend 10+ minutes building artifacts only to discover that signing
+fails, run these checks once:
+
+```shell script
+# 1. The apache.org key has a secret signing subkey available locally.
+gpg --list-secret-keys apache.org
+
+# 2. Signing actually works (exits 0, writes a .asc, verifies cleanly).
+echo test > /tmp/sign-check && \
+    gpg --yes --armor --local-user apache.org \
+        --output /tmp/sign-check.asc --detach-sig /tmp/sign-check && \
+    gpg --verify /tmp/sign-check.asc /tmp/sign-check && \
+    rm -f /tmp/sign-check /tmp/sign-check.asc && \
+    echo "GPG signing OK"
+
+# 3. The fingerprint of your signing (sub)key appears in the Airflow KEYS file.
+#    Without this, PMC verifiers cannot validate the release.
+FINGERPRINT=$(gpg --list-keys --with-colons apache.org | awk -F: '/^fpr:/ 
{print $10; exit}')
+curl -fsS https://dist.apache.org/repos/dist/release/airflow/KEYS | \
+    grep -q "${FINGERPRINT}" && echo "Key ${FINGERPRINT} is in KEYS" || \
+    echo "MISSING: add your key to KEYS before releasing"
+```
+
+If any of these fail, fix them before the build step. For first-time release
+managers, adding your key to the `KEYS` file is a separate PR against
+`https://dist.apache.org/repos/dist/release/airflow/` (SVN).
+
+`sign.sh` defaults to `SIGN_WITH=apache.org`. If your `apache.org` uid resolves
+to multiple keys (rare), set `SIGN_WITH` explicitly to the fingerprint of the
+key you want to use.
+
 ## Build and sign the source and convenience packages
 
 * Cleanup dist folder:
@@ -482,7 +531,30 @@ increased until the tag is not found.
 twine check ${AIRFLOW_REPO_ROOT}/dist/*
 ```
 
-* Upload the package to PyPi:
+* Configure a short-lived PyPI token for this upload only. **Until Trusted
+  Publishing is deployed for the Airflow provider distributions on PyPI**,
+  the recommended practice is:
+
+  1. Log in to https://pypi.org and create an API token right before the
+     upload step. **Scope caveat:** you would ideally create a
+     project-scoped token, but PyPI only allows project-scoped tokens for
+     projects you already own/maintain on that account. Most Airflow
+     release managers do not have per-project owner rights on every
+     provider being released, so in practice you will need to create an
+     account-wide ("all projects") token. That is acceptable **only if**
+     you treat it as single-use and delete it immediately after the upload
+     (step 4 below). Never keep an all-projects token on disk longer than
+     the upload itself.
+  2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+     `TWINE_PASSWORD=pypi-...`).
+  3. Run the upload (below).
+  4. **Immediately delete the token** from the PyPI web UI after the upload
+     completes. Do not keep long-lived release-manager tokens on disk.
+
+  This is a defence-in-depth practice: the RM machine becomes a one-time
+  release vehicle, not a persistent point of compromise.
+
+* Upload the package to PyPI:
 
 ```shell script
 twine upload -r pypi ${AIRFLOW_REPO_ROOT}/dist/*
@@ -776,6 +848,7 @@ cd "$AIRFLOW_REPO_ROOT"
 2) Check out the ``providers/YYYY-MM-DD`` tag:
 
 ```shell
+cd "$AIRFLOW_REPO_ROOT"
 git fetch apache --tags
 git checkout providers/${RELEASE_DATE}
 ```
@@ -869,7 +942,7 @@ tar -xzf /tmp/apache-rat-0.17-bin.tar.gz -C /tmp
 Unpack the release source archive (the `<package + version>-source.tar.gz` 
file) to a folder
 
 ```shell script
-rm -rf /tmp/apache/airflow-providers-src && mkdir -p 
/tmp/apache-airflow-providers-src && tar -xzf 
${PATH_TO_AIRFLOW_SVN}/providers/${RELEASE_DATE}/apache_airflow_providers-*-source.tar.gz
 --strip-components 1 -C /tmp/apache-airflow-providers-src
+rm -rf /tmp/apache-airflow-providers-src && mkdir -p 
/tmp/apache-airflow-providers-src && tar -xzf 
${PATH_TO_AIRFLOW_SVN}/providers/${RELEASE_DATE}/apache_airflow_providers-*-source.tar.gz
 --strip-components 1 -C /tmp/apache-airflow-providers-src
 ```
 
 Run the check:
@@ -1275,7 +1348,30 @@ rm 
dist/apache_airflow_providers-${RELEASE_DATE}-source.tar.gz
 twine check ${AIRFLOW_REPO_ROOT}/dist/*.whl ${AIRFLOW_REPO_ROOT}/dist/*.tar.gz
 ```
 
-* Upload the package to PyPi:
+* Configure a short-lived PyPI token for this upload only. **Until Trusted
+  Publishing is deployed for the Airflow provider distributions on PyPI**,
+  the recommended practice is:
+
+  1. Log in to https://pypi.org and create an API token right before the
+     upload step. **Scope caveat:** you would ideally create a
+     project-scoped token, but PyPI only allows project-scoped tokens for
+     projects you already own/maintain on that account. Most Airflow
+     release managers do not have per-project owner rights on every
+     provider being released, so in practice you will need to create an
+     account-wide ("all projects") token. That is acceptable **only if**
+     you treat it as single-use and delete it immediately after the upload
+     (step 4 below). Never keep an all-projects token on disk longer than
+     the upload itself.
+  2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+     `TWINE_PASSWORD=pypi-...`).
+  3. Run the upload (below).
+  4. **Immediately delete the token** from the PyPI web UI after the upload
+     completes. Do not keep long-lived release-manager tokens on disk.
+
+  This is a defence-in-depth practice: the RM machine becomes a one-time
+  release vehicle, not a persistent point of compromise.
+
+* Upload the package to PyPI:
 
 ```shell script
 twine upload -r pypi ${AIRFLOW_REPO_ROOT}/dist/*.whl 
${AIRFLOW_REPO_ROOT}/dist/*.tar.gz
@@ -1288,7 +1384,7 @@ Copy links to updated packages, sort it alphabetically 
and save it on the side.
 * Again, confirm that the packages are available under the links printed.
 
 
-## Add tags in git
+## Add the final release tag in git
 
 Assume that your remote for apache repository is called `apache` you should now
 set tags for the providers in the repository.
diff --git a/dev/README_RELEASE_PYTHON_CLIENT.md 
b/dev/README_RELEASE_PYTHON_CLIENT.md
index 68d6e57d044..516b7feda13 100644
--- a/dev/README_RELEASE_PYTHON_CLIENT.md
+++ b/dev/README_RELEASE_PYTHON_CLIENT.md
@@ -21,6 +21,7 @@
 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
 **Table of Contents**  *generated with 
[DocToc](https://github.com/thlorenz/doctoc)*
 
+- [Collect ambiguities during the release (for a follow-up doc 
PR)](#collect-ambiguities-during-the-release-for-a-follow-up-doc-pr)
 - [Perform review of security issues that are marked for the 
release](#perform-review-of-security-issues-that-are-marked-for-the-release)
 - [Release package](#release-package)
   - [Prepare PyPI convenience "RC" 
packages](#prepare-pypi-convenience-rc-packages)
@@ -38,6 +39,21 @@
 
 <!-- END doctoc generated TOC please keep comment here to allow auto update -->
 
+# Collect ambiguities during the release (for a follow-up doc PR)
+
+These instructions are imperfect. Every release uncovers at least one command
+that has drifted, one step that is under-documented, or one automation that
+silently did the wrong thing. As you run through this document, jot down any
+such observations in a scratch file kept **outside** the repo (anywhere that
+is not tracked by git — a note in your home directory, a scratchpad, a
+gist). Once the release has landed, turn those notes into a follow-up PR
+against this document.
+
+Keeping the scratch file out of the repo avoids accidentally committing
+release-manager notes along with the release-prep PR, and makes it obvious
+that the notes are input to the next doc PR rather than something to keep
+around long-term.
+
 # Perform review of security issues that are marked for the release
 
 We are keeping track of security issues in the [Security 
Issues](https://github.com/airflow-s/airflow-s/issues)
@@ -195,6 +211,39 @@ breeze release-management prepare-tarball --tarball-type 
apache_airflow_python_c
 - Generate signatures and checksum files for the packages (if you have not 
generated a key yet, generate
   it by following instructions on 
http://www.apache.org/dev/openpgp.html#key-gen-generate-key)
 
+- Verify your GPG signing key is ready.
+
+  Before you spend 10+ minutes building artifacts only to discover that signing
+  fails, run these checks once:
+
+  ```shell script
+  # 1. The apache.org key has a secret signing subkey available locally.
+  gpg --list-secret-keys apache.org
+
+  # 2. Signing actually works (exits 0, writes a .asc, verifies cleanly).
+  echo test > /tmp/sign-check && \
+      gpg --yes --armor --local-user apache.org \
+          --output /tmp/sign-check.asc --detach-sig /tmp/sign-check && \
+      gpg --verify /tmp/sign-check.asc /tmp/sign-check && \
+      rm -f /tmp/sign-check /tmp/sign-check.asc && \
+      echo "GPG signing OK"
+
+  # 3. The fingerprint of your signing (sub)key appears in the Airflow KEYS 
file.
+  #    Without this, PMC verifiers cannot validate the release.
+  FINGERPRINT=$(gpg --list-keys --with-colons apache.org | awk -F: '/^fpr:/ 
{print $10; exit}')
+  curl -fsS https://dist.apache.org/repos/dist/release/airflow/KEYS | \
+      grep -q "${FINGERPRINT}" && echo "Key ${FINGERPRINT} is in KEYS" || \
+      echo "MISSING: add your key to KEYS before releasing"
+  ```
+
+  If any of these fail, fix them before the build step. For first-time release
+  managers, adding your key to the `KEYS` file is a separate PR against
+  `https://dist.apache.org/repos/dist/release/airflow/` (SVN).
+
+  `sign.sh` defaults to `SIGN_WITH=apache.org`. If your `apache.org` uid 
resolves
+  to multiple keys (rare), set `SIGN_WITH` explicitly to the fingerprint of the
+  key you want to use.
+
 ```shell script
 cd ${AIRFLOW_REPO_ROOT}
 pushd dist
@@ -251,7 +300,30 @@ breeze release-management prepare-python-client 
--distribution-format both --ver
 twine check dist/*
 ```
 
-- Upload the package to PyPi's production environment:
+- Configure a short-lived PyPI token for this upload only. **Until Trusted
+  Publishing is deployed for apache-airflow-client on PyPI**, the
+  recommended practice is:
+
+  1. Log in to https://pypi.org and create an API token right before the
+     upload step. **Scope caveat:** you would ideally create a
+     project-scoped token for `apache-airflow-client` alone, but PyPI only
+     allows project-scoped tokens for projects you already own/maintain on
+     that account. Most Airflow release managers do not have per-project
+     owner rights on `apache-airflow-client`, so in practice you will need
+     to create an account-wide ("all projects") token. That is acceptable
+     **only if** you treat it as single-use and delete it immediately
+     after the upload (step 4 below). Never keep an all-projects token on
+     disk longer than the upload itself.
+  2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+     `TWINE_PASSWORD=pypi-...`).
+  3. Run the upload (below).
+  4. **Immediately delete the token** from the PyPI web UI after the upload
+     completes. Do not keep long-lived release-manager tokens on disk.
+
+  This is a defence-in-depth practice: the RM machine becomes a one-time
+  release vehicle, not a persistent point of compromise.
+
+- Upload the package to PyPI's production environment:
 
 ```shell script
 twine upload -r pypi dist/*
@@ -391,6 +463,7 @@ cd "${AIRFLOW_REPO_ROOT}"
 3) Check out the ``python-client`` tag (assume apache is the remote name of 
the repository):
 
 ```shell
+cd "${AIRFLOW_REPO_ROOT}"
 git fetch apache --tags
 git checkout python-client/${VERSION_RC}
 ```
@@ -471,7 +544,7 @@ tar -xzf /tmp/apache-rat-0.17-bin.tar.gz -C /tmp
 Unpack the release source archive (the `<package + version>-source.tar.gz` 
file) to a folder
 
 ```shell script
-rm -rf /tmp/apache/airflow-python-client-src && mkdir -p 
/tmp/apache-airflow-python-client-src && tar -xzf 
${PATH_TO_AIRFLOW_SVN}/clients/python/${VERSION_RC}/apache_airflow_python_client-*-source.tar.gz
 --strip-components 1 -C /tmp/apache-airflow-python-client-src
+rm -rf /tmp/apache-airflow-python-client-src && mkdir -p 
/tmp/apache-airflow-python-client-src && tar -xzf 
${PATH_TO_AIRFLOW_SVN}/clients/python/${VERSION_RC}/apache_airflow_python_client-*-source.tar.gz
 --strip-components 1 -C /tmp/apache-airflow-python-client-src
 ```
 
 Run the check:
@@ -745,7 +818,30 @@ cd ${VERSION}
 twine check *${VERSION}.tar.gz *.whl
 ```
 
-- Upload the package to PyPi's production environment:
+- Configure a short-lived PyPI token for this upload only. **Until Trusted
+  Publishing is deployed for apache-airflow-client on PyPI**, the
+  recommended practice is:
+
+  1. Log in to https://pypi.org and create an API token right before the
+     upload step. **Scope caveat:** you would ideally create a
+     project-scoped token for `apache-airflow-client` alone, but PyPI only
+     allows project-scoped tokens for projects you already own/maintain on
+     that account. Most Airflow release managers do not have per-project
+     owner rights on `apache-airflow-client`, so in practice you will need
+     to create an account-wide ("all projects") token. That is acceptable
+     **only if** you treat it as single-use and delete it immediately
+     after the upload (step 4 below). Never keep an all-projects token on
+     disk longer than the upload itself.
+  2. Put it in `~/.pypirc` (or export as `TWINE_USERNAME=__token__`
+     `TWINE_PASSWORD=pypi-...`).
+  3. Run the upload (below).
+  4. **Immediately delete the token** from the PyPI web UI after the upload
+     completes. Do not keep long-lived release-manager tokens on disk.
+
+  This is a defence-in-depth practice: the RM machine becomes a one-time
+  release vehicle, not a persistent point of compromise.
+
+- Upload the package to PyPI's production environment:
 
 ```shell script
 twine upload -r pypi *${VERSION}.tar.gz *.whl

Reply via email to