Skip to content
Santekno.com | Level Up Your Engineering Skills
ID
📖 0%
09 Oct 2026 · 24 mnt baca ·Artikel 63 / 208
Go

Setup Claude Code di GitHub Actions untuk Golang: Auth, CLAUDE.md, API

Panduan lengkap setup Claude Code di GitHub Actions untuk Go project. Konfigurasi API key, akses CLAUDE.md di CI, dan integrasi pertama Claude API call dari pipeline.

IH
Ihsan Arif
Penulis di Santekno · Backend Engineer

Ini adalah artikel implementasi pertama di Topik 4, dan fokusnya adalah setup Claude Code di GitHub Actions golang dari nol. Setelah blueprint di Artikel 02, sekarang kita hands-on: menyiapkan Claude agar bisa dipakai di GitHub Actions untuk Santekno Shop.

Ada tiga pendekatan yang berbeda untuk menggunakan Claude di CI. Ringkasan berikut memetakan ketiganya beserta kondisi paling cocok untuk masing-masing pendekatan.

text
 1Pendekatan A: GitHub Copilot PR Review
 2  → Built-in action dari GitHub
 3  → Paling mudah setup
 4  → Terbaik untuk: PR review otomatis
 5
 6Pendekatan B: Claude API via HTTP (curl/script)
 7  → Fleksibel, bisa custom prompt
 8  → Terbaik untuk: PR description, failure analysis, release notes
 9
10Pendekatan C: Claude Code CLI di Runner
11  → Full Claude Code experience di CI
12  → Terbaik untuk: complex multi-file analysis
13  → Membutuhkan Node.js di runner

Di Topik 4 kita akan pakai ketiganya sesuai use case. Artikel ini cover ketiga setup itu secara lengkap.


03.1 Pendekatan A: GitHub Copilot PR Review

Ini adalah pilihan paling mudah jika tim sudah subscribe GitHub Copilot Business/Enterprise. Workflow berikut mengaktifkan Copilot review otomatis di setiap PR yang menyentuh file Go, lengkap dengan instruksi review-nya.

yaml
 1# Setup yang dibutuhkan: NIL — action sudah tersedia
 2# yang perlu dikonfigurasi: permissions dan copilot-instructions.md
 3
 4# .github/workflows/ai-review.yml
 5name: Copilot PR Review
 6
 7on:
 8  pull_request:
 9    types: [opened, synchronize, ready_for_review]
10    paths: ['**.go']
11
12jobs:
13  copilot-review:
14    runs-on: ubuntu-latest
15    if: "!github.event.pull_request.draft"
16    permissions:
17      pull-requests: write
18      contents: read
19    steps:
20      - uses: actions/checkout@v4
21        with:
22          fetch-depth: 0
23
24      - name: Copilot Code Review
25        uses: github/copilot-for-pull-requests@v1
26        with:
27          github-token: ${{ secrets.GITHUB_TOKEN }}
28          review-type: "code-review"
29          review-instructions: |
30            Review Go code untuk production service Santekno Shop.
31            Baca dan ikuti semua rules di .github/copilot-instructions.md.
32
33            CRITICAL — block PR jika ditemukan:
34            1. Error tidak di-wrap: `return err` (harus `fmt.Errorf("pkg.Method: %w", err)`)
35            2. float64/float32 untuk monetary values (harus int64 cents)
36            3. Architecture violation: handler import repository implementation
37            4. Repository return error untuk not-found (harus return nil, nil)
38            5. Error di-ignore dengan _ di non-test code
39
40            SUGGESTION — informational:
41            6. Missing test untuk error paths
42            7. Missing godoc untuk exported symbols
43            8. Context tidak di-pass ke downstream calls
44
45            Akhiri dengan: REVIEW_SCORE: X/100

Kualitas review Copilot sangat bergantung pada file konteks yang menyertainya. File copilot-instructions.md berikut menerjemahkan aturan CLAUDE.md menjadi rules yang ringkas untuk gaya review Copilot.

markdown
 1# .github/copilot-instructions.md
 2# Santekno Shop — Copilot Review Rules
 3# Derived from CLAUDE.md
 4
 5## Architecture
 6Clean Architecture: handler → usecase → repository → domain
 7
 8## Error Handling (CRITICAL)
 9Repository not-found: MUST return (nil, nil)
10Error wrap: MUST use fmt.Errorf("package.Method: %w", err)
11HTTP error format: {"error": "UPPERCASE_CODE"}
12
13## Type Rules (CRITICAL)
14Monetary: ALWAYS int64 cents (money.IDR)
15IDs: ALWAYS uuid.UUID
16
17## Testing
18testify/suite + gomock pattern
19
20## Go Version: 1.22 — no 1.23+ features

Dengan kombinasi workflow dan file instruksi ini, Copilot berhenti memberi feedback generik dan mulai menegakkan konvensi spesifik Santekno Shop — tanpa satu baris kode API pun yang perlu kamu tulis.


03.2 Pendekatan B: Claude API via HTTP

Untuk use case yang butuh custom prompt — PR description, failure analysis, release notes — kita panggil Claude API langsung via HTTP. Pertama, daftarkan API key ke GitHub Secrets seperti berikut.

bash
1# Setup: tambahkan ANTHROPIC_API_KEY ke GitHub Secrets
2gh secret set ANTHROPIC_API_KEY --body "sk-ant-api03-xxx"
3
4# Verify:
5gh secret list
6# Output: ANTHROPIC_API_KEY  Updated 2026-07-15

Setelah key tersimpan, kita bisa memanggilnya dari step manapun. Template step berikut menunjukkan pola dasar memanggil Claude API dengan curl dan mem-parsing responsnya dengan jq.

yaml
 1# Template step yang reusable:
 2# Gunakan pola ini di setiap workflow yang butuh Claude
 3
 4- name: Claude API Call
 5  env:
 6    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
 7  run: |
 8    # Build prompt (ganti dengan prompt spesifik)
 9    PROMPT="Your specific prompt here"
10
11    # Call Claude API
12    RESPONSE=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
13      -H "x-api-key: ${ANTHROPIC_API_KEY}" \
14      -H "anthropic-version: 2023-06-01" \
15      -H "content-type: application/json" \
16      -d "$(jq -n \
17        --arg prompt "$PROMPT" \
18        '{
19          model: "claude-haiku-4-5-20251001",
20          max_tokens: 500,
21          messages: [{"role": "user", "content": $prompt}]
22        }'
23      )")
24
25    # Extract text dari response
26    RESULT=$(echo "$RESPONSE" | jq -r '.content[0].text')
27    echo "$RESULT"

Pola inline ini berfungsi, tapi mengulang blok curl yang sama di banyak step cepat menjadi berantakan — itulah masalah yang kita selesaikan di bagian berikutnya dengan wrapper script.


03.3 Wrapper Script untuk Claude API

Supaya tidak repeat curl di setiap step, kita bungkus logika pemanggilan API menjadi satu script reusable. Script claude-call.sh berikut menerima prompt, max tokens, dan model — lengkap dengan penanganan error API.

bash
 1#!/bin/bash
 2# scripts/claude-call.sh
 3# Usage: scripts/claude-call.sh "Your prompt" [max_tokens] [model]
 4
 5set -euo pipefail
 6
 7PROMPT="${1}"
 8MAX_TOKENS="${2:-500}"
 9MODEL="${3:-claude-haiku-4-5-20251001}"
10
11if [ -z "${ANTHROPIC_API_KEY:-}" ]; then
12  echo "ERROR: ANTHROPIC_API_KEY not set" >&2
13  exit 1
14fi
15
16RESPONSE=$(curl -sf -X POST https://api.anthropic.com/v1/messages \
17  -H "x-api-key: ${ANTHROPIC_API_KEY}" \
18  -H "anthropic-version: 2023-06-01" \
19  -H "content-type: application/json" \
20  -d "$(jq -n \
21    --arg p "$PROMPT" \
22    --argjson t "$MAX_TOKENS" \
23    --arg m "$MODEL" \
24    '{
25      model: $m,
26      max_tokens: $t,
27      messages: [{"role": "user", "content": $p}]
28    }'
29  )" 2>&1) || {
30  echo "ERROR: Claude API call failed: $RESPONSE" >&2
31  exit 1
32}
33
34# Check untuk error response dari API
35if echo "$RESPONSE" | jq -e '.error' > /dev/null 2>&1; then
36  ERROR_MSG=$(echo "$RESPONSE" | jq -r '.error.message')
37  echo "ERROR: Claude API error: $ERROR_MSG" >&2
38  exit 1
39fi
40
41# Return content text
42echo "$RESPONSE" | jq -r '.content[0].text'

Sebelum dipakai di CI, wajib dites lokal dulu agar tidak debugging di log Actions. Perintah berikut menandai script sebagai executable dan menjalankan smoke test sederhana.

bash
1# Make executable dan test:
2chmod +x scripts/claude-call.sh
3
4# Test lokal:
5export ANTHROPIC_API_KEY="sk-ant-xxx"
6./scripts/claude-call.sh "Say 'CI ready' in one word" 50
7# Output: Ready

Dengan wrapper ini, setiap script berikutnya cukup memanggil claude-call.sh alih-alih menduplikasi logika curl — satu tempat untuk error handling, pemilihan model, dan parsing JSON.


03.4 Integrasi CLAUDE.md ke CI Context

CLAUDE.md adalah context file yang Claude perlu baca untuk memberikan review yang relevant. Di CI, kita inject CLAUDE.md ke setiap prompt lewat script claude-review.sh berikut — yang membangun prompt berbeda untuk review general maupun security.

bash
 1#!/bin/bash
 2# scripts/claude-review.sh
 3# Claude review dengan CLAUDE.md sebagai context
 4
 5set -euo pipefail
 6
 7DIFF_FILE="${1}"
 8REVIEW_TYPE="${2:-general}"  # general, security, spec
 9
10# Load CLAUDE.md sebagai context
11CLAUDE_CONTEXT=""
12if [ -f "CLAUDE.md" ]; then
13  CLAUDE_CONTEXT=$(cat CLAUDE.md | head -200)  # first 200 lines
14fi
15
16# Load service-specific context jika ada
17SERVICE_CONTEXT=""
18if [ -f "services/order-service/CLAUDE.md" ]; then
19  SERVICE_CONTEXT=$(cat "services/order-service/CLAUDE.md")
20fi
21
22# Build review diff
23DIFF=$(cat "$DIFF_FILE" | head -300)  # limit untuk cost control
24
25# Build prompt berdasarkan review type
26case "$REVIEW_TYPE" in
27  "general")
28    PROMPT="Project context (CLAUDE.md):
29${CLAUDE_CONTEXT}
30
31Review Go code diff berikut. Check CRITICAL issues:
321. Error tidak di-wrap (return err tanpa fmt.Errorf)
332. float64 untuk monetary values
343. Architecture layer violations
354. Nil tidak di-check setelah repo call
365. Errors di-ignore dengan _
37
38Diff:
39${DIFF}
40
41Format output:
42CRITICAL: [issue] at [file:line] → [fix]
43SUGGESTION: [improvement]
44REVIEW_SCORE: [0-100]"
45    ;;
46
47  "security")
48    PROMPT="Review Go code diff untuk security issues:
491. SQL injection via string concatenation
502. Hardcoded credentials
513. Missing input validation
524. Path traversal
535. Integer overflow untuk financial calculations
54
55Diff:
56${DIFF}
57
58Mark: BLOCKING (immediate fix) / WARNING / OK"
59    ;;
60esac
61
62# Call Claude
63RESULT=$(./scripts/claude-call.sh "$PROMPT" 800)
64echo "$RESULT"
65
66# Check jika ada CRITICAL atau BLOCKING
67if echo "$RESULT" | grep -qE "^(CRITICAL|BLOCKING):"; then
68  echo ""
69  echo "::warning::AI review found critical issues"
70  exit 1  # fail step
71fi
72
73exit 0

Perhatikan dua puluh baris pertama: tanpa injeksi CLAUDE.md, AI hanya memakai konvensi Go generik; dengan konteks itu, ia tahu aturan spesifik proyek seperti larangan float64 untuk uang dan pola nil/nil untuk not-found.


03.5 Workflow: AI Review dengan CLAUDE.md Context

Setelah punya script, kita rangkai menjadi workflow utuh yang mengambil diff, menjalankan review, dan mem-posting hasilnya sebagai komentar PR. Workflow berikut menyatukan semua langkah itu — dari ekstraksi diff sampai score gate.

yaml
 1# .github/workflows/ai-code-review.yml
 2name: AI Code Review
 3
 4on:
 5  pull_request:
 6    types: [opened, synchronize, ready_for_review]
 7    paths: ['**.go']
 8
 9env:
10  ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
11
12jobs:
13  claude-review:
14    name: Claude Code Review
15    runs-on: ubuntu-latest
16    if: "!github.event.pull_request.draft"
17    permissions:
18      pull-requests: write
19      contents: read
20    steps:
21      - uses: actions/checkout@v4
22        with:
23          fetch-depth: 0
24
25      - name: Get Go diff
26        id: diff
27        run: |
28          # Get diff dari PR
29          git diff origin/${{ github.base_ref }}...HEAD -- '*.go' \
30            | head -500 > /tmp/pr-diff.txt
31
32          # Check apakah ada Go changes
33          if [ ! -s /tmp/pr-diff.txt ]; then
34            echo "no_changes=true" >> $GITHUB_OUTPUT
35          else
36            echo "no_changes=false" >> $GITHUB_OUTPUT
37            echo "diff_size=$(wc -l < /tmp/pr-diff.txt)" >> $GITHUB_OUTPUT
38          fi
39
40      - name: AI Review
41        id: review
42        if: steps.diff.outputs.no_changes != 'true'
43        run: |
44          chmod +x scripts/claude-review.sh
45          REVIEW=$(./scripts/claude-review.sh /tmp/pr-diff.txt general) || REVIEW_FAILED=true
46
47          echo "review_output<<EOF" >> $GITHUB_OUTPUT
48          echo "$REVIEW" >> $GITHUB_OUTPUT
49          echo "EOF" >> $GITHUB_OUTPUT
50
51          # Extract score
52          SCORE=$(echo "$REVIEW" | grep "REVIEW_SCORE:" | grep -oP '\d+' || echo "0")
53          echo "score=$SCORE" >> $GITHUB_OUTPUT
54          echo "failed=${REVIEW_FAILED:-false}" >> $GITHUB_OUTPUT
55
56      - name: Post Review Comment
57        if: steps.diff.outputs.no_changes != 'true'
58        uses: actions/github-script@v7
59        with:
60          script: |
61            const review = `${{ steps.review.outputs.review_output }}`;
62            const score = parseInt('${{ steps.review.outputs.score }}') || 0;
63
64            const scoreEmoji = score >= 90 ? '🟢' : score >= 70 ? '🟡' : '🔴';
65
66            const body = [
67              `## 🤖 AI Code Review`,
68              ``,
69              `**Score:** ${scoreEmoji} ${score}/100`,
70              ``,
71              review,
72              ``,
73              `---`,
74              `*Reviewed by Claude claude-haiku-4-5-20251001 | [Ignore this review](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests)*`
75            ].join('\n');
76
77            await github.rest.issues.createComment({
78              owner: context.repo.owner,
79              repo: context.repo.repo,
80              issue_number: context.issue.number,
81              body
82            });
83
84      - name: Check Score Gate
85        if: |
86          steps.diff.outputs.no_changes != 'true' &&
87          steps.review.outputs.failed == 'true'
88        run: |
89          SCORE=${{ steps.review.outputs.score }}
90          echo "AI Review Score: $SCORE/100"
91
92          # Phase 1: warning only
93          # Phase 2 (uncomment): block jika ada CRITICAL
94          # if echo "$REVIEW" | grep -q "^CRITICAL:"; then
95          #   echo "::error::PR has CRITICAL issues that must be fixed"
96          #   exit 1
97          # fi
98
99          echo "::warning::AI review issues found — please review the comment above"

Perhatikan langkah “Check Score Gate”: di fase awal ia hanya mengeluarkan warning, dan blok merge (baris yang di-comment) baru diaktifkan setelah tim terbiasa — persis semangat graduated enforcement dari Artikel 02.


03.6 Pendekatan C: Claude Code CLI di Runner

Untuk use case yang butuh full Claude Code experience — multi-file analysis, spec-aware — kita pasang Claude Code CLI langsung di runner. Workflow berikut menginstal CLI, mengonfigurasi auth, menjalankan analisis, lalu mem-posting hasilnya ke PR.

yaml
 1# .github/workflows/claude-code-ci.yml
 2name: Claude Code Analysis
 3
 4on:
 5  pull_request:
 6    paths: ['**.go', 'CLAUDE.md', '.specify/**']
 7
 8jobs:
 9  claude-code:
10    runs-on: ubuntu-latest
11    permissions:
12      pull-requests: write
13      contents: read
14    steps:
15      - uses: actions/checkout@v4
16        with:
17          fetch-depth: 0
18
19      - uses: actions/setup-go@v5
20        with:
21          go-version: '1.22'
22          cache: true
23
24      # Install Node.js untuk Claude Code CLI
25      - uses: actions/setup-node@v4
26        with:
27          node-version: '20'
28
29      # Install Claude Code
30      - name: Install Claude Code
31        run: npm install -g @anthropic-ai/claude-code
32
33      # Setup API key
34      - name: Configure Claude Code
35        env:
36          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
37        run: |
38          # Claude Code otomatis baca ANTHROPIC_API_KEY dari environment
39          claude --version
40
41      # Run Claude Code analysis
42      - name: Claude Code Architecture Review
43        env:
44          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
45        run: |
46          # Non-interactive mode untuk CI
47          claude --print "
48            Baca CLAUDE.md dan analyze perubahan di PR ini.
49
50            Run checks:
51            1. go build ./... (verify build tidak break)
52            2. Review diff untuk architecture violations
53            3. Check spec compliance (jika ada .specify/)
54
55            Output format:
56            BUILD: [PASS/FAIL]
57            ARCHITECTURE: [PASS/FAIL + issues jika ada]
58            SPEC: [COMPLIANT/NON-COMPLIANT + details]
59            OVERALL: [PASS/FAIL]
60          " --output-format text > /tmp/claude-analysis.txt 2>&1
61
62          cat /tmp/claude-analysis.txt
63
64      # Post result ke PR
65      - name: Post Claude Code Analysis
66        uses: actions/github-script@v7
67        with:
68          script: |
69            const fs = require('fs');
70            const analysis = fs.readFileSync('/tmp/claude-analysis.txt', 'utf8');
71
72            await github.rest.issues.createComment({
73              owner: context.repo.owner,
74              repo: context.repo.repo,
75              issue_number: context.issue.number,
76              body: `## 🤖 Claude Code Analysis\n\n\`\`\`\n${analysis}\n\`\`\``
77            });

Keunggulan pendekatan ini: claude --print berjalan non-interaktif dan membaca CLAUDE.md otomatis dari root repo, sehingga cocok untuk analisis multi-file yang butuh konteks penuh — dengan ongkos tambahan berupa instalasi Node.js di runner.


03.7 Rate Limiting dan Error Handling

Di CI yang sibuk, panggilan API bisa kena rate limit atau server overload. Script berikut membungkus curl dengan retry dan exponential backoff agar kegagalan sementara tidak langsung menggagalkan pipeline.

bash
 1#!/bin/bash
 2# scripts/claude-call-with-retry.sh
 3# Claude API call dengan retry untuk rate limit handling
 4
 5set -euo pipefail
 6
 7PROMPT="${1}"
 8MAX_TOKENS="${2:-500}"
 9MAX_RETRIES=3
10RETRY_DELAY=5  # detik
11
12for attempt in $(seq 1 $MAX_RETRIES); do
13  RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
14    https://api.anthropic.com/v1/messages \
15    -H "x-api-key: ${ANTHROPIC_API_KEY}" \
16    -H "anthropic-version: 2023-06-01" \
17    -H "content-type: application/json" \
18    -d "$(jq -n \
19      --arg p "$PROMPT" \
20      --argjson t "$MAX_TOKENS" \
21      '{
22        model: "claude-haiku-4-5-20251001",
23        max_tokens: $t,
24        messages: [{"role": "user", "content": $p}]
25      }'
26    )")
27
28  HTTP_CODE=$(echo "$RESPONSE" | tail -1)
29  BODY=$(echo "$RESPONSE" | head -n -1)
30
31  case "$HTTP_CODE" in
32    200)
33      echo "$BODY" | jq -r '.content[0].text'
34      exit 0
35      ;;
36    429)
37      # Rate limit — tunggu dan retry
38      echo "Rate limited (attempt $attempt/$MAX_RETRIES), waiting ${RETRY_DELAY}s..." >&2
39      sleep $RETRY_DELAY
40      RETRY_DELAY=$((RETRY_DELAY * 2))  # exponential backoff
41      ;;
42    529)
43      # Overloaded — retry dengan backoff
44      echo "API overloaded (attempt $attempt/$MAX_RETRIES), waiting ${RETRY_DELAY}s..." >&2
45      sleep $RETRY_DELAY
46      ;;
47    *)
48      echo "ERROR: HTTP $HTTP_CODE: $BODY" >&2
49      exit 1
50      ;;
51  esac
52done
53
54echo "ERROR: All $MAX_RETRIES attempts failed" >&2
55exit 1

Kunci desain di sini: hanya HTTP 429 dan 529 yang di-retry dengan backoff, sedangkan error lain langsung gagal — sehingga pipeline tidak membuang waktu me-retry kesalahan yang tidak akan sembuh dengan menunggu.


03.8 Caching AI Review Results

Ketika beberapa commit di-push ke PR yang sama tanpa mengubah kode Go, menjalankan ulang review adalah pemborosan. Konfigurasi cache berikut menyimpan hasil review per kombinasi SHA dan hash file Go, sehingga review yang sama tidak dibayar dua kali.

yaml
 1# Cache AI review untuk commit yang sama (hindari double billing)
 2- name: Check review cache
 3  id: cache
 4  uses: actions/cache@v4
 5  with:
 6    path: /tmp/ai-review-cache
 7    key: ai-review-${{ github.sha }}-${{ hashFiles('**/*.go') }}
 8
 9- name: Run AI Review
10  if: steps.cache.outputs.cache-hit != 'true'
11  env:
12    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
13  run: |
14    mkdir -p /tmp/ai-review-cache
15
16    # Run review
17    REVIEW=$(./scripts/claude-review.sh /tmp/pr-diff.txt general)
18
19    # Save ke cache
20    echo "$REVIEW" > /tmp/ai-review-cache/result.txt
21
22- name: Read Review Result
23  run: |
24    # Baca dari cache (atau dari run sebelumnya)
25    REVIEW=$(cat /tmp/ai-review-cache/result.txt)
26    echo "$REVIEW"

Dengan cache key yang mengunci pada hash file Go, review hanya dijalankan ulang saat kode benar-benar berubah — setiap cache hit menghemat biaya API sekaligus waktu pipeline.


03.9 Testing Setup Lokal Sebelum CI

Sebelum mendorong perubahan ke CI, semua script sebaiknya divalidasi lokal supaya kamu tidak terjebak debugging di log Actions. Rangkaian perintah berikut menguji konektivitas API, script review, architecture check, sampai memastikan tidak ada key yang bocor ke YAML.

bash
 1# Validate semua scripts berjalan dengan benar sebelum push ke CI
 2
 3# 1. Test claude-call.sh
 4export ANTHROPIC_API_KEY="sk-ant-xxx"
 5./scripts/claude-call.sh "Say 'test passed' in 3 words" 20
 6# Expected output: "The test passed" atau serupa
 7
 8# 2. Test claude-review.sh dengan sample diff
 9git diff HEAD~1 -- '*.go' > /tmp/test-diff.txt
10./scripts/claude-review.sh /tmp/test-diff.txt general
11# Expected: output dengan CRITICAL/SUGGESTION/SCORE
12
13# 3. Test architecture check
14go run scripts/check-architecture.go ./...
15# Expected: "Architecture check: PASSED" atau violation list
16
17# 4. Simulate CI environment
18act -j claude-review  # gunakan 'act' tool untuk run Actions locally
19# Install act: brew install act
20
21# 5. Verify secret tidak di-expose ke logs
22grep -r "sk-ant" .github/ 2>/dev/null && echo "WARNING: API key in YAML!" || echo "✅ No hardcoded keys"

Langkah 4 dengan act sangat berharga: ia menjalankan workflow secara lokal sehingga kamu bisa memvalidasi perilaku CI penuh sebelum satu commit pun menyentuh GitHub.


03.10 Monitoring dan Alerting untuk CI Claude Usage

Setelah AI aktif di pipeline, kamu perlu memantau pemakaiannya agar biaya tetap terkendali. Konfigurasi berikut mencatat usage ke GitHub Step Summary di setiap run dan menyiapkan hook untuk laporan biaya mingguan.

yaml
 1# Track token usage di setiap run
 2- name: Track AI usage
 3  if: always()
 4  run: |
 5    # Log usage ke GitHub Step Summary
 6    cat >> $GITHUB_STEP_SUMMARY << EOF
 7    ## AI Usage
 8    - Model: claude-haiku-4-5-20251001
 9    - PR: #${{ github.event.number }}
10    - Author: ${{ github.actor }}
11    - Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)
12    EOF
13
14    # Optional: kirim ke monitoring system
15    # curl -X POST https://monitoring.santekno.com/api/ai-usage ...
16
17# Weekly cost report via scheduled job
18- name: Weekly AI Cost Report
19  if: github.event_name == 'schedule'
20  run: |
21    echo "Monthly AI tool costs:"
22    echo "Review Anthropic dashboard: https://console.anthropic.com/settings/usage"
23    echo "Review GitHub Copilot: https://github.com/organizations/santekno/settings/billing"

Dengan mencatat model dan timestamp di setiap run, kamu punya jejak audit untuk membandingkan estimasi versus pemakaian nyata di console Anthropic setiap bulan.


03.11 Troubleshooting Common Issues

Setup AI di CI hampir selalu memunculkan error di percobaan pertama. Kumpulan solusi berikut memetakan masalah yang paling sering muncul — dari permission denied sampai false positive — beserta cara mengatasinya.

bash
 1# Issue 1: "Permission denied" saat run script
 2chmod +x scripts/claude-call.sh scripts/claude-review.sh
 3git add scripts/*.sh
 4git commit -m "chore: make scripts executable"
 5
 6# Issue 2: "ANTHROPIC_API_KEY not set" di CI
 7# Check: apakah secret sudah di-set?
 8gh secret list | grep ANTHROPIC
 9# Jika tidak ada: gh secret set ANTHROPIC_API_KEY --body "sk-ant-xxx"
10
11# Issue 3: jq tidak tersedia di runner
12# ubuntu-latest sudah include jq, tapi jika tidak:
13sudo apt-get install -y jq
14
15# Issue 4: "curl: (6) Could not resolve host"
16# Check: apakah runner punya internet access?
17# Self-hosted runner mungkin tidak — check network policy
18
19# Issue 5: "content[0].text not found"
20# Debug:
21RESPONSE=$(curl ... api.anthropic.com ...)
22echo "$RESPONSE" | jq .  # lihat full response structure
23
24# Issue 6: Pipeline terlalu lambat
25# Identify bottleneck:
26# GitHub Actions → workflow run → lihat timeline setiap job
27# Bottleneck biasanya: go test (perlu cache), golangci-lint (perlu cache)
28
29# Issue 7: False positives dari AI review
30# Solusi: update copilot-instructions.md atau review prompt
31# Tambahkan: "Exception: X adalah intentional karena Y"

Dua isu yang paling sering: lupa chmod +x (Issue 1) dan secret yang belum di-set (Issue 2) — keduanya menggagalkan run pertama, dan keduanya perbaikannya satu baris.


03.12 Security Hardening untuk CI

Karena diff dan secret melewati pipeline, hardening keamanan bukan opsional. Konfigurasi berikut menerapkan lima praktik inti: pin action, minimal permissions, tidak meng-echo secret, validasi input, dan timeout.

yaml
 1# Best practices security di GitHub Actions:
 2
 3# 1. Pin action versions ke commit hash (bukan tag)
 4- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
 5
 6# 2. Minimal permissions per job
 7permissions:
 8  contents: read          # minimal yang dibutuhkan
 9  pull-requests: write    # hanya untuk job yang perlu
10
11# 3. Jangan expose secrets ke output
12- name: Claude API Call
13  env:
14    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
15  run: |
16    # JANGAN: echo $ANTHROPIC_API_KEY
17    # DO: gunakan langsung di command, tidak di-echo
18
19# 4. Validate input sebelum kirim ke AI
20- name: Validate diff before AI review
21  run: |
22    # Check ukuran diff (terlalu besar → skip atau chunk)
23    DIFF_SIZE=$(wc -c < /tmp/pr-diff.txt)
24    if [ "$DIFF_SIZE" -gt 50000 ]; then
25      echo "::warning::Diff terlalu besar ($DIFF_SIZE bytes), skip AI review"
26      exit 0  # graceful skip, tidak fail
27    fi
28
29    # Redact secrets dari diff sebelum kirim ke AI
30    sed -i 's/sk-ant-[a-zA-Z0-9_-]*/sk-ant-REDACTED/g' /tmp/pr-diff.txt
31    sed -i 's/ghp_[a-zA-Z0-9]*/ghp_REDACTED/g' /tmp/pr-diff.txt
32
33# 5. Timeout untuk mencegah hanging
34jobs:
35  claude-review:
36    timeout-minutes: 10    # maksimum 10 menit
37    steps:
38      - name: Claude API Call
39        timeout-minutes: 3   # per-step timeout

Langkah redaksi secret sebelum diff dikirim ke AI adalah defense in depth: bahkan jika API key atau token tak sengaja masuk diff, ia sudah tersamarkan sebelum meninggalkan runner.


03.13 Multi-Environment Setup

Beberapa tim ingin memisahkan biaya AI antara CI production dan development. Konfigurasi berikut memilih API key berbeda berdasarkan branch, sehingga usage per environment bisa dilacak terpisah.

yaml
 1# Berbeda API key untuk berbeda environment (opsional)
 2# Useful jika mau track cost per environment
 3
 4# Production CI (main branch):
 5secrets.ANTHROPIC_API_KEY_PROD
 6
 7# Development CI (feature branches):
 8secrets.ANTHROPIC_API_KEY_DEV
 9
10# Implementasi:
11- name: Set API key based on branch
12  run: |
13    if [ "${{ github.ref }}" == "refs/heads/main" ]; then
14      echo "ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY_PROD }}" >> $GITHUB_ENV
15    else
16      echo "ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY_DEV }}" >> $GITHUB_ENV
17    fi

Pemisahan key ini opsional, tapi berguna saat kamu perlu menjawab pertanyaan seperti “berapa biaya AI khusus untuk PR ke main?” tanpa menebak-nebak dari satu tagihan gabungan.


03.14 Reusable Workflow untuk Multi-Repo

Di setup monorepo atau multi-repo, menyalin workflow yang sama ke setiap service cepat menjadi mimpi buruk maintenance. Reusable workflow berikut memusatkan logika review sehingga repo lain cukup memanggilnya dengan beberapa baris.

yaml
 1# .github/workflows/reusable-ai-review.yml
 2# Reusable workflow yang bisa dipanggil dari repo lain
 3
 4name: Reusable AI Review
 5
 6on:
 7  workflow_call:
 8    inputs:
 9      go_version:
10        default: '1.22'
11        type: string
12      review_model:
13        default: 'claude-haiku-4-5-20251001'
14        type: string
15      fail_on_critical:
16        default: false
17        type: boolean
18    secrets:
19      anthropic_api_key:
20        required: true
21
22jobs:
23  ai-review:
24    runs-on: ubuntu-latest
25    permissions:
26      pull-requests: write
27      contents: read
28    steps:
29      - uses: actions/checkout@v4
30        with: { fetch-depth: 0 }
31
32      - name: Run AI Review
33        env:
34          ANTHROPIC_API_KEY: ${{ secrets.anthropic_api_key }}
35          REVIEW_MODEL: ${{ inputs.review_model }}
36        run: |
37          # ... review logic
38
39# Penggunaan dari repo lain:
40# .github/workflows/ci.yml (di repo santekno-payment-service)
41jobs:
42  ai-review:
43    uses: santekno/.github/.github/workflows/reusable-ai-review.yml@main
44    with:
45      go_version: '1.22'
46      fail_on_critical: true
47    secrets:
48      anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

Dengan pola ini, satu perubahan pada reusable workflow otomatis berlaku ke semua service yang memanggilnya — menghilangkan duplikasi yang selama ini menjadi sumber drift antar-repo.


03.15 Checklist Setup Lengkap

Sebelum menganggap setup selesai, ada baiknya menyisir kembali semua langkah lewat checklist. Daftar berikut mengelompokkan verifikasi per pendekatan (A/B/C) plus bagian keamanan.

text
 1Setup checklist untuk AI review di GitHub Actions:
 2
 3Pendekatan A (Copilot):
 4□ GitHub Copilot Business/Enterprise subscription aktif
 5□ .github/copilot-instructions.md dibuat dari CLAUDE.md
 6□ Workflow file .github/workflows/ai-review.yml dibuat
 7□ Test: buat PR kecil, verify Copilot comment muncul
 8
 9Pendekatan B (Claude API):
10□ ANTHROPIC_API_KEY di-set di GitHub Secrets
11□ scripts/claude-call.sh dibuat dan executable
12□ scripts/claude-review.sh dibuat dengan CLAUDE.md injection
13□ Workflow file dengan proper permissions
14□ Test: push PR, verify AI comment muncul
15
16Pendekatan C (Claude Code CLI):
17□ Node.js 20 tersedia di runner
18□ npm install -g @anthropic-ai/claude-code berhasil
19□ CLAUDE.md di root repository
20□ Test: run claude --print "test" di runner
21
22Security:
23□ Tidak ada API key hardcoded di YAML
24□ Permissions minimal per job (pull-requests: write hanya yang perlu)
25□ Diff di-redact dari secrets sebelum kirim ke AI
26□ Timeout di-set untuk semua AI steps
27□ Action versions di-pin ke commit hash

Bagian Security di checklist ini bukan pelengkap: keempat item terakhir adalah yang paling sering terlewat dan paling berisiko jika diabaikan.


03.16 Verifikasi End-to-End

Setup baru benar-benar terbukti bekerja ketika diuji end-to-end dengan pelanggaran yang disengaja. Skenario berikut membuat branch dengan kode yang sengaja salah, membuka PR, lalu memverifikasi AI menandai pelanggarannya.

bash
 1# Test end-to-end setup:
 2
 3# 1. Buat branch dan buat perubahan yang intentional salah
 4git checkout -b test/ai-review-setup
 5
 6# Buat file dengan intentional violation
 7cat > /tmp/test_order.go << 'GOFILE'
 8package usecase
 9
10import "errors"
11
12func BadFunction() error {
13    err := doSomething()
14    return err  // WRONG: not wrapped
15}
16
17type Order struct {
18    Price float64  // WRONG: should be int64
19}
20GOFILE
21
22cp /tmp/test_order.go internal/usecase/order/test_order.go
23git add internal/usecase/order/test_order.go
24git commit -m "test: intentional violations for AI review testing"
25git push origin test/ai-review-setup
26
27# 2. Buat PR di GitHub
28gh pr create --title "Test: AI Review Setup" \
29  --body "Testing AI review pipeline setup" \
30  --base develop
31
32# 3. Verify AI review muncul sebagai PR comment
33# Expected: AI flag CRITICAL untuk float64 dan unwrapped error
34gh pr view --json comments
35
36# 4. Cleanup
37git checkout develop
38git branch -d test/ai-review-setup
39gh pr close --delete-branch

Kalau AI menandai kedua pelanggaran itu — float64 untuk harga dan error yang tidak di-wrap — sebagai CRITICAL, berarti seluruh rantai dari diff sampai komentar PR sudah berfungsi utuh.


03.17 Cost Control per Repository

Biaya AI paling mudah membengkak ketika review dijalankan untuk file yang tidak relevan atau PR raksasa. Konfigurasi berikut membatasi review hanya ke file Go dan melewati PR yang terlalu besar demi efisiensi.

yaml
 1# Batasi AI review hanya untuk file yang relevan
 2on:
 3  pull_request:
 4    paths:
 5      # Hanya review Go files, bukan semua files
 6      - '**.go'
 7      # Excludes:
 8      # - '**.md'     → tidak perlu review dokumentasi
 9      # - '**.yaml'   → tidak perlu review config
10      # - '**.json'   → tidak perlu review JSON
11
12# Batasi berdasarkan ukuran PR
13- name: Check PR size
14  run: |
15    CHANGED_FILES=$(git diff origin/${{ github.base_ref }}...HEAD --name-only | wc -l)
16
17    if [ "$CHANGED_FILES" -gt 50 ]; then
18      echo "::notice::PR terlalu besar ($CHANGED_FILES files). AI review skip untuk efisiensi."
19      echo "SKIP_AI=true" >> $GITHUB_ENV
20    fi
21
22- name: AI Review
23  if: env.SKIP_AI != 'true'
24  # ... review logic

Dua pembatas ini — filter path dan ambang jumlah file — memastikan token AI hanya dibelanjakan untuk perubahan Go yang benar-benar perlu direview, bukan untuk perubahan dokumentasi atau config.


03.18 Debug Mode untuk Development

Ketika AI review berperilaku aneh, kamu butuh cara melihat apa yang sebenarnya dikirim ke model. Konfigurasi debug berikut mencetak potongan CLAUDE.md dan ukuran diff, dan bisa diaktifkan lewat repository variable tanpa mengubah kode.

yaml
 1# Debug mode yang bisa di-enable via repository variable
 2
 3- name: AI Review (with debug)
 4  env:
 5    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
 6    DEBUG_AI: ${{ vars.DEBUG_AI_REVIEW }}  # repository variable
 7  run: |
 8    if [ "${DEBUG_AI}" == "true" ]; then
 9      set -x  # print setiap command
10      echo "=== CLAUDE.md content (first 50 lines) ==="
11      head -50 CLAUDE.md
12      echo "=== Diff size ==="
13      wc -l /tmp/pr-diff.txt
14    fi
15
16    # Run review
17    ./scripts/claude-review.sh /tmp/pr-diff.txt general
18
19# Enable debug via GitHub:
20# Repository → Settings → Variables → New variable
21# Name: DEBUG_AI_REVIEW, Value: true

Karena debug dikendalikan oleh repository variable, kamu bisa menyalakannya saat menyelidiki masalah lalu mematikannya kembali — tanpa perlu commit atau revert apa pun.


03.19 Penggunaan Model yang Tepat per Use Case

Memilih model yang tepat adalah tuas biaya-vs-kualitas paling penting di CI. Panduan berikut membandingkan haiku dan sonnet — kapan masing-masing dipakai, beserta rule of thumb sederhananya.

text
 1Model selection guide untuk CI/CD:
 2
 3claude-haiku-4-5-20251001 (default untuk automation):
 4  Cost: $0.80/M input + $4.00/M output
 5  Speed: < 3 detik
 6  Quality: good untuk mechanical checks
 7
 8  Use untuk:
 9  ✅ Pre-commit quick review
10  ✅ PR description generation
11  ✅ Test failure analysis
12  ✅ Release notes generation
13  ✅ Security flag (tidak butuh deep reasoning)
14
15claude-sonnet-4-6 (untuk complex analysis):
16  Cost: $3.00/M input + $15.00/M output
17  Speed: 5-10 detik
18  Quality: better untuk nuanced analysis
19
20  Use untuk:
21  ✅ Architecture review yang complex
22  ✅ Spec compliance yang butuh reasoning
23  ✅ Security review yang butuh understanding context
24
25  NOTE: Gunakan dengan hemat di CI —
26  cost 3-4x lebih mahal dari haiku
27
28Rule of thumb:
29  Automation yang run di setiap PR → haiku
30  Analysis yang run sekali per sprint → sonnet

Rule of thumb-nya mudah diingat: pakai haiku untuk apa pun yang jalan di setiap PR, dan cadangkan sonnet hanya untuk analisis bernilai tinggi yang jarang dijalankan.


03.20 Ringkasan

Kita sudah setup tiga pendekatan untuk menggunakan Claude di GitHub Actions:

Pendekatan A (Copilot): Paling mudah, terbaik untuk PR review otomatis. Butuh Copilot subscription.

Pendekatan B (Claude API via HTTP): Fleksibel, murah, cocok untuk automation: PR description, failure analysis, release notes.

Pendekatan C (Claude Code CLI): Full experience, terbaik untuk complex multi-file analysis.

Key security rules:

  • API key selalu via ${{ secrets.ANTHROPIC_API_KEY }}
  • Diff di-redact dari secrets sebelum kirim
  • Timeout di semua AI steps
  • Permissions minimal per job

Di artikel selanjutnya, kita gunakan setup ini untuk implementasi quality gate pertama: spec validation di CI.

Artikel Terkait

💬 Komentar