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

Issue:
bug: ConvertInlienPoliciesToManaged breaks dependencies on default policies
### What is the problem?

In some common cases (such as with Pipelines or Lambda Functions), automated conversion of the Policy to a ManagedPolic break existing DependsOn relationships. This causes deployments to fail, as some resources are created before their depended policies. 

### Reproduction Steps

```
    const fn = new Function(stack, 'TestLambda', {
      code: Code.fromInline(`def handler(event, context)\n    print(event)`),
      handler: 'index.handler',
      runtime: Runtime.PYTHON_3_11,
    });
    fn.addToRolePolicy(
      new iam.PolicyStatement({
        actions: ['s3:*'],
        resources: ['*'],
      })
    );
    Aspects.of(app).add(new ConvertInlinePoliciesToManaged());
```

### What did you expect to happen?

The resulting template should maintain the DependsOn referenceing the default policy of the role

### What actually happened?

The DependsOn reference is lost

### cdk-enterprise-iac version

0.0.439

### Language

Typescript, Python

### Other information

_No response_


Discussion / hints:

Fix patch:
diff --git a/src/patches/convertInlinePoliciesToManaged.ts b/src/patches/convertInlinePoliciesToManaged.ts
index a7724d7..29859e7 100644
--- a/src/patches/convertInlinePoliciesToManaged.ts
+++ b/src/patches/convertInlinePoliciesToManaged.ts
@@ -2,8 +2,8 @@
 Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 SPDX-License-Identifier: Apache-2.0
 */
-import { IAspect, aws_iam as iam } from 'aws-cdk-lib';
-import { IConstruct } from 'constructs';
+import { Stack, IAspect, aws_iam as iam } from 'aws-cdk-lib';
+import { Construct, IConstruct } from 'constructs';
 
 /**
  * Patch for turning all Policies into ConvertInlinePoliciesToManaged
@@ -22,17 +22,20 @@ import { IConstruct } from 'constructs';
 export class ConvertInlinePoliciesToManaged implements IAspect {
   public visit(node: IConstruct): void {
     if (node instanceof iam.CfnPolicy) {
-      const logicalId = node.stack.resolve(node.logicalId);
-      const policyDocument = node.stack.resolve(node.policyDocument);
-      const parent = node.node?.scope?.node;
-      parent?.tryRemoveChild(node.node.id);
+      const policy = node as iam.CfnPolicy;
+      const logicalId = Stack.of(policy).resolve(policy.logicalId);
+      const policyDocument = Stack.of(policy).resolve(policy.policyDocument);
+      const parent = policy.node.scope as Construct;
+      parent.node.tryRemoveChild(policy.node.id);
 
-      const resource = new iam.CfnManagedPolicy(node.stack, logicalId, {
-        managedPolicyName: node.stack.resolve(node.policyName),
-        groups: node.groups,
-        roles: node.roles,
+      const resource = new iam.CfnManagedPolicy(parent, logicalId, {
+        managedPolicyName: Stack.of(policy).resolve(policy.policyName),
+        groups: policy.groups,
+        roles: policy.roles,
         policyDocument,
       });
+      resource.overrideLogicalId(logicalId);
+
       const overrides = (node as any).rawOverrides;
       if (overrides?.Properties?.PolicyName) {
         resource.addPropertyOverride(


Test patch:
diff --git a/test/patches/convertInlinePoliciesToManaged.test.ts b/test/patches/convertInlinePoliciesToManaged.test.ts
index 2e6abc7..58d85be 100644
--- a/test/patches/convertInlinePoliciesToManaged.test.ts
+++ b/test/patches/convertInlinePoliciesToManaged.test.ts
@@ -78,6 +78,32 @@ describe('Updating Resource Types', () => {
     );
   });
 
+  test('Function dependencies on policy are maintained', () => {
+    const fn = new Function(stack, 'TestLambda', {
+      code: Code.fromInline(`def handler(event, context)\n    print(event)`),
+      handler: 'index.handler',
+      runtime: Runtime.PYTHON_3_11,
+    });
+    fn.addToRolePolicy(
+      new iam.PolicyStatement({
+        actions: ['s3:*'],
+        resources: ['*'],
+      })
+    );
+
+    Aspects.of(app).add(new ConvertInlinePoliciesToManaged());
+    app.synth();
+    const template = Template.fromStack(stack);
+    let functions = template.findResources('AWS::Lambda::Function');
+    let i = 0;
+    for (const name of Object.keys(functions)) {
+      const deps = functions[name].DependsOn;
+      expect(deps.length).toBe(2);
+      i++;
+    }
+    expect(i).toBeGreaterThan(0);
+  });
+
   test('ManagedPolicy works with resource extractor', () => {
     const extractedStack = new Stack(app, 'TestExtractedStack');
     const resourceTypesToExtract = [