From 23b1fd37d3ddc6d85b3f29573539dc5fd3b7e758 Mon Sep 17 00:00:00 2001 From: "Miss Islington (bot)" <31488909+miss-islington@users.noreply.github.com> Date: Mon, 22 Jul 2024 02:13:34 +0200 Subject: [PATCH] [3.10] gh-120522: Apply App Store compliance patch during installation (GH-121947) (#122105) gh-120522: Apply App Store compliance patch during installation (GH-121947) Adds a --with-app-store-compliance configuration option that patches out code known to be an issue with App Store review processes. This option is applied automatically on iOS, and optionally on macOS. (cherry picked from commit 728432c8043edc07bb8a24b180a70778fcd35878) Co-authored-by: Russell Keith-Magee --- Doc/library/urllib.parse.rst | 8 +++ Doc/using/configure.rst | 69 +++++++++++++++++++ Doc/using/mac.rst | 22 ++++++ Mac/Resources/app-store-compliance.patch | 0 Makefile.pre.in | 26 ++++++- ...-07-18-07-53-07.gh-issue-120522.dg3o5A.rst | 2 + configure | 60 ++++++++++++++-- configure.ac | 41 +++++++++++ 8 files changed, 222 insertions(+), 6 deletions(-) create mode 100644 Mac/Resources/app-store-compliance.patch create mode 100644 Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst diff --git a/Doc/library/urllib.parse.rst b/Doc/library/urllib.parse.rst index 1e85602951c2b5..8f5af980dee282 100644 --- a/Doc/library/urllib.parse.rst +++ b/Doc/library/urllib.parse.rst @@ -27,6 +27,14 @@ Resource Locators. It supports the following URL schemes: ``file``, ``ftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``, ``telnet``, ``wais``, ``ws``, ``wss``. +.. impl-detail:: + + The inclusion of the ``itms-services`` URL scheme can prevent an app from + passing Apple's App Store review process for the macOS and iOS App Stores. + Handling for the ``itms-services`` scheme is always removed on iOS; on + macOS, it *may* be removed if CPython has been built with the + :option:`--with-app-store-compliance` option. + The :mod:`urllib.parse` module defines functions that fall into two broad categories: URL parsing and URL quoting. These are covered in detail in the following sections. diff --git a/Doc/using/configure.rst b/Doc/using/configure.rst index ab33e0a06f5145..6fe63e9ce2dcd1 100644 --- a/Doc/using/configure.rst +++ b/Doc/using/configure.rst @@ -506,6 +506,75 @@ See ``Mac/README.rst``. Specify the name for the python framework on macOS only valid when :option:`--enable-framework` is set (default: ``Python``). +.. option:: --with-app-store-compliance +.. option:: --with-app-store-compliance=PATCH-FILE + + The Python standard library contains strings that are known to trigger + automated inspection tool errors when submitted for distribution by + the macOS and iOS App Stores. If enabled, this option will apply the list of + patches that are known to correct app store compliance. A custom patch + file can also be specified. This option is disabled by default. + + .. versionadded:: 3.13 + +iOS Options +----------- + +See :source:`iOS/README.rst`. + +.. option:: --enable-framework=INSTALLDIR + + Create a Python.framework. Unlike macOS, the *INSTALLDIR* argument + specifying the installation path is mandatory. + +.. option:: --with-framework-name=FRAMEWORK + + Specify the name for the framework (default: ``Python``). + + +Cross Compiling Options +----------------------- + +Cross compiling, also known as cross building, can be used to build Python +for another CPU architecture or platform. Cross compiling requires a Python +interpreter for the build platform. The version of the build Python must match +the version of the cross compiled host Python. + +.. option:: --build=BUILD + + configure for building on BUILD, usually guessed by :program:`config.guess`. + +.. option:: --host=HOST + + cross-compile to build programs to run on HOST (target platform) + +.. option:: --with-build-python=path/to/python + + path to build ``python`` binary for cross compiling + + .. versionadded:: 3.11 + +.. option:: CONFIG_SITE=file + + An environment variable that points to a file with configure overrides. + + Example *config.site* file: + + .. code-block:: ini + + # config.site-aarch64 + ac_cv_buggy_getaddrinfo=no + ac_cv_file__dev_ptmx=yes + ac_cv_file__dev_ptc=no + + +Cross compiling example:: + + CONFIG_SITE=config.site-aarch64 ../configure \ + --build=x86_64-pc-linux-gnu \ + --host=aarch64-unknown-linux-gnu \ + --with-build-python=../x86_64/python + Python Build System =================== diff --git a/Doc/using/mac.rst b/Doc/using/mac.rst index 9ae0270eaee7ab..2bb14d88dc9b42 100644 --- a/Doc/using/mac.rst +++ b/Doc/using/mac.rst @@ -164,6 +164,28 @@ The standard tool for deploying standalone Python applications on the Mac is at https://pypi.org/project/py2app/. +App Store Compliance +-------------------- + +Apps submitted for distribution through the macOS App Store must pass Apple's +app review process. This process includes a set of automated validation rules +that inspect the submitted application bundle for problematic code. + +The Python standard library contains some code that is known to violate these +automated rules. While these violations appear to be false positives, Apple's +review rules cannot be challenged. Therefore, it is necessary to modify the +Python standard library for an app to pass App Store review. + +The Python source tree contains +:source:`a patch file ` that will remove +all code that is known to cause issues with the App Store review process. This +patch is applied automatically when CPython is configured with the +:option:`--with-app-store-compliance` option. + +This patch is not normally required to use CPython on a Mac; nor is it required +if you are distributing an app *outside* the macOS App Store. It is *only* +required if you are using the macOS App Store as a distribution channel. + Other Resources =============== diff --git a/Mac/Resources/app-store-compliance.patch b/Mac/Resources/app-store-compliance.patch new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/Makefile.pre.in b/Makefile.pre.in index 506778da174b91..6a84a1b0c50ce3 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -170,6 +170,9 @@ EXPORTSFROM= @EXPORTSFROM@ EXE= @EXEEXT@ BUILDEXE= @BUILDEXEEXT@ +# Name of the patch file to apply for app store compliance +APP_STORE_COMPLIANCE_PATCH=@APP_STORE_COMPLIANCE_PATCH@ + # Short name and location for Mac OS X Python framework UNIVERSALSDK=@UNIVERSALSDK@ PYTHONFRAMEWORK= @PYTHONFRAMEWORK@ @@ -481,7 +484,7 @@ DTRACE_DEPS = \ # Default target all: @DEF_MAKE_ALL_RULE@ -build_all: check-clean-src $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \ +build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) oldsharedmods sharedmods gdbhooks \ Programs/_testembed python-config # Check that the source is clean when building out of source. @@ -493,6 +496,16 @@ check-clean-src: exit 1; \ fi +# Check that the app store compliance patch can be applied (if configured). +# This is checked as a dry-run against the original library sources; +# the patch will be actually applied during the install phase. +.PHONY: check-app-store-compliance +check-app-store-compliance: + @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ + patch --dry-run --quiet --force --strip 1 --directory "$(abs_srcdir)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)"; \ + echo "App store compliance patch can be applied."; \ + fi + # Profile generation build must start from a clean tree. profile-clean-stamp: $(MAKE) clean @@ -1677,7 +1690,16 @@ libinstall: build_all $(srcdir)/Modules/xxmodule.c $(INSTALL_DATA) $(srcdir)/Modules/xxmodule.c \ $(DESTDIR)$(LIBDEST)/distutils/tests ; \ fi - -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ + @ # If app store compliance has been configured, apply the patch to the + @ # installed library code. The patch has been previously validated against + @ # the original source tree, so we can ignore any errors that are raised + @ # due to files that are missing because of --disable-test-modules etc. + @if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \ + echo "Applying app store compliance patch"; \ + patch --force --reject-file "$(abs_builddir)/app-store-compliance.rej" --strip 2 --directory "$(DESTDIR)$(LIBDEST)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)" || true ; \ + fi + @ # Build PYC files for the 3 optimization levels (0, 1, 2) + -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \ $(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \ -j0 -d $(LIBDEST) -f \ -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \ diff --git a/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst b/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst new file mode 100644 index 00000000000000..e90c625a886b65 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2024-07-18-07-53-07.gh-issue-120522.dg3o5A.rst @@ -0,0 +1,2 @@ +Added a :option:`--with-app-store-compliance` option to patch out known +issues with macOS/iOS App Store review processes. diff --git a/configure b/configure index e5fe957f9dd990..75f80db10815df 100755 --- a/configure +++ b/configure @@ -742,6 +742,7 @@ IPHONEOS_DEPLOYMENT_TARGET EXPORT_MACOSX_DEPLOYMENT_TARGET CONFIGURE_MACOSX_DEPLOYMENT_TARGET _PYTHON_HOST_PLATFORM +APP_STORE_COMPLIANCE_PATCH INSTALLTARGETS FRAMEWORKINSTALLAPPSPREFIX FRAMEWORKUNIXTOOLSPREFIX @@ -825,6 +826,7 @@ enable_universalsdk with_universal_archs with_framework_name enable_framework +with_app_store_compliance with_cxx_main with_suffix enable_shared @@ -1536,6 +1538,10 @@ Optional Packages: specify the name for the python framework on macOS only valid when --enable-framework is set. see Mac/README.rst (default is 'Python') + --with-app-store-compliance=[PATCH-FILE] + Enable any patches required for compiliance with app + stores. Optional PATCH-FILE specifies the custom + patch to apply. --with-cxx-main[=COMPILER] compile main() and link Python executable with C++ compiler specified in COMPILER (default is $CXX) @@ -3485,6 +3491,52 @@ cat >>confdefs.h <<_ACEOF _ACEOF +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-app-store-compliance" >&5 +$as_echo_n "checking for --with-app-store-compliance... " >&6; } + +# Check whether --with-app_store_compliance was given. +if test "${with_app_store_compliance+set}" = set; then : + withval=$with_app_store_compliance; + case "$withval" in + yes) + case $ac_sys_system in + Darwin|iOS) + # iOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) as_fn_error $? "no default app store compliance patch available for $ac_sys_system" "$LINENO" 5 ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 +$as_echo "applying default app store compliance patch" >&6; } + ;; + *) + APP_STORE_COMPLIANCE_PATCH="${withval}" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying custom app store compliance patch" >&5 +$as_echo "applying custom app store compliance patch" >&6; } + ;; + esac + +else + + case $ac_sys_system in + iOS) + # Always apply the compliance patch on iOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: applying default app store compliance patch" >&5 +$as_echo "applying default app store compliance patch" >&6; } + ;; + *) + # No default app compliance patching on any other platform + APP_STORE_COMPLIANCE_PATCH= + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not patching for app store compliance" >&5 +$as_echo "not patching for app store compliance" >&6; } + ;; + esac + +fi + + + # Set name for machine-dependent library files @@ -3580,12 +3632,12 @@ if test "$cross_compiling" = yes; then _host_device=${_host_device:=os} # IPHONEOS_DEPLOYMENT_TARGET is the minimum supported iOS version - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking iOS deployment target" >&5 -printf %s "checking iOS deployment target... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking iOS deployment target" >&5 +$as_echo_n "checking iOS deployment target... " >&6; } IPHONEOS_DEPLOYMENT_TARGET=${_host_os:3} IPHONEOS_DEPLOYMENT_TARGET=${IPHONEOS_DEPLOYMENT_TARGET:=13.0} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $IPHONEOS_DEPLOYMENT_TARGET" >&5 -printf "%s\n" "$IPHONEOS_DEPLOYMENT_TARGET" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $IPHONEOS_DEPLOYMENT_TARGET" >&5 +$as_echo "$IPHONEOS_DEPLOYMENT_TARGET" >&6; } case "$host_cpu" in aarch64) diff --git a/configure.ac b/configure.ac index 563ec995401364..9595707b18b95d 100644 --- a/configure.ac +++ b/configure.ac @@ -541,6 +541,47 @@ AC_SUBST([INSTALLTARGETS]) AC_DEFINE_UNQUOTED(_PYTHONFRAMEWORK, "${PYTHONFRAMEWORK}", [framework name]) +dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output +AC_MSG_CHECKING([for --with-app-store-compliance]) +AC_ARG_WITH( + [app_store_compliance], + [AS_HELP_STRING( + [--with-app-store-compliance=@<:@PATCH-FILE@:>@], + [Enable any patches required for compiliance with app stores. + Optional PATCH-FILE specifies the custom patch to apply.] + )],[ + case "$withval" in + yes) + case $ac_sys_system in + Darwin|iOS) + # iOS is able to share the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + ;; + *) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;; + esac + AC_MSG_RESULT([applying default app store compliance patch]) + ;; + *) + APP_STORE_COMPLIANCE_PATCH="${withval}" + AC_MSG_RESULT([applying custom app store compliance patch]) + ;; + esac + ],[ + case $ac_sys_system in + iOS) + # Always apply the compliance patch on iOS; we can use the macOS patch + APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch" + AC_MSG_RESULT([applying default app store compliance patch]) + ;; + *) + # No default app compliance patching on any other platform + APP_STORE_COMPLIANCE_PATCH= + AC_MSG_RESULT([not patching for app store compliance]) + ;; + esac +]) +AC_SUBST([APP_STORE_COMPLIANCE_PATCH]) + AC_SUBST([_PYTHON_HOST_PLATFORM]) # Set name for machine-dependent library files