From 887bf38d9dc1d39f2354dd28ecfb874b58ee6413 Mon Sep 17 00:00:00 2001 From: Serge Gatezh <2880401+gatezh@users.noreply.github.com> Date: Tue, 12 May 2026 21:56:32 -0600 Subject: [PATCH] fix(claude-code): create /etc/claude-code as root so managed-settings is readable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BuildKit applies COPY --chmod to any parent directories it auto-creates, so "COPY --chmod=0644 managed-settings.json /etc/claude-code/managed-settings.json" landed the file inside a drw-r--r-- directory — no execute bit, not traversable by anyone in the container. The node user could not read the file even though the file mode itself was correct, and jq in the CI verify step failed with "Could not open file ... Permission denied". Pre-create the directory explicitly as root before the COPY, and copy the file with --chown=root:root so it matches normal /etc/ ownership conventions. Also add a test -r precondition to the verify-command so future breakage of this kind surfaces with a clear "file unreadable" failure before jq sees it. Verified locally: built --target base from the modified Dockerfile, confirmed /etc/claude-code is now drwxr-xr-x and managed-settings.json is -rw-r--r-- readable as the node user, and the full verify-command exits 0 under the exact bash -c wrapping the CI matrix uses. --- .github/workflows/build-claude-code.yml | 8 ++++---- claude-code/.devcontainer/Dockerfile | 12 ++++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-claude-code.yml b/.github/workflows/build-claude-code.yml index 405bf75..3f8b8e0 100644 --- a/.github/workflows/build-claude-code.yml +++ b/.github/workflows/build-claude-code.yml @@ -77,19 +77,19 @@ jobs: matrix: include: - image-suffix: claude-code - verify-command: "bun --version || true && claude --version && mise --version && fish --version && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp && printenv AGENT_BROWSER_EXECUTABLE_PATH | grep -qx /usr/bin/chromium" + verify-command: "bun --version || true && claude --version && mise --version && fish --version && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && test -r /etc/claude-code/managed-settings.json && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp && printenv AGENT_BROWSER_EXECUTABLE_PATH | grep -qx /usr/bin/chromium" runner: ubuntu-24.04 arch: amd64 - image-suffix: claude-code - verify-command: "bun --version || true && claude --version && mise --version && fish --version && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp && printenv AGENT_BROWSER_EXECUTABLE_PATH | grep -qx /usr/bin/chromium" + verify-command: "bun --version || true && claude --version && mise --version && fish --version && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && test -r /etc/claude-code/managed-settings.json && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp && printenv AGENT_BROWSER_EXECUTABLE_PATH | grep -qx /usr/bin/chromium" runner: ubuntu-24.04-arm arch: arm64 - image-suffix: claude-code-sandbox - verify-command: "claude --version && mise --version && fish --version && which iptables && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp" + verify-command: "claude --version && mise --version && fish --version && which iptables && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && test -r /etc/claude-code/managed-settings.json && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp" runner: ubuntu-24.04 arch: amd64 - image-suffix: claude-code-sandbox - verify-command: "claude --version && mise --version && fish --version && which iptables && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp" + verify-command: "claude --version && mise --version && fish --version && which iptables && rtk --version && ralphex --version && test -x /usr/local/bin/patch-playwright-mcp && test -r /etc/claude-code/managed-settings.json && jq -r '.hooks.SessionStart[0].hooks[0].command' /etc/claude-code/managed-settings.json | grep -qx /usr/local/bin/patch-playwright-mcp" runner: ubuntu-24.04-arm arch: arm64 runs-on: ${{ matrix.runner }} diff --git a/claude-code/.devcontainer/Dockerfile b/claude-code/.devcontainer/Dockerfile index 6c588a7..a20d18f 100644 --- a/claude-code/.devcontainer/Dockerfile +++ b/claude-code/.devcontainer/Dockerfile @@ -149,8 +149,16 @@ COPY --chmod=0755 patch-playwright-mcp.sh /usr/local/bin/patch-playwright-mcp # Image-policy settings at the Linux managed location (highest precedence, # outside any volume mount). Wires patch-playwright-mcp as a SessionStart hook # so cache dirs created by mid-session plugin auto-updates get patched before -# the next session reads them. See issue #98. -COPY --chmod=0644 managed-settings.json /etc/claude-code/managed-settings.json +# the next session reads them. See issues #98, #101. +# +# Pre-create /etc/claude-code as root: BuildKit applies COPY --chmod to any +# parent directories it auto-creates, which would leave the dir at mode 0644 +# (no execute bit, not traversable). Creating it explicitly avoids that and +# makes the file readable for the node user at runtime. +USER root +RUN mkdir -p /etc/claude-code +COPY --chown=root:root --chmod=0644 managed-settings.json /etc/claude-code/managed-settings.json +USER node # ── Claude Code CLI ─────────────────────────────────────────────────────────── # Using npm instead of the native installer (curl claude.ai/install.sh | bash).