Skip to content

Commit 8dd2eaf

Browse files
committed
Add "expr" type as a schema type
1 parent 8246785 commit 8dd2eaf

File tree

11 files changed

+1040
-16
lines changed

11 files changed

+1040
-16
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
plugin "terraform" {
2+
enabled = false
3+
}
4+
5+
plugin "opa" {
6+
enabled = true
7+
8+
policy_dir = "policies"
9+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
resource "aws_instance" "valid" {
2+
ami = get_ami_id("service1", "v1")
3+
4+
lifecycle {
5+
ignore_changes = [tags]
6+
}
7+
}
8+
9+
resource "aws_instance" "invalid" {
10+
ami = get_ami_id("service1", "v0.9")
11+
12+
lifecycle {
13+
ignore_changes = [ami]
14+
}
15+
}
16+
17+
module "valid" {
18+
providers = {
19+
aws = aws.usw1
20+
}
21+
}
22+
23+
module "invalid" {
24+
providers = {
25+
aws = aws.usw2
26+
}
27+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package tflint
2+
3+
import rego.v1
4+
5+
deny_require_lifecycle_ignore_tags contains issue if {
6+
res := terraform.resources("*",{"lifecycle": {"ignore_changes": "expr"}},{"expand_mode": "none"})[_]
7+
not has_tags_ignore(res)
8+
9+
issue := tflint.issue(
10+
sprintf("Resource %s.%s must have lifecycle.ignore_changes include \"tags\"", [res.type, res.name]),
11+
res.decl_range
12+
)
13+
}
14+
15+
# helper succeeds only if there's a lifecycle.ignore_changes list and one of its elements == "tags"
16+
has_tags_ignore(res) if {
17+
lifeblock := res.config.lifecycle[_]
18+
19+
ic := lifeblock.config.ignore_changes
20+
print(hcl.expr_list(ic))
21+
some i
22+
hcl.expr_list(ic)[i].value == "tags"
23+
}
24+
25+
deny_deprecated_regions contains issue if {
26+
call := terraform.module_calls({"providers": "expr"}, {})[_]
27+
has_deprecated_region(call)
28+
29+
issue := tflint.issue(
30+
"deprecated region reference found",
31+
call.config.providers.range,
32+
)
33+
}
34+
35+
has_deprecated_region(call) if {
36+
providers := call.config.providers
37+
38+
some i
39+
hcl.expr_map(providers)[i].value.value == "aws.usw2"
40+
}
41+
42+
deny_deprecated_ami_version contains issue if {
43+
instance := terraform.resources("aws_instance", {"ami": "expr"}, {})[_]
44+
is_function_call_with_deprecated_version(instance)
45+
46+
issue := tflint.issue(
47+
"get_ami_id function should be called with v1",
48+
instance.decl_range
49+
)
50+
}
51+
52+
is_function_call_with_deprecated_version(instance) if {
53+
ami := instance.config.ami
54+
55+
call := hcl.expr_call(ami)
56+
call.name == "get_ami_id"
57+
call.arguments[1].value != `"v1"`
58+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package tflint
2+
3+
import rego.v1
4+
5+
invalid_resources(type, schema, options) := terraform.mock_resources(type, schema, options, {
6+
"main.tf": `
7+
resource "aws_instance" "invalid" {
8+
ami = get_ami_id("service1", "v0.9")
9+
10+
lifecycle {
11+
ignore_changes = [ami]
12+
}
13+
}
14+
`,
15+
})
16+
17+
valid_resources(type, schema, options) := terraform.mock_resources(type, schema, options, {
18+
"main.tf": `
19+
resource "aws_instance" "valid" {
20+
ami = get_ami_id("service1", "v1")
21+
22+
lifecycle {
23+
ignore_changes = [tags]
24+
}
25+
}
26+
`,
27+
})
28+
29+
test_wrong_ignore_passed if {
30+
issues := deny_require_lifecycle_ignore_tags with terraform.resources as invalid_resources
31+
32+
count(issues) == 1
33+
issues[_].msg == "Resource aws_instance.invalid must have lifecycle.ignore_changes include \"tags\""
34+
}
35+
36+
test_wrong_ignore_failed if {
37+
issues := deny_require_lifecycle_ignore_tags with terraform.resources as invalid_resources
38+
39+
count(issues) == 0
40+
}
41+
42+
test_correct_ignore_passed if {
43+
issues := deny_require_lifecycle_ignore_tags with terraform.resources as valid_resources
44+
45+
count(issues) == 0
46+
}
47+
48+
test_correct_ignore_failed if {
49+
issues := deny_require_lifecycle_ignore_tags with terraform.resources as valid_resources
50+
51+
count(issues) == 1
52+
}
53+
54+
test_wrong_ami_passed if {
55+
issues := deny_deprecated_ami_version with terraform.resources as invalid_resources
56+
57+
count(issues) == 1
58+
issues[_].msg == "get_ami_id function should be called with v1"
59+
}
60+
61+
test_wrong_ami_failed if {
62+
issues := deny_deprecated_ami_version with terraform.resources as invalid_resources
63+
64+
count(issues) == 0
65+
}
66+
67+
test_correct_ami_passed if {
68+
issues := deny_deprecated_ami_version with terraform.resources as valid_resources
69+
70+
count(issues) == 0
71+
}
72+
73+
test_correct_ami_failed if {
74+
issues := deny_deprecated_ami_version with terraform.resources as valid_resources
75+
76+
count(issues) == 1
77+
}
78+
79+
invalid_calls(schema, options) := terraform.mock_module_calls(schema, options, {
80+
"main.tf": `
81+
module "invalid" {
82+
providers = {
83+
aws = aws.usw2
84+
}
85+
}
86+
`,
87+
})
88+
89+
valid_calls(schema, options) := terraform.mock_module_calls(schema, options, {
90+
"main.tf": `
91+
module "valid" {
92+
providers = {
93+
aws = aws.usw1
94+
}
95+
}
96+
`,
97+
})
98+
99+
test_wrong_region_passed if {
100+
issues := deny_deprecated_regions with terraform.module_calls as invalid_calls
101+
102+
count(issues) == 1
103+
issues[_].msg == "deprecated region reference found"
104+
}
105+
106+
test_wrong_region_failed if {
107+
issues := deny_deprecated_regions with terraform.module_calls as invalid_calls
108+
109+
count(issues) == 0
110+
}
111+
112+
test_correct_region_passed if {
113+
issues := deny_deprecated_regions with terraform.module_calls as valid_calls
114+
115+
count(issues) == 0
116+
}
117+
118+
test_correct_region_failed if {
119+
issues := deny_deprecated_regions with terraform.module_calls as valid_calls
120+
121+
count(issues) == 1
122+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"issues": [
3+
{
4+
"rule": {
5+
"name": "opa_deny_require_lifecycle_ignore_tags",
6+
"severity": "error",
7+
"link": "policies/main.rego:5"
8+
},
9+
"message": "Resource aws_instance.invalid must have lifecycle.ignore_changes include \"tags\"",
10+
"range": {
11+
"filename": "main.tf",
12+
"start": {
13+
"line": 9,
14+
"column": 1
15+
},
16+
"end": {
17+
"line": 9,
18+
"column": 34
19+
}
20+
},
21+
"callers": []
22+
},
23+
{
24+
"rule": {
25+
"name": "opa_deny_deprecated_ami_version",
26+
"severity": "error",
27+
"link": "policies/main.rego:42"
28+
},
29+
"message": "get_ami_id function should be called with v1",
30+
"range": {
31+
"filename": "main.tf",
32+
"start": {
33+
"line": 9,
34+
"column": 1
35+
},
36+
"end": {
37+
"line": 9,
38+
"column": 34
39+
}
40+
},
41+
"callers": []
42+
},
43+
{
44+
"rule": {
45+
"name": "opa_deny_deprecated_regions",
46+
"severity": "error",
47+
"link": "policies/main.rego:25"
48+
},
49+
"message": "deprecated region reference found",
50+
"range": {
51+
"filename": "main.tf",
52+
"start": {
53+
"line": 24,
54+
"column": 15
55+
},
56+
"end": {
57+
"line": 26,
58+
"column": 4
59+
}
60+
},
61+
"callers": []
62+
}
63+
],
64+
"errors": []
65+
}

0 commit comments

Comments
 (0)