Skip to content

Comments

fix: resolve error when using destinations with per-function IAM roles#13293

Merged
czubocha merged 5 commits intomainfrom
cursor/per-function-iam-destinations-6551
Jan 26, 2026
Merged

fix: resolve error when using destinations with per-function IAM roles#13293
czubocha merged 5 commits intomainfrom
cursor/per-function-iam-destinations-6551

Conversation

@czubocha
Copy link
Contributor

@czubocha czubocha commented Jan 26, 2026

This commit fixes issue #13292 where using Lambda destinations with per-function IAM roles (provider.iam.role.mode: perFunction) caused a TypeError: Cannot read properties of undefined (reading 'Properties').

Root cause:

  • When per-function IAM mode is enabled, the shared IamRoleLambdaExecution role is not created
  • The compileFunctionEventInvokeConfig() method did not detect per-function mode and tried to add destination permissions to the non-existent shared role
  • Additionally, the per-function roles module did not add destination permissions (sqs:SendMessage, sns:Publish, lambda:InvokeFunction, events:PutEvents) for functions using destinations

Changes:

  1. functions.js: Updated hasAccessPoliciesHandledExternally check to detect per-function IAM mode (provider.iam.role.mode === 'perFunction')
  2. roles-per-function-permissions.js: Added applyDestinationPermissions() function that adds the appropriate IAM permissions for Lambda destinations (onSuccess/onFailure) to each function's per-function role

Fixes #13292

Summary by CodeRabbit

  • New Features

    • Per-function IAM mode now properly supports destination permissions for onSuccess/onFailure targets (Lambda, SQS, SNS, EventBridge).
  • Tests

    • Added unit tests validating per-function destination permission generation, ARN resolution, and EventInvokeConfig behavior.
  • Chores

    • Updated CLA verification workflow allowlist.

✏️ Tip: You can customize this high-level summary in your review settings.

This commit fixes issue #13292 where using Lambda destinations with
per-function IAM roles (provider.iam.role.mode: perFunction) caused
a TypeError: Cannot read properties of undefined (reading 'Properties').

Root cause:
- When per-function IAM mode is enabled, the shared IamRoleLambdaExecution
  role is not created
- The compileFunctionEventInvokeConfig() method did not detect per-function
  mode and tried to add destination permissions to the non-existent shared role
- Additionally, the per-function roles module did not add destination
  permissions (sqs:SendMessage, sns:Publish, lambda:InvokeFunction,
  events:PutEvents) for functions using destinations

Changes:
1. functions.js: Updated hasAccessPoliciesHandledExternally check to detect
   per-function IAM mode (provider.iam.role.mode === 'perFunction')
2. roles-per-function-permissions.js: Added applyDestinationPermissions()
   function that adds the appropriate IAM permissions for Lambda destinations
   (onSuccess/onFailure) to each function's per-function role

Fixes #13292
@github-actions
Copy link

github-actions bot commented Jan 26, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Mmarzex
Copy link
Contributor

Mmarzex commented Jan 26, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 26, 2026

📝 Walkthrough

Walkthrough

Treats provider IAM configured with mode: perFunction as externally handled for access policies and adds per-function destination permission generation so destinations produce IAM policy statements instead of relying on shared role resources.

Changes

Cohort / File(s) Summary
Core function compilation
packages/serverless/lib/plugins/aws/package/compile/functions.js
Extend compileFunctionEventInvokeConfig to detect provider.iam.role.mode === 'perFunction' (in addition to custom execution role) and mark access policies as handled externally, skipping ensureTargetExecutionPermission when appropriate.
Per-function permission helpers
packages/serverless/lib/plugins/aws/package/lib/roles-per-function-permissions.js
Add getDestinationAction(), getDestinationArn(), and applyDestinationPermissions() to map destination definitions to IAM actions, resolve ARNs (including Fn::Sub for function refs), and emit destination-based policy statements; integrate into applyPerFunctionPermissions.
Compile unit tests
packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
Add test ensuring per-function IAM mode prevents reliance on shared IamRoleLambdaExecution and that EventInvokeConfig is emitted with correct OnSuccess/OnFailure targets (including function ARN via Fn::GetAtt/Fn::Sub).
Permission unit tests
packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
New tests covering destination permission generation: SQS/SNS/Lambda/EventBridge actions, ARN inference from string patterns, Fn::Sub for function refs, multiple destinations, no-op when none, and erroring on unsupported types.
Workflow allowlist
.github/workflows/check-cla.yml
Added an additional user to the CLA allowlist.

Sequence Diagram(s)

sequenceDiagram
  participant Packager as "Package step"
  participant Compiler as "AwsCompileFunctions"
  participant IAM as "Provider IAM config"
  participant Permissions as "roles-per-function-permissions"
  participant DestService as "Destination service\n(Lambda/SQS/SNS/Events)"

  Packager->>Compiler: compileFunctionEventInvokeConfig(function)
  Compiler->>IAM: read provider.iam.role (mode)
  IAM-->>Compiler: returns mode (e.g., 'perFunction')
  alt mode === 'perFunction' or executionRole present
    Compiler->>Permissions: applyPerFunctionPermissions(function)
    Permissions->>Permissions: applyDestinationPermissions(onSuccess/onFailure)
    Permissions->>DestService: emit policy statement (action, resource/ARN)
    Compiler->>DestService: create EventInvokeConfig with destinations
  else shared-role mode
    Compiler->>Compiler: ensureTargetExecutionPermission(target)
    Compiler->>DestService: create EventInvokeConfig with destinations
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through stacks of code today,
Marked per-function roles to find their way,
Destinations get policies, tidy and true,
ARNs stitched neatly, permissions anew,
I thump my foot — deployments jump hooray! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The CLA workflow update to include 'cursoragent' appears unrelated to the destination and per-function IAM role fix objectives. Remove the unrelated CLA workflow change or justify its inclusion as part of this PR's scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: resolving an error when using Lambda destinations with per-function IAM roles.
Linked Issues check ✅ Passed The PR fully addresses issue #13292 by detecting per-function IAM mode in compileFunctionEventInvokeConfig and adding destination permissions to per-function roles via applyDestinationPermissions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/serverless/lib/plugins/aws/package/lib/roles-per-function-permissions.js (1)

516-595: Fail fast when destination permissions can’t be inferred.

In per-function IAM mode, ensureTargetExecutionPermission is skipped; if getDestinationAction returns null (typo/unsupported type), we now silently skip permissions, which can surface later as runtime delivery failures. Consider throwing (or using throwError) to keep behavior consistent with the shared-role path.

🧩 Proposed fix
-function applyDestinationPermissions({
-  functionObject,
-  policyStatements,
-  serverless,
-}) {
+function applyDestinationPermissions({
+  functionObject,
+  policyStatements,
+  serverless,
+  throwError,
+}) {
   const { destinations } = functionObject
   if (!destinations) return

   const processDestination = (destinationProperty) => {
     const action = getDestinationAction(destinationProperty)
-    if (!action) return
+    if (!action) {
+      if (typeof throwError === 'function') {
+        throwError(`Unsupported destination target`, functionObject)
+      }
+      return
+    }

     const resourceArn = getDestinationArn(destinationProperty, serverless)

     policyStatements.push({
       Effect: 'Allow',
       Action: action,
       Resource: resourceArn,
     })
   }
@@
-  applyDestinationPermissions({ functionObject, policyStatements, serverless })
+  applyDestinationPermissions({
+    functionObject,
+    policyStatements,
+    serverless,
+    throwError,
+  })
 }
🤖 Fix all issues with AI agents
In
`@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js`:
- Around line 661-664: The test currently uses await
expect(awsCompileFunctions.compileFunctions()).resolves.not.toThrow(), which is
invalid because toThrow expects a function; replace that assertion with a direct
await of the promise to ensure it resolves without throwing: change the
assertion to await awsCompileFunctions.compileFunctions(); (locate and update
the test that calls awsCompileFunctions.compileFunctions()).

@czubocha czubocha requested a review from eahefnawy January 26, 2026 16:28
@czubocha
Copy link
Contributor Author

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)

packages/serverless/lib/plugins/aws/package/lib/roles-per-function-permissions.js (1)> 516-595: Fail fast when destination permissions can’t be inferred.

In per-function IAM mode, ensureTargetExecutionPermission is skipped; if getDestinationAction returns null (typo/unsupported type), we now silently skip permissions, which can surface later as runtime delivery failures. Consider throwing (or using throwError) to keep behavior consistent with the shared-role path.

🧩 Proposed fix

-function applyDestinationPermissions({
-  functionObject,
-  policyStatements,
-  serverless,
-}) {
+function applyDestinationPermissions({
+  functionObject,
+  policyStatements,
+  serverless,
+  throwError,
+}) {
   const { destinations } = functionObject
   if (!destinations) return

   const processDestination = (destinationProperty) => {
     const action = getDestinationAction(destinationProperty)
-    if (!action) return
+    if (!action) {
+      if (typeof throwError === 'function') {
+        throwError(`Unsupported destination target`, functionObject)
+      }
+      return
+    }

     const resourceArn = getDestinationArn(destinationProperty, serverless)

     policyStatements.push({
       Effect: 'Allow',
       Action: action,
       Resource: resourceArn,
     })
   }
@@
-  applyDestinationPermissions({ functionObject, policyStatements, serverless })
+  applyDestinationPermissions({
+    functionObject,
+    policyStatements,
+    serverless,
+    throwError,
+  })
 }

🤖 Fix all issues with AI agents

In
`@packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js`:
- Around line 661-664: The test currently uses await
expect(awsCompileFunctions.compileFunctions()).resolves.not.toThrow(), which is
invalid because toThrow expects a function; replace that assertion with a direct
await of the promise to ensure it resolves without throwing: change the
assertion to await awsCompileFunctions.compileFunctions(); (locate and update
the test that calls awsCompileFunctions.compileFunctions()).

This has been addressed

@czubocha czubocha merged commit 27dff9c into main Jan 26, 2026
12 checks passed
@czubocha czubocha deleted the cursor/per-function-iam-destinations-6551 branch January 26, 2026 19:01
@github-actions github-actions bot locked and limited conversation to collaborators Jan 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error when using destinations with per-function IAM role

4 participants