Ringkasan Utama
OpenTofu 1.13, diumumkan pada 29 September 2026, sengaja dibuat ringan: fungsi convert dan assume baru, linting dan Symbol Libraries yang masih experimental, serta paket Windows ARM64. Risiko upgrade-nya adalah output base64gzip berubah, koneksi provisioner WinRM dihapus, macOS 13 jadi minimum, dan ini series terakhir dengan build 32-bit.
Kebanyakan post rilis dibaca untuk daftar fitur. Untuk 1.13 daftar fiturnya pendek, dan upgrade notes-lah yang bisa menghabiskan satu sore Anda, jadi post ini membacanya berdasarkan urutan tingkat bahayanya.
Saya membaca pengumuman resmi 1.13.0, halaman referensi fungsi convert, keluarga assume dan base64gzip, dua post tentang experiment, serta halaman release di GitHub. Saya belum menjalankan 1.13 terhadap state production, jadi kode di bawah dibentuk dari dokumen-dokumen itu dan bukan hasil pengukuran. Apa pun yang tidak saya temukan di sana sengaja dibuang.
Rilis ringan, dengan sengaja
Pengumuman menyebut masa pengembangan dipersingkat agar OpenTofu selaras dengan siklus rilis Go, dan menyebut 1.13 relatif ringan soal fitur baru. Series 1.13 mendapat security support sampai Agustus 2027.
Ringan bukan berarti tanpa kejadian. Upgrade Go di bawah binary-lah yang mengubah output base64gzip, dan penghapusan fitur mengikuti jalur biasa: deprecate dulu, baru remove. Berikut semua perubahan yang bisa saya konfirmasi, diurutkan menurut apakah bisa merugikan Anda.
| Perubahan | Jenis | Siapa yang kena | Yang perlu dilakukan |
|---|---|---|---|
| Output base64gzip | Breaking | Siapa pun yang punya argumen resource dari base64gzip; plan berikutnya mengusulkan perubahan | Review diff; pakai ignore_changes sementara kalau belum bisa apply |
| WinRM untuk provisioner | Breaking (dihapus) | Setiap connection block dengan type winrm pada provisioner remote-exec atau file | Pindah ke OpenSSH for Windows sebelum upgrade |
| Build 32-bit (386, arm) | Series terakhir | Runner dan laptop dengan CPU 32-bit; tofu init menampilkan warning selama series 1.13 | Rencanakan pindah ke amd64 atau arm64 sebelum 1.14 |
| Minimum macOS 13 Ventura | Batas platform | macOS yang lebih lama bisa crash atau berperilaku salah | Upgrade OS atau pertahankan CLI lama di mesin itu |
| Fungsi convert dan assume | Baru, tambahan | Tidak ada; opt in per expression | Pakai hanya jika provider menjamin propertinya |
| Linting dan Symbol Libraries | Experimental | Tidak ada secara default; keduanya opt-in dan bisa berubah | Coba di branch, beri feedback, jangan jadikan dependency |
Windows di ARM64 juga baru menjadi platform yang didukung resmi. Ini kabar baik, tetapi seperti dijelaskan di bagian enam, ada catatan soal provider.
base64gzip: output setara, byte berbeda
Fungsi base64gzip meng-gzip sebuah string lalu meng-encode hasilnya dengan Base64. Pengumuman menyebut perubahan di standard library Go membuat hasilnya setara dengan versi lama tetapi tidak identik byte per byte, dan halaman referensi fungsinya mengulang hal itu. Karena OpenTofu membandingkan nilai konfigurasi dengan state sebagai string persis, argumen resource apa pun yang dibangun dari fungsi ini akan tampak berubah.
Jalan keluar yang didokumentasikan adalah meta-argument ignore_changes: pertahankan nilai lama untuk sementara dan hapus block-nya saat siap memakai encoding baru. Pengumuman juga menyebut provider pihak ketiga yang dibuild dengan Go 1.26 atau lebih lama bisa menyediakan perilaku lama, OpenTofu tidak menyediakan provider resmi untuk itu, dan Anda bisa mencarinya di OpenTofu Registry. Saya anggap itu pilihan terakhir.
resource "aws_s3_object" "index" {
bucket = aws_s3_bucket.site.id
key = "index.html.gz"
content_base64 = base64gzip(file("${path.module}/index.html"))
content_encoding = "gzip"
# Temporary: the 1.13 encoding is equivalent but not byte-for-byte identical,
# so the first plan after upgrading proposes an in-place update. Pin the old
# value, upgrade, then delete this block in its own reviewed change.
lifecycle {
ignore_changes = [content_base64]
}
}Kegagalan yang perlu diwaspadai: reviewer melihat deretan in-place update pada objek yang isinya tidak berubah lalu menyetujuinya begitu saja. Jalankan upgrade di pull request tersendiri agar satu-satunya diff adalah ini, dan jadikan penghapusan ignore_changes perubahan terpisah yang diberi label.
WinRM hilang dari provisioner
WinRM sudah deprecated sejak 1.12.0 dan kini dihapus untuk provisioner remote-exec dan file; connection block dengan type winrm menjadi error. Pengumuman menyarankan migrasi ke OpenSSH for Windows sebelum upgrade. Connection type ssh di bawah adalah alternatif standarnya, tetapi pekerjaan sebenarnya adalah memastikan sshd terpasang dan bisa dijangkau di host Windows Anda.
# Wrong: errors in 1.13 (deprecated in 1.12, removed for remote-exec and file).
resource "null_resource" "bootstrap" {
connection {
type = "winrm"
host = var.windows_host
user = "Administrator"
password = var.admin_password
}
provisioner "remote-exec" {
inline = ["powershell -File C:\\bootstrap.ps1"]
}
}
# Right: the same connection over OpenSSH for Windows, once sshd is running on the host.
resource "null_resource" "bootstrap" {
connection {
type = "ssh"
host = var.windows_host
user = "Administrator"
private_key = file(var.ssh_key_path)
}
provisioner "remote-exec" {
inline = ["powershell -File C:\\bootstrap.ps1"]
}
}Jika image Windows berasal dari golden template, aktifkan OpenSSH di sana, bukan di provisioner yang butuh WinRM untuk melakukannya. Anda akan membangun jalur baru memakai jalur yang sudah tidak ada.
convert dan assume: lebih sedikit unknown saat plan
Nilai yang baru diketahui setelah apply tampil sebagai known after apply di plan, dan beberapa fitur menolaknya saat planning, termasuk enabled, for_each, dan count. Fungsi baru ini memungkinkan module author memberi tahu OpenTofu apa yang tidak bisa ia simpulkan sendiri.
convert mendeklarasikan tipe, sehingga hasil yang unknown tetap punya bentuk yang diketahui. Keluarga assume mendeklarasikan properti nilai, sehingga perbandingan dan pengecekan bisa berjalan saat plan. Halaman referensi mencantumkan signature ini dan menyatakan hint tercakup dalam compatibility promise, dengan deteksi lebih awal bersifat best effort.
| Fungsi | Yang dijanjikan | Yang terbuka saat plan |
|---|---|---|
| assumenotnull(value) | Nilai bukan null; error jika sebaliknya | Perbandingan dengan null menghasilkan boolean yang known, jika tipenya sudah known (pasangkan dengan convert jika belum) |
| assumestringprefix(string, expected_prefix) | String diawali prefix tersebut; error jika sebaliknya | Perbandingan dengan string kosong dan pemanggilan startswith menghasilkan hasil yang known |
| assumeequal(actual_value, expected_value) | Mengonversi ke tipe argumen kedua, mengecek kesamaan, mengembalikan argumen kedua | Module bisa memprediksi nilai yang tidak bisa diprediksi provider, misalnya ARN dari input yang known |
| assumelistlength, assumesetlength, assumemaplength | Panjang berada dalam batas min dan max (inklusif) | Pengecekan panjang menghasilkan hasil yang known; varian min dan max mengecek satu batas |
| convert(value, type) | Nilai sesuai type constraint | Nilai unknown tetap punya bentuk yang known, sehingga akses atribut punya tipe yang known |
# 1. convert: tell OpenTofu the SHAPE of a value it cannot see until apply.
locals {
vendor = convert(
jsondecode(something_dynamic.example.output_json),
object({ id = string, tags = map(string) })
)
# local.vendor is still unknown, but local.vendor.id is known to be a string.
}
# 2. assume...: promise a property of the value, so downstream checks run at plan.
variable "vpc_id" {
type = string
validation {
# Without the hint, an unknown vpc_id makes this rule wait for apply.
condition = startswith(var.vpc_id, "vpc-")
error_message = "vpc_id must look like vpc-..."
}
}
module "network_checks" {
source = "./modules/network-checks"
# Only safe because the provider documentation guarantees the prefix.
vpc_id = assumenotnull(assumestringprefix(aws_vpc.example.id, "vpc-"))
}Perhatikan urutan di contoh: assumenotnull membungkus assumestringprefix karena validation rule biasanya mengecek null lebih dulu. Referensi menyatakan assumenotnull hanya bekerja jika tipenya sudah known, dan itulah kasus yang ditutup oleh convert.
Dua experiment, dan cara menyalakannya
Linting dinyalakan per command dengan opsi lint. Post tentang linting mencantumkan empat rule bawaan di 1.13: core:no-type-variable, core:count-instead-enabled, core:unused-variable, dan core:unused-local. Post itu juga menyebut pendekatan lewat file konfigurasi direncanakan tetapi belum didefinisikan, jadi flag adalah satu-satunya jalur yang terdokumentasi saat ini.
# Every built-in rule, as warnings, on any of the three commands.
tofu validate -lint=all
tofu plan -lint=all
# Or pick rules by ID. These four are the ones the linting post says 1.13 ships.
tofu plan -lint=core:no-type-variable,core:count-instead-enabled,core:unused-variable,core:unused-localSymbol Libraries adalah kumpulan function, type, dan constant yang bisa dipakai ulang dalam file berekstensi sym.hcl, diimpor dengan block symbols, dan diaktifkan lewat daftar experiments di konfigurasi project. Post pengantarnya menyebut library tidak bisa membaca state resource atau data maupun memakai provider function, meskipun nilai resource bisa dikirim sebagai argumen.
# project configuration: opt in to the experiment explicitly
language {
experiments = [symbol_libraries]
}
# Import a directory of *.sym.hcl files under the label "lib".
symbols "lib" {
source = "./example-lib"
}
# Functions and types: symbols::lib::<name>() Constants: symbols.lib.<name>Post Symbol Libraries menyebut tujuannya adalah stabil di 1.14 dan meminta feedback lewat GitHub discussion. Itu niat, bukan janji, jadi jauhkan library dari apa pun yang tidak bisa Anda tulis ulang.
Platform: Windows ARM64 masuk, 32-bit dan macOS lama keluar
Windows di ARM64 mendapat paket resmi, dan pengumuman menyebut sebagian besar build OpenTofu untuk provider cloud besar sudah punya paket windows_arm64. Maintainer provider pihak ketiga menentukan kebijakan platform sendiri, jadi satu provider yang belum ada bisa menghalangi runner Windows ARM64.
| Platform | Status di series 1.13 | Yang perlu dilakukan |
|---|---|---|
| Windows ARM64 | Paket resmi baru | Cek tiap provider menyediakan windows_arm64 sebelum memindahkan runner |
| 386 dan arm (32-bit) | Series terakhir; tofu init menampilkan warning | Migrasi ke amd64 atau arm64; 1.14 tidak punya paket resmi untuk keduanya |
| macOS 13 Ventura atau lebih baru | Batas minimum yang didukung | Verifikasi laptop developer dan self-hosted Mac runner |
| macOS sebelum 13 | Bisa crash atau berperilaku salah | Jangan upgrade CLI di sana; ganti mesin atau OS |
Warning 32-bit adalah yang diam-diam penting: runner ARM ala Raspberry Pi bisa tetap jalan sepanjang 1.13 lalu tidak punya jalur upgrade resmi.
Di mana ia bisa salah: hint yang berbohong dan experiment yang bergeser
Fungsi assume adalah janji, dan pengumuman eksplisit soal biaya melanggarnya. Jika Anda menjanjikan prefix vpc- lalu nilainya ternyata subnet-, pemanggilan gagal saat apply, yang lebih telat dan lebih menyakitkan daripada unknown yang digantikannya.
Pakai fungsi assume hanya jika dokumentasi provider atau vendor menjamin propertinya. Hint yang salah mengubah unknown saat plan menjadi kegagalan saat apply, bahkan mungkin di tengah sebuah perubahan.
- Waktu deteksi bisa berbeda antar versi: masalah yang tertangkap saat plan di satu rilis bisa baru muncul saat apply di rilis lain, dan sebaliknya. Jangan membangun jaminan di atasnya.
- Elemen bahasa Symbol Libraries digambarkan sebagai titik awal yang bisa berubah berdasarkan feedback.
- Linting masih infrastruktur awal dengan empat rule; hasil bersih belum membuktikan banyak hal.
- ignore_changes untuk base64gzip adalah utang. Jika dibiarkan, resource diam-diam berhenti melacak perubahan konten yang nyata.
Aturan saya: ambil fitur tambahan pelan-pelan dan penghapusan dengan serius. Kelompok pertama bisa menunggu satu rilis; kelompok kedua akan menggagalkan pipeline pada run pertama.
Yang dilakukan hari Senin
Semua ini tidak butuh proyek migrasi. Cukup satu sore dan satu branch.
- Cari di repository koneksi type winrm dan pemakaian base64gzip.
- Cek platform setiap runner dan laptop terhadap tabel di bagian enam.
- Upgrade di branch khusus dengan tofu init -upgrade dan simpan plan-nya.
- Pastikan satu-satunya perubahan berasal dari base64gzip; apply, atau pakai ignore_changes untuk satu rilis dan catat penghapusannya.
- Jalankan tofu validate dengan opsi lint pada satu module dan beri tahu project apa yang Anda temukan.
# 1. Find the three things that break before you touch the binary.
grep -rn 'type *= *"winrm"' --include='*.tf' .
grep -rn 'base64gzip' --include='*.tf' .
tofu version # note the platform line: windows_386 / linux_arm / darwin on macOS < 13
# 2. Upgrade in a branch, then read the plan before anything else.
tofu init -upgrade
tofu plan -out=tfplan-1.13
# 3. Only base64gzip arguments should show as changes. Anything else is a real diff.
tofu show tfplan-1.13 | grep -B2 -A6 'base64gzip\|content_base64'
# 4. Try the linter on the module you know best.
tofu validate -lint=allPerintah di bawah adalah jam pertama dari sore itu. Langkah tiga menjalankan grep pada plan tersimpan, itu kemudahan dan bukan jaminan, jadi tetap baca diff-nya.
Aturan yang dibawa: pada rilis OpenTofu yang ringan, catatan di bawah breaking changes adalah seluruh rilisnya. Perbaiki WinRM dan base64gzip dalam perubahan tersendiri, cek platform Anda, dan perlakukan convert, assume, linting, serta Symbol Libraries sebagai hal untuk dicoba di branch, bukan untuk dijadikan fondasi.

