CI/CD GitHub Actions: Dari Pull Request sampai Deployment Aman
Pipeline GitHub Actions dengan least privilege, environment protection, concurrency, OIDC, artifact, smoke test, dan rollback.
0xNN · · 7 min read
CI/CD GitHub Actions: Dari Pull Request sampai Deployment yang Aman
Pipeline yang baik tidak hanya menjalankan build. Ia memisahkan validasi pull request dari izin deployment, membatasi token, mencegah dua deploy bertabrakan, dan menyimpan bukti versi yang benar-benar dirilis.
Contoh berikut memakai aplikasi Node.js, tetapi prinsipnya berlaku untuk stack lain.
---
Pisahkan CI dan Deployment
CI berjalan pada pull request dan push ke branch utama:
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
npm ci memakai lockfile dan gagal jika manifest tidak sinkron. Commit lockfile agar runner memasang dependency yang telah direview.
permissions: contents: read membatasi GITHUB_TOKEN. Tambahkan permission lain hanya pada job yang benar-benar memerlukannya.
Untuk workflow production, GitHub merekomendasikan pin third-party action ke full-length commit SHA karena tag dapat dipindahkan. Tag dipakai di contoh agar mudah dibaca; pilih SHA dari repository action resmi dan gunakan Dependabot untuk memperbaruinya.
---
Deployment Hanya Setelah Commit Utama Lolos
Workflow deployment dapat dipicu setelah CI selesai:
name: Deploy production
on:
workflow_run:
workflows: [CI]
types: [completed]
branches: [main]
permissions:
contents: read
concurrency:
group: production
cancel-in-progress: false
jobs:
deploy:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
timeout-minutes: 20
environment:
name: production
url: https://example.com
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.workflow_run.head_sha }}
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run build
- run: npm run deploy
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
Checkout head_sha penting agar yang dideploy adalah commit yang lulus CI, bukan main terbaru yang mungkin berubah setelah workflow dimulai.
concurrency mencegah dua deployment production berjalan bersamaan. Pilihan cancel-in-progress bergantung pada platform: membatalkan deploy yang sedang menulis state bisa lebih berbahaya daripada menunggu.
---
Gunakan Environment Protection
GitHub Environment dapat menyediakan:
• required reviewer;
• pembatasan branch/tag yang boleh deploy;
• environment secrets;
• deployment history;
• protection rule tambahan.
Secret environment baru tersedia untuk job setelah protection rule terpenuhi. Ini lebih aman daripada memberi semua workflow akses ke secret production.
Fitur tertentu bergantung pada jenis repository dan paket GitHub. Periksa dokumentasi akun sebelum merancang approval wajib.
---
Hindari Credential Jangka Panjang jika Ada OIDC
Untuk cloud provider yang mendukung OpenID Connect, workflow dapat meminta token berumur pendek:
permissions:
contents: read
id-token: write
id-token: write hanya memberi kemampuan meminta OIDC token; izin cloud tetap ditentukan trust policy provider. Batasi trust berdasarkan repository, branch atau environment, audience, dan claim lain yang relevan.
OIDC mengurangi kebutuhan menyimpan access key jangka panjang. Jika provider belum mendukungnya, gunakan token dengan scope minimum, expiry/rotation, dan environment secret.
Jangan mencetak secret. Masking GitHub bukan jaminan semua transformasi nilai akan terdeteksi.
---
Jangan Menjalankan Kode Pull Request Tak Tepercaya dengan Secret
Workflow pull_request dari fork tidak seharusnya menerima secret production. Berhati-hatilah dengan pull_request_target: event ini berjalan dalam konteks base repository dan dapat menjadi berbahaya jika checkout serta menjalankan kode PR yang tidak dipercaya.
Pisahkan job yang menguji kode PR dari job privileged. Jangan melewatkan input seperti branch, judul PR, atau komentar langsung ke shell:
Berisiko jika nilai berasal dari input tidak tepercaya
• run: echo "${{ github.event.pull_request.title }}"
Gunakan environment variable dan quoting yang benar, atau action/API yang tidak membentuk perintah shell.
---
Build Sekali atau Build Ulang?
Contoh di atas membangun ulang pada deployment. Untuk reproducibility lebih kuat, CI dapat menghasilkan artifact immutable, mencatat checksum dan commit SHA, lalu deployment mempromosikan artifact yang sama.
Artifact perlu:
• retention yang sesuai;
• provenance dan checksum;
• pemisahan artifact PR dari production;
• proteksi terhadap overwrite;
• konfigurasi environment yang tidak membocorkan secret ke bundle frontend.
Variable frontend seperti VITE_* atau NEXT_PUBLIC_* biasanya masuk ke bundle browser. Jangan menyimpan token server di sana meskipun nilainya berasal dari GitHub Secrets.
---
Verifikasi dan Rollback
Deployment belum selesai hanya karena command exit 0. Tambahkan smoke test:
curl --fail --retry 5 --retry-delay 3 \
https://example.com/health
Verifikasi versi atau commit yang aktif, endpoint penting, dan error rate. Simpan cara rollback yang telah diuji: mempromosikan artifact sebelumnya, rollback release provider, atau mengembalikan konfigurasi.
Migration database membutuhkan strategi kompatibilitas. Perubahan “expand and contract” biasanya lebih aman: tambahkan schema kompatibel, deploy aplikasi, migrasikan data bila perlu, lalu hapus bagian lama pada rilis terpisah.
---
Cache dengan Kunci yang Benar
Cache dependency dapat mempercepat CI, tetapi cache bukan pengganti lockfile. Kunci cache harus berubah ketika dependency berubah. actions/setup-node dengan cache: npm memakai dependency cache dan tetap mengharuskan npm ci.
Jangan memasukkan .env, token, hasil build yang mengandung secret, atau credential package registry ke cache. Cache dari branch atau pull request yang tidak dipercaya juga tidak boleh diperlakukan sebagai artifact production tepercaya.
---
Matrix dan Path Filter Secukupnya
Library yang mendukung beberapa versi Node dapat memakai matrix:
strategy:
fail-fast: false
matrix:
node: [20, 22]
Aplikasi yang hanya berjalan pada satu runtime production tidak selalu membutuhkan matrix besar. Uji minimal runtime production dan versi yang secara resmi didukung.
Path filter dapat menghindari build mahal saat hanya dokumentasi berubah, tetapi hati-hati pada file bersama seperti lockfile, konfigurasi root, action reusable, dan infrastructure. Pipeline yang salah melewatkan perubahan lebih buruk daripada pipeline sedikit lebih lambat.
Tambahkan timeout-minutes pada job agar runner macet tidak menghabiskan kapasitas tanpa batas. Retensi artifact dan log juga perlu disesuaikan dengan kebutuhan audit serta biaya.
---
Checklist Pipeline
1. CI wajib lulus sebelum merge dan deploy.
2. Dependency dipasang dari lockfile.
3. Token workflow memakai least privilege.
4. Action dipin ke SHA dan diperbarui terkontrol.
5. Production memakai environment protection dan concurrency.
6. Secret tidak tersedia untuk kode PR tak tepercaya.
7. OIDC dipakai jika provider mendukung.
8. Commit/artifact yang dideploy dapat dibuktikan.
9. Smoke test dan rollback benar-benar diuji.
Referensi
• GitHub Actions: Workflow syntax
• GitHub Actions: Secure use reference
• GitHub Actions: Deployment environments
• GitHub Actions: Control deployments
• GitHub Actions: OpenID Connect