Skip to content

Commit 085e997

Browse files
Merge remote-tracking branch 'origin/main' into feat/one-click-setup
2 parents 0b31545 + 1079678 commit 085e997

5 files changed

Lines changed: 328 additions & 8 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ name: Release
1313
# APPLE_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY, APPLE_TEAM_ID and for notarization either an App Store Connect
1414
# API key (APPLE_API_ISSUER, APPLE_API_KEY = key id, APPLE_API_KEY_P8 = contents of the .p8) or APPLE_ID + APPLE_PASSWORD.
1515
#
16+
# Official releases fail instead of shipping anything unsigned: the DMGs, the apps inside them, the update bundles and
17+
# the standalone macOS binaries are all checked with scripts/macos-verify.sh, and verify-downloads.yml re-checks what
18+
# usegodmode.com serves every morning (it opens an issue when Gatekeeper would refuse a download).
19+
#
1620
# Required secrets for auto-update: TAURI_SIGNING_PRIVATE_KEY + TAURI_SIGNING_PRIVATE_KEY_PASSWORD (the key matching
1721
# `plugins.updater.pubkey` in tauri.conf.json). They sign the update bundles and add latest.json to the release;
1822
# installed apps pick the update up once the release is published.
@@ -91,6 +95,41 @@ jobs:
9195
exit 1
9296
fi
9397
98+
- name: Check the Apple signing setup
99+
if: github.repository == 'codextde/godmode-bot'
100+
env:
101+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
102+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
103+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
104+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
105+
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
106+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
107+
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
108+
run: |
109+
# An official release is never shipped unsigned: macOS would only offer to move it to the Trash.
110+
missing=0
111+
for name in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_TEAM_ID APPLE_API_ISSUER APPLE_API_KEY APPLE_API_KEY_P8; do
112+
if [ -z "${!name}" ]; then echo "::error::the $name secret is missing (see the top of release.yml)"; missing=1; fi
113+
done
114+
[ "$missing" = 0 ] || exit 1
115+
[[ "$APPLE_SIGNING_IDENTITY" == "Developer ID Application: "*"($APPLE_TEAM_ID)" || "$APPLE_SIGNING_IDENTITY" =~ ^[0-9A-Fa-f]{40}$ ]] ||
116+
{ echo "::error::APPLE_SIGNING_IDENTITY must be a Developer ID Application identity of team $APPLE_TEAM_ID"; exit 1; }
117+
printf '%s' "$APPLE_CERTIFICATE" | base64 --decode > "$RUNNER_TEMP/cert.p12"
118+
export PW="$APPLE_CERTIFICATE_PASSWORD"
119+
openssl pkcs12 -in "$RUNNER_TEMP/cert.p12" -passin env:PW -nokeys -clcerts -out "$RUNNER_TEMP/cert.pem" 2>/dev/null ||
120+
openssl pkcs12 -legacy -in "$RUNNER_TEMP/cert.p12" -passin env:PW -nokeys -clcerts -out "$RUNNER_TEMP/cert.pem" ||
121+
{ echo "::error::APPLE_CERTIFICATE can't be opened with APPLE_CERTIFICATE_PASSWORD"; exit 1; }
122+
subject=$(openssl x509 -in "$RUNNER_TEMP/cert.pem" -noout -subject)
123+
until=$(openssl x509 -in "$RUNNER_TEMP/cert.pem" -noout -enddate | cut -d= -f2)
124+
rm -f "$RUNNER_TEMP/cert.p12"
125+
[[ "$subject" == *"$APPLE_TEAM_ID"* ]] || { echo "::error::APPLE_CERTIFICATE belongs to another team: $subject"; exit 1; }
126+
openssl x509 -in "$RUNNER_TEMP/cert.pem" -noout -checkend 0 >/dev/null ||
127+
{ echo "::error::the Developer ID certificate expired on $until: create a new one on developer.apple.com and update APPLE_CERTIFICATE"; exit 1; }
128+
openssl x509 -in "$RUNNER_TEMP/cert.pem" -noout -checkend $((45 * 86400)) >/dev/null ||
129+
echo "::warning::the Developer ID certificate expires on $until: renew it before then"
130+
rm -f "$RUNNER_TEMP/cert.pem"
131+
echo "Signing as $APPLE_SIGNING_IDENTITY, certificate valid until $until"
132+
94133
- name: Create (or reuse) the draft release
95134
id: release
96135
env:
@@ -201,7 +240,11 @@ jobs:
201240
printf '%s\n' "$APPLE_API_KEY_P8" > "$key_path"
202241
echo "APPLE_API_KEY_PATH=$key_path" >> "$GITHUB_ENV"
203242
fi
204-
if [ -z "$APPLE_CERTIFICATE" ]; then
243+
if [ -z "$APPLE_CERTIFICATE" ] || [ -z "$APPLE_API_KEY_P8" ]; then
244+
if [ "$GITHUB_REPOSITORY" = "codextde/godmode-bot" ]; then
245+
echo "::error::the Apple signing secrets are missing: an unsigned app can only be moved to the Trash on a Mac"
246+
exit 1
247+
fi
205248
echo "::warning::macOS build is not signed with a Developer ID (APPLE_CERTIFICATE missing): Gatekeeper will block it"
206249
fi
207250
@@ -236,11 +279,9 @@ jobs:
236279
- name: Check the macOS signature and notarization
237280
if: runner.os == 'macOS' && env.APPLE_CERTIFICATE != ''
238281
run: |
239-
app=$(ls -d apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/macos/*.app | head -n1)
240-
codesign --verify --deep --strict --verbose=2 "$app"
241-
codesign -dvv "$app" 2>&1 | grep -E "Authority=Developer ID Application|TeamIdentifier"
242-
xcrun stapler validate "$app"
243-
spctl --assess --type execute --verbose=2 "$app"
282+
bundle=apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle
283+
apps=("$bundle"/macos/*.app) updates=("$bundle"/macos/*.app.tar.gz)
284+
scripts/macos-verify.sh "${apps[0]}" "${updates[0]}"
244285
245286
# The bundler notarizes the .app only; a downloaded DMG that is signed but not notarized can still warn on open.
246287
- name: Notarize the DMG and replace it in the release
@@ -252,7 +293,8 @@ jobs:
252293
dmg=$(ls apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle/dmg/*.dmg | head -n1)
253294
xcrun notarytool submit "$dmg" --key "$APPLE_API_KEY_PATH" --key-id "$APPLE_API_KEY" --issuer "$APPLE_API_ISSUER" --wait --timeout 30m
254295
xcrun stapler staple "$dmg"
255-
spctl --assess --type open --context context:primary-signature --verbose=2 "$dmg"
296+
# What a user downloads: the DMG and the app inside it, as Gatekeeper sees them.
297+
scripts/macos-verify.sh "$dmg"
256298
# GitHub stores spaces in asset names as dots.
257299
name=$(basename "$dmg" | tr ' ' '.')
258300
old=$(gh api "repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID/assets?per_page=100" --jq ".[] | select(.name == \"$name\") | .id")
@@ -314,7 +356,7 @@ jobs:
314356
fail-fast: false
315357
matrix:
316358
include:
317-
# Built on Linux: Linux + Windows. macOS binaries are built (and signed ad hoc) on macOS.
359+
# Built on Linux: Linux + Windows. macOS binaries are built, signed and notarized on macOS.
318360
- os: ubuntu-latest
319361
targets: bun-linux-x64 bun-linux-x64-baseline bun-linux-arm64 bun-windows-x64
320362
- os: macos-latest
@@ -340,6 +382,29 @@ jobs:
340382
bun run scripts/build.ts --target="$target" --smoke
341383
done
342384
385+
- name: Sign and notarize the macOS binaries
386+
if: runner.os == 'macOS'
387+
env:
388+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
389+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
390+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
391+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
392+
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
393+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
394+
APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }}
395+
run: |
396+
# Ad-hoc signed binaries downloaded in a browser can only be moved to the Trash.
397+
if [ -z "$APPLE_CERTIFICATE" ] || [ -z "$APPLE_API_KEY_P8" ]; then
398+
if [ "$GITHUB_REPOSITORY" = "codextde/godmode-bot" ]; then echo "::error::the Apple signing secrets are missing"; exit 1; fi
399+
echo "::warning::macOS binaries stay ad-hoc signed (no Apple signing secrets)"
400+
exit 0
401+
fi
402+
export APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_$APPLE_API_KEY.p8"
403+
printf '%s\n' "$APPLE_API_KEY_P8" > "$APPLE_API_KEY_PATH"
404+
scripts/macos-sign-binaries.sh packages/core/bin/godmode-darwin-*
405+
packages/core/bin/godmode-darwin-arm64 version
406+
scripts/macos-verify.sh packages/core/bin/godmode-darwin-*
407+
343408
- name: Upload to the draft release
344409
working-directory: packages/core/bin
345410
env:
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Verify macOS downloads
2+
3+
# What a Mac user gets from usegodmode.com and the in-app updater must open without a Gatekeeper prompt:
4+
# Developer ID Application: Codext GmbH, notarized, stapled. Runs every morning and after each published release;
5+
# a failure opens (or updates) an issue so a broken signature never stays unnoticed.
6+
7+
on:
8+
schedule:
9+
- cron: "17 5 * * *"
10+
release:
11+
types: [published]
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: read
16+
issues: write
17+
18+
jobs:
19+
verify:
20+
name: Gatekeeper check
21+
runs-on: macos-latest
22+
timeout-minutes: 30
23+
steps:
24+
- uses: actions/checkout@v7
25+
26+
- name: Download what users download
27+
run: |
28+
mkdir -p "$RUNNER_TEMP/dl" && cd "$RUNNER_TEMP/dl"
29+
# The website picks the latest published release; a release event may beat its five-minute cache.
30+
if [ "${{ github.event_name }}" = release ]; then sleep 360; fi
31+
for platform in mac mac-intel; do
32+
curl -fsSL --retry 3 -o "$platform.dmg" "https://usegodmode.com/download/$platform"
33+
done
34+
for platform in server-macos-arm64 server-macos-x64; do
35+
curl -fsSL --retry 3 -o "godmode-$platform" "https://usegodmode.com/download/$platform"
36+
chmod +x "godmode-$platform"
37+
done
38+
curl -fsSL --retry 3 -o latest.json "https://usegodmode.com/api/update/latest.json" ||
39+
gh release download --repo "$GITHUB_REPOSITORY" --pattern latest.json --clobber
40+
for arch in darwin-aarch64 darwin-x86_64; do
41+
url=$(jq -r --arg p "$arch" '.platforms[$p].url' latest.json)
42+
curl -fsSL --retry 3 -o "update-$arch.app.tar.gz" "$url"
43+
done
44+
# Mark everything as downloaded by a browser, like a user's copy.
45+
for f in *; do xattr -w com.apple.quarantine "0081;$(printf '%x' "$(date +%s)");Safari;" "$f"; done
46+
ls -la
47+
env:
48+
GH_TOKEN: ${{ github.token }}
49+
50+
- name: Check signatures and notarization
51+
run: scripts/macos-verify.sh "$RUNNER_TEMP"/dl/*.dmg "$RUNNER_TEMP"/dl/*.app.tar.gz "$RUNNER_TEMP"/dl/godmode-server-*
52+
53+
- name: Open an issue when a download is broken
54+
if: failure() && github.event_name != 'workflow_dispatch'
55+
env:
56+
GH_TOKEN: ${{ github.token }}
57+
run: |
58+
title="macOS downloads fail the Gatekeeper check"
59+
body="The [Verify macOS downloads]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID) run found a download that macOS would refuse to open. Check the log, fix the signing (see the top of release.yml) and re-run the release."
60+
number=$(gh issue list --repo "$GITHUB_REPOSITORY" --state open --search "\"$title\" in:title" --json number --jq '.[0].number // empty')
61+
if [ -n "$number" ]; then
62+
gh issue comment "$number" --repo "$GITHUB_REPOSITORY" --body "$body"
63+
else
64+
gh issue create --repo "$GITHUB_REPOSITORY" --title "$title" --body "$body"
65+
fi

‎scripts/macos-sign-binaries.sh‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/usr/bin/env bash
2+
# Signs standalone macOS binaries with the Developer ID (hardened runtime, timestamp) and notarizes them, so a
3+
# browser download opens without "can't be opened, move to the Trash". A bare binary can't carry a stapled ticket:
4+
# Gatekeeper looks the notarization up online.
5+
#
6+
# scripts/macos-sign-binaries.sh <binary>...
7+
#
8+
# Env: APPLE_CERTIFICATE (base64 .p12), APPLE_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY,
9+
# APPLE_API_KEY_PATH (.p8), APPLE_API_KEY (key id), APPLE_API_ISSUER.
10+
set -euo pipefail
11+
12+
for name in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_API_KEY_PATH APPLE_API_KEY APPLE_API_ISSUER; do
13+
[ -n "${!name:-}" ] || { echo "::error::$name is not set"; exit 1; }
14+
done
15+
16+
here="$(cd "$(dirname "$0")" && pwd)"
17+
work="$(mktemp -d)"
18+
keychain="$work/signing.keychain-db"
19+
pass="$(openssl rand -hex 16)"
20+
old_keychains=()
21+
while IFS= read -r line; do
22+
line="${line#"${line%%[![:space:]]*}"}"
23+
line="${line#\"}"
24+
line="${line%\"}"
25+
[ -n "$line" ] && old_keychains+=("$line")
26+
done < <(security list-keychains -d user)
27+
cleanup() {
28+
security list-keychains -d user -s "${old_keychains[@]}" >/dev/null 2>&1 || true
29+
security delete-keychain "$keychain" >/dev/null 2>&1 || true
30+
rm -rf "$work"
31+
}
32+
trap cleanup EXIT
33+
34+
printf '%s' "$APPLE_CERTIFICATE" | base64 --decode > "$work/cert.p12"
35+
security create-keychain -p "$pass" "$keychain"
36+
security set-keychain-settings -lut 3600 "$keychain"
37+
security unlock-keychain -p "$pass" "$keychain"
38+
security import "$work/cert.p12" -k "$keychain" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign >/dev/null
39+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$pass" "$keychain" >/dev/null
40+
security list-keychains -d user -s "$keychain" "${old_keychains[@]}"
41+
42+
for bin in "$@"; do
43+
codesign --force --options runtime --timestamp --entitlements "$here/macos/binary.entitlements" \
44+
--keychain "$keychain" --sign "$APPLE_SIGNING_IDENTITY" "$bin"
45+
zip="$work/$(basename "$bin").zip"
46+
ditto -c -k --keepParent "$bin" "$zip"
47+
result="$(xcrun notarytool submit "$zip" --key "$APPLE_API_KEY_PATH" --key-id "$APPLE_API_KEY" --issuer "$APPLE_API_ISSUER" \
48+
--wait --timeout 30m --output-format json)"
49+
status="$(plutil -extract status raw -o - - <<<"$result" 2>/dev/null || echo unknown)"
50+
if [ "$status" != "Accepted" ]; then
51+
id="$(plutil -extract id raw -o - - <<<"$result" 2>/dev/null || true)"
52+
echo "::error::notarization of $bin: $status"
53+
[ -n "$id" ] && xcrun notarytool log "$id" --key "$APPLE_API_KEY_PATH" --key-id "$APPLE_API_KEY" --issuer "$APPLE_API_ISSUER" || true
54+
exit 1
55+
fi
56+
echo "signed and notarized: $bin"
57+
done

‎scripts/macos-verify.sh‎

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
#!/usr/bin/env bash
2+
# Fails unless every given macOS download opens without a Gatekeeper prompt: signed with the Developer ID of
3+
# Codext GmbH, hardened runtime, secure timestamp, and (apps and DMGs) notarized with a stapled ticket.
4+
#
5+
# scripts/macos-verify.sh <file.dmg | file.app | file.app.tar.gz | binary>...
6+
#
7+
# APPLE_TEAM_ID (default STSYBH724K) is the team the signature must belong to; CERT_WARN_DAYS (default 45) warns
8+
# when the signing certificate runs out soon, and the check fails once it has.
9+
set -euo pipefail
10+
11+
TEAM="${APPLE_TEAM_ID:-STSYBH724K}"
12+
WARN_DAYS="${CERT_WARN_DAYS:-45}"
13+
WORK="$(mktemp -d)"
14+
MOUNTS=()
15+
cleanup() {
16+
for m in "${MOUNTS[@]:-}"; do [ -n "$m" ] && hdiutil detach "$m" -quiet -force 2>/dev/null || true; done
17+
rm -rf "$WORK"
18+
}
19+
trap cleanup EXIT
20+
21+
fail() {
22+
echo "::error::$*"
23+
exit 1
24+
}
25+
26+
signer() {
27+
local path="$1" kind="${2:-code}" info
28+
info="$(codesign -dvv "$path" 2>&1)" || fail "$path is not signed"
29+
grep -q "^Authority=Developer ID Application: .*($TEAM)$" <<<"$info" ||
30+
fail "$path is not signed with a Developer ID of team $TEAM ($(grep -m1 -E '^(Authority|Signature)=' <<<"$info" || echo unsigned))"
31+
grep -q "^TeamIdentifier=$TEAM$" <<<"$info" || fail "$path has another team identifier"
32+
[ "$kind" = disk ] || grep -q "flags=.*runtime" <<<"$info" || fail "$path is signed without the hardened runtime (notarization needs it)"
33+
grep -q "^Timestamp=" <<<"$info" || fail "$path has no secure timestamp"
34+
codesign --verify --strict --verbose=2 "$path"
35+
certificate "$path"
36+
echo " signed: $(grep -m1 '^Authority=' <<<"$info" | cut -d= -f2-)"
37+
}
38+
39+
certificate() {
40+
local dir="$WORK/certs-$RANDOM"
41+
mkdir -p "$dir"
42+
(cd "$dir" && codesign -d --extract-certificates "$1" 2>/dev/null)
43+
local leaf="$dir/codesign0"
44+
[ -f "$leaf" ] || fail "could not read the signing certificate of $1"
45+
local until
46+
until="$(openssl x509 -inform DER -in "$leaf" -noout -enddate | cut -d= -f2)"
47+
# The signatures stay valid after expiry thanks to the timestamp, but new releases can no longer be signed.
48+
openssl x509 -inform DER -in "$leaf" -noout -checkend 0 >/dev/null || fail "the Developer ID certificate expired on $until: create a new one (see the top of release.yml)"
49+
if ! openssl x509 -inform DER -in "$leaf" -noout -checkend $((WARN_DAYS * 86400)) >/dev/null; then
50+
echo "::warning::the Developer ID certificate expires on $until: renew it and update APPLE_CERTIFICATE before then"
51+
fi
52+
}
53+
54+
gatekeeper() {
55+
local out
56+
out="$(spctl --assess --verbose=2 "$@" 2>&1)" || fail "Gatekeeper rejects ${*: -1}: $out"
57+
grep -q "source=Notarized Developer ID" <<<"$out" || fail "${*: -1} is not notarized: $out"
58+
}
59+
60+
app() {
61+
local path="$1"
62+
echo "app: $path"
63+
signer "$path"
64+
codesign --verify --deep --strict --verbose=2 "$path"
65+
xcrun stapler validate "$path" >/dev/null || fail "$path has no stapled notarization ticket"
66+
gatekeeper --type execute "$path"
67+
if command -v syspolicy_check >/dev/null; then
68+
syspolicy_check distribution "$path" || fail "syspolicy_check rejects $path"
69+
fi
70+
}
71+
72+
dmg() {
73+
local path="$1" mnt
74+
echo "dmg: $path"
75+
signer "$path" disk
76+
xcrun stapler validate "$path" >/dev/null || fail "$path has no stapled notarization ticket"
77+
gatekeeper --type open --context context:primary-signature "$path"
78+
mnt="$WORK/mnt-$RANDOM"
79+
mkdir -p "$mnt"
80+
# The DMG carries a licence agreement: `yes` accepts it like a click on Agree.
81+
hdiutil attach -nobrowse -readonly -noautoopen -mountpoint "$mnt" "$path" < <(yes) >/dev/null || fail "could not open $path"
82+
MOUNTS+=("$mnt")
83+
local found=0
84+
for a in "$mnt"/*.app; do
85+
[ -d "$a" ] || continue
86+
found=1
87+
app "$a"
88+
done
89+
[ "$found" = 1 ] || fail "$path contains no app"
90+
}
91+
92+
tarball() {
93+
local path="$1" dir="$WORK/tar-$RANDOM"
94+
echo "update bundle: $path"
95+
mkdir -p "$dir"
96+
tar -xzf "$path" -C "$dir"
97+
local found=0
98+
for a in "$dir"/*.app; do
99+
[ -d "$a" ] || continue
100+
found=1
101+
app "$a"
102+
done
103+
[ "$found" = 1 ] || fail "$path contains no app"
104+
}
105+
106+
[ $# -gt 0 ] || fail "usage: $0 <file.dmg|file.app|file.app.tar.gz|binary>..."
107+
for target in "$@"; do
108+
[ -e "$target" ] || fail "$target does not exist"
109+
case "$target" in
110+
*.dmg) dmg "$target" ;;
111+
*.app) app "$target" ;;
112+
*.tar.gz) tarball "$target" ;;
113+
*)
114+
# A command-line binary: Gatekeeper checks its notarization online (a ticket can't be stapled to it).
115+
echo "binary: $target"
116+
signer "$target"
117+
;;
118+
esac
119+
done
120+
echo "All macOS downloads pass Gatekeeper."

‎scripts/macos/binary.entitlements‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!-- Bun (JavaScriptCore) needs JIT under the hardened runtime, like the app's core sidecar. -->
6+
<key>com.apple.security.cs.allow-jit</key>
7+
<true/>
8+
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
9+
<true/>
10+
<key>com.apple.security.cs.disable-library-validation</key>
11+
<true/>
12+
</dict>
13+
</plist>

0 commit comments

Comments
 (0)