Skip to content

Commit 724e633

Browse files
authored
Merge pull request hashicorp#155 from hashicorp/add-all-resources-in-pmr-policy
add require-all-resources-from-pmr
2 parents d39d9f6 + ab7855b commit 724e633

File tree

9 files changed

+984
-0
lines changed

9 files changed

+984
-0
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# This policy validates that all modules loaded directly by the
2+
# root module are in the Private Module Registry (PMR) of a TFC
3+
# server and that no resources are created in the root module
4+
5+
#####Imports#####
6+
import "tfconfig"
7+
import "strings"
8+
9+
#####Functions#####
10+
11+
#Prevent resources in root module
12+
prevent_resources_in_root_module = func() {
13+
14+
validated = true
15+
16+
if length(tfconfig.resources) != 0 {
17+
print("Resources are not allowed in the root module.")
18+
print("Your root module has", length(tfconfig.resources), "type(s) of resources.")
19+
validated = false
20+
}
21+
22+
return validated
23+
}
24+
25+
# Require all modules directly under root module to come from PMR
26+
require_modules_from_pmr = func(address, organization) {
27+
28+
validated = true
29+
30+
for tfconfig.modules as name, m {
31+
if not strings.has_prefix(m.source, address + "/" + organization) {
32+
print("All non-root modules must come from the private module registry",
33+
address + "/" + organization)
34+
print("You included module,", name, ", with source,", m.source)
35+
validated = false
36+
}
37+
}
38+
39+
return validated
40+
}
41+
42+
##### Global Variables #####
43+
# Define the address of the TFE server
44+
address = "app.terraform.io"
45+
46+
# Define organization variable
47+
organization = "Cloud-Operations"
48+
49+
##### Rules #####
50+
51+
# Main rule that requires other rules to be true
52+
no_resources_in_root_module = prevent_resources_in_root_module()
53+
all_non_root_modules_from_pmr = require_modules_from_pmr(address, organization)
54+
main = rule {
55+
no_resources_in_root_module and all_non_root_modules_from_pmr
56+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mock": {
3+
"tfconfig": "mock-tfconfig-fail-0.11.sentinel"
4+
},
5+
"test": {
6+
"main": false
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"mock": {
3+
"tfconfig": "mock-tfconfig-fail-0.12.sentinel"
4+
},
5+
"test": {
6+
"main": false
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import "strings"
2+
import "types"
3+
4+
_modules = {
5+
"root": {
6+
"data": {},
7+
"modules": {
8+
"first": {
9+
"config": {},
10+
"source": "./module",
11+
"version": "",
12+
},
13+
},
14+
"outputs": {},
15+
"providers": {
16+
"aws": {
17+
"alias": {
18+
"": {
19+
"config": {
20+
"region": "us-east-2",
21+
},
22+
"version": "",
23+
},
24+
"root-east": {
25+
"config": {
26+
"region": "us-east-1",
27+
},
28+
"version": "",
29+
},
30+
"root-west": {
31+
"config": {
32+
"region": "us-west-1",
33+
},
34+
"version": "",
35+
},
36+
},
37+
"config": {
38+
"region": "us-east-2",
39+
},
40+
"version": "",
41+
},
42+
},
43+
"resources": {
44+
"aws_instance": {
45+
"web": {
46+
"config": {
47+
"ami": "ami-2e1ef954",
48+
"instance_type": "t2.micro",
49+
"tags": [
50+
{
51+
"Name": "root module instance",
52+
},
53+
],
54+
},
55+
"provisioners": null,
56+
},
57+
},
58+
},
59+
"variables": {},
60+
},
61+
62+
"module.first": {
63+
"data": {},
64+
"modules": {
65+
"second": {
66+
"config": {},
67+
"source": "./module",
68+
"version": "",
69+
},
70+
},
71+
"outputs": {},
72+
"providers": {
73+
"aws": {
74+
"alias": {
75+
"": {
76+
"config": {
77+
"region": "us-east-2",
78+
},
79+
"version": "",
80+
},
81+
"first-east": {
82+
"config": {
83+
"region": "us-east-1",
84+
},
85+
"version": "",
86+
},
87+
"first-west": {
88+
"config": {
89+
"region": "us-west-1",
90+
},
91+
"version": "",
92+
},
93+
},
94+
"config": {
95+
"region": "us-east-2",
96+
},
97+
"version": "",
98+
},
99+
},
100+
"resources": {
101+
"aws_instance": {
102+
"web": {
103+
"config": {
104+
"ami": "ami-2e1ef954",
105+
"instance_type": "t2.micro",
106+
"tags": [
107+
{
108+
"Name": "first module instance",
109+
},
110+
],
111+
},
112+
"provisioners": null,
113+
},
114+
},
115+
},
116+
"variables": {},
117+
},
118+
119+
"module.first.module.second": {
120+
"data": {},
121+
"modules": {},
122+
"outputs": {},
123+
"providers": {
124+
"aws": {
125+
"alias": {
126+
"": {
127+
"config": {
128+
"region": "us-east-2",
129+
},
130+
"version": "",
131+
},
132+
"second-east": {
133+
"config": {
134+
"region": "us-east-1",
135+
},
136+
"version": "",
137+
},
138+
"second-west": {
139+
"config": {
140+
"region": "us-west-1",
141+
},
142+
"version": "",
143+
},
144+
},
145+
"config": {
146+
"region": "us-east-2",
147+
},
148+
"version": "",
149+
},
150+
},
151+
"resources": {
152+
"aws_instance": {
153+
"web": {
154+
"config": {
155+
"ami": "ami-2e1ef954",
156+
"instance_type": "t2.micro",
157+
"tags": [
158+
{
159+
"Name": "second module instance",
160+
},
161+
],
162+
},
163+
"provisioners": null,
164+
},
165+
},
166+
},
167+
"variables": {},
168+
},
169+
}
170+
171+
module_paths = [
172+
[],
173+
[
174+
"first",
175+
],
176+
[
177+
"first",
178+
"second",
179+
],
180+
]
181+
182+
module = func(path) {
183+
if types.type_of(path) is not "list" {
184+
error("expected list, got", types.type_of(path))
185+
}
186+
187+
if length(path) < 1 {
188+
return _modules.root
189+
}
190+
191+
addr = []
192+
for path as p {
193+
append(addr, "module")
194+
append(addr, p)
195+
}
196+
197+
return _modules[strings.join(addr, ".")]
198+
}
199+
200+
data = _modules.root.data
201+
modules = _modules.root.modules
202+
providers = _modules.root.providers
203+
resources = _modules.root.resources
204+
variables = _modules.root.variables
205+
outputs = _modules.root.outputs

0 commit comments

Comments
 (0)