From 06a89e8a5e6efb18d6d58c1c7c35c0dd627bb867 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Fri, 14 Aug 2026 11:16:06 -0700 Subject: [PATCH 1/3] Harden SPM integration test to guard visionOS slices Make visionOS device + simulator slices default-on in the SPM integration test and verify they are present in the built MSAL.xcframework, so the published binary can never silently ship out of sync with Package.swift's .visionOS() platform declaration (root cause of #2809). - spm-integration-test.sh: default INCLUDE_VISIONOS=true; add --skip-visionos opt-out (keep --include-visionos as a no-op alias); add plistlib verification that xros device + xros-simulator slices are present, failing the build if either is missing. - azure_pipelines/pr-validation.yml: pass --skip-visionos on the fast PR job, which does not install the visionOS SDK (visionOS is validated separately in visionos-validation.yml). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b06a8f53-b71a-4ce4-b94d-210d927e09fa --- azure_pipelines/pr-validation.yml | 4 ++- spm-integration-test.sh | 44 +++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/azure_pipelines/pr-validation.yml b/azure_pipelines/pr-validation.yml index 977fef3e3e..9f014020be 100644 --- a/azure_pipelines/pr-validation.yml +++ b/azure_pipelines/pr-validation.yml @@ -265,7 +265,9 @@ jobs: inputs: targetType: 'inline' script: | - sh spm-integration-test.sh "${BRANCH_NAME}" + # visionOS slices are validated in visionos-validation.yml (which installs + # the visionOS SDK). This fast PR job does not, so skip them here. + sh spm-integration-test.sh "${BRANCH_NAME}" --skip-visionos continueOnError: false - task: Bash@3 diff --git a/spm-integration-test.sh b/spm-integration-test.sh index 98ca721e50..a60197fad8 100644 --- a/spm-integration-test.sh +++ b/spm-integration-test.sh @@ -1,5 +1,10 @@ BRANCH_NAME="$1" -INCLUDE_VISIONOS=false +# visionOS device + simulator slices are included by default so the published +# xcframework never ships out of sync with Package.swift's .visionOS() platform. +# Use --skip-visionos on fast paths (e.g. regular PR validation) that do not have +# the visionOS SDK installed. --include-visionos is kept as a no-op alias for +# backward compatibility with existing callers. +INCLUDE_VISIONOS=true SKIP_SAMPLE_APP=false # Parse optional flags @@ -8,6 +13,9 @@ for arg in "$@"; do --include-visionos) INCLUDE_VISIONOS=true ;; + --skip-visionos) + INCLUDE_VISIONOS=false + ;; --skip-sample-app) SKIP_SAMPLE_APP=true ;; @@ -35,11 +43,43 @@ if [ "$INCLUDE_VISIONOS" = true ]; then xcodebuild -sdk xros -configuration Release -workspace MSAL.xcworkspace -scheme "MSAL (iOS Framework)" archive SKIP_INSTALL=NO BUILD_LIBRARY_FOR_DISTRIBUTION=YES -archivePath archive/visionOS CODE_SIGNING_ALLOWED=NO -quiet > build.log 2>&1 XCFRAMEWORK_ARGS="$XCFRAMEWORK_ARGS -framework archive/visionOSSimulator.xcarchive/Products/Library/Frameworks/MSAL.framework -framework archive/visionOS.xcarchive/Products/Library/Frameworks/MSAL.framework" else - echo "Skipping visionOS (use --include-visionos to include)" + echo "Skipping visionOS (use default, or pass --include-visionos, to include; --skip-visionos to opt out)" fi xcodebuild -create-xcframework $XCFRAMEWORK_ARGS -output framework/MSAL.xcframework > build.log 2>&1 +if [ "$INCLUDE_VISIONOS" = true ]; then + echo "Verifying visionOS slices are present in MSAL.xcframework" + python3 - <<'PY' +import plistlib, sys + +plist_path = "framework/MSAL.xcframework/Info.plist" +with open(plist_path, "rb") as f: + info = plistlib.load(f) + +libraries = info.get("AvailableLibraries", []) + +def has_slice(platform, simulator): + for lib in libraries: + is_sim = lib.get("SupportedPlatformVariant") == "simulator" + if lib.get("SupportedPlatform") == platform and is_sim == simulator: + return True + return False + +missing = [] +if not has_slice("xros", False): + missing.append("visionOS device (xros)") +if not has_slice("xros", True): + missing.append("visionOS simulator (xros-simulator)") + +if missing: + sys.stderr.write("** ERROR: MSAL.xcframework is missing required slices: " + ", ".join(missing) + " **\n") + sys.exit(1) + +print("Verified visionOS device + simulator slices are present in MSAL.xcframework") +PY +fi + echo "Creating MSAL.zip" zip -r MSAL.zip framework/MSAL.xcframework -y -v From 3b01a98197976c83fb329f47ac43a668df3f7958 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Fri, 14 Aug 2026 11:40:11 -0700 Subject: [PATCH 2/3] Improve CI diagnosability for visionOS xcframework build Address review feedback on #3073: - Add an ERR trap that dumps build.log on any failure, so failing xcodebuild archive steps (which run with -quiet and redirect to build.log) surface an actionable error in the CI log. - Add an explicit existence check for MSAL.xcframework/Info.plist before parsing it, emitting a clear error instead of an unhandled Python stack trace if xcframework creation failed. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b06a8f53-b71a-4ce4-b94d-210d927e09fa --- spm-integration-test.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spm-integration-test.sh b/spm-integration-test.sh index a60197fad8..b54f4daf63 100644 --- a/spm-integration-test.sh +++ b/spm-integration-test.sh @@ -27,6 +27,11 @@ current_date=$(date +"%Y-%m-%d %H:%M:%S") set -e +# xcodebuild steps below run with -quiet and redirect output to build.log, so a +# failure would otherwise exit with no actionable context in the CI log. Dump +# build.log on any error so the underlying xcodebuild error is visible. +trap 'echo "** Build step failed. Contents of build.log: **"; cat build.log 2>/dev/null || echo "(build.log not found)"' ERR + # Build framework echo "Building framework" @@ -50,6 +55,10 @@ xcodebuild -create-xcframework $XCFRAMEWORK_ARGS -output framework/MSAL.xcframew if [ "$INCLUDE_VISIONOS" = true ]; then echo "Verifying visionOS slices are present in MSAL.xcframework" + if [ ! -f framework/MSAL.xcframework/Info.plist ]; then + echo "** ERROR: framework/MSAL.xcframework/Info.plist not found; xcframework creation likely failed. See build.log above. **" + exit 1 + fi python3 - <<'PY' import plistlib, sys From e0dc0291e4782afee24bfcc993508ef889e16b51 Mon Sep 17 00:00:00 2001 From: mipetriu Date: Fri, 14 Aug 2026 11:46:32 -0700 Subject: [PATCH 3/3] Use POSIX EXIT trap instead of bash-only ERR trap Address high-severity review feedback on #3073: the script is invoked via `sh spm-integration-test.sh` and has no shebang, so the previous `trap ... ERR` (a bash-ism) is unreliable under a POSIX /bin/sh such as dash and could abort the script before any build step. Replace it with a POSIX-compatible EXIT trap that inspects the exit status and dumps build.log only on a non-zero exit. Validated with `dash -n` and a functional set -e test under sh. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b06a8f53-b71a-4ce4-b94d-210d927e09fa --- spm-integration-test.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/spm-integration-test.sh b/spm-integration-test.sh index b54f4daf63..d89aab9ce4 100644 --- a/spm-integration-test.sh +++ b/spm-integration-test.sh @@ -28,9 +28,19 @@ current_date=$(date +"%Y-%m-%d %H:%M:%S") set -e # xcodebuild steps below run with -quiet and redirect output to build.log, so a -# failure would otherwise exit with no actionable context in the CI log. Dump -# build.log on any error so the underlying xcodebuild error is visible. -trap 'echo "** Build step failed. Contents of build.log: **"; cat build.log 2>/dev/null || echo "(build.log not found)"' ERR +# failure would otherwise exit with no actionable context in the CI log. On a +# non-zero exit, dump build.log so the underlying xcodebuild error is visible. +# This script is invoked via `sh`, so use a POSIX-compatible EXIT trap that +# checks the status rather than a bash-only ERR trap. +on_exit() +{ + status=$? + if [ "$status" -ne 0 ]; then + echo "** Build step failed (exit $status). Contents of build.log: **" + cat build.log 2>/dev/null || echo "(build.log not found)" + fi +} +trap on_exit EXIT # Build framework