Skenario paling dingin di dunia version control dimulai sederhana: berkas .env berisi koneksi database dan API key ikut ter-commit, ketemu seminggu kemudian. Refleks pertama hampir semua orang — hapus berkasnya, commit, selesai — dan refleks itu salah total. Commit bukan tempat penyimpanan terkini, melainkan mesin waktu: setiap commit adalah snapshot utuh yang tidak pernah diubah oleh commit setelahnya. Chapter ini membuktikan dengan perintah nyata bahwa secret yang “dihapus” tetap terbaca dari riwayat, menyebar ke setiap clone, dan — bila repo dipublikasikan — dipindai platform secara otomatis. Respons insidennya dibahas di akhir, dan pembersihan riwayatnya menunggu di Menghapus Secret dari Riwayat
.
Demo: Berkas Dihapus, Secret Tetap Ada #
Sandbox menyiapkan repository toko-buku dengan tiga commit: proyek dimulai, konfigurasi lingkungan ditambahkan, lalu berkasnya dihapus:
git log --onelineOutput yang Dihasilkan:
0df07cd Hapus berkas rahasia dari repository
f463b04 Tambah konfigurasi lingkungan
7871a7a Commit awal proyekHash di mesin pembaca berbeda, urutan dan pesannya yang stabil. Posisi terakhir memang bersih — .env sudah tidak ada:
git show HEAD:.envOutput yang Dihasilkan:
fatal: path '.env' does not exist in 'HEAD'Namun commit f463b04 adalah snapshot lengkap saat .env masih hidup, dan snapshot itu tidak ikut terhapus:
git show f463b04:.envOutput yang Dihasilkan:
DATABASE_URL=postgres://budi:[email protected]/toko
API_KEY=sk-live-YOUR_API_KEYInilah bukti terkuat bahwa “hapus berkasnya” tidak pernah menghapus secret: git show <hash>:.env membuka isi berkas tepat seperti saat commit itu dibuat. Perintah git rm pada commit ketiga hanya menambahkan snapshot baru yang tidak memuat .env — snapshot lama tetap utuh di object database, terjangkau satu hash jauhnya.
Riwayat Menyebar ke Setiap Clone #
Sifat terdistribusi Git memperparah keadaan. Satu perintah git clone menyalin seluruh object database — termasuk snapshot ber-secret. Sandbox membuktikannya dengan meng-clone repository di atas ke direktori klon-teman, lalu membaca berkas yang sama dari clone tersebut:
cd klon-teman
git show f463b04:.envOutput yang Dihasilkan:
DATABASE_URL=postgres://budi:[email protected]/toko
API_KEY=sk-live-YOUR_API_KEYSetiap pemilik clone — kolega, server CI, fork di akun orang lain — memegang salinan yang identik. Membersihkan riwayat di repository pusat tidak menyentuh clone-clone itu; secret tetap terbaca dari laptop kolega meskipun repository pusat sudah steril. Konsekuensinya lugas: satu-satunya tindakan yang menutup insiden bagi semua pemegang salinan adalah merotasi kredensialnya, bukan membersihkan berkasnya.
Melacak Jejak: log –all –source #
Sebelum membersihkan, ketahui dulu jejaknya. Opsi --all memeriksa seluruh ref (semua branch, tag, remote-tracking), dan --source menampilkan ref mana yang membawa tiap commit:
git log --all --source --oneline -- .envOutput yang Dihasilkan:
0df07cd refs/heads/main Hapus berkas rahasia dari repository
f463b04 refs/heads/main Tambah konfigurasi lingkunganDua commit menyentuh .env: yang memasukkannya dan yang menghapusnya — keduanya di main. Pada repository nyata, keluaran ini sering lebih panjang: branch lama yang belum terhapus, tag rilis, bahkan commit yang hanya hidup di remote-tracking branch pun ikut terdaftar. Daftar ini adalah peta kerja untuk Menghapus Secret dari Riwayat
: pembersihan harus menyentuh setiap ref di daftar itu, bukan hanya main.
Platform Memindai Secret #
Untuk repository yang berada di platform, ada penjaga ketiga yang bekerja otomatis: secret scanning. GitHub memindai isi repository untuk pola kredensial yang dikenali — format token GitHub, kunci AWS, string koneksi database, dan daftar panjang lainnya — dalam dua arah: push protection menolak push yang berisi secret sebelum ia masuk, dan pemindaian historis mencari secret di repo publik yang sudah ada. Bila token GitHub sendiri terdeteksi, platform tidak hanya memberi laporan: token dinonaktifkan otomatis dan pemiliknya dikabarkan. GitLab menempatkan fitur setara lewat secret push protection. Perilaku platform ini terdokumentasi di dokumentasi GitHub tentang secret scanning .
Dua catatan penting menjaga ekspektasi tetap jujur. Pemindaian otomatis hanya menjamin terhadap pola yang dikenali — string rahasia internal perusahaan tidak dikenali polanya dan lolos begitu saja. Dan pada repository privat, pemindaian menyeluruh umumnya adalah fitur berbayar atau perlu diaktifkan organisasi — jangan berasumsi repo privat sudah terlindungi.
Respons Insiden: Rotasi Dulu, Bersih-bersih Kemudian #
Saat secret ter-commit diketahui, urutan tindakan menentukan besar kerusakan. Empat langkah ini disusun berdasarkan prioritas:
| Langkah | Tindakan | Alasannya |
|---|---|---|
| 1. Rotasi | cabut/ganti kredensial di platform penyedianya sekarang | clone lama memegang secret selamanya; hanya rotasi yang menutup aksesnya |
| 2. Evaluasi | git log --all --source -- <berkas> untuk memetakan sebaran | pembersihan harus menyentuh semua ref yang tercatat |
| 3. Bersihkan | tulis ulang riwayat dengan alat yang sesuai | mencegah clone baru mewarisi secret |
| 4. Audit | periksa log aktivitas platform | mencari tanda token dipakai pihak lain selama bocor |
Urutan langkah 1 sebelum 3 bukan selera: pembersihan riwayat butuh waktu — koordinasi tim, force-push, re-clone — dan selama waktu itu secret tetap hidup di clone-clone lama. Rotasi memutus aksesnya seketika tanpa menunggu pembersihan tuntas.
Dengan secret sudah dirotasi, pekerjaan berikutnya menjadikan repository itu sendiri bersih — tiga jalur pembersihan, dari yang ringan untuk commit terakhir hingga menulis ulang seluruh riwayat, menunggu di Menghapus Secret dari Riwayat .