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:

  1. npm/npx paketi indiriyor → macOS kernel seviyesinde dosyaya com.apple.provenance etiketi yapıştırıyor
  2. npx indirdiği paketin binary'sini #!/usr/bin/env node shebang'i ile çalıştırmayı deniyor
  3. macOS bu dosyayı çalıştırmadan önce syspolicyd'ye soruyor
  4. syspolicyd Apple sunucularına bağlanıp notarization kontrolü yapıyor
  5. Binary adhoc signed 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.

Subscribe to DevOps TR

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe