Belajar GitHub Actions - Automated Testing, Code Quality & Security Scanning
Episode 16 of 21

Belajar GitHub Actions - Automated Testing, Code Quality & Security Scanning

Kode yang berhasil dibuild belum tentu berkualitas dan aman. Di episode ini kita mengotomasi unit test, integration test, dan upload coverage ke Codecov, lalu mengintegrasikan ESLint, ShellCheck, dan SonarQube untuk menjaga kualitas. Kita juga mengaktifkan SAST dengan CodeQL dan Dependabot agar kerentanan pada kode dan dependensi terdeteksi lebih awal.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Pendahuluan

Di episode 15 kita mengelola self-hosted runner dan memahami kapan membutuhkannya. Sekarang kita masuk fase paling krusial dari CI/CD: membuktikan bahwa kode benar-benar layak di-release. Build yang sukses hanya membuktikan kode bisa dikompilasi; kualitas, keamanan, dan perilaku runtime masih belum teruji. Pipeline produksi yang baik harus menjawab empat pertanyaan: apakah fungsi bekerja (test), seberapa luas diuji (coverage), apakah kode bersih (static analysis), dan apakah ada kerentanan (security scanning).

Di episode ini kita membahas:

  1. Automatisasi unit test, integration test, dan upload coverage ke Codecov atau Coveralls.
  2. Code quality & static analysis dengan ESLint, ShellCheck, dan SonarQube/SonarCloud.
  3. Security scanning native GitHub dengan CodeQL (SAST) dan Dependabot.

Membangun Gerbang Kualitas di Pipeline

Bayangkan pipeline seperti jalur produksi pabrik. Setiap stasiun punya tugas memeriksa produk sebelum menyerahkannya ke stasiun berikutnya. Kalau satu stasiun lolos tanpa memeriksa, produk cacat akan terus mengalir sampai ke tangan pelanggan. Demikian pula pipeline: setiap job adalah stasiun pemeriksa yang menghentikan alur begitu menemukan masalah.

Urutan idealnya: lint → unit test → coverage → static analysis → security scan. Semua dijalankan saat pull request dibuat, sehingga masalah ditemukan sebelum kode masuk ke main.

Automatisasi Unit Test, Integration Test & Coverage

Menyiapkan Script Test yang Bisa Diukur

Prasyaratnya adalah script npm yang menghasilkan laporan coverage dalam format yang bisa dibaca alat eksternal. Untuk project Node.js dengan Vitest, contohnya:

NPMpackage.json - script test dengan coverage
{
  "scripts": {
    "test": "vitest run",
    "test:coverage": "vitest run --coverage"
  }
}

Command test:coverage menghasilkan file coverage/lcov.info plus laporan HTML. Pisahkan unit test (cepat, terisolasi, tanpa jaringan) dari integration test (memakai database atau HTTP nyata) supaya feedback lebih cepat — developer tidak perlu menunggu integration test yang lambat untuk setiap commit kecil.

Workflow Test + Upload Coverage ke Codecov

Workflow berikut menjalankan test lalu mengunggah laporan coverage ke Codecov, yang menampilkan badge dan bisa diatur untuk gagal kalau coverage turun di bawah threshold:

test.yml - unit & integration test plus coverage
name: Test & Coverage
 
on:
  push:
    branches: [main]
  pull_request:
 
permissions:
  contents: read
 
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Setup Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: Install dependensi
        run: npm ci
 
      - name: Jalankan unit & integration test
        run: npm run test:coverage
 
      - name: Upload coverage ke Codecov
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          files: coverage/lcov.info
          fail_ci_if_error: true

Beberapa hal penting:

  • npm ci melakukan install deterministik dari lockfile — lebih andal daripada npm install karena hasilnya selalu identik.
  • fail_ci_if_error: true membuat workflow gagal jika upload coverage error, jadi kalian tidak pernah diam-diam kehilangan laporan.
  • Token Codecov disimpan sebagai repository secret. Untuk repository public, Codecov juga menerima upload tanpa token pada pull request dari contributor.
  • Untuk Coveralls, action yang setara adalah coverallsapp/github-action@v2 dengan file yang sama.

Tip

Pasang branch protection di main yang mewajibkan job test lulus. Dengan begitu test dan coverage menjadi gerbang wajib sebelum pull request digabungkan.

Code Quality & Static Analysis

ESLint & ShellCheck

Linter menangkap error yang tidak ditemukan compiler: variabel tak terpakai, kondisi yang salah, atau pola berbahaya. Workflow terpisah membuat hasilnya jelas per job:

lint.yml - ESLint dan ShellCheck
name: Lint & Static Analysis
 
on:
  pull_request:
 
permissions:
  contents: read
 
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
 
      - name: ESLint
        run: npx eslint . --max-warnings 0
 
  shellcheck:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Jalankan ShellCheck
        uses: ludeeus/action-shellcheck@master

Flag --max-warnings 0 membuat lint gagal walaupun hanya ada warning — standar yang tepat untuk tim yang ingin disiplin. Job shellcheck memakai action community untuk memeriksa semua script *.sh di repository.

SonarQube & SonarCloud

Linter memeriksa file demi file; SonarQube menambahkan analisis lintas-modul: duplikasi kode, complexity, dan reliability bugs. SonarCloud adalah versi cloud-nya — gratis untuk project open source dan menyimpan hasil analisis di cloud tanpa perlu server sendiri:

Scan SonarCloud untuk pull request
name: SonarCloud Analysis
 
on:
  pull_request:
 
jobs:
  sonar:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Analisis SonarCloud
        uses: SonarSource/sonarcloud-scan-action@v5
        with:
          args: >
            -Dsonar.organization=my-org
            -Dsonar.projectKey=my-org_my-app
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

Hasil scan diposting sebagai komentar di pull request dan dihitung sebagai check. Kalau quality gate di dashboard SonarCloud tidak lolos, pull request bisa diatur untuk gagal.

Warning

Jangan pernah menuliskan token Sonar langsung di file YAML. Seluruh token diambil lewat context secrets, misal secrets.SONAR_TOKEN, bukan diketik manual ke dalam workflow.

Security Scanning Native GitHub

CodeQL — SAST dari GitHub

CodeQL menganalisis kode secara statis (SAST) dan mencari pola kerentanan seperti SQL injection, path traversal, atau unsafe deserialization. Action resminya butuh tiga langkah: init, autobuild, dan analyze.

codeql.yml - SAST CodeQL
name: CodeQL Analysis
 
on:
  push:
    branches: [main]
  pull_request:
  schedule:
    - cron: '0 3 * * 1'
 
permissions:
  security-events: write
  contents: read
 
jobs:
  analyze:
    name: Analyze
    runs-on: ubuntu-latest
    timeout-minutes: 360
    strategy:
      fail-fast: false
      matrix:
        language: ['javascript-typescript']
    steps:
      - name: Checkout kode
        uses: actions/checkout@v4
 
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{ matrix.language }}
 
      - name: Autobuild
        uses: github/codeql-action/autobuild@v3
 
      - name: Perform analysis
        uses: github/codeql-action/analyze@v3

Penjelasan penting:

  • security-events: write dibutuhkan agar hasil scan bisa ditulis ke Security tab.
  • schedule dengan cron 0 3 * * 1 (setiap Senin 03:00 UTC) menjalankan scan penuh berkala; pada pull request hanya delta perubahan yang dianalisis.
  • autobuild menebak cara build project; untuk bahasa yang tidak terdeteksi, ganti dengan langkah build manual.

Hasilnya muncul di tab Security → Code scanning sebagai alert, lengkap dengan severity, lokasi, dan rekomendasi perbaikan.

Dependabot — Vulnerability Scanning pada Dependensi

Kode kalian aman, tapi dependensinya belum tentu. Dependabot memantau package manager (npm, pip, Maven, dan lainnya) lalu membuka pull request otomatis ketika ada versi yang mengatasi CVE. Konfigurasinya disimpan di .github/dependabot.yml:

dependabot.yml - update dependensi otomatis
version: 2
updates:
  - package-ecosystem: npm
    directory: /
    schedule:
      interval: weekly
      day: monday
      time: '09:00'
      timezone: Asia/Jakarta
    open-pull-requests-limit: 10
    labels:
      - dependencies
      - security
    ignore:
      - dependency-name: '*'
        update-types: ['version-update:semver-major']

Dependabot membedakan security updates (dipicu CVE, prioritas tinggi, tidak menunggu schedule) dari version updates (jadwal rutin di atas). Keduanya sama-sama menghasilkan pull request, jadi beri label jelas dan wajibkan review sebelum merge.

Penutup

Di episode ini kita membangun gerbang kualitas dan keamanan:

  • Workflow test menjalankan unit & integration test lalu mengunggah coverage ke Codecov.
  • ESLint dan ShellCheck menangkap kesalahan gaya dan bug kecil sebelum merge.
  • SonarQube/SonarCloud menambahkan analisis lintas-modul dengan quality gate.
  • CodeQL men-scan kerentanan statis pada setiap pull request dan terjadwal.
  • Dependabot membuka pull request otomatis untuk dependensi yang bermasalah.

Pipeline yang menguji segalanya bisa terasa menakutkan ketika terjadi kecelakaan di production. Di episode 17 kita membahas environment protection rules & approval gateways — cara menambahkan persetujuan manual dan kontrol lingkungan agar production tidak bisa dideploy sembarangan. Sampai jumpa!