summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Walls <jacobtylerwalls@gmail.com>2026-06-05 12:02:26 -0400
committerJacob Walls <jacobtylerwalls@gmail.com>2026-06-11 13:38:01 -0400
commit443780780bbe88822f0af4b27517d7e8f080a6a2 (patch)
tree1afe4c6de22a9d8c922e3d056dc74df20a963ee2
parent1d714484f67777e586fbea49ec743a7e39cba50f (diff)
Doc'd security standards in howto-release-django.txt.
-rw-r--r--docs/internals/howto-release-django.txt37
-rw-r--r--docs/spelling_wordlist1
2 files changed, 23 insertions, 15 deletions
diff --git a/docs/internals/howto-release-django.txt b/docs/internals/howto-release-django.txt
index 8d95018a0d..7acad7ac2b 100644
--- a/docs/internals/howto-release-django.txt
+++ b/docs/internals/howto-release-django.txt
@@ -85,9 +85,8 @@ permissions.
Linux, or ``md5`` and ``shasum`` on macOS)
* python
-* A GPG key pair. Ensure that the private part of this key is securely stored.
- The public part needs to be uploaded to your GitHub account, and also to the
- Jenkins server running the "confirm release" job.
+* A GPG key pair. Securely store the private part, and protect it with a
+ passphrase. The public part needs to be uploaded to your GitHub account.
.. admonition:: More than one GPG key
@@ -96,18 +95,16 @@ permissions.
``you@example.com`` is the email address associated with the key you want
to use.
-* A clean Python virtual environment (Python 3.9+) to build artifacts, with
- these required Python packages installed:
-
- .. code-block:: shell
-
- $ python -m pip install build twine
+* A clean Python virtual environment (Python 3.10+, pip 26.1+) to build
+ artifacts.
* Access to `Django's project on PyPI <https://pypi.org/project/Django/>`_ to
upload binaries, ideally with extra permissions to `yank a release
- <https://pypi.org/help/#yanked>`_ if necessary. Create a project-scoped token
- following the `official documentation <https://pypi.org/help/#apitoken>`_
- and set up your ``$HOME/.pypirc`` file like this:
+ <https://pypi.org/help/#yanked>`_ if necessary. Ensure your PyPI account
+ only uses WebAuthn-based authentication factors, not TOTP (one-time codes).
+ Create an API token following the `official documentation
+ <https://pypi.org/help/#apitoken>`_, and set up your ``$HOME/.pypirc`` file
+ like this:
.. code-block:: ini
:caption: ``~/.pypirc``
@@ -451,10 +448,15 @@ issuing **multiple releases**, repeat these steps for each release.
release date for all releases, if necessary (:commit:`example commit
<34a503162fe222033a1cd3249bccad014fcd1d20>`).
+#. Regenerate a fresh, dedicated virtual environment for the release tools
+ using a cooldown:
+
+ .. code-block:: shell
+
+ $ python -m pip install build twine --uploaded-prior-to=P7D
+
#. A release always begins from a release branch, so you should make sure
- you're on an up-to-date stable branch. Also, you should have available a
- clean and dedicated virtual environment per version being released. For
- example:
+ you're on an up-to-date stable branch. For example:
.. code-block:: shell
@@ -642,12 +644,17 @@ Now you're ready to actually put the release out there. To do this:
__ https://djangoci.com/job/confirm-release/
+#. Generate a new token for this release on PyPI, and store it in ``.pypirc``
+ as shown above.
+
#. Upload the release packages to PyPI:
.. code-block:: shell
$ twine upload --repository django dist/*
+#. On PyPI, revoke the token you just created.
+
#. Update the newly created ``Release`` in the admin in ``djangoproject.com``
and enable the ``is_active`` flag.
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 8d548d6439..61f7a1cb0d 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -95,6 +95,7 @@ conf
config
contenttypes
contrib
+cooldown
coroutine
coroutines
counterintuitive