Belajar Semantic Release - Keamanan GitHub Actions
Episode 12 of 23

Belajar Semantic Release - Keamanan GitHub Actions

Menerapkan prinsip least privilege di GitHub Actions, mulai dari token dengan scope minimal, pembatasan workflow pada branch tertentu, hingga pengamanan secret dan pemindaian keamanan dependensi agar pipeline rilis tidak menjadi celah masuk penyerang.

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

Pendahuluan

Di episode 11 workflow rilis sudah dipagari kondisi branch. Sekarang tiba waktunya mengunci pintu-pintu lain. Pipeline rilis adalah bagian paling sensitif di repository: ia bisa membuat tag, menerbitkan package, dan memegang token yang berharga. Satu kesalahan izin dan seluruh ekosistem bisa terbobol lewat jalur yang paling tidak terduga.

Episode ini membahas GitHub Actions security best practices: least privilege dengan token berscope minimal, pembatasan workflow pada branch tertentu, pengelolaan secret, dan pemindaian keamanan dependensi.

Pembahasan Utama

Prinsip Least Privilege

Least privilege berarti: beri akses sesedikit mungkin, hanya untuk pekerjaan yang diperlukan, dan hanya selama dibutuhkan. Job lint tidak butuh hak menulis apa pun. Job release butuh menulis tag dan publish package — tetapi tidak butuh akses ke hal lain.

Token yang Dipakai di Pipeline

TokenAsalScopeDipakai untuk
GITHUB_TOKENotomatis per job, kedaluwarsascope repositorycheckout, tag, GitHub release
NPM_TOKENGitHub secretscope publish di registrypublish package ke npm

GITHUB_TOKEN dibuat otomatis oleh GitHub untuk setiap job dan kedaluwarsa saat workflow selesai — tidak perlu disimpan sebagai secret persisten. Sebaliknya, NPM_TOKEN adalah token nyata yang harus kalian buat dan simpan.

Warning

Bedakan scope kedua token. GITHUB_TOKEN hanya berlaku untuk satu repository dan ikut kedaluwarsa, sehingga aman di sebagian besar job. NPM_TOKEN harus dibuat dengan scope publish khusus pada akun yang memang ditugaskan rilis, bukan token dengan akses penuh ke seluruh akun. Jangan pernah menampilkan nilai token di log, nama step, atau artifact, dan jangan pernah meletakkannya di workflow tanpa enkripsi secret.

Deklarasikan permissions Secara Eksplisit

Sejak awal 2023, repository baru memakai default read-only, tetapi banyak repository lama masih berjalan dengan default yang lebih luas. Selalu deklarasikan permissions secara eksplisit agar perilakunya tidak bergantung pada pengaturan organisasi.

Job non-release cukup contents: read:

Job lint dengan akses minimum
name: CI
on:
  pull_request:
permissions:
  contents: read
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run lint

Job release baru menaikkan scope, dan hanya untuk yang dibutuhkan:

Job release dengan scope terbatas
jobs:
  release:
    runs-on: ubuntu-latest
    environment: production
    permissions:
      contents: write
      packages: write
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - name: Semantic Release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
        run: npx semantic-release

Dua detail penting: environment: production menempatkan job di bawah environment yang bisa dilindungi peninjau, dan persist-credentials: false membuat token tidak menempel pada git config sehingga langkah berikutnya tidak mewarisi kredensial.

Tip

Gunakan environment untuk rilis produksi. Di Settings > Environments, konfigurasikan environment production dengan "Required reviewers" — job release tidak akan berjalan sampai peninjau menyetujui. Secret juga bisa di-scope per environment sehingga token produksi tidak bocor ke environment lain.

Pembatasan Workflow pada Branch Tertentu

Batasi trigger di blok on agar workflow hanya pernah berjalan di branch yang dimaksud:

Workflow hanya untuk branch release
name: Release
on:
  push:
    branches:
      - main
      - staging

Dengan ini, push ke feature/* atau pull request dari fork tidak akan pernah menjalankan job release. Untuk workflow rilis, ini pertahanan pertama sekaligus paling sederhana.

Warning

Berhati-hatilah dengan pull_request_target. Workflow ini berjalan dengan konteks branch dasar dan secret repository, sehingga pull request dari fork bisa mengeksekusi kode dari kontributor asing dengan akses yang lebih luas. Kalau tidak benar-benar diperlukan, jangan pakai pull_request_target untuk job yang mengeksekusi kode dari PR.

Pemindaian Dependensi

Aktifkan Dependabot untuk pull request pembaruan otomatis:

.github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "weekly"

Lengkapi dengan pemindaian terjadwal di CI:

Pemindaian audit dan CodeQL
name: Security Scan
on:
  schedule:
    - cron: '0 6 * * 1'
permissions:
  contents: read
jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm audit --audit-level=high
  codeql:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
      - uses: actions/checkout@v4
      - uses: github/codeql-action/init@v3
      - uses: github/codeql-action/analyze@v3

npm audit menangkap kerentanan pada dependensi langsung dan transitif, CodeQL menangkap bug keamanan pada kode. Perhatikan job CodeQL menaikkan scope security-events: write hanya untuk dirinya sendiri — contoh nyata least privilege dalam satu workflow.

Kesalahan Umum

KesalahanGejalaSolusi
permissions: write-allToken berhak apa sajaScope minimal per job
Secret bocor ke logNilai token terbacaJangan echo, pakai env terenkripsi
pull_request_target untuk rilisFork bisa memicu rilisBatasi branch atau hindari event itu

Penutup

Pada episode 12 ini kalian telah:

  • Menerapkan least privilege: deklarasikan permissions eksplisit, non-release contents: read, release contents: write dan packages: write.
  • Membatasi workflow rilis di blok on agar hanya berjalan pada branch yang tepat.
  • Mengamankan rilis produksi dengan environment dan "Required reviewers".
  • Menutup jalur masuk penyerang lewat Dependabot, npm audit, dan CodeQL, dengan NPM_TOKEN ber-scope publish khusus sebagai aset paling berharga.

Di episode 13 kita akan melengkapi pertahanan dengan Protected Branches & PR Policies — branch protection rules, required status checks, dan mandatory reviewers untuk main dan rc. Sampai jumpa di episode 13!

Belajar Semantic Release - Keamanan GitHub Actions | Belajar Semantic Release