Lompat ke konten
Aback Tools Logo

Perilaku yaml-cpp terhadap Kunci Duplikat Dijelaskan

yaml-cpp diam-diam menerima kunci duplikat pada mapping YAML dan hanya menyimpan nilai terakhir: tanpa galat, tanpa peringatan, tanpa indikasi bahwa nilai sebelumnya dibuang. Panduan ini menjelaskan apa yang dilakukan yaml-cpp, bagaimana parser lain berbeda, skenario nyata apa yang menghasilkan duplikat, dan cara mendeteksinya sebelum menimbulkan bug kehilangan data senyap di produksi.

DH
Tutorials & How-Tos12 menit baca2,700 kata

yaml-cpp diam-diam menerima kunci duplikat pada mapping YAML dan hanya menyimpan nilai terakhir: tanpa galat, tanpa peringatan, tanpa indikasi bahwa nilai sebelumnya dibuang. Spesifikasi YAML secara eksplisit menyebut perilaku ini tidak terdefinisi, namun setiap parser besar membuat pilihannya sendiri. Panduan ini menjelaskan apa yang dilakukan yaml-cpp, bagaimana parser lain berbeda, skenario nyata apa yang menghasilkan duplikat, dan cara mendeteksinya sebelum menimbulkan bug kehilangan data senyap di produksi.

TerakhirNilai menangNilai sebelumnya hilang senyap
0Galat secara defaultyaml-cpp tidak memberi peringatan
Tak def.Kata spesifikasiYAML 1.2 menyebutnya tidak terdefinisi

Apa itu kunci duplikat di YAML?

Kunci duplikat terjadi ketika string kunci yang sama muncul lebih dari sekali pada level yang sama dalam satu mapping YAML. Pada bahasa seperti JSON hal ini juga tidak terdefinisi, tetapi terlihat jelas secara visual. Di YAML, tempat mapping membentang beberapa baris dan file bisa berisi ratusan baris, kunci duplikat mudah dimasukkan tanpa sengaja dan sama mudahnya terlewat saat peninjauan.

Seperti apa bentuk duplikat

Bentuk paling sederhana adalah pengulangan langsung: kunci didefinisikan di bagian atas mapping lalu didefinisikan ulang di bawahnya, kadang dengan nilai berbeda. Ini paling sering terjadi karena kesalahan salin-tempel, refaktor yang belum selesai, atau penggabungan potongan konfigurasi dari sumber berbeda. Nama kuncinya identik byte per byte (huruf besar-kecil sama, spasi sama) dan hanya muncul dua kali dalam blok mapping yang sama.

  • Kesalahan salin-tempel: blok kunci diduplikasi saat menambahkan bagian baru berdasarkan bagian yang sudah ada
  • Penggantian nama yang belum tuntas: kunci diganti namanya tetapi yang asli tidak dihapus, sehingga keduanya ada di file
  • Penggabungan konfigurasi: dua fragmen YAML disatukan dan keduanya kebetulan mendefinisikan kunci level atas yang sama
  • Pembatalan komentar: kunci yang dikomentari diaktifkan kembali tanpa menghapus pengganti aktif di bawahnya
  • Ekspansi template: generator atau mesin template mengeluarkan kunci yang sama dua kali dari cabang kondisi berbeda

Catatan

Kunci duplikat pada level anidasi berbeda bukanlah duplikat: `database.host` dan `cache.host` adalah kunci yang sepenuhnya terpisah meski keduanya memakai `host` sebagai nama lokalnya. Aturan kunci duplikat hanya berlaku di dalam satu blok mapping, bukan di seluruh dokumen.

Apa yang sebenarnya dikatakan spesifikasi YAML

Spesifikasi YAML 1.2 membahas kunci duplikat secara langsung dan tanpa ambiguitas: kunci tersebut tidak diizinkan dalam mapping YAML yang valid. Bagian 3.2.1.3 menyatakan bahwa kunci mapping harus unik di dalam mapping tersebut. Setiap dokumen yang memuat kunci duplikat secara teknis tidak sesuai spesifikasi.

Isi sebuah node mapping adalah himpunan tak berurutan dari pasangan node kunci/nilai, dengan batasan bahwa setiap kunci bersifat unik.

- Spesifikasi YAML 1.2, bagian 3.2.1.3

Tidak terdefinisi bukan berarti penguraian tidak valid

Nuansa pentingnya adalah meski spesifikasi menyebut kunci duplikat tidak sesuai, ia tidak mewajibkan parser menolaknya dengan galat keras. Sebaliknya, spesifikasi menyebut perilakunya tidak terdefinisi, artinya setiap implementasi parser bebas menangani duplikat sesuai pilihannya. Itulah sebabnya yaml-cpp, PyYAML, js-yaml, dan parser lain menerima duplikat tanpa melempar galat, meski dokumen hasilnya secara teknis YAML tidak valid.

Mengapa ini penting dalam praktik

"Perilaku tidak terdefinisi" dalam sebuah spesifikasi berarti aplikasi Anda bergantung pada detail implementasi yang bisa berubah antar versi pustaka. yaml-cpp saat ini memakai "nilai terakhir menang", tetapi tidak ada jaminan dalam spesifikasi untuk itu. Versi mendatang bisa berubah menjadi "nilai pertama menang", melempar pengecualian, atau mengembalikan node galat, dan semua perubahan itu tetap sesuai spesifikasi. Kode yang tanpa sengaja bergantung pada perilaku penyelesaian kunci duplikat rapuh secara definisi.

Peringatan

Jika aplikasi Anda sengaja menulis YAML dengan kunci duplikat dan mengharapkan perilaku penyelesaian tertentu, kode itu bergantung pada perilaku tidak terdefinisi dalam spesifikasi YAML. Pembaruan parser apa pun bisa memecahkannya secara senyap. Hilangkan duplikatnya dan nyatakan maksudnya dengan struktur eksplisit.

Perilaku yaml-cpp secara rinci

yaml-cpp adalah pustaka pengurai YAML untuk C++ yang paling banyak dipakai dan pilihan default di banyak aplikasi C++ serta mesin game. Saat yaml-cpp menemukan kunci duplikat dalam sebuah mapping, ia mengurai kedua kemunculan tetapi hanya menyimpan yang terakhir pada pohon Node yang dihasilkan. Nilai sebelumnya ditimpa dan hilang permanen dari struktur hasil penguraian.

Aturan "nilai terakhir menang"

Dalam implementasi yaml-cpp, setiap kunci pada mapping disimpan dalam daftar terurut pasangan kunci-nilai. Saat kunci duplikat diurai, yaml-cpp mencari di daftar yang ada untuk kunci yang cocok. Jika ditemukan, nilai tersimpan diganti dengan nilai baru. Node nilai sebelumnya dilepaskan. Dari sudut pandang aplikasi, memanggil `node["key"]` mengembalikan nilai yang terakhir didefinisikan seolah hanya ada satu definisi.

Tidak ada keluaran diagnostik secara default

yaml-cpp tidak mengeluarkan peringatan, pesan log, atau pengecualian saat menimpa kunci duplikat. Penguraian berhasil dengan `YAML::Node` yang tampak sepenuhnya normal. Tidak ada flag yang bisa Anda periksa setelah penguraian untuk mengetahui bahwa duplikat telah diselesaikan secara senyap. Satu-satunya cara mendeteksinya adalah memeriksa teks mentah sebelum penguraian, yang persis dilakukan detektor kunci duplikat khusus.

Perilaku konsisten di semua gaya mapping

yaml-cpp menerapkan "nilai terakhir menang" secara konsisten, baik mapping memakai gaya blok (kunci pada baris terpisah) maupun gaya alir dengan kurung kurawal. Mapping bersarang ditangani secara independen: duplikat hanya dibandingkan dalam level mapping yang sama, bukan di seluruh pohon dokumen. Kunci yang muncul pada dua mapping bersaudara dengan kedalaman anidasi berbeda tidak dianggap duplikat.

Detektor kunci duplikat YAML

Tempelkan dokumen YAML Anda dan temukan semua kunci duplikat di setiap level anidasi seketika: melaporkan nomor baris dan kedua nilai yang bersaing agar Anda memperbaikinya sebelum sampai ke yaml-cpp.

Open tool

Bagaimana parser lain menangani duplikat

Karena spesifikasi YAML membiarkan perilaku kunci duplikat tidak terdefinisi, setiap ekosistem parser membuat keputusannya sendiri. Perbedaannya antar bahasa cukup besar sehingga file YAML yang lolos secara senyap di satu pipeline bisa gagal keras di pipeline lain. Memahami lanskapnya membantu Anda menulis YAML yang portabel.

Parser / PustakaBahasaPerilaku pada kunci duplikat
yaml-cppC++Nilai terakhir menang: senyap, tanpa peringatan
PyYAMLPythonNilai terakhir menang: senyap, tanpa peringatan
ruamel.yaml (ketat)PythonMelempar DuplicateKeyError bila dikonfigurasi
js-yamlJavaScriptNilai terakhir menang: senyap, tanpa peringatan
gopkg.in/yaml.v3GoMengembalikan galat: duplicate map key
go-yaml v2GoNilai terakhir menang: senyap, tanpa peringatan
Psych (default)RubyMelempar Psych::BadAlias / galat pada versi baru
SnakeYAMLJavaNilai terakhir menang: senyap (dapat dikonfigurasi)
YamlDotNetC# / .NETNilai terakhir menang: senyap, tanpa peringatan
libfyamlCMengeluarkan peringatan; perilaku dapat dikonfigurasi

Kesimpulan praktisnya tegas: `yaml.v3` di Go memperlakukan duplikat sebagai galat keras, sementara yaml-cpp, PyYAML, dan js-yaml menerimanya secara senyap. File konfigurasi YAML yang berfungsi di aplikasi C++ Anda dengan yaml-cpp bisa langsung gagal ketika file yang sama diproses oleh layanan Go atau linter Python yang ketat di pipeline CI.

Tips

Gunakan [Validator YAML](/tools/data/validators/yaml-validator) untuk memeriksa file YAML Anda terhadap spesifikasi sebelum di-commit. Untuk portabilitas antar bahasa, anggap setiap file yang memiliki kunci duplikat sebagai rusak, bahkan jika parser spesifik Anda menerimanya secara senyap hari ini.

Skenario nyata yang menyebabkan duplikat

Sebagian besar kunci duplikat tidak disengaja. Kunci itu muncul melalui pola yang dapat diprediksi dalam cara pengembang menulis dan memelihara file konfigurasi YAML. Mengetahui penyebab umumnya membantu Anda menangkapnya di sumbernya.

1

Pertumbuhan file konfigurasi seiring waktu

File konfigurasi berumur panjang menumpuk perubahan dari banyak kontributor. Kunci yang didefinisikan berbulan-bulan lalu di dekat bagian atas file didefinisikan ulang oleh kontributor baru yang tidak menyadari kunci itu sudah ada. Ini sangat umum pada file `values.yaml` Helm, ConfigMap Kubernetes, dan file variabel Ansible, yang bisa memuat ratusan kunci tersebar di file terlalu panjang untuk ditinjau seluruhnya.

2

Menggabungkan potongan konfigurasi dari tim berbeda

Ketika dua tim independen atau mikrolayanan menyumbang ke konfigurasi YAML bersama, kunci level atas yang sama bisa didefinisikan keduanya. File hasil gabungan memuat kedua definisi, dan yang muncul terakhir menang secara senyap. Ini sumber umum bug penimpaan spesifik lingkungan, tempat nilai dari tim yang salah berlaku di produksi.

3

Pola mengomentari lalu mengganti

Seorang pengembang mengomentari `timeout: 30` dan menambahkan `timeout: 60` tepat di bawahnya sebagai pengganti. Kemudian seseorang menghapus karakter komentar dari baris lama, mungkin dalam pencarian-dan-ganti global atau karena formatter editor salah konfigurasi, dan kedua nilai menjadi aktif. Yang terakhir menang, tetapi mana yang terakhir bergantung pada posisi masing-masing baris dalam file.

4

Bug template atau pembuatan kode

Pipeline CI/CD dan alat infrastructure-as-code sering menghasilkan YAML secara programatik. Bug pada logika template, misalnya cabang kondisi yang tidak mengecualikan kunci yang sudah dikeluarkan cabang lain dengan benar, bisa menghasilkan YAML yang tampak valid tetapi memuat duplikat senyap. File hasilnya lolos penguraian yaml-cpp, dan nilai yang salah dipakai di produksi tanpa galat tercatat.

Peringatan

Duplikat paling berbahaya ada pada kunci kritis keamanan: `admin`, `enabled`, `role`, `permissions`. Karena yaml-cpp menerima duplikat secara senyap, konfigurasi dengan `admin: false` yang diikuti `admin: true` memberi akses admin sambil tetap menampilkan `false` kepada siapa pun yang membaca file secara linear. Jalankan [Detektor kunci duplikat YAML](/tools/data/validators/yaml-duplicate-key-detector) pada setiap file konfigurasi terkait keamanan sebelum deployment.

Mendeteksi dan mencegah duplikat

Kunci duplikat mudah dideteksi dengan peralatan yang tepat. Tantangannya adalah menangkapnya sebelum mencapai parser produksi, bukan setelah kehilangan data senyap terjadi. Alur berikut mencakup deteksi pada setiap tahap, dari penulisan sampai deployment.

Langkah 1: deteksi sebelum commit dengan Detektor kunci duplikat YAML

Detektor kunci duplikat YAML memindai seluruh dokumen YAML Anda, termasuk mapping bersarang pada setiap kedalaman, dan melaporkan setiap kunci duplikat beserta nomor barisnya serta nilai yang ditimpa dan yang bertahan. Tempelkan file Anda sebelum commit untuk menangkap masalah seketika. Tanpa unggahan, tanpa pendaftaran, dan file tidak pernah meninggalkan browser Anda.

Langkah 2: linting di editor dengan yamllint

Untuk tim yang bekerja dengan file YAML setiap hari, `yamllint` dengan aturan `key-duplicates` yang disetel ke `enable` menangkap duplikat pada setiap penyimpanan. Pengguna VS Code dapat memasang ekstensi YAML (Red Hat) yang mengintegrasikan yamllint secara otomatis. Menambahkan yamllint ke hook pra-commit dan pipeline CI berarti duplikat tidak pernah sampai ke peninjauan kode tempat mereka bisa terlewat.

Langkah 3: penguraian mode ketat di rangkaian tes Anda

Meski kode produksi Anda memakai yaml-cpp, Anda bisa menambahkan validasi saat pengujian dengan parser ketat. Uraikan setiap file konfigurasi YAML dengan `yaml.v3` dari Go atau ruamel.yaml dari Python dalam mode ketat sebagai bagian dari rangkaian tes Anda. Parser ini memberi galat pada duplikat, sehingga Anda mendapat kegagalan tes yang tegas alih-alih bug runtime senyap. Setelah menjalankan pemeriksaan duplikat, gunakan Validator anchor dan alias YAML untuk memastikan pula bahwa penggunaan anchor dan alias Anda bersih.

Detektor kunci duplikat YAML

Temukan semua kunci duplikat di dokumen YAML mana pun seketika: setiap level anidasi dipindai, nomor baris dilaporkan, dan kedua nilai ditampilkan berdampingan.

Open tool

Pencegahan: praktik struktural terbaik

  • Urutkan kunci secara alfabetis: urutan alfabetis membuat deteksi duplikat menjadi sepele saat peninjauan kode
  • Gunakan anchor YAML untuk nilai bersama: alih-alih menduplikasi blok, definisikan anchor sekali lalu rujuk dengan alias
  • Terapkan yamllint di CI: pipeline yang gagal jauh lebih kuat sebagai sinyal daripada komentar di peninjauan kode
  • Tinjau diff konfigurasi besar secara menyeluruh: periksa tampilan file lengkap, bukan hanya baris yang berubah, saat meninjau perubahan konfigurasi
  • Jaga file tetap pendek: pisahkan file konfigurasi besar menjadi subfile yang fokus untuk mengurangi luas permukaan duplikat

Kunci merge, anchor, dan jebakan terkait

Kunci merge YAML (`<<`) serta sistem anchor dan alias adalah mekanisme sah untuk menggunakan ulang nilai dalam sebuah dokumen. Memahami bagaimana keduanya berinteraksi dengan deteksi kunci duplikat mencegah positif palsu pada peralatan Anda dan membantu menggunakannya dengan aman.

Cara kerja kunci merge

Kunci merge `<<` memberi tahu parser YAML agar memasukkan pasangan kunci-nilai dari mapping ber-anchor ke mapping saat ini. Ini bukan kunci duplikat: `<<` adalah indikator cadangan dalam spesifikasi YAML 1.1 dan ekstensi yang didukung luas pada 1.2. Saat kunci merge mengimpor kunci yang sudah ada di mapping tujuan, definisi eksplisit pada tujuan lebih diprioritaskan daripada nilai hasil merge. Ini perilaku yang disengaja dan dapat diprediksi, berbeda dari kunci duplikat yang tidak disengaja.

Anchor dan deteksi duplikat

Anchor YAML (`&name`) dan alias (`*name`) bukan duplikat. Anchor mendefinisikan node yang dapat digunakan ulang; alias merujuk padanya. Keduanya bisa muncul berkali-kali dalam dokumen tanpa menimbulkan pelanggaran kunci duplikat. Validator anchor dan alias YAML secara khusus memeriksa bahwa setiap alias mengarah ke anchor yang dideklarasikan dan tidak ada referensi melingkar, masalah yang berbeda dari kunci duplikat.

Ketika kunci merge menghasilkan duplikat semu

Kunci merge dapat menciptakan sesuatu yang tampak seperti duplikat jika mapping dasar ber-anchor dan mapping tujuan sama-sama mendefinisikan kunci yang sama. Ini bukan bug: spesifikasi menetapkan bahwa kunci eksplisit lebih diprioritaskan daripada kunci hasil merge. Namun, sebagian linter kunci duplikat melaporkannya sebagai galat. Jika Anda melihat positif palsu di yamllint untuk konfigurasi berbasis `<<`, pastikan Anda memakai kunci merge dengan benar sebelum membungkam peringatannya. Untuk file `values.yaml` Helm yang kompleks dan banyak memakai anchor, membandingkan versi dengan Penyorot perbedaan untuk konfigurasi JSON/YAML memudahkan menemukan perubahan pada level kunci di pull request.

Catatan

yaml-cpp mendukung kunci merge ketika fungsi `YAML::LoadAll` atau `YAML::Load` dipakai dengan dokumen YAML 1.1. Jika Anda memakai yaml-cpp dengan mode ketat YAML 1.2, kunci merge mungkin tidak diproses. Periksa versi yaml-cpp Anda dan deklarasi versi dokumen (`%YAML 1.2`) jika kunci merge tampak diabaikan.

Poin penting

  • yaml-cpp memakai nilai terakhir menang untuk kunci duplikat: nilai sebelumnya ditimpa secara senyap tanpa galat atau peringatan.
  • Spesifikasi YAML 1.2 menyatakan secara eksplisit bahwa kunci duplikat tidak diizinkan dan menyebut perilakunya tidak terdefinisi.
  • Perilaku parser sangat beragam: `yaml.v3` dari Go memberi galat pada duplikat, sementara PyYAML dan js-yaml seperti yaml-cpp menyimpan nilai terakhir secara senyap.
  • Kunci kritis keamanan seperti `admin` atau `enabled` adalah target paling berbahaya: duplikat dapat memberi atau mencabut akses secara tidak terlihat.
  • Gunakan Detektor kunci duplikat YAML untuk memindai file YAML mana pun dan menemukan duplikat di setiap level anidasi sebelum deployment.
  • Tambahkan `yamllint` dengan `key-duplicates: enable` ke pipeline CI Anda untuk pencegahan otomatis pada setiap commit.
  • Kunci merge YAML (`<<`) dan anchor bukan duplikat: keduanya mekanisme penggunaan ulang yang disengaja dengan aturan prioritas yang terdefinisi.

Pertanyaan yang sering diajukan

yaml-cpp memakai semantik "nilai terakhir menang" saat mengurai mapping YAML berkunci duplikat. Jika kunci yang sama muncul lebih dari sekali pada level mapping yang sama, parser menimpa nilai sebelumnya dengan yang terakhir dan secara default tidak mengeluarkan galat maupun peringatan. Objek Node hasilnya di memori hanya berisi nilai akhir, sementara semua nilai sebelumnya dibuang diam-diam. Ini sesuai dengan perilaku banyak parser YAML lain, tetapi secara teknis dinyatakan tidak terdefinisi oleh spesifikasi YAML.

Tidak: spesifikasi YAML 1.2 menyatakan bahwa kunci duplikat dalam sebuah mapping "tidak diizinkan" dan secara eksplisit menyebut perilakunya tidak terdefinisi. Namun, spesifikasi tidak mewajibkan parser melempar galat; ia hanya menyatakan hasilnya tidak ditentukan. Sebagian besar parser, termasuk yaml-cpp, memilih menerima duplikat secara senyap daripada menghentikan penguraian, sehingga kunci duplikat menjadi sumber bug kehilangan data senyap alih-alih galat runtime yang jelas.

Saat yaml-cpp menemukan kunci yang sudah pernah dilihatnya dalam mapping yang sama, ia mengganti nilai yang tersimpan dengan nilai baru. Nilai sebelumnya hilang secara permanen: tidak ada cara mengambilnya setelah penguraian. Disebut "nilai terakhir menang" karena definisi kunci yang muncul terakhir dalam dokumen itulah yang bertahan. Aturan ini berlaku secara independen pada setiap level anidasi.

Perilakunya berbeda-beda antar parser. PyYAML (Python) juga memakai "nilai terakhir menang" secara senyap sebagai default, meski ruamel.yaml dapat dikonfigurasi untuk melempar galat. gopkg.in/yaml.v3 (Go) melempar galat pada kunci duplikat. js-yaml (JavaScript) menyimpan nilai terakhir secara senyap tanpa peringatan. Psych (Ruby) melempar galat. Ketidakkonsistenan antar parser berarti file yang tampak valid di rantai alat satu bahasa bisa kehilangan data secara senyap di bahasa lain.

Cara tercepat adalah menempelkan YAML Anda ke Detektor kunci duplikat YAML dari Aback Tools, yang memindai seluruh dokumen termasuk mapping bersarang dan melaporkan semua duplikat beserta nomor baris dan kedua nilai yang bersaing. Alternatifnya, Anda bisa memakai parser ketat seperti gopkg.in/yaml.v3 di Go atau ruamel.yaml di Python dengan opsi allow_duplicate_keys=False. Untuk pipeline CI/CD, yamllint dengan aturan braces: {forbid-flow-sequences: true} dan key-duplicates: enable mendeteksi duplikat secara otomatis pada setiap commit.

Ya, pada skenario tertentu. Jika file YAML dipakai untuk konfigurasi kontrol akses atau feature flag, kunci duplikat bisa menimpa nilai yang kritis bagi keamanan secara senyap. Contohnya, kunci `admin: false` yang diikuti `admin: true` di bagian bawah akan memberi akses admin karena aturan "nilai terakhir menang", sementara entri `false` tampak sebagai nilai yang berlaku bagi siapa pun yang membaca file dari atas ke bawah. Kelas bug ini pernah muncul pada CVE nyata terkait penguraian file konfigurasi. Deteksi duplikat otomatis adalah pengaman berbiaya rendah.

Kunci duplikat adalah pengulangan nama kunci yang sama di dalam sebuah mapping, baik tidak sengaja maupun karena kesalahan. Kunci merge YAML (<<) adalah fitur standar YAML yang sengaja memasukkan isi sebuah anchor ke dalam mapping. Kunci merge itu sendiri bukan duplikat: ia kunci khusus dengan semantik yang terdefinisi. Namun, jika kunci merge memasukkan kunci yang sudah ada pada mapping tujuan, definisi eksplisit lebih diprioritaskan daripada nilai hasil merge. Ini disengaja dan bukan bug kunci duplikat.

Untuk kode produksi, ya. API Node pada yaml-cpp tidak secara bawaan menyediakan opsi mode ketat yang memberi galat pada duplikat, tetapi Anda bisa menambahkan validasi setelah penguraian memakai Detektor kunci duplikat YAML atau penelusuran khusus yang memeriksa kunci berulang sebelum aplikasi membaca konfigurasi. Untuk file konfigurasi kritis, terutama autentikasi, keamanan, dan infrastruktur, pemeriksaan kunci duplikat di pipeline CI sangat dianjurkan. Detektor kunci duplikat YAML dari Aback Tools dirancang tepat untuk kasus ini.

ShareXLinkedIn