Mert Özen Her Satırda Daha İleri
Yapay Zeka GitHub Copilot — #07

Copilot Coding Agent: Issue'yu Atamak, GitHub Actions Ortamı, Setup Adımları, Firewall ve Açılan PR'ı Review Etmek

Mert Özen 15 Kas 2026 13 dk 5 görüntülenme
Copilot Coding Agent: Issue'yu Atamak, GitHub Actions Ortamı, Setup Adımları, Firewall ve Açılan PR'ı Review Etmek

Copilot coding agent'ın açtığı pull request'te kırmızı check olmaması testlerin geçtiği anlamına gelmez: Copilot'un push'larında workflow'lar varsayılan olarak çalışmaz, Approve and run workflows beklenir. Issue yazmak ve atamak, copilot-setup-steps.yml ile .NET, Node ve SQL Server ortamı, actionlint'in kaçırdığı kurallar, Agents secret'ları, firewall, PR review ve Agent Merge.

Sürüm notu: Bu yazıdaki kodlar .NET 10, xUnit.net v3 4.0.3, Angular 22.2 (TypeScript 6.0) ve Vitest 5.1 ile derlenip denenmiştir; testler SQL Server 2025 üzerinde çalıştırılmış, copilot-setup-steps.yml actionlint 1.7.12 ile doğrulanmıştır. Copilot coding agent bu yazıda çalıştırılmadı (GitHub hesabı ve Copilot aboneliği kullanılmadı): issue'daki özelliği agent'ın izleyeceği adımlarla elle ekledik ve her adımın gerçek çıktısını gösteriyoruz. Agent'ın ortamı, firewall, Agent Merge ve ruleset davranışı 15 Kasım 2026'da docs.github.com'dan alınmıştır.

Önce Tahmin Et

Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için bir issue'yu Copilot'a atadın. Yarım saat sonra bildirim geliyor: Copilot bir pull request açmış ve seni reviewer olarak eklemiş. Pull request'te kırmızı bir check yok, açıklamada "added unit, integration and component tests" yazıyor.

Tahminin ne? Bu pull request'te CI testleri çalıştı mı? Kırmızı check olmaması neyi kanıtlıyor? Agent'ın kendi ortamında çalıştırdığı testlerle repodaki CI aynı şey mi? Cevap yazının ortasında, GitHub'ın dokümanındaki tek bir cümlede.

Coding Agent Nerede Çalışır

Beşinci yazıdaki agent senin IDE'nde, senin makinende çalışıyordu. Copilot coding agent (GitHub'ın yeni adlandırmasıyla cloud agent) ise işi GitHub'ın ortamında yapıyor: repoyu klonluyor, branch açıyor, kodu değiştirip build ve test çalıştırıyor, değişikliği bir pull request olarak sunuyor. 28 Ekim 2026'dan beri ücretli planlarda "Copilot in the cloud" adlı yeni deneyim açık ve agent üç ortamdan birinde çalışabiliyor:

ÖzellikGitHub ActionsCloud sandbox
Nerede başlarIssue ataması, Agent Merge, ortam olarak seçildiğindeOrtam seçilebilen yerlerde varsayılan
Repo kapsamıTek repoAynı organization'da birden fazla repo
Kurulumcopilot-setup-steps.yml, larger runner, self-hosted runnerSetup steps ve özel runner yok; dotfiles reposu ile kişisel ayar
Oturuma devamYalnız GitHub web sitesindeCLI, Visual Studio Code (VS Code), Copilot app ve web arasında
Chat verisinin saklanması28 günHesap yaşadıkça

Üçüncü seçenek Remote: senin kurduğun özel bir ortama bağlanmak. Bu yazıdaki senaryo GitHub Actions ortamı, çünkü issue atamasıyla başlayan görevler orada çalışıyor. Bu ortamın sınırları açık: her oturum en fazla 59 dakika çalışabiliyor ve bu süre uzatılamıyor; agent görev başına tek branch'te çalışıp tek pull request açıyor; yalnız görevi başlattığın repoda değişiklik yapabiliyor; yazma yetkin olmayan bir repoda oturum salt okunur kalıyor. Ortamın çalışma süresi AI Credits'ten ayrı, hesabın aylık compute hakkından düşüyor.

Görevi Başlatmak

Dokümana göre en yaygın yol issue'yu Copilot'a atamak: issue'nun sağındaki Assignees menüsünden Copilot seçiliyor ve açılan pencerede hedef repo, başlangıç branch'i, varsa bir custom agent, model ve "Optional prompt" alanı var. Altıncı yazıdaki migration-reviewer gibi bir custom agent'ı burada seçebilirsin.

Atama anında Copilot'a issue'nun başlığı, açıklaması, o ana kadarki yorumları ve ek talimatın gidiyor. Sonradan issue'ya yazılan yorumları görmüyor; ek bilgi pull request'e yazılmalı. Pull request'te @copilot ile başlayan bir yorum agent'ı aynı branch üzerinde yeniden çalıştırıyor; Files changed sekmesinde bir review yorumundaki Fix with Copilot ise o yorumu, Add to batch ile birden fazlasını agent'a devrediyor. Copilot yalnız repoda yazma yetkisi olanların yorumlarına cevap veriyor; dışarıdan biri pull request'e yorum yazarak agent'ı yönlendiremiyor.

Diğer giriş noktaları repodaki Agents sekmesi, github.com/copilot, GitHub Mobile, Copilot CLI ve IDE'ler. Bu yazının dokuzuncu yazıyla kesiştiği yer de bu: CLI'dan cloud agent'a görev devretmek mümkün.

Agent İçin İyi Bir Issue

GitHub'ın en iyi sonuç rehberi iyi bir görevin üç parçasını sayıyor: problemin net tarifi, iyi bir çözümün kabul kriterleri ve hangi dosyaların değişeceğine dair ipucu. Bookstore'daki issue:

Title: Show the ISBN-10 on the book detail page

Librarians in our institutional customers (see Institutional) still search their systems by ISBN-10.
The book detail page shows only the ISBN-13.

## What to change
- GET /api/books/{isbn} returns a new field `isbn10` (string or null).
- ISBN-13s starting with 978 convert to ISBN-10 (check digit mod 11, 10 is written as X).
  ISBN-13s starting with 979 have no ISBN-10: return null.
- The Angular book detail page shows "ISBN-10 <value>" next to the ISBN-13 when it is not null.

## Acceptance criteria
- Unit tests for the conversion: Dune 9780441172719 -> 0441172717, a check digit of X, a 979 ISBN, a wrong check digit.
- An integration test for GET /api/books/9780441172719.
- A Vitest spec for both cases on the book detail page.
- dotnet test and npm test pass. Do not change existing tests or migrations; no database change is needed.

Issue kurumsal müşterilerin isteğinden çıktı: kütüphaneler kitabı hâlâ eski, on haneli ISBN (kitapların uluslararası standart numarası) ile arıyor. Bu issue'da agent'ın tahmin etmesi gereken bir şey bırakmadık: alanın adı ve tipi, 979 önekinin davranışı, X kuralı ve test sayısı yazıyor. Son satır önemli: "mevcut testleri ve migration'ları değiştirme". Beşinci yazıda kırmızı testi testi değiştirerek yeşile çeviren bir agent'ı fark etmenin zorluğunu görmüştük; bu cümle review'da elinde bir ölçüt olmasını sağlıyor. Rehber bazı işleri agent'a vermek yerine kendin yapmanı öneriyor: production'ı etkileyen ya da güvenlik, kişisel veri ve authentication (kimlik doğrulama) ile ilgili işler, incident müdahalesi, belirsiz istekler ve geniş kapsamlı refactoring.

Ortamı Hazırlamak: copilot-setup-steps.yml

Agent bir .NET ve Angular reposunda SDK'yı, npm paketlerini ve SQL Server'ı deneme yanılmayla kurmaya çalışırsa hem yavaş olur hem de 59 dakikanın bir kısmını buna harcar. GitHub Actions ortamında bunu önceden yapan dosya .github/workflows/copilot-setup-steps.yml:

name: Copilot Setup Steps

# Bu dosya değişince kendi kendine çalışır; bozuk kurulum pull request'te kırmızı check olarak görünür.
on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
  # Job'un adı copilot-setup-steps olmalı, yoksa Copilot onu görmez.
  copilot-setup-steps:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    permissions:
      contents: read
    steps:
      - name: Check out the repository
        uses: actions/checkout@v7

      - name: Set up .NET 10
        uses: actions/setup-dotnet@v6
        with:
          global-json-file: global.json

      - name: Set up Node.js 24
        uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
          cache-dependency-path: web/bookstore-web/package-lock.json

      - name: Restore .NET packages and tools
        run: |
          dotnet restore
          dotnet tool restore

      - name: Install Angular dependencies
        working-directory: web/bookstore-web
        run: npm ci

      - name: Start SQL Server and store the connection string in user-secrets
        run: |
          # Çalışma anında üretilen tek kullanımlık şifre: secret'ta saklanacak bir şey yok, log'da maskelenir.
          SQL_PASSWORD="Bk1-$(openssl rand -hex 16)"
          echo "::add-mask::$SQL_PASSWORD"
          docker run -d --name bookstore-sql -p 1433:1433 \
            -e ACCEPT_EULA=Y -e "MSSQL_SA_PASSWORD=$SQL_PASSWORD" \
            mcr.microsoft.com/mssql/server:2025-latest
          for attempt in $(seq 1 30); do
            if docker exec bookstore-sql /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P "$SQL_PASSWORD" -Q "SELECT 1" > /dev/null 2>&1; then
              echo "SQL Server is ready after $attempt attempt(s)"
              break
            fi
            if [ "$attempt" -eq 30 ]; then
              echo "SQL Server did not start" >&2
              exit 1
            fi
            sleep 2
          done
          dotnet user-secrets set "ConnectionStrings:BookstoreDb" \
            "Server=localhost,1433;Database=BookstoreDb;User Id=sa;Password=$SQL_PASSWORD;TrustServerCertificate=True" \
            --project src/Bookstore.Api

      - name: Build once so the agent starts from a warm state
        run: dotnet build --no-restore

Dosya normal bir workflow gibi görünüyor ama kuralları var. Job'un adı copilot-setup-steps olmalı. Bu job'da yalnız steps, permissions, runs-on, services, snapshot ve timeout-minutes (en fazla 59) dikkate alınıyor; diğer anahtarlar sessizce yok sayılıyor. Dosya default branch'te değilse hiç çalışmıyor. Bir adım hata verirse Copilot kalan adımları atlayıp ortam o hâldeyken çalışmaya başlıyor. actions/checkout'taki fetch-depth değeri de agent'ın commit geri alabilmesi için eziliyor.

SQL Server için bir secret tutmadık. Container her oturumda sıfırdan başlıyor, şifre adım içinde üretiliyor, ::add-mask:: ile log'da gizleniyor ve connection string, README'deki gibi user-secrets'a yazılıyor. Test factory'si connection string'i user-secrets'tan okuduğu için agent'ın dotnet test komutu ek ayar olmadan çalışıyor; bu mekanizmayı kendi makinemizde environment variable olmadan, yalnız user-secrets ile denedik ve 22 testin hepsi geçti. Runner'ı da ubuntu-latest bıraktık: Windows runner mümkün ama dokümana göre agent'ın yerleşik firewall'u Windows'ta çalışmıyor.

Dosyayı doğrulamanın ilk adımı actionlint. Workflow sözdizimini, expression'ları ve bilinen action'ların girdilerini kontrol ediyor:

$ actionlint .github/workflows/copilot-setup-steps.yml
$ echo $?
0
$ dotnet run eng/check-instructions.cs
...
.github/workflows/copilot-setup-steps.yml: job copilot-setup-steps (runs-on, timeout-minutes, permissions, steps)
Always loaded (AGENTS.md + copilot-instructions.md): 2,334 characters, budget 8,000
OK

actionlint Copilot'un kurallarını bilmiyor. Bunu görmek için dosyayı bilerek bozduk: timeout-minutes'ı 90 yaptık ve job düzeyinde bir env bloğu ekledik. İlk taslağımızda gerçekten de job düzeyinde env vardı; Copilot onu yok sayacaktı. actionlint yine temiz geçti, dördüncü yazıdaki kontrol script'ine eklediğimiz kural ise ikisini de yakaladı:

$ actionlint .github/workflows/copilot-setup-steps.yml
$ echo $?
0
$ dotnet run eng/check-instructions.cs
...
.github/workflows/copilot-setup-steps.yml: job copilot-setup-steps (runs-on, timeout-minutes, permissions, env, steps)
Always loaded (AGENTS.md + copilot-instructions.md): 2,334 characters, budget 8,000
error: .github/workflows/copilot-setup-steps.yml: timeout-minutes is 90, the maximum is 59
error: .github/workflows/copilot-setup-steps.yml: 'env' is ignored by Copilot (allowed: steps, permissions, runs-on, services, snapshot, timeout-minutes)
2 error(s)

Dosya değiştiğinde workflow push ve pull request'te kendi kendine çalışıyor; kurulumun bozulduğunu agent'ın oturumundan önce, pull request'teki check'ten görüyorsun. Default branch'e girdikten sonra Actions sekmesinden elle de çalıştırılabiliyor.

Secret'lar ve Firewall

Agent'ın özel bir NuGet feed'ine ya da npm registry'sine erişmesi gerekiyorsa Settings > Secrets and variables > Agents altında secret tanımlanıyor. Bunlar Actions secret'larından ayrı; agent Actions, Codespaces ve Dependabot secret'larını görmüyor. Agents secret'ları agent'ın ortamına environment variable olarak geliyor ve session log'larında maskeleniyor; adı COPILOT_MCP_ ile başlayanlar ise yalnız MCP (Model Context Protocol; agent'ın dış araçlara bağlandığı protokol) server'larına gidiyor. Cloud sandbox'ta yalnız secret'lar geliyor, variable'lar gelmiyor.

Agent'ın internet erişimini varsayılan olarak bir firewall sınırlıyor. GitHub ve Copilot'un kendi host'ları her zaman açık; varsayılan olarak açık gelen önerilen allowlist ise işletim sistemi paket depolarını, yaygın container registry'lerini, NuGet ve npm dahil dil paket registry'lerini ve sertifika otoritelerini kapsıyor. Engellenen bir istek pull request açıklamasına ya da yoruma uyarı olarak düşüyor; uyarıda adres ve isteği yapan komut görünüyor. Organization ve repository düzeyinde kendi domain ya da URL kuralını ekleyebiliyorsun.

Dokümanın kendi sınırlamalarına dikkat: firewall yalnız agent'ın Bash tool'uyla başlattığı process'lere uygulanıyor; repository ayarlarına eklenen MCP server'ları bunun dışında. Karmaşık bir saldırı firewall'u aşabilir; GitHub bunu kapsamlı bir güvenlik çözümü saymamayı söylüyor. Firewall'u kapatmak ise agent'ın her host'a bağlanabilmesi, yani kodun dışarı sızma riskinin artması demek.

Açılan Pull Request'i Review Etmek

Agent oturumunu kendisi çalıştıramadığımız için issue'yu agent'ın izleyeceği yolla elle uyguladık: copilot/ önekli bir branch, önce testler, sonra kod. Review'a her zaman olduğu gibi diff'in özetiyle başladık:

$ git diff --stat main...copilot/isbn10-on-book-detail
 src/Bookstore.Api/Catalog/CatalogModule.cs         |  5 ++-
 src/Bookstore.Api/Catalog/Isbn.cs                  | 34 ++++++++++++++++
 tests/Bookstore.Api.Tests/CatalogTests.cs          |  9 +++++
 tests/Bookstore.Api.Tests/IsbnTests.cs             | 25 ++++++++++++
 .../src/app/catalog/book-detail-page.html          |  7 +++-
 .../src/app/catalog/book-detail-page.spec.ts       | 46 ++++++++++++++++++++++
 web/bookstore-web/src/app/core/api-models.ts       |  2 +
 7 files changed, 125 insertions(+), 3 deletions(-)

Yedi dosya, tamamı issue'nun söylediği yerlerde; migration yok, var olan bir testte silinen satır yok. Asıl dönüşüm kodu küçük:

using System.Globalization;

namespace Bookstore.Catalog;

// Gösterim için ISBN-13'ten ISBN-10'a. Yalnız 978 önekli ISBN-13'lerin ISBN-10'u var; 979 olanların yok.
public static class Isbn
{
    public static string? ToIsbn10(string isbn13)
    {
        if (isbn13.Length != 13 || !isbn13.All(char.IsAsciiDigit) || !isbn13.StartsWith("978") || !HasValidCheckDigit(isbn13))
        {
            return null;
        }

        string core = isbn13[3..12];
        int sum = 0;
        for (int i = 0; i < core.Length; i++)
        {
            sum += (10 - i) * (core[i] - '0');
        }
        int check = (11 - sum % 11) % 11;
        return core + (check == 10 ? "X" : check.ToString(CultureInfo.InvariantCulture));
    }

    private static bool HasValidCheckDigit(string isbn13)
    {
        int sum = 0;
        for (int i = 0; i < 12; i++)
        {
            sum += (isbn13[i] - '0') * (i % 2 == 0 ? 1 : 3);
        }
        return (10 - sum % 10) % 10 == isbn13[12] - '0';
    }
}
$ dotnet test
Test run summary: Passed!
  total: 22
  failed: 0
  succeeded: 22
  skipped: 0

$ cd web/bookstore-web && npm test
 Test Files  3 passed (3)
      Tests  5 passed (5)

Testlerin yeşil olması tek başına yetmiyor; değişiklikten önce kırmızı olduklarını da görmek gerekiyor. Template değişikliğini geri alıp Vitest'i yeniden çalıştırdık:

$ git stash push src/app/catalog/book-detail-page.html
$ npx ng test --no-watch
     × shows the ISBN-10 next to the ISBN-13 22ms
     × hides the ISBN-10 when the book has none 4ms
      Tests  2 failed | 3 passed (5)

İki test de kırmızı, ama ikincisinin sebebi farklı: eski template'te data-testid="isbn" olmadığı için test, ISBN-10'un gizlenmesini değil element'in var olmasını ölçüyor. Review yorumu olarak yazılacak türden bir bulgu bu. İki not daha: API'ye isbn10 alanı eklenmesi bir contract değişikliği ve altıncı yazıdaki MCP server'ın BookDetails kaydı bu alanı bilmiyor; agent repoda başka bir istemci olduğunu bilmezse bunu fark etmez.

Şimdi Önce Tahmin Et'e dönelim. GitHub'ın dokümanı açık: Copilot pull request'e push ettiğinde GitHub Actions workflow'ları varsayılan olarak otomatik çalışmıyor. Merge box'ta Approve and run workflows düğmesine basana kadar CI hiç koşmamış oluyor; kırmızı check olmaması testlerin geçtiğini değil, hiç çalışmadığını gösteriyor olabilir. Agent'ın kendi ortamında testleri çalıştırması ayrı bir şey ve onun çıktısını yalnız session log'unda görüyorsun. Workflow'ların onaysız çalışması repository ayarlarından açılabiliyor; ama bu, agent'ın yazdığı bir workflow değişikliğinin de onaysız çalışması demek.

Agent Merge ve Ruleset'ler

Agent Merge, pull request'in merge box'ındaki Watch and fix ile açılıyor. Seçtiğin engelleri izliyor: başarısız GitHub Actions workflow'ları, merge conflict'leri ya da ikisi. Biri ortaya çıktığında Copilot GitHub Actions tabanlı bir ortamda düzeltmeye başlıyor ve pull request zaman çizelgesine neden başladığını yazıyor; aynı copilot-setup-steps.yml'ı, talimatları ve skill'leri kullanıyor. Agent Merge auto-merge'ü açmıyor ve review'un yerine geçmiyor. Kullandığı AI Credits, pull request'in yazarına değil, Agent Merge'ü o pull request için açan kişiye yazılıyor; fork'tan gelen ya da stacked pull request'lerde çalışmıyor.

Ruleset'ler ve branch protection kuralları Copilot'un pull request açmasını ya da güncellemesini engelleyebiliyor; repository yöneticileri Copilot için bir bypass tanımlayabiliyor. Bypass'ı bir kolaylık olarak açmadan önce düşün: Bookstore'da main için istediğimiz kural, agent'ın pull request'inin de insan onayı ve geçen CI olmadan birleşmemesi. Rulesets'in temelini Git & GitHub serisinde anlattık; Copilot code review'u bir ruleset ile zorunlu kılmak bir sonraki yazının konusu.

Üretimde Dikkat

Agent'ın ortamına production secret'ı koyma. Agents secret'ları agent'ın çalıştırdığı her komutta environment variable olarak görünüyor; prompt injection içeren bir issue ya da bağımlılık bu değeri okuyabilir. Test için gereken değerleri, Bookstore'daki SQL şifresi gibi, çalışma anında üret.

Setup steps'in permissions bloğunu dar tut. Dokümandaki örnek de yalnız contents: read veriyor; Copilot kendi işlemleri için ayrı bir token alıyor.

59 dakikayı hesaba kat. Bookstore'da setup steps paket kurulumu ve SQL Server'ın açılması kadar sürüyor; daha uzun bir kurulum ve yavaş bir test suite'i agent'a kod yazacak çok az zaman bırakır. Gerekirse larger runner kullanılabiliyor.

Maliyet iki kalemli: agent'ın model kullanımı AI Credits'ten, ortamın çalışma süresi hesabın compute hakkından düşüyor. Agent Merge'ün bir pull request'i saatlerce izleyip her kırık workflow'da yeniden çalışması iki kalemi de artırır.

Sık Düşülen Tuzaklar

Agent'ın pull request'ini insan pull request'inden daha az dikkatle review etmek. Diff'i aynı checklist ile oku; Code Review serisinin üçüncü yazısındaki kontrol listesi burada da geçerli.

Kırmızı check olmamasını yeşil saymak. Approve and run workflows'a basmadan CI çalışmıyor olabilir.

Atamadan sonra issue'ya bilgi eklemek. Copilot atama anındaki metni görüyor; sonraki bilgi pull request'e @copilot ile yazılmalı.

Setup steps'te job düzeyinde env ya da 59'dan büyük timeout-minutes kullanmak. Copilot ikisini de sessizce yok sayıyor; actionlint de yakalamıyor.

Secret'ları agent ortamına gereğinden geniş açmak. Organization düzeyindeki bir Agents secret'ını "All repositories" ile açmak, onu her reponun agent'ına vermek demek.

Küçük Bir Deneme

★☆☆ Kendi repona bir copilot-setup-steps.yml yaz, actionlint'ten geçir ve job adını bilerek değiştir. actionlint bir şey söylüyor mu?

★★☆ Bookstore'daki ikinci Vitest testini, eski template'te de anlamlı kalacak şekilde yeniden yaz: önce ISBN satırının var olduğunu doğrula, sonra ISBN-10'un gizlendiğini. Template değişikliğini geri alıp hangi testin hangi sebeple kırmızı olduğuna bak.

★★★ Altıncı yazıdaki MCP server'ın get_book tool'una ISBN-10'u ekleyen bir issue yaz; kabul kriterlerini ve "değiştirilmeyecek dosyalar" listesini de koy. Bu yazıdaki issue ile karşılaştır: agent'ın tahmin etmesi gereken ne kaldı?

Agent'ın pull request'ini biz review ettik. Bir sonraki yazıda review'un kendisini Copilot'a veriyoruz: pull request'te otomatik code review, bir ruleset ile zorunlu kılmak, review talimatları ve Copilot'un neyi yakalayıp neyi kaçırdığı.