moby / moby/buildkit

bug: COPY does not take /. (slash-dot) into account

Open
#791 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area/dockerfile kind/enhancement
Dominant language
Go
Stars
10.3k
Forks
1.5k
Avg merge
1d 23h
Merged PRs (30d)
48

Description

Relates to https://github.com/moby/moby/pull/38599

note: this is the same behavior as the classic builder, so we should discuss if we can change this without introducing a breaking change 😞

I think there's a bug in the copy behavior (both in classic builder, and in buildkit); it's come up a few times, and matching with the docker cp documentation;

SRC_PATH specifies a directory:

  • DEST_PATH does not exist
    • DEST_PATH is created as a directory and the contents of the source directory are copied into this directory
  • DEST_PATH exists and is a file
    • Error condition: cannot copy a directory to a file
  • DEST_PATH exists and is a directory
    • SRC_PATH does not end with /. (that is: slash followed by dot)
      • the source directory is copied into this directory
    • SRC_PATH does end with /. (that is: slash followed by dot)
      • the content of the source directory is copied into this directory

So without the trailing /., this line should result in dir itself being copied to /existingdir/dir; similar to cp:

Without trailing /.;

docker run --rm --workdir=/test alpine sh -c 'apk add --no-cache --quiet tree && mkdir -p src/dir/subdir dest/existingdir  && touch src/dir/subdir/nestedfile && cp -R src/dir dest/existingdir && cd /test/dest && tree'

.
└── existingdir
    └── dir
        └── subdir
            └── nestedfile

3 directories, 1 file

With trailing /.;

docker run --rm --workdir=/test alpine sh -c 'apk add --no-cache --quiet tree && mkdir -p src/dir/subdir dest/existingdir  && touch src/dir/subdir/nestedfile && cp -R src/dir/. dest/existingdir && cd /test/dest && tree'

.
└── existingdir
    └── subdir
        └── nestedfile

2 directories, 1 file

In a Dockerfile; without trailing /.;

DOCKER_BUILDKIT=1 docker build -<<EOF
FROM alpine AS source
RUN mkdir -p /dir/subdir && touch /dir/subdir/nestedfile

FROM alpine AS no_slash_dot
WORKDIR /dest
RUN apk add --no-cache --quiet tree
RUN mkdir existingdir
COPY --from=source /dir existingdir
RUN tree; exit 1
EOF

Produces;

.
└── existingdir
    └── subdir
        └── nestedfile

2 directories, 1 file

And with;

DOCKER_BUILDKIT=1 docker build -<<EOF
FROM alpine AS source
RUN mkdir -p /dir/subdir && touch /dir/subdir/nestedfile

FROM alpine AS slash_dot
WORKDIR /dest
RUN apk add --no-cache --quiet tree
RUN mkdir existingdir
COPY --from=source /dir/. existingdir
RUN tree; exit 1
EOF

Produces the same;

.
└── existingdir
    └── subdir
        └── nestedfile

2 directories, 1 file

The behavior should match the cp -R result

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up β€” it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing Dockerfile COPY handling in BuildKit and compare it with the documented docker cp behavior and the classic builder. Reproduce both COPY --from cases with and without a trailing '/.' and add regression coverage where the existing COPY tests belong. Done means the results match cp -R, subject to resolving the noted compatibility concern.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, go
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.