aws / aws/aws-sam-cli

sam sync/local operations silently target the wrong physical resource when --resource-id collides across sibling nested stacks

Open
#9,185 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
6.7k
Forks
1.2k
Avg merge
1d 10h
Merged PRs (30d)
52

Description

### Description

`get_resource_by_id()` in `samcli/lib/providers/provider.py` is the core lookup used by `sam sync --resource-id ` (and the underlying file-watch/code-trigger machinery used by `sam sync --watch`) to resolve a bare, unqualified resource logical ID to the deployed resource it should operate on.

When a bare ID (no `Stack/` path prefix) is given and it matches a resource with the same logical ID in **more than one nested stack**, with no match in the root stack to prefer, the function silently returns whichever stack happens to come first in its internal stack list — with no error, warning, or disambiguation prompt.

```python
def get_resource_by_id(
stacks: List[Stack], identifier: ResourceIdentifier, explicit_nested: bool = False
) -> Optional[Dict[str, Any]]:
...
search_all_stacks = not identifier.stack_path and not explicit_nested
for stack in stacks:
if stack.stack_path == identifier.stack_path or search_all_stacks:
found_resource = None
for logical_id, resource in stack.resources.items():
...
if resource_id == identifier.resource_iac_id or (...):
found_resource = resource
break
if found_resource:
return cast(Dict[str, Any], found_resource) # <-- first match wins, silently
return None
```

### Reproduction

A SAM template using nested stacks where two different nested `AWS::CloudFormation::Stack` resources each contain a resource with the same logical ID (e.g. a shared/reusable nested-stack module deployed twice, or two independently-authored nested stacks that happen to reuse a common name like `Function1`) — no root-level resource with that ID.

```
sam sync --watch --resource-id Function1
```

### Expected behavior

Since the ID is genuinely ambiguous (matches deployed resources in two different nested stacks), the CLI should either ask the user to disambiguate or fail with a clear error telling them to qualify the ID with the full stack path (e.g. `NestedStackA/Function1`), which `ResourceIdentifier` already supports as valid input syntax.

### Actual behavior

The lookup silently returns whichever nested stack's resource happens to be first in the internal (construction-order-dependent) stack list. Since `sam sync` bypasses full CloudFormation deployment and pushes code directly to the resolved physical resource (e.g. via `UpdateFunctionCode`), this means the wrong live, deployed Lambda function (or other resource) can silently receive the local code changes intended for a different one — with no error printed and no indication anything went wrong.

Note: this is distinct from, and does not affect, the existing (and intentional/tested) precedence where a root-stack resource always wins over a same-named nested-stack resource for a bare ID — that behavior is correct and unaffected by this report. The bug is specifically the nested-vs-nested collision case, which has no precedence rule and no test coverage today.

### Fix

PR incoming — raises a clear, actionable error when a bare ID matches more than one nested stack with no root-stack match to prefer, instead of silently picking the first one.

Contributor guide

Open the contributing guide

Research direction

Start in samcli/lib/providers/provider.py at get_resource_by_id() and reproduce the bare-ID lookup with two nested stacks containing the same resource logical ID. The change is complete when an ambiguous nested match raises a clear error requiring a qualified stack path, while root-stack precedence remains unchanged; add coverage for the collision case and existing precedence behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, python
Domain
cli, cloud
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.