1- // Guards the class of defect behind #1967 and #1968: an AWS action the
2- // application calls under the runtime role that no runtime IaC flavor grants.
3- // check-aws-iam-parity.sh cannot see this class because it only compares the
4- // three runtime flavors with each other, so a gap present in all three passes.
5- // This derives the called-action set straight from the SDK request structs
6- // under the scanned roots and asserts each flavor grants every one.
7- //
8- // Two limits are deliberate. The guard is one-way: it catches an action the
9- // code calls that a flavor does not grant, never a grant no code uses. Dead
10- // grants are #1322's subject. And it covers only the reservation-related
11- // service prefixes below, matching check-aws-iam-parity.sh's scope; platform
12- // namespaces (sns, ses, secretsmanager, lambda, kms, logs) are out of reach
13- // and have known gaps of their own, tracked on #1204.
1+ // Detects CE/EC2 action names missing from runtime IaC, including gaps shared
2+ // by all three flavors that check-aws-iam-parity.sh cannot detect (#1967/#1968).
3+ // This is source/action-presence coverage, not IAM evaluation: Effect, resource
4+ // scope, role attachment, and inline comments require separate review. Unused
5+ // grants (#1322) and other service namespaces are outside this guard's scope.
146package aws_test
157
168import (
@@ -25,22 +17,13 @@ import (
2517 "testing"
2618)
2719
28- // sdkServiceToIAMPrefix maps an aws-sdk-go-v2 service package name to the IAM
29- // action prefix it authorizes against. Two services rename: Cost Explorer's
30- // package is costexplorer but its actions are ce:*, and OpenSearch's package
31- // is opensearch but its actions (for historical reasons) are es:*. sts is
32- // deliberately absent: GetCallerIdentity requires no IAM permission at all,
33- // so a call to it must never enter the derived set.
20+ // sdkServiceToIAMPrefix maps the CE/EC2 aws-sdk-go-v2 service package names to
21+ // the IAM action prefixes they authorize against. Cost Explorer's package is
22+ // costexplorer but its actions are ce:*. sts is deliberately absent:
23+ // GetCallerIdentity requires no IAM permission and must never enter the set.
3424var sdkServiceToIAMPrefix = map [string ]string {
35- "costexplorer" : "ce" ,
36- "ec2" : "ec2" ,
37- "rds" : "rds" ,
38- "elasticache" : "elasticache" ,
39- "opensearch" : "es" ,
40- "redshift" : "redshift" ,
41- "memorydb" : "memorydb" ,
42- "savingsplans" : "savingsplans" ,
43- "organizations" : "organizations" ,
25+ "costexplorer" : "ce" ,
26+ "ec2" : "ec2" ,
4427}
4528
4629// requiredDerivedActions is the floor from #1967/#1968: actions the code is
@@ -54,9 +37,6 @@ var requiredDerivedActions = []string{
5437 "ec2:CancelReservedInstancesListing" ,
5538 "ec2:DescribeInstanceTypes" ,
5639 "ec2:CreateTags" ,
57- "redshift:DescribeTags" ,
58- "redshift:CreateTags" ,
59- "es:AddTags" ,
6040}
6141
6242// scanRoots are walked, relative to the repo root, for SDK call sites.
@@ -250,19 +230,17 @@ func sdkImportAliases(file *ast.File) map[string]string {
250230 return aliases
251231}
252232
253- // grantedActionPattern is check-aws-iam-parity.sh's extraction regex,
254- // rewritten with a capture group so the match includes only the action
255- // itself, not the boundary byte before it.
256- var grantedActionPattern = regexp .MustCompile (`(?:^|[^A-Za-z])((?:ce|ec2|rds|elasticache|es|redshift|memorydb|savingsplans|organizations ):[A-Z][A-Za-z]+)` )
233+ // grantedActionPattern is the CE/EC2 subset of check-aws-iam-parity.sh's
234+ // extraction regex, rewritten with a capture group so the match includes only
235+ // the action itself, not the boundary byte before it.
236+ var grantedActionPattern = regexp .MustCompile (`(?:^|[^A-Za-z])((?:ce|ec2):[A-Z][A-Za-z]+)` )
257237
258238// hashCommentLinePattern matches a whole line whose first non-blank byte is
259239// #, the comment style both Terraform and CloudFormation YAML use here.
260240var hashCommentLinePattern = regexp .MustCompile (`(?m)^[ \t]*#.*$` )
261241
262- // grantedActions reads path (relative to this package's directory, matching
263- // how go test sets its working directory) and returns the set of IAM actions
264- // it grants. Comment lines are stripped first, so a comment naming an action
265- // cannot satisfy the guard.
242+ // grantedActions extracts action names from path after stripping whole-line
243+ // # comments. It does not parse policy semantics or other comment forms.
266244func grantedActions (t * testing.T , path string ) map [string ]bool {
267245 t .Helper ()
268246
0 commit comments