2 poin oleh GN⁺ 2025-03-21 | Belum ada komentar. | Bagikan ke WhatsApp
  • Dalam proses mengembalikan CI yang kompleks ke GitHub Actions, merge queue, beberapa runner, build Rust, image Docker, dan pengujian integrasi saling terkait, sehingga biaya debugging tampak lebih besar daripada konfigurasi itu sendiri
  • Semua perubahan yang masuk ke main harus lulus pengujian, dan kesalahan kecil diperbaiki otomatis seperti format, dependensi yang tidak digunakan, serta lint; artefak CI juga harus sama dengan artefak rilis
  • Untuk mewajibkan validasi sebelum dan sesudah merge queue, nama job harus dibuat sama pada kedua tahap; jika tidak, check bisa berhenti atau perubahan yang gagal dapat ter-merge
  • GITHUB_TOKEN, permissions workflow, token kustom, serta pengecualian fork dan self-hosted runner saling bertaut, membuat model keamanan sulit dipahami dan memperbesar peluang kesalahan
  • Eksekusi container Docker, workflow YAML, dan pengujian lokal yang terbatas memperlambat pengembangan, tetapi skrip CI baru memangkas waktu merge secara signifikan

CI kompleks yang kembali ke GitHub Actions

  • Selama 2 minggu terakhir, skrip CI ditulis ulang kembali ke GitHub Actions
  • Ini adalah perombakan ketiga untuk konfigurasi CI
    • Awalnya menggunakan GitHub Actions
    • Lalu pindah ke Earthly
    • Karena Earthly dihentikan, kembali lagi ke GitHub Actions
  • CI saat ini menangani merge queue, beberapa runner, build Rust, image Docker, dan pengujian integrasi berat secara bersamaan
    • Runner yang digunakan mencakup self-hosted, blacksmith.sh, dan GitHub-hosted
    • Saat menggabungkan satu PR, sekitar 1 jam waktu CI terpakai di beberapa runner paralel

Syarat yang harus dipenuhi CI

  • Semua perubahan yang masuk ke main harus lulus semua pengujian
  • Kesalahan kecil seperti masalah format, dependensi yang tidak digunakan, dan lint sebaiknya diperbaiki otomatis alih-alih berakhir sebagai kegagalan
  • Artefak yang diuji di CI harus sama dengan artefak rilis sebenarnya
  • Demi pengalaman developer, CI harus selesai dengan cepat
  • GitHub Actions secara teknis mendukung syarat-syarat ini, tetapi proses konfigurasinya disertai jebakan tersembunyi, perilaku yang tidak konsisten, dan debugging yang sulit

Merge queue dan status check

  • Kunci untuk menjaga branch main tetap bersih adalah merge queue GitHub
    • merge queue melakukan rebase PR di atas main sebelum menjalankan CI
  • Eksekusi CI yang diperlukan terbagi menjadi dua tahap
    • Menjalankan CI sebelum masuk ke queue untuk memperbaiki masalah kecil secara otomatis
    • Menjalankan CI lagi di dalam queue untuk memvalidasi status merge final
  • Agar kedua eksekusi wajib di GitHub Actions, nama job harus ditetapkan sama pada kedua tahap
    • GitHub memperlakukan kedua eksekusi sebagai check yang sama, sehingga keduanya harus berhasil sebelum merge dapat dilakukan
    • Cara ini ditemukan melalui jawaban Stack Overflow setelah beberapa jam debugging
  • Cara lain dapat membuat status check tertahan sebelum masuk ke queue sehingga job tidak dimulai, atau membuat job yang seharusnya gagal di dalam merge queue tetap berujung pada merge

Model keamanan GitHub Actions yang sulit dipahami

  • Setelah sebuah GitHub Action populer baru-baru ini diretas, muncul respons “kunci dependensi ke hash”, tetapi di komentar banyak yang mengatakan hampir tidak ada orang yang melakukannya
  • GitHub Actions memiliki token default bernama GITHUB_TOKEN
    • Token ini diinisialisasi dengan izin default
    • Izin default dapat diatur di pengaturan repository melalui Actions → General → Workflow Permissions
  • Jika izin default GITHUB_TOKEN bersifat terbatas, izin harus dinaikkan agar action dan perintah yang diperlukan dapat berjalan; jika izin default bersifat permisif, sebagian izin dapat dihapus dari file workflow
  • Default yang lebih baik adalah memulai dari tanpa izin, lalu pengguna hanya menambahkan izin yang diperlukan
  • Jenis izinnya banyak, dan bagi yang bukan ahli GitHub, sulit memahami apa yang dilindungi masing-masing izin

Pengecualian token dan izin

  • Saat membuat rilis GitHub secara otomatis dengan softprops/action-gh-release, token kustom CI_RELEASE digunakan
- name: Release on GitHub
  if: env.version_exists == 'false'
  uses: softprops/action-gh-release@v2
  with:
    tag_name: v${{ env.CURRENT_VERSION }}
    generate_release_notes: true
    make_latest: true
    token: ${{ secrets.CI_RELEASE }}
  • Rilis itu sendiri tetap selesai dengan token default, tetapi workflow setelah rilis tidak terpicu
    • Tidak ada indikasi khusus, sehingga penyebabnya baru diketahui setelah menemukan issue dari orang yang mengalami masalah sama
  • Izin juga dapat dinaikkan di dalam YAML workflow
    • Struktur menaikkan izin di dalam kode yang hendak dilindungi terasa asing
  • Menurut dokumentasi GitHub, kunci permissions dapat menambah atau menghapus izin baca untuk repository fork, tetapi biasanya tidak dapat memberikan izin tulis
    • Pengecualiannya adalah ketika admin memilih opsi Send write tokens to workflows from pull requests di pengaturan GitHub Actions
  • Karena banyak pengecualian dan jebakan, model keamanan GitHub Actions kuat sekaligus memperbesar permukaan serangan dan peluang kesalahan

Ketidakpastian self-hosted runner

  • Dokumentasi GitHub tidak merekomendasikan penggunaan self-hosted runner pada repository publik
    • Alasannya, fork dari repository publik dapat menjalankan kode berbahaya di mesin self-hosted runner melalui PR
  • GitHub juga memiliki pengaturan self-hosted runner yang mewajibkan persetujuan untuk menjalankan PR dari kontributor eksternal
  • Tidak ada jawaban yang jelas dalam dokumentasi apakah penggunaan pengaturan ini bersama self-hosted runner aman, dan di internet pun tidak ada konsensus
  • Kompleksitasnya tinggi, sehingga tetap sulit untuk yakin 100%

Benturan Docker dan GitHub Actions

  • GitHub Actions dapat menjalankan job di dalam container
    • Keuntungannya, dependensi dapat dipaketkan terlebih dahulu dalam dev container tanpa perlu menginstalnya setiap kali
  • Dalam penggunaan nyata, masalah izin file terus berulang
    • Container membangun file sebagai satu user, tetapi GitHub runner dapat berjalan dengan uid/gid yang berbeda
    • Akibatnya, file di dalam container, GitHub workspace, atau direktori host sementara mungkin tidak dapat diakses
  • Direktori $HOME juga bisa tidak selaras
    • Dev container dapat menginstal tool di /home/ubuntu
    • Di dalam GitHub Actions, $HOME bisa menjadi /github/home
    • Tool yang bergantung pada file di bawah $HOME mungkin tidak dapat menemukan file yang diperlukan
  • Action yang berinteraksi dengan sistem host juga dapat rusak
    • Cache GitHub dibatasi 10GB, sehingga action sticky disk dari blacksmith digunakan untuk me-mount drive NVMe untuk caching
    • Ini tidak berfungsi di dalam container, lalu terselesaikan setelah perbaikan dari blacksmith.sh
  • Field container sendiri juga memiliki batasan
    • entrypoint tidak dapat di-override
    • Tidak mungkin menjalankan hanya beberapa step di dalam container dan sisanya di luar

Pengembangan dan debugging workflow YAML

  • Logika GitHub Actions ditulis dalam YAML, dan semakin kompleks, semakin mudah terjadi kesalahan
  • Pemeriksaan GitHub YAML linter di RustRover membantu, tetapi diperlukan pemeriksaan statis yang lebih baik
  • Di lokal, sulit menguji perilaku CI sebenarnya secara memadai
    • act adalah tool yang dikenal, tetapi hanya mendukung sebagian kecil dari hal yang ingin dilakukan di CI
  • Cara debugging terbaik adalah membuat satu repository lain yang sama, lalu mengulang git commit -a -m "wip" && git push test-ci branch sampai CI berjalan sesuai harapan

Pemisahan workflow dan penggunaan ulang artefak

  • Agar tidak menjalankan seluruh pipeline CI setiap kali, tiap workflow dijaga tetap kecil
  • Di akhir setiap workflow, artefak diunggah, lalu workflow berikutnya mengunduhnya agar tidak perlu build ulang dari awal
  • Workflow dapat diuji secara terisolasi dengan mengunduh artefak dari eksekusi sebelumnya
    • Namun saat mengunduh dari eksekusi sebelumnya, token harus diberikan ke action download-artifact
    • Token ini boleh token default, tetapi mengapa masih harus dinyatakan secara eksplisit tetap menjadi pertanyaan yang belum terjawab
  • File workflow utama menjadi rantai yang memanggil file YAML lain
jobs:
  invoke-build-rust:
    name: Build Rust
    uses: ./.github/workflows/build-rust.yml
  invoke-build-java:
    name: Build Java
    uses: ./.github/workflows/build-java.yml
  invoke-tests-unit:
    name: Unit Tests
    needs: [invoke-build-rust, invoke-build-java]
    uses: ./.github/workflows/test-unit.yml
  invoke-tests-adapter:
    name: Adapter Tests
    needs: [invoke-build-rust]
    uses: ./.github/workflows/test-adapters.yml
    secrets: inherit
  invoke-build-docker:
    name: Build Docker
    needs: [invoke-build-rust, invoke-build-java]
    uses: ./.github/workflows/build-docker.yml
  invoke-tests-integration:
    name: Integration Tests
    needs: [invoke-build-docker]
    uses: ./.github/workflows/test-integration.yml
  invoke-tests-java:
    name: Java Tests
    needs: [invoke-build-java]
    uses: ./.github/workflows/test-java.yml
  • Beberapa job memerlukan secrets: inherit
    • Saat satu workflow memanggil workflow lain, secret tidak dibagikan secara default
    • Ini adalah penyebab masalah di mana seluruh pipeline CI gagal, tetapi masing-masing step berjalan jika dieksekusi terpisah

Merge makin cepat, debugging masih mahal

  • Skrip CI baru secara signifikan mengurangi waktu merge, dan hasilnya memuaskan
  • Namun terlalu banyak waktu diperlukan untuk mencapai kondisi itu, dan debugging perlu dibuat lebih mudah saat masalah muncul

Belum ada komentar.

Belum ada komentar.