bug(terraform): both .tf and .tofu files with the same name are scanned
Discussed in https://github.com/aquasecurity/trivy/discussions/11181
Description
Trivy parses every .tf and .tofu file in a directory and merges them into one module. Neither tool does that. When a .tf and a .tofu file share a name, OpenTofu loads the .tofu one and skips the .tf one. Terraform does not know the .tofu extension, so it loads the .tf one and skips the .tofu one.
Two things follow from this.
Findings come from a file that is not applied. That is what https://github.com/aquasecurity/trivy/discussions/11181 reports, where three findings come from a
main.tfthat OpenTofu never loads.If both files declare the same resource address, the module gets two blocks for it. Neither tool ever sees that state and the evaluation result is undefined. It is easy to hit while migrating from Terraform to OpenTofu, when a
.tofufile is written over an existing.tfone.
Reproduction steps
- Save a
terraform_dataresource asmain.tofu. - Save an
aws_security_groupthat opens port 22 to0.0.0.0/0asmain.tfin the same directory. - Run
trivy config ..
AWS-0099, AWS-0107 and AWS-0124 are reported against main.tf. tofu plan for the same directory shows only the terraform_data resources, so nothing from main.tf is part of the configuration.
Workaround
The shadowed files can be excluded with --skip-files, but only by listing them one by one.
Possible direction
OpenTofu already has a rule for this. A .tofu file takes precedence over a .tf file with the same name, and the shadowed file is not loaded at all. The pairing is per extension, so main.tofu shadows main.tf and main.tofu.json shadows main.tf.json, but main.tofu does not shadow main.tf.json.
Trivy could follow the same rule.
In an application repository a same-name pair usually means a migration in progress. Nobody writes a .tofu file without running OpenTofu, and keeping two variants of one file in sync costs enough that the pair rarely stays for long. While it lasts, the .tofu file is the one being applied and the .tf file is what is left of the old setup.
Published modules are the other case, and OpenTofu names it in its own documentation. A module author can ship both variants so the module works for Terraform and OpenTofu users alike. Trivy cannot tell which tool a scan is meant for, so following OpenTofu would hide the findings from the .tf file. Those users can keep the Terraform reading by excluding the OpenTofu files with --skip-files, which needs two patterns because **/*.tofu does not match main.tofu.json.
Source: aquasecurity/trivy