İçeriğe atla
Ayhan Sipahi Ayhan Sipahi

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).

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; ayarla salt-okunur yap
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 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_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 uzanmayı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 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.

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 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: published ve push: tags:, farklı anlarda tetiklenen farklı olaylardır; işin ham tag push’tan değil Release yaşam döngüsünden tetiklenmesi için release: published’ı tercih edin. Attestation adımını adlandırırken, actions/attest-build-provenance daha alt seviyeli actions/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.

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 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.

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 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_TOKEN varsayı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.

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

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

İlgili yazılar