Mengapa Pipeline Anda Membutuhkan Pengujian dan Pemindaian Sebelum Terlambat
Anda baru saja selesai membangun aplikasi. Build berhasil. Artifact sudah ada. Lalu apa?
Banyak tim berhenti di sini. Mereka berasumsi bahwa jika kode bisa dikompilasi dan build lolos, artifact sudah siap untuk produksi. Namun, build yang sukses hanya memberi tahu bahwa kode bisa dirakit. Itu tidak memberi tahu apakah kode benar-benar berfungsi, apakah ada celah keamanan, atau apakah akan crash saat berkomunikasi dengan database.
Melewatkan pemeriksaan di tahap ini seperti mengirim paket tanpa melihat ke dalamnya. Anda mungkin mengirimkan sesuatu yang rusak, berbahaya, atau keduanya.
Mulai dengan Umpan Balik Tercepat: Unit Test
Pemeriksaan pertama dalam pipeline mana pun haruslah unit test. Pengujian ini memverifikasi perilaku kode Anda dari dalam ke luar. Anda memanggil fungsi, use case, atau endpoint, dan memeriksa apakah hasilnya sesuai dengan yang diharapkan.
Diagram alir berikut menunjukkan urutan pemeriksaan dan titik keputusan kritis di mana kegagalan menghentikan pipeline:
Unit test mengeksekusi lapisan logika aktual Anda, dari titik masuk hingga modul terdalam. Mereka tidak membutuhkan database nyata, layanan eksternal, atau panggilan jaringan. Itulah yang membuatnya cepat. Rangkaian unit test yang baik berjalan dalam hitungan detik atau paling lama beberapa menit.
Berikut adalah cuplikan pipeline YAML minimal yang menjalankan unit test dan pemindaian kerentanan, menghentikan pipeline jika salah satu gagal:
jobs:
test-and-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm test
- name: Run vulnerability scan
run: npm audit --audit-level=high
Jika unit test gagal, hentikan pipeline segera. Tidak ada gunanya melanjutkan jika perilaku dasar kode Anda rusak. Semua yang lain bergantung pada asumsi bahwa kode melakukan apa yang seharusnya dilakukan. Jika asumsi itu salah, setiap pemeriksaan selanjutnya hanya membuang-buang usaha.
Periksa Apakah Bagian-Bagiannya Benar-Benar Cocok: Integration Test
Unit test membuktikan bahwa perilaku yang bermakna berfungsi sementara dunia luar dikendalikan. Lapisan internal Anda masih bisa berjalan bersama, tetapi sistem tetangga disimulasikan atau dijaga dalam kendali pengujian. Perangkat lunak juga rusak ketika harus berbicara dengan dependensi nyata. Di sinilah integration test berperan.
Integration test memeriksa apakah modul-modul Anda dapat bekerja sama dengan benar. Dapatkah modul pengguna menyimpan data ke database? Apakah API merespons dengan benar ketika layanan pembayaran mati? Apakah format data cocok antar layanan?
Pengujian ini lebih lambat daripada unit test karena membutuhkan infrastruktur nyata: database, antrean pesan, atau instance uji dari layanan lain. Tapi justru di sinilah sebagian besar bug dunia nyata bersembunyi. Kode yang lolos semua unit test masih bisa gagal dalam integration test karena:
- String koneksi database yang salah
- Skema data yang tidak cocok
- Nilai konfigurasi yang salah
- Variabel lingkungan yang hilang
Integration test menangkap jenis masalah yang hanya muncul ketika komponen benar-benar saling bersentuhan. Jika Anda melewatkannya, Anda bertaruh bahwa kode Anda akan bekerja dengan sempurna di lingkungan yang belum Anda uji.
Pindai Kode Itu Sendiri: Static Analysis
Pengujian fungsional memeriksa apa yang dilakukan kode. Static analysis memeriksa bagaimana kode ditulis. Ia membaca kode sumber Anda tanpa mengeksekusinya dan mencari pola yang bermasalah.
Alat static analysis dapat mendeteksi:
- Variabel yang dideklarasikan tetapi tidak pernah digunakan
- Kode yang terlalu kompleks atau bertingkat dalam
- Potensi null pointer dereference
- Pelanggaran standar pengkodean yang disepakati tim Anda
- Pola sensitif keamanan seperti kredensial yang di-hardcode
Static analysis tidak akan menangkap bug logika. Tapi ia menangkap jenis kesalahan yang dilakukan pengembang puluhan kali sehari dan sering terlewatkan selama peninjauan kode. Ia juga menegakkan konsistensi di seluruh tim. Ketika setiap komit diperiksa terhadap aturan yang sama, basis kode tetap terpelihara bahkan saat tim bertambah besar.
Temukan Bahaya Tersembunyi: Vulnerability Scanning
Sebagian besar kerentanan keamanan dalam aplikasi modern tidak berasal dari kode yang Anda tulis. Mereka berasal dari library dan paket yang Anda gunakan. Satu dependensi usang dengan eksploitasi yang diketahui dapat membahayakan seluruh aplikasi Anda.
Vulnerability scanning memeriksa daftar dependensi Anda terhadap database masalah keamanan yang diketahui. Jika sebuah library memiliki kerentanan kritis, pemindai akan menandainya dan pipeline harus berhenti. Lebih baik menunda rilis daripada mengirimkan celah keamanan yang diketahui ke produksi.
Pemindaian ini harus berjalan pada setiap build, bukan hanya sebelum rilis besar. Kerentanan baru ditemukan setiap hari. Library yang aman minggu lalu mungkin memiliki CVE kritis yang diterbitkan hari ini. Pemindaian rutin memastikan Anda menangkap masalah ini sebelum mencapai pengguna.
Simpan Buktinya: Mengapa Hasil Harus Disimpan
Setiap pemeriksaan di tahap ini menghasilkan hasil. Unit test lulus atau gagal. Integration test melaporkan skenario mana yang berhasil. Static analysis mencantumkan peringatan dan kesalahan. Vulnerability scanning menandai dependensi.
Hasil ini adalah bukti. Mereka membuktikan bahwa pipeline melakukan pemeriksaannya dan menunjukkan apa yang terjadi. Simpanlah.
Bukti penting karena tiga alasan:
Debugging masalah produksi. Ketika terjadi kesalahan di produksi, Anda dapat memeriksa apakah pipeline mendeteksi masalah tersebut. Jika iya, Anda tahu pemeriksaan berhasil. Jika tidak, Anda tahu Anda membutuhkan pengujian yang lebih baik.
Audit dan kepatuhan. Regulator, pelanggan, dan kebijakan internal sering kali membutuhkan bukti bahwa setiap perubahan telah diuji sebelum dirilis. Bukti yang disimpan memenuhi persyaratan itu.
Analisis tren. Seiring waktu, bukti menunjukkan apakah kualitas kode Anda meningkat. Apakah pengujian semakin jarang gagal? Apakah kerentanan menurun? Apakah modul tertentu secara konsisten bermasalah? Data ini membantu Anda memutuskan di mana harus menginvestasikan upaya perbaikan.
Simpan bukti dalam format yang bisa dibaca mesin, seperti JUnit XML atau SARIF, dan juga simpan ringkasan yang bisa dibaca manusia. Tempatkan di lokasi yang bertahan setelah pipeline selesai, seperti artifact registry atau bucket penyimpanan khusus. Jangan mengandalkan log pipeline yang dibersihkan setelah beberapa hari.
Daftar Periksa Praktis untuk Tahap Ini
Sebelum Anda memindahkan artifact ke deployment, pastikan pemeriksaan ini sudah ada:
- Unit test berjalan pada setiap komit dan menggagalkan pipeline jika rusak
- Integration test mencakup interaksi komponen kritis
- Static analysis menegakkan standar kualitas kode
- Vulnerability scanning memeriksa semua dependensi
- Semua hasil disimpan sebagai bukti dengan timestamp dan ID komit
Apa yang Terjadi Selanjutnya
Setelah pengujian dan pemindaian lolos, Anda tahu artifact layak disimpan. Ia bekerja dengan benar, kode terpelihara, dan dependensi aman. Sekarang Anda perlu mengemasnya dan menyimpannya sehingga bisa di-deploy nanti.
Tetapi jika ada pemeriksaan yang gagal, pipeline berhenti. Tim mendapat notifikasi. Artifact tidak pernah mencapai tahap berikutnya. Itulah intinya: tangkap masalah di sini, bukan di produksi.
Biaya menemukan bug di produksi secara eksponensial lebih tinggi daripada menemukannya di pipeline. Pengujian yang gagal memakan waktu beberapa menit dari waktu pengembang. Gangguan produksi menghabiskan kepercayaan pengguna, respons insiden, dan sesi debugging larut malam.
Uji dan pindai sejak awal. Uji dan pindai secara otomatis. Dan simpan buktinya. Diri Anda di masa depan akan berterima kasih ketika terjadi kesalahan dan Anda bisa membuktikan dengan tepat apa yang diperiksa dan kapan.