Debug rilis Rust gagal saat crates.io bergantung pada GitHub biasanya bukan soal token saja. Dalam banyak kasus, cargo publish gagal padahal autentikasi valid, karena pipeline rilis atau dependensi crate Anda masih membutuhkan GitHub sebagai titik kritis: misalnya dependency berbasis Git, source archive yang diambil dari release asset, atau validasi yang menghubungi repository metadata.

Jika gejalanya adalah publish gagal, CI menolak rilis tanpa error yang jelas, atau proses verifikasi berhenti karena sumber kode tidak tersedia, masalahnya sering ada pada rantai dependensi rilis, bukan pada crates.io itu sendiri. Kuncinya adalah memisahkan proses publish dari layanan eksternal non-esensial dan memastikan artefak sumber yang dipakai saat rilis benar-benar mandiri.

Gejala Nyata yang Sering Muncul

Kasus ini biasanya tidak muncul sebagai satu error tunggal yang eksplisit. Yang terlihat justru kombinasi gejala berikut:

  • cargo publish gagal di CI, tetapi token crates.io masih valid.
  • Publish berhasil secara lokal pada kondisi tertentu, tetapi gagal di pipeline otomatis.
  • Proses verifikasi crate gagal saat mencoba menyelesaikan dependency atau membaca metadata repository.
  • Langkah build release menarik source archive atau asset dari GitHub, lalu gagal ketika archive tidak tersedia atau tidak dapat diakses.
  • Release tertunda karena pipeline menunggu langkah yang sebenarnya tidak esensial untuk publish.

Gejala seperti ini sering menyesatkan karena error yang muncul berada di permukaan, misalnya network failure, timeout, checksum mismatch pada artefak, atau kegagalan mengunduh dependency transitive yang ternyata masih merujuk ke GitHub.

Studi Kasus: Token Valid, Tapi Publish Tetap Gagal

Bayangkan sebuah crate backend Rust akan dirilis melalui CI. Pipeline melakukan langkah berikut:

  1. Checkout source dari GitHub.
  2. Generate changelog dan metadata release dari tag GitHub.
  3. Build paket.
  4. Jalankan cargo publish.
  5. Upload artefak tambahan ke GitHub Releases.

Di atas kertas, ini terlihat normal. Namun ada dua masalah laten:

  • Salah satu dependency internal masih dideklarasikan sebagai dependency Git, bukan versi registry.
  • Proses validasi sebelum publish mengunduh source archive dari URL GitHub release/tag, bukan dari working tree yang sudah ada di CI.

Saat GitHub mengalami gangguan parsial, repository masih bisa di-clone dari cache CI, tetapi endpoint archive, metadata tag, atau release asset gagal diakses. Akibatnya, publish terlihat seperti gagal di crates.io, padahal akar masalahnya ada pada ketergantungan tersembunyi terhadap GitHub.

Root Cause Analysis: Kenapa Bisa Terjadi?

1. Dependency Git tidak cocok untuk alur publish yang stabil

Crate yang dipublikasikan ke crates.io sebaiknya tidak bergantung pada dependency yang hanya tersedia melalui Git URL untuk kebutuhan rilis normal. Ketika dependency Anda merujuk ke GitHub, keberhasilan publish ikut bergantung pada ketersediaan dan konsistensi layanan GitHub.

Contoh pola yang berisiko:

[dependencies]
my_internal_lib = { git = "https://github.com/example/my_internal_lib", tag = "v0.3.1" }

Secara teknis ini bisa valid untuk pengembangan tertentu, tetapi untuk rilis publik ke crates.io, pola seperti ini menambah titik kegagalan eksternal. Jika crate tersebut seharusnya reusable dan stabil, lebih aman mempublikasikan dependency internal itu juga ke registry lalu mengunci ke versi:

[dependencies]
my_internal_lib = "0.3.1"

2. Source artifact tidak benar-benar mandiri

Banyak pipeline membuat paket rilis dengan mengambil archive dari tag GitHub, misalnya melalui endpoint .tar.gz atau release asset. Ini problematik karena artefak sumber untuk publish menjadi bergantung pada layanan lain di luar proses build lokal/CI itu sendiri.

Jika archive itu gagal diambil, berubah struktur folder-nya, atau tertunda propagasinya setelah tag dibuat, validasi rilis dapat gagal walaupun kode sebenarnya sudah ada di workspace CI.

3. Metadata repository dipakai sebagai syarat keras

Kolom seperti repository, homepage, atau documentation di Cargo.toml berguna, tetapi beberapa tool di sekitar pipeline sering memperlakukan URL tersebut sebagai dependency operasional. Contohnya:

  • script internal yang memverifikasi tag terhadap remote repository,
  • generator changelog yang mewajibkan API GitHub tersedia,
  • langkah audit yang mengambil release note atau commit range langsung dari GitHub.

Masalahnya bukan pada metadata itu sendiri, melainkan pada keputusan pipeline yang menjadikan akses GitHub sebagai prasyarat publish.

4. CI mencampur langkah esensial dan non-esensial

Langkah seperti upload release note, sinkronisasi changelog, atau publish dokumentasi sering dicampur dalam satu job yang sama dengan cargo publish. Saat satu layanan eksternal gagal, seluruh rilis ikut tertahan. Ini membuat proses publish tidak punya degradasi yang anggun.

Langkah Investigasi yang Efektif

Saat menghadapi kasus seperti ini, jangan mulai dari asumsi bahwa token crates.io salah. Lakukan investigasi berlapis dari yang paling menentukan.

1. Pisahkan masalah autentikasi dari masalah dependensi

Verifikasi dulu bahwa token memang dikenali oleh cargo di environment CI yang benar. Setelah itu, cek apakah kegagalan muncul sebelum atau sesudah fase packaging/verifikasi.

cargo login <TOKEN>
cargo publish --dry-run

Kenapa --dry-run penting? Karena mode ini membantu memeriksa packaging dan validasi awal tanpa benar-benar merilis crate. Jika --dry-run sudah gagal, fokus Anda sebaiknya pada isi paket, dependency, atau langkah build, bukan pada proses upload ke registry.

2. Inspeksi dependency graph untuk referensi Git

Cari dependency langsung maupun transitif yang masih menggunakan source Git. Dalam workspace besar, ini sering terlewat karena dependency tersebut berada di crate internal atau feature opsional.

Periksa file manifest dan lockfile secara manual, lalu cocokkan dengan kebijakan rilis Anda. Jika ada dependency Git yang masih aktif saat feature default dinyalakan, itu kandidat utama penyebab masalah.

3. Uji packaging secara lokal tanpa akses jaringan yang tidak perlu

Simulasikan rilis sedekat mungkin dengan kondisi minimum. Tujuannya adalah menjawab pertanyaan: apakah source package ini bisa dibangun dan diverifikasi tanpa bergantung pada GitHub?

Jika proses lokal hanya sukses saat internet penuh tersedia atau saat API GitHub bisa diakses, berarti paket atau pipeline Anda belum mandiri.

4. Audit langkah CI satu per satu

Banyak false lead muncul karena log CI menampilkan kegagalan terakhir, bukan kegagalan pertama yang relevan. Audit setiap tahap:

  • apakah changelog dihasilkan dari API GitHub,
  • apakah source archive diunduh dari tag release,
  • apakah tool internal memanggil endpoint release atau compare API,
  • apakah ada langkah verifikasi signature atau checksum terhadap artefak yang di-host di GitHub.

Sering kali cargo publish hanya menjadi korban dari kegagalan tahap pendahuluan.

5. Bandingkan publish lokal dan publish CI

Jika lokal berhasil tetapi CI gagal, perbedaan utamanya biasanya ada pada:

  • credential source,
  • network policy,
  • cache dependency,
  • script rilis tambahan yang hanya berjalan di CI,
  • environment variable yang mengaktifkan mode release tertentu.

Bandingkan command final yang benar-benar dieksekusi, bukan hanya definisi pipeline-nya.

False Lead yang Paling Umum

"Pasti token crates.io salah"

Ini dugaan pertama yang paling sering, tetapi tidak selalu benar. Jika token salah, biasanya error akan konsisten pada tahap autentikasi/upload. Jika error berubah-ubah antara fetch, verify, archive, atau metadata, kemungkinan besar akar masalahnya bukan token.

"crates.io sedang down"

Bisa saja, tetapi terlalu cepat menyalahkan registry sering membuat investigasi mandek. Jika ada petunjuk kegagalan pada Git fetch, release asset, changelog generator, atau URL repository, lihat dependency eksternal lain dalam pipeline.

"Kalau lokal sukses berarti pipeline benar"

Belum tentu. Lokal sering memiliki cache cargo, clone repository yang lengkap, atau akses jaringan yang lebih longgar. CI justru lebih jujur karena menunjukkan dependensi implisit yang belum Anda sadari.

"Repository metadata hanya informasi, tidak berpengaruh"

Di level Cargo, metadata memang deskriptif. Namun dalam ekosistem tool di sekitar release, metadata itu sering dipakai untuk operasi aktif. Jadi pengaruhnya datang dari otomasi buatan tim, bukan dari field manifest semata.

Perbaikan Praktis agar Rilis Tidak Bergantung pada GitHub

1. Kurangi dependency tunggal pada GitHub

Jika crate internal digunakan oleh crate lain yang akan dipublikasikan, prioritaskan publikasi crate tersebut ke crates.io atau registry yang memang Anda kelola untuk konsumsi release. Hindari dependency Git untuk jalur rilis utama.

Pilih dependency Git hanya jika:

  • proyek belum siap dipublikasikan,
  • dipakai sementara pada branch pengembangan,
  • bukan bagian dari artefak release final ke crates.io.

Untuk rilis stabil, dependency berbasis versi registry jauh lebih tahan gangguan dan lebih mudah diaudit.

2. Siapkan source artifact yang mandiri

Bangun paket dari working tree yang sudah ada di CI, bukan dari archive yang diunduh ulang dari GitHub. Jika Anda butuh artefak sumber terkompresi untuk distribusi tambahan, hasilkan langsung dari commit yang sudah di-checkout pada job tersebut.

Prinsipnya:

  • source of truth untuk publish adalah isi workspace saat job berjalan,
  • bukan archive eksternal yang dibuat layanan lain,
  • bukan release asset yang muncul belakangan.

Ini mengurangi risiko race condition antara pembuatan tag, propagasi release, dan publish crate.

3. Pisahkan langkah esensial dan non-esensial

Buat job atau stage yang berbeda antara:

  • esensial: test, package, verify, publish crate
  • non-esensial: upload release notes, publish binary tambahan, sinkronisasi changelog, update website dokumentasi

Dengan pemisahan ini, gangguan pada GitHub tidak otomatis memblokir publish ke crates.io jika langkah inti sebenarnya masih dapat berjalan.

4. Sediakan fallback saat outage

Fallback tidak harus rumit. Yang penting adalah ada mode operasi minimum. Contohnya:

  • jika generator changelog gagal mengakses GitHub API, gunakan changelog statis dari repository,
  • jika upload asset gagal, lanjutkan publish crate dan tandai langkah pasca-rilis untuk diulang,
  • jika verifikasi release metadata eksternal gagal, ubah menjadi warning, bukan hard failure, selama integritas source package tetap terjaga.

Catatan: fallback sebaiknya hanya diterapkan pada langkah non-esensial. Jangan menurunkan standar pada pemeriksaan integritas paket, isi file, lisensi, atau konsistensi versi.

5. Validasi pipeline tanpa layanan eksternal non-esensial

Lakukan uji berkala terhadap jalur rilis minimum: dari source checkout ke cargo publish --dry-run tanpa dependensi tambahan selain yang memang wajib. Jika pipeline inti masih bergantung pada GitHub API, release asset, atau repository archive, itu sinyal bahwa desain rilis perlu disederhanakan.

Contoh prinsip shell script yang lebih aman:

set -euo pipefail

cargo test
cargo package
cargo publish --dry-run

# Langkah non-esensial dijalankan terpisah
# dan tidak memblokir publish utama.

Pola Pipeline yang Lebih Tahan Gangguan

Untuk backend team yang mengelola beberapa crate, pola berikut biasanya lebih aman:

  1. Checkout source dari commit/tag yang sudah diketahui.
  2. Jalankan test dan lint.
  3. Pastikan semua dependency release menggunakan registry atau sumber yang memang dijamin tersedia.
  4. Bangun package dari workspace lokal, bukan dari archive eksternal.
  5. Jalankan cargo publish --dry-run.
  6. Publish crate.
  7. Setelah publish sukses, lanjutkan tugas non-esensial: GitHub Release, changelog terformat, upload binary, notifikasi.

Pola ini bekerja karena urutannya menempatkan registri dan source package sebagai inti, sementara integrasi platform eksternal diperlakukan sebagai pelengkap, bukan fondasi.

Checklist Pre-Release untuk Mencegah Kegagalan Serupa

  • Semua dependency release sudah menggunakan versi registry yang valid, bukan Git URL, kecuali memang benar-benar diperlukan.
  • cargo publish --dry-run sukses di environment bersih.
  • Source package dibangun dari workspace CI, bukan dari archive GitHub.
  • Langkah pasca-rilis dipisahkan dari langkah publish inti.
  • Generator changelog atau metadata release tidak menjadi syarat keras untuk publish.
  • Pipeline bisa tetap menerbitkan crate saat layanan eksternal non-esensial terganggu.
  • Lockfile, fitur default, dan dependency transitive sudah diperiksa agar tidak menarik source dari GitHub secara tidak sengaja.
  • Tim memiliki prosedur manual atau semi-manual saat outage, termasuk command yang harus dijalankan dan langkah yang boleh ditunda.

Penutup

Kegagalan publish crate ke crates.io sering tampak seperti masalah registry atau token, padahal akar masalahnya adalah desain pipeline rilis yang masih diam-diam bergantung pada GitHub. Begitu repository metadata, release asset, atau dependency Git menjadi prasyarat operasional, satu gangguan eksternal bisa menunda seluruh rilis.

Solusi yang paling efektif bukan menambah retry tanpa arah, tetapi mengurangi coupling: gunakan dependency registry untuk jalur rilis, hasilkan source artifact yang mandiri, validasi alur minimum tanpa layanan non-esensial, dan sediakan fallback yang jelas. Dengan begitu, publish ke crates.io tetap bisa berjalan walaupun platform pendukung sedang bermasalah.