Skip to content

Commit 91eff8c

Browse files
Fix macOS framework layout so the inner bundle can be signed (#39)
The signing job failed on every python-macos-dart archive with: Python.framework: unsealed contents present in the root directory of an embedded framework macOS frameworks are VERSIONED bundles: everything at the framework root must be a symlink into Versions/Current, and only `Versions` itself may be a real directory. package-macos-for-dart.sh wrote the overlaid `Modules` and the public `Headers` as real directories at the root. That was invisible while only the outer xcframework was signed -- the outer seal does not care -- and became fatal the moment the inner framework was signed in its own right. They now go into Versions/Current with symlinks at the root, which is both what codesign requires and what CPython's own macOS framework already does for Headers and Resources. Consumers resolve Headers/ and Modules/ through the symlinks exactly as before. Also fixes the verifier, which was wrong in a way the same run exposed: it probed for `_CodeSignature` or `Versions/A/_CodeSignature`, but a versioned bundle's version directory is not always "A" -- CPython's macOS framework uses Versions/3.14 -- so a correctly signed macOS framework was reported as unsigned. It now asks `codesign -dv`, which is layout-agnostic and is the actual question. Verified with the real identity against the released 20260729 macOS archive: inner and outer both sign and verify, dart_bridge v1.7.1 (Versions/A) still verifies, and stripping the inner signature still fails the run.
1 parent 3c168a5 commit 91eff8c

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

darwin/package-macos-for-dart.sh

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,34 @@ mkdir -p $stdlib_dir
3434

3535
# copy Python.xcframework
3636
rsync -av --exclude-from=$script_dir/python-darwin-framework.exclude $python_apple_support_root/support/$python_version_short/macOS/Python.xcframework $frameworks_dir
37-
cp -r $script_dir/Modules $frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework
38-
mkdir -p $frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework/Headers
39-
cp -r $python_apple_support_root/support/$python_version_short/macOS/Python.xcframework/macos-arm64_x86_64/Python.framework/Versions/$python_version_short/include/python$python_version_short/* $frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework/Headers
37+
# Overlay the module map and public headers.
38+
#
39+
# macOS frameworks are VERSIONED bundles: everything at the framework root must be
40+
# a symlink into Versions/Current, and only `Versions` itself is a real directory.
41+
# These used to be written as real directories at the root, which codesign rejects
42+
# outright once the framework is signed in its own right:
43+
#
44+
# Python.framework: unsealed contents present in the root directory of an
45+
# embedded framework
46+
#
47+
# That went unnoticed while only the outer xcframework was signed. Write them into
48+
# Versions/Current and symlink from the root, which is both what codesign requires
49+
# and what CPython's own macOS framework does for Headers and Resources.
50+
macos_fw=$frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework
51+
[ -d "$macos_fw/Versions/Current" ] || {
52+
echo "expected a versioned macOS framework at $macos_fw"; exit 1; }
53+
54+
cp -r $script_dir/Modules "$macos_fw/Versions/Current/"
55+
mkdir -p "$macos_fw/Versions/Current/Headers"
56+
cp -r $python_apple_support_root/support/$python_version_short/macOS/Python.xcframework/macos-arm64_x86_64/Python.framework/Versions/$python_version_short/include/python$python_version_short/* "$macos_fw/Versions/Current/Headers"
4057
# The built-in modulemap (if the source framework shipped one) is replaced by the
4158
# overlaid darwin/Modules/module.modulemap above; -f tolerates builds without one.
42-
rm -f $frameworks_dir/Python.xcframework/macos-arm64_x86_64/Python.framework/Headers/module.modulemap
59+
rm -f "$macos_fw/Versions/Current/Headers/module.modulemap"
60+
61+
for _d in Headers Modules; do
62+
rm -rf "$macos_fw/$_d"
63+
ln -sfn "Versions/Current/$_d" "$macos_fw/$_d"
64+
done
4365

4466
# Last mutation of the bundle: stable, provider-owned identifier for the Python
4567
# runtime, replacing CPython's shared `org.python.python`. The macOS framework is

darwin/xcframework_signing.sh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,12 @@ xcf_verify_one() {
285285
local fw count=0
286286
while IFS= read -r fw; do
287287
[ -n "$fw" ] || continue
288-
if [ ! -d "$fw/_CodeSignature" ] && [ ! -d "$fw/Versions/A/_CodeSignature" ]; then
288+
# `codesign -dv` rather than probing for a _CodeSignature directory: a
289+
# versioned bundle keeps it at Versions/<name>/_CodeSignature, and the
290+
# version directory is not always "A" (CPython's macOS framework uses the
291+
# Python version, e.g. Versions/3.14). codesign exits non-zero with
292+
# "code object is not signed at all", which is the question being asked.
293+
if ! codesign -dv "$fw" >/dev/null 2>&1; then
289294
xcf_err "$fw: inner framework is unsigned"
290295
return 1
291296
fi

0 commit comments

Comments
 (0)