fix(release): verify export compliance in apple artifacts

This commit is contained in:
Haitao Pan 2026-03-25 14:03:09 +08:00
parent 55c2c6fb7b
commit 2e2f075d1f
4 changed files with 138 additions and 1 deletions

View File

@ -8,7 +8,7 @@ DART ?= dart
DEVICE ?= macos
APP_STORE_DART_DEFINE ?= --dart-define=XWORKMATE_APP_STORE=true
.PHONY: help deps analyze test check format run build-linux build-macos build-ios-sim package-deb package-rpm package-linux package-mac install-mac clean build-go-core render-release-docs
.PHONY: help deps analyze test check format run build-linux build-macos build-ios-sim package-deb package-rpm package-linux package-mac install-mac clean build-go-core render-release-docs check-export-compliance
help: ## Show available targets
@grep -E '^[a-zA-Z0-9_.-]+:.*?## ' Makefile | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "%-18s %s\n", $$1, $$2}'
@ -38,9 +38,11 @@ build-linux: ## Build the Linux app in release mode
build-macos: ## Build the macOS app in release mode
$(FLUTTER) build macos --release $(APP_STORE_DART_DEFINE)
bash scripts/check-apple-export-compliance.sh build/macos/Build/Products/Release/XWorkmate.app
build-ios-sim: ## Build the iOS app for the simulator
$(FLUTTER) build ios --simulator $(APP_STORE_DART_DEFINE)
bash scripts/check-apple-export-compliance.sh build/ios/iphonesimulator/Runner.app
build-go-core: ## Build the Go core helper
bash scripts/build-go-core.sh
@ -65,6 +67,9 @@ clean: ## Remove generated artifacts
$(FLUTTER) clean
rm -rf build dist
check-export-compliance: ## Verify source and built Apple plist export-compliance flags
bash scripts/check-apple-export-compliance.sh
# Rust FFI targets
.PHONY: rust-build rust-build-release rust-build-debug rust-test ffi-copy ffi-generate

View File

@ -0,0 +1,124 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
IOS_SOURCE_PLIST="$ROOT_DIR/ios/Runner/Info.plist"
MACOS_SOURCE_PLIST="$ROOT_DIR/macos/Runner/Info.plist"
TARGET_PATH="${1:-}"
usage() {
cat <<'EOF'
Usage:
scripts/check-apple-export-compliance.sh [artifact-path]
Without an artifact path, the script validates the source plist values for iOS
and macOS. With an artifact path, it also validates the built bundle/archive:
Supported artifact paths:
- *.xcarchive
- *.app
- path to an Info.plist file
EOF
}
if [[ "${TARGET_PATH:-}" == "-h" || "${TARGET_PATH:-}" == "--help" ]]; then
usage
exit 0
fi
read_bool() {
local plist_path="$1"
local key="$2"
python3 - "$plist_path" "$key" <<'PY'
import plistlib
import sys
plist_path = sys.argv[1]
key = sys.argv[2]
with open(plist_path, "rb") as handle:
data = plistlib.load(handle)
value = data.get(key, None)
if value is None:
print("__MISSING__")
elif value is True:
print("true")
elif value is False:
print("false")
else:
print(str(value).strip().lower())
PY
}
resolve_artifact_plist() {
local input_path="$1"
if [[ -f "$input_path" && "$(basename "$input_path")" == "Info.plist" ]]; then
printf '%s\n' "$input_path"
return 0
fi
if [[ -d "$input_path" && "$input_path" == *.xcarchive ]]; then
local plist_path=""
plist_path="$(find "$input_path/Products/Applications" -maxdepth 3 -name Info.plist | head -n 1)"
if [[ -n "$plist_path" ]]; then
printf '%s\n' "$plist_path"
return 0
fi
fi
if [[ -d "$input_path" && "$input_path" == *.app ]]; then
if [[ -f "$input_path/Contents/Info.plist" ]]; then
printf '%s\n' "$input_path/Contents/Info.plist"
return 0
fi
if [[ -f "$input_path/Info.plist" ]]; then
printf '%s\n' "$input_path/Info.plist"
return 0
fi
fi
return 1
}
report_value() {
local label="$1"
local plist_path="$2"
local value="$3"
echo "$label: $plist_path"
echo " ITSAppUsesNonExemptEncryption = $value"
}
assert_false() {
local label="$1"
local plist_path="$2"
local value="$3"
if [[ "$value" != "false" ]]; then
echo "Export compliance check failed for $label" >&2
report_value "$label" "$plist_path" "$value" >&2
return 1
fi
}
source_ios_value="$(read_bool "$IOS_SOURCE_PLIST" ITSAppUsesNonExemptEncryption)"
source_macos_value="$(read_bool "$MACOS_SOURCE_PLIST" ITSAppUsesNonExemptEncryption)"
assert_false "iOS source" "$IOS_SOURCE_PLIST" "$source_ios_value"
assert_false "macOS source" "$MACOS_SOURCE_PLIST" "$source_macos_value"
report_value "iOS source" "$IOS_SOURCE_PLIST" "$source_ios_value"
report_value "macOS source" "$MACOS_SOURCE_PLIST" "$source_macos_value"
if [[ -z "$TARGET_PATH" ]]; then
exit 0
fi
ARTIFACT_PLIST="$(resolve_artifact_plist "$TARGET_PATH" || true)"
if [[ -z "$ARTIFACT_PLIST" ]]; then
echo "Unsupported artifact path: $TARGET_PATH" >&2
usage >&2
exit 2
fi
artifact_value="$(read_bool "$ARTIFACT_PLIST" ITSAppUsesNonExemptEncryption)"
report_value "Artifact" "$ARTIFACT_PLIST" "$artifact_value"
assert_false "Artifact" "$ARTIFACT_PLIST" "$artifact_value"
echo "Export compliance check passed."

View File

@ -69,6 +69,9 @@ if [[ ! -d "$BUILD_APP_PATH" ]]; then
exit 1
fi
echo "Validating export compliance metadata..."
bash "$ROOT_DIR/scripts/check-apple-export-compliance.sh" "$BUILD_APP_PATH"
rm -rf "$DIST_APP_PATH" "$DIST_DMG_PATH"
ditto "$BUILD_APP_PATH" "$DIST_APP_PATH"
mkdir -p "$HELPERS_DIR"

View File

@ -65,6 +65,11 @@ sed "s|\${EXPORT_METHOD}|$export_method|g" "$root_dir/ios/ExportOptions.plist" >
flutter pub get
flutter build ipa --release --export-options-plist="$export_options_path"
archive_path="$root_dir/build/ios/archive/Runner.xcarchive"
if [[ -d "$archive_path" ]]; then
bash "$root_dir/scripts/check-apple-export-compliance.sh" "$archive_path"
fi
find "$root_dir/build/ios/ipa" -maxdepth 1 -name '*.ipa' -exec cp {} "$dist_dir/" \;
if ! compgen -G "$dist_dir/*.ipa" >/dev/null; then