Repository: smithy-lang/smithy
Pull request #2095 (2024-01-09 22:41:42)

Improve deprecation of IAM Action traits
This commit formally deprecates the traits superseded by `@iamAction`
in Java code. Methods are added to IamAction to aid users in the
resolution of properties.

A resolution aid is also added to IamResource.

-----

Update IAM trait documentation

- Supersedes #2055 

-----

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/docs/source-2.0/aws/aws-iam.rst b/docs/source-2.0/aws/aws-iam.rst
index ee39923db..91377a1fe 100644
--- a/docs/source-2.0/aws/aws-iam.rst
+++ b/docs/source-2.0/aws/aws-iam.rst
@@ -18,12 +18,17 @@ Smithy are automatically inferred. These can be disabled or augmented. For
 more information, see :ref:`deriving-condition-keys`.
 
 
+.. _aws-iam_traits-principal:
+
+----------------
+Principal traits
+----------------
+
 .. smithy-trait:: aws.iam#supportedPrincipalTypes
 .. _aws.iam#supportedPrincipalTypes-trait:
 
------------------------------------------
 ``aws.iam#supportedPrincipalTypes`` trait
------------------------------------------
+=========================================
 
 Summary
     The `IAM principal types`_ that can use the service or operation.
@@ -64,68 +69,6 @@ The following example defines two operations:
     operation OperationB {}
 
 
-.. _aws-iam_traits-resources:
-
----------------
-Resource traits
----------------
-
-.. smithy-trait:: aws.iam#iamResource
-.. _aws.iam#iamResource-trait:
-
-``aws.iam#iamResource`` trait
-=============================
-
-Summary
-    Indicates properties of a Smithy resource in AWS IAM.
-Trait selector
-    ``resource``
-Value type
-    ``structure``
-
-The ``aws.iam#iamResource`` trait is a structure that supports the following
-members:
-
-.. list-table::
-    :header-rows: 1
-    :widths:  10 20 70
-
-    * - Property
-      - Type
-      - Description
-    * - name
-      - ``string``
-      - The name of the resource in AWS IAM.
-    * - relativeDocumentation
-      - ``string``
-      - A relative URL path that defines more information about the resource
-        within a set of IAM-related documentation.
-    * - disableConditionKeyInheritance
-      - ``boolean``
-      - When set to ``true``, decouples this IAM resource's condition keys from
-        those of its parent resource(s). This can be used in combination with
-        the :ref:`aws.iam#conditionKeys-trait` trait to isolate a resource's
-        condition keys from those of its parent(s).
-
-The following example defines a simple resource with a name in AWS IAM that
-deviates from the :ref:`shape name of the shape ID <shape-id>` of the resource.
-
-.. code-block:: smithy
-
-    $version: "2"
-
-    namespace smithy.example
-
-    use aws.iam#iamResource
-
-    @iamResource(name: "super")
-    resource SuperResource {
-        identifiers: {
-            superId: String,
-        }
-    }
-
-
 .. _aws-iam_traits-actions:
 
 -------------
@@ -246,11 +189,16 @@ contains the following properties:
       - The condition keys used for authorizing against this resource.
 
 
+.. _aws-iam_traits-actions-deprecated-traits:
+
+Deprecated action traits
+========================
+
 .. smithy-trait:: aws.iam#actionName
 .. _aws.iam#actionName-trait:
 
 ``aws.iam#actionName`` trait
-============================
+----------------------------
 
 .. danger::
     This trait is deprecated. The ``name`` property of the
@@ -295,7 +243,7 @@ The following example defines two operations:
 .. _aws.iam#actionPermissionDescription-trait:
 
 ``aws.iam#actionPermissionDescription`` trait
-=============================================
+---------------------------------------------
 
 .. danger::
     This trait is deprecated. The ``documentation`` property of the
@@ -325,7 +273,7 @@ Value type
 .. _aws.iam#requiredActions-trait:
 
 ``aws.iam#requiredActions`` trait
-=================================
+---------------------------------
 
 .. danger::
     This trait is deprecated. The ``requiredActions`` property of the
@@ -369,6 +317,68 @@ operation for it to complete successfully.
     @requiredActions(["otherservice:OtherOperation"])
     operation MyOperation {}
 
+.. _aws-iam_traits-resources:
+
+---------------
+Resource Traits
+---------------
+
+.. smithy-trait:: aws.iam#iamResource
+.. _aws.iam#iamResource-trait:
+
+``aws.iam#iamResource`` trait
+=============================
+
+Summary
+    Indicates properties of a Smithy resource in AWS IAM.
+Trait selector
+    ``resource``
+Value type
+    ``structure``
+
+The ``aws.iam#iamResource`` trait is a structure that supports the following
+members:
+
+.. list-table::
+    :header-rows: 1
+    :widths:  10 20 70
+
+    * - Property
+      - Type
+      - Description
+    * - name
+      - ``string``
+      - The name of the resource in AWS IAM.
+    * - relativeDocumentation
+      - ``string``
+      - A relative URL path that defines more information about the resource
+        within a set of IAM-related documentation.
+    * - disableConditionKeyInheritance
+      - ``boolean``
+      - When set to ``true``, decouples this IAM resource's condition keys from
+        those of its parent resource(s). This can be used in combination with
+        the :ref:`aws.iam#conditionKeys-trait` trait to isolate a resource's
+        condition keys from those of its parent(s).
+
+The following example defines a simple resource with a name in AWS IAM that
+deviates from the :ref:`shape name of the shape ID <shape-id>` of the resource.
+
+.. code-block:: smithy
+
+    $version: "2"
+
+    namespace smithy.example
+
+    use aws.iam#iamResource
+
+    @iamResource(name: "super")
+    resource SuperResource {
+        identifiers: {
+            superId: String,
+        }
+    }
+
+
 
 .. _aws-iam_traits-condition-keys:
 
@@ -384,7 +394,8 @@ Condition key traits
 
 Summary
     Defines the set of condition keys that appear within a service in
-    addition to inferred and global condition keys.
+    addition to :ref:`inferred <deriving-condition-keys>` and global condition
+    keys.
 Trait selector
     ``service``
 Value type
@@ -433,7 +444,7 @@ Each condition key structure supports the following members:
 
     @service(sdkId: "My Value", arnNamespace: "myservice")
     @defineConditionKeys(
-        "otherservice:Bar": {
+        "myservice:Bar": {
             type: "String"
             documentation: "The Bar string"
             externalDocumentation: "http://example.com"
@@ -449,49 +460,6 @@ Each condition key structure supports the following members:
     defined on the service.
 
 
-.. _condition-key-types:
-
-Condition Key Types
--------------------
-
-The following table describes the available types a condition key can have.
-Condition keys in IAM policies can be evaluated with `condition operators`_.
-
-.. list-table::
-    :header-rows: 1
-    :widths: 20 80
-
-    * - Type
-      - Description
-    * - ``ARN``
-      - A String type that contains an `Amazon Resource Name (ARN)`_.
-    * - ``Binary``
-      - A String type that contains base-64 encoded binary data.
-    * - ``Bool``
-      - A general boolean type.
-    * - ``Date``
-      - A String type that conforms to the ``datetime`` profile of `ISO 8601`_.
-    * - ``IPAddress``
-      - A String type that conforms to :rfc:`4632`.
-    * - ``Numeric``
-      - A general type for integers and floats.
-    * - ``String``
-      - A general string type.
-    * - ``ArrayOfARN``
-      - An unordered list of ARN types.
-    * - ``ArrayOfBinary``
-      - An unordered list of Binary types.
-    * - ``ArrayOfBool``
-      - An unordered list of Bool types.
-    * - ``ArrayOfDate``
-      - An unordered list of Date types.
-    * - ``ArrayOfIPAddress``
-      - An unordered list of IPAddress types.
-    * - ``ArrayOfNumeric``
-      - An unordered list of Numeric types.
-    * - ``ArrayOfString``
-      - An unordered list of String types.
-
 
 .. smithy-trait:: aws.iam#conditionKeys
 .. _aws.iam#conditionKeys-trait:
@@ -507,11 +475,11 @@ Value type
     ``list<string>``
 
 Condition keys derived automatically can be applied to a resource or operation
-explicitly. Condition keys applied this way MUST be either inferred or
-explicitly defined via the :ref:`aws.iam#defineConditionKeys-trait` trait.
+explicitly. Condition keys applied this way MUST be either :ref:`inferred <deriving-condition-keys>`
+or explicitly defined via the :ref:`aws.iam#defineConditionKeys-trait` trait.
 
 The following example's ``MyResource`` resource has the
-``myservice:MyResourceFoo`` and  ``otherservice:Bar`` condition keys. The
+``myservice:MyResourceFoo`` and  ``myservice:Bar`` condition keys. The
 ``MyOperation`` operation has the ``aws:region`` condition key.
 
 .. code-block:: smithy
@@ -525,13 +493,13 @@ The following example's ``MyResource`` resource has the
     use aws.iam#conditionKeys
 
     @service(sdkId: "My Value", arnNamespace: "myservice")
-    @defineConditionKeys("otherservice:Bar": { type: "String" })
+    @defineConditionKeys("myservice:Bar": { type: "String" })
     service MyService {
         version: "2017-02-11"
         resources: [MyResource]
     }
 
-    @conditionKeys(["otherservice:Bar"])
+    @conditionKeys(["myservice:Bar"])
     resource MyResource {
         identifiers: {foo: String}
         operations: [MyOperation]
@@ -546,85 +514,6 @@ The following example's ``MyResource`` resource has the
     without being defined on the service.
 
 
-.. smithy-trait:: aws.iam#disableConditionKeyInference
-.. _aws.iam#disableConditionKeyInference-trait:
-
-``aws.iam#disableConditionKeyInference`` trait
-==============================================
-
-Summary
-    Declares that the condition keys of a resource should not be inferred.
-Trait selector
-    ``:test(service, resource)``
-Value type
-    Annotation trait
-
-When a service is marked with the ``aws.iam#disableConditionKeyInference``
-trait, all the resources bound to the service will not have condition
-keys automatically inferred from its identifiers and the identifiers
-of its ancestors.
-
-The following example shows resources ``MyResource1`` and ``MyResource2``
-have had condition key inference disabled because they are bound to a
-service marked with ``aws.iam#disableConditionKeyInference`` trait.
-
-.. code-block:: smithy
-
-    $version: "2"
-
-    namespace smithy.example
-
-    use aws.api#service
-    use aws.iam#disableConditionKeyInference
-
-    @service(sdkId: "My Value", arnNamespace: "myservice")
-    @disableConditionKeyInference
-    service MyService {
-        version: "2017-02-11"
-        resources: [MyResource1, MyResource2]
-    }
-
-    resource MyResource1 {
-        identifiers: {
-            foo: String
-        }
-    }
-
-    resource MyResource2 {
-        identifiers: {
-            foo: String
-        }
-    }
-
-A resource marked with the ``aws.iam#disableConditionKeyInference`` trait will
-not have its condition keys automatically inferred from its identifiers and
-the identifiers of its ancestors (if present.)
-
-The following example shows a resource, ``MyResource``, that has had its
-condition key inference disabled.
-
-.. code-block:: smithy
-
-    $version: "2"
-
-    namespace smithy.example
-
-    use aws.api#service
-    use aws.iam#disableConditionKeyInference
-
-    @service(sdkId: "My Value", arnNamespace: "myservice")
-    service MyService {
-        version: "2017-02-11"
-        resources: [MyResource]
-    }
-
-    @disableConditionKeyInference
-    resource MyResource {
-        identifiers: {
-            foo: String
-            bar: String
-        }
-    }
 
 .. smithy-trait:: aws.iam#serviceResolvedConditionKeys
 .. _aws.iam#serviceResolvedConditionKeys-trait:
@@ -642,8 +531,8 @@ Value type
 
 All condition keys defined with the ``serviceResolvedConditionKeys`` trait
 MUST also be defined via the :ref:`aws.iam#defineConditionKeys-trait` trait.
-Derived resource condition keys MUST NOT be included
-with the ``serviceResolvedConditionKeys`` trait.
+:ref:`Inferred resource condition keys <deriving-condition-keys>` MUST NOT be
+included with the ``serviceResolvedConditionKeys`` trait.
 
 The following example defines two service-specific condition keys:
 
@@ -715,9 +604,134 @@ explicitly binds ``ActionContextKey1`` to the field ``key``.
     }
 
 
+.. smithy-trait:: aws.iam#disableConditionKeyInference
+.. _aws.iam#disableConditionKeyInference-trait:
+
+``aws.iam#disableConditionKeyInference`` trait
+==============================================
+
+Summary
+    Declares that the condition keys of a resource should not be
+    :ref:`inferred <deriving-condition-keys>`.
+Trait selector
+    ``:test(service, resource)``
+Value type
+    Annotation trait
+
+When a service is marked with the ``aws.iam#disableConditionKeyInference``
+trait, all the resources bound to the service will not have condition
+keys automatically inferred from its identifiers and the identifiers
+of its ancestors.
+
+The following example shows resources ``MyResource1`` and ``MyResource2``
+have had condition key inference disabled because they are bound to a
+service marked with ``aws.iam#disableConditionKeyInference`` trait.
+
+.. code-block:: smithy
+
+    $version: "2"
+
+    namespace smithy.example
+
+    use aws.api#service
+    use aws.iam#disableConditionKeyInference
+
+    @service(sdkId: "My Value", arnNamespace: "myservice")
+    @disableConditionKeyInference
+    service MyService {
+        version: "2017-02-11"
+        resources: [MyResource1, MyResource2]
+    }
+
+    resource MyResource1 {
+        identifiers: {
+            foo: String
+        }
+    }
+
+    resource MyResource2 {
+        identifiers: {
+            foo: String
+        }
+    }
+
+A resource marked with the ``aws.iam#disableConditionKeyInference`` trait will
+not have its condition keys automatically inferred from its identifiers and
+the identifiers of its ancestors. if present.
+
+The following example shows a resource, ``MyResource``, that has condition key
+inference disabled.
+
+.. code-block:: smithy
+
+    $version: "2"
+
+    namespace smithy.example
+
+    use aws.api#service
+    use aws.iam#disableConditionKeyInference
+
+    @service(sdkId: "My Value", arnNamespace: "myservice")
+    service MyService {
+        version: "2017-02-11"
+        resources: [MyResource]
+    }
+
+    @disableConditionKeyInference
+    resource MyResource {
+        identifiers: {
+            foo: String
+            bar: String
+        }
+    }
+
+
+.. _condition-key-types:
+
+Condition Key Types
+=======================
+
+The following table describes the available types a condition key can have.
+Condition keys in IAM policies can be evaluated with `condition operators`_.
+
+.. list-table::
+    :header-rows: 1
+    :widths: 20 80
+
+    * - Type
+      - Description
+    * - ``ARN``
+      - A String type that contains an `Amazon Resource Name (ARN)`_.
+    * - ``Binary``
+      - A String type that contains base-64 encoded binary data.
+    * - ``Bool``
+      - A general boolean type.
+    * - ``Date``
+      - A String type that conforms to the ``datetime`` profile of `ISO 8601`_.
+    * - ``IPAddress``
+      - A String type that conforms to :rfc:`4632`.
+    * - ``Numeric``
+      - A general type for integers and floats.
+    * - ``String``
+      - A general string type.
+    * - ``ArrayOfARN``
+      - An unordered list of ARN types.
+    * - ``ArrayOfBinary``
+      - An unordered list of Binary types.
+    * - ``ArrayOfBool``
+      - An unordered list of Bool types.
+    * - ``ArrayOfDate``
+      - An unordered list of Date types.
+    * - ``ArrayOfIPAddress``
+      - An unordered list of IPAddress types.
+    * - ``ArrayOfNumeric``
+      - An unordered list of Numeric types.
+    * - ``ArrayOfString``
+      - An unordered list of String types.
+
 .. _deriving-condition-keys:
 
-Deriving Condition Keys
+Deriving condition keys
 =======================
 
 Smithy will automatically derive condition key information for a service, as
@@ -747,13 +761,13 @@ Given the following model,
     use aws.iam#iamResource
 
     @service(sdkId: "My Value", arnNamespace: "myservice")
-    @defineConditionKeys("otherservice:Bar": { type: "String" })
+    @defineConditionKeys("myservice:Bar": { type: "String" })
     service MyService {
         version: "2017-02-11"
         resources: [MyResource]
     }
 
-    @conditionKeys(["otherservice:Bar"])
+    @conditionKeys(["myservice:Bar"])
     resource MyResource {
         identifiers: {foo: String}
         operations: [MyOperation]
@@ -792,11 +806,11 @@ The computed condition keys for the service are:
     * - ``MyResource``
       -
           * ``myservice:MyResourceFoo``
-          * ``otherservice:Bar``
+          * ``myservice:Bar``
     * - ``InnerResource``
       -
           * ``myservice:MyResourceFoo``
-          * ``otherservice:Bar``
+          * ``myservice:Bar``
           * ``myservice:InnerResourceYum``
     * - ``MyDetachedResource``
       - None
@@ -807,7 +821,6 @@ The computed condition keys for the service are:
       -
           * ``aws:region``
 
-
 .. _AWS Identity and Access Management: https://aws.amazon.com/iam/
 .. _Condition keys: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_condition-keys.html
 .. _Actions: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html
diff --git a/docs/source-2.0/guides/generating-cloudformation-resources.rst b/docs/source-2.0/guides/generating-cloudformation-resources.rst
index 412bfaee5..2953b2d22 100644
--- a/docs/source-2.0/guides/generating-cloudformation-resources.rst
+++ b/docs/source-2.0/guides/generating-cloudformation-resources.rst
@@ -292,9 +292,10 @@ disableHandlerPermissionGeneration (``boolean``)
     Sets whether to disable generating ``handler`` ``permission`` lists for
     Resource Schemas. By default, handler permissions lists are automatically
     added to schemas based on :ref:`lifecycle-operations` and permissions
-    listed in the :ref:`aws.iam#requiredActions-trait` on the operation. See
-    `the handlers section`_ in the CloudFormation Resource Schemas
-    documentation for more information.
+    listed in the :ref:`requiredActions property of the aws.iam#iamAction
+    trait <aws.iam#iamAction-trait>` on the operation. See `the handlers
+    section`_ in the CloudFormation Resource Schemas documentation for more
+    information.
 
     .. code-block:: json
 
@@ -312,7 +313,8 @@ disableHandlerPermissionGeneration (``boolean``)
     CloudFormation Resource Schema handlers determine what provisioning actions
     can be performed for the resource. The handlers utilized by CloudFormation
     align with some :ref:`lifecycle-operations`. These operations can also
-    define other permission actions required to invoke them with the :ref:`aws.iam#requiredActions-trait`.
+    define other permission actions required to invoke them with the :ref:`requiredActions
+    property of the aws.iam#iamAction trait <aws.iam#iamAction-trait>`
 
     When handler permission generation is enabled, all the actions required to
     invoke the operations related to the handler, including the actions for the
diff --git a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/HandlerPermissionMapper.java b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/HandlerPermissionMapper.java
index 4a671f949..a32bbc516 100644
--- a/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/HandlerPermissionMapper.java
+++ b/smithy-aws-cloudformation/src/main/java/software/amazon/smithy/aws/cloudformation/schema/fromsmithy/mappers/HandlerPermissionMapper.java
@@ -23,7 +23,6 @@ import software.amazon.smithy.aws.cloudformation.schema.fromsmithy.Context;
 import software.amazon.smithy.aws.cloudformation.schema.model.Handler;
 import software.amazon.smithy.aws.cloudformation.schema.model.ResourceSchema;
 import software.amazon.smithy.aws.iam.traits.IamActionTrait;
-import software.amazon.smithy.aws.iam.traits.RequiredActionsTrait;
 import software.amazon.smithy.aws.traits.ServiceTrait;
 import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.shapes.OperationShape;
@@ -31,7 +30,6 @@ import software.amazon.smithy.model.shapes.ResourceShape;
 import software.amazon.smithy.model.shapes.ServiceShape;
 import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.NoReplaceTrait;
-import software.amazon.smithy.utils.ListUtils;
 import software.amazon.smithy.utils.SetUtils;
 import software.amazon.smithy.utils.SmithyInternalApi;
 
@@ -114,11 +112,7 @@ public final class HandlerPermissionMapper implements CfnMapper {
         permissionsEntries.add(operationActionName);
 
         // Add all the other required actions for the operation.
-        permissionsEntries.addAll(operation.getTrait(IamActionTrait.class)
-                .map(IamActionTrait::getRequiredActions)
-                .orElseGet(() -> operation.getTrait(RequiredActionsTrait.class)
-                        .map(RequiredActionsTrait::getValues)
-                        .orElse(ListUtils.of())));
+        permissionsEntries.addAll(IamActionTrait.resolveRequiredActions(operation));
         return permissionsEntries;
     }
 }
diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartition.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartition.java
index c04116f7e..c4d93d5cc 100644
--- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartition.java
+++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartition.java
@@ -5,6 +5,7 @@
 
 package software.amazon.smithy.rulesengine.aws.language.functions;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -24,6 +25,7 @@ import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.
 import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.FunctionNode;
 import software.amazon.smithy.rulesengine.language.syntax.expressions.functions.LibraryFunction;
 import software.amazon.smithy.utils.MapUtils;
+import software.amazon.smithy.utils.SmithyInternalApi;
 import software.amazon.smithy.utils.SmithyUnstableApi;
 
 /**
@@ -41,13 +43,39 @@ public final class AwsPartition extends LibraryFunction {
     public static final Identifier INFERRED = Identifier.of("inferred");
 
     private static final Definition DEFINITION = new Definition();
-    private static final List<Partition> PARTITIONS;
+
+    // The following are mutable to allow for overriding the contents
+    // of the PARTITIONS list for test use cases. They MUST NOT have
+    // contents exposed directly, only through copies as is done in
+    // the `evaluate` method below.
+    private static final List<Partition> PARTITIONS = new ArrayList<>();
     private static final Map<String, Partition> REGION_MAP = new HashMap<>();
 
     static {
-        PARTITIONS = Partitions.fromNode(Node.parse(Partitions.class.getResourceAsStream("partitions.json")))
-                .getPartitions();
+        PARTITIONS.addAll(Partitions.fromNode(
+                        Node.parse(Partitions.class.getResourceAsStream("partitions.json")))
+                .getPartitions());
+        initializeRegionMap();
+    }
+
+    private AwsPartition(FunctionNode functionNode) {
+        super(DEFINITION, functionNode);
+    }
 
+    /**
+     * Overrides the partitions provided by default.
+     *
+     * @param partitions A list of partitions to set.
+     */
+    @SmithyInternalApi
+    public static void overridePartitions(Partitions partitions) {
+        PARTITIONS.clear();
+        PARTITIONS.addAll(partitions.getPartitions());
+        initializeRegionMap();
+    }
+
+    private static void initializeRegionMap() {
+        REGION_MAP.clear();
         for (Partition partition : PARTITIONS) {
             for (String region : partition.getRegions().keySet()) {
                 REGION_MAP.put(region, partition);
@@ -55,10 +83,6 @@ public final class AwsPartition extends LibraryFunction {
         }
     }
 
-    private AwsPartition(FunctionNode functionNode) {
-        super(DEFINITION, functionNode);
-    }
-
     /**
      * Gets the {@link FunctionDefinition} implementation.
      *
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionNameTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionNameTrait.java
index fcf491aca..c0afede91 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionNameTrait.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionNameTrait.java
@@ -10,6 +10,12 @@ import software.amazon.smithy.model.SourceLocation;
 import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.StringTrait;
 
+/**
+ * Use the {@code @iamAction} trait's {@code name} property instead.
+ *
+ * @deprecated As of release 1.44.0, replaced by {@link IamActionTrait#resolveActionName}.
+ */
+@Deprecated
 public final class ActionNameTrait extends StringTrait {
 
     public static final ShapeId ID = ShapeId.from("aws.iam#actionName");
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTrait.java
index c818afdb1..331357e53 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTrait.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTrait.java
@@ -20,8 +20,11 @@ import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.StringTrait;
 
 /**
- * Defines the description of what providing access to an operation entails.
+ * Use the {@code @iamAction} trait's {@code documentation} property instead.
+ *
+ * @deprecated As of release 1.44.0, replaced by {@link IamActionTrait#resolveActionDocumentation}.
  */
+@Deprecated
 public final class ActionPermissionDescriptionTrait extends StringTrait {
     public static final ShapeId ID = ShapeId.from("aws.iam#actionPermissionDescription");
 
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionTrait.java
index 67377e186..63a81ed1f 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionTrait.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionTrait.java
@@ -19,11 +19,15 @@ import java.util.List;
 import java.util.Optional;
 import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.model.node.NodeMapper;
+import software.amazon.smithy.model.shapes.OperationShape;
 import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.AbstractTrait;
 import software.amazon.smithy.model.traits.AbstractTraitBuilder;
+import software.amazon.smithy.model.traits.DocumentationTrait;
 import software.amazon.smithy.model.traits.Trait;
 import software.amazon.smithy.utils.BuilderRef;
+import software.amazon.smithy.utils.FunctionalUtils;
+import software.amazon.smithy.utils.ListUtils;
 import software.amazon.smithy.utils.SmithyBuilder;
 import software.amazon.smithy.utils.ToSmithyBuilder;
 
@@ -60,6 +64,27 @@ public final class IamActionTrait extends AbstractTrait
         return Optional.ofNullable(name);
     }
 
+    /**
+     * Resolves the IAM action name for the given operation. Uses the following
+     * resolution order:
+     *
+     * <ol>
+     *     <li>Value of the {@code @iamAction} trait's {@code name} property</li>
+     *     <li>Value of the {@code @actionName} trait</li>
+     *     <li>The operation's name</li>
+     * </ol>
+     *
+     * @param operation the operation to resolve a name for.
+     * @return The resolved action name.
+     */
+    @SuppressWarnings("deprecation")
+    public static String resolveActionName(OperationShape operation) {
+        return operation.getTrait(IamActionTrait.class).flatMap(IamActionTrait::getName)
+                .orElseGet(() -> operation.getTrait(ActionNameTrait.class)
+                        .map(ActionNameTrait::getValue)
+                        .orElseGet(() -> operation.getId().getName()));
+    }
+
     /**
      * Gets the description of what granting the user permission to
      * invoke an operation would entail.
@@ -70,6 +95,29 @@ public final class IamActionTrait extends AbstractTrait
         return Optional.ofNullable(documentation);
     }
 
+    /**
+     * Resolves the IAM action documentation for the given operation. Uses the following
+     * resolution order:
+     *
+     * <ol>
+     *     <li>Value of the {@code @iamAction} trait's {@code documentation} property</li>
+     *     <li>Value of the {@code @actionPermissionDescription} trait</li>
+     *     <li>Value of the {@code @documentation} trait</li>
+     * </ol>
+     *
+     * @param operation the operation to resolve documentation for.
+     * @return The resolved action documentation.
+     */
+    @SuppressWarnings("deprecation")
+    public static String resolveActionDocumentation(OperationShape operation) {
+        return operation.getTrait(IamActionTrait.class).flatMap(IamActionTrait::getDocumentation)
+                .orElseGet(() -> operation.getTrait(ActionPermissionDescriptionTrait.class)
+                        .map(ActionPermissionDescriptionTrait::getValue)
+                        .orElseGet(() -> operation.getTrait(DocumentationTrait.class)
+                                .map(DocumentationTrait::getValue)
+                                .orElse(null)));
+    }
+
     /**
      * Gets the relative URL path for the action within a set of
      * IAM-related documentation.
@@ -90,6 +138,28 @@ public final class IamActionTrait extends AbstractTrait
         return requiredActions;
     }
 
+    /**
+     * Resolves the IAM action required actions for the given operation. Uses the following
+     * resolution order:
+     *
+     * <ol>
+     *     <li>Value of the {@code @iamAction} trait's {@code requiredActions} property</li>
+     *     <li>Value of the {@code @requiredActions} trait</li>
+     *     <li>An empty list.</li>
+     * </ol>
+     *
+     * @param operation the operation to resolve required actions for.
+     * @return The resolved required actions.
+     */
+    @SuppressWarnings("deprecation")
+    public static List<String> resolveRequiredActions(OperationShape operation) {
+        return operation.getTrait(IamActionTrait.class).map(IamActionTrait::getRequiredActions)
+                .filter(FunctionalUtils.not(List::isEmpty))
+                .orElseGet(() -> operation.getTrait(RequiredActionsTrait.class)
+                        .map(RequiredActionsTrait::getValues)
+                        .orElse(ListUtils.of()));
+    }
+
     /**
      * Gets the resources an IAM action can be authorized against.
      *
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionValidator.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionValidator.java
index b04a2a268..9c5de2802 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionValidator.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamActionValidator.java
@@ -32,6 +32,7 @@ public final class IamActionValidator extends AbstractValidator {
         return events;
     }
 
+    @SuppressWarnings("deprecation")
     private List<ValidationEvent> validateDuplicateTraits(OperationShape operation, IamActionTrait trait) {
         List<ValidationEvent> events = new ArrayList<>();
         if (operation.hasTrait(ActionNameTrait.ID) && trait.getName().isPresent()) {
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTrait.java
index 1787b320d..74e68fab6 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTrait.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/IamResourceTrait.java
@@ -18,6 +18,7 @@ package software.amazon.smithy.aws.iam.traits;
 import java.util.Optional;
 import software.amazon.smithy.model.node.Node;
 import software.amazon.smithy.model.node.NodeMapper;
+import software.amazon.smithy.model.shapes.ResourceShape;
 import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.AbstractTrait;
 import software.amazon.smithy.model.traits.AbstractTraitBuilder;
@@ -52,6 +53,26 @@ public final class IamResourceTrait extends AbstractTrait
         return Optional.ofNullable(name);
     }
 
+
+
+    /**
+     * Resolves the IAM resource name for the given resource. Uses the following
+     * resolution order:
+     *
+     * <ol>
+     *     <li>Value of the {@code @iamResource} trait's {@code name} property</li>
+     *     <li>The resource's name</li>
+     * </ol>
+     *
+     * @param resource the resource to resolve a name for.
+     * @return The resolved resource name.
+     */
+    public static String resolveResourceName(ResourceShape resource) {
+        return resource.getTrait(IamResourceTrait.class)
+                .flatMap(IamResourceTrait::getName)
+                .orElse(resource.getId().getName());
+    }
+
     /**
      * Get the relative URL path that defines more information about the resource
      * within a set of IAM-related documentation.
diff --git a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTrait.java b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTrait.java
index 4a434b1b7..f008b5eae 100644
--- a/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTrait.java
+++ b/smithy-aws-iam-traits/src/main/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTrait.java
@@ -22,6 +22,12 @@ import software.amazon.smithy.model.shapes.ShapeId;
 import software.amazon.smithy.model.traits.StringListTrait;
 import software.amazon.smithy.utils.ToSmithyBuilder;
 
+/**
+ * Use the {@code @iamAction} trait's {@code requiredActions} property instead.
+ *
+ * @deprecated As of release 1.44.0, replaced by {@link IamActionTrait#resolveRequiredActions}.
+ */
+@Deprecated
 public final class RequiredActionsTrait extends StringListTrait implements ToSmithyBuilder<RequiredActionsTrait> {
     public static final ShapeId ID = ShapeId.from("aws.iam#requiredActions");
 
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/loader/Version.java b/smithy-model/src/main/java/software/amazon/smithy/model/loader/Version.java
index a9de96dcb..9f5367902 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/loader/Version.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/loader/Version.java
@@ -171,7 +171,7 @@ enum Version {
         }
 
         @Override
-        @SuppressWarnings("deprecated")
+        @SuppressWarnings("deprecation")
         ValidationEvent validateVersionedTrait(ShapeId target, ShapeId traitId, Node value) {
             if (traitId.equals(BoxTrait.ID)) {
                 return ValidationEvent.builder()


Test patch:
diff --git a/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionFunctionTest.java b/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionFunctionTest.java
deleted file mode 100644
index 089164f93..000000000
--- a/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionFunctionTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package software.amazon.smithy.rulesengine.aws.language.functions;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.not;
-
-import org.junit.jupiter.api.Test;
-import software.amazon.smithy.rulesengine.language.evaluation.RuleEvaluator;
-import software.amazon.smithy.rulesengine.language.evaluation.value.RecordValue;
-import software.amazon.smithy.rulesengine.language.syntax.expressions.Expression;
-
-public class AwsPartitionFunctionTest {
-    @Test
-    public void eval() {
-        RecordValue result = evalWithRegion("us-west-2");
-
-        assertThat(result.get(AwsPartition.DNS_SUFFIX).expectStringValue().getValue(), not(equalTo("")));
-        assertThat(result.get(AwsPartition.DUAL_STACK_DNS_SUFFIX).expectStringValue().getValue(), not(equalTo("")));
-        assertThat(result.get(AwsPartition.SUPPORTS_FIPS).expectBooleanValue().getValue(), equalTo(true));
-        assertThat(result.get(AwsPartition.SUPPORTS_DUAL_STACK).expectBooleanValue().getValue(), equalTo(true));
-        assertThat(result.get(AwsPartition.IMPLICIT_GLOBAL_REGION).expectStringValue().getValue(), not(equalTo("")));
-    }
-
-    @Test
-    public void eval_enumeratedRegion_inferredIsFalse() {
-        RecordValue result = evalWithRegion("us-west-1");
-
-        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(false));
-    }
-
-    @Test
-    public void eval_regionNotEnumerated_inferredIsTrue() {
-        RecordValue result = evalWithRegion("us-west-3");
-
-        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(true));
-    }
-
-
-    private RecordValue evalWithRegion(String region) {
-        AwsPartition fn = AwsPartition.ofExpressions(Expression.of(region));
-        return fn.accept(new RuleEvaluator()).expectRecordValue();
-    }
-}
diff --git a/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionTest.java b/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionTest.java
new file mode 100644
index 000000000..73a57e37e
--- /dev/null
+++ b/smithy-aws-endpoints/src/test/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsPartitionTest.java
@@ -0,0 +1,75 @@
+package software.amazon.smithy.rulesengine.aws.language.functions;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.not;
+
+import org.junit.jupiter.api.Test;
+import software.amazon.smithy.model.node.Node;
+import software.amazon.smithy.rulesengine.aws.language.functions.partition.Partition;
+import software.amazon.smithy.rulesengine.aws.language.functions.partition.PartitionOutputs;
+import software.amazon.smithy.rulesengine.aws.language.functions.partition.Partitions;
+import software.amazon.smithy.rulesengine.language.evaluation.RuleEvaluator;
+import software.amazon.smithy.rulesengine.language.evaluation.value.RecordValue;
+import software.amazon.smithy.rulesengine.language.syntax.expressions.Expression;
+
+public class AwsPartitionTest {
+    @Test
+    public void eval() {
+        RecordValue result = evalWithRegion("us-west-2");
+
+        assertThat(result.get(AwsPartition.DNS_SUFFIX).expectStringValue().getValue(), not(equalTo("")));
+        assertThat(result.get(AwsPartition.DUAL_STACK_DNS_SUFFIX).expectStringValue().getValue(), not(equalTo("")));
+        assertThat(result.get(AwsPartition.SUPPORTS_FIPS).expectBooleanValue().getValue(), equalTo(true));
+        assertThat(result.get(AwsPartition.SUPPORTS_DUAL_STACK).expectBooleanValue().getValue(), equalTo(true));
+        assertThat(result.get(AwsPartition.IMPLICIT_GLOBAL_REGION).expectStringValue().getValue(), not(equalTo("")));
+    }
+
+    @Test
+    public void enumeratedRegionIsNotInferred() {
+        RecordValue result = evalWithRegion("us-west-1");
+
+        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(false));
+    }
+
+    @Test
+    public void regionNotEnumeratedIsInferred() {
+        RecordValue result = evalWithRegion("us-west-3");
+
+        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(true));
+    }
+
+    @Test
+    public void overridesPartitions() {
+        RecordValue result = evalWithRegion("us-west-1");
+        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(false));
+
+        // Remove the enumerated regions, so the same region is now inferred.
+        AwsPartition.overridePartitions(Partitions.builder()
+                .addPartition(Partition.builder()
+                        .id("aws")
+                        .regionRegex("^(us|eu|ap|sa|ca|me|af)-\\w+-\\d+$")
+                        .outputs(PartitionOutputs.builder()
+                                .name("aws")
+                                .dnsSuffix("amazonaws.com")
+                                .dualStackDnsSuffix("api.aws")
+                                .supportsFips(true)
+                                .supportsDualStack(true)
+                                .implicitGlobalRegion("us-east-1")
+                                .build())
+                        .build())
+                .build());
+
+        result = evalWithRegion("us-west-1");
+        assertThat(result.get(AwsPartition.INFERRED).expectBooleanValue().getValue(), equalTo(true));
+
+        // Set the partitions back to what they were.
+        AwsPartition.overridePartitions(Partitions.fromNode(
+                        Node.parse(Partitions.class.getResourceAsStream("partitions.json"))));
+    }
+
+    private RecordValue evalWithRegion(String region) {
+        AwsPartition fn = AwsPartition.ofExpressions(Expression.of(region));
+        return fn.accept(new RuleEvaluator()).expectRecordValue();
+    }
+}
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionNameTraitTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionNameTraitTest.java
index 0b39e3b1c..274ad449b 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionNameTraitTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionNameTraitTest.java
@@ -5,16 +5,17 @@
 
 package software.amazon.smithy.aws.iam.traits;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.model.Model;
 import software.amazon.smithy.model.shapes.Shape;
 import software.amazon.smithy.model.shapes.ShapeId;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-
 public class ActionNameTraitTest {
     @Test
+    @SuppressWarnings("deprecation")
     public void loadsFromModel() {
         Model result = Model.assembler()
                 .discoverModels(getClass().getClassLoader())
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTraitTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTraitTest.java
index 426e9cada..5ab161cec 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTraitTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/ActionPermissionDescriptionTraitTest.java
@@ -28,6 +28,7 @@ import software.amazon.smithy.model.traits.TraitFactory;
 
 public class ActionPermissionDescriptionTraitTest {
     @Test
+    @SuppressWarnings("deprecation")
     public void createsTrait() {
         Node node = Node.from("Foo baz bar");
         TraitFactory provider = TraitFactory.createServiceFactory();
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamActionTraitTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamActionTraitTest.java
index e0cad6b3e..d4f40f661 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamActionTraitTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamActionTraitTest.java
@@ -18,15 +18,21 @@ package software.amazon.smithy.aws.iam.traits;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.empty;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.shapes.OperationShape;
 import software.amazon.smithy.model.shapes.Shape;
 import software.amazon.smithy.model.shapes.ShapeId;
+import software.amazon.smithy.model.traits.DocumentationTrait;
 
 public class IamActionTraitTest {
+    private static final ShapeId ID = ShapeId.from("smithy.example#Foo");
+
     @Test
     public void loadsFromModel() {
         Model result = Model.assembler()
@@ -35,7 +41,7 @@ public class IamActionTraitTest {
                 .assemble()
                 .unwrap();
 
-        Shape fooOperation = result.expectShape(ShapeId.from("smithy.example#Foo"));
+        Shape fooOperation = result.expectShape(ID);
 
         assertTrue(fooOperation.hasTrait(IamActionTrait.class));
         IamActionTrait trait = fooOperation.expectTrait(IamActionTrait.class);
@@ -54,4 +60,99 @@ public class IamActionTraitTest {
         assertTrue(actionResources.getOptional().containsKey("baz"));
         assertTrue(actionResources.getOptional().get("baz").getConditionKeys().isEmpty());
     }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void prefersIamActionTraitName() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(IamActionTrait.builder().name("ThisOne").build())
+                .addTrait(new ActionNameTrait("Unused"))
+                .build();
+
+        assertEquals("ThisOne", IamActionTrait.resolveActionName(op));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void usesDeprecatedActionNameTrait() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(new ActionNameTrait("ThisOne"))
+                .build();
+
+        assertEquals("ThisOne", IamActionTrait.resolveActionName(op));
+    }
+
+    @Test
+    public void defaultsToOperationName() {
+        OperationShape op = OperationShape.builder().id(ID).build();
+
+        assertEquals("Foo", IamActionTrait.resolveActionName(op));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void prefersIamActionTraitDocumentation() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(IamActionTrait.builder().documentation("ThisOne").build())
+                .addTrait(new ActionPermissionDescriptionTrait("Unused"))
+                .addTrait(new DocumentationTrait("Unused"))
+                .build();
+
+        assertEquals("ThisOne", IamActionTrait.resolveActionDocumentation(op));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void usesDeprecatedActionPermissionDescriptionTrait() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(new ActionPermissionDescriptionTrait("ThisOne"))
+                .addTrait(new DocumentationTrait("Unused"))
+                .build();
+
+        assertEquals("ThisOne", IamActionTrait.resolveActionDocumentation(op));
+    }
+
+    @Test
+    public void usesDocumentationTrait() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(new DocumentationTrait("ThisOne"))
+                .build();
+
+        assertEquals("ThisOne", IamActionTrait.resolveActionDocumentation(op));
+    }
+
+    @Test
+    public void defaultsToNoDocumentation() {
+        OperationShape op = OperationShape.builder().id(ID).build();
+
+        assertNull(IamActionTrait.resolveActionDocumentation(op));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void prefersIamActionTraitRequiredActions() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(IamActionTrait.builder().addRequiredAction("ThisOne").build())
+                .addTrait(new ActionNameTrait("Unused"))
+                .build();
+
+        assertThat(IamActionTrait.resolveRequiredActions(op), contains("ThisOne"));
+    }
+
+    @Test
+    @SuppressWarnings("deprecation")
+    public void usesDeprecatedRequiredActionsTrait() {
+        OperationShape op = OperationShape.builder().id(ID)
+                .addTrait(RequiredActionsTrait.builder().addValue("ThisOne").build())
+                .build();
+
+        assertThat(IamActionTrait.resolveRequiredActions(op), contains("ThisOne"));
+    }
+
+    @Test
+    public void defaultsToEmptyRequiredActions() {
+        OperationShape op = OperationShape.builder().id(ID).build();
+
+        assertThat(IamActionTrait.resolveRequiredActions(op), empty());
+    }
 }
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitTest.java
index dc03eb967..eceacac1a 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/IamResourceTraitTest.java
@@ -21,10 +21,13 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import org.junit.jupiter.api.Test;
 import software.amazon.smithy.model.Model;
+import software.amazon.smithy.model.shapes.ResourceShape;
 import software.amazon.smithy.model.shapes.Shape;
 import software.amazon.smithy.model.shapes.ShapeId;
 
 public class IamResourceTraitTest {
+    private static final ShapeId ID = ShapeId.from("smithy.example#SuperResource");
+
     @Test
     public void loadsFromModel() {
         Model result = Model.assembler()
@@ -33,11 +36,27 @@ public class IamResourceTraitTest {
                 .assemble()
                 .unwrap();
 
-        Shape superResource = result.expectShape(ShapeId.from("smithy.example#SuperResource"));
+        Shape superResource = result.expectShape(ID);
 
         assertTrue(superResource.hasTrait(IamResourceTrait.class));
         assertEquals(superResource.expectTrait(IamResourceTrait.class).getName().get(), "super");
         assertEquals(superResource.expectTrait(IamResourceTrait.class).getRelativeDocumentation().get(), "API-Super.html");
         assertFalse(superResource.expectTrait(IamResourceTrait.class).isDisableConditionKeyInheritance());
     }
+
+    @Test
+    public void prefersIamResourceTraitName() {
+        ResourceShape resource = ResourceShape.builder().id(ID)
+                .addTrait(IamResourceTrait.builder().name("ThisOne").build())
+                .build();
+
+        assertEquals("ThisOne", IamResourceTrait.resolveResourceName(resource));
+    }
+
+    @Test
+    public void defaultsToResourceName() {
+        ResourceShape resource = ResourceShape.builder().id(ID).build();
+
+        assertEquals("SuperResource", IamResourceTrait.resolveResourceName(resource));
+    }
 }
diff --git a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTraitTest.java b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTraitTest.java
index aba961b71..d4b2569d2 100644
--- a/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTraitTest.java
+++ b/smithy-aws-iam-traits/src/test/java/software/amazon/smithy/aws/iam/traits/RequiredActionsTraitTest.java
@@ -26,6 +26,7 @@ import software.amazon.smithy.model.shapes.ShapeId;
 
 public class RequiredActionsTraitTest {
     @Test
+    @SuppressWarnings("deprecation")
     public void loadsFromModel() {
         Model result = Model.assembler()
                 .discoverModels(getClass().getClassLoader())