Skip to content

fix(aws): scope shared IAM role to functions without dedicated per-function roles#13704

Open
czubocha wants to merge 2 commits into
mainfrom
branch/per-function-iam-global-role-c6d4f1
Open

fix(aws): scope shared IAM role to functions without dedicated per-function roles#13704
czubocha wants to merge 2 commits into
mainfrom
branch/per-function-iam-global-role-c6d4f1

Conversation

@czubocha

@czubocha czubocha commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix per-function IAM "selected functions" mode: the shared execution role no longer accumulates auto-generated permissions for functions that have their own dedicated role (stream/SQS/scheduler/MSK/Kafka/ActiveMQ/RabbitMQ event grants, onError/kmsKeyArn/EFS/destination grants, custom log-group grants)
  • Reach permission parity first: dedicated per-function roles now receive grants that previously existed only on the shared role — Kinesis enhanced-fan-out consumer actions incl. kinesis:SubscribeToShard, stream onFailure SNS/SQS destination grants, and kms:Decrypt for kmsKeyArn (these were broken for dedicated-role functions before this PR)
  • Add a compile-time predicate (uses-dedicated-per-function-role.js) kept in lockstep with role creation, plus a divergence guard that fails packaging loudly if a function predicted to receive a dedicated role did not get one
  • Unaffected configs produce byte-identical templates: services without per-function IAM, provider.iam.role.mode: perFunction, services using the external serverless-iam-roles-per-function plugin, functions with the role: property, and provider.role configs
  • Document the shared-role scoping behavior in the IAM guide

Root cause

Event compilers and the functions compiler write per-function permissions into the shared IamRoleLambdaExecution role during package:compileEvents/package:compileFunctions, while dedicated per-function roles are created later (before finalize). Nothing skipped functions destined for a dedicated role, so their grants remained on the shared role as unreachable duplicates. The shared role's inline policy grew with every function and event source, eventually exceeding the 10,240-byte IAM inline policy limit ("Maximum policy size exceeded") — and moving functions to dedicated roles provided zero relief, defeating the feature's documented purpose.

Test plan

  • Unit suites for every touched writer (stream, SQS, scheduler, MSK, Kafka, ActiveMQ, RabbitMQ, functions compiler, merge-iam-templates) covering skip + retention behavior
  • Predicate truth-table tests (plugin installed, role: property, existing-role reference, provider.role, perFunction mode, statements/legacy/managedPolicies shapes)
  • Parity tests: dedicated roles receive EFO consumer, stream onFailure, and KMS grants mirroring the shared-role writers exactly
  • Composed regression tests: shared-resource retention (shared + dedicated function on the same stream ARN), policy-size monotonicity, byte-identity snapshots for unaffected configs, scheduler Target.RoleArn pinned to the dedicated role, perFunction-mode output
  • Divergence guard: packaging fails loudly on prediction mismatch
  • Full unit suite green (2605 tests, 139 suites); lint and prettier clean
  • End-to-end packaging of reproduction services (built from this branch): shared-role policy shrinks 1499→869 bytes (3-function mixed service) and 1783→642 bytes (a service combining EFO consumer, stream onFailure, scheduler, KMS, onError and destinations) with no grant lost for shared-role functions
  • disableLogs deny statements verified emitted on the wildcard-fallback path; destination grants no-op cleanly when no shared role exists
  • Live AWS verification (real deploy): EFO consumer event source mapping active and processing records on the dedicated role, scheduler targeting the dedicated role and firing, CMK-encrypted env vars decrypting, deployed shared-role policy free of dedicated-function ARNs, dedicated role carrying all parity grants; full stack teardown confirmed

Summary by CodeRabbit

  • New Features
    • Expanded per-function IAM role permissions to cover more stream event options (including consumer scenarios), on-failure stream destinations, and KMS decrypt permissions.
  • Bug Fixes
    • Prevented event-source and destination IAM permissions (streams, SQS, Kafka/MSK, ActiveMQ, RabbitMQ, and scheduler invokes) from leaking into the shared execution role when per-function roles are used.
    • Improved shared log-policy handling to avoid invalid/empty IAM resources and corrected fallback behavior with disabled logs.
    • Added safer handling when shared roles are not present, plus stronger packaging consistency checks for dedicated roles.
  • Documentation
    • Clarified shared vs per-function IAM role generation behavior and inline policy merging rules.
  • Tests
    • Added/expanded unit and regression coverage for scoped IAM behavior across event types and edge cases.

… roles

Dedicated per-function IAM roles were missing several permissions that the
shared execution role grants for the same configuration, leaving functions
with dedicated roles under-permissioned:

- Kinesis enhanced-fan-out consumers: consumer-variant stream actions
  (DescribeStreamSummary, ListShards) and kinesis:SubscribeToShard on the
  consumer ARN (both consumer: true and explicit consumer ARN forms)
- Stream onFailure destinations: sns:Publish / sqs:ListQueues+SendMessage
  on the destination ARN
- kms:Decrypt when kmsKeyArn is configured (function- or provider-level)

Also extracts stream-name resolution from the stream event compiler into a
shared util (pure refactor) so per-function role generation resolves
consumer logical IDs identically.
@Mmarzex

Mmarzex commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

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

Status Scan Engine 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

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b3be5b0b-183d-4c0d-a12f-eac1d7abc1d5

📥 Commits

Reviewing files that changed from the base of the PR and between 38a9e4c and cea4644.

⛔ Files ignored due to path filters (1)
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/__snapshots__/per-function-iam-global-role.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (27)
  • docs/sf/providers/aws/guide/iam.md
  • packages/serverless/lib/plugins/aws/package/compile/events/activemq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/kafka.js
  • packages/serverless/lib/plugins/aws/package/compile/events/msk/index.js
  • packages/serverless/lib/plugins/aws/package/compile/events/rabbitmq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/schedule.js
  • packages/serverless/lib/plugins/aws/package/compile/events/sqs.js
  • packages/serverless/lib/plugins/aws/package/compile/events/stream.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js
  • packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js
  • packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/activemq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/kafka.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/msk.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/rabbitmq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/sqs.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/stream.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/merge-iam-templates.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.test.js
🚧 Files skipped from review as they are similar to previous changes (20)
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.test.js
  • packages/serverless/lib/plugins/aws/package/compile/events/activemq.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/kafka.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/sqs.test.js
  • packages/serverless/lib/plugins/aws/package/compile/events/rabbitmq.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/rabbitmq.test.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js
  • docs/sf/providers/aws/guide/iam.md
  • packages/serverless/lib/plugins/aws/package/compile/events/kafka.js
  • packages/serverless/lib/plugins/aws/package/compile/events/stream.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/activemq.test.js
  • packages/serverless/lib/plugins/aws/package/compile/events/sqs.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/msk.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
  • packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/stream.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/merge-iam-templates.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js

📝 Walkthrough

Walkthrough

Dedicated per-function IAM role detection now controls whether generated permissions are added to the shared Lambda execution role. Dedicated roles receive stream, KMS, VPC, and destination permissions, with expanded coverage for role creation, policy isolation, and IAM policy validity.

Changes

IAM role isolation

Layer / File(s) Summary
Dedicated-role detection and creation
packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js, packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js, packages/serverless/test/unit/...
Dedicated-role prediction, external-plugin detection, role creation validation, and role wiring were added.
Shared-role permission routing
packages/serverless/lib/plugins/aws/package/compile/events/*, packages/serverless/lib/plugins/aws/package/compile/functions.js, packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js, docs/sf/providers/aws/guide/iam.md
Event, function, scheduler, and log IAM generation now excludes contributions from dedicated-role functions while retaining shared-role permissions.
Dedicated-role permissions
packages/serverless/lib/plugins/aws/package/lib/roles-per-function-permissions.js, packages/serverless/lib/plugins/aws/utils/get-stream-name-from-arn.js
Per-function roles now assemble Kinesis consumer, stream destination, KMS, and VPC permissions using shared stream-name extraction.
Regression coverage
packages/serverless/test/unit/...
Tests cover event-specific isolation, scheduler behavior, log fallbacks, external plugins, per-function mode, role wiring, and empty IAM collections.

Estimated code review effort: 5 (Critical) | ~90 minutes

Possibly related PRs

Suggested reviewers: eahefnawy

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: limiting the shared AWS IAM role to functions that do not use dedicated per-function roles.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch branch/per-function-iam-global-role-c6d4f1

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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/compile/events/schedule.js (1)

384-404: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fully isolate the shared role when every Scheduler function has a dedicated role.

The invoke policy is omitted, but the shared role still gains the Scheduler service principal.

  • packages/serverless/lib/plugins/aws/package/compile/events/schedule.js#L384-L404: gate the trust-policy mutation on schedulerStatement.Resource.length.
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js#L607-L643: assert that scheduler.amazonaws.com is absent when all Scheduler targets use dedicated roles.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/serverless/lib/plugins/aws/package/compile/events/schedule.js`
around lines 384 - 404, Gate the shared role trust-policy mutation in the
schedule compilation flow on schedulerStatement.Resource.length, so
scheduler.amazonaws.com is added only when the shared role has invoke resources.
Update
packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js
lines 607-643 to assert that scheduler.amazonaws.com is absent when every
Scheduler target uses a dedicated role.
🧹 Nitpick comments (3)
packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace lodash with native JavaScript.

Use optional chaining and native object checks instead of _.get and _.isObject.

As per coding guidelines, “Prefer native JavaScript over lodash.”

Also applies to: 31-50

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js`
at line 1, Replace the lodash import and its usages in the
dedicated-per-function-role logic with native JavaScript: use optional chaining
for nested property access instead of _.get, and native object checks instead of
_.isObject. Preserve the existing behavior across the logic spanning the
referenced lines, then remove the unused lodash import.

Source: Coding guidelines

packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js (1)

225-267: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the duplicated disableLogs-Deny construction into a helper.

The Deny-statement building logic (map function names → log-group ARNs → mergeStatements) here duplicates the existing block a few lines above (the hasOneOrMoreCanonicallyNamedFunctions branch). A future edit to one copy (e.g. Action list or ARN format) risks silently missing the other.

♻️ Proposed extraction
+    const emitDisableLogsDeny = (functionNames) => {
+      const arnOfDisableLogGroups = functionNames.map((fnName) => ({
+        'Fn::Sub':
+          'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' +
+          `:log-group:${this.provider.naming.getLogGroupName(fnName)}:*`,
+      }))
+      this.mergeStatements([
+        {
+          Effect: 'Deny',
+          Action: 'logs:PutLogEvents',
+          Resource: arnOfDisableLogGroups,
+        },
+      ])
+    }
+
     if (hasOneOrMoreCanonicallyNamedFunctions) {
       ...
       if (disableLogsCanonicallyNamedFunctions.length > 0) {
-        // add deny rule for disabled logs function
-        const arnOfDisableLogGroups = disableLogsCanonicallyNamedFunctions.map(...)
-        this.mergeStatements([...])
+        emitDisableLogsDeny(disableLogsCanonicallyNamedFunctions)
       }
     }
     ...
     if (skippedDedicatedLogContributions && ...) {
       ...
       if (disableLogsCanonicallyNamedFunctions.length > 0) {
-        const arnOfDisableLogGroups = disableLogsCanonicallyNamedFunctions.map(...)
-        this.mergeStatements([...])
+        emitDisableLogsDeny(disableLogsCanonicallyNamedFunctions)
       }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js`
around lines 225 - 267, Extract the duplicated disableLogs Deny construction
into a shared helper near the existing IAM merge logic, including mapping
function names to log-group ARNs and calling mergeStatements with the Deny
statement. Replace both the hasOneOrMoreCanonicallyNamedFunctions branch and the
skippedDedicatedLogContributions branch with calls to that helper, preserving
their existing conditions and behavior.
packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js (1)

59-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated real-pipeline test harness across two new sibling files. Both files independently define byte-identical buildService and runEventCompilers helpers (construct real Serverless+AwsProvider, wire functions, seed Lambda resources, run selected event compilers). One root cause: no shared test-utility module for this harness, risking future drift between the two copies.

  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js#L59-L125: extract buildService/runEventCompilers into a shared test-helper module (e.g. alongside the existing test-lib utilities) and import it here.
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js#L72-L133: import the same shared helper module instead of redefining buildService/runEventCompilers locally.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js`
around lines 59 - 125, Extract the shared buildService and runEventCompilers
harness into a common test-helper module, preserving their current behavior and
dependencies. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
lines 59-125, remove the local definitions and import the helpers; do the same
in
packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
lines 72-133, using the same shared module in both files.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js`:
- Around line 445-463: Update the validation around createdRoleNames and
usesDedicatedPerFunctionRole to compare predicted and created dedicated-role
names in both directions, failing packaging whenever either set contains an
entry absent from the other. Preserve the existing error behavior for
prediction/creation mismatches and add the inverse regression test covering a
role created without a corresponding prediction.

---

Outside diff comments:
In `@packages/serverless/lib/plugins/aws/package/compile/events/schedule.js`:
- Around line 384-404: Gate the shared role trust-policy mutation in the
schedule compilation flow on schedulerStatement.Resource.length, so
scheduler.amazonaws.com is added only when the shared role has invoke resources.
Update
packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js
lines 607-643 to assert that scheduler.amazonaws.com is absent when every
Scheduler target uses a dedicated role.

---

Nitpick comments:
In `@packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js`:
- Around line 225-267: Extract the duplicated disableLogs Deny construction into
a shared helper near the existing IAM merge logic, including mapping function
names to log-group ARNs and calling mergeStatements with the Deny statement.
Replace both the hasOneOrMoreCanonicallyNamedFunctions branch and the
skippedDedicatedLogContributions branch with calls to that helper, preserving
their existing conditions and behavior.

In
`@packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js`:
- Line 1: Replace the lodash import and its usages in the
dedicated-per-function-role logic with native JavaScript: use optional chaining
for nested property access instead of _.get, and native object checks instead of
_.isObject. Preserve the existing behavior across the logic spanning the
referenced lines, then remove the unused lodash import.

In
`@packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js`:
- Around line 59-125: Extract the shared buildService and runEventCompilers
harness into a common test-helper module, preserving their current behavior and
dependencies. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
lines 59-125, remove the local definitions and import the helpers; do the same
in
packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
lines 72-133, using the same shared module in both files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b6201cb-3360-42c0-9b6f-a709da6206ae

📥 Commits

Reviewing files that changed from the base of the PR and between 49c2d35 and c554c73.

⛔ Files ignored due to path filters (1)
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/__snapshots__/per-function-iam-global-role.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (29)
  • docs/sf/providers/aws/guide/iam.md
  • packages/serverless/lib/plugins/aws/package/compile/events/activemq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/kafka.js
  • packages/serverless/lib/plugins/aws/package/compile/events/msk/index.js
  • packages/serverless/lib/plugins/aws/package/compile/events/rabbitmq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/schedule.js
  • packages/serverless/lib/plugins/aws/package/compile/events/sqs.js
  • packages/serverless/lib/plugins/aws/package/compile/events/stream.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js
  • packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function-permissions.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js
  • packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js
  • packages/serverless/lib/plugins/aws/utils/get-stream-name-from-arn.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/activemq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/kafka.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/msk.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/rabbitmq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/sqs.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/stream.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/merge-iam-templates.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.test.js

@czubocha czubocha force-pushed the branch/per-function-iam-global-role-c6d4f1 branch from c554c73 to 38a9e4c Compare July 14, 2026 09:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js (1)

16-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Shared test-fixture logic duplicated across two suites. FakeServerlessError, buildContext, and the isExistingRoleProvided mock are copy-pasted between both files, which both exercise the same dedicated-role-creation subsystem; keeping two independent copies risks the mocks drifting out of sync and masking real regressions in one suite but not the other.

  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js#L16-L93: extract FakeServerlessError, buildContext, and isExistingRoleProvided into a shared test-helper module and import it here.
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js#L34-L111: import the same shared helper (extending it with mergeIamTemplatesMixin/utils.readFileSync wiring specific to this suite) instead of re-declaring the fixture.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js`
around lines 16 - 93, Extract FakeServerlessError, buildContext, and the
isExistingRoleProvided mock into one shared test-helper module. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js
lines 16-93, import and use that helper instead of the duplicated fixture. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js
lines 34-111, import the same helper and retain only the suite-specific
mergeIamTemplatesMixin and utils.readFileSync wiring.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js`:
- Around line 16-93: Extract FakeServerlessError, buildContext, and the
isExistingRoleProvided mock into one shared test-helper module. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js
lines 16-93, import and use that helper instead of the duplicated fixture. In
packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js
lines 34-111, import the same helper and retain only the suite-specific
mergeIamTemplatesMixin and utils.readFileSync wiring.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ad9c0c81-dcff-42b5-80c2-5b1ff606de10

📥 Commits

Reviewing files that changed from the base of the PR and between c554c73 and 38a9e4c.

⛔ Files ignored due to path filters (1)
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/__snapshots__/per-function-iam-global-role.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (27)
  • docs/sf/providers/aws/guide/iam.md
  • packages/serverless/lib/plugins/aws/package/compile/events/activemq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/kafka.js
  • packages/serverless/lib/plugins/aws/package/compile/events/msk/index.js
  • packages/serverless/lib/plugins/aws/package/compile/events/rabbitmq.js
  • packages/serverless/lib/plugins/aws/package/compile/events/schedule.js
  • packages/serverless/lib/plugins/aws/package/compile/events/sqs.js
  • packages/serverless/lib/plugins/aws/package/compile/events/stream.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js
  • packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js
  • packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/activemq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/kafka.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/msk.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/rabbitmq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/sqs.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/stream.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/merge-iam-templates.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.lockstep.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.test.js
🚧 Files skipped from review as they are similar to previous changes (23)
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.test.js
  • docs/sf/providers/aws/guide/iam.md
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/rabbitmq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/stream.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/roles-per-function-permissions.test.js
  • packages/serverless/lib/plugins/aws/package/compile/events/stream.js
  • packages/serverless/lib/plugins/aws/package/compile/events/sqs.js
  • packages/serverless/lib/plugins/aws/package/lib/roles-per-function.js
  • packages/serverless/lib/plugins/aws/package/compile/events/kafka.js
  • packages/serverless/lib/plugins/aws/package/compile/events/activemq.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/sqs.test.js
  • packages/serverless/lib/plugins/aws/package/compile/events/msk/index.js
  • packages/serverless/lib/plugins/aws/package/lib/uses-dedicated-per-function-role.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/kafka.test.js
  • packages/serverless/lib/plugins/aws/package/lib/merge-iam-templates.js
  • packages/serverless/lib/plugins/aws/package/compile/events/rabbitmq.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/per-function-iam-global-role.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/functions.test.js
  • packages/serverless/lib/plugins/aws/package/compile/functions.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/msk.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/compile/events/activemq.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/merge-iam-templates.test.js
  • packages/serverless/test/unit/lib/plugins/aws/package/lib/iam-empty-collection-invariant.test.js

…nction roles

In per-function IAM 'selected functions' mode (some functions define
functions.<name>.iam.role.*, the rest use the shared execution role), the
shared role's inline policy kept accumulating auto-generated permissions
for every function in the service - including functions that assume their
own dedicated role. Those grants were unreachable dead weight that grew
with function count and pushed services past the 10,240-byte IAM inline
policy limit ('Maximum policy size exceeded'), so moving functions to
dedicated roles bought no relief.

A new predicate (uses-dedicated-per-function-role.js) predicts at compile
time whether a function will receive a dedicated role, staying in lockstep
with the role creation logic in roles-per-function.js. Every
per-function-growing writer to the shared role consults it and skips
dedicated functions: stream/SQS/scheduler/MSK/Kafka/ActiveMQ/RabbitMQ event
compilers, onError/kms/EFS/destination grants in the functions compiler,
and custom log-group grants in merge-iam-templates (with a wildcard
fallback so the shared role's log statements can never end up with an
empty Resource list; the fallback also emits the disableLogs deny
statements so log-disabled functions stay disabled).

Safety:
- The predicate returns false (behavior unchanged, byte-identical
  templates) when the external serverless-iam-roles-per-function plugin is
  installed, for functions using the role: property, for existing-role
  references, for provider.role configs, and for services without
  per-function IAM.
- A divergence guard at the end of createRolesPerFunction fails packaging
  loudly if a function predicted to get a dedicated role did not receive
  one.
- Destination grants no-op cleanly when no shared role exists instead of
  erroring while compiling event invoke config.
- Composed regression tests pin shared-resource retention, policy-size
  monotonicity, byte-identity for unaffected configs, scheduler RoleArn
  wiring, and perFunction-mode output.

Functions remaining on the shared role keep exactly the permissions they
had; grants removed from the shared role exist on the dedicated roles
(reaching parity in the previous commit).
@czubocha czubocha force-pushed the branch/per-function-iam-global-role-c6d4f1 branch from 38a9e4c to cea4644 Compare July 14, 2026 10:42
Comment thread packages/serverless/lib/plugins/aws/package/compile/events/schedule.js Dismissed
Comment thread packages/serverless/test/unit/lib/plugins/aws/package/compile/events/schedule.test.js Dismissed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants