Claude Code di GitLab CI/CD: Job, OIDC, dan MR

Tambahkan variabel ter-mask ANTHROPIC_API_KEY di Settings lalu CI/CD lalu Variables, dan tambahkan job yang memasang CLI-nya dengan script installer lalu memanggil claude dengan flag -p. Setel permission mode ke acceptEdits dan sebutkan tool yang boleh dipakai Claude, termasuk tool MCP GitLab, di flag allowedTools.
Installer meletakkan binary-nya di ~/.local/bin, yang tidak ada di PATH pada image node alpine. Tambahkan baris export yang memasukkan direktori itu ke PATH di before_script Anda, setelah langkah instalasi. Error-nya menyebut nama perintah alih-alih path, dan itulah sebabnya orang tergiring kembali memeriksa langkah instalasi yang justru berhasil.
Tidak. GitLab mendengarkan pemicu yang Anda konfigurasi, dan run berbasis mention butuh bagian yang Anda sediakan: webhook proyek untuk event komentar yang mengarah ke sebuah listener yang memanggil API pemicu pipeline dengan konteks komentar sebagai variabel. Kalau sebuah mention tampak tidak melakukan apa-apa, biasanya listener itulah yang belum ada.
Bisa, pada Amazon Bedrock dan Google Cloud Agent Platform. GitLab mencetak token OIDC untuk job dari blok id_tokens; job itu menukarnya dengan kredensial AWS sementara lewat assume-role-with-web-identity, atau memakai Workload Identity Federation untuk Google Cloud. Tidak ada kunci berumur panjang yang disimpan di kedua jalur tersebut.
Ada tiga rem independen: flag --max-turns membatasi iterasi bolak-balik dan membatasi belanja token, timeout level job milik GitLab membatasi menit runner yang ditagih terpisah, dan batas concurrency membatasi berapa job berjalan sekaligus. Prompt yang spesifik juga lebih murah daripada yang kabur, karena run yang kabur baru berhenti ketika anggaran gilirannya habis.

Ringkasan Utama
Claude Code berjalan di GitLab CI/CD sebagai job biasa yang memasang CLI-nya lalu memanggilnya dalam mode non-interaktif. Ini integrasi beta yang dipelihara GitLab. Setup-nya satu job di file pipeline ditambah satu variabel ter-mask, dan ia mendukung Claude API, Amazon Bedrock lewat OIDC, serta Google Cloud Agent Platform lewat Workload Identity Federation.
Job GitLab pertama saya memasang Claude Code dengan sukses lalu gagal dengan pesan claude: not found. Pemasangannya benar-benar berhasil. Installer meletakkan binary-nya di direktori yang tidak ada di path pada image node alpine, dan satu baris export yang hilang mengubah setup yang berfungsi menjadi lima belas menit membaca log yang menyatakan instalasinya sukses.
Itu mewakili integrasi ini secara umum: konsepnya sederhana dan gesekannya sepenuhnya ada di pipa-pipanya. Tulisan ini membahas apa sebenarnya integrasi ini, job minimalnya, pemicu berbasis mention yang harus Anda bangun sendiri, dua jalur autentikasi tanpa kunci untuk provider enterprise, dan flag yang mencegah job liar memakan biaya lebih besar daripada manfaatnya.
Tidak ada aplikasi GitLab yang perlu dipasang dan tidak ada layanan yang perlu diotorisasi. Integrasi ini dibangun di atas CLI Claude Code dan Agent SDK: sebuah job memasang CLI-nya, menjalankannya dengan sebuah prompt dalam mode non-interaktif, lalu membiarkannya mengembalikan hasil lewat merge request. Setiap perubahan mengalir melalui MR, jadi peninjau melihat diff-nya dan approval serta branch protection Anda tetap berlaku.
Dua hal mengikuti dari situ. Pertama, integrasi ini masih beta dan dipelihara GitLab alih-alih Anthropic, dengan dukungan yang dilacak lewat sebuah issue GitLab, bukan lewat Anthropic. Kedua, apa pun yang bisa Anda lakukan dengan CLI-nya bisa Anda lakukan di sini — batasannya adalah yang Anda pasang di job, bukan yang dipaksakan integrasinya.
Ini seluruh setup-nya: tambahkan variabel ter-mask untuk API key Anda di pengaturan CI/CD proyek, lalu tambahkan sebuah job. Perhatikan baris export di before-script — itulah selisih antara pipeline yang berfungsi dan pipeline yang membingungkan.
# .gitlab-ci.yml — the smallest job that works.
stages:
- ai
claude:
stage: ai
image: node:24-alpine3.21
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
variables:
GIT_STRATEGY: fetch
before_script:
- apk update
- apk add --no-cache git curl bash
- curl -fsSL https://claude.ai/install.sh | bash
# The installer puts claude in ~/.local/bin, which is NOT on
# PATH in this image. Miss this line and the job fails with
# "claude: not found" AFTER a successful install.
- export PATH="$HOME/.local/bin:$PATH"
script:
- /bin/gitlab-mcp-server || true
- >
claude
-p "Review this MR and implement the requested changes"
--permission-mode acceptEdits
--allowedTools "Bash Read Edit Write mcp__gitlab"
--max-turns 25
timeout: 30mInstaller meletakkan binary-nya di direktori yang tidak ada di path pada image ini, jadi tanpa baris export tersebut job akan memasang Claude Code dengan sukses lalu gagal menemukannya. Error-nya menyebut nama perintah alih-alih path, sehingga Anda tergiring memeriksa langkah instalasi yang justru berhasil ketimbang environment yang tidak. Ini menelan satu sore, tepat sekali seumur hidup.
Setiap tulisan tentang integrasi ini memperlihatkan seseorang mengetik at-mention di komentar MR lalu Claude menjawab, dan itu membuatnya tampak seolah penanganan komentar sudah bawaan. Bukan. GitLab mendengarkan pemicu apa pun yang Anda konfigurasi, dan run berbasis mention butuh satu bagian yang Anda sediakan sendiri: webhook proyek untuk event komentar yang mengarah ke sebuah listener, yang memanggil API pemicu pipeline dengan konteks komentar sebagai variabel ketika melihat mention tersebut.
Job itu lalu membaca variabel tersebut — input, konteks, dan event-nya — dan meneruskan input-nya ke CLI sebagai prompt, dengan nilai default kalau job dijalankan lewat jalur lain. Kalau mention di komentar Anda tampak tidak melakukan apa-apa, hampir selalu listener-nya yang belum ada, bukan job-nya. Layak juga memeriksa bahwa komentarnya memakai bentuk tanda at alih-alih garis miring, salah ketik yang mengejutkan seringnya.
Untuk lingkungan enterprise, bagian menariknya adalah kedua provider itu tidak membutuhkan kunci tersimpan. GitLab mencetak token OIDC untuk job dari blok id-tokens lalu mengeksposnya ke script, yang menukarnya dengan kredensial sementara saat runtime. Nilai audience-nya harus cocok dengan yang Anda konfigurasikan di identity provider — biasanya URL instance GitLab Anda.
# Amazon Bedrock via OIDC — no static AWS keys anywhere.
claude-bedrock:
stage: ai
image: node:24-alpine3.21
rules:
- if: '$CI_PIPELINE_SOURCE == "web"'
id_tokens:
GITLAB_OIDC_TOKEN:
# Must match the audience configured on the IAM OIDC
# identity provider in AWS — usually your GitLab URL.
aud: https://gitlab.example.com
before_script:
- apk add --no-cache bash curl jq git aws-cli
- curl -fsSL https://claude.ai/install.sh | bash
- export PATH="$HOME/.local/bin:$PATH"
- export AWS_WEB_IDENTITY_TOKEN_FILE="/tmp/oidc_token"
- printf "%s" "$GITLAB_OIDC_TOKEN" > "$AWS_WEB_IDENTITY_TOKEN_FILE"
- >
aws sts assume-role-with-web-identity
--role-arn "$AWS_ROLE_TO_ASSUME"
--role-session-name "gitlab-claude-run"
--web-identity-token "file://$AWS_WEB_IDENTITY_TOKEN_FILE"
--duration-seconds 3600 > /tmp/aws_creds.json
- export AWS_ACCESS_KEY_ID="$(jq -r .Credentials.AccessKeyId /tmp/aws_creds.json)"
- export AWS_SECRET_ACCESS_KEY="$(jq -r .Credentials.SecretAccessKey /tmp/aws_creds.json)"
- export AWS_SESSION_TOKEN="$(jq -r .Credentials.SessionToken /tmp/aws_creds.json)"
variables:
AWS_REGION: "us-west-2"
CLAUDE_CODE_USE_BEDROCK: "1"Google Cloud Agent Platform mengikuti bentuk yang sama lewat Workload Identity Federation: job menulis token OIDC-nya ke sebuah file, menulis konfigurasi kredensial yang credential source-nya menunjuk file itu, lalu mengeksposnya lewat variabel application default credentials. Tidak ada service account key yang diunduh pada titik mana pun. Kedua jalur ini jelas lebih baik daripada secret berumur panjang di variabel CI, dan keduanya butuh sekitar dua puluh menit untuk disiapkan sekali.
Ada dua sistem permission terpisah yang berlaku di sini dan mencampuradukkannya menghasilkan kegagalan paling umum, yaitu job yang berjalan mulus lalu tidak bisa berkomentar atau membuka MR:
Letakkan konvensi Anda di CLAUDE.md pada root repository alih-alih di prompt job. Claude membacanya pada setiap run, jadi kriteria review, standar penulisan kode, dan hal-hal yang tidak boleh disentuh hidup di satu file yang ditinjau alih-alih diduplikasi di job review, job implement, dan job refactor yang akan saling melenceng dalam sebulan.
Kerangka yang berguna: sebuah job CI adalah tempat untuk pekerjaan dengan input jelas dan output yang bisa ditinjau. Apa pun yang butuh pertimbangan soal arah produk sebaiknya tetap di sesi tempat Anda bisa mengemudikannya.
Tiga bentuk yang bekerja baik, dan pemicunya:
| Tugas | Pemicu | Keluaran |
|---|---|---|
| Mengubah issue jadi merge request | Mention di komentar issue | Sebuah branch dan MR untuk ditinjau |
| Memperbaiki bug yang disebut namanya | Mention yang menyebut error dan komponennya | Commit di branch yang ada, atau MR baru |
| Menanggapi umpan balik review | Komentar lanjutan di MR | Commit tambahan di branch yang sama |
Job CI yang bisa berputar adalah job CI yang bisa menghabiskan uang, dan ada tiga rem independen yang layak disetel sejak run pertama alih-alih sejak tagihan pertama:
Mention yang spesifik lebih murah daripada yang kabur. Meminta Claude memperbaiki type error di komponen dashboard pengguna memberinya sasaran; meminta Claude memperbaiki kodenya memberinya pencarian. Flag turns memang akan menghentikan run yang kabur, tetapi ia menghentikannya karena kehabisan anggaran, bukan karena selesai, dan Anda membayar selisihnya baik-baik saja.
Integrasi GitLab layak disiapkan kalau hidup Anda memang sudah di merge request, dan setup-nya benar-benar kecil — satu job, satu variabel, dan sebuah listener kalau Anda ingin mention. Yang menentukan apakah ia layak bukan konfigurasi pipeline-nya melainkan CLAUDE.md di sebelahnya: job dengan konvensi yang jelas menghasilkan MR yang Anda merge, dan job tanpa itu menghasilkan MR yang Anda tutup. Benahi file itu dulu sebelum menyetel apa pun di YAML.
Sumber & bacaan lanjutan