Skip to content

Commit 587a8f8

Browse files
[3.13] 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 728432c) Co-authored-by: Russell Keith-Magee <[email protected]>
1 parent 82b8137 commit 587a8f8

File tree

9 files changed

+207
-2
lines changed

9 files changed

+207
-2
lines changed

Doc/library/urllib.parse.rst

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,19 @@ to an absolute URL given a "base URL."
2222

2323
The module has been designed to match the internet RFC on Relative Uniform
2424
Resource Locators. It supports the following URL schemes: ``file``, ``ftp``,
25-
``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``mailto``, ``mms``,
25+
``gopher``, ``hdl``, ``http``, ``https``, ``imap``, ``itms-services``, ``mailto``, ``mms``,
2626
``news``, ``nntp``, ``prospero``, ``rsync``, ``rtsp``, ``rtsps``, ``rtspu``,
2727
``sftp``, ``shttp``, ``sip``, ``sips``, ``snews``, ``svn``, ``svn+ssh``,
2828
``telnet``, ``wais``, ``ws``, ``wss``.
2929

30+
.. impl-detail::
31+
32+
The inclusion of the ``itms-services`` URL scheme can prevent an app from
33+
passing Apple's App Store review process for the macOS and iOS App Stores.
34+
Handling for the ``itms-services`` scheme is always removed on iOS; on
35+
macOS, it *may* be removed if CPython has been built with the
36+
:option:`--with-app-store-compliance` option.
37+
3038
The :mod:`urllib.parse` module defines functions that fall into two broad
3139
categories: URL parsing and URL quoting. These are covered in detail in
3240
the following sections.

Doc/using/configure.rst

+11
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,17 @@ See :source:`Mac/README.rst`.
945945
Specify the name for the python framework on macOS only valid when
946946
:option:`--enable-framework` is set (default: ``Python``).
947947

948+
.. option:: --with-app-store-compliance
949+
.. option:: --with-app-store-compliance=PATCH-FILE
950+
951+
The Python standard library contains strings that are known to trigger
952+
automated inspection tool errors when submitted for distribution by
953+
the macOS and iOS App Stores. If enabled, this option will apply the list of
954+
patches that are known to correct app store compliance. A custom patch
955+
file can also be specified. This option is disabled by default.
956+
957+
.. versionadded:: 3.13
958+
948959
iOS Options
949960
-----------
950961

Doc/using/ios.rst

+18
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,21 @@ modules in your app, some additional steps will be required:
323323

324324
* If you're using a separate folder for third-party packages, ensure that folder
325325
is included as part of the ``PYTHONPATH`` configuration in step 10.
326+
327+
App Store Compliance
328+
====================
329+
330+
The only mechanism for distributing apps to third-party iOS devices is to
331+
submit the app to the iOS App Store; apps submitted for distribution must pass
332+
Apple's app review process. This process includes a set of automated validation
333+
rules that inspect the submitted application bundle for problematic code.
334+
335+
The Python standard library contains some code that is known to violate these
336+
automated rules. While these violations appear to be false positives, Apple's
337+
review rules cannot be challenged; so, it is necessary to modify the Python
338+
standard library for an app to pass App Store review.
339+
340+
The Python source tree contains
341+
:source:`a patch file <Mac/Resources/app-store-compliance.patch>` that will remove
342+
all code that is known to cause issues with the App Store review process. This
343+
patch is applied automatically when building for iOS.

Doc/using/mac.rst

+22
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,28 @@ distributable application:
188188
* `PyInstaller <https://pyinstaller.org/>`__: A cross-platform packaging tool that creates
189189
a single file or folder as a distributable artifact.
190190

191+
App Store Compliance
192+
--------------------
193+
194+
Apps submitted for distribution through the macOS App Store must pass Apple's
195+
app review process. This process includes a set of automated validation rules
196+
that inspect the submitted application bundle for problematic code.
197+
198+
The Python standard library contains some code that is known to violate these
199+
automated rules. While these violations appear to be false positives, Apple's
200+
review rules cannot be challenged. Therefore, it is necessary to modify the
201+
Python standard library for an app to pass App Store review.
202+
203+
The Python source tree contains
204+
:source:`a patch file <Mac/Resources/app-store-compliance.patch>` that will remove
205+
all code that is known to cause issues with the App Store review process. This
206+
patch is applied automatically when CPython is configured with the
207+
:option:`--with-app-store-compliance` option.
208+
209+
This patch is not normally required to use CPython on a Mac; nor is it required
210+
if you are distributing an app *outside* the macOS App Store. It is *only*
211+
required if you are using the macOS App Store as a distribution channel.
212+
191213
Other Resources
192214
===============
193215

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
diff --git a/Lib/test/test_urlparse.py b/Lib/test/test_urlparse.py
2+
index d6c83a75c1c..19ed4e01091 100644
3+
--- a/Lib/test/test_urlparse.py
4+
+++ b/Lib/test/test_urlparse.py
5+
@@ -237,11 +237,6 @@ def test_roundtrips(self):
6+
'','',''),
7+
('git+ssh', '[email protected]','/user/project.git',
8+
'', '')),
9+
- ('itms-services://?action=download-manifest&url=https://example.com/app',
10+
- ('itms-services', '', '', '',
11+
- 'action=download-manifest&url=https://example.com/app', ''),
12+
- ('itms-services', '', '',
13+
- 'action=download-manifest&url=https://example.com/app', '')),
14+
('+scheme:path/to/file',
15+
('', '', '+scheme:path/to/file', '', '', ''),
16+
('', '', '+scheme:path/to/file', '', '')),
17+
diff --git a/Lib/urllib/parse.py b/Lib/urllib/parse.py
18+
index 8f724f907d4..148caf742c9 100644
19+
--- a/Lib/urllib/parse.py
20+
+++ b/Lib/urllib/parse.py
21+
@@ -59,7 +59,7 @@
22+
'imap', 'wais', 'file', 'mms', 'https', 'shttp',
23+
'snews', 'prospero', 'rtsp', 'rtsps', 'rtspu', 'rsync',
24+
'svn', 'svn+ssh', 'sftp', 'nfs', 'git', 'git+ssh',
25+
- 'ws', 'wss', 'itms-services']
26+
+ 'ws', 'wss']
27+
28+
uses_params = ['', 'ftp', 'hdl', 'prospero', 'http', 'imap',
29+
'https', 'shttp', 'rtsp', 'rtsps', 'rtspu', 'sip',

Makefile.pre.in

+22-1
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ EXPORTSFROM= @EXPORTSFROM@
179179
EXE= @EXEEXT@
180180
BUILDEXE= @BUILDEXEEXT@
181181

182+
# Name of the patch file to apply for app store compliance
183+
APP_STORE_COMPLIANCE_PATCH=@APP_STORE_COMPLIANCE_PATCH@
184+
182185
# Short name and location for Mac OS X Python framework
183186
UNIVERSALSDK=@UNIVERSALSDK@
184187
PYTHONFRAMEWORK= @PYTHONFRAMEWORK@
@@ -692,7 +695,7 @@ list-targets:
692695
@grep -E '^[A-Za-z][-A-Za-z0-9]+:' Makefile | awk -F : '{print $$1}'
693696

694697
.PHONY: build_all
695-
build_all: check-clean-src $(BUILDPYTHON) platform sharedmods \
698+
build_all: check-clean-src check-app-store-compliance $(BUILDPYTHON) platform sharedmods \
696699
gdbhooks Programs/_testembed scripts checksharedmods rundsymutil
697700

698701
.PHONY: build_wasm
@@ -715,6 +718,16 @@ check-clean-src:
715718
exit 1; \
716719
fi
717720

721+
# Check that the app store compliance patch can be applied (if configured).
722+
# This is checked as a dry-run against the original library sources;
723+
# the patch will be actually applied during the install phase.
724+
.PHONY: check-app-store-compliance
725+
check-app-store-compliance:
726+
@if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \
727+
patch --dry-run --quiet --force --strip 1 --directory "$(abs_srcdir)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)"; \
728+
echo "App store compliance patch can be applied."; \
729+
fi
730+
718731
# Profile generation build must start from a clean tree.
719732
profile-clean-stamp:
720733
$(MAKE) clean
@@ -2568,6 +2581,14 @@ libinstall: all $(srcdir)/Modules/xxmodule.c
25682581
$(INSTALL_DATA) `cat pybuilddir.txt`/_sysconfigdata_$(ABIFLAGS)_$(MACHDEP)_$(MULTIARCH).py \
25692582
$(DESTDIR)$(LIBDEST); \
25702583
$(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
2584+
@ # If app store compliance has been configured, apply the patch to the
2585+
@ # installed library code. The patch has been previously validated against
2586+
@ # the original source tree, so we can ignore any errors that are raised
2587+
@ # due to files that are missing because of --disable-test-modules etc.
2588+
@if [ "$(APP_STORE_COMPLIANCE_PATCH)" != "" ]; then \
2589+
echo "Applying app store compliance patch"; \
2590+
patch --force --reject-file "$(abs_builddir)/app-store-compliance.rej" --strip 2 --directory "$(DESTDIR)$(LIBDEST)" --input "$(abs_srcdir)/$(APP_STORE_COMPLIANCE_PATCH)" || true ; \
2591+
fi
25712592
@ # Build PYC files for the 3 optimization levels (0, 1, 2)
25722593
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
25732594
$(PYTHON_FOR_BUILD) -Wi $(DESTDIR)$(LIBDEST)/compileall.py \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Added a :option:`--with-app-store-compliance` option to patch out known
2+
issues with macOS/iOS App Store review processes.

configure

+53
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

configure.ac

+41
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,47 @@ AC_SUBST([INSTALLTARGETS])
695695
AC_DEFINE_UNQUOTED([_PYTHONFRAMEWORK], ["${PYTHONFRAMEWORK}"],
696696
[framework name])
697697

698+
dnl quadrigraphs "@<:@" and "@:>@" produce "[" and "]" in the output
699+
AC_MSG_CHECKING([for --with-app-store-compliance])
700+
AC_ARG_WITH(
701+
[app_store_compliance],
702+
[AS_HELP_STRING(
703+
[--with-app-store-compliance=@<:@PATCH-FILE@:>@],
704+
[Enable any patches required for compiliance with app stores.
705+
Optional PATCH-FILE specifies the custom patch to apply.]
706+
)],[
707+
case "$withval" in
708+
yes)
709+
case $ac_sys_system in
710+
Darwin|iOS)
711+
# iOS is able to share the macOS patch
712+
APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
713+
;;
714+
*) AC_MSG_ERROR([no default app store compliance patch available for $ac_sys_system]) ;;
715+
esac
716+
AC_MSG_RESULT([applying default app store compliance patch])
717+
;;
718+
*)
719+
APP_STORE_COMPLIANCE_PATCH="${withval}"
720+
AC_MSG_RESULT([applying custom app store compliance patch])
721+
;;
722+
esac
723+
],[
724+
case $ac_sys_system in
725+
iOS)
726+
# Always apply the compliance patch on iOS; we can use the macOS patch
727+
APP_STORE_COMPLIANCE_PATCH="Mac/Resources/app-store-compliance.patch"
728+
AC_MSG_RESULT([applying default app store compliance patch])
729+
;;
730+
*)
731+
# No default app compliance patching on any other platform
732+
APP_STORE_COMPLIANCE_PATCH=
733+
AC_MSG_RESULT([not patching for app store compliance])
734+
;;
735+
esac
736+
])
737+
AC_SUBST([APP_STORE_COMPLIANCE_PATCH])
738+
698739
AC_SUBST([_PYTHON_HOST_PLATFORM])
699740
if test "$cross_compiling" = yes; then
700741
case "$host" in

0 commit comments

Comments
 (0)