Skip to content

Commit d57c9f0

Browse files
committed
Patch onedir Lib/ssl.py instead of dropping sitecustomize for cpython#104135
After #69490 landed, the `ci-test-onedir` job got past Install Deps, but the next session - `pre-archive-cleanup` (noxfile.py:1397-1402) - failed at the same step with the same `[ASN1: NOT_ENOUGH_DATA]`. That session also uses the onedir Python but creates its virtualenv WITHOUT `--system-site-packages`, so the `sitecustomize.py` we dropped in `artifacts/salt/Lib/site-packages/` isn't loaded by it and the buggy `_load_windows_store_certs` is back. Patch `Lib/ssl.py` in the onedir itself instead: virtualenv's venvs always read stdlib from the base Python's `Lib/` (with or without `--system-site-packages`), so a `Lib/ssl.py` append covers every venv launched from the onedir, plus the onedir Python directly. Verified on a local relenv 0.22.14 build (Python 3.10.20, OpenSSL 3.5.7): both a `--system-site-packages` venv and an isolated venv now report `_salt_safe_load_windows_store_certs` as the qualname for `ssl.SSLContext._load_windows_store_certs`, and a synthetic truncated cert injected via a monkey-patched `_ssl.enum_certificates` no longer aborts `load_default_certs()`. Drops `cicd/windows-ssl-104135-sitecustomize.py` (now redundant) and adds `cicd/windows-ssl-104135-patch.py` (idempotent in-place patcher; takes the ssl.py path as argv). The CI step swaps `cp ... -> sitecustomize.py` for `python3 cicd/windows-ssl-104135-patch.py artifacts/salt/Lib/ssl.py`. Cross-references in `salt/__init__.py` and `salt/ext/tornado/netutil.py` updated to point at the new filename so the trio still drops together when this branch's onedir Python moves off 3.10.
1 parent a4f5886 commit d57c9f0

5 files changed

Lines changed: 113 additions & 77 deletions

File tree

.github/workflows/build-deps-ci-action.yml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -292,20 +292,21 @@ jobs:
292292
cd artifacts
293293
tar xvf ${{ inputs.package-name }}-${{ inputs.salt-version }}-onedir-windows-${{ matrix.arch }}.tar.xz
294294
295-
- name: Apply cpython#104135 sitecustomize to onedir Python
296-
# The ci-test-onedir nox session creates a virtualenv from the onedir
297-
# Python (3.10 on this branch) and runs pip *inside it* before salt is
298-
# importable; Python 3.10's _load_windows_store_certs feeds the whole
299-
# Windows root store to load_verify_locations as one blob, which
300-
# OpenSSL 3.5.x (relenv >= 0.22.13) rejects on a single bad cert.
301-
# Dropping the sitecustomize at the onedir site-packages root means
302-
# the venv inherits it via --system-site-packages and the iter-and-
303-
# skip patch fires at every interpreter start. Self-disables on
304-
# Python 3.11+; remove with the rest of the cpython#104135 trio.
295+
- name: Patch cpython#104135 in onedir Lib/ssl.py
296+
# The build-deps-ci nox sessions (ci-test-onedir, pre-archive-cleanup)
297+
# create virtualenvs from the onedir Python (3.10 on this branch) and
298+
# run pip *inside them* before salt is importable; Python 3.10's
299+
# _load_windows_store_certs feeds the whole Windows root store to
300+
# load_verify_locations as one blob, which OpenSSL 3.5.x (relenv >=
301+
# 0.22.13) rejects on a single bad cert. Patching Lib/ssl.py in the
302+
# onedir reaches every venv created from it (the venv's python.exe
303+
# always reads stdlib from the base Python's Lib/), whether or not
304+
# nox passes --system-site-packages. Self-disables on Python 3.11+;
305+
# remove with the rest of the cpython#104135 trio.
305306
if: steps.nox-dependencies-cache.outputs.cache-hit != 'true'
306307
shell: bash
307308
run: |
308-
cp cicd/windows-ssl-104135-sitecustomize.py artifacts/salt/Lib/site-packages/sitecustomize.py
309+
python3 cicd/windows-ssl-104135-patch.py artifacts/salt/Lib/ssl.py
309310
310311
- name: Set up Python ${{ inputs.ci-python-version }}
311312
if: steps.nox-dependencies-cache.outputs.cache-hit != 'true'

cicd/windows-ssl-104135-patch.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
"""
2+
Patch the salt onedir Python's ``Lib/ssl.py`` in place to apply
3+
cpython#104135's iterate-and-skip variant of
4+
``ssl.SSLContext._load_windows_store_certs``.
5+
6+
Usage: ``python windows-ssl-104135-patch.py <path-to-ssl.py>``
7+
8+
Background
9+
----------
10+
11+
The build-deps-ci Windows job extracts the salt onedir, then runs
12+
``nox --install-only -e ci-test-onedir`` and ``nox -e pre-archive-cleanup``.
13+
Both sessions target the onedir's relenv-bundled Python (3.10.20 on 3006.x)
14+
and create virtualenvs from it. The ``ci-test-onedir`` session uses
15+
``--system-site-packages``; ``pre-archive-cleanup`` does not. Either way,
16+
both venvs share the onedir's ``Lib/ssl.py`` because virtualenv leaves the
17+
base Python's stdlib on ``sys.path``.
18+
19+
Python 3.10's stdlib ``ssl._load_windows_store_certs`` concatenates every
20+
cert from the Windows root store and feeds them to
21+
``load_verify_locations(cadata=...)`` as one blob. OpenSSL 3.5.x (shipped by
22+
relenv >= 0.22.13) rejects the whole blob on a single ASN.1-malformed cert,
23+
so pip's TLS to pypi.org dies with ``[ASN1: NOT_ENOUGH_DATA]`` before any
24+
deps land. See cpython#104135.
25+
26+
Appending the patch to ``Lib/ssl.py`` means every Python invocation using
27+
the onedir picks up the fix - the ``ci-test-onedir`` venv, the
28+
``pre-archive-cleanup`` venv, the raw onedir python itself, anything.
29+
30+
A ``sitecustomize.py`` would only reach the venv that turns on
31+
``--system-site-packages``; a ``Lib/ssl.py`` append covers both.
32+
33+
Python-3.10-only: self-disables on Python 3.11+ (whose stdlib already has
34+
the upstream fix). Delete this file together with the salt/__init__.py
35+
block and the salt/ext/tornado/netutil.py ``sys.platform == 'win32'``
36+
special-case on any branch whose onedir Python is >= 3.11.
37+
"""
38+
39+
import sys
40+
41+
MARKER = "# >>> cpython#104135 patch (windows-ssl-104135-patch.py) <<<"
42+
43+
PATCH_BODY = f"""
44+
45+
{MARKER}
46+
# Replace the pre-fix _load_windows_store_certs with the iterate-and-skip
47+
# variant cpython merged for the 3.11 branch. See cpython#104135.
48+
# Self-disable on Python 3.11+ (where Lib/ssl.py already has the upstream
49+
# fix) and on non-Windows.
50+
import sys as _patch_sys
51+
52+
if _patch_sys.platform == "win32" and _patch_sys.version_info < (3, 11):
53+
54+
def _salt_safe_load_windows_store_certs(
55+
self, storename, purpose, _SSLError=SSLError
56+
):
57+
try:
58+
from _ssl import enum_certificates
59+
except ImportError:
60+
return
61+
try:
62+
for cert, encoding, trust in enum_certificates(storename):
63+
if encoding != "x509_asn":
64+
continue
65+
if trust is True or purpose.oid in trust:
66+
try:
67+
self.load_verify_locations(cadata=cert)
68+
except _SSLError:
69+
pass
70+
except PermissionError:
71+
pass
72+
73+
SSLContext._load_windows_store_certs = _salt_safe_load_windows_store_certs
74+
"""
75+
76+
77+
def main(argv: list[str]) -> int:
78+
if len(argv) != 2:
79+
print(
80+
f"usage: {argv[0]} <path-to-ssl.py>",
81+
file=sys.stderr,
82+
)
83+
return 2
84+
path = argv[1]
85+
with open(path, encoding="utf-8") as fh:
86+
contents = fh.read()
87+
if MARKER in contents:
88+
print(f"{path}: already patched, leaving alone")
89+
return 0
90+
with open(path, "a", encoding="utf-8") as fh:
91+
fh.write(PATCH_BODY)
92+
print(f"{path}: appended cpython#104135 work-around")
93+
return 0
94+
95+
96+
if __name__ == "__main__":
97+
raise SystemExit(main(sys.argv))

cicd/windows-ssl-104135-sitecustomize.py

Lines changed: 0 additions & 62 deletions
This file was deleted.

salt/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
#
2626
# Companion work-arounds (delete together with this block):
2727
# - salt/ext/tornado/netutil.py: certifi.where() pin on Windows
28-
# - cicd/windows-ssl-104135-sitecustomize.py + the Apply-sitecustomize step
29-
# in .github/workflows/build-deps-ci-action.yml's Windows job, which
28+
# - cicd/windows-ssl-104135-patch.py + the Patch-Lib/ssl.py step in
29+
# .github/workflows/build-deps-ci-action.yml's Windows job, which
3030
# re-applies this same patch to the onedir Python *before* salt is
3131
# importable (covers pip during the CI-Deps step).
3232
if sys.platform == "win32":

salt/ext/tornado/netutil.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ def match_hostname(cert, hostname):
289289
#
290290
# Companion work-arounds (delete together with this block):
291291
# - salt/__init__.py: _load_windows_store_certs monkey-patch
292-
# - cicd/windows-ssl-104135-sitecustomize.py + the Apply-
293-
# sitecustomize step in build-deps-ci-action.yml's Windows job.
292+
# - cicd/windows-ssl-104135-patch.py + the Patch-Lib/ssl.py step
293+
# in build-deps-ci-action.yml's Windows job.
294294
if sys.platform == 'win32' and certifi is not None:
295295
_client_ssl_defaults = ssl.create_default_context(
296296
ssl.Purpose.SERVER_AUTH, cafile=certifi.where())

0 commit comments

Comments
 (0)