Hangi CI Adımı Hangi Tetikleyicide Çalışır
Her git olayı farklı bir işi hak eder. push, pull_request, merge kuyruğu ve tag/release'de ne çalışmalı ve bu, lead time'ı neden korur? Bir GitHub Actions yönlendirme rehberi.
Çoğu pipeline aynı kontrol setini her olayda çalıştırır: tam test matrisi, entegrasyon paketi ve deploy mantığı; bir geliştirici özellik commit’i attığında da, pull request açtığında da, release çıkardığında da hepsi tetiklenir. Asıl sorun bu tekdüzeliktir, çünkü her git olayı yaşam döngüsünün farklı bir noktasında gelir ve farklı bir güvenlik bağlamı taşır; bir tetikleyiciye ait olan kontrol, başka bir tetikleyicide ya israftır ya da tehlikelidir. Bunun yerine on: bloğunu bir yönlendirme tablosu gibi ele alın: kontrolü tetikleyiciye eşleyin ki PR geri bildirimi hızlı kalsın, main deploy edilebilir kalsın ve release’ler tekrar üretilebilir kalsın. CI kurulumunun sahibi neyin nerede çalışacağına karar verir.
Ana eksen Compressing Time to Production yazısındakiyle aynıdır: lead time’ı korumak. Her push’ta her şeyi çalıştırmak teslimatı güvenli yapmaz; geri bildirimi yavaşlatır ve henüz incelemediğiniz koda yetki sızdırır. Çözüm yönlendirmedir.
Tetikleyici Yönlendirme Tablosu
GitHub Actions’ta on: olayları birbirinin yerine geçen etiketler değildir. Her biri farklı bir yaşam döngüsü anında tetiklenir ve işe farklı bir token ile secret bağlamı verir. Önce tetikleyiciyi seçin, sonra işin ne yapacağına karar verin.
Bir push, commit push’larında ve tag push’larında tetiklenir; branches, tags veya paths ile kapsamı daraltılır (branch ve path filtreleri AND ile birleşir). Bir pull_request, bir PR açıldığında, güncellendiğinde veya yeniden açıldığında çalışır ve branch ucunu değil, birleştirilmiş sonucu test eder. Merge kuyruğu, toplu bir kombinasyon için kontrol istediğinde kendi olayını, merge_group’u, gönderir. Bir release, Release nesnesinin yaşam döngüsünden tetiklenir; bu, push: tags: olayının gözlemlediği ham tag push’tan farklı bir andır. Tabloyu iki tetikleyici daha tamamlar. workflow_run bir workflow’u başka birinden zincirler (yalnızca default branch, GitHub dokümanlarına göre en fazla üç seviye). workflow_dispatch ise manuel veya API tetikleyicisidir (yalnızca default branch, GitHub dokümanlarına göre sınırlı sayıda input ile).
Aşağıdaki tablo aynı haritanın tablo halidir. Token ve secret sütunu çoğu ekibin atladığı kısımdır ve bir tetikleyicide ayrıcalıklı iş çalıştırmanın güvenli olup olmadığına karar veren kısımdır.
| Tetikleyici | Amaç | Tipik kontroller | Token / secret bağlamı |
|---|---|---|---|
push (özellik branch’i) | Hızlı commit başına geri bildirim | Lint, unit test, tip kontrolü | Repo token; ayarla salt-okunur yap |
pull_request | Merge kapısı | Birleştirilmiş sonuçta zorunlu kontroller | Salt-okunur token, fork PR’larda secret yok |
push (main) | Merge sonrası entegrasyon, staging | Entegrasyon paketi, staging deploy | Repo token; güvenilir bağlam |
merge_group | Merge öncesi entegrasyon kanıtı | Tam zorunlu kontrol seti | Repo token; güvenilir bağlam |
release: published | Tekrar üretilebilir imzalı build | Build, attest, deploy | Onay arkasında yükseltilmiş yazma yetkisi |
Pull Request Kapısı
pull_request tetikleyicisi merge kararının uygulandığı yerdir; bu yüzden zorunlu kontrolleri taşır ve ayrıcalıklı hiçbir iş taşımaz. Varsayılan olarak opened, synchronize ve reopened etkinlik türlerinde çalışır ve PR branch ucu yerine merge commit’ini (refs/pull/N/merge) checkout eder. Bu detay önemlidir: CI, branch’i tek başına değil, PR’ı base’e birleştirmenin sonucunu test eder ve PR çakışma içerdiğinde hiç çalışmaz. Gerçekten inecek olan şeyi test ediyorsunuz.
Bu tetikleyicideki bir kontrol, siz onu zorunlu yapana kadar tavsiye niteliğindedir. Bir kontrolü kapıya çeviren şey branch protection veya bir ruleset’tir; bu olmadan kırmızı bir build yine de merge olabilir. “Kapı yanlış yerde” sorununun en yaygın hali budur: kontrol çalışır, ekip ona güvenir ve başarısız olduğunda merge’i hiçbir şey durdurmaz.
Güvenlik sınırı da burada yaşar. Bir fork’tan açılan pull request salt-okunur bir GITHUB_TOKEN alır ve repository secret’larına erişemez. Fork için güvenli bağlam budur: güvenilmeyen katkıcı kodu cloud kimlik bilgilerinizi okuyamaz veya reponuza push yapamaz.
Warning:
pull_requestvepull_request_targetbirbirinin yerine geçmez.pull_request_target, base-repo bağlamında yazma yetkisi olan bir token ve tam secret erişimiyle çalışır. Bunu güvenilmeyen PR head’inin checkout’uyla birleştirince GitHub Security Lab’ın belgelediği “pwn request” açığı ortaya çıkar: saldırgan kontrolündeki kod sizin secret’larınızla çalışır. Güvenilmeyen kodu build etmeniz ve secret da kullanmanız gerekiyorsapull_request_target’a uzanmayın. Güvenilmeyen build’ipull_requestüzerinde (salt-okunur, secret’sız) çalıştırın ve çıktısını artifact olarak yükleyin; sonra o artifact’iworkflow_runile tetiklenen ayrı, ayrıcalıklı bir workflow’da işleyin.
Main’e Merge Aşaması
Main’e bir merge, main’e bir push’tur; bu yüzden on: push: branches: [main] merge sonrası entegrasyon ve staging deploy için doğal evdir. PR kapısı merge commit’ini tek başına kanıtladı; push-to-main aşaması gerçekten inen şeye karşı çalışır ve onu bir staging ortamına yükseltir.
Ölçek büyüdükçe PR kapısının bir boşluğu olur: her biri tek başına geçen iki PR, birleştirildiğinde bozulabilir. Merge kuyruğu bu boşluğu kapatır. Geçici bir branch (hedef artı kuyruktaki PR’lar, main/pr-N gibi adlandırılan) oluşturur ve merge_group olayını gönderir; böylece CI, herhangi bir tek PR’ı değil, merge sonrası kombinasyonu çalıştırır. İşin püf noktası bağlantıdır. Bir zorunlu kontrol workflow’a göre eşleşir ve zorunlu-kontrol workflow’unuz merge_group’a abone olmazsa, kontrol kuyruktaki kombinasyonda hiç raporlanmaz ve merge süresiz takılır. Çözüm on: bloğunda tek bir satırdır.
on:
pull_request:
merge_group:
Bu parça, tüm modeldeki tek olmazsa-olmaz yapılandırmadır. Geri kalan her şey yönlendirme kararıdır; bu, eksik bir tetikleyicinin kuyruğu sessizce bozduğu tek yerdir. Build eşzamanlılığı kuyruk çalıştırmalarının kaçının aynı anda yürüyeceğini sınırlar (GitHub dokümanlarına göre sınırlı bir aralık). Staging deploy ise bir deployment ortamı artı bir concurrency grubu kullanarak tek bir devam eden deploy’la sınırlar; böylece hızlı bir kuyruk üst üste binen deploy’lar başlatmaz.
Tag ve Release İşi
Release, yazma yetkisini yükseltmenin tesadüfen değil, bilerek yapıldığı tek tetikleyicidir. release: published’a abone olun ve iş tag’de (refs/tags/<tag>) çalışır; bu, build, imzalama ve deploy için sabit, tekrar üretilebilir noktadır. published’a abone olmak hem kararlı release’leri hem de ön sürümleri kapsar; taslak hareketliliğini ise pipeline’ın dışında tutar.
İmzalı provenance üretmenin yeri burasıdır. GitHub Artifact Attestations, Haziran 2024’ten beri genel kullanıma açıktır; üretilen artifact’i onu üreten workflow çalıştırmasına bağlayan, Sigstore destekli bir attestation üretir; tüketici bunu gh attestation verify ile doğrular. İzin temeli üç yetkidir: imzalama kimliğini üretmek için id-token: write, kaynağı okumak için contents: read ve attestation’ı kaydetmek için attestations: write. packages: write’i yalnızca bir container imajı da push ediyorsanız ekleyin; temelin parçası değildir.
Note:
release: publishedvepush: tags:, farklı anlarda tetiklenen farklı olaylardır; işin ham tag push’tan değil Release yaşam döngüsünden tetiklenmesi içinrelease: published’ı tercih edin. Attestation adımını adlandırırken,actions/attest-build-provenancedaha alt seviyeliactions/attest’in bir sarmalayıcısıdır. Bu action’lara isimle başvurun ve sürümü pinleme politikanız seçsin; çünkü upload, download ve attestation action’larının hepsi kendi takvimlerinde major sürüm değiştirir.
Attestation’lar SLSA Build Level 2 şekline karşılık gelir: barındırılan bir build platformu, bir tüketicinin doğrulayabileceği imzalı provenance üretir. Bunu sertifikalı bir derece değil, tanımlayıcı bir eşleme olarak ele alın; SLSA v1.0 seviyeleri alıntılamaya değer, ama v1.2 güncel spektir, bu yüzden kutudan çıkan kurulum için katı bir “L3” iddiası ileri sürmeyin.
Build İşinin Kendisi
Build işi tetikleyiciden bağımsızdır. Aynı derle-ve-test mantığı bir push’ta, bir PR’da veya bir release’de çalışabilir; tetikleyici ise bunun ne kadarının çalışacağına ve çalıştırmanın yük altında nasıl davranacağına karar verir. Her kontrolün anlamını değiştirmeden maliyeti şekillendirdiğiniz yer burasıdır.
İki depolama mekanizması karıştırılır ve zıt amaçlara hizmet eder. Bir cache, nadiren değişen girdileri tutar; böylece onları her çalıştırmada yeniden çekmezsiniz. Onu bir lockfile hash’i gibi bir şeyle anahtarlar ve restore-keys ile yakın bir eşleşmeye geri düşersiniz; ya da bir setup action’ının yönetmesine izin verirsiniz. Varsayılan cache bütçesi GitHub dokümanlarına göre repo başına yaklaşık 10 GB’tır ve en az kullanılan önce silinir. Bir artifact ise tutmak veya needs ile sonraki bir işe geçirmek istediğiniz çıktıları tutar; fork için güvenli desenin kanalı budur: güvenilmeyen build yükler, ayrıcalıklı iş indirir.
Eşzamanlılık diğer koldur ve iki mod birbirine karışmaz. PR’larda cancel-in-progress: true istersiniz; böylece yeni bir push, eski commit üzerinde hâlâ çalışan çalıştırmanın yerine geçer. Deploy’larda ise kuyruk modunu (queue: max, FIFO, GitHub dokümanlarına göre sınırlı bekleyen sayısıyla) istersiniz; bu, iptalle birleşemez çünkü production’a hâlâ dokunan bir deploy’u iptal etmemelisiniz. Matris üçüncü koldur: her kombinasyon için bir iş çalıştırır, bu yüzden onu tetikleyiciye göre daraltın. Main ve release’lerde tam matrisi, PR’larda küçültülmüş bir matrisi çalıştırın.
| Konu | Cache | Artifact |
|---|---|---|
| Amaç | Nadiren değişen girdileri yeniden kullan | Çıktıları tut veya geçir |
| Ömür | En az kullanılan silinir | Belirli bir süre saklanır |
| Nasıl paylaşılır | Anahtarla çalıştırmalar arası geri yüklenir | needs ile geçirilir / indirilir |
| Tipik kullanım | Bağımlılıklar, build katmanları | Derlenmiş çıktı, raporlar, fork-güvenli devir |
| Tetikleyici | Eşzamanlılık modu | Neden |
|---|---|---|
pull_request | cancel-in-progress: true | En yeni commit kazanır; runner’ı serbest bırak |
| Deploy işi | queue: max (FIFO) | Devam eden production deploy’unu asla iptal etme |
Kapılar ve En Az Yetkili Token
Tetikleyiciler işi yönlendirir, ama yalnızca üç mekanizma aracılığıyla uygulanabilir hale gelir: branch protection veya rulesetler, deployment ortamları ve OIDC ile eşleşen en az yetkili bir token. Desen şudur: yetki, küresel olarak verilmek yerine tetikleyiciyle birlikte yükselir.
Branch protection ve rulesetler, PR bölümünde anlatıldığı gibi bir kontrolü zorunlu yapan şeydir. Deployment ortamları insan kapısını ekler: zorunlu onaylayıcılar (GitHub dokümanlarına göre sınırlı sayıda, isteğe bağlı kendini-onaylamayı-engelle kuralıyla), bir çalıştırma onay beklerken “Waiting” durumu, onay penceresi geçince otomatik başarısızlık, faturalandırılmayan bir bekleme zamanlayıcısı ve hangi ref’lerin deploy edebileceğini sınırlayan branch veya tag politikaları. Bu, yukarıdaki diyagramda release deploy’unun önünde duran onaydır. Ortam koruma kuralları ve özel veya internal repolarda attestation’lar ücretli katmanlara plan-bağlıdır; public repolarda tüm planlarda mevcuttur.
Token son parçadır. Bir permissions: bloğu bildirmek, listelenmeyen her yetkiyi none’a ayarlar; yazma okumayı kapsar ve güvenli şekil, kısıtlayıcı bir üst seviye blok artı yalnızca bir işin ihtiyacı olduğu yerde iş başına yükseltmedir. OIDC, uzun ömürlü cloud secret’larını tamamen kaldırır: permissions: id-token: write çalıştırma başına bir JWT üretir, cloud’unuz bunu bir kez yapılandırdığınız güven ilişkisine karşı doğrular ve o tek işe kapsamlı, kendi kendine süresi dolan bir kimlik bilgisi döner. Dikkat edin: id-token: write yalnızca JWT’yi isteme yeteneğini verir; herhangi bir kaynağa yazma erişimi vermez.
Warning:
GITHUB_TOKENvarsayılanı, sabit bir değer değil, bir repository veya organizasyon “Workflow permissions” ayarıdır. 2023-02-02 tarihinde veya sonrasında oluşturulan repolar salt-okunur’a varsayılır; eski repolar yazma-okuma’ya varsayılır. Bunu denetleyin ve varsayılanı salt-okunur yapın, sonra workflow başına yükseltin. Token’ın zaten salt-okunur olduğunu varsaymayın.
| Tetikleyici | Token kapsamı | Secret / cloud erişimi |
|---|---|---|
push (özellik) | Salt-okunur | Gerekmez |
pull_request (fork) | Salt-okunur (zorunlu) | Yok |
push (main) | Salt-okunur varsayılan, iş başına yükselt | Yalnızca staging |
release: published | contents: read, id-token: write, attestations: write | OIDC ile production, onay arkasında |
En az yetki ve OIDC mekaniği Security Without the Review Queue yazısıyla örtüşür; o yazı kapı-ve-token tarafını derinlemesine ele alır; buradaki odak ise her yetkinin hangi tetikleyiciye ait olduğudur. Client tarafı release açısı için The Client You Cannot Roll Back yazısı, gönderdiğinizi geri çağıramadığınızda release tetikleyicisinin neden ekstra ağırlık taşıdığını anlatır.
Maliyet ile Tetikleyici Arasındaki Sınır
Her tetikleyiciyi işine eşleyin ve pipeline kendini yönlendirir: bir özellik-branch push’u hızlı geri bildirimi hak eder, bir pull_request birleştirilmiş sonuçta zorunlu kapıyı hak eder, merge_group entegrasyon kanıtını hak eder ve release: published insan onayı arkasında tekrar üretilebilir imzalı build’i hak eder. Her olay, yaşam döngüsü anına ve güvenlik bağlamına uyan kontrolü çalıştırır; PR geri bildirimini hızlı ve main’i deploy edilebilir aynı anda tutan şey budur.
Üzerinde durulması gereken kısım sınırdır. Yazma yetkilerini küresel olarak vermeyin, çünkü izin veren bir varsayılan, fork PR’larına ve güvenilmeyen koda yetki sızdırır. Tam matrisi her push’ta çalıştırmayın, çünkü bu dakikaları yakar ve tüm modelin korumayı amaçladığı geri bildirimi yavaşlatır. Tek sonraki adım bir denetimdir: hangi workflow’un hangi olayda çalıştığını ve her birinin hangi token kapsamını tuttuğunu listeleyin, sonra uyumsuz olan her şeyi taşıyın.
Kaynaklar
- Events that trigger workflows — GitHub Docs - Olay başına referans ve yönlendirme haritasının kaynağı.
- Managing a merge queue — GitHub Docs -
merge_groupolayı, geçicimain/pr-Nbranch’i ve zorunluon: merge_group:bağlantısı. - About protected branches — GitHub Docs - Bir kontrolün nasıl zorunlu durum kontrolü olduğu.
- Preventing pwn requests — GitHub Security Lab -
pull_request_targettehlikesi ve güvenli artifact-devir deseni. - Using artifact attestations to establish provenance — GitHub Docs - Provenance izinleri ve
gh attestation verifyile doğrulama. - Artifact Attestations is generally available — GitHub Changelog - Genel kullanıma açılma duyurusu.
- SLSA • Security levels (v1.0) - Build track seviyeleri L1’den L3’e (v1.2’nin güncel spek olduğuna dikkat).
- Managing environments for deployment — GitHub Docs - Zorunlu onaylayıcılar, bekleme zamanlayıcısı ve deploy branch politikaları.
- Security hardening with OpenID Connect — GitHub Docs - OIDC ile kısa ömürlü, tek-işe kapsamlı cloud kimlik bilgileri.
- Control workflow concurrency — GitHub Docs -
cancel-in-progressvequeue: maxkarşılaştırması. - Authentication in a workflow (GITHUB_TOKEN) — GitHub Docs - İzin semantiği ve en az yetki varsayılanları.
- Dependency caching — GitHub Docs - Cache anahtarları, restore-keys ve repo başına üst sınır.
İlgili yazılar
Yüksek performanslı ekiplerin kod-tamam ile canlı arasındaki süreyi güvenlik ve kalite ödün vermeden nasıl kısalttığı. Teknik liderler için bir karar rehberi.
Yüksek performanslı ekiplerin güvenlik incelemesini üretime çıkış darboğazına çevirmeden nasıl yönettiği: shift-left otomasyon, risk-tabanlı kapılar, hazır yol ve bağımlılık ritmi.
Üretim deploy'ları gerçek bir onay adımı ister: GitHub Environment, native koruma kuralları ve environment'a bağlı secret'lar; if: hilesi ya da marketplace değil.
Organizasyon düzeyinde paylaşımlı bir GitHub Actions platformu kurma rehberi: mimari kararlar, güvenlik yönetişimi, benimseme ve en maliyetli 7 hata.
Anthropic'in claude-code-action'ını bir GitHub repo'suna eklemek için sıkılaştırılmış, kopyalanmaya hazır kurulum; güvenlik ve maliyet ayarlarıyla.