fix: プラグインインストールを vscode ユーザーで実行 - #635
Conversation
root で実行すると claude バイナリにアクセスできない問題を修正。 BuildKit secret を一時ファイルにコピーし、vscode ユーザーで install-claude-plugins.sh を実行するように変更。 - Dockerfile: secret を /tmp/claude-secret/token にコピー後、USER vscode で実行 - install-claude-plugins.sh: /tmp/claude-secret/token もシークレットソースとして探索 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughRefactors DevContainer Claude plugin installation to copy BuildKit-mounted credentials into a temporary file as root, run the installer as the Changes
Sequence Diagram(s)sequenceDiagram
participant BuildKit as BuildKit (secret mount)
participant Docker as Dockerfile build
participant Root as root (build stage)
participant VSCode as vscode (user)
participant Installer as /tmp/install-claude-plugins.sh
participant FS as Filesystem (/home/vscode/.claude)
BuildKit->>Docker: mount secret at /run/secrets/claude_credentials
Docker->>Root: RUN step creates /tmp/claude-secret/token (copy, chmod)
Root->>VSCode: switch USER to vscode
VSCode->>Installer: execute installer (probes /run/secrets/... and /tmp/claude-secret/token)
Installer->>FS: install plugins under /home/vscode/.claude
VSCode->>Root: return to root user
Root->>Root: remove /tmp/claude-secret
Root->>FS: chown -R vscode:vscode /home/vscode/.claude
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly Related PRs
Suggested Labels
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 62cda75006
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| env HOME=/home/vscode CLAUDE_CODE_OAUTH_TOKEN="${CLAUDE_CODE_OAUTH_TOKEN}" ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY}" /tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt || ( \ | ||
| mkdir -p /tmp/claude-secret \ | ||
| && if [ -f /run/secrets/claude_credentials ]; then \ | ||
| cp /run/secrets/claude_credentials /tmp/claude-secret/token && \ |
There was a problem hiding this comment.
Avoid persisting secret token in image layers
Copying /run/secrets/claude_credentials into /tmp/claude-secret/token inside a standalone RUN step writes the credential into a committed image layer, and deleting it later in another layer does not remove the underlying bytes. When a real BuildKit secret is supplied, this can leak auth material to anyone with access to the image or layer cache. Keep secret use within a single secret-mounted RUN so it is never persisted.
Useful? React with 👍 / 👎.
| ) \ | ||
| && chown -R vscode:vscode /home/vscode/.claude | ||
| ) | ||
| RUN rm -rf /tmp/claude-secret |
There was a problem hiding this comment.
Clean up temp secret directory with root privileges
/tmp/claude-secret is created in the previous layer while running as root, but cleanup (rm -rf /tmp/claude-secret) now runs as vscode. On typical Ubuntu /tmp (sticky bit) with root-owned entries, this deletion is not permitted for non-owner users, so the Docker build can fail at this step even after successful plugin installation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
.devcontainer/Dockerfile (1)
186-192: Consider stricter permissions on the temp credentials file.
chmod 644makes the token world-readable. While the file is temporary and deleted after use,chmod 600(or640) would follow the principle of least privilege.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.devcontainer/Dockerfile around lines 186 - 192, The temporary credential file /tmp/claude-secret/token is made world-readable via the chmod 644 step in the RUN block; change the permission to a more restrictive mode (e.g., chmod 600 or 640) in that same RUN command that creates and copies the secret to /tmp/claude-secret/token so the token is only readable by the owner (and group if chosen) while preserving the rest of the flow that copies and later removes the file.script/install-claude-plugins.sh (1)
101-105: Consider showing searched paths in error message.When
CREDENTIALS_SECRETis empty, line 103 outputs an unhelpful blank value. Showing the paths that were checked would aid debugging.💡 Suggested improvement
else log_warn "認証情報が見つかりません" - echo " - BuildKit secret: $CREDENTIALS_SECRET" + echo " - BuildKit secret paths checked: /run/secrets/claude_credentials, /tmp/claude-secret/token" echo " - 環境変数: CLAUDE_CODE_OAUTH_TOKEN または ANTHROPIC_API_KEY" exit 1 fi🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@script/install-claude-plugins.sh` around lines 101 - 105, The error branch that calls log_warn "認証情報が見つかりません" prints an empty CREDENTIALS_SECRET which is unhelpful; update that block to also print the specific locations the script searched for credentials (e.g., the value of CREDENTIALS_SECRET and any search list variable such as CREDENTIALS_SEARCH_PATHS or other path variables used when resolving credentials), and keep the existing hints about CLAUDE_CODE_OAUTH_TOKEN and ANTHROPIC_API_KEY; modify the echo lines in the else branch that reference CREDENTIALS_SECRET so they show the checked paths or filenames (or the variable name that holds them) to aid debugging while still calling log_warn and exit 1.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.devcontainer/Dockerfile:
- Around line 193-200: The cleanup of /tmp/claude-secret is executed while USER
is vscode (see the RUN /tmp/install-claude-plugins.sh ... line and the
subsequent RUN rm -rf /tmp/claude-secret), but the temp dir was created by root;
either move the rm -rf /tmp/claude-secret to run as root (after the final USER
root) or ensure the directory is created/chowned to vscode before switching
users; update the Dockerfile so the RUN rm -rf /tmp/claude-secret executes with
root privileges (or add chown to give vscode ownership prior to the deletion)
and keep the USER switching (USER vscode / USER root) consistent with that
change.
---
Nitpick comments:
In @.devcontainer/Dockerfile:
- Around line 186-192: The temporary credential file /tmp/claude-secret/token is
made world-readable via the chmod 644 step in the RUN block; change the
permission to a more restrictive mode (e.g., chmod 600 or 640) in that same RUN
command that creates and copies the secret to /tmp/claude-secret/token so the
token is only readable by the owner (and group if chosen) while preserving the
rest of the flow that copies and later removes the file.
In `@script/install-claude-plugins.sh`:
- Around line 101-105: The error branch that calls log_warn "認証情報が見つかりません"
prints an empty CREDENTIALS_SECRET which is unhelpful; update that block to also
print the specific locations the script searched for credentials (e.g., the
value of CREDENTIALS_SECRET and any search list variable such as
CREDENTIALS_SEARCH_PATHS or other path variables used when resolving
credentials), and keep the existing hints about CLAUDE_CODE_OAUTH_TOKEN and
ANTHROPIC_API_KEY; modify the echo lines in the else branch that reference
CREDENTIALS_SECRET so they show the checked paths or filenames (or the variable
name that holds them) to aid debugging while still calling log_warn and exit 1.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 62a57380-2635-4780-875a-c99d0a3a8cb0
📒 Files selected for processing (2)
.devcontainer/Dockerfilescript/install-claude-plugins.sh
コードレビュー概要root ユーザーで claude バイナリにアクセスできなかった問題の根本原因を正しく特定しており、アプローチの方向性は妥当です。 重大な問題セキュリティ: secret が中間レイヤーに残留する現在のコードでは 推奨する修正 ① : RUN --mount=type=secret,id=claude_credentials,uid=0,gid=0 \
mkdir -p /tmp/claude-secret \
&& if [ -f /run/secrets/claude_credentials ]; then \
cp /run/secrets/claude_credentials /tmp/claude-secret/token \
&& chmod 600 /tmp/claude-secret/token; \
fi \
&& su vscode -c "/tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt" \
|| (echo "[WARN] プラグインインストール失敗"; echo "[INFO] 手動インストールしてください") \
; rm -rf /tmp/claude-secret \
&& chown -R vscode:vscode /home/vscode/.claude推奨する修正 ② (よりクリーン) : secret の uid を vscode に設定 vscode ユーザーが uid=1000 の場合、コピー不要で直接アクセス可能です。 USER vscode
RUN --mount=type=secret,id=claude_credentials,uid=1000,gid=1000 \
/tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt \
|| (echo "[WARN] プラグインインストール失敗"; echo "[INFO] 手動インストールしてください")
USER root
RUN chown -R vscode:vscode /home/vscode/.claude軽微な問題
|
| 項目 | 評価 |
|---|---|
| 問題の原因特定 | ✅ 正確 |
| アプローチの方向性 | ✅ 妥当 |
| セキュリティ(レイヤー残留) | |
| 環境変数の伝達 | ❓ 要確認 |
| コードの複雑度 |
上記のうち「secret の中間レイヤー残留」は認証情報漏洩リスクがあるため、マージ前に対処を推奨します。修正 ② の --mount=type=secret,uid=1000 アプローチが最もシンプルで安全です。
🤖 Generated with Claude Code
root で作成したディレクトリを vscode ユーザーで rm できない問題を修正。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.devcontainer/Dockerfile:
- Around line 187-200: The Dockerfile currently copies the BuildKit secret into
a layer (creating /tmp/claude-secret/token with mode 644) then removes it in a
later RUN, leaving the token recoverable; fix by consolidating the secret copy,
plugin install, and cleanup into a single RUN so the token never persists across
layers, switch to the vscode user inside that same RUN when invoking
/tmp/install-claude-plugins.sh (or run the install script via sudo -u vscode),
and set restrictive permissions (600) on the temporary token file before running
the installer; ensure the RUN references the same paths
(/run/secrets/claude_credentials, /tmp/claude-secret/token,
/home/vscode/.claude) and the installer script name
(/tmp/install-claude-plugins.sh) so the steps are performed atomically and the
secret is removed at the end of that same RUN.
| RUN --mount=type=secret,id=claude_credentials,uid=0,gid=0 \ | ||
| env HOME=/home/vscode CLAUDE_CODE_OAUTH_TOKEN="${CLAUDE_CODE_OAUTH_TOKEN}" ANTHROPIC_API_KEY="${ANTHROPIC_API_KEY}" /tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt || ( \ | ||
| mkdir -p /tmp/claude-secret \ | ||
| && if [ -f /run/secrets/claude_credentials ]; then \ | ||
| cp /run/secrets/claude_credentials /tmp/claude-secret/token && \ | ||
| chmod 644 /tmp/claude-secret/token; \ | ||
| fi | ||
| USER vscode | ||
| RUN /tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt || ( \ | ||
| echo "[WARN] Claude プラグインのインストールに失敗しました(認証情報が不足している可能性があります)" && \ | ||
| echo "[INFO] コンテナ起動後に手動でインストールしてください: claude plugin install <plugin>@<marketplace>" \ | ||
| ) \ | ||
| && chown -R vscode:vscode /home/vscode/.claude | ||
| ) | ||
| USER root | ||
| RUN rm -rf /tmp/claude-secret \ | ||
| && chown -R vscode:vscode /home/vscode/.claude |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .devcontainer/Dockerfile | sed -n '180,210p'Repository: keito4/config
Length of output: 1714
🏁 Script executed:
# Look at the install script to understand dependencies
cat -n /tmp/install-claude-plugins.sh 2>/dev/null || find .devcontainer -name "*install-claude*" -type fRepository: keito4/config
Length of output: 39
🏁 Script executed:
find .devcontainer -name "*install-claude*" -type fRepository: keito4/config
Length of output: 39
🏁 Script executed:
# Search for install-claude-plugins references
rg "install-claude-plugins" .devcontainer/Repository: keito4/config
Length of output: 280
🏁 Script executed:
cat -n script/install-claude-plugins.shRepository: keito4/config
Length of output: 5443
🏁 Script executed:
# Check if this is single or multi-stage build and see the base image
head -50 .devcontainer/Dockerfile | cat -nRepository: keito4/config
Length of output: 1760
🏁 Script executed:
# Check the coding guidelines to see if there's a base image requirement
grep -i "base image" .devcontainer/Dockerfile | head -5Repository: keito4/config
Length of output: 172
🏁 Script executed:
# Confirm the actual BuildKit secret behavior with a quick check of Docker documentation and layer behavior
# Verify that secrets mounted with --mount are NOT persisted in layers
cat <<'EOF' > /tmp/test_analysis.py
# Docker BuildKit secret semantics:
# --mount=type=secret mounts read-only at /run/secrets/ID
# This mount is temporary and NOT included in the layer
# BUT: If you CP that secret to another path, that copy IS included in the layer
# So the concern is valid: copying secret to /tmp/... and deleting later leaves it in earlier layer
print("Docker BuildKit secret analysis:")
print("1. --mount=type=secret,id=X: Temporary, not in layer")
print("2. COPY from /run/secrets/X to /tmp/...: Creates committed copy in layer")
print("3. DELETE in later RUN: Does NOT remove from earlier layer")
print("\nConclusion: Original review concern is CORRECT")
print("Solution: Single RUN to copy→install→delete before layer commit")
EOF
python3 /tmp/test_analysis.pyRepository: keito4/config
Length of output: 386
Don't bake the Claude token into an image layer.
Lines 187–200 copy the BuildKit secret into /tmp/claude-secret/token in one RUN, then delete it in a later RUN. In a single-stage Docker build, this leaves the token recoverable from the earlier layer. Additionally, line 191 uses mode 644, which is unnecessarily readable. Consolidate the copy, install, and cleanup into a single RUN instruction, switch to vscode within that step, and use restrictive permissions (600) so the secret never lands in a committed layer.
🔐 Safer one-layer pattern
-# Note: Secret is copied to a temp file readable by vscode, then plugin install runs as vscode
-RUN --mount=type=secret,id=claude_credentials,uid=0,gid=0 \
- mkdir -p /tmp/claude-secret \
- && if [ -f /run/secrets/claude_credentials ]; then \
- cp /run/secrets/claude_credentials /tmp/claude-secret/token && \
- chmod 644 /tmp/claude-secret/token; \
- fi
-USER vscode
-RUN /tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt || ( \
- echo "[WARN] Claude プラグインのインストールに失敗しました(認証情報が不足している可能性があります)" && \
- echo "[INFO] コンテナ起動後に手動でインストールしてください: claude plugin install <plugin>@<marketplace>" \
- )
-USER root
-RUN rm -rf /tmp/claude-secret \
- && chown -R vscode:vscode /home/vscode/.claude
+RUN --mount=type=secret,id=claude_credentials,uid=0,gid=0 \
+ set -eu; \
+ install -d -m 700 -o vscode -g vscode /tmp/claude-secret; \
+ if [ -f /run/secrets/claude_credentials ]; then \
+ install -m 600 -o vscode -g vscode /run/secrets/claude_credentials /tmp/claude-secret/token; \
+ fi; \
+ su -s /bin/bash vscode -c 'HOME=/home/vscode /tmp/install-claude-plugins.sh /home/vscode/.claude/plugins/plugins.txt' || { \
+ echo "[WARN] Claude プラグインのインストールに失敗しました(認証情報が不足している可能性があります)"; \
+ echo "[INFO] コンテナ起動後に手動でインストールしてください: claude plugin install <plugin>@<marketplace>"; \
+ }; \
+ rm -rf /tmp/claude-secret; \
+ chown -R vscode:vscode /home/vscode/.claude🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.devcontainer/Dockerfile around lines 187 - 200, The Dockerfile currently
copies the BuildKit secret into a layer (creating /tmp/claude-secret/token with
mode 644) then removes it in a later RUN, leaving the token recoverable; fix by
consolidating the secret copy, plugin install, and cleanup into a single RUN so
the token never persists across layers, switch to the vscode user inside that
same RUN when invoking /tmp/install-claude-plugins.sh (or run the install script
via sudo -u vscode), and set restrictive permissions (600) on the temporary
token file before running the installer; ensure the RUN references the same
paths (/run/secrets/claude_credentials, /tmp/claude-secret/token,
/home/vscode/.claude) and the installer script name
(/tmp/install-claude-plugins.sh) so the steps are performed atomically and the
secret is removed at the end of that same RUN.
|
🎉 This PR is included in version 1.106.3 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Summary
Why
root ユーザーで
install-claude-plugins.shを実行すると、vscode ユーザーとしてインストールされたclaudeバイナリにアクセスできず、全15プラグインのインストールが失敗していた。What
Dockerfile
/tmp/claude-secret/tokenにコピーUSER vscodeに切り替えてからプラグインインストールを実行USER rootに戻って権限修正install-claude-plugins.sh
/run/secrets/claude_credentials(従来)と/tmp/claude-secret/token(新)の両方を探索Test plan
Claude version: x.x.xが表示されること0 失敗)🤖 Generated with Claude Code
Summary by CodeRabbit