Summary
.dockerignore does not exclude auth*, and .docker/cli.dockerfile copies it explicitly. A project with a local auth.json therefore bakes its package token into the built image.
The --mount=type=secret,id=package_token mount already supplies that token to the Composer install, so the file copy is redundant as well as unsafe.
Details
.docker/cli.dockerfile at 1.41.0:
COPY composer.json composer.* patches.lock.* .env* auth* /app/
RUN --mount=type=secret,id=package_token \
token=$(if [ -s /run/secrets/package_token ]; then cat /run/secrets/package_token; else echo "${PACKAGE_TOKEN}"; fi) && \
if [ -n "${token}" ]; then export COMPOSER_AUTH="{\"github-oauth\": {\"github.com\": \"${token}\"}}"; fi && \
COMPOSER_MEMORY_LIMIT=-1 composer install -n --no-dev --ansi --prefer-dist --optimize-autoloader
Two paths put the file in the image: the explicit COPY ... auth* /app/ above, and the later COPY . /app, because the 1.41.0 deny-list .dockerignore does not list auth*.
Credentials for the install come from COMPOSER_AUTH, built from the build secret or the PACKAGE_TOKEN build arg - never from auth.json. So nothing in the build needs the file.
This is not a regression introduced by the deny-list rewrite: the previous allow-list .dockerignore carried an explicit !auth.json, so the file was already entering the build context. The rewrite preserved the behaviour rather than causing it.
Suggested change
Add the credentials file to .dockerignore:
# Credentials. The package token reaches the build through a build secret.
auth*
and drop it from the copy:
COPY composer.json composer.* patches.lock.* .env* /app/
Verified on a consumer project: the CLI image builds and Composer authenticates unchanged with both applied.
Worth considering alongside this: auth.json is not in the template's .gitignore either, so a token can also reach the repository.
How this surfaced
Raised by an automated review on a consumer project's 1.41.0 update PR, then verified against the template.
Summary
.dockerignoredoes not excludeauth*, and.docker/cli.dockerfilecopies it explicitly. A project with a localauth.jsontherefore bakes its package token into the built image.The
--mount=type=secret,id=package_tokenmount already supplies that token to the Composer install, so the file copy is redundant as well as unsafe.Details
.docker/cli.dockerfileat 1.41.0:Two paths put the file in the image: the explicit
COPY ... auth* /app/above, and the laterCOPY . /app, because the 1.41.0 deny-list.dockerignoredoes not listauth*.Credentials for the install come from
COMPOSER_AUTH, built from the build secret or thePACKAGE_TOKENbuild arg - never fromauth.json. So nothing in the build needs the file.This is not a regression introduced by the deny-list rewrite: the previous allow-list
.dockerignorecarried an explicit!auth.json, so the file was already entering the build context. The rewrite preserved the behaviour rather than causing it.Suggested change
Add the credentials file to
.dockerignore:and drop it from the copy:
COPY composer.json composer.* patches.lock.* .env* /app/Verified on a consumer project: the CLI image builds and Composer authenticates unchanged with both applied.
Worth considering alongside this:
auth.jsonis not in the template's.gitignoreeither, so a token can also reach the repository.How this surfaced
Raised by an automated review on a consumer project's 1.41.0 update PR, then verified against the template.