forked from Manuel/meeting-assistant
ci: prepare source-bound native macOS build and tests under TCG
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
# Apple LaunchDaemon bootstrap before the guest .NET SDK exists.
|
||||
# Runs only inside the isolated owned VM; installs CLT and expands the pinned SDK.
|
||||
set -u
|
||||
PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
||||
export PATH
|
||||
PROOF_TOKEN="${1:-}"
|
||||
STATE_DIR="/Volumes/installstate"
|
||||
WORK="/private/var/tmp/meeting-assistant-native-$PROOF_TOKEN"
|
||||
[[ "$PROOF_TOKEN" =~ ^[0-9a-f]{32}$ ]] || exit 1
|
||||
[ "$(cat "$STATE_DIR/run.owner" 2>/dev/null)" = "$PROOF_TOKEN" ] || exit 1
|
||||
exec >> "$STATE_DIR/firstboot.log" 2>&1
|
||||
|
||||
phase() {
|
||||
printf '{"token":"%s","phase":"%s","updatedUtc":"%s"}\n' "$PROOF_TOKEN" "$1" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$STATE_DIR/guest-phase.json.tmp"
|
||||
mv -f "$STATE_DIR/guest-phase.json.tmp" "$STATE_DIR/guest-phase.json"
|
||||
}
|
||||
fail() { printf '[firstboot] ERROR: %s\n' "$1"; phase bootstrap-failed; exit 1; }
|
||||
require_installed_macos_version() {
|
||||
# Numeric sw_vers product release with a major version of at least 14.
|
||||
[[ "${1:-}" =~ ^(1[4-9]|[2-9][0-9]|[1-9][0-9]{2,})\.[0-9]+(\.[0-9]+)?$ ]]
|
||||
}
|
||||
phase toolchain-installing
|
||||
echo '[firstboot] verifying installed OS, APFS and owned physical store'
|
||||
uname -a; id
|
||||
installed_version=$(/usr/bin/sw_vers -productVersion) || fail installed_os_version_failed
|
||||
require_installed_macos_version "$installed_version" || fail installed_macos_14_or_newer_required
|
||||
printf '[firstboot] installed macOS version=%s\n' "$installed_version"
|
||||
[ "$(id -u)" = 0 ] && [ "$(uname -m)" = x86_64 ] || fail wrong_guest_platform
|
||||
/usr/sbin/diskutil info -plist / > "$STATE_DIR/installed-root.plist" || fail root_diskutil_failed
|
||||
[ "$(/usr/libexec/PlistBuddy -c 'Print :FilesystemType' "$STATE_DIR/installed-root.plist")" = apfs ] || fail root_is_not_installed_apfs
|
||||
container=$(/usr/libexec/PlistBuddy -c 'Print :APFSContainerReference' "$STATE_DIR/installed-root.plist") || fail root_container_missing
|
||||
/usr/sbin/diskutil apfs list -plist > "$STATE_DIR/apfs-containers.plist" || fail apfs_list_failed
|
||||
index=0
|
||||
physical=""
|
||||
while reference=$(/usr/libexec/PlistBuddy -c "Print :Containers:$index:ContainerReference" "$STATE_DIR/apfs-containers.plist" 2>/dev/null); do
|
||||
if [ "$reference" = "$container" ]; then
|
||||
[ -z "$physical" ] || fail ambiguous_root_containers
|
||||
physical=$(/usr/libexec/PlistBuddy -c "Print :Containers:$index:PhysicalStores:0:DeviceIdentifier" "$STATE_DIR/apfs-containers.plist") || fail physical_store_missing
|
||||
/usr/libexec/PlistBuddy -c "Print :Containers:$index:PhysicalStores:1" "$STATE_DIR/apfs-containers.plist" >/dev/null 2>&1 && fail multiple_physical_stores
|
||||
fi
|
||||
index=$((index + 1))
|
||||
done
|
||||
[[ "$physical" =~ ^disk[0-9]+s[0-9]+$ ]] || fail invalid_physical_store
|
||||
/usr/sbin/diskutil info -plist "/dev/$physical" > "$STATE_DIR/physical-store.plist" || fail physical_store_info_failed
|
||||
whole=$(/usr/libexec/PlistBuddy -c 'Print :ParentWholeDisk' "$STATE_DIR/physical-store.plist") || fail physical_parent_missing
|
||||
. "$STATE_DIR/macos-native-disk-guard.sh"
|
||||
verify_owned_disk "/dev/$whole" "$STATE_DIR" "$PROOF_TOKEN" || fail installed_root_is_not_the_owned_64g_disk
|
||||
|
||||
# The phase has an independent 30-minute watchdog; host outer deadline is 180 minutes.
|
||||
parent=$$
|
||||
(
|
||||
trap 'kill "$sleeper" 2>/dev/null || :; exit 0' TERM INT
|
||||
# Toolchain watchdog: 30 minutes, also bounded by the host's 172-minute total.
|
||||
sleep 1800 & sleeper=$!; wait "$sleeper"; kill -TERM "$parent" 2>/dev/null || :
|
||||
) & watchdog=$!
|
||||
clt_marker="/tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress"
|
||||
trap 'rm -f "$clt_marker"; kill -TERM "$watchdog" 2>/dev/null || :; wait "$watchdog" 2>/dev/null || :' EXIT
|
||||
trap 'fail toolchain_deadline_or_cancellation' TERM INT
|
||||
[ ! -e "$WORK" ] || fail guest_work_directory_already_exists
|
||||
mkdir -p "$WORK" || fail guest_work_directory_failed
|
||||
printf '%s\n' "$PROOF_TOKEN" > "$WORK/run.owner" || fail guest_work_owner_failed
|
||||
free_kib=$(df -Pk "$WORK" | awk 'NR==2 {print $4}')
|
||||
[[ "$free_kib" =~ ^[0-9]+$ ]] && (( free_kib >= 8 * 1024 * 1024 )) || fail insufficient_existing_guest_free_space
|
||||
|
||||
echo '[firstboot] installing a compatible Apple CLT catalog entry without a GUI'
|
||||
touch "$clt_marker" || fail clt_marker_failed
|
||||
/usr/sbin/softwareupdate -l > "$STATE_DIR/clt-catalog.log" 2>&1 || fail clt_catalog_failed
|
||||
label=$(grep -B 1 -E 'Command Line Tools' "$STATE_DIR/clt-catalog.log" | awk -F'*' '/^ *\*/ {print $2}' | sed -e 's/^ *Label: //' -e 's/^ *//' | sort -V | tail -n 1)
|
||||
[ -n "$label" ] || fail no_compatible_headless_clt_label
|
||||
printf '[firstboot] selected CLT: %s\n' "$label"
|
||||
/usr/sbin/softwareupdate -i "$label" > "$STATE_DIR/clt-install.log" 2>&1 || fail clt_install_failed
|
||||
/usr/bin/xcode-select --switch /Library/Developer/CommandLineTools || fail clt_switch_failed
|
||||
/usr/sbin/pkgutil --pkg-info=com.apple.pkg.CLTools_Executables || fail clt_receipt_failed
|
||||
/usr/bin/xcrun --find swiftc || fail swiftc_missing
|
||||
/usr/bin/xcrun swiftc --version || fail swiftc_version_failed
|
||||
{
|
||||
/usr/bin/xcrun --sdk macosx --show-sdk-version &&
|
||||
/usr/bin/xcrun --sdk macosx --show-sdk-path
|
||||
} > "$STATE_DIR/clt-sdk.log" 2>&1 || fail clt_sdk_identity_failed
|
||||
printf 'import AppKit\nimport AVFoundation\nimport ScreenCaptureKit\nimport EventKit\nimport WebKit\nprint("native SDK ready")\n' > "$WORK/toolchain-smoke.swift"
|
||||
/usr/bin/xcrun swiftc -target x86_64-apple-macos13.0 "$WORK/toolchain-smoke.swift" -o "$WORK/toolchain-smoke" || fail native_framework_compile_failed
|
||||
"$WORK/toolchain-smoke" || fail native_framework_execution_failed
|
||||
rm -f "$clt_marker"
|
||||
|
||||
echo '[firstboot] validating and expanding the pinned .NET SDK on owned APFS'
|
||||
expected_sdk=33401b4a2da8554e3306db6072ea8569d9fcc608509c271e0aa4b39e7cc432da3631f14e7e1e2445d67d72550d18ce44a8bbd2382a756867ad2edab6b1c963c0
|
||||
actual_sdk=$(shasum -a 512 "$STATE_DIR/sdk.tar.gz" | awk '{print $1}')
|
||||
[ "$actual_sdk" = "$expected_sdk" ] || fail sdk_hash_mismatch
|
||||
mkdir "$WORK/dotnet" || fail sdk_directory_failed
|
||||
tar -xzf "$STATE_DIR/sdk.tar.gz" -C "$WORK/dotnet" || fail sdk_extract_failed
|
||||
[ "$("$WORK/dotnet/dotnet" --version)" = 10.0.401 ] || fail sdk_version_mismatch
|
||||
# Guest C# owns build/test deadlines from this point; stop the CLT-only watchdog.
|
||||
kill -TERM "$watchdog" 2>/dev/null || :
|
||||
wait "$watchdog" 2>/dev/null || :
|
||||
trap - TERM INT
|
||||
"$WORK/dotnet/dotnet" run --file "$STATE_DIR/MacOsNativeGuest.cs" -- --run --state "$STATE_DIR" --work "$WORK"
|
||||
result=$?
|
||||
(( result == 0 )) || fail native_tests_failed
|
||||
exit 0
|
||||
Reference in New Issue
Block a user