Platform seperti GitHub, GitLab, dan Gitea semuanya memiliki sistem pelacakan dependensi dan pembaruan dapat. Namun, bagian yang paling menarik dari fitur-fitur ini sering kali bersifat premium atau bersumber tertutup (closed source). Saya ingin memahami bagaimana fitur-fitur ini bisa dibangun secara terbuka ke dalam platform seperti Forgejo. Karena Dependabot adalah bagian kunci dari perkakas dependensi GitHub, dan repositori dependabot-core berlisensi MIT serta ditulis menggunakan bahasa Ruby, ini tampak seperti tempat yang sangat tepat untuk memulai eksplorasi.

Sebagian besar pengembang perangkat lunak menganggap Dependabot sebagai sebuah bot pintar yang secara terus-menerus mengawasi repositori mereka dan membuat pull request (PR) saat pembaruan tersedia. Kenyataannya, basis kodenya hanyalah sebuah pustaka Ruby stateless (tanpa memori status) yang tidak tahu apa-apa di antara satu jadwal eksekusi dengan eksekusi berikutnya. Ia sekadar dibungkus oleh infrastruktur eksklusif milik GitHub yang menangani semua proses koordinasinya.

Ilustrasi Arsitektur Dependabot dan Ekosistem Open Source

Pada bulan Mei 2024, GitHub secara resmi mengubah lisensi dependabot-core menjadi MIT, menggantikan Prosperity Public License yang sebelumnya membatasi penggunaan komersial. Lisensi terbuka ini mencakup logika pembaruan inti: mem-parsing manifes, memeriksa registry, dan menghasilkan perubahan file. Sayangnya, fitur penjadwalan, pelacakan status, dan koordinasi yang membuat Dependabot bekerja layaknya sebuah layanan (service) tetap bersifat tertutup. Artinya, jika Anda ingin melakukan self-hosting, Anda harus membangun bagian-bagian tersebut sendiri.

Membongkar Basis Kode Dependabot

Repositori ini memiliki sekitar 330.000 baris kode Ruby yang mendukung lebih dari 25 ekosistem paket. Penamaannya cukup unik dan spesifik: menggunakan nama bundler alih-alih rubygems, pip bukan pypi, penggabungan npm_and_yarn, go_modules bukan golang, hex bukan elixir, dan cargo alih-alih crates. Gaya ini berbeda dengan standar ECMA baru bernama PURL yang menggunakan nama registry, atau perkakas lain yang menggunakan nama bahasa pemrograman. Jika Anda mencoba melakukan pemetaan antar sistem, bersiaplah menghadapi gesekan ketidakcocokan.

Setiap ekosistem mengimplementasikan empat kelas inti: FileFetcher untuk mengunduh file manifes dan lockfile dari repo, FileParser untuk mengekstrak dependensi, UpdateChecker untuk mencari versi baru di registry*, dan FileUpdater untuk menghasilkan perubahan file guna keperluan PR. Tingkat kompleksitasnya sangat bervariasi. FileParser untuk GitHub Actions hanya 194 baris, sementara Gradle mencapai 615 baris. Ekosistem *npm lebih gila lagi, mencakup banyak file untuk menangani package.json, berbagai format lockfile, yarn, pnpm, hingga workspaces. File pengujian file_updater_spec.rb untuk npm saja panjangnya mencapai 4.000 baris kode!

Untuk menjalankan pembaruan, dependabot-core menggunakan perintah shell ke perkakas bawaan package manager. File Dockerfile Python terdiri dari 209 baris karena harus menyertakan enam versi Python sekaligus (3.9 hingga 3.14). Versi lama dikompresi menggunakan zstd untuk menghemat ruang. Mereka menyalin sistem Python dari image Docker resmi lalu menulis ulang semua shebangs menggunakan perintah sed untuk memperbaiki path*. Bahasa Rust juga dibundel karena banyak paket Python memiliki ekstensi *native yang membutuhkan kompilasi.

Ekosistem npm memiliki "situs purbakala"-nya sendiri. Mereka masih menyertakan npm versi 6 di samping @npmcli/arborist yang lebih baru dari npm versi 8+. Mereka bahkan memelihara fork khusus dari Yarn 1.x yang dipublikasikan sebagai `@dependabot/yarn-lib`. Sebuah tambalan pada pacote ditambahkan agar GIT_CONFIG_GLOBAL masuk ke dalam variabel lingkungan yang diizinkan.

Bundler mendapatkan banyak monkey-patch yang berat. Salah satu patch secara paksa mengubah URL SSH [email protected]: menjadi HTTPS karena Dependabot berjalan tanpa kunci SSH. Patch lain memanipulasi $LOAD_PATH untuk mencegah pemuatan gem yang bermasalah saat mengevaluasi gemspecs. Yang ketiga bahkan menyuntikkan metadata versi Ruby palsu ke dalam proses resolusi agar tetap berfungsi tanpa versi Ruby target benar-benar terinstal.

Paket pengujian mereka mencakup ekosistem tiruan bernama "silent" yang sama sekali tidak melakukan panggilan jaringan. Sistem ini membaca versi yang tersedia dari file JSON lokal menggunakan format txtar, memungkinkan mereka menguji mesin pembaruan tanpa perlu menghubungi registry asli.

NuGet menarik repositori NuGet.Client aktual sebagai git submodule, yang dipaku pada versi release-6.12.x. Mereka juga menjadikan dotnet-core sebagai submodule.

Saat menanyakan data ke registry, dependabot-core mengidentifikasi dirinya menggunakan user agent string yang khas: dependabot-core/#{VERSION} ... (+https://github.com/dependabot/dependabot-core). Saya jadi penasaran seberapa masif lalu lintas Dependabot yang diterima oleh registry-registry besar setiap harinya.

Desain yang Sepenuhnya Stateless

Meskipun tingkat kompleksitasnya sangat tinggi, dependabot-core sejatinya bersifat stateless. Diberikan sebuah definisi tugas (job), ia akan mengkloning repo Anda, mem-parsing manifes, memeriksa registry, mengeluarkan perubahan file, lalu mati. Eksekusi berikutnya dimulai dari nol tanpa ingatan apa pun tentang eksekusi sebelumnya. Semua konteks harus diberikan di dalam definisi tugas tersebut:

job:
 package-manager: bundler
 source:
 provider: github
 repo: owner/repo
 directory: "/"
 commit: abc123
 existing-pull-requests:
 - - dependency-name: "lodash"
 dependency-version: "4.17.21"
 security-advisories:
 - dependency-name: sinatra
 affected-versions:
 - ">= 2.0.0, < 2.2.3"
 updating-a-pull-request: false

Definisi pekerjaan ini tidak terlihat di mana pun dalam hasil pull request*. Padahal, akan sangat berguna jika data ini disematkan di badan PR sebagai komentar HTML tersembunyi, memberikan metadata *machine-readable kepada alat eksternal tentang apa yang diperbarui dan alasannya. Saat saya membuat indeks PR Dependabot di dependabot.ecosyste.ms, saya terpaksa menulis 400 baris regex parsing untuk merekayasa balik nama dan versi paket hanya dari judul dan deskripsi PR.

Keberadaan field existing-pull-requests adalah bukti nyata: Dependabot tidak bisa melakukan query untuk mengetahui PR apa saja yang pernah ia buat sebelumnya. Infrastruktur GitHub-lah yang mencari PR Dependabot yang masih terbuka dan memasukkan daftar tersebut. Hal yang sama berlaku untuk security-advisories. Pustaka inti ini tidak memelihara basis data kerentanan. GitHub menarik data dari Advisory Database dan menyuntikkan CVE yang relevan per tugas. Pustaka tersebut hanya melakukan pencocokan pola nama paket dan rentang versi dari data yang disuapkan kepadanya.

Saat menyegarkan PR yang ada (yang sering disebut pengguna sebagai *"rebasing"), tugas tersebut menyertakan updating-a-pull-request: true dan mendaftar paket spesifik. Logika penyegaran akan memutuskan apakah harus memperbarui PR yang ada, menutupnya karena sudah up-to-date, menutupnya karena dependensi telah dihapus, atau menggantinya dengan PR baru untuk versi yang lebih mutakhir. Alasan penutupan dihitung secara internal (seperti dependency_removed, up_to_date) namun tidak diekspos dalam metadata PR.

GitHub menjalankan semua ini di atas infrastruktur Actions. Jadwal dependabot.yml Anda memicu sebuah tugas, GitHub memutar runner dengan image Docker dependabot-core, meneruskan definisi tugas via file JSON, dan menerima kembali panggilan API untuk membuat, memperbarui, atau menutup PR. Operasi Git terjadi di sisi GitHub melalui API mereka. Dependabot-core hanya mengeluarkan instruksi; ia tidak pernah menekan (push) commit secara langsung.

Apa yang Dibutuhkan oleh Sang Penjadwal?

Sifat stateless berarti harus ada pihak lain yang melacak status. GitHub melakukannya secara eksklusif dan tertutup, tetapi dependabot-gitlab menunjukkan apa yang dibutuhkan untuk melakukannya secara open source. Itu adalah aplikasi Rails yang mengimplementasikan koordinator yang hilang tersebut, khusus untuk GitLab. Skema basis data PostgreSQL mereka dengan jelas mengungkapkan status apa saja yang Anda butuhkan di luar dependabot-core:

Layanan merge request memeriksa PR yang sudah ada sebelum membuat yang baru, menangani penyelesaian konflik, auto-approve, hingga menutup PR usang. Semua logika koordinasi mahapenting yang dirahasiakan GitHub, ternyata bisa diimplementasikan dalam Ruby open source.

Polling Versus Pendekatan Berbasis Event

Sebuah repositori dengan 500 dependensi yang berjalan pada jadwal harian akan membuat sekitar 182.000 pencarian registry per tahun. Padahal, sebagian besar hari tidak ada perubahan apa-apa. Sistem mem-parsing setiap manifes dan memeriksa setiap registry hanya untuk tidak menemukan apa-apa lalu membuang hasilnya.

Alternatif yang jauh lebih cerdas adalah pembaruan berbasis event (kejadian). Jika Anda memelihara indeks dependensi lintas repositori, Anda bisa membalikkan model ini. Ketika lodash 4.17.22 dirilis ke npm, sistem cukup melakukan query repo mana saja yang masih menggunakan versi lama, dan memperbarui repo tersebut secara eksklusif. Ini berarti Anda hanya bereaksi pada dua hal yang benar-benar penting: munculnya rilis versi baru dan perubahan file manifes saat push kode.

Indeks dependensi inilah bagian yang tersulit, namun ia benar-benar ada. Di ecosyste.ms, kami melacak jutaan repositori lintas ekosistem. Data yang dibutuhkan untuk pembaruan berbasis event sudah tersedia. Yang kurang hanyalah penyambungan data ini ke umpan registry dan sebuah koordinator yang bisa memicu dependabot-core saat sesuatu berubah.

Renovate memiliki arsitektur yang sama. CLI-nya berlisensi AGPL secara terbuka, namun tetap stateless. Penjadwal, webhook, dan sistem antreannya hidup tersembunyi dalam edisi Community dan Enterprise milik Mend yang closed-source*. Perbedaannya, pembungkus milik Renovate masih tersedia untuk *self-hosting menggunakan kunci lisensi, sedangkan lapisan koordinasi GitHub benar-benar tidak tersedia untuk umum sama sekali.

Pada akhirnya, bongkahan-bongkahan di sekitar dependabot-core ini berpotensi dirangkai dengan cara yang berbeda di masa depan: dependabot-core sebagai mesin mekanik, dependabot-gitlab membuktikan bahwa penjadwal bisa dibuat terbuka, advisory databases sebagai penyuplai kerentanan, dan koordinator berbasis event yang menggantikan metode polling yang tidak efisien.

✍️ Artikel oleh: Tim Redaksi & Analis Ekosistem Open Source 📅 2 Januari 2026

Artikel ini merupakan bentuk analisis teknis independen terhadap arsitektur perangkat lunak otomatisasi dependensi. Informasi di atas bersumber dari observasi langsung ke repositori publik MIT dependabot-core, dependabot-gitlab, serta data telemetri ecosyste.ms yang digunakan untuk memahami metode stateless operation dan pengelolaan Advisory Database secara faktual. Seluruh tautan referensi primer telah disematkan langsung di dalam teks bacaan guna kemudahan verifikasi.