macOS 26 (Tahoe) Apple Provenance ve Gatekeeper Çözümü
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, kaldırılamıyor |
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 |
Çözüm
Kalıcı çözüm için iki adımı da uygulamak gerekiyor:
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. Shebang'leri Düzeltmek
Node çalışsa bile npm/npx'in indirdiği her paket #!/usr/bin/env node shebang'i kullanıyor ve bu macOS 26'da çalışmıyor. Shebang'i doğrudan node path'ine değiştirmek gerekiyor.
Bunu otomatik yapan bir script:
#!/bin/bash
# fix-node-shebangs: macOS 26 Tahoe shebang fix
# #!/usr/bin/env node → #!/usr/local/bin/node
NODE_PATH=$(which node)
fix_shebangs() {
local dir="$1"
[ -d "$dir" ] || return
local count=0
for f in "$dir"/*; do
[ -f "$f" ] || continue
if head -1 "$f" 2>/dev/null | grep -q '#!/usr/bin/env node'; then
sed -i '' "1s|#!/usr/bin/env node|#!${NODE_PATH}|" "$f"
count=$((count + 1))
fi
done
[ $count -gt 0 ] && echo "Fixed $count shebangs in $dir"
}
# Global npm bin
fix_shebangs "/usr/local/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 ve her npm install -g veya npx sonrası ç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
Ö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 |
| Çözüm 1 | Node.js'i resmi tarball ile kurmak (.pkg değil, tar.gz) |
| Çözüm 2 | Shebang'leri #!/usr/local/bin/node olarak değiştirmek |
| 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 ve #!/usr/bin/env yerine doğrudan binary path'lerini kullanmak.