diff --git a/README.md b/README.md index 25535fcfa..a986e2a77 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ trunk check enable {linter} | SQL | [sqlfluff], [sqlfmt], [sql-formatter] | | SVG | [svgo] | | Swift | [stringslint], [swiftlint], [swiftformat] | -| Terraform | [terraform] (validate and fmt), [checkov], [tflint],[tfsec],[terrascan] | +| Terraform | [terraform] (validate and fmt), [checkov], [tflint], [tfsec], [terrascan], [tofu] | | Terragrunt | [terragrunt] | | Textproto | [txtpbfmt] | | TOML | [taplo] | @@ -177,6 +177,7 @@ trunk check enable {linter} [taplo]: https://github.com/tamasfe/taplo#readme [terrascan]: https://github.com/tenable/terrascan#readme [terraform]: https://developer.hashicorp.com/terraform/cli/code +[tofu]: https://opentofu.org/ [terragrunt]: https://terragrunt.gruntwork.io/docs/getting-started/quick-start/ [tflint]: https://github.com/terraform-linters/tflint#readme [tfsec]: https://github.com/aquasecurity/tfsec diff --git a/linters/tofu/plugin.yaml b/linters/tofu/plugin.yaml new file mode 100644 index 000000000..68e1bf66b --- /dev/null +++ b/linters/tofu/plugin.yaml @@ -0,0 +1,39 @@ +version: 0.1 +lint: + definitions: + - name: tofu + files: [terraform] + tools: [tofu] + commands: + - name: validate + # Custom parser type defined in the trunk cli to handle tofu's JSON output. + output: terraform_validate + target: ${parent} + run: tofu validate -json + run_from: ${target_directory} + success_codes: [0, 1] + enabled: false + - name: fmt + output: rewrite + formatter: true + run: tofu fmt -no-color - + stdin: true + success_codes: [0] + cache_results: true + suggest_if: never + environment: + - name: PATH + list: ["${linter}"] + - name: GITHUB_APP_ID + value: ${env.GITHUB_APP_ID} + optional: true + - name: GITHUB_APP_INSTALLATION_ID + value: ${env.GITHUB_APP_INSTALLATION_ID} + optional: true + - name: GITHUB_APP_PEM_FILE + value: ${env.GITHUB_APP_PEM_FILE} + optional: true + known_good_version: 1.6.2 + version_command: + parse_regex: ${semver} + run: tofu --version diff --git a/linters/tofu/test_data/tofu_v1.6.2_variables.check.shot b/linters/tofu/test_data/tofu_v1.6.2_variables.check.shot new file mode 100644 index 000000000..bc325d35a --- /dev/null +++ b/linters/tofu/test_data/tofu_v1.6.2_variables.check.shot @@ -0,0 +1,60 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing linter tofu test variables 1`] = ` +{ + "issues": [ + { + "code": "Invalid quoted type constraints", + "file": "test_data/variables.in.tf", + "issueClass": "ISSUE_CLASS_EXISTING", + "level": "LEVEL_HIGH", + "line": "2", + "linter": "tofu", + "message": "OpenTofu 0.11 and earlier required type constraints to be given in quotes, but that form is now deprecated and will be removed in a future version of OpenTofu. Remove the quotes around "map" and write map(string) instead to explicitly indicate that the map elements are strings.", + "targetType": "terraform", + }, + ], + "lintActions": [ + { + "command": "fmt", + "fileGroupName": "terraform", + "linter": "tofu", + "paths": [ + "test_data/variables.in.tf", + ], + "verb": "TRUNK_VERB_FMT", + }, + { + "command": "validate", + "fileGroupName": "terraform", + "linter": "tofu", + "paths": [ + "test_data", + ], + "verb": "TRUNK_VERB_CHECK", + }, + { + "command": "validate", + "fileGroupName": "terraform", + "linter": "tofu", + "paths": [ + "test_data", + ], + "upstream": true, + "verb": "TRUNK_VERB_CHECK", + }, + ], + "taskFailures": [], + "unformattedFiles": [ + { + "column": "1", + "file": "test_data/variables.in.tf", + "issueClass": "ISSUE_CLASS_UNFORMATTED", + "level": "LEVEL_HIGH", + "line": "1", + "linter": "tofu", + "message": "Incorrect formatting, autoformat by running 'trunk fmt'", + }, + ], +} +`; diff --git a/linters/tofu/test_data/tofu_v1.6.2_variables.fmt.shot b/linters/tofu/test_data/tofu_v1.6.2_variables.fmt.shot new file mode 100644 index 000000000..7ead6f5f8 --- /dev/null +++ b/linters/tofu/test_data/tofu_v1.6.2_variables.fmt.shot @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing formatter tofu test variables 1`] = ` +"variable "ssl_certificates" { + type = map(string) + default = { + lorem-elb-us-west-3 = "lorem" + ipsum-elb-us-east-1 = "ipsum" + dolor-elb-us-east-2 = "dolor" + } +} +" +`; diff --git a/linters/tofu/test_data/variables.in.tf b/linters/tofu/test_data/variables.in.tf new file mode 100644 index 000000000..3743a3fef --- /dev/null +++ b/linters/tofu/test_data/variables.in.tf @@ -0,0 +1,8 @@ + variable "ssl_certificates" { + type = "map" + default = { + lorem-elb-us-west-3 = "lorem" + ipsum-elb-us-east-1 = "ipsum" + dolor-elb-us-east-2 = "dolor" + } +} diff --git a/linters/tofu/tofu.test.ts b/linters/tofu/tofu.test.ts new file mode 100644 index 000000000..616f4a3b5 --- /dev/null +++ b/linters/tofu/tofu.test.ts @@ -0,0 +1,18 @@ +import { linterCheckTest, linterFmtTest } from "tests"; +import { TrunkLintDriver } from "tests/driver"; + +// Due to tofu's validate subcommand being disabled by default, we need to manually enable it in our test's trunk.yaml. +const preCheck = (driver: TrunkLintDriver) => { + const trunkYamlPath = ".trunk/trunk.yaml"; + const currentContents = driver.readFile(trunkYamlPath); + const sqlfluffRegex = /- tofu@(.+)\n/; + const newContents = currentContents.replace( + sqlfluffRegex, + "- tofu@$1:\n commands: [validate, fmt]\n", + ); + driver.writeFile(trunkYamlPath, newContents); +}; + +linterCheckTest({ linterName: "tofu", preCheck }); + +linterFmtTest({ linterName: "tofu" }); diff --git a/tools/tofu/plugin.yaml b/tools/tofu/plugin.yaml new file mode 100644 index 000000000..beb10b9d6 --- /dev/null +++ b/tools/tofu/plugin.yaml @@ -0,0 +1,19 @@ +version: 0.1 +downloads: + - name: tofu + version: 1.6.2 + downloads: + - os: + linux: linux + macos: darwin + windows: windows + cpu: + x86_64: amd64 + arm_64: arm64 + url: https://github.com/opentofu/opentofu/releases/download/v${version}/tofu_${version}_${os}_${cpu}.zip +tools: + definitions: + - name: tofu + download: tofu + shims: [tofu] + known_good_version: 1.6.2 diff --git a/tools/tofu/tofu.test.ts b/tools/tofu/tofu.test.ts new file mode 100644 index 000000000..bacd89cca --- /dev/null +++ b/tools/tofu/tofu.test.ts @@ -0,0 +1,11 @@ +import { makeToolTestConfig, toolTest } from "tests"; +toolTest({ + toolName: "tofu", + toolVersion: "1.6.2", + testConfigs: [ + makeToolTestConfig({ + command: ["tofu", "--version"], + expectedOut: "OpenTofu v1.6.2", + }), + ], +});