İçeriğe atla

GitHub Actions Tetikleyicileri: push vs pull_request vs Merge Queue vs Release

Her git olayı farklı bir işi hak eder: push, pull_request, merge kuyruğu ve tag/release'de ne çalışmalı? Lead time'ı koruyan bir GitHub Actions yönlendirme rehberi.

Ayhan Sipahi Ayhan Sipahi

Özellik commit’i push’layın, pull request açın ya da release çıkarın; birçok pipeline üçüne de aynı yanıtı verir: tam test matrisi, entegrasyon paketi ve deploy mantığının hepsi tetiklenir. Asıl sorun bu tekdüzeliktir. 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.

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.

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 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, en fazla üç seviye derinlikte). workflow_dispatch ise manuel veya API tetikleyicisidir (yalnızca default branch).

Ozellik commit'i

push: branches

PR ac / guncelle

pull_request

main'e merge

push: main

Merge kuyruguna gir

merge_group

Release cikar

release: published

Hizli geri bildirim: lint, unit, types

Merge commit'inde zorunlu kapi

Entegrasyon + staging deploy

Merge sonrasi entegrasyon kaniti

Onay arkasinda build, imzala, deploy

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.

TetikleyiciAmaçTipik kontrollerToken / secret bağlamı
push (özellik branch’i)Hızlı commit başına geri bildirimLint, unit test, tip kontrolüRepo token; ayardan salt-okunur yapın
pull_requestMerge kapısıBirleştirilmiş sonuçta zorunlu kontrollerSalt-okunur token, fork PR’larda secret yok
push (main)Merge sonrası entegrasyon, stagingEntegrasyon paketi, staging deployRepo token; güvenilir bağlam
merge_groupMerge öncesi entegrasyon kanıtıTam zorunlu kontrol setiRepo token; güvenilir bağlam
release: publishedTekrar üretilebilir imzalı buildBuild, attest, deployOnay 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 buradadır. 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_request ve pull_request_target birbirinin 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 gerekiyorsa pull_request_target’a başvurmayın. Güvenilmeyen build’i pull_request üzerinde (salt-okunur, secret’sız) çalıştırın ve çıktısını artifact olarak yükleyin; sonra o artifact’i workflow_run ile tetiklenen ayrı, ayrıcalıklı bir workflow’da işleyin.

Hayir

Evet

PR acildi veya guncellendi

Merge commit checkout refs/pull/N/merge

Zorunlu kontrolleri calistir

Tum zorunlu kontroller yesil mi?

Merge branch protection ile engellendi

PR merge edilebilir

Fork PR

Salt-okunur token, secret yok

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 yerdir. PR kapısı merge commit’ini tek başına kanıtladı; push-to-main aşaması gerçekten inen kod üzerinde çalışır ve onu bir staging ortamına yükseltir.

Ölçek büyüdükçe PR kapısında bir boşluk ortaya çıkar: 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 yerine 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. Staging deploy ise bir deployment ortamı ve bir concurrency grubu kullanarak devam eden deploy sayısını bire indirir; böylece hızlı bir kuyruk üst üste binen deploy’lar başlatmaz.

Hayir

Evet

PR A (tek basina gecti)

Gecici branch main/pr-N: hedef + kuyruktaki PR'lar

PR B (tek basina gecti)

merge_group olayi gonderildi

Birlesik sonuc uzerinde CI

Kombinasyon yesil mi?

PR kuyruktan cikarildi

main'e merge, sonra push: main calisir

Tag ve Release İşi#

Release, yazma yetkisini bilerek yükselttiğiniz 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 trafiğ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. Temel izin seti üç yetkiden oluşur: 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; temel setin parçası değildir.

Note

release: published ve push: tags:, farklı anlarda tetiklenen farklı olaylardır; işin ham tag push yerine Release yaşam döngüsünden tetiklenmesi için release: published’ı tercih edin. Attestation adımında actions/attest-build-provenance, daha alt seviyeli actions/attest’in bir sarmalayıcısıdır. Sürümünü kendi pinleme politikanıza göre sabitleyin; çünkü upload, download ve attestation action’larının hepsi kendi takviminde 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. Bu eşlemeyi tanımlayıcı kabul edin: bilinen seviye adları SLSA v1.0’dan gelir, güncel spek v1.2’dir ve varsayılan kurulum katı bir “L3” iddiasını haklı çıkarmaz.

Hayir

Evet

release: published

refs/tags/{tag} uzerinde build

Provenance attest et (Sigstore)

Ortam onaycisi onayliyor mu?

Deploy bekler veya zaman asiminda fail olur

Production'a deploy

Tuketici gh attestation verify calistirir

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 dönersiniz; ya da bir setup action’ının yönetmesine izin verirsiniz. Varsayılan cache bütçesi 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 kaldıraçtır ve iki mod bir arada kullanılmaz. 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) istersiniz; bu, iptalle birleşemez çünkü production’a hâlâ dokunan bir deploy’u iptal etmemelisiniz. Matris üçüncü kaldıraçtır: 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.

KonuCacheArtifact
AmaçNadiren değişen girdileri yeniden kullanÇıktıları tut veya geçir
ÖmürEn az kullanılan silinirBelirli bir süre saklanır
Nasıl paylaşılırAnahtarla çalıştırmalar arası geri yüklenirneeds ile geçirilir / indirilir
Tipik kullanımBağımlılıklar, build katmanlarıDerlenmiş çıktı, raporlar, fork-güvenli devir
TetikleyiciEşzamanlılık moduNeden
pull_requestcancel-in-progress: trueEn yeni commit kazanır; runner’ı serbest bırak
Deploy işiqueue: max (FIFO)Devam eden production deploy’unu asla iptal etme

Kapılar ve En Az Yetkili Token#

Tetikleyiciler işi yönlendirir, ama yönlendirme yalnızca üç mekanizmayla uygulanabilir hale gelir: branch protection veya rulesetler, deployment ortamları ve OIDC ile birlikte kullanılan en az yetkili bir token. Desen şudur: yetki tetikleyiciyle birlikte yükselir; hiçbir şey global olarak verilmez.

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 (isteğe bağlı bir kuralla kişinin kendi çalıştırmasını onaylaması engellenebilir), 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ı ile private veya internal repolardaki attestation’lar ücretli planlarla sınırlı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 yalnızca o işle sınırlı, süresi kendiliğinden 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_TOKEN varsayılanını bir repository veya organizasyon “Workflow permissions” ayarı belirler. 2023-02-02 tarihinde veya sonrasında oluşturulan repolarda varsayılan salt-okunurdur; daha eski repolarda okuma-yazmadı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.

TetikleyiciToken kapsamıSecret / cloud erişimi
push (özellik)Salt-okunurGerekmez
pull_request (fork)Salt-okunur (zorunlu)Yok
push (main)Salt-okunur varsayılan, iş başına yükseltYalnızca staging
release: publishedcontents: read, id-token: write, attestations: writeOIDC 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#

Üzerinde durulması gereken kısım sınırdır. Yazma yetkilerini global 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. Sıradaki adım bir denetim: 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#

İlgili yazılar