aws-lambda-nodejs: Dockerfile's 'update-notifier false' step re-creates /tmp/npm-cache/_logs as root, regressing #9167's fix
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 83
Description
### Describe the bug
`aws-cdk-lib`'s Lambda-bundling Docker image (`aws-cdk-lib/aws-lambda-nodejs/lib/docker/Dockerfile`) makes `npm ci`/`npm install` fail for any Lambda built with `bundling.forceDockerBundling: true` (or any Lambda that needs Docker bundling for another reason, e.g. a native dependency compiled for the target platform/arch) — because `/tmp/npm-cache/_logs` ends up owned by `root:root` (mode 755) instead of the `777`-permissioned `/tmp/npm-cache` it lives under.
Any later `npm ci` run as the non-root bundling UID (CDK does `docker run -u ":" ...`) then fails outright, because npm treats "can't write the log file" as fatal for `npm ci`, not just a warning.
### This is a regression of #9167 (merged 2020)
PR #9167 ("fix(lambda-nodejs): permission denied on npm cache") originally fixed this exact class of bug by adding a `chmod -R 777 /tmp/npm-cache` and moving cache-folder creation so no root-owned content existed in it before the image starts, plus disabling npm's update notifier "so [it doesn't] write to that folder as root."
Looking at the current Dockerfile (confirmed on `aws-cdk-lib@2.265.0`), the ordering has drifted so the update-notifier line now runs **after** the chmod, undoing the original fix:
```dockerfile
# Ensure all users can write to npm cache
RUN mkdir /tmp/npm-cache && \
chmod -R 777 /tmp/npm-cache && \
npm config --global set cache /tmp/npm-cache
...
# Disable npm update notifications
RUN npm config --global set update-notifier false
```
That second `RUN npm config --global set update-notifier false` executes as root during `docker build`, and itself writes an npm debug log to the configured cache dir, recreating `/tmp/npm-cache/_logs` as `root:root 755`. Nothing chmods it again afterward.
### Reproduction
```bash
docker run --rm public.ecr.aws/sam/build-nodejs24.x sh -c "
mkdir /tmp/npm-cache && chmod -R 777 /tmp/npm-cache && npm config --global set cache /tmp/npm-cache
npm config --global set update-notifier false
stat -c '%n %U %a' /tmp/npm-cache/_logs
"
# -> root 755
```
Then any `npm ci` run as a non-root UID against that cache directory fails:
```bash
docker run --rm -u "501:20" sh -c "
mkdir -p /tmp/t && cd /tmp/t
echo '{\"name\":\"t\",\"version\":\"1.0.0\"}' > package.json
echo '{\"name\":\"t\",\"version\":\"1.0.0\",\"lockfileVersion\":3,\"requires\":true,\"packages\":{\"\":{\"name\":\"t\",\"version\":\"1.0.0\"}}}' > package-lock.json
npm ci
"
# -> EACCES / log write failure, npm ci fails
```
### Expected Behavior
`npm ci`/`npm install` inside the Docker bundling image should succeed for any UID, the same guarantee #9167 originally established for the whole npm cache directory.
### Current Behavior
`npm ci` fails because `/tmp/npm-cache/_logs` is root-owned and non-writable by the bundling UID.
### Reproduction Steps
See reproduction commands above. Also reproducible via any `NodejsFunction` with `bundling.forceDockerBundling: true` and `bundling.nodeModules` set — running `cdk synth` fails with `CommandExecutionFailed: docker exited with status 1` and an `npm error` about the log directory (or, once the underlying log-write failure obscures the real error, a less obvious npm failure).
### Possible Solution
Either:
1. Move `RUN npm config --global set update-notifier false` before the `mkdir /tmp/npm-cache && chmod -R 777 ...` block, or
2. Re-run `chmod -R 777 /tmp/npm-cache` after the update-notifier line, or
3. Set the workaround `npm_config_logs_max=0` via env in the base image so npm never attempts to write a log file inside the container at all.
As an immediate workaround, setting `bundling.environment: { npm_config_logs_max: '0' }` on the affected `NodejsFunction`(s) avoids the issue without an aws-cdk-lib change, since it disables npm's log-writing entirely.
### CDK CLI Version
2.1139.0 (aws-cdk-lib 2.265.0)
### Framework Version
_No response_
### Node.js Version
Node 24 (bundling image: `public.ecr.aws/sam/build-nodejs24.x`)
### OS
macOS (host); Amazon Linux (SAM build image, Lambda-compatible Docker container)
### Language
TypeScript
### Language Version
_No response_
### Other information
Affects any project using `NodejsFunction` with `bundling.forceDockerBundling: true` and `bundling.nodeModules`, not specific to any one project — reproduced directly against the unmodified `public.ecr.aws/sam/build-nodejs24.x`-derived bundling image with no project-specific configuration involved.
Contributor guide
Research direction
Start with aws-cdk-lib/aws-lambda-nodejs/lib/docker/Dockerfile and compare the npm cache setup with the update-notifier step described in the issue. Run the supplied Docker reproduction, then verify that npm ci succeeds as a non-root UID and that /tmp/npm-cache remains writable for any bundling UID.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, dockerfile, nodejs, typescript
- Domain
- build-system, cloud, devops
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100