Repository: cdklabs/cdk-enterprise-iac (language: python)

Issue:
bug: AddPermissionBoundary does not properly handle roles where the roleName is already specified
### What is the problem?

Today, the `AddPermissionBoundary` aspect always overrides the `RoleName` property, even if it matches the `rolePrefix`. This is because it always resolves to a token, and that token does not match the prefix.

### Reproduction Steps

```
    const rolePrefix = 'Bannana_';
      const roleName = `${rolePrefix}MyRole`;
      new Role(stack, 'Role', {
        roleName,
        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
      });

      Aspects.of(stack).add(
        new AddPermissionBoundary({
          permissionsBoundaryPolicyName: pbName,
          rolePrefix,
        })
      );
      const template = Template.fromStack(stack);
      template.hasResourceProperties('AWS::IAM::Role', {
        RoleName: roleName,
      }); //this will fail.
```

### What did you expect to happen?

We expect the provided `roleName` property to be honored and not replaced with the one generated using the logical name.

### What actually happened?

The logical id is used to generate the actual role name as though no role name was provided

### cdk-enterprise-iac version

0.0.383

### Language

Typescript

### Other information

_No response_


Discussion / hints:

Fix patch:
diff --git a/src/patches/addPermissionsBoundary.ts b/src/patches/addPermissionsBoundary.ts
index 43b5d51..085da07 100644
--- a/src/patches/addPermissionsBoundary.ts
+++ b/src/patches/addPermissionsBoundary.ts
@@ -7,7 +7,6 @@ import {
   CfnInstanceProfile,
   CfnManagedPolicy,
   CfnPolicy,
-  CfnRole,
 } from 'aws-cdk-lib/aws-iam';
 import { IConstruct } from 'constructs';
 import { getResourceId } from '../utils/utils';
@@ -97,34 +96,14 @@ export class AddPermissionBoundary implements IAspect {
           'PermissionsBoundary',
           permissionsBoundaryPolicyArn
         );
-        this.checkAndOverride(
-          node,
-          this._rolePrefix,
-          64,
-          'RoleName',
-          cfnResourceNode.logicalId
-        );
+        const roleName =
+          // eslint-disable-next-line dot-notation
+          cfnResourceNode['cfnProperties'].roleName ||
+          cfnResourceNode.logicalId;
+        this.checkAndOverride(node, this._rolePrefix, 64, 'RoleName', roleName);
       }
     }
-    if (node instanceof CfnRole) {
-      const permissionsBoundaryPolicyArn = Stack.of(node).formatArn({
-        service: 'iam',
-        resource: 'policy',
-        region: '',
-        resourceName: this._permissionsBoundaryPolicyName,
-      });
-      node.addPropertyOverride(
-        'PermissionsBoundary',
-        permissionsBoundaryPolicyArn
-      );
-      this.checkAndOverride(
-        node,
-        this._rolePrefix,
-        64,
-        'RoleName',
-        node.roleName
-      );
-    } else if (node instanceof CfnPolicy) {
+    if (node instanceof CfnPolicy) {
       this.checkAndOverride(
         node,
         this._policyPrefix,


Test patch:
diff --git a/test/patches/addPermissionsBoundary.test.ts b/test/patches/addPermissionsBoundary.test.ts
index eae6740..76c47b4 100644
--- a/test/patches/addPermissionsBoundary.test.ts
+++ b/test/patches/addPermissionsBoundary.test.ts
@@ -120,6 +120,25 @@ describe('Permissions Boundary patch', () => {
         RoleName: `Bananas_Default-${idWithSpaces.replace(/\s/g, '')}-Resource`,
       });
     });
+    test('Role name is not altered if it already complies with naming convention', () => {
+      const rolePrefix = 'Cust_';
+      const roleName = `${rolePrefix}MyRole`;
+      new Role(stack, 'Role', {
+        roleName,
+        assumedBy: new ServicePrincipal('ec2.amazonaws.com'),
+      });
+
+      Aspects.of(stack).add(
+        new AddPermissionBoundary({
+          permissionsBoundaryPolicyName: pbName,
+          rolePrefix,
+        })
+      );
+      const template = Template.fromStack(stack);
+      template.hasResourceProperties('AWS::IAM::Role', {
+        RoleName: roleName,
+      });
+    });
   });
   describe('Policies', () => {
     const policyPrefix = 'POLICY_PREFIX_';