Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6fd375c
feat(socks5): vendor hev-socks5-tunnel 2.15.0 as submodule with xcfra…
Timo972 Jun 12, 2026
6350bb3
feat(socks5): add SOCKS5 URI parser and shared tunnel protocol with h…
Timo972 Jun 12, 2026
50799e3
feat(socks5): add tunnel manager and /mobilerun/socks5 command endpoints
Timo972 Jun 12, 2026
2c7abcc
feat(socks5): add WebDriverAgentTunnel packet tunnel extension target
Timo972 Jun 12, 2026
4a8c43b
feat(socks5): embed tunnel extension into Runner.app via scheme post-…
Timo972 Jun 12, 2026
f1aff01
feat(socks5): build the tunnel engine before runner builds in build.sh
Timo972 Jun 12, 2026
50165b5
docs(socks5): document the SOCKS5 tunnel endpoints, build and signing
Timo972 Jun 12, 2026
952189b
fix(socks5): silence NSJSONReadingOptions cast warning in stats query
Timo972 Jun 12, 2026
61c4d37
Merge remote-tracking branch 'origin/master' into timo/socks5-vpn
Timo972 Aug 26, 2026
16c5a8d
fix: run the socks5 routes on the control queue
Timo972 Aug 26, 2026
b30ad08
fix: confirm the VPN consent alert the way the broadcast alert is con…
Timo972 Aug 26, 2026
8a67924
fix: ship and build the tunnel inputs outside a recursive git checkout
Timo972 Aug 26, 2026
d69a263
fix: address the P1/P2 review of the socks5 tunnel
Timo972 Aug 26, 2026
d53fbc6
fix: address the second review round of the socks5 tunnel
Timo972 Aug 26, 2026
4cad102
fix: serialize concurrent builds of the shared hev source tree
Timo972 Aug 26, 2026
2b207c5
fix: fence a timed-out VPN save before the next lifecycle operation
Timo972 Aug 26, 2026
65e1825
fix: close six correctness gaps around the socks5 lifecycle and build
Timo972 Aug 26, 2026
c2f4258
fix: report preference deadline misses as timeouts
Timo972 Aug 26, 2026
504c169
feat: make the SOCKS5 tunnel extension an opt-in build
Timo972 Aug 26, 2026
bb985e3
fix: address the opt-in review round (stop/start race, DNS failover, …
Timo972 Aug 26, 2026
000db88
Merge branch 'master' into timo/dro-2802-integrate-vpn-into-mobilerun…
Timo972 Aug 26, 2026
6ef1fff
fix: harden SOCKS5 tunnel lifecycle
Timo972 Aug 27, 2026
93d0fbd
chore: update SOCKS5 copyrights
Timo972 Aug 27, 2026
670f34f
fix: handle stale VPN saves and credential limits
Timo972 Aug 27, 2026
86a9b90
fix: harden tunnel cleanup and scoped proxies
Timo972 Aug 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/publish.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ jobs:
runs-on: macos-15
steps:
- uses: actions/checkout@v7
with:
# The published npm package ships ThirdParty/hev-socks5-tunnel (see the
# 'files' list in package.json) so consumers can build the opt-in
# WebDriverAgentRunnerTunnel scheme; without the submodule the pack
# would silently omit the engine sources.
submodules: recursive
- name: Use Node.js
uses: actions/setup-node@v7
with:
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/wda-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ on:
- 'PrivateHeaders/**'
- 'Configurations/**'
- 'WebDriverAgent.xcodeproj/**'
- 'WebDriverAgentTunnel/**'
- 'ThirdParty/**'
- '.gitmodules'
- 'Scripts/build.sh'
- 'Scripts/build-hev-socks5-tunnel.sh'
- 'Scripts/embed-tunnel-extension.sh'
- 'Fastlane/**'
- 'Gemfile*'
- '.github/workflows/wda-tests.yml'
Expand Down Expand Up @@ -57,6 +62,8 @@ jobs:
{"name": "Generic_tvOS_Build_Min_Xcode", "vm_image": "${{ env.MIN_VM_IMAGE }}", "xcode_version": "${{ env.MIN_XCODE_VERSION }}", "action": "build", "target": "tv_runner", "sdk": "tv_sim", "dest": "tv_generic", "code_sign": "no"},
{"name": "iOS_Build_Max_Xcode", "vm_image": "${{ env.MAX_VM_IMAGE }}", "xcode_version": "${{ env.MAX_XCODE_VERSION }}", "action": "build", "target": "runner", "sdk": "sim", "iphone_model": "${{ env.MAX_IPHONE_DEVICE_NAME }}", "ipad_model": "${{ env.MAX_IPAD_DEVICE_NAME }}", "ios_version": "${{ env.MAX_PLATFORM_VERSION }}"},
{"name": "iOS_Build_Min_Xcode", "vm_image": "${{ env.MIN_VM_IMAGE }}", "xcode_version": "${{ env.MIN_XCODE_VERSION }}", "action": "build", "target": "runner", "sdk": "sim", "iphone_model": "${{ env.MIN_IPHONE_DEVICE_NAME }}", "ipad_model": "${{ env.MIN_IPAD_DEVICE_NAME }}", "ios_version": "${{ env.MIN_PLATFORM_VERSION }}"},
{"name": "iOS_Tunnel_Build_Max_Xcode", "vm_image": "${{ env.MAX_VM_IMAGE }}", "xcode_version": "${{ env.MAX_XCODE_VERSION }}", "action": "build", "target": "tunnel_runner", "sdk": "sim", "iphone_model": "${{ env.MAX_IPHONE_DEVICE_NAME }}", "ipad_model": "${{ env.MAX_IPAD_DEVICE_NAME }}", "ios_version": "${{ env.MAX_PLATFORM_VERSION }}"},
{"name": "iOS_Tunnel_Build_Min_Xcode", "vm_image": "${{ env.MIN_VM_IMAGE }}", "xcode_version": "${{ env.MIN_XCODE_VERSION }}", "action": "build", "target": "tunnel_runner", "sdk": "sim", "iphone_model": "${{ env.MIN_IPHONE_DEVICE_NAME }}", "ipad_model": "${{ env.MIN_IPAD_DEVICE_NAME }}", "ios_version": "${{ env.MIN_PLATFORM_VERSION }}"},
{"name": "tvOS_Build_Max_Xcode", "vm_image": "${{ env.MAX_VM_IMAGE }}", "xcode_version": "${{ env.MAX_XCODE_VERSION }}", "action": "build", "target": "tv_runner", "sdk": "tv_sim", "tv_model": "${{ env.MAX_TV_DEVICE_NAME }}", "tv_version": "${{ env.MAX_TV_PLATFORM_VERSION }}"},
{"name": "tvOS_Build_Min_Xcode", "vm_image": "${{ env.MIN_VM_IMAGE }}", "xcode_version": "${{ env.MIN_XCODE_VERSION }}", "action": "build", "target": "tv_runner", "sdk": "tv_sim", "dest": "tv", "tv_model": "${{ env.MIN_TV_DEVICE_NAME }}", "tv_version": "${{ env.MIN_TV_PLATFORM_VERSION }}"}
]
Expand Down Expand Up @@ -138,6 +145,11 @@ jobs:
config: ${{ fromJSON(needs.build_matrix.outputs.matrix) }}
steps:
- uses: actions/checkout@v7
with:
# Only the tunnel_runner matrix entries need ThirdParty/hev-socks5-tunnel
# (and its nested submodules); checking it out unconditionally keeps the
# shared build job simple.
submodules: recursive
- uses: ./.github/actions/xcode-setup
with:
xcode_version: ${{ matrix.config.xcode_version }}
Expand Down
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,8 @@ WebDriverAgentRunner-Runner.app/

# Ruby
Gemfile.lock

# Built from the hev-socks5-tunnel submodule (Scripts/build-hev-socks5-tunnel.sh)
ThirdParty/HevSocks5Tunnel.xcframework/
ThirdParty/.hev-socks5-tunnel.stamp
ThirdParty/.hev-socks5-tunnel.lock
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "ThirdParty/hev-socks5-tunnel"]
path = ThirdParty/hev-socks5-tunnel
url = https://github.com/heiher/hev-socks5-tunnel
1 change: 1 addition & 0 deletions Configurations/IOSSettings.xcconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
EXCLUDED_ARCHS = i386
WDA_PRODUCT_BUNDLE_IDENTIFIER = com.facebook.WebDriverAgentRunner

GCC_TREAT_WARNINGS_AS_ERRORS = YES
GCC_WARN_PEDANTIC = YES
Expand Down
1 change: 1 addition & 0 deletions Configurations/TVOSSettings.xcconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
EXCLUDED_ARCHS = i386
WDA_PRODUCT_BUNDLE_IDENTIFIER = com.facebook.WebDriverAgentRunner

GCC_TREAT_WARNINGS_AS_ERRORS = YES
GCC_WARN_PEDANTIC = YES
Expand Down
150 changes: 150 additions & 0 deletions Scripts/build-hev-socks5-tunnel.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/bash
# Copyright (c) 2026-present, Droidrun.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

# Build ThirdParty/HevSocks5Tunnel.xcframework from the hev-socks5-tunnel
# git submodule (ThirdParty/hev-socks5-tunnel, pinned by SHA).
#
# Trimmed from upstream build-apple.sh: only the slices WebDriverAgent needs
# (iphoneos-arm64, iphonesimulator-arm64+x86_64). The result is consumed by
# the WebDriverAgentTunnel packet-tunnel appex; see docs/socks5-tunnel.md.
#
# The output is gitignored. Skips the build when the xcframework already
# matches the current submodule SHA + script contents (stamp file).
#
# Usage: Scripts/build-hev-socks5-tunnel.sh [--force]

set -euo pipefail

ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
SUBMODULE_DIR="$ROOT_DIR/ThirdParty/hev-socks5-tunnel"
OUTPUT="$ROOT_DIR/ThirdParty/HevSocks5Tunnel.xcframework"
STAMP_FILE="$ROOT_DIR/ThirdParty/.hev-socks5-tunnel.stamp"
MIN_IOS="15.0"
JOBS="$(sysctl -n hw.ncpu)"

if [ ! -f "$SUBMODULE_DIR/src/hev-main.h" ]; then
echo "error: hev-socks5-tunnel submodule is missing or not initialized." >&2
echo " run: git submodule update --init --recursive" >&2
exit 1
fi

SCRIPT_SHA=$(shasum -a 256 "$0" | cut -d' ' -f1)

# build_static runs `make clean` in the shared submodule checkout, so two concurrent
# preparations (e.g. two WDA sessions starting at once) would delete each other's archives
# mid-compile or mid-libtool and produce nondeterministic failures or a corrupt xcframework.
# Serialize across processes, and hold the lock across the stamp check too: the loser then
# re-reads the stamp the winner just wrote and exits early instead of rebuilding.
LOCK_FILE="$ROOT_DIR/ThirdParty/.hev-socks5-tunnel.lock"
LOCK_WAIT_SECONDS="${HEV_SOCKS5_LOCK_WAIT_SECONDS:-900}"
BUILD_DIR=""

cleanup()
{
[ -n "$BUILD_DIR" ] && rm -rf "$BUILD_DIR"
return 0
}
trap cleanup EXIT

# Keep one inode permanently and let the kernel release its advisory lock when this process exits.
# Unlike stale-directory reclamation, a waiter can never rename or remove another builder's live
# lock between observing and acquiring it. Descriptor 9 remains open for the rest of the script.
exec 9>"$LOCK_FILE"
if ! /usr/bin/lockf -t "$LOCK_WAIT_SECONDS" 9; then
echo "error: timed out after ${LOCK_WAIT_SECONDS}s waiting for $LOCK_FILE" >&2
exit 1
fi

# The npm tarball ships the engine sources without Git metadata. `git -C` must not be allowed to
# walk up into the consuming application's repository, where every application commit would look
# like a new hev revision. Only trust Git when its top-level is the vendored engine itself;
# otherwise hash every shipped input while excluding the build products made by this script.
SUBMODULE_REALPATH="$(cd "$SUBMODULE_DIR" && pwd -P)"
SUBMODULE_GIT_TOPLEVEL="$(git -C "$SUBMODULE_DIR" rev-parse --show-toplevel 2>/dev/null || true)"
if [ -n "$SUBMODULE_GIT_TOPLEVEL" ] \
&& [ "$(cd "$SUBMODULE_GIT_TOPLEVEL" && pwd -P)" = "$SUBMODULE_REALPATH" ]; then
SUBMODULE_SHA=$(git -C "$SUBMODULE_DIR" rev-parse HEAD)
SOURCE_ID="$SUBMODULE_SHA"
else
SOURCE_ID=$(
cd "$SUBMODULE_DIR"
find . -name .git -prune -o -type f \
! -path './bin/*' ! -path './build/*' \
! -path './third-part/hev-task-system/bin/*' \
! -path './third-part/hev-task-system/build/*' \
! -path './third-part/lwip/bin/*' ! -path './third-part/lwip/build/*' \
! -path './third-part/yaml/bin/*' ! -path './third-part/yaml/build/*' \
-print0 \
| LC_ALL=C sort -z \
| xargs -0 shasum -a 256 \
| shasum -a 256 | cut -d' ' -f1
)
SUBMODULE_SHA="tree-$SOURCE_ID"
fi
STAMP="${SOURCE_ID}-${SCRIPT_SHA}-${MIN_IOS}"

if [ "${1:-}" != "--force" ] && [ -d "$OUTPUT" ] && [ -f "$STAMP_FILE" ] \
&& [ "$(cat "$STAMP_FILE")" = "$STAMP" ]; then
echo "HevSocks5Tunnel.xcframework is up to date ($SUBMODULE_SHA); skipping build"
exit 0
fi

BUILD_DIR=$(mktemp -d -t hev-socks5-tunnel-build)

# Other-platform sources (linux/windows/jni/...) compile to empty objects on
# iOS, producing harmless 'has no symbols' archive warnings; drop just those.
filter_no_symbols()
{
grep -v 'has no symbols' >&2 || true
}

# build_static <sdk> <arch> <version-min-flag>
build_static()
{
local SDK="$1" ARCH="$2" MIN_FLAG="$3"
echo "building libhev-socks5-tunnel for $SDK/$ARCH"
make -C "$SUBMODULE_DIR" clean >/dev/null
make -C "$SUBMODULE_DIR" -j"$JOBS" \
PP="xcrun --sdk $SDK --toolchain $SDK clang" \
CC="xcrun --sdk $SDK --toolchain $SDK clang" \
CFLAGS="-arch $ARCH $MIN_FLAG" \
LFLAGS="-arch $ARCH $MIN_FLAG -Wl,-Bsymbolic-functions" static \
>/dev/null 2> >(filter_no_symbols)
mkdir -p "$BUILD_DIR/$SDK-$ARCH"
# The 'static' target leaves one archive per component; merge them.
libtool -static -o "$BUILD_DIR/$SDK-$ARCH/libhev-socks5-tunnel.a" \
"$SUBMODULE_DIR/bin/libhev-socks5-tunnel.a" \
"$SUBMODULE_DIR/third-part/lwip/bin/liblwip.a" \
"$SUBMODULE_DIR/third-part/yaml/bin/libyaml.a" \
"$SUBMODULE_DIR/third-part/hev-task-system/bin/libhev-task-system.a" \
2> >(filter_no_symbols)
make -C "$SUBMODULE_DIR" clean >/dev/null
}

build_static iphoneos arm64 "-miphoneos-version-min=$MIN_IOS"
build_static iphonesimulator arm64 "-mios-simulator-version-min=$MIN_IOS"
build_static iphonesimulator x86_64 "-mios-simulator-version-min=$MIN_IOS"

mkdir -p "$BUILD_DIR/iphonesimulator-universal"
lipo -create \
"$BUILD_DIR/iphonesimulator-arm64/libhev-socks5-tunnel.a" \
"$BUILD_DIR/iphonesimulator-x86_64/libhev-socks5-tunnel.a" \
-output "$BUILD_DIR/iphonesimulator-universal/libhev-socks5-tunnel.a"

INCLUDE_DIR="$BUILD_DIR/include"
mkdir -p "$INCLUDE_DIR/HevSocks5Tunnel"
cp "$SUBMODULE_DIR/src/hev-main.h" "$INCLUDE_DIR/HevSocks5Tunnel/"
cp "$SUBMODULE_DIR/module.modulemap" "$INCLUDE_DIR/HevSocks5Tunnel/"

rm -rf "$OUTPUT"
xcodebuild -create-xcframework \
-library "$BUILD_DIR/iphoneos-arm64/libhev-socks5-tunnel.a" -headers "$INCLUDE_DIR" \
-library "$BUILD_DIR/iphonesimulator-universal/libhev-socks5-tunnel.a" -headers "$INCLUDE_DIR" \
-output "$OUTPUT"

echo "$STAMP" > "$STAMP_FILE"
echo "built $OUTPUT from hev-socks5-tunnel $SUBMODULE_SHA"
20 changes: 20 additions & 0 deletions Scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function define_xc_macros() {
case "$TARGET" in
"lib" ) XC_TARGET="WebDriverAgentLib";;
"runner" ) XC_TARGET="WebDriverAgentRunner";;
"tunnel_runner" ) XC_TARGET="WebDriverAgentRunnerTunnel";;
"tv_lib" ) XC_TARGET="WebDriverAgentLib_tvOS";;
"tv_runner" ) XC_TARGET="WebDriverAgentRunner_tvOS";;
"watch_lib" ) XC_TARGET="WebDriverAgentLib_watchOS";;
Expand Down Expand Up @@ -123,7 +124,26 @@ function fastlane_test() {
SDK="$XC_SDK" DEVICE="$FASTLANE_DEVICE" SCHEME="$1" bundle exec fastlane test
}

function prepare_socks5_engine() {
# Only the WebDriverAgentRunnerTunnel scheme builds the WebDriverAgentTunnel appex, which
# links HevSocks5Tunnel.xcframework built from the hev-socks5-tunnel submodule (no-op when
# the build stamp is current). Plain runner builds need neither the submodule nor the
# engine. See docs/socks5-tunnel.md.
if [[ "$TARGET" != "tunnel_runner" ]]; then
return
fi
local script_dir
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
if [ ! -f "$script_dir/../ThirdParty/hev-socks5-tunnel/src/hev-main.h" ]; then
echo "error: the hev-socks5-tunnel submodule is not initialized;" \
"run 'git submodule update --init --recursive' first"
exit 1
fi
"$script_dir/build-hev-socks5-tunnel.sh"
}

define_xc_macros
prepare_socks5_engine
case "$ACTION" in
"analyze" ) analyze ;;
"int_test_1" ) fastlane_test IntegrationTests_1 ;;
Expand Down
118 changes: 118 additions & 0 deletions Scripts/embed-tunnel-extension.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/bash
# Copyright (c) 2026-present, Droidrun.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

# Embed the WebDriverAgentTunnel NetworkExtension packet tunnel extension into
# the wrapping XCTRunner host app.
#
# Apple's USES_XCTRUNNER auto-generates a Runner.app around UI-testing
# .xctest bundles after all target build phases have run, so an appex
# cannot reach Runner.app/PlugIns through a regular embed build phase.
# The extension target is built into BUILT_PRODUCTS_DIR via a target
# dependency of WebDriverAgentRunner; this scheme post-action copies it
# into Runner.app/PlugIns, validates that its bundle id matches the host app
# (extensions must be prefixed by the host's CFBundleIdentifier, which
# Xcode suffixes with '.xctrunner') and re-signs inner-first.
#
# Mirrors Scripts/embed-broadcast-extension.sh; kept separate because the
# tunnel additionally needs the NetworkExtension entitlement repaired on
# the host app (see below and docs/socks5-tunnel.md).
#
# Limitations:
# - Touches XCTRunner internals; may need updates across Xcode versions.
# - iOS only; the extension is not built for tvOS.
# - Loading the tunnel on a device needs paid-team signing with the
# packet-tunnel-provider entitlement (WDA_TUNNEL_ENTITLEMENTS /
# WDA_RUNNER_ENTITLEMENTS build settings); see docs/socks5-tunnel.md.

set -euo pipefail

RUNNER_APP="${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}-Runner.app"
APPEX_NAME="WebDriverAgentTunnel.appex"
APPEX_SRC="${BUILT_PRODUCTS_DIR}/${APPEX_NAME}"
NE_ENTITLEMENT="com.apple.developer.networking.networkextension"

if [ ! -d "$RUNNER_APP" ]; then
echo "warning: ${PRODUCT_NAME}-Runner.app not found at $RUNNER_APP; skipping tunnel extension embed"
exit 0
fi

if [ ! -d "$APPEX_SRC" ]; then
echo "warning: $APPEX_NAME not found at $APPEX_SRC; skipping tunnel extension embed"
exit 0
fi

APPEX_DST="$RUNNER_APP/PlugIns/$APPEX_NAME"
rm -rf "$APPEX_DST"
mkdir -p "$RUNNER_APP/PlugIns"
cp -R "$APPEX_SRC" "$APPEX_DST"

# Extensions must be provisioned with their final bundle id. Rewriting it after Xcode signs the
# appex cannot update the embedded provisioning profile's application identifier, so fail the
# build instead of producing a bundle that installd will reject.
HOST_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$RUNNER_APP/Info.plist")
WANT_ID="${HOST_ID}.tunnel"
CURRENT_ID=$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$APPEX_DST/Info.plist")
if [ "$CURRENT_ID" != "$WANT_ID" ]; then
echo "error: $APPEX_NAME was built as '$CURRENT_ID', expected '$WANT_ID'." >&2
echo "error: set WDA_PRODUCT_BUNDLE_IDENTIFIER to the runner's base bundle id before building." >&2
exit 1
fi

# Re-codesign the copied appex first, then the app so its seal covers the new nested code. In a
# scheme post-action context Xcode's CODE_SIGN_* env vars are not exposed, so discover the
# existing signing identity from the already-signed bundle.
if [ -d "$RUNNER_APP/_CodeSignature" ]; then
# Capture the signature info once. Piping codesign straight into
# `awk ... exit` makes awk close the pipe early, killing codesign with
# SIGPIPE -- which `set -o pipefail` turns into a fatal error. That trips
# only when an Authority line exists, i.e. on every real-device build.
SIGN_INFO=$(codesign -dvv "$RUNNER_APP" 2>&1 || true)
EXISTING_IDENT="${EXPANDED_CODE_SIGN_IDENTITY:-}"
if [ -z "$EXISTING_IDENT" ]; then
EXISTING_IDENT=$(awk -F'=' '/^Authority/ {print $2; exit}' <<< "$SIGN_INFO")
fi
# Simulator builds are ad-hoc signed: there is no Authority line, but the
# bundle can still be re-signed ad-hoc with an identity of "-".
if [ -z "$EXISTING_IDENT" ] && grep -q '^Signature=adhoc' <<< "$SIGN_INFO"; then
EXISTING_IDENT="-"
fi
if [ -n "$EXISTING_IDENT" ]; then
APPEX_ENTITLEMENTS_PLIST=$(mktemp -t tunnel-appex-entitlements).plist
if ! codesign -d --entitlements - --xml "$APPEX_DST" > "$APPEX_ENTITLEMENTS_PLIST" 2>/dev/null; then
: > "$APPEX_ENTITLEMENTS_PLIST"
fi
codesign --force --sign "$EXISTING_IDENT" \
--preserve-metadata=identifier,entitlements "$APPEX_DST"

# Xcode is not documented to propagate the UI-test target's CODE_SIGN_ENTITLEMENTS onto
# the generated Runner.app. The host must hold the NetworkExtension entitlement for
# NETunnelProviderManager to accept the configuration, so when the appex carries it but
# the host does not, inject it into the host's entitlements while re-sealing.
RUNNER_ENTITLEMENTS_PLIST=$(mktemp -t tunnel-runner-entitlements).plist
if ! codesign -d --entitlements - --xml "$RUNNER_APP" > "$RUNNER_ENTITLEMENTS_PLIST" 2>/dev/null; then
: > "$RUNNER_ENTITLEMENTS_PLIST"
fi
APPEX_HAS_NE=$(/usr/libexec/PlistBuddy -c "Print :${NE_ENTITLEMENT}" "$APPEX_ENTITLEMENTS_PLIST" 2>/dev/null || true)
RUNNER_HAS_NE=$(/usr/libexec/PlistBuddy -c "Print :${NE_ENTITLEMENT}" "$RUNNER_ENTITLEMENTS_PLIST" 2>/dev/null || true)
if [ -n "$APPEX_HAS_NE" ] && [ -z "$RUNNER_HAS_NE" ] && [ -s "$RUNNER_ENTITLEMENTS_PLIST" ]; then
/usr/libexec/PlistBuddy -c "Add :${NE_ENTITLEMENT} array" "$RUNNER_ENTITLEMENTS_PLIST"
/usr/libexec/PlistBuddy -c "Add :${NE_ENTITLEMENT}:0 string packet-tunnel-provider" "$RUNNER_ENTITLEMENTS_PLIST"
codesign --force --sign "$EXISTING_IDENT" \
--preserve-metadata=identifier \
--entitlements "$RUNNER_ENTITLEMENTS_PLIST" "$RUNNER_APP"
echo "injected $NE_ENTITLEMENT into Runner.app entitlements during re-sign"
else
codesign --force --sign "$EXISTING_IDENT" \
--preserve-metadata=identifier,entitlements "$RUNNER_APP"
fi
rm -f "$APPEX_ENTITLEMENTS_PLIST" "$RUNNER_ENTITLEMENTS_PLIST"
else
echo "warning: bundle is signed but no identity discovered; signature will be invalid"
fi
fi

echo "embedded $APPEX_NAME into $RUNNER_APP (bundle id $WANT_ID)"
Loading
Loading