Fix macOS publish bundle signing
This commit is contained in:
@@ -15,8 +15,11 @@ dotnet build clients/apple/VoiceCat.Apple.slnx -c Debug --no-restore
|
|||||||
|
|
||||||
Use `publish-macos.sh --dry-run` to validate a local ad-hoc macOS bundle. The dry-run build does
|
Use `publish-macos.sh --dry-run` to validate a local ad-hoc macOS bundle. The dry-run build does
|
||||||
not enable hardened runtime because ad-hoc signatures have no Team ID and cannot satisfy macOS
|
not enable hardened runtime because ad-hoc signatures have no Team ID and cannot satisfy macOS
|
||||||
library validation. Distribution builds remain hardened and require `VOICECAT_CODESIGN_IDENTITY`;
|
library validation. The script normalizes nested signatures and installs the verified bundle at
|
||||||
optional notarization uses `APPLE_ID`, `APPLE_TEAM_ID`, and `APPLE_APP_PASSWORD`.
|
both `VoiceCat.Mac/bin/Release/net10.0-macos27.0/osx-arm64/VoiceCat.app` and
|
||||||
|
`VoiceCat.Mac/bin/Release/distribution/VoiceCat.app`. Distribution builds remain hardened and
|
||||||
|
require `VOICECAT_CODESIGN_IDENTITY`; optional notarization uses `APPLE_ID`, `APPLE_TEAM_ID`, and
|
||||||
|
`APPLE_APP_PASSWORD`.
|
||||||
|
|
||||||
For a physical iOS device, use `build-ios-device.sh` and `deploy-ios-device.sh`. The host and
|
For a physical iOS device, use `build-ios-device.sh` and `deploy-ios-device.sh`. The host and
|
||||||
ReplayKit extension require signing profiles with App Group `group.me.iamtalon.voicecat`.
|
ReplayKit extension require signing profiles with App Group `group.me.iamtalon.voicecat`.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0"><dict>
|
<plist version="1.0"><dict>
|
||||||
<key>com.apple.security.app-sandbox</key><true/>
|
<key>com.apple.security.app-sandbox</key><true/>
|
||||||
|
<key>com.apple.security.cs.allow-jit</key><true/>
|
||||||
<key>com.apple.security.network.client</key><true/>
|
<key>com.apple.security.network.client</key><true/>
|
||||||
<key>com.apple.security.device.audio-input</key><true/>
|
<key>com.apple.security.device.audio-input</key><true/>
|
||||||
<key>com.apple.security.files.user-selected.read-write</key><true/>
|
<key>com.apple.security.files.user-selected.read-write</key><true/>
|
||||||
|
|||||||
@@ -45,11 +45,39 @@ fi
|
|||||||
mkdir -p "$distribution"
|
mkdir -p "$distribution"
|
||||||
ditto "$built_app" "$app"
|
ditto "$built_app" "$app"
|
||||||
|
|
||||||
|
entitlements="$script_dir/VoiceCat.Mac/VoiceCat.Mac.entitlements"
|
||||||
|
|
||||||
|
sign_nested_code() {
|
||||||
|
local identity=$1
|
||||||
|
local timestamp_option=${2:-}
|
||||||
|
local runtime_option=${3:-}
|
||||||
|
local nested
|
||||||
|
local sign_options=(--force)
|
||||||
|
|
||||||
|
[[ -n "$timestamp_option" ]] && sign_options+=("$timestamp_option")
|
||||||
|
[[ -n "$runtime_option" ]] && sign_options+=("$runtime_option")
|
||||||
|
|
||||||
|
# Do not use codesign --deep for signing. It is intended as an emergency repair operation
|
||||||
|
# and can apply the app's entitlements to nested code. Sign each bundled Mach-O library first,
|
||||||
|
# then sign the outer app once with its own entitlements.
|
||||||
|
while IFS= read -r -d '' nested; do
|
||||||
|
codesign "${sign_options[@]}" --sign "$identity" "$nested"
|
||||||
|
done < <(find "$app/Contents" -type f \( -name '*.dylib' -o -name '*.so' \) -print0)
|
||||||
|
}
|
||||||
|
|
||||||
|
install_verified_primary_bundle() {
|
||||||
|
# dotnet publish must create the workload bundle before it can be normalized. Replace that
|
||||||
|
# misleading intermediate with the verified result so both documented output paths work.
|
||||||
|
rm -rf "$built_app"
|
||||||
|
ditto "$app" "$built_app"
|
||||||
|
}
|
||||||
|
|
||||||
if (( dry_run )); then
|
if (( dry_run )); then
|
||||||
# Normalize the workload's mixed nested signatures after bundling.
|
sign_nested_code -
|
||||||
codesign --force --deep --sign - "$app"
|
codesign --force --entitlements "$entitlements" --sign - "$app"
|
||||||
codesign --verify --deep --strict "$app"
|
codesign --verify --deep --strict "$app"
|
||||||
spctl --assess --type execute "$app" 2>/dev/null || true
|
spctl --assess --type execute "$app" 2>/dev/null || true
|
||||||
|
install_verified_primary_bundle
|
||||||
print "Validated ad-hoc build: $app"
|
print "Validated ad-hoc build: $app"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
@@ -60,10 +88,12 @@ if [[ -z "$identity" ]]; then
|
|||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
codesign --force --deep --timestamp --options runtime \
|
sign_nested_code "$identity" --timestamp --options=runtime
|
||||||
--entitlements "$script_dir/VoiceCat.Mac/VoiceCat.Mac.entitlements" \
|
codesign --force --timestamp --options runtime \
|
||||||
|
--entitlements "$entitlements" \
|
||||||
--sign "$identity" "$app"
|
--sign "$identity" "$app"
|
||||||
codesign --verify --deep --strict --verbose=2 "$app"
|
codesign --verify --deep --strict --verbose=2 "$app"
|
||||||
|
install_verified_primary_bundle
|
||||||
|
|
||||||
archive="$distribution/VoiceCat-macOS-arm64.zip"
|
archive="$distribution/VoiceCat-macOS-arm64.zip"
|
||||||
ditto -c -k --keepParent "$app" "$archive"
|
ditto -c -k --keepParent "$app" "$archive"
|
||||||
|
|||||||
@@ -24,6 +24,21 @@ public class PublishServerScriptTests
|
|||||||
Assert.Contains("(?:bin|obj)", script);
|
Assert.Contains("(?:bin|obj)", script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task MacPublishPreservesAppEntitlementsAndReplacesBrokenWorkloadBundle()
|
||||||
|
{
|
||||||
|
string root = FindRoot();
|
||||||
|
string script = await File.ReadAllTextAsync(Path.Combine(root, "clients", "apple", "publish-macos.sh"));
|
||||||
|
string entitlements = await File.ReadAllTextAsync(Path.Combine(
|
||||||
|
root, "clients", "apple", "VoiceCat.Mac", "VoiceCat.Mac.entitlements"));
|
||||||
|
|
||||||
|
Assert.Contains("sign_nested_code", script);
|
||||||
|
Assert.Contains("--entitlements \"$entitlements\"", script);
|
||||||
|
Assert.Contains("install_verified_primary_bundle", script);
|
||||||
|
Assert.DoesNotContain("codesign --force --deep", script);
|
||||||
|
Assert.Contains("com.apple.security.cs.allow-jit", entitlements);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DefaultPublishTargetsWindowsAndLinuxWhileRuntimeCanSelectOne()
|
public async Task DefaultPublishTargetsWindowsAndLinuxWhileRuntimeCanSelectOne()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user