Skip to content

fix(docker): share corepack cache so etherpad user can resolve pnpm#7689

Merged
JohnMcLear merged 2 commits intodevelopfrom
fix/7687-corepack-home
May 7, 2026
Merged

fix(docker): share corepack cache so etherpad user can resolve pnpm#7689
JohnMcLear merged 2 commits intodevelopfrom
fix/7687-corepack-home

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

Summary

  • Pins COREPACK_HOME=/opt/corepack and chowns it to the etherpad user, so the corepack lastKnownGood activation file written by root is visible after the USER etherpad switch.
  • Without this, the etherpad user's per-user corepack cache is empty when bin/installLocalPlugins.sh invokes pnpm; corepack re-resolves and (for builds without a matching packageManager pin) falls back to pnpm@latest (currently 10.33.4), failing the workspace's engines.pnpm check.

Why

PR #7674 (docker CVE sweep) replaced npm install -g pnpm with corepack prepare pnpm@${PnpmVersion} --activate. corepack prepare --activate writes to $COREPACK_HOME, which defaults to ~/.cache/node/corepack — a per-user path. We activate as root, then drop to etherpad, whose home dir has no cache. Sharing $COREPACK_HOME is the smallest fix.

Reported by @ferrlen in #7687 — they hit:

Your pnpm version is incompatible with "/opt/etherpad-lite/src".
Expected version: >=11.0.0
Got: 10.33.4

Test plan

  • docker build --target build . succeeds.
  • docker run --rm <build> sh -c 'pnpm --version' as etherpad reports the activated pnpm version (11.0.6) instead of falling back to "latest".
  • docker build --target development --build-arg ETHERPAD_LOCAL_PLUGINS=ep_test_corepack . with a stub local plugin runs installLocalPlugins.sh cleanly (Done in 16.6s using pnpm v11.0.6) — the original failure scenario.
  • CI image-build job stays green.

Follow-up (not blocking)

corepack prepare pnpm@11.0.6 --activate resolves to the highest matching patch (11.0.8) and caches that, while package.json pins packageManager: "pnpm@11.0.6" exactly. Result: corepack emits a one-time "about to download pnpm-11.0.6.tgz" line at runtime even though the activated version is in the cache. Functional, just inefficient — worth a separate small PR to either drop the packageManager exact pin or align with corepack's resolution.

🤖 Generated with Claude Code

…7687)

PR #7674 switched the Dockerfile from `npm install -g pnpm` to corepack
and `corepack prepare pnpm@${PnpmVersion} --activate`. The activate step
runs as root and writes its lastKnownGood pin into `$COREPACK_HOME`,
which defaults to `~/.cache/node/corepack` — i.e. a per-user path. The
Dockerfile then drops to `USER etherpad` and later runs
`bin/installLocalPlugins.sh`, which invokes `pnpm` as etherpad. With an
empty per-user corepack cache and no shared activation file, corepack
re-resolves pnpm and (for forks/configs without a `packageManager` pin
matching the activated version) can fall back to "latest" from the
registry — pulling `pnpm@10.33.4` instead of the requested 11.x and
failing the workspace's `engines.pnpm` check.

Pin `COREPACK_HOME=/opt/corepack` and chown it to etherpad after the
prepare step. Both root and etherpad now share the same lastKnownGood
file and tarball cache, so etherpad inherits the activated pnpm without
hitting the registry again.

Verified end-to-end:

- `docker build --target development --build-arg ETHERPAD_LOCAL_PLUGINS=ep_test`
  with a stub local plugin runs `installLocalPlugins.sh` cleanly:
  `Done in 16.6s using pnpm v11.0.6`.
- `docker run ... pnpm --version` as etherpad reports 11.0.6 from the
  shared cache — no "Unsupported environment" error.

Note: corepack still emits a one-time "about to download" line at
runtime because `corepack prepare pnpm@11.0.6` resolves to the highest
matching patch (11.0.8) at build time while the project's
`packageManager` field pins exactly 11.0.6. That's a follow-up — the
download succeeds non-interactively and the engine check passes.

Fixes #7687.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Share corepack cache between root and etherpad user

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Pins COREPACK_HOME=/opt/corepack to share pnpm cache between root and etherpad user
• Prevents corepack from re-resolving pnpm and falling back to latest version
• Fixes etherpad user's inability to resolve correct pnpm version during plugin installation
• Ensures bin/installLocalPlugins.sh uses activated pnpm 11.0.6 instead of registry fallback
Diagram
flowchart LR
  A["Root activates pnpm<br/>via corepack"] -->|writes to COREPACK_HOME| B["Shared /opt/corepack<br/>cache directory"]
  B -->|chown to etherpad| C["Etherpad user<br/>inherits activation"]
  C -->|pnpm resolved| D["installLocalPlugins.sh<br/>succeeds"]
Loading

Grey Divider

File Changes

1. Dockerfile 🐞 Bug fix +10/-1

Configure shared corepack cache for etherpad user

• Added COREPACK_HOME=/opt/corepack environment variable to pin shared cache location
• Created /opt/corepack directory during corepack installation
• Changed ownership of /opt/corepack to etherpad user after corepack prepare step
• Added explanatory comment documenting the per-user cache issue and solution

Dockerfile


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 7, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. COREPACK_HOME fix lacks test 📘 Rule violation ⚙ Maintainability
Description
This PR fixes a Docker build bug (Corepack cache visibility across USER switch) but does not add
an automated regression test to ensure the local plugin install path keeps using pnpm >=11 in future
changes. Without a CI check that builds with ETHERPAD_LOCAL_PLUGINS set, the original failure mode
can silently reappear.
Code

Dockerfile[R102-116]

+# Share corepack's cache between root (which activates pnpm here) and
+# the `etherpad` user (which invokes pnpm later via the corepack shim).
+# $COREPACK_HOME defaults to ~/.cache/node/corepack and is per-user;
+# without this pin the etherpad user finds an empty cache, re-resolves
+# pnpm, and corepack can fall back to "latest" from the registry. See
+# https://github.com/ether/etherpad/issues/7687.
+ENV COREPACK_HOME=/opt/corepack
+
# the mkdir is needed for configuration of openjdk-11-jre-headless, see
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN  \
-    mkdir -p /usr/share/man/man1 && \
+    mkdir -p /usr/share/man/man1 /opt/corepack && \
  npm install -g corepack@latest && \
  corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
+    chown -R etherpad:etherpad /opt/corepack && \
Evidence
PR Compliance ID 2 requires a regression test for bug fixes. The Dockerfile change explicitly
addresses the Corepack/pnpm version failure during local plugin install, but the existing CI Docker
workflow does not exercise the ETHERPAD_LOCAL_PLUGINS code path (which is where pnpm is
invoked), so no automated regression coverage is added with this fix.

Dockerfile[102-116]
bin/installLocalPlugins.sh[36-51]
.github/workflows/docker.yml[36-44]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Dockerfile bug fix is not protected by an automated regression test that exercises the local plugin installation path (the path that runs `pnpm` during image build).
## Issue Context
The reported failure happens when `ETHERPAD_LOCAL_PLUGINS` is set, causing `bin/installLocalPlugins.sh` to run `pnpm`. Current CI builds the Docker image but does not build with local plugins enabled, so the regression scenario is not automatically checked.
## Fix Focus Areas
- .github/workflows/docker.yml[36-82]
- bin/installLocalPlugins.sh[36-51]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. COREPACK_HOME path duplication ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The Dockerfile sets COREPACK_HOME but later hard-codes /opt/corepack for mkdir/chown, so a
future change to COREPACK_HOME can silently break cache sharing and permissions. This can
reintroduce the original “pnpm falls back to latest” failure mode or cause permission errors.
Code

Dockerfile[R108-116]

+ENV COREPACK_HOME=/opt/corepack
+
# the mkdir is needed for configuration of openjdk-11-jre-headless, see
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN  \
-    mkdir -p /usr/share/man/man1 && \
+    mkdir -p /usr/share/man/man1 /opt/corepack && \
  npm install -g corepack@latest && \
  corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
+    chown -R etherpad:etherpad /opt/corepack && \
Evidence
The cache location is declared via environment variable but subsequent filesystem operations don’t
reference that variable, creating a DRY violation and a mismatch hazard if the value is edited
later.

Dockerfile[102-117]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`COREPACK_HOME` is set, but `/opt/corepack` is repeated literally in the same stage. If `COREPACK_HOME` is changed later, the directory creation/ownership logic will not follow, risking a permission mismatch and reintroducing the pnpm/corepack cache issue.
### Issue Context
The PR’s intent is to pin the corepack cache directory and ensure it is readable/writable after switching to `USER etherpad`.
### Fix Focus Areas
- Dockerfile[108-116]
### Suggested change
Replace hard-coded `/opt/corepack` usages with `${COREPACK_HOME}` (and quote it), e.g.:
- `mkdir -p /usr/share/man/man1 "${COREPACK_HOME}"`
- `chown -R etherpad:etherpad "${COREPACK_HOME}"`
This keeps the filesystem operations aligned with the configured cache path.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread Dockerfile Outdated
Comment on lines +102 to +116
# Share corepack's cache between root (which activates pnpm here) and
# the `etherpad` user (which invokes pnpm later via the corepack shim).
# $COREPACK_HOME defaults to ~/.cache/node/corepack and is per-user;
# without this pin the etherpad user finds an empty cache, re-resolves
# pnpm, and corepack can fall back to "latest" from the registry. See
# https://github.com/ether/etherpad/issues/7687.
ENV COREPACK_HOME=/opt/corepack

# the mkdir is needed for configuration of openjdk-11-jre-headless, see
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
RUN \
mkdir -p /usr/share/man/man1 && \
mkdir -p /usr/share/man/man1 /opt/corepack && \
npm install -g corepack@latest && \
corepack enable && corepack prepare pnpm@${PnpmVersion} --activate && \
chown -R etherpad:etherpad /opt/corepack && \
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Corepack_home fix lacks test 📘 Rule violation ⚙ Maintainability

This PR fixes a Docker build bug (Corepack cache visibility across USER switch) but does not add
an automated regression test to ensure the local plugin install path keeps using pnpm >=11 in future
changes. Without a CI check that builds with ETHERPAD_LOCAL_PLUGINS set, the original failure mode
can silently reappear.
Agent Prompt
## Issue description
The Dockerfile bug fix is not protected by an automated regression test that exercises the local plugin installation path (the path that runs `pnpm` during image build).

## Issue Context
The reported failure happens when `ETHERPAD_LOCAL_PLUGINS` is set, causing `bin/installLocalPlugins.sh` to run `pnpm`. Current CI builds the Docker image but does not build with local plugins enabled, so the regression scenario is not automatically checked.

## Fix Focus Areas
- .github/workflows/docker.yml[36-82]
- bin/installLocalPlugins.sh[36-51]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

- Replace hard-coded /opt/corepack with ${COREPACK_HOME} in mkdir/chown
  so the env var stays the single source of truth (Qodo: "COREPACK_HOME
  path duplication").

- Add a build-test-local-plugin job to .github/workflows/docker.yml that
  builds the development target with a stub ETHERPAD_LOCAL_PLUGINS so
  the original failure mode (corepack/pnpm cache invisible across the
  USER switch) cannot silently regress (Qodo: "COREPACK_HOME fix lacks
  test"). The job is small — `docker build` only, no run — and uses the
  shared GHA buildx cache.

Verified: same docker build + `docker run pnpm --version` flow on the
variable form gives identical output (pnpm 11.0.6 from the etherpad-owned
cache).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnMcLear JohnMcLear merged commit fe9727b into develop May 7, 2026
43 checks passed
@JohnMcLear JohnMcLear deleted the fix/7687-corepack-home branch May 7, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant