macOS 26 (Tahoe) Apple Provenance ve Gatekeeper Çözümü
Title: macOS 26 (Tahoe) Apple Provenance ve Gatekeeper Çözümü
[Edit: 24 Şubat 2026] - Bu makale, Gatekeeper'ın iç içe geçmiş (nested) binary dosyalarında yarattığı kilitlenmeler (deadlock) ve symlink sorunlarını içerecek şekilde güncellenmiştir.
macOS 26'ya (Tahoe) geçtikten sonra npx komutları bir süre sorunsuz çalışmaya devam edebiliyor. Sorun, yeni bir binary veya paket indirildiğinde ortaya çıkıyor. Örneğin brew upgrade node çalıştırdığınızda veya npx ile daha önce cache'lenmemiş bir paket indirdiğinizde. macOS, yeni indirilen dosyalara kernel seviyesinde com.apple.provenance etiketi yapıştırıyor ve Gatekeeper bu dosyaları sessizce engelliyor.
Sonuç olarak hata mesajı yok, çıktı yok, komut sonsuza kadar asılı kalıyor. curl çalışıyor, npm install çalışıyor, node -e "console.log('test')" bile çalışıyor. Ama npx ile bir paket çalıştırmaya kalktığınızda sadece yanıp sönen bir cursor görüyorsunuz.
Sorunun Kaynağı
npm debug loglarına bakınca paketlerin başarıyla indirildiği görülüyor:
13 http fetch GET 200 https://registry.npmjs.org/vibe-kanban 246ms (cache revalidated)
14 silly packumentCache heap:4345298944 maxSize:1086324736
... (ve sessizlik)
Paket indiriliyor, cache'e yazılıyor ama çalıştırılmıyor.
Aynı dosyayı iki farklı shebang ile çalıştırınca fark ortaya çıkıyor:
# #!/usr/bin/env node → asılı kalıyor
$ ./node_modules/.bin/cowsay "test"
# ❌ Sonsuza kadar bekliyor
# #!/usr/local/bin/node → çalışıyor
$ ./node_modules/.bin/cowsay "test"
# ✅ Sorunsuz
# Doğrudan node ile → çalışıyor
$ node node_modules/cowsay/cli.js "test"
# ✅ Sorunsuz
Neden Oluyor?
macOS system loglarında (syspolicyd) şu kayıtlar var:
syspolicyd: rejecting due to lack of matching active rule
syspolicyd: Error checking with notarization daemon: 3
syspolicyd: MacOS error: -67002
Olan şey şu:
- npm/npx paketi indiriyor → macOS kernel seviyesinde dosyaya
com.apple.provenanceetiketi yapıştırıyor - npx indirdiği paketin binary'sini
#!/usr/bin/env nodeshebang'i ile çalıştırmayı deniyor - macOS bu dosyayı çalıştırmadan önce
syspolicyd'ye soruyor syspolicydApple sunucularına bağlanıp notarization kontrolü yapıyor- Binary
adhocsigned olduğu için notarization bulamıyor ve sessizce reddediyor
#!/usr/bin/env node dediğinizde macOS env programı aracılığıyla dolaylı bir çalıştırma yapıyor ve bu Gatekeeper kontrolünü tetikliyor. #!/usr/local/bin/node dediğinizde ise doğrudan binary'ye gidiyor, dolaylı kontrol devre dışı kalıyor.
Homebrew Node da Etkileniyor
brew upgrade node çalıştırınca durum daha da kötüleşiyor. Yeni indirilen Node.js binary'si de com.apple.provenance alıyor ve node -v bile çalışmaz hale geliyor:
$ spctl -a -v /opt/homebrew/Cellar/node/25.6.1/bin/node
/opt/homebrew/Cellar/node/25.6.1/bin/node: rejected
$ codesign -dv /opt/homebrew/bin/node
Signature=adhoc # Apple notarized değil
Denediğimiz klasik çözümlerden hiçbiri işe yaramadı:
| Denenen | Sonuç |
|---|---|
xattr -cr ile provenance kaldırma |
Kernel seviyesinde, bazen kaldırılamıyor veya Apple imzalarını bozuyor |
sudo xattr -dr com.apple.provenance |
Permission denied veya etkisiz |
sudo spctl --add --label "Homebrew" |
"This operation is no longer supported" |
sudo spctl --master-disable |
"Needs to be confirmed in System Settings" (buton yok) |
codesign --force --sign - |
Yine adhoc, hala rejected |
| System Settings → Allow Anyway | Seçenek görünmüyor |
[!CAUTION]
Kritik Hata:syspolicydKilitlenmesi (Deadlock)
Çözüm arayışında syspolicyd arka arkaya hata verirse veyaxattrile dosyalardaki etiketleri agresif silmeye çalışırsanız, macOS Gatekeeper servisi (syspolicyd) tamamen kilitlenebiliyor (deadlock). Bu olduğunda sistem genelindeki tüm Node komutları (hatta sağlam dosyalar bile) sonsuza kadar asılı kalır. Eğer her yolu denediğiniz halde terminal kilitlenmeye devam ediyorsa servisi acilen şu komutla yeniden başlatmalısınız:sudo killall -9 syspolicyd
Kapsamlı Çözüm
Gerçek ve kalıcı bir çözüm için üç adımı da sırayla uygulamak şart:
1. Node.js'i Resmi Tarball ile Kurmak
Homebrew'un Node.js'i adhoc signed olduğu için macOS 26 tarafından reddediliyor. Resmi tarball ile kurulum çalışıyor:
# Homebrew node'u kaldır
brew uninstall node
# Resmi tarball indir
curl -L -o /tmp/node.tar.gz \
"https://nodejs.org/dist/v22.22.0/node-v22.22.0-darwin-arm64.tar.gz"
# /usr/local'e kur
sudo tar -xzf /tmp/node.tar.gz -C /usr/local --strip-components=1
# Test
node -v # v22.22.0 ✅
npm -v # 10.9.4 ✅
Not: .pkg installer'ı da denedik, o da asılı kalıyor. sudo installer -pkg komutu "Installing at base path /" mesajından sonra sonsuza kadar bekliyor. macOS'un installd daemon'u da aynı notarization kontrolüne takılıyor. Tarball + tar extract bu kontrolü bypass ediyor.
2. İçiçe Geçmiş Binary'lerin Karantinalarını (Provenance) Temizlemek
Sadece node'u düzeltmek yetmeyebilir. Özellikle claude veya popüler global framework'ler, içlerinde derlenmiş (C++/Rust) ikincil araçlar barındırırlar (örneğin uçlarda çalışan ripgrep). Bu araçlara bulaşan com.apple.provenance etiketi, Gatekeeper'ın Child Process (Alt İşlem) kalkanına çarpar. Ana Node uygulamanız düzgün çalışsa bile, altındaki araç engelleneceği için ana uygulamanız bu yüzden kilitlenir.
Bu etiketleri global klasörden topluca silmek için şu komutla süpürme yapın:
sudo xattr -r -d com.apple.provenance $(npm config get prefix -g) 2>/dev/null
3. Tüm Shebang'leri ve Symlink'leri Düzeltmek
Node çalışsa bile npm/npx'in indirdiği her paket #!/usr/bin/env node shebang'i kullanıyor. Global npm bin klasöründe dosyalar genelde symlink olduğu için klasik sed komutları başarısız olur ve hatayı gizler. Asıl dosyanın realpathini bulup değiştirmemiz gerekir.
Önceki scriptin symlink destekleyen son halini kullanın:
#!/bin/bash
# fix-node-shebangs: macOS 26 Tahoe shebang & symlink fix
# #!/usr/bin/env node → #!/usr/local/bin/node
NODE_PATH=$(which node)
fix_shebangs() {
local dir="$1"
[ -d "$dir" ] || return
local count=0
find "$dir" -type f -o -type l 2>/dev/null | while read -r f; do
# Eğer dosya sembolik link (kısayol) ise asıl hedef dosyayı bul
local real_f=$(realpath "$f" 2>/dev/null || echo "$f")
if head -1 "$real_f" 2>/dev/null | grep -q '#!/usr/bin/env node'; then
sed -i '' "1s|#!/usr/bin/env node|#!${NODE_PATH}|" "$real_f"
count=$((count + 1))
fi
done
[ $count -gt 0 ] && echo "Fixed $count shebangs in $dir"
}
# Global npm bin
fix_shebangs "$(npm config get prefix -g)/bin"
# npx cache
for d in ~/.npm/_npx/*/node_modules/.bin; do
fix_shebangs "$d"
done
Bu scripti /usr/local/bin/fix-node-shebangs olarak kaydedin, sudo chmod +x ile çalıştırılabilir yapın ve ileride her npx yüklemesinde asılı kalma hissettiğiniz an çalıştırın.
Teşhis
Eğer npx komutlarınız hata vermeden asılı kalıyorsa, aşağıdaki komutla syspolicyd loglarını kontrol edin:
log show --last 2m --predicate 'process == "syspolicyd"' --style compact | grep reject
Şu çıktıyı görüyorsanız bu sorundan etkileniyorsunuz:
syspolicyd: rejecting due to lack of matching active rule
(Loglarda hiçbir şey görmüyor ama kilitlenme yaşıyorsanız syspolicyd daemon'u deadlock olmuş demektir. Çözüm: sudo killall -9 syspolicyd)
Özet
| Sorun | macOS 26'da npx komutları sessizce asılı kalıyor |
| Neden | Gatekeeper, #!/usr/bin/env node shebang'li provenance-tagged dosyaları reddediyor |
| Belirtiler | Hata yok, çıktı yok, sonsuz bekleme (Deadlock) |
| Çözüm 1 | Node.js'i resmi tarball ile kurmak (.pkg değil, tar.gz) |
| Çözüm 2 | Çökmüş/Asılı kalmış syspolicyd servisini sıfırlamak (killall) |
| Çözüm 3 | Shebang'leri symlinkleri de (realpath) kapsayacak şekilde düzeltmek |
| Etkilenen | Homebrew Node.js, tüm npx paketleri, npm global install'lar |
macOS'un güvenlik katmanları her sürümde daha da sıkılaşıyor. macOS 26 ile adhoc signed binary'ler Gatekeeper tarafından sessizce reddediliyor ve klasik workaround'lar (xattr -cr, spctl --add, spctl --master-disable) artık çalışmıyor. Çözüm: resmi notarized binary'leri kullanmak, daemon hatalarına karşı tetikte olmak ve #!/usr/bin/env yerine doğrudan binary path'lerini kullanmak.