Repository: smithy-lang/smithy
Pull request #2632 (2025-05-13 12:43:56)

Search all resource operations for condition keys
This fixes a bug where collection operations were not being searched by `ConditionKeysIndex`.

---
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.



Patch:
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndex.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndex.java
index 5269aae17..c3ce98d3a 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndex.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndex.java
@@ -192,7 +192,7 @@ public final class ConditionKeysIndex implements KnowledgeIndex {
                     : MapUtils.of();
 
             // Compute the keys of each child operation, passing no keys.
-            for (ShapeId operationId : resource.getOperations()) {
+            for (ShapeId operationId : resource.getAllOperations()) {
                 Optional<Shape> operationOptional = model.getShape(operationId);
                 if (operationOptional.isPresent()) {
                     compute(model, service, arnRoot, operationOptional.get(), resource);


Test patch:
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndexTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndexTest.java
index 3e3d5ade7..40ad381f6 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndexTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ConditionKeysIndexTest.java
@@ -13,6 +13,7 @@ import static org.hamcrest.Matchers.not;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import java.util.Optional;
+import java.util.Set;
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.shapes.ShapeId;
@@ -65,6 +66,20 @@ public class ConditionKeysIndexTest {
                 is(empty()));
     }
 
+    @Test
+    public void getsConditionKeysFromResourceCollectionOperations() {
+        Model model = Model.assembler()
+                .addImport(getClass().getResource("resource-condition-keys.smithy"))
+                .discoverModels(getClass().getClassLoader())
+                .assemble()
+                .unwrap();
+        ShapeId service = ShapeId.from("ns.example#MyService");
+        ShapeId operation = ShapeId.from("ns.example#MyOperation");
+        ConditionKeysIndex index = ConditionKeysIndex.of(model);
+        Set<String> result = index.getConditionKeyNames(service, operation);
+        assertThat(result, containsInAnyOrder("aws:accountId", "s3:bucket"));
+    }
+
     @Test
     public void disableConditionKeyInferenceForResources() {
         Model model = Model.assembler()
diff --git a/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/resource-condition-keys.smithy b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/resource-condition-keys.smithy
new file mode 100644
index 000000000..a22c0280d
--- /dev/null
+++ b/smithy-aws-iam-traits/src/test/resources/software/amazon/smithy/aws/iam/traits/resource-condition-keys.smithy
@@ -0,0 +1,80 @@
+$version: "2.0"
+
+namespace ns.example
+
+use aws.api#service
+use aws.iam#conditionKeys
+use aws.iam#defineConditionKeys
+use aws.iam#disableConditionKeyInference
+use aws.iam#supportedPrincipalTypes
+
+/// MyService is a service for me.
+@service(
+    sdkId: "My Value"
+    arnNamespace: "myservice"
+)
+@defineConditionKeys(
+    "aws:accountId": {
+        type: "Numeric"
+    }
+    "aws:region": {
+        type: "String"
+    }
+    "myservice:pop": {
+        type: "String"
+    }
+    "myservice:snap": {
+        type: "String"
+    }
+    "otherservice:crackle": {
+        type: "String"
+    }
+    "s3:bucket": {
+        type: "String"
+    }
+)
+@supportedPrincipalTypes([
+    "Root"
+    "IAMUser"
+    "IAMRole"
+    "FederatedUser"
+])
+@title("My Service")
+service MyService {
+    version: "0.0.1"
+    resources: [
+        MyResource
+    ]
+}
+
+@conditionKeys([
+    "aws:region"
+    "myservice:pop"
+    "myservice:snap"
+    "otherservice:crackle"
+])
+@disableConditionKeyInference
+resource MyResource {
+    identifiers: {
+        buzz: String
+        fizz: String
+        pop: String
+    }
+    collectionOperations: [
+        MyOperation
+    ]
+}
+
+@conditionKeys([
+    "aws:accountId"
+    "s3:bucket"
+])
+operation MyOperation {
+    input := {
+        @required
+        fizz: String
+        @required
+        buzz: String
+        pop: String
+    }
+}