Skip to content

fix(docker): pre-create node_modules with node ownership for named volume#70

Merged
TortoiseWolfe merged 1 commit intomainfrom
69/node-modules-volume-permissions
May 5, 2026
Merged

fix(docker): pre-create node_modules with node ownership for named volume#70
TortoiseWolfe merged 1 commit intomainfrom
69/node-modules-volume-permissions

Conversation

@TortoiseWolfe
Copy link
Copy Markdown
Owner

Summary

  • Pre-creates /app/node_modules and /app/.next with node:node ownership in the Dockerfile dev stage so Docker named volumes inherit node ownership on first mount, fixing EACCES on container start when pnpm runs as node and tries to recreate .bin.
  • Mirrors the ce0e64d pattern that originally landed for .next. The .next pre-create had been removed during 7bdb86a's refactor; this commit restores it alongside the new node_modules treatment.

Problem

Latent bug. As long as the scripthammer_node_modules volume is reused across up/down cycles, ownership stays correct (set once on first install). It bites only on volume reset (docker volume rm scripthammer_node_modules, docker compose down -v, or first-startup of a fresh-clone fork). Symptom:

EACCES: permission denied, rmdir '/app/node_modules/.bin'

The container enters a restart loop on exit code 243.

Why this matters for the fork roadmap

Phase 1a (GrimGlow browser fork), Phase 2 (RN ScriptHammer extraction), and Phase 3 (KDG-stack template) all start from a gh repo create clone followed by a fresh docker compose up — i.e., always a brand-new volume. Every fresh fork will hit this bug on first startup. Fix once at the source.

Test plan

Verified locally:

  • docker compose down && docker volume rm scripthammer_node_modules scripthammer_next_cache && docker compose build && docker compose up -d
  • Container reaches healthy state (Up, no Restarting (243))
  • No EACCES errors in docker compose logs scripthammer
  • docker run --rm -v scripthammer_node_modules:/v alpine ls -ld /v reports 1000:1000 (was root:root before fix)
  • Husky pre-commit hooks ran clean (gitleaks, lint-staged)
  • Pre-push CI checks all passed

Refs

Closes #69

  • Reference fix: ce0e64d (.next named volume)
  • Removed-by: 7bdb86a (refactor that dropped the .next pre-create alongside the slow chown -R)
  • Bret Fisher named-volume guidance: ~/repos/TranScripts/Docker/Docker_Edited/nodejs_rocks_in_docker_dockercon2023.md

🤖 Generated with Claude Code

@TortoiseWolfe TortoiseWolfe force-pushed the 69/node-modules-volume-permissions branch from 3decf85 to 33e7b80 Compare May 4, 2026 17:35
TortoiseWolfe added a commit that referenced this pull request May 5, 2026
…regression hotfix) (#76)

Batch 8 (commit 52becd7, PR #74) added a module-level shared-secret cache
read-path in getMessageHistory to avoid re-deriving ECDH on every poll
tick. Post-merge CI showed a real Firefox/WebKit messaging E2E regression:

- Run 25306048649 (main, dd83ac7, pre-batch-8) at 07:14 UTC: all green
- Run 25332113434 (main, 0e20fb3, post-batch-8) at 17:04 UTC: firefox-msg
  failed with messages-not-visible timeouts on real-time-delivery,
  encrypted-messaging, and message-delete-placeholder specs
- Subsequent PR runs reproduced the same pattern, with webkit-msg also
  failing on the rebased PR #70 branch

The cache reuse is symmetric in design (same pattern as sendMessage's
cache, which has been there for months) but interacts badly with
Firefox/WebKit reload + tab semantics. The cached CryptoKey reference
appears to behave differently across these browsers when getCurrentKeys
returns a freshly-deserialized key from IndexedDB after a page reload —
the invalidation guard `cachedSenderPrivateKey !== currentKeys.privateKey`
was likely thrashing or holding a stale reference.

Hotfix: getMessageHistory now derives a fresh shared secret per call,
matching pre-batch-8 behavior. The cache infrastructure remains in place
(sendMessage still uses it as before) — this revert is read-path only.

Cost: ~6 ECDH derivations/min under polling — measurable but not
user-perceivable. A browser-safe instance-aware cache key can return as
a separate change once the Firefox CryptoKey-reference behavior is
properly understood.

Verification:
- pnpm run type-check: clean
- pnpm run lint: clean
- pnpm test: 3237/3237 pass

Refs: #74 (introduced regression), runs 25306048649 (last green),
25332113434 (first red post-batch-8)

Co-authored-by: TurtleWolfe <TurtleWolfe@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lume

Docker named volumes inherit permissions from the image directory on
first mount. Without pre-creating /app/node_modules as node:node, the
volume root stays root:root, causing EACCES on container start when
pnpm runs as node and tries to recreate .bin.

Latent bug: as long as the volume is reused across up/down cycles,
ownership stays correct. Bites only on volume reset
(docker volume rm scripthammer_node_modules, docker compose down -v,
or first-startup of a fresh-clone fork). Phase 1a (GrimGlow browser
fork), Phase 2 (RN ScriptHammer), and Phase 3 (KDG-stack) all hit
this on first up.

Mirrors the ce0e64d fix that originally landed for .next. The .next
fix had been removed during 7bdb86a refactor; this commit restores
it alongside the new node_modules treatment so both volumes inherit
node ownership on first mount.

Tested:
- docker compose down && docker volume rm scripthammer_node_modules
  scripthammer_next_cache && docker compose build && docker compose up -d
- Container reaches healthy state, no EACCES in logs
- docker run --rm -v scripthammer_node_modules:/v alpine ls -ld /v
  reports 1000:1000 (was root:root before fix)

Closes #69
Refs: ce0e64d, 7bdb86a, ~/repos/TranScripts/Docker/Docker_Edited/nodejs_rocks_in_docker_dockercon2023.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TortoiseWolfe TortoiseWolfe force-pushed the 69/node-modules-volume-permissions branch from 33e7b80 to ff81662 Compare May 5, 2026 02:12
@TortoiseWolfe TortoiseWolfe merged commit c8b439b into main May 5, 2026
28 checks passed
@TortoiseWolfe TortoiseWolfe deleted the 69/node-modules-volume-permissions branch May 5, 2026 04:17
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.

fix(docker): pre-create /app/node_modules with node ownership for named volume

2 participants