From 6c6edf6532352cbf0854b17e7823d938f28652a2 Mon Sep 17 00:00:00 2001 From: Mohamed MAACHE Date: Sat, 4 Jul 2026 01:48:05 +0200 Subject: [PATCH 1/2] fix(terraform): support OpenTofu language block OpenTofu v1.12 introduced a top-level `language` block used to declare version/compatibility constraints (with a nested `compatible_with` block). Trivy's hardcoded HCL body schema did not list this block type, so any `.tofu`/`.tf` file containing it failed to parse with: Unsupported block type; Blocks of type "language" are not expected here. Add `language` to the terraform body schema so the parser accepts it. The nested `compatible_with` block is decoded by the generic block machinery, so no further schema changes are required. Adds a regression test that parses a config using the `language` block and reads the nested `compatible_with.opentofu` constraint. Closes #10906 --- .../scanners/terraform/parser/parser_test.go | 45 +++++++++++++++++++ pkg/iac/terraform/schema.go | 5 +++ 2 files changed, 50 insertions(+) diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index 1baa9053e9..3f906a0405 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -164,6 +164,51 @@ check "cats_mittens_is_special" { require.NotNil(t, checkBlocks[0].GetBlock("assert")) } +// Test_OpenTofuLanguageBlock reproduces aquasecurity/trivy#10906. +// +// Given a .tofu file using the OpenTofu v1.12 top-level `language` block +// (https://opentofu.org/docs/language/settings/#language-compatibility) +// When the parser reads the file +// Then it must not fail with "Unsupported block type", and the nested +// `compatible_with.opentofu` constraint must be readable. +func Test_OpenTofuLanguageBlock(t *testing.T) { + fs := testutil.CreateFS(map[string]string{ + "main.tofu": ` +language { + compatible_with { + opentofu = ">= 1.12" + } +} + +resource "cats_cat" "mittens" { + name = "mittens" +} +`, + }) + + parser := New(fs, "", OptionStopOnHCLError(true)) + err := parser.ParseFS(t.Context(), ".") + require.NoError(t, err, "parser must accept the OpenTofu `language` block") + + modules, err := parser.EvaluateAll(t.Context()) + require.NoError(t, err) + require.NotEmpty(t, modules) + + blocks := modules[0].GetBlocks() + + languageBlocks := blocks.OfType("language") + require.Len(t, languageBlocks, 1) + + compatibleWith := languageBlocks[0].GetBlock("compatible_with") + require.NotNil(t, compatibleWith) + require.NotNil(t, compatibleWith.GetAttribute("opentofu")) + assert.Equal(t, ">= 1.12", compatibleWith.GetAttribute("opentofu").Value().AsString()) + + // sanity: the rest of the file still parses normally + resourceBlocks := blocks.OfType("resource") + require.Len(t, resourceBlocks, 1) +} + func Test_Modules(t *testing.T) { fs := testutil.CreateFS(map[string]string{ diff --git a/pkg/iac/terraform/schema.go b/pkg/iac/terraform/schema.go index dcedda7c00..a9fbec5904 100644 --- a/pkg/iac/terraform/schema.go +++ b/pkg/iac/terraform/schema.go @@ -8,6 +8,11 @@ var Schema = &hcl.BodySchema{ { Type: "terraform", }, + { + // language declares OpenTofu/language compatibility constraints. + // Introduced in OpenTofu v1.12: https://opentofu.org/docs/language/settings/#language-compatibility + Type: "language", + }, { Type: "required_providers", }, From ee368a1d7b2fd70f1f027b2929e77bd1d7ce874e Mon Sep 17 00:00:00 2001 From: Mohamed MAACHE Date: Mon, 6 Jul 2026 19:12:07 +0200 Subject: [PATCH 2/2] test(terraform): trim OpenTofu language block regression test Drop the Given/When/Then comment and over-specified assertions per review; the test only needs to prove the language block no longer triggers Unsupported block type. Ref #10906 --- .../scanners/terraform/parser/parser_test.go | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index 3f906a0405..d31c112c45 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -164,13 +164,7 @@ check "cats_mittens_is_special" { require.NotNil(t, checkBlocks[0].GetBlock("assert")) } -// Test_OpenTofuLanguageBlock reproduces aquasecurity/trivy#10906. -// -// Given a .tofu file using the OpenTofu v1.12 top-level `language` block -// (https://opentofu.org/docs/language/settings/#language-compatibility) -// When the parser reads the file -// Then it must not fail with "Unsupported block type", and the nested -// `compatible_with.opentofu` constraint must be readable. +// Test_OpenTofuLanguageBlock: see https://github.com/aquasecurity/trivy/issues/10906 func Test_OpenTofuLanguageBlock(t *testing.T) { fs := testutil.CreateFS(map[string]string{ "main.tofu": ` @@ -179,34 +173,14 @@ language { opentofu = ">= 1.12" } } - -resource "cats_cat" "mittens" { - name = "mittens" -} `, }) parser := New(fs, "", OptionStopOnHCLError(true)) - err := parser.ParseFS(t.Context(), ".") - require.NoError(t, err, "parser must accept the OpenTofu `language` block") + require.NoError(t, parser.ParseFS(t.Context(), ".")) - modules, err := parser.EvaluateAll(t.Context()) + _, err := parser.Load(t.Context()) require.NoError(t, err) - require.NotEmpty(t, modules) - - blocks := modules[0].GetBlocks() - - languageBlocks := blocks.OfType("language") - require.Len(t, languageBlocks, 1) - - compatibleWith := languageBlocks[0].GetBlock("compatible_with") - require.NotNil(t, compatibleWith) - require.NotNil(t, compatibleWith.GetAttribute("opentofu")) - assert.Equal(t, ">= 1.12", compatibleWith.GetAttribute("opentofu").Value().AsString()) - - // sanity: the rest of the file still parses normally - resourceBlocks := blocks.OfType("resource") - require.Len(t, resourceBlocks, 1) } func Test_Modules(t *testing.T) {