Skip to content

Commit b3f9604

Browse files
committed
fix(cli): traverse unreadable directories when stripping node_modules in the code stage
chmod -R u+w itself fails on a directory without owner execute; u+rwX grants traversal as it recurses. Also trim generated-Containerfile comments to the non-obvious constraints.
1 parent cc15136 commit b3f9604

2 files changed

Lines changed: 9 additions & 17 deletions

File tree

packages/cli-v3/src/deploy/buildImage.test.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@ describe("generateContainerfile", () => {
4444
`COPY --from=build --chown=${user} /app/node_modules ./node_modules`
4545
);
4646
expect(containerfile).toContain(`COPY --from=code --chown=${user} /app ./`);
47-
// The final stage must not copy all of /app from the build stage anymore,
48-
// or node_modules would be duplicated across two layers
47+
// copying all of /app from build would duplicate node_modules across two layers
4948
expect(containerfile).not.toContain(`COPY --from=build --chown=${user} /app ./`);
5049
}
5150
);
@@ -62,12 +61,11 @@ describe("generateContainerfile", () => {
6261
});
6362

6463
const postInstall = containerfile.indexOf("RUN echo post-install");
65-
// The guard must run after post-install commands so a command that prunes
66-
// node_modules can't break the final-stage COPY of /app/node_modules
64+
// guard after post-install so a command that prunes node_modules can't break the COPY
6765
const mkdirGuard = containerfile.indexOf("RUN mkdir -p node_modules");
6866
const codeStage = containerfile.indexOf("FROM build AS code");
6967
const rmNodeModules = containerfile.indexOf(
70-
"RUN chmod -R u+w node_modules && rm -rf node_modules"
68+
"RUN chmod -R u+rwX node_modules && rm -rf node_modules"
7169
);
7270

7371
expect(postInstall).toBeGreaterThan(-1);

packages/cli-v3/src/deploy/buildImage.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -783,11 +783,10 @@ ${postInstallCommands}
783783
# node_modules may not exist when there are no dependencies to install
784784
RUN mkdir -p node_modules
785785
786-
# App files without node_modules, so the final stage can layer them separately
787786
FROM build AS code
788787
789-
# u+w first: rm as a non-root user fails on read-only directories
790-
RUN chmod -R u+w node_modules && rm -rf node_modules
788+
# u+rwX first: non-root rm fails on read-only or non-traversable directories
789+
RUN chmod -R u+rwX node_modules && rm -rf node_modules
791790
792791
FROM build AS indexer
793792
@@ -840,11 +839,9 @@ ENV TRIGGER_PROJECT_ID=\${TRIGGER_PROJECT_ID} \
840839
NODE_EXTRA_CA_CERTS=\${NODE_EXTRA_CA_CERTS} \
841840
NODE_ENV=production
842841
843-
# Dependencies as their own layer: unchanged deps produce an identical blob
844-
# that registries and workers already have, so repeat deploys skip it
842+
# Unchanged dependencies produce an identical layer that repeat deploys skip
845843
COPY --from=build --chown=bun:bun /app/node_modules ./node_modules
846844
847-
# Copy the app files (without node_modules) from the code stage
848845
COPY --from=code --chown=bun:bun /app ./
849846
850847
# Copy the index.json file from the indexer stage
@@ -904,11 +901,10 @@ COPY --chown=node:node . .
904901
# node_modules may not exist when there are no dependencies to install
905902
RUN mkdir -p node_modules
906903
907-
# App files without node_modules, so the final stage can layer them separately
908904
FROM build AS code
909905
910-
# u+w first: rm as a non-root user fails on read-only directories
911-
RUN chmod -R u+w node_modules && rm -rf node_modules
906+
# u+rwX first: non-root rm fails on read-only or non-traversable directories
907+
RUN chmod -R u+rwX node_modules && rm -rf node_modules
912908
913909
FROM build AS indexer
914910
@@ -963,11 +959,9 @@ ENV TRIGGER_PROJECT_ID=\${TRIGGER_PROJECT_ID} \
963959
NODE_EXTRA_CA_CERTS=\${NODE_EXTRA_CA_CERTS} \
964960
NODE_ENV=production
965961
966-
# Dependencies as their own layer: unchanged deps produce an identical blob
967-
# that registries and workers already have, so repeat deploys skip it
962+
# Unchanged dependencies produce an identical layer that repeat deploys skip
968963
COPY --from=build --chown=node:node /app/node_modules ./node_modules
969964
970-
# Copy the app files (without node_modules) from the code stage
971965
COPY --from=code --chown=node:node /app ./
972966
973967
# Copy the index.json file from the indexer stage

0 commit comments

Comments
 (0)