Repository navigation
Expand file tree
/
Copy pathvariables.tf
More file actions
313 lines (281 loc) · 11.9 KB
/
Copy pathvariables.tf
File metadata and controls
313 lines (281 loc) · 11.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
###############################################################################
# Identity
###############################################################################
variable "repository_name" {
description = <<EOT
Name for the CodeCommit repository. REQUIRED. Must be 1-100 characters, using
only letters, numbers, periods, underscores, and dashes, and must not end in
".git" (AWS repository-naming rules). Also serves as the `terraform import` key.
Not marked force-new by the provider (codecommit:UpdateRepositoryName is a
supported, in-place rename), but treat it as force-new IN PRACTICE — clone
URLs, IAM policy Resource ARNs, CI/CD wiring, and this module's own trigger /
approval-rule-template-association resources are all keyed on the current
name, so a rename breaks external references silently even though the
`apply` itself succeeds.
EOT
type = string
validation {
condition = can(regex("^[A-Za-z0-9._-]{1,100}$", var.repository_name))
error_message = "repository_name must be 1-100 characters using only letters, numbers, periods, underscores, and dashes."
}
validation {
condition = !endswith(var.repository_name, ".git")
error_message = "repository_name must not end in \".git\"."
}
}
###############################################################################
# Optional repository configuration
###############################################################################
variable "description" {
description = "Description of the repository, shown in the console. Optional; must be 1000 characters or fewer. Null (default) leaves the repository undescribed."
type = string
default = null
validation {
condition = var.description == null || length(var.description) <= 1000
error_message = "description must be 1000 characters or fewer."
}
}
variable "default_branch" {
description = <<EOT
Default branch of the repository. Optional; null (default) leaves no default
branch configured.
IMPORTANT — the branch named here must already exist in the repository before
it can be set. A brand-new CodeCommit repository starts with ZERO branches
until a first commit is pushed, so you CANNOT set default_branch in the same
apply that creates the repository. Leave this null on initial creation, push
an initial commit out-of-band (or via a follow-up pipeline step), then set
default_branch in a subsequent apply.
EOT
type = string
default = null
}
variable "kms_key_id" {
description = <<EOT
ARN (preferred) or key id of a customer-managed KMS key (CMK) used to encrypt
the repository. Null (default) uses the AWS-managed `aws/codecommit` key.
Wire from terraform-aws-kms (arn output) for a CMK — this is a hardening
ADDITION, not a weakening opt-out; CodeCommit repositories cannot be created
unencrypted either way. Prefer the key ARN over an alias ARN (alias/...),
which the provider does not reliably accept for this argument.
EOT
type = string
default = null
}
###############################################################################
# Triggers (child collection, rendered as dynamic "trigger" blocks inside a
# SINGLE aws_codecommit_trigger resource)
#
# The provider allows only ONE aws_codecommit_trigger resource per repository,
# and creating it replaces ALL triggers on the repository -- including any
# manually-created ones. Multiple logical triggers are therefore modeled here
# as multiple entries in this map, each becoming one nested `trigger {... }`
# block inside that single resource (AWS caps a repository at 10 triggers
# total -- enforced below to fail at plan time rather than apply time).
###############################################################################
variable "triggers" {
description = <<EOT
Map of repository triggers keyed by a stable name, each becoming one nested
`trigger {... }` block inside the single aws_codecommit_trigger resource this
module manages. Leave empty (default) to configure no triggers. AWS caps a
repository at 10 triggers total.
triggers = {
all-events = {
destination_arn = module.sns_topic.arn
events = ["all"]
}
pr-updates = {
destination_arn = module.sns_topic.arn
events = ["updateReference"]
branches = ["main"]
}
}
Per-trigger fields:
- name: (Optional) Trigger name shown in the console. Defaults to
the map key. 1-100 characters; letters, numbers,
periods, underscores, dashes only -- no spaces or commas.
- destination_arn: (Required) ARN of the notification target -- typically
an SNS topic ARN (wire from terraform-aws-sns).
CodeCommit does not manage the target's resource policy;
the target must independently allow
codecommit.amazonaws.com to publish/invoke.
- events: (Optional) Repository events that fire the trigger. One
or more of: "all", "createReference",
"updateReference", "deleteReference". Defaults to
["all"].
- custom_data: (Optional) Opaque string passed through to the
notification payload. Max 1000 characters. Cannot carry
dynamic parameters.
- branches: (Optional) Branches the trigger applies to. Empty list
(default) applies the trigger to all branches.
EOT
type = map(object({
name = optional(string)
destination_arn = string
events = optional(list(string), ["all"])
custom_data = optional(string)
branches = optional(list(string), [])
}))
default = {}
validation {
condition = length(var.triggers) <= 10
error_message = "triggers supports at most 10 entries -- AWS CodeCommit caps a repository at 10 triggers total."
}
validation {
condition = alltrue([
for k, t in var.triggers:
can(regex("^arn:aws[a-zA-Z-]*:", t.destination_arn))
])
error_message = "Every triggers[*].destination_arn must be a valid ARN (arn:aws:...)."
}
validation {
condition = alltrue([
for k, t in var.triggers: alltrue([
for e in t.events: contains(["all", "createReference", "updateReference", "deleteReference"], e)
])
])
error_message = "Every triggers[*].events entry must be one of: all, createReference, updateReference, deleteReference."
}
validation {
condition = alltrue([
for k, t in var.triggers:
can(regex("^[A-Za-z0-9._-]{1,100}$", coalesce(t.name, k)))
])
error_message = "Every trigger name (explicit name or map key) must be 1-100 characters using only letters, numbers, periods, underscores, and dashes -- no spaces or commas."
}
validation {
condition = alltrue([
for k, t in var.triggers:
t.custom_data == null || length(t.custom_data) <= 1000
])
error_message = "Every triggers[*].custom_data must be 1000 characters or fewer."
}
}
###############################################################################
# Approval rule templates (child collection, for_each over map(object))
#
# Each map entry renders BOTH an aws_codecommit_approval_rule_template AND a
# matching aws_codecommit_approval_rule_template_association against this
# repository -- an approval rule template has no effect on any repository
# until associated, so this module associates every template it creates with
# its own repository automatically. `content` is a structured object (not a
# raw JSON/heredoc string) so jsonencode renders it deterministically and
# drift stays limited to genuine content changes rather than key reordering.
###############################################################################
variable "approval_rule_templates" {
description = <<EOT
Map of pull-request approval-rule templates keyed by a stable name (used as
the template's `name`), each rendering one aws_codecommit_approval_rule_template
PLUS a matching aws_codecommit_approval_rule_template_association binding it to
this repository. Leave empty (default) to define no approval rule templates --
change-control guidance recommends at least one for repositories touching
regulated workloads, but this module does not force a default.
approval_rule_templates = {
two-approvers-main = {
description = "Require 2 approvals on pull requests targeting main"
content = {
destination_references = ["refs/heads/main"]
statements = [{
number_of_approvals_needed = 2
approval_pool_members = [module.reviewer_role.arn]
}]
}
}
}
Per-template fields:
- description: (Optional) Template description. Max 1000 characters.
- content: (Required) Structured approval-rule content, rendered via
jsonencode into the provider's `content` argument
(max 3000 characters once encoded):
- version: (Optional) Content schema version. Defaults
to "2018-11-08" (the current AWS schema).
- destination_references: (Required) List of branch refs the rule
applies to (e.g. ["refs/heads/main"]).
- statements: (Required) List of approval statements:
- type: (Optional) Statement type. Defaults
to "Approvers" (the only type AWS
currently defines).
- number_of_approvals_needed: (Required) Approvals required, >= 1.
- approval_pool_members: (Optional) IAM principal ARNs (or
assumed-role ARN patterns, e.g.
"arn:aws:sts::111122223333:assumed-role/Reviewers/*")
eligible to approve. Wire from
terraform-aws-iam-role. Empty list
(default) means any repository
contributor may approve.
EOT
type = map(object({
description = optional(string)
content = object({
version = optional(string, "2018-11-08")
destination_references = list(string)
statements = list(object({
type = optional(string, "Approvers")
number_of_approvals_needed = number
approval_pool_members = optional(list(string), [])
}))
})
}))
default = {}
validation {
condition = alltrue([for k, t in var.approval_rule_templates: can(regex("^[A-Za-z0-9._ -]{1,100}$", k))])
error_message = "Every approval_rule_templates key (used as the template name) must be 1-100 characters using only letters, numbers, periods, spaces, underscores, and dashes."
}
validation {
condition = alltrue([for k, t in var.approval_rule_templates: !endswith(k, ".git")])
error_message = "Every approval_rule_templates key (used as the template name) must not end in \".git\"."
}
validation {
condition = alltrue([for k, t in var.approval_rule_templates: t.description == null || length(t.description) <= 1000])
error_message = "Every approval_rule_templates[*].description must be 1000 characters or fewer."
}
validation {
condition = alltrue([for k, t in var.approval_rule_templates: length(t.content.destination_references) > 0])
error_message = "Every approval_rule_templates[*].content.destination_references must have at least one branch ref."
}
validation {
condition = alltrue([for k, t in var.approval_rule_templates: length(t.content.statements) > 0])
error_message = "Every approval_rule_templates[*].content.statements must have at least one statement."
}
validation {
condition = alltrue([
for k, t in var.approval_rule_templates: alltrue([
for s in t.content.statements: s.number_of_approvals_needed >= 1
])
])
error_message = "Every approval_rule_templates[*].content.statements[*].number_of_approvals_needed must be >= 1."
}
validation {
condition = alltrue([
for k, t in var.approval_rule_templates:
length(jsonencode({
Version = t.content.version
DestinationReferences = t.content.destination_references
Statements = [
for s in t.content.statements: {
Type = s.type
NumberOfApprovalsNeeded = s.number_of_approvals_needed
ApprovalPoolMembers = s.approval_pool_members
}
]
})) <= 3000
])
error_message = "Every approval_rule_templates[*].content, once jsonencode-ed, must be 3000 characters or fewer (AWS approval-rule-template content limit)."
}
}
###############################################################################
# Universal tail
###############################################################################
variable "tags" {
description = <<EOT
A map of tags to assign to taggable resources created by this module. Of the
four resources this module manages, only aws_codecommit_repository accepts a
`tags` argument (verified against the live hashicorp/aws v6.53.0 provider
schema) -- aws_codecommit_trigger, aws_codecommit_approval_rule_template, and
aws_codecommit_approval_rule_template_association expose no `tags` argument
at all, so tags flow to the repository only. These merge with provider-level
default_tags; resource tags win on key conflict. The computed tags_all output
reflects the merged set.
EOT
type = map(string)
default = {}
}