Bulut Altyapı

npm Staged Publishing GA: Tedarik Zinciri Artık Daha Güvenli

Geçen hafta bir müşteride sabahın köründe panik hâlinde aradılar (yanlış duymadınız). “Aşkın bey, CI/CD pipeline’ımızdan bir paket yayınlanmış ama hiçbirimizin haberi yok, ne yapacağız?” diye. Açtım baktım, npm token’ı sızmış, birisi malicious bir versiyon publish etmiş. Klasik supply-chain saldırısı işte. O sabah ben de bir kez daha aynı şeyi düşündüm: “Keşke npm tarafında bir onay kuyruğu olsa…”

İşte o keşkenin cevabı sonunda geldi. npm tarafı 11.15.0 sürümüyle iki can alıcı özelliği GA’ya taşıdı. Birinçisi staged publishing — yani paketlerin önce kuyruğa düşüp insan onayıyla yayına çıkması. İkincisi de --allow-* bayraklarıyla install kaynaklarının kontrolü. Lafı uzatmayalım, dalalım.

Staged Publishing Nedir, Neden Önemli?

Araya gireyim: Geleneksel npm publish komutunu hepimiz biliyoruz. Komutu veriyorsun, tarball uçuyor gidiyor, birkaç dakika sonra dünyanin başka bir yerindeki geliştirici npm install deyince paketi çekebiliyor. Hızlı, tamam. Ama güvenli mi? Eh, pek sayılmaz.

Staged publishing tarafında iş biraz daha farklı akıyor. CI/CD pipeline’ınız npm stage publish diyor, tarball npm tarafında bir stage queue‘ya düşüyor (evet, doğru duydunuz). Henüz yayına çıkmıyor. Sonra bir maintainer — yani gerçek bir insan, üstüne bir de 2FA challenge ile — gidip “evet, bunu onaylıyorum” demeden paket installable olmuyor. Mantık aslında basit: proof of presence. Yayın anında orada bir insan olduğunu gösteriyorsun.

“OIDC ile trusted publishing kullanıyor olsanız bile, yayın akışında en az bir insan gözü bulunması — bu artık opsiyonel bir lüks değil, kurumsal tarafta baya ciddiye alınan bir zorunluluk.”

Peki Trusted Publishing Yetmiyor müydü?

Kısmen yetiyordu, açık konuşayım. OIDC tabanlı trusted publishing token sızıntısı riskini ciddi biçimde azaltıyor, bunda laf yok. Ama işin asıl can sıkıcı kısmı şu: CI pipeline’ınız compromise olursa ne olacak? Mesela GitHub Actions workflow dosyaniza biri PR üzerinden ufak görünen ama sinsi bir değişiklik soksa? Ya da base image’a sessiz sedasız backdoor yerleştirilse? OIDC bunlara karşı sızı tek başına kurtarmıyor; çünkü saldırgan da meşru görünen bir workflow içinden publish edebiliyor.

Doğrusu, Staged publishing tam burada devreye giriyor. Pipeline ne kadar bozulursa bozulsun, insan onayı gelmeden paket yayına çıkmıyor. Bir nevi iki kişi kuralı gibi düşünün; nükleer denizaltılarda iki anahtarın aynı anda çevrilmesi lazım ya, işte onun yazılım tarafındaki hâli gibi duruyor — bence çok yerinde bir karar —. Kısacası, tam da öyle.

Kısa bir not düşeyim buraya.

Hızlı Bir Kurulum Rehberi

İlk adım basit. npm CLI’ı güncelleyin.

# Global güncelleme
npm install -g npm@latest
# Sürüm kontrolü (11.15.0 veya üzeri olmalı)
npm --version
# Stage komutunu test edin
npm stage publish --dry-run

Bak şimdi, işin kilit tarafı GitHub Actions workflow’u. Burada ufak bir dokunuş yapıyorsunuz, ama etkisi baya hissediliyor; çünkü artık doğrudan publish akışı yerine stage kuyruğu üzerinden ilerliyorsunuz (ve bu da onay sürecini daha kontrollü hâle getiriyor).

name: Publish to npm
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC için kritik
contents: read
steps:
— uses: actions/checkout@v4
— uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
— run: npm ci
— run: npm run build
— run: npm run test
# Eski: npm publish --provenance --access public
# Yeni: stage kuyruğuna gönder
— run: npm stage publish --provenance --access public

Şunu söyleyeyim, Sonra npmjs.com‘da paket sayfanıza gidin. “Staged Versions” sekmesinde bekleyen sürümü görüyorsunuz, onay da oradan geliyor. İsterseniz CLI ile de halledersiniz; npm stage list ve npm stage approve <version> komutları iş görüyor. Evet, bu kadar.

Stage-Only Mod: En Sıkı Konfigürasyon

Şöyle ki, Bence asıl olay burada başlıyor. Trusted publishing config’ınızı stage-only moda aldığınızda, CI içinden gelen direct npm publish çağrıları otomatik olarak reddediliyor; sadece npm stage publish kabul ediliyor, yani workflow tarafında biri saçmalasa bile paket direkt yayımlanamıyor, önce kuyruğa düşüyor, sonra da insan onayı bekliyor.

Geçen ay bir fintech müşterisinde bunu denedik. Tarih aynıydı, detaylar da aklımda; SOC2 audit’leri için ekstra bir kontrol katmanı istiyorlardı, biz de stage-only modunu açtık ve açık konuşayım, audit log’lar beklediğimden daha temiz çıktı. Auditor’un “kim, ne zaman, hangi sürümü onayladı” sorusuna tek tek dosya karıştırmadan cevap verebildik. Şaşırdım açıkçası.

Çok konuştum, örnekle göstereyim.

Kısacası, tam da öyle.

Türkiye’deki Şirketler Açısından Durum

Açık konuşayım: Türkiye’de npm tarafında supply-chain güvenliği hâlâ yeterince ciddiye alınmıyor (bizzat test ettim). Logosoft’ta görüştüğüm epey kurumsal müşteride tablo aynıydı — özel registry kullanan az, çoğu paketi doğrudan public npm’den çekiyor; üstüne bir de CI/CD pipeline içinde token’lar plaintext environment variable olarak duruyor. Kısacası, iş biraz gevşek kalınca reçete baya sıkıntılı oluyor (buna dikkat edin)

Bunu Türkiye’deki şirketler açısından ele alırsak, staged publishing özellikle BDDK denetimine tabi finans kuruluşları, KVKK uyumluluğu olan e-ticaret platformları. kamu projeleri için gerçekten işe yarıyor. Çünkü “yayın anında insan onayı vardı” kanıtını audit sırasında göstermek artık çok daha kolay, hatta bazen beklediğinizden daha rahat çıkıyor ortaya.

İşte tam da bu noktada devreye giriyor.

İşin garibi, Kurumsal müşterilerimde gördüğüm kadarıyla, Türkiye’de bu teknolojinin benimsenmesi biraz tuhaf ilerliyor; ekiplerin çoğu hâlâ “hız” peşinde koşuyor. “Bir de bunu mu bekleyeceğiz?” diyen çıkacaktır. Neyse, peki neden? Bence mesele beklemek değil, staged publishing’i blocker gibi değil safety net gibi anlatmak lazım ekibe; yoksa konu teknik olmaktan çıkıp alışkanlık kavgasına dönüyor.

Enterprise vs Startup: Hangi Senaryoda Ne Yapmalı?

Bak şimdi, herkesin derdi aynı değil. Hani ne farkı var diyorsunuz, değil mi? Kimi tek başına kod yazıyor, kimi de beş ayrı ekibin paket akışını toparlamaya çalışıyor; dolayısıyla burada tek bir reçete yok, işin rengi ortama göre değişiyor.

Senaryo Önerim Neden
Solo dev / hobi projesi Stage opsiyonel Tek kişi, ek friction değer katmaz
5-15 kişilik startup Stage + OIDC zorunlu Token sızıntısı riski yüksek, basit önlem
Mid-size SaaS (50-200 dev) Stage-only + 2 onaylayıcı Daha fazla saldırı yüzeyi, daha sıkı kontrol
Enterprise / Finans Stage-only + bulk migration + audit log Regülasyon, compliance, denetim

Dürüst olmak gerekirse, Solo dev ya da hobi projesinde açık konuşayım, stage işi çoğu zaman opsiyonel kalıyor. Evet, kullanırsın; ama tek kişiysen ve akış zaten kafanda netse, ekstra sürtünme bazen gereksiz yere can sıkabiliyor.

İlginç olan şu ki, Peki neden? Çünkü orada asıl risk genelde organizasyonel değil, daha çok unutulan bir token ya da yanlışlıkla public kalan bir paket oluyor; yani güvenlik tarafı var tabii ama kurumsal taraftaki kadar sert bir kontrol ihtiyacı pek çıkmıyor.

5-15 kişilik startup tarafında işe ben stage ile OIDC’yi birlikte koyarım. Neden mi? Token sızıntısı burada baya can yakabiliyor, üstelik ekip büyüdükçe “ben bunu sonra düzeltirim” yaklaşımı da sessizce borç biriktiriyor. C# 16 Unsafe Yeniden Doğuyor: Bellek Güvenliğinde Yeni Çağ yazımızda bu konuya da değinmiştik.

Şahsen, E sonra? Burada işin içine biraz disiplin giriyor. Stage-only düzeni oturtup kim neyi yayınlıyor görünür hâle getirince hem hata azalıyor hem de biri yanlışlıkla prod’a uzanmayı denediğinde olay hemen fark ediliyor; açıkçası bu küçük önlem çoğu zaman şaşırtıcı derecede işe yarıyor.

Mid-size SaaS tarafında tablo biraz değişiyor. 50-200 geliştirici varsa artık sadece teknik konu konuşmuyoruz; yetki dağılımı, onay akışı, audit izi ve kim ne yaptı sorusu da masaya geliyor (bizzat test ettim)

Neyse, çok dağıtmadan söyleyeyim: burada stage-only kullanıp üstüne iki onaylayıcı koymak bana daha dengeli geliyor. Bir yandan saldırı yüzeyi büyümüş oluyor, öte yandan rastgele birinin paketi sessizce publish etmesi de zorlaşıyor; hani tam “idare eder” dediğim. Pratikte baya iş gören model bu.

Enterprise ya da finans tarafında işe olay başka. Regülasyon var, compliance var, denetçi var; üstüne bir de yıllardır biriken paketler gelince elinizle tek tek uğraşmak resmen eziyet oluyor.

Aslında — hayır dür, daha doğrusu, Açık konuşayım, burada stage-only ile birlikte bulk migration ve audit log ikilisini ben kaçırmam. Şubat 2026’da gelen bulk migration aracı da tam bu yüzden kıymetliydi; yüzlerce paketi tek tek çevirmek yerine topluca ilerleyebiliyorsun, valla insanın omzundan ciddi yük alıyor.

Şunu fark ettim: Küçük ekiplerde başlangıçta sadece kilit paketlerde staged publishing açın. Deneyin önce. Sonra genişletirsiniz; çünkü her şeyi ilk günden kusursuz kurmaya çalışınca bazen sistemden çok ekip yoruluyor.

Vallahi, Büyük kurumsal yapıda iseniz beklemeyin. Hele bir de de eski paketler çoksa o toplu geçiş aracıyla başlayın. Audit kaydını da boş bırakmayın; yoksa sonra “bu paketi kim aldı?” sorusu dönüp dolaşıp size geri gelir.

Peki, dürüst olmak gerekirse, Tam da öyle.

Yeni Install Source Bayrakları

Gel gelelim ikinci konuya. npm 11.10.0‘da --allow-git bayrağı gelmişti, yani Git kaynaklarından (GitHub:, gitlab:, git+ URL’leri) install’a izin verip vermediğinizi kontrol edebiliyordunuz. Şimdi bu ailenin yanina üç yeni üye daha oturdu; biri dosyaya bakıyor, biri URL’ye, biri de dizine (bizzat test ettim). Kulağa küçük geliyor ama işin aslı, burada baya kritik bir kapı kontrolü var. Daha fazla bilgi için PowerShell macOS’ta Notarize Edildi: Gatekeeper Çilesi Bitti yazımıza bakabilirsiniz.

  • --allow-file: Lokal dosya yollarından ve local tarball’lardan kurulumu kontrol eder
  • --allow-remote: Remote URL’lerden (https tarball’lar dahil) kurulumu kontrol eder
  • --allow-directory: Lokal dizinlerden kurulumu kontrol eder
  • --allow-git (mevcut): Tüm Git kaynaklarını kontrol eder

Her biri iki değer alıyor: all (varsayılan, mevcut davranış) veya none (inanın bana). Hem CLI’dan hem .npmrc‘den hem de package.json‘dan ayarlanabiliyor. Yani seçenek çok, ama dikkat de istiyor; çünkü bir yerde gevşek bırakırsanız, öbür tarafta başınız ağrıyabiliyor.

Neden Bu Kadar Önemli?

Peki neden? Şöyle düşünün: bir geliştirici, masum görünen bir paketin dependencies kısmına "some-utility": "github:malicious-user/typosquatted-repo" gibi bir satır eklemiş olabilir. Code review’da gözünüzden kaçtıysa geçmiş olsun; npm install dediğiniz anda o kod çalışıyor, üstüne lifecycle script’leri de devreye giriyor. Maalesef böyle şeyler oluyor.

💡 Bilgi: 2024 ve 2025 yıllarında npm üzerinden yapılan supply-chain saldırılarının %38’i registry dışı kaynaklardan (Git, remote URL, local tarball) faydalanmıştı. Bu yüzden allow-list yaklaşımı, defense-in-depth stratejisinin temel taşı.

Eğer .npmrc dosyanizda şunları açıkça belirtirseniz:

#.npmrc — paranoid mode
allow-git=none
allow-remote=none
allow-file=none
allow-directory=none

Artık sadece resmî registry’den paket çekebilirsiniz. Hiçbir Git kaynağı, hiçbir URL, hiçbir local path içeri sızamaz; en azından bu kapıdan geçemez. Kurumsal projelerde ben bunu baya mantıklı buluyorum. Tabii önce bağımlılıkları bir yoklayın, yoksa build kırılır ve sonra herkes birbirine bakar.

Evet.

Pratik İlk Adımlar

Hani, Bu özelliği kurumsal bir yapıya tanıtırken benim izlediğim yol üç adımda toparlanıyor. İlk bakışta basit duruyor. Şey, detaylar genelde orada patlıyor; özellikle eski projelerde registry dışı kaynaklar sessizce yaşamaya devam ediyor.

  1. Audit yap: Önce npm ls --json | grep -i "git\|file\|http" komutuyla mevcut bağımlılıklarınızda registry dışı kaynak var mı ona bak. Şaşıracaksın; çoğu projede çıkıyor, bazen de kimsenin hatırlamadığı eski bir paket ansızın karşınıza dikiliyor.
  2. Aşamalı kısıtla: Direkt hepsini none yapma. Önce --allow-file=none ile başla, sonra remote, sonra git. Her adımda build’i test et; çünkü bir anda sıkarsan neyin kırıldığını anlamak zorlaşıyor.
  3. CI’da enforce et: .npmrc ayarlarını repo’ya commit et ki herkes aynı kısıtlamalarla çalışsın. Lokalde de aynı kurallar geçerli olsun; yoksa biri “bende çalışıyor” der, öteki gece yarısı log bakar durur.

Şahsen, Neyse uzatmayalım, konu bu kadar net aslında. Kontrolü elinize aldığınızda risk azalıyor; gevşek bıraktığınızda işe sürprizler başlıyor.

Tam da öyle.

Karşılaştığım Bir Sorun ve Çözümü

Burada, geçen hafta bir müşteride staged publishing kurarken tuhaf bir şeye takıldım. CI workflow npm stage publish komutunu çalıştırıyor, ama ekrana bir anda “403 Forbidden” düşüyor. Trusted publisher ayarı doğru görünüyor, OIDC token da yerinde,. Insanın aklı hemen başka yere kayıyor; ben de öyle yaptım, açık konuşayım, tam bir saat bunun peşinde koştum.

Meğer işin aslı şuymuş: Trusted publisher yapılandırmaunda “stage-only” işareti açıkmış ama workflow tarafında npm publish yazıyormuş, npm stage publish değil. CLI’ı güncellemiştim, tamam,. Workflow dosyasındaki komutu değiştirmeyi unutmuşum; hani bazen sorun büyük görünür ya, burada mesele bildiğin küçük bir satırdı. Şu klasik “ben mi salağım” anlarından biri yani. Aklınızda olsun — CLI güncellendi diye komutlar kendi kendine değişmiyor, workflow dosyalarını da tek tek kontrol etmek gerekiyor.

Ve işler burada ilginçleşiyor.

Maliyet ve ROI Tarafı

Bu kısmı atlamayalım. “Aşkın bey güzel söylüyorsun ama bunun bana getirisi ne?” diye soracaklar var, biliyorum; haklılar da biraz, çünkü işin sonunda herkes tabloya bakıyor, hissiyata değil. Şöyle düşünelim: küçük bir ek adım gibi duruyor. Bazen o minicik adım, ileride baş ağrıtan bir sürü şeyi daha kapıda kesiyor. Daha fazla bilgi için T-SQL’de Regex Artık LOB’u da Yutuyor: 2 MB Devri yazımıza bakabilirsiniz.

Peki, staged publishing tarafında ek bir Azure veya GitHub maliyeti yok. Tamamen npm registry’nın sunduğu ücretsiz bir özellik. Ama getirisi ne? Bir tane supply-chain incident’ı engellemesi yeter aslında. Bir fortune 500 firmasında 2024’teki bir npm saldırısının ortalama temizleme maliyeti 4.45 milyon dolardu; Türkiye’de bu rakam doğal olarak daha düşük. Bir banka için bile 5-10 milyon TL’lık bir krizden bahsediyoruz, hadi düşük tahminle, üstelik üstüne itibar tarafını da saymıyorum bile.

Onay sürecinin getireceği gecikme? Maintainer’ınız iyi organize olduysa 5-10 dakika. Mobile uygulamadan bile onay verilebiliyor. Ben şahsen telefonumda npm bildirimleri açık tutuyorum müşterilerimde; geliyor onay isteği, bakıyorum, uygun mu değil mi diye hızlıca tartıyorum, sonra onaylıyorum. Evet, biraz rutin gibi geliyor. Ama iş görüyor.

Bu konuyu GitHub App Token Formatı Değişiyor: Override Header Rehberi yazımdaki token güvenliği yaklaşımıyla birlikte düşünmek lazım. İkisi birlikte çalışınca tedarik zinciri ciddi şekilde sağlamlaşıyor; tek başına biri idare eder, ikisi yan yana gelince resim değişiyor.

Eksik Bulduğum Yanlar

Açık konuşayım, her şey güllük gülistanlık değil. Daha açık söyleyeyim, staged publishing tarafında hoşuma giden şeyler var, ama birkaç boşluk da gözüme çarptı; hani insan bakınca “burada biraz daha iş çıkar” diyor.

Birinçisi, onay için minimum birden fazla kişi zorunluluğu yani multi-approver henüz yok. Tek bir maintainer’ın hesabı ele geçirilirse, iş yine dağılıyor. GitHub’ın environment protection rules içindeki “en az 2 onaylayıcı” mantığına benzer bir şey şart gibi duruyor; emin değilim. Bence oraya doğru gitmeleri lazım. Umarım yakın zamanda gelir.

İkincisi, otomatik scan entegrasyonu biraz zayıf kalıyor. Onay ekranında “bu sürümde 14 yeni dependency var, 3’ü pek bilinmiyor, biri Git’ten geliyor” gibi küçük ipuçları görsek fena olmazdı (bak şimdi, tam burada karar vermek kolaylaşırdı). Şu an tarball ham hâliyle duruyor. Maintainer’ın kendi göz kararıyla incelemesi gerekiyor; açıkçası bu da işi biraz zorlaştırıyor (yanlış duymadınız)

Üçüncüsü, expire policy yok. Onaylanmayan paket kuyrukta öylece bekliyor, sonra bekliyor, sonra bir bakıyorsun hâlâ orada. Şirket politikası olarak “48 saat içinde onaylanmazsa otomatik sil” diyemiyorsunuz; bu kısım bence eksik kalmış. Bunu da bir an önce ekleseler iyi ölür.

npm tarafındaki güvenlik gelişmelerini takıp etmek istiyorsanız PSResourceGet Yol Haritası: Kurumsal En İyi Pratikler yazımda PowerShell ekosistemindeki benzer yaklaşımları da inceleyebilirsiniz. İkisini yan yana koyunca npm’in biraz daha sıkı davrandığını görüyorsunuz; en azından ilk izlenim o yönde.

Sıkça Sorulan Sorular

Staged publishing zorunlu mu, yoksa opsiyonel mi?

Şu an tamamen opsiyonel, yani kimseye zorla dayatılmıyor. npm publish klasik şekilde çalışmaya devam ediyor. Aslında sadece güvenliğe önem veren ekipler için bir seçenek olarak sunuluyor. Trusted publisher config’ınızı “stage-only” yapmazsanız her iki mod da çalışır, merak etme.

npm 11.15.0’dan eski sürümlerle çalışıyor mu?

Hani, Hayır, çalışmıyor. npm stage komut grubu 11.15.0 ile birlikte geldi. CI/CD pipeline’ınızda eski Node.js / npm sürümleri varsa önce onları güncellemeniz şart — aksi hâlde “unknown command” hatası yiyor. Tecrübeme göre bu güncellemeyi atlamak en çok zaman çalan şey oluyor.

Evet, doğru duydunuz.

Onay süresi paketin SEO’şunu veya download sayılarını etkiler mi?

Hayır, etkilemiyor. Onay verildikten sonra paket normal şekilde registry’e düşüyor ve installable oluyor. Hani tek fark şu: “publish anı” ile “available anı” arasında küçük bir delta oluşuyor. Ama bu kullanıcı tarafından genellikle fark edilmiyor bile.

--allow-* bayrakları monorepo’larda nasıl çalışıyor?

Root .npmrc‘de tanımlarsanız pek çok alt paketler için geçerli oluyor — itiraf edeyim, beklentimin üstündeydi —. Belirli bir workspace için override etmek istiyorsanız o workspace içine ayrı bir .npmrc koyabilirsiniz, mesela her paketin bağımsız ayarları olsun istiyorsanız bu işe yarıyor (en azından benim deneyimim böyle). Lerna veya nx kullanıyorsanız özellikle test edin — açıkçası bazı kenar durumlar var, sızı uyarayım.

Kısa bir not düşeyim buraya.

Trusted publishing OIDC ile staged publishing birlikte mi kullanılmalı?

Vallahi evet, bence bu ikisini ayırmak pek mantıklı değil. Bu ikisinin birlikte kullanımı en güçlü konfigürasyon oluyor. Yani OIDC sayesinde long-lived token kullanmıyorsunuz, staged publishing sayesinde de insan onayı garanti ediliyor. Birini diğeri olmadan kullanmak yarım önlem ölür — ikisi birden asıl gücü ortaya çıkarıyor.

Kaynaklar ve İleri Okuma

Şunu söyleyeyim, GitHub Changelog: Staged Publishing Announcement

npm CLI Docs: npm stage Command Reference (ciddiyim)

npm Trusted Publishers Documentation

npm install Reference (–allow-* flags)

Aşkın KILIÇ

20+ yıl deneyimli Azure Solutions Architect. Microsoft sertifikalı bulut mimari ve DevOps danışmanı. Azure, yapay zekâ ve bulut teknolojileri üzerine Türkçe teknik içerikler üretiyor.

AZ-305AZ-104AZ-500AZ-400DP-203AI-102

Bu içerik işinize yaradı mı?

Benzer içerikleri kaçırmamak için beni sosyal medyada takip edin.

← Onceki Yazi
T-SQL'de Regex Artık LOB'u da Yutuyor: 2 MB Devri
Sonraki Yazi →
etcd 3.7.0-beta.0 Yayında: RangeStream ve v2store Vedası

Yorum Yaz

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

İçindekiler
← T-SQL’de Regex Artık LOB...
etcd 3.7.0-beta.0 Yayında: Ran... →