From 489aae7e5627043b7407037fc2a630fec45c360d Mon Sep 17 00:00:00 2001 From: Erik Gomez Date: Tue, 12 May 2026 14:26:09 -0500 Subject: [PATCH 1/2] add a sitecustomize --- build_python_framework_pkgs.zsh | 10 +++++++++ managed_python_sitecustomize.py | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 managed_python_sitecustomize.py diff --git a/build_python_framework_pkgs.zsh b/build_python_framework_pkgs.zsh index 87dcbe1..39146de 100755 --- a/build_python_framework_pkgs.zsh +++ b/build_python_framework_pkgs.zsh @@ -139,6 +139,15 @@ build_framework() { "$TOOLSDIR/$TYPE/payload${FRAMEWORKDIR}/Python3.framework" } +install_sitecustomize() { + # Drop a sitecustomize.py that points OpenSSL at certifi's CA bundle via + # SSL_CERT_FILE at interpreter startup. Works around macadmins/python#38: + # python.org's framework has the OpenSSL CA path compiled in to + # /Library/Frameworks/... which doesn't match our relocated install. + local site_packages="$TOOLSDIR/$TYPE/payload${FRAMEWORKDIR}/Python3.framework/Versions/${PYTHON_BIN_VERSION}/lib/python${PYTHON_BIN_VERSION}/site-packages" + /bin/cp "${TOOLSDIR}/managed_python_sitecustomize.py" "$site_packages/sitecustomize.py" +} + codesign_framework() { local identity="${APPLICATION_ID:--}" # `-` means ad-hoc local framework_root="$TOOLSDIR/$TYPE/payload${FRAMEWORKDIR}/Python3.framework" @@ -274,6 +283,7 @@ download_tool munki-pkg "$MP_SHA" \ "https://github.com/munki/munki-pkg/archive/${MP_SHA}.zip" \ "$MP_ZIP" "$MP_BINDIR" build_framework +install_sitecustomize codesign_framework build_pkg notarize_and_staple diff --git a/managed_python_sitecustomize.py b/managed_python_sitecustomize.py new file mode 100644 index 0000000..18385c3 --- /dev/null +++ b/managed_python_sitecustomize.py @@ -0,0 +1,39 @@ +""" +Site-customization for the macadmins Python framework. + +Why this file exists: + The python.org Python.framework is built with OpenSSL's default CA-bundle + path hardcoded to /Library/Frameworks/Python.framework/Versions//etc/ + openssl/cert.pem. Our framework installs under /Library/ManagedFrameworks/ + Python/Python3.framework/..., so that hardcoded path doesn't exist on + target machines. Stdlib SSL (urllib.request, http.client.HTTPSConnection, + ssl.SSLContext with default verify paths, etc.) then fails to find a CA + bundle and certificate validation errors out. + + A regular python.org install ships /Applications/Python 3.X/Install + Certificates.command that fixes this by symlinking the expected path to + certifi's bundled cacert.pem. We can't do the equivalent because the + expected path is outside our framework — touching it would conflict with + a python.org install if the user has one. + +What it does: + Sets SSL_CERT_FILE to certifi's bundled cert path during interpreter + startup. OpenSSL reads SSL_CERT_FILE ahead of its compiled-in path, so + stdlib SSL operations get a working CA bundle. + + Only sets the variable when it isn't already set, so an explicit user + override (e.g. `export SSL_CERT_FILE=/path/to/ca.pem`) still wins. + +References: + macadmins/python#38 + gregneagle/relocatable-python#13 +""" +import os + +if "SSL_CERT_FILE" not in os.environ: + try: + import certifi + except ImportError: + pass + else: + os.environ["SSL_CERT_FILE"] = certifi.where() From 3ab1b19d910f6481c65d00e760da1076eecbacd9 Mon Sep 17 00:00:00 2001 From: Erik Gomez Date: Tue, 12 May 2026 14:35:01 -0500 Subject: [PATCH 2/2] also look for path --- managed_python_sitecustomize.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/managed_python_sitecustomize.py b/managed_python_sitecustomize.py index 18385c3..74f30b5 100644 --- a/managed_python_sitecustomize.py +++ b/managed_python_sitecustomize.py @@ -21,16 +21,25 @@ startup. OpenSSL reads SSL_CERT_FILE ahead of its compiled-in path, so stdlib SSL operations get a working CA bundle. - Only sets the variable when it isn't already set, so an explicit user - override (e.g. `export SSL_CERT_FILE=/path/to/ca.pem`) still wins. + Falls back to certifi only when SSL_CERT_FILE is unset OR points at a + path that doesn't exist on disk. A valid user override (e.g. a corporate + CA bundle at `export SSL_CERT_FILE=/opt/corp/ca.pem`) is preserved; + a stale or typo'd path gets corrected to certifi. References: macadmins/python#38 gregneagle/relocatable-python#13 """ import os +import os.path -if "SSL_CERT_FILE" not in os.environ: + +def _ssl_cert_file_is_valid(): + path = os.environ.get("SSL_CERT_FILE") + return bool(path) and os.path.isfile(path) + + +if not _ssl_cert_file_is_valid(): try: import certifi except ImportError: