Skip to content

Commit 6c5caa0

Browse files
feat: Add validation for JSON config file naming convention
JSON configuration files must now end with "tflint.json" to avoid confusion with other JSON files like terraform.tfvars.json. This ensures clear distinction between TFLint configuration files and other JSON files in the project. Valid names: - .tflint.json - my-tflint.json - project.tflint.json Invalid names: - config.json - test.json - terraform.tfvars.json This change prevents accidental parsing of non-TFLint JSON files and provides clearer error messages when invalid filenames are used. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 34c8961 commit 6c5caa0

File tree

6 files changed

+68
-26
lines changed

6 files changed

+68
-26
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,5 @@ require (
192192
)
193193

194194
tool golang.org/x/vuln/cmd/govulncheck
195+
196+
replace github.com/terraform-linters/tflint-plugin-sdk => ../tflint-plugin-sdk

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,8 +1288,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
12881288
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
12891289
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
12901290
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
1291-
github.com/terraform-linters/tflint-plugin-sdk v0.22.0 h1:holOVJW0hjf0wkjtnYyPWRooQNp8ETUcKE86rdYkH5U=
1292-
github.com/terraform-linters/tflint-plugin-sdk v0.22.0/go.mod h1:Cag3YJjBpHdQzI/limZR+Cj7WYPLTIE61xsCdIXoeUI=
12931291
github.com/terraform-linters/tflint-ruleset-terraform v0.13.0 h1:6obXOhxh5e9ijBGhrDm45eMDJiPsDQdYrrdkTI3C2dw=
12941292
github.com/terraform-linters/tflint-ruleset-terraform v0.13.0/go.mod h1:r6nu7KOv86j/oEOcNmwf156BzskCSMWlyKgNV0loaRQ=
12951293
github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI=
Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +0,0 @@
1-
{
2-
"issues": [],
3-
"errors": [
4-
{
5-
"message": "Failed to check ruleset; failed to check \"terraform_module_pinned_source\" rule: <nil>: Unexpected file extension; The file name `.tflint.json` is a file with an unexpected extension. Valid extensions are `.tf`, `.tf.json`, and `.hcl`.",
6-
"severity": "error"
7-
}
8-
]
9-
}

tflint/config.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"log"
66
"maps"
77
"os"
8+
"path/filepath"
89
"strings"
910

1011
"github.com/hashicorp/go-version"
@@ -256,6 +257,15 @@ func loadConfig(file afero.File) (*Config, error) {
256257
// Parse based on file extension
257258
switch {
258259
case strings.HasSuffix(strings.ToLower(filename), ".json"):
260+
// JSON config files must end with "tflint.json" to avoid confusion
261+
// with other JSON files (e.g., terraform.tfvars.json)
262+
if !strings.HasSuffix(strings.ToLower(filename), "tflint.json") {
263+
return nil, fmt.Errorf(
264+
"JSON configuration file must be named '.tflint.json' or end with 'tflint.json'. "+
265+
"Got: %s. Please rename the file or use an HCL configuration file.",
266+
filepath.Base(filename),
267+
)
268+
}
259269
f, diags = parser.ParseJSON(src, filename)
260270
default:
261271
f, diags = parser.ParseHCL(src, filename)

tflint/config_test.go

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,9 @@ config {
475475
},
476476
{
477477
name: "load JSON config file",
478-
file: "config.json",
478+
file: "config-tflint.json",
479479
files: map[string]string{
480-
"config.json": `{
480+
"config-tflint.json": `{
481481
"tflint": {
482482
"required_version": ">= 0"
483483
},
@@ -572,21 +572,21 @@ config {
572572
},
573573
{
574574
name: "empty JSON file",
575-
file: "empty.json",
575+
file: "empty-tflint.json",
576576
files: map[string]string{
577-
"empty.json": "{}",
577+
"empty-tflint.json": "{}",
578578
},
579579
want: EmptyConfig().enableBundledPlugin(),
580580
errCheck: neverHappend,
581581
},
582582
{
583583
name: "JSON syntax error",
584-
file: "syntax_error.json",
584+
file: "syntax_error-tflint.json",
585585
files: map[string]string{
586-
"syntax_error.json": `{"config": {`,
586+
"syntax_error-tflint.json": `{"config": {`,
587587
},
588588
errCheck: func(err error) bool {
589-
return err == nil || !strings.Contains(err.Error(), "syntax_error.json")
589+
return err == nil || !strings.Contains(err.Error(), "syntax_error-tflint.json")
590590
},
591591
},
592592
{
@@ -673,19 +673,60 @@ config {
673673
},
674674
errCheck: neverHappend,
675675
},
676+
{
677+
name: "invalid JSON config filename",
678+
file: "myconfig.json",
679+
files: map[string]string{
680+
"myconfig.json": `{
681+
"config": {
682+
"force": true
683+
}
684+
}`,
685+
},
686+
errCheck: func(err error) bool {
687+
return err == nil || !strings.Contains(err.Error(), "JSON configuration file must be named '.tflint.json' or end with 'tflint.json'")
688+
},
689+
},
690+
{
691+
name: "valid JSON config with tflint.json suffix",
692+
file: "my-tflint.json",
693+
files: map[string]string{
694+
"my-tflint.json": `{
695+
"config": {
696+
"force": true
697+
}
698+
}`,
699+
},
700+
want: &Config{
701+
CallModuleType: terraform.CallLocalModule,
702+
Force: true,
703+
ForceSet: true,
704+
IgnoreModules: map[string]bool{},
705+
Varfiles: []string{},
706+
Variables: []string{},
707+
Rules: map[string]*RuleConfig{},
708+
Plugins: map[string]*PluginConfig{
709+
"terraform": {
710+
Name: "terraform",
711+
Enabled: true,
712+
},
713+
},
714+
},
715+
errCheck: neverHappend,
716+
},
676717
{
677718
name: "TFLINT_CONFIG_FILE with JSON",
678719
file: "",
679720
files: map[string]string{
680-
"env.json": `{
721+
"env-tflint.json": `{
681722
"config": {
682723
"force": true,
683724
"disabled_by_default": true
684725
}
685726
}`,
686727
},
687728
envs: map[string]string{
688-
"TFLINT_CONFIG_FILE": "env.json",
729+
"TFLINT_CONFIG_FILE": "env-tflint.json",
689730
},
690731
want: &Config{
691732
CallModuleType: terraform.CallLocalModule,
@@ -1501,9 +1542,9 @@ plugin "terraform" {
15011542
},
15021543
{
15031544
name: "JSON config sources preserved",
1504-
file: "config.json",
1545+
file: "config-tflint.json",
15051546
files: map[string]string{
1506-
"config.json": `{
1547+
"config-tflint.json": `{
15071548
"config": {
15081549
"format": "json"
15091550
},
@@ -1516,7 +1557,7 @@ plugin "terraform" {
15161557
}`,
15171558
},
15181559
wantSources: map[string]string{
1519-
"config.json": `{
1560+
"config-tflint.json": `{
15201561
"config": {
15211562
"format": "json"
15221563
},
@@ -1553,9 +1594,9 @@ plugin "terraform" {
15531594
},
15541595
{
15551596
name: "mixed HCL bundled + JSON user config",
1556-
file: "user.json",
1597+
file: "user-tflint.json",
15571598
files: map[string]string{
1558-
"user.json": `{
1599+
"user-tflint.json": `{
15591600
"rule": {
15601601
"terraform_unused_declarations": {
15611602
"enabled": false
@@ -1564,7 +1605,7 @@ plugin "terraform" {
15641605
}`,
15651606
},
15661607
wantSources: map[string]string{
1567-
"user.json": `{
1608+
"user-tflint.json": `{
15681609
"rule": {
15691610
"terraform_unused_declarations": {
15701611
"enabled": false

tflint/tflint

5.1 KB
Binary file not shown.

0 commit comments

Comments
 (0)