Migrasi Git hosting dari GitHub ke platform lain tidak cukup dilakukan dengan mirror push repository. Ketika spam, abuse, atau beban moderasi di platform lama mendorong tim untuk pindah, risiko terbesar biasanya berada pada integrasi di sekeliling repository: OAuth login, token API, deploy key, webhook, bot, pipeline CI, dan otomasi yang mengasumsikan kontrak API tertentu.

Strategi yang aman adalah memperlakukan perpindahan ini sebagai migrasi sistem integrasi, bukan sekadar migrasi Git. Repository dapat disalin lebih awal, tetapi perpindahan trafik integrasi harus dilakukan bertahap: inventaris dependensi, uji kompatibilitas kontrak, jalankan dua jalur bila perlu, rotasi kredensial, lalu cutover dengan rollback yang terukur.

Mengapa clone repository bukan bagian tersulit

Objek Git—commit, branch, tag, dan sebagian besar riwayat—relatif portabel. Namun, komponen berikut sering tidak ikut berpindah secara otomatis atau memiliki representasi berbeda antarplatform:

  • Pull request atau merge request, komentar, review, label, milestone, issue, dan attachment.
  • Identitas pengguna, organisasi atau grup, role, team, dan aturan akses repository.
  • OAuth application, redirect URI, consent screen, serta access token yang diterbitkan oleh platform lama.
  • Webhook endpoint, format event, header signature, kebijakan retry, dan identifier delivery.
  • Konfigurasi CI, secret, variable, runner, artifact, cache, environment, dan status check.
  • Bot internal yang membaca atau menulis data melalui REST, GraphQL, atau API khusus platform.

Jangan mengasumsikan token, URL API, identifier pengguna, atau ID repository dapat dipakai kembali. Token umumnya diterbitkan untuk satu issuer dan satu model izin; token dari platform lama harus dianggap tidak valid untuk platform tujuan.

1. Petakan seluruh dependensi sebelum migrasi

Buat inventaris yang dapat diaudit. Mulailah dari konfigurasi organisasi, secret manager, konfigurasi CI, source code layanan, dokumentasi runbook, dan log akses API. Tujuannya bukan hanya menemukan integrasi yang diketahui, tetapi juga menemukan skrip lama yang masih aktif.

Inventaris yang perlu dikumpulkan

KomponenData yang dicatatRisiko saat pindah
OAuth appClient ID, pemilik aplikasi, redirect URI, scope, callback handler, pengguna aplikasiLogin gagal atau callback masih menerima token dari issuer lama
Personal/access tokenPemilik, lokasi penyimpanan, scope, masa berlaku, layanan pemakaiOtomasi gagal karena token tidak portabel atau izinnya berubah
Deploy key dan machine credentialRepository tujuan, mode read-only/write, host SSH, fingerprint host keyDeploy atau mirror gagal mengakses remote baru
GitHub App atau aplikasi ekuivalenEvent subscription, permission, instalasi per organisasi/repository, private keyBot kehilangan izin granular atau tidak menerima event
WebhookEndpoint, event, secret, owner, retry policy, consumer, SLAEvent hilang, ganda, signature ditolak, atau diproses dari sumber salah
CI dan botTrigger, API call, secret, identity, branch protection, status checkPipeline tidak berjalan atau proteksi merge tidak lagi terpenuhi

Tambahkan kolom owner, tingkat kritikalitas, lingkungan, dan rencana uji. Integrasi tanpa owner harus diperlakukan sebagai risiko sampai diputuskan untuk dipensiunkan atau dimigrasikan.

Cari dependensi tersembunyi

Lakukan pencarian terhadap hostname lama, URL API lama, nama organisasi, dan variabel seperti GIT_, OAUTH_, WEBHOOK_, atau TOKEN di repository konfigurasi dan CI. Periksa pula firewall, allowlist egress, DNS, API gateway, secret manager, sistem observability, dan layanan pihak ketiga seperti tool deployment atau issue tracker.

# Contoh pencarian indikasi ketergantungan pada platform lama
rg -n --hidden --glob '!**/.git/**' \
  'api\.(github|git-host-lama)|github\.com|GITHUB_|WEBHOOK.*SECRET' \
  .

Jangan memasukkan token aktif ke hasil pencarian, tiket migrasi, atau log CI. Catat lokasi secret dan identitas pemiliknya, bukan nilainya.

2. Uji kontrak API, bukan hanya endpoint

Platform Git yang berbeda dapat sama-sama menawarkan API dan webhook, tetapi kesetaraan nama event bukan jaminan kesetaraan perilaku. Buat contract test untuk perilaku yang benar-benar dipakai aplikasi Anda. Adapter khusus platform di satu lapisan akan jauh lebih aman daripada menyebarkan kondisi vendor di seluruh kode.

Perbedaan kontrak yang harus diuji

  • Format event: nama event, struktur payload, field opsional, representasi branch, aksi seperti opened/updated/merged, dan event yang tidak tersedia di platform baru.
  • Signature webhook: header tempat signature berada, algoritme yang digunakan, encoding payload mentah, dan aturan perbandingan signature. Verifikasi harus memakai body mentah sebelum JSON diparse atau diubah.
  • Scope dan izin: izin baca/tulis repository, akses organisasi, issue, pull/merge request, status CI, dan model instalasi aplikasi. Scope yang lebih lebar bukan pengganti pemetaan izin yang benar.
  • Pagination: parameter halaman atau cursor, ukuran halaman, format tautan lanjutan, urutan hasil, serta perilaku ketika data berubah di tengah iterasi.
  • Rate limit: batas per token, aplikasi, IP, atau organisasi; header informasi kuota; dan respons saat limit tercapai.
  • Retry dan status: timeout pengiriman, jumlah percobaan ulang, apakah respons selain 2xx diproses ulang, serta apakah delivery yang sama mempertahankan ID yang sama.
  • Identitas: perbedaan antara username, slug, numeric ID, UUID, email, dan ID organisasi/grup. Simpan ID stabil dari masing-masing platform, jangan menjadikan username sebagai primary key.

Untuk operasi tulis, uji juga semantik error: apakah respons konflik, validasi, atau otorisasi dapat dibedakan dengan andal; apakah operasi dapat diulang; dan apakah API menyediakan mekanisme idempotensi. Bila tidak, aplikasi Anda sendiri harus menyediakannya.

Normalisasi event di boundary aplikasi

Consumer bisnis sebaiknya tidak langsung bergantung pada payload mentah vendor. Ubah webhook menjadi event internal dengan kontrak yang Anda miliki sendiri.

{
  "event_id": "source:delivery-8f42",
  "source": "git-host-baru",
  "event_type": "merge_request.updated",
  "occurred_at": "2025-03-08T10:15:31Z",
  "repository": {
    "external_id": "repo-42",
    "full_name": "platform/payments-api"
  },
  "actor": {
    "external_id": "user-91",
    "login": "rani"
  },
  "change": {
    "number": 187,
    "head_sha": "a1b2c3d4",
    "target_branch": "main"
  },
  "raw_delivery_ref": "delivery-8f42"
}

Field source dan external_id mencegah benturan ID antarplatform. Simpan payload mentah secara terbatas dan terenkripsi bila diperlukan untuk audit atau replay, dengan kebijakan retensi yang jelas.

3. Bangun consumer webhook yang tahan event ganda dan terlambat

Webhook adalah sistem pengiriman at-least-once dalam banyak desain praktis: event dapat dikirim lebih dari sekali, tiba tidak berurutan, atau terlambat. Endpoint harus cepat mengakui penerimaan, lalu memindahkan pemrosesan ke queue. Jangan melakukan proses berat atau panggilan API berantai sebelum mengembalikan respons sukses.

Verifikasi signature dan deduplikasi

Gunakan secret berbeda untuk setiap sumber webhook dan setiap fase migrasi. Verifikasi signature secara constant-time, batasi ukuran request, dan tolak timestamp yang terlalu lama jika skema signature platform mendukung timestamp. Nama header dan format signature berbeda antarplatform; contoh berikut sengaja memakai adapter agar detail vendor tidak bocor ke handler utama.

async function receiveWebhook(request) {
  const rawBody = await request.readRawBody();
  const source = request.headers.get('x-git-source');
  const deliveryId = webhookAdapter.deliveryId(request.headers);

  if (!webhookAdapter.verifySignature(source, request.headers, rawBody)) {
    return { status: 401 };
  }

  const eventId = `${source}:${deliveryId}`;
  const inserted = await db.webhookDeliveries.insertIfAbsent({
    event_id: eventId,
    received_at: new Date(),
    raw_payload: rawBody
  }); // event_id memiliki unique constraint

  if (!inserted) {
    return { status: 202 }; // delivery duplikat sudah pernah diterima
  }

  await queue.enqueue('process-git-event', { eventId });
  return { status: 202 };
}

Jika platform tidak menyediakan delivery ID yang stabil, gunakan kunci deduplikasi yang diturunkan dari sumber, tipe event, ID objek, revision atau SHA, dan waktu dalam jendela terbatas. Pendekatan hash payload dapat membantu, tetapi jangan menjadikannya satu-satunya kunci: payload yang sama secara bisnis dapat valid untuk diproses lagi pada waktu berbeda.

Skenario gagal yang wajib diuji

  • Event ganda: delivery yang sama tiba dua kali karena timeout di sisi pengirim. Pastikan hanya satu pekerjaan bisnis dibuat.
  • Webhook terlambat atau tidak berurutan: event update lama tiba setelah merge. Worker harus membandingkan revision, status terkini, atau mengambil ulang data otoritatif sebelum melakukan perubahan destruktif.
  • Token kadaluarsa atau dicabut: worker menerima 401/403. Tandai kredensial tidak sehat, hentikan retry agresif, beri alert ke owner, dan jalankan rotasi terkontrol.
  • Rate limit: hormati header atau respons limit yang tersedia, gunakan backoff dengan jitter, dan jangan mengulang request gagal secara paralel tanpa batas.
  • Signature salah: periksa apakah proxy mengubah body, secret yang dipakai salah, atau handler memverifikasi JSON yang sudah diparse alih-alih byte mentah.

4. Strategi dual-run dan cutover bertahap

Dual-run tidak selalu berarti menulis ke dua platform secara penuh. Pilih bentuknya berdasarkan risiko: mirror Git untuk menjaga sinkronisasi referensi, dual-delivery webhook ke consumer yang sama, atau mode baca-bandingkan untuk API. Hindari dua sumber kebenaran untuk operasi tulis seperti merge, label, atau komentar kecuali aturan otoritasnya sangat jelas.

Fase migrasi yang direkomendasikan

  1. Persiapan: buat organisasi/grup, repository, akses anggota, aturan proteksi branch, runner CI, secret, deploy key, dan aplikasi integrasi di platform baru.
  2. Sinkronisasi data: migrasikan repository dan data kerja yang memang dibutuhkan. Validasi commit, tag, branch, default branch, LFS bila digunakan, serta akses clone melalui SSH dan HTTPS.
  3. Shadow read: jalankan adapter baru dalam mode baca. Bandingkan hasil list repository, anggota, pull/merge request, dan status pipeline terhadap ekspektasi tanpa mengubah data produksi.
  4. Dual-delivery terbatas: kirim event dari kedua platform ke endpoint yang dapat membedakan source. Proses platform baru sebagai observasi dahulu atau untuk subset repository berisiko rendah.
  5. Cutover per kelompok: pindahkan satu organisasi, beberapa repository, atau satu alur bot pada satu waktu. Tetapkan platform baru sebagai sumber otoritatif untuk write operation pada kelompok tersebut.
  6. Stabilisasi: monitor error autentikasi, delivery webhook, antrean, rate limit, dan kegagalan CI sebelum memperluas cakupan.
  7. Retire: setelah periode observasi dan persetujuan owner, cabut webhook, aplikasi, token, deploy key, dan akses di platform lama.

Gunakan feature flag untuk memilih adapter API, endpoint clone, dan sumber event berdasarkan repository. Dengan cara ini, cutover dapat dilakukan per repository tanpa redeploy besar.

Rotasi secret dan kredensial

Jangan menyalin personal token lama ke platform baru. Terbitkan kredensial baru dengan prinsip least privilege, simpan di secret manager, beri nama berdasarkan sistem dan lingkungan, serta dokumentasikan owner dan tanggal rotasi. Jika platform mendukung beberapa secret webhook aktif, tambahkan secret baru, deploy consumer yang dapat memverifikasi keduanya sementara, lalu hapus secret lama setelah delivery lama tidak mungkin tiba lagi.

Untuk deploy key dan SSH, verifikasi host key platform baru melalui jalur tepercaya dan perbarui konfigurasi known_hosts. Jangan menonaktifkan pemeriksaan host key hanya agar deploy cepat berhasil.

5. Rencana rollback yang benar-benar dapat dijalankan

Rollback harus dibatasi waktunya dan memiliki syarat jelas. Jika kedua platform menerima write operation tanpa aturan, rollback justru menghasilkan divergence. Selama masa cutover, tentukan sumber otoritatif per repository dan larang merge atau perubahan metadata pada platform non-otoritatif.

Contoh kriteria rollback: kegagalan login di atas ambang yang ditetapkan tim, antrean webhook tertahan, pipeline rilis kritis tidak dapat selesai, atau bot menulis status yang salah. Prosedur rollback minimal mencakup mengalihkan feature flag ke adapter lama, mengembalikan URL remote atau trigger CI yang relevan, menonaktifkan write operation pada platform baru, dan merekonsiliasi commit atau metadata yang sempat berubah.

Uji rollback dalam staging atau repository pilot. Rencana yang hanya ada di dokumen tetapi belum diuji biasanya gagal pada detail seperti secret yang sudah dicabut, DNS yang belum dipulihkan, atau perubahan proteksi branch yang tidak terdokumentasi.

Checklist verifikasi pascamigrasi

Git, akses, dan identitas

  • Clone, fetch, push, branch, tag, dan default branch bekerja dengan URL baru.
  • Hak akses anggota, team, service account, dan organisasi/grup sesuai model izin platform baru.
  • Mapping ID pengguna dan organisasi disimpan; username tidak dipakai sebagai satu-satunya identitas.
  • Deploy key, machine credential, dan verifikasi SSH host key telah diperbarui.

OAuth, token, dan aplikasi

  • Login OAuth berhasil dari awal hingga callback, termasuk pengguna baru dan pengguna yang sebelumnya terhubung ke issuer lama.
  • Redirect URI yang terdaftar tepat, menggunakan HTTPS bila diperlukan, dan callback lama tidak menerima token baru secara keliru.
  • Token baru memiliki izin minimum yang diperlukan; token lama sudah dijadwalkan untuk pencabutan.
  • GitHub App atau aplikasi ekuivalen telah diinstal pada cakupan repository yang benar dan permission-nya diuji dengan operasi nyata.

Webhook, API, dan CI

  • Signature diverifikasi dari raw body, delivery duplikat tidak memicu efek bisnis ganda, dan event terlambat tidak menimpa state baru.
  • Dashboard atau metrik menunjukkan delivery masuk, kegagalan verifikasi, latency queue, retry, dan dead-letter queue.
  • Contract test mencakup pagination, rate limit, error otorisasi, dan operasi tulis penting.
  • CI berjalan pada push dan pull/merge request, secret tersedia, status build terlihat pada alur review, dan artifact/deploy dapat diakses.
  • Bot komentar, label, sinkronisasi issue, release automation, dan notifikasi diuji pada repository pilot sebelum diperluas.

Penutup

Migrasi Git hosting yang dipicu oleh meningkatnya spam sebaiknya menghasilkan perbaikan arsitektur, bukan hanya pergantian URL repository. Dengan memisahkan adapter vendor dari logika bisnis, menormalisasi event, menerapkan deduplikasi, dan menjalankan cutover bertahap, tim dapat pindah platform tanpa memutus OAuth, webhook, token API, maupun alur delivery.

Ukuran keberhasilan bukan sekadar seluruh repository tampil di platform baru, melainkan seluruh alur penting—autentikasi, review, build, deploy, bot, dan audit—tetap bekerja dengan sumber kebenaran yang jelas.