aws / aws/aws-cdk

(ecs): ContainerImage.from_asset incorrectly states the default follow_symlinks mode is NEVER

Open
#21,334 1 comment 0 reactions 0 assignees View on GitHub
@aws-cdk/aws-ecs breaking-change bug effort/small needs-discussion p1
Dominant language
TypeScript
Stars
12.9k
Forks
4.6k
Avg merge
2d 3h
Merged PRs (30d)
83

Description

### Describe the bug

The [documentation of ContainerImage](https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_ecs/ContainerImage.html) states:

> follow_symlinks (Optional[[SymlinkFollowMode](https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk/SymlinkFollowMode.html#aws_cdk.SymlinkFollowMode)]) – A strategy for how to handle symlinks. Default: SymlinkFollowMode.NEVER

As best as I can tell, this documentation comes from [CopyOptions or FileCopyOptions](https://github.com/aws/aws-cdk/blob/v2.33.0/packages/@aws-cdk/core/lib/fs/options.ts#L77-L99). However I do not see this behavior during actual usage.

If I use ContainerImage.from_asset and use Dockerfile that copies a symlink that references a file outside of the directory the Dockerfile is in, I'd expect that build to fail when using SymlinkFollowMode.NEVER. However the build succeeds, and in the Docker image is built, I see no symlink, only the file that is symlinked to.

When I explicitly set `follow_symlinks` to `SymlinkFollowMode.NEVER`, I see the expected failure.

It's again hard to work out just how the `follow_symlinks` value actually affects the build logic, but I think the offending code is in the core function [copyDirectory](https://github.com/aws/aws-cdk/blob/v2.33.0/packages/@aws-cdk/core/lib/fs/copy.ts#L8), which begins:

```
export function copyDirectory(srcDir: string, destDir: string, options: CopyOptions = { }, rootDir?: string) {
const follow = options.follow ?? SymlinkFollowMode.EXTERNAL;

```

Defaulting the SymlinkFollowMode to EXTERNAL. This matches the behavior I'm seeing.

### Expected Behavior

The ContainerImage.from_asset parameter follow_symlinks defaults to SymlinkFollowMode.NEVER, as per the documentation

### Current Behavior

The ContainerImage.from_asset parameter follow_symlinks appears to default to SymlinkFollowMode.EXTERNAL

### Reproduction Steps

The stack definition

```
from aws_cdk import Stack, aws_ecs, SymlinkFollowMode
from constructs import Construct

class DockerImageDemoStack(Stack):

def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

fargate_task_definition = aws_ecs.FargateTaskDefinition(
scope=self,
id="FargateTaskDefinition",
cpu=1024,
memory_limit_mib=2048,
)

fargate_task_definition.add_container(
id="Container",
image=aws_ecs.ContainerImage.from_asset(
"docker_images/test",
# follow_symlinks=SymlinkFollowMode.NEVER,
),
)
```

With docker_images/test containing the Dockerfile

```
FROM debian:bullseye-slim

# This line should not work in our build, as app.py is outside the docker_images/test context
# directory. It does fail from a direct docker build, but the CDK will allow the COPY.

COPY app.py .
```

And an app.py symlink created by executing:

```
cd docker_images/test && ln -s ../../app.py app.py && cd -
```

### Possible Solution

I suspect for backwards compatibility reasons this should be a documentation fix. However it seems like NEVER really should be the default, both so that the default behavior matches what you'd see with a `docker build`, and because of the security implications that copy operations can materialize files from the user’s file system.

### Additional Information/Context

It would be nice if the documentation included a recipe for duplicating what SymlinkFollowMode.EXTERNAL actually does to materialize the symlinks. For most of our docker images we've been able to cd into the directory the Dockerfile is contained in, and `docker build` and `docker run` to test the images locally.

However one of my colleagues has used some symlinks with one of his docker files, and now I'm not sure what the best way to build it locally is.

### CDK CLI Version

2.33.0 (build 859272d)

### Framework Version

_No response_

### Node.js Version

v16.15.1

### OS

Ubuntu (Windows Subsystem for Linux)

### Language

Python

### Language Version

Python 3.9.7

### Other information

_No response_

Contributor guide

Open the contributing guide

Research direction

Start with ContainerImage.from_asset and inspect packages/@aws-cdk/core/lib/fs/options.ts and packages/@aws-cdk/core/lib/fs/copy.ts, especially the documented and effective defaults. Reproduce the behavior using the Dockerfile and external app.py symlink described in the issue. Done means the implementation and documentation agree on the default, with coverage for the reported case and explicit SymlinkFollowMode.NEVER behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, docker, python, typescript
Domain
devops, infrastructure
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.