2026-05-19
GitHub Actions'ta Üretim Onayı: Environment Kullan, if: Değil
Üretim deploy'ları gerçek bir onay adımı ister. Doğru yer: GitHub Environment, native koruma kuralları ve environment'a bağlı secret'lar; if: hilesi ya da üçüncü parti onay action'ı değil.
Üretim deploy’larında insan onayı gerekir, ama çoğu ekip yanlış parçayı seçer. En sık görülen üç şekil şudur: bir label’a bakan workflow if: koşulu, issues: write izniyle yorum bekleyen marketplace onay action’ı, ya da herkesin tetikleyebildiği workflow_dispatch butonu. Artifact’ı main üzerinden bir kez üretin, staging’e otomatik düşsün, aynı artifact production’a ancak bir PM ya da QA bir GitHub Environment kapısında onay verdikten sonra promote edilsin. Stage başına yeniden build yok — aynı artifact, iki environment, tek onay; insanı ve credential’ı aynı kapının arkasına koyan ve run’a bağlı audit kaydı bırakan tek şekil budur.
Environment nedir
GitHub Environment, repo üzerinde adlandırılmış bir nesnedir ve üç şey tutar: environment secret’ları, environment variable’ları ve deployment protection rule’lar. UI’da Settings → Environments altında, REST API’da /repos/{owner}/{repo}/environments adresinde yaşar. Bir job environment: ile bir environment’ı hedef aldığında, koruma kuralları geçmeden ne secret’ları çözebilir ne de adımlarını çalıştırabilir. Koruma kuralı ile secret erişimi aynı kapıdır; bu özellik soyutlamayı değerli kılan şeydir.
Üç deployment protection rule
Bunlar branch protection rule değil. Branch protection (ve yeni repository ruleset’ler) main’e merge’ü kapatır. Deployment protection rule ise Environment nesnesinde yaşar ve o environment’ı hedefleyen deploy’u kapatır; merge’ten sonra, bir job artifact’ı alıp deploy etmeye çalıştığında devreye girer. GitHub üç tane sunuyor.
Required reviewers. En fazla altı kullanıcı veya takım. Onaycıların repo’ya en azından read erişimi olmalıdır. Listedeki onaycılardan yalnızca birinin onay vermesi yeterlidir; diğerleri görmezden gelebilir. Onay formundaki yorum kutusu run başına audit izini taşır. Prevent self-review anahtarı vardır ve default’u kapalıdır; her üretim environment’ında bunu açın.
Wait timer. 1 ile 43.200 dakika (30 gün) arasında bir değer. Deploy job’ı tetiklendikten sonra bu süre boyunca Waiting durumunda bekler. Bekleme süresi faturalandırılan Actions dakikalarına dahil edilmez.
Deployment branch and tag policies. Üç mod: kısıtlama yok, sadece protected branch’ler, ya da isim deseniyle seçilen branch ve tag’ler (main, release/*, v*.*.*). Hangi ref’lerin bu environment’a deploy talebi açabileceğini filtreler; bu olmadan bir feature branch kapıda bekleyip onay isteyebilir.
Bir de kaçış kapısı var. Bir job, job-level deployment: false (Mart 2026) ayarıyla bir environment’ı hedef alabilir; kapıda kuyruklanmaz, deployment kaydı oluşmaz. Bu, plan-only iş yükleri için doğru şekildir — terraform plan, dry-run build, manifest üretici gibi environment secret’ına read erişimi isteyen ama onaya düşmemesi gereken job’lar. Kısıtlama: deployment: false, custom deployment protection rule’lar ile birlikte kullanılamaz; özel kural taşıyan bir environment’ı hedef alan her job hâlâ auto-deploy gerektirir.
Adım adım kurulum
Bir tag, iki environment, tek onay. main üzerine atılan bir tag artifact’ı bir kez üretir, registry’ye push’lar ve staging’e otomatik deploy eder. Ayrı bir workflow_dispatch workflow’u aynı image’ı production’a promote eder ve Environment kapısında PM ya da QA onayını bekler. Build stage başına tekrar etmez; production’a giden byte’lar staging’i geçen byte’larla aynıdır.
# .github/workflows/release.yml
# main'e tag push'unda: artifact bir kez build edilir, staging'e otomatik deploy edilir.
name: release
on:
push:
tags: ['v*.*.*']
permissions:
contents: read
packages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
outputs:
image: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
steps:
- uses: actions/checkout@v6
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.example.com
steps:
- uses: actions/checkout@v6
- run: ./deploy.sh staging "${{ needs.build.outputs.image }}"
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
staging yine bir Environment’tır — staging deploy credential’ını, staging URL’sini ve dilerseniz bir tag policy’sini tutar. Required reviewer yoktur, dolayısıyla deploy job’ı build biter bitmez çalışır.
Production ayrı bir workflow’ta yaşar. Input olarak bir tag alır, asla yeniden build etmez ve registry’deki mevcut image’ı çeker. production Environment’ı required-reviewers listesini taşır; bir PM ya da QA onaylayana kadar run kapıda bekler.
# .github/workflows/promote.yml
# Mevcut bir image'i production'a manuel promote. Required reviewer kapida bekletir.
name: promote
on:
workflow_dispatch:
inputs:
tag:
description: 'Promote edilecek release tag (orn. v1.4.2)'
required: true
concurrency:
group: deploy-production-${{ inputs.tag }}
cancel-in-progress: false
permissions:
contents: read
packages: read
id-token: write
jobs:
deploy-production:
runs-on: ubuntu-latest
environment:
name: production
url: https://app.example.com
steps:
- uses: actions/checkout@v6
- run: ./deploy.sh production "ghcr.io/${{ github.repository }}:${{ inputs.tag }}"
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
DEPLOY_TOKEN her Environment’ta ayrı bir environment secret’ı olarak yaşar — staging deploy staging token’ını, production deploy production token’ını okur; iki workflow birbirinin secret’ına dokunamaz. id-token: write izni, deploy adımının OIDC token üretip kısa ömürlü cloud credential alabilmesi içindir. production Environment’ına v*.*.* desenli bir tag policy koymak, promote workflow’unun yalnızca release tag’leriyle çalışmasını sağlar; workflow_dispatch’i bir feature branch adıyla tetikleyen biri kapıda durur. promote.yml’in başındaki concurrency bloğu da aynı tag için iki eşzamanlı promote denemesinin yarışmasını engeller; ikincisi birincisi bitene kadar kuyrukta bekler.
Onaycı tarafı şöyle işler: deploy yetkili biri gh workflow run promote.yml -f tag=v1.4.2 der ya da UI’da Run workflow der. GitHub deploy-production job’ını kuyruğa alır, Deployments görünümüne yazar ve listedeki onaycılara mail atar. Onaycı Review deployments der, production’ı işaretler, dilerse bir yorum yazar ve Approve and deploy ya da Reject der. Yorum, audit string’i olarak saklanır.
Aynı akışın API tarafı, change ticket bot’ları için faydalıdır:
# Mevcut bir tag'e karşı promote workflow'unu tetikle
gh workflow run promote.yml -f tag=v1.4.2
# Olusan run id'sini bul
gh run list --workflow=promote.yml --limit 1
# O run icin bekleyen onaylari listele
gh api /repos/OWNER/REPO/actions/runs/RUN_ID/pending_deployments
# API uzerinden onayla
gh api -X POST /repos/OWNER/REPO/actions/runs/RUN_ID/pending_deployments \
-F environment_ids[]=PROD_ENV_ID \
-F state=approved \
-F comment="CHG-12345 ile onaylandı"
state değeri approved ya da rejected olur. Reddedilen run, deploy-production job’ını durdurur ve production environment’ını o run için failed olarak işaretler; image registry tag’inde olduğu gibi durur. Rollback aynı akıştır, sadece tag farklı: en son sağlam v*.*.* ile promote.yml’i tetikleyin, kapıda onaylayın, deploy edin. Artifact değişmez olduğu için ayrı bir rollback workflow’una ihtiyaç yoktur.
Sık atlanan ayarlar
En çok kaçırılan üç şey YAML’da değil, environment ayarlarındadır.
Kendi kendine onay default’u
Default’ta deploy’u tetikleyen kullanıcı, required-reviewers listesinde de yer alıyorsa kendi deploy’unu onaylayabilir. Görev ayrımı (separation of duties) zorunluluğu olan ekipler için bu yanlış bir default’tur. Prevent self-review anahtarı Ekim 2023’ten beri environment ayar sayfasında durur ve tek tıklamayla açılır; workflow tarafına bir etkisi yoktur. Bunu repo bazında bir karar değil, environment template’inin parçası olarak ele alın.
Onaycı takımlar mı, kişiler mi
Required-reviewers listesi kendi başına bir listedir. CODEOWNERS değildir ve CODEOWNERS kuralları buraya akmaz. Onaycı rotasyonunun environment ayarları yerine takım üyeliğinde yaşaması için kişi yerine takım ekleyin. Birey eklerseniz, birisi her takım değiştirdiğinde environment ayarlarını düzelten kişi siz olursunuz.
Asıl kapı: environment secret’ı
Environment’ın güvenlik gerekçesi insan duraklaması değil, deploy credential’ının kapı geçene kadar okunamaz olmasıdır. Repo secret’ı, repo’daki her workflow tarafından çözülebilir; PR tetiklemeli akışlar ya da label hilesiyle atlatılmış onay yolları da buna dahildir. Environment secret’ı, ancak environment: hedefinin koruma kurallarını geçtiği bir job tarafından çözülebilir. Üretim token’ınız repo secret’ındaysa kapınız YAML’da bir yorumdur, gerçek bir sınır değil.
Hangi durumlarda kullanmayın
Environment’ın doğru cevap olmadığı üç durum.
GitOps repo’ları. Rollout’u Argo CD ya da Flux yönetiyorsa, GHA workflow yalnızca bir PR açar ya da manifest push’lar. Onay kapısı, sync politikasının yaşadığı CD controller’a aittir. PR açan workflow’a Environment koymak insanı yanlış noktaya yerleştirir.
Repo’lar arası orchestration. Bir orchestrator workflow başka repo’larda child workflow’lar tetikliyorsa, kapı orchestrator’da olur. Hem orchestrator’ı hem de child’ları kapı arkasına koyarsanız tek deploy için iki onay sorulur ve onaycılar bir süre sonra okumadan onaylar.
Deploy hedefi olmayan job’lar. Housekeeping cron’ları, dependency-update bot’ları ve üretim hedefi olmayan diğer iş yükleri Environment istemez. Checklist tutturmak için eklemek, güvenlik kazancı olmadan sürtünme yaratır.
GHEC, GHES, Free planı
Plan kapsamı, ikincil yazıların çoğunun yanlış yaptığı kısımdır. Yayın zamanında GitHub Plans sayfasıyla doğrulayın; wording zaman zaman değişiyor. Güncel docs’a göre:
- Free. Environment’lar public repo’larda koruma kuralları dahil çalışır. Private repo’larda environment nesnesi vardır ama required reviewer ve wait timer sunulmaz.
- Pro ve Team. Environment’lar private repo’larda çalışır. Required reviewer ve wait timer ise bu planlarda yalnızca public repo’larda kullanılabilir.
- Enterprise. Required reviewer, wait timer, branch policy ve custom deployment protection rule’ların hepsi private ve internal repo’larda çalışır.
Üretim kodunuz Pro ya da Team planındaki bir private repo’da yaşıyorsa, elde ettiğiniz tek deployment protection rule branch ve tag policy’sidir. Bu, feature branch’in üretim deploy’u talep etmesini durdurur ama reviewer kapısı değildir. İnsan onayı ve audit kaydı için Enterprise gerekir.
Custom deployment protection rule
“Şu an deploy edebilir miyiz?” sorusunun kaynağı GitHub dışında yaşıyorsa, bir GitHub App’i custom deployment protection rule olarak kaydedebilirsiniz. App deployment_protection_rule webhook’una abone olur ve REST API’ye geri dönüş yaparak onaylar ya da reddeder. ServiceNow change window’u, Datadog deploy gate, Honeycomb SLO kontrolü ya da kendi ticket sisteminizle entegrasyon noktası budur. Public-beta duyurusu Nisan 2023 tarihli; docs sayfası artık beta etiketi taşımıyor, ama compliance tasarımına yerleştirmeden önce bağlantılı dokümandaki güncel ifadeyi teyit edin.
Trade-off açıktır: dış sistem deploy’u durdurabilen bir bağımlılık olur ve GitHub App’in diğer kritik entegrasyonlar kadar ops dikkati ister. Mevcut bir change-management sistemi varsa ve gerçek kayıt kaynağı oysa kullanın. Sırf modern görünmek için kurmayın.
Kapanış
Artifact’ı main üzerinden bir kez üretin, staging’e otomatik düşürün, aynı artifact’ı required reviewer arkasında production’a promote edin. Deploy credential’larını her Environment’ın kendi secret’larına koyun, repo secret’ına değil. Prevent self-review anahtarını açın. Production environment’ına v*.*.* desenli bir tag policy koyun, yalnızca release tag’leri promote edebilsin. Sınır durumları nettir: GitOps controller’lar kendi kapılarını kurar, orchestrator’lar child’larını yönetir, housekeeping job’ları hiçbirini istemez. Geri kalan her şey default’a oturur.
Kaynaklar
- Using environments for deployment - GitHub Docs - Environment nesnesi, secret’lar, variable’lar ve koruma kuralları için birincil dokümantasyon.
- Deployment protection rules - GitHub Docs - Required reviewer (en fazla 6), wait timer (1-43.200 dakika), branch ve tag policy, prevent self-review anahtarı.
- Reviewing deployments - GitHub Docs - Onaycının UI’da neyi gördüğü ve yorum kutusunun audit izini nasıl bıraktığı.
- REST API: pending deployments - GitHub Docs - Bekleyen deployment’ı onaylama veya reddetme için endpoint ve payload.
- Configuring custom deployment protection rules - GitHub Docs - ServiceNow, Datadog ve benzeri sistemler için GitHub App tabanlı dış kapılar.
- Security hardening for GitHub Actions - GitHub Docs - Environment secret’ı ile repo secret’ı farkı, OIDC ve üçüncü parti action sabitleme.
- Workflow syntax: jobs.job_id.environment - GitHub Docs -
environment:alanının kısa ve uzun form YAML referansı. - GitHub blog: custom deployment protection rules (public beta) - Custom deployment protection rule’ların ilk duyurusu; docs sayfası artık beta etiketi taşımıyor.
- GitHub Actions: Mart 2026 sonu güncellemeleri - Changelog - Job-level
deployment: falseanahtarı; environment secret’larına onay kuyruğuna girmeden ve deployment kaydı oluşturmadan erişim verir, custom deployment protection rule’larla birlikte kullanılamaz. - Using OpenID Connect with cloud providers - GitHub Docs - Kısa ömürlü cloud credential için environment scope ile OIDC eşleştirmesi.
- Automatic token authentication - GitHub Docs - Environment hedefleyen deploy job’ları için en az ayrıcalık permissions bloğu.
- GitHub Plans pricing - Free, Pro, Team ve Enterprise planlarında private repo’lar için deployment protection rule kapsamı.
İlgili yazılar
Organizasyon düzeyinde paylaşımlı bir GitHub Actions platformu kurmak için pratik bir rehber: mimari kararlar, güvenlik yönetişimi, benimseme stratejisi ve bu süreçte yaptığımız en büyük 7 hata.
Anthropic'in claude-code-action'ını bir GitHub repo'suna eklemek için sıkılaştırılmış, kopyalanmaya hazır bir kurulum; üretim için güvenlik ve maliyet ayarları açıkça anlatılıyor.
Takım büyüklüğü, ürün tipi ve gerçek başarısızlıklara dayanan Git branching stratejileri hakkında acımasızca dürüst bir rehber.
AWS Secrets Manager ve Systems Manager Parameter Store'u karşılaştıran kapsamlı teknik rehber - hangi servisi ne zaman kullanmalı ve gerçek dünya implementation pattern'leri.
TypeScript ile organizasyonunuzun internal sistemleri için custom Model Context Protocol serverları nasıl geliştirip, güvenli hale getirip, deploy edeceğinizi öğren. Authentication, monitoring ve Kubernetes deployment örnekleriyle.