npm automatically picks up GITHUB_TOKEN / NPM_TOKEN from the build environment and writes them as _authToken entries in /root/.npmrc and /usr/local/etc/npmrc during 'npm install -g'. Add a cleanup RUN step that removes any npmrc file containing auth tokens before the image is finalised, and explicitly deletes the two most common registry auth keys via 'npm config delete'. Also add .npmrc to .dockerignore as an extra guard against accidentally COPY-ing a local credential file into the build context. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
90 lines
3.8 KiB
Docker
90 lines
3.8 KiB
Docker
FROM node:24-alpine
|
|
|
|
# Upgrade npm to pull in patched bundled deps (cross-spawn, glob, minimatch, tar)
|
|
# CVEs: CVE-2024-21538, CVE-2025-64756, CVE-2026-26996/27903/27904, CVE-2026-23745/23950/24842/26960/29786/31802
|
|
RUN npm install -g npm@11.12.1
|
|
|
|
# Fix CVE-2026-33671: upgrade picomatch 4.0.3 → 4.0.4 in every location it appears
|
|
RUN find /usr/local/lib/node_modules -name "picomatch" -type d | while read dir; do \
|
|
ver=$(node -p "require('$dir/package.json').version" 2>/dev/null); \
|
|
[ "$ver" = "4.0.3" ] || continue; \
|
|
echo "Patching picomatch in $dir"; \
|
|
prefix=$(dirname "$(dirname "$dir")"); \
|
|
npm install --prefix "$prefix" picomatch@4.0.4 \
|
|
--no-save --no-audit --no-fund 2>/dev/null || true; \
|
|
done
|
|
|
|
# Install runtime dependencies
|
|
RUN apk add --no-cache \
|
|
git \
|
|
curl \
|
|
ca-certificates \
|
|
bash
|
|
|
|
# Install kubectl — architecture-aware, checksum-verified
|
|
RUN KUBECTL_VERSION=$(curl -fsSL https://dl.k8s.io/release/stable.txt) \
|
|
&& ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') \
|
|
&& curl -fsSL "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl" \
|
|
-o /usr/local/bin/kubectl \
|
|
&& curl -fsSL "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl.sha256" \
|
|
-o /tmp/kubectl.sha256 \
|
|
&& echo "$(cat /tmp/kubectl.sha256) /usr/local/bin/kubectl" | sha256sum -c \
|
|
&& rm /tmp/kubectl.sha256 \
|
|
&& chmod +x /usr/local/bin/kubectl
|
|
|
|
# System-level Claude Code policy — owned by root, not writable by the node user.
|
|
# Restricts available models; cannot be bypassed via CLI flags or env vars.
|
|
COPY settings.json /etc/claude-code/managed-settings.json
|
|
|
|
# Install Claude Code stable release
|
|
RUN curl -fsSL https://claude.ai/install.sh | bash -s stable
|
|
|
|
# Install MCP servers globally — entry points land in /usr/local/lib/node_modules/
|
|
RUN npm install -g \
|
|
@modelcontextprotocol/server-github \
|
|
@yoda.digital/gitlab-mcp-server \
|
|
@aashari/mcp-server-atlassian-jira \
|
|
@aashari/mcp-server-atlassian-confluence
|
|
|
|
# Patch transitive CVEs bundled inside MCP server node_modules:
|
|
# CVE-2025-66414, CVE-2026-0621 — @modelcontextprotocol/sdk <1.25.2
|
|
# CVE-2026-33671 — picomatch <4.0.4 (also covers npm bundled copy above)
|
|
RUN for pkg_dir in \
|
|
/usr/local/lib/node_modules/@modelcontextprotocol/server-github \
|
|
/usr/local/lib/node_modules/@yoda.digital/gitlab-mcp-server \
|
|
/usr/local/lib/node_modules/@aashari/mcp-server-atlassian-jira \
|
|
/usr/local/lib/node_modules/@aashari/mcp-server-atlassian-confluence; do \
|
|
[ -d "$pkg_dir" ] && \
|
|
cd "$pkg_dir" && \
|
|
npm install --no-audit --no-fund \
|
|
@modelcontextprotocol/sdk@1.25.2 \
|
|
picomatch@4.0.4 \
|
|
|| true; \
|
|
done
|
|
|
|
# Remove any npm auth credentials written during install.
|
|
# npm automatically picks up GITHUB_TOKEN and NPM_TOKEN from the build environment
|
|
# and persists them in .npmrc files — scrub all of them before the image is finalised.
|
|
RUN find /root /home /usr/local/etc -name ".npmrc" -o -name "npmrc" \
|
|
| xargs grep -l "_authToken\|_auth\b" 2>/dev/null \
|
|
| xargs rm -f 2>/dev/null || true \
|
|
&& npm config delete //npm.pkg.github.com/:_authToken 2>/dev/null || true \
|
|
&& npm config delete //registry.npmjs.org/:_authToken 2>/dev/null || true
|
|
|
|
# Workspace and Claude config dir — owned by the built-in node user (uid 1000).
|
|
# Pre-creating ~/.claude ensures the named volume is initialised with the
|
|
# correct ownership when first mounted (Docker copies image content into
|
|
# an empty named volume on first use).
|
|
RUN mkdir -p /workspace /home/node/.claude \
|
|
&& chown -R node:node /workspace /home/node/.claude
|
|
|
|
USER node
|
|
WORKDIR /workspace
|
|
|
|
# Proxy traffic through sidecar — override at runtime if needed
|
|
ENV HTTP_PROXY=http://proxy:3128
|
|
ENV HTTPS_PROXY=http://proxy:3128
|
|
ENV ALL_PROXY=http://proxy:3128
|
|
ENV NO_PROXY=localhost,127.0.0.1
|
|
|
|
ENTRYPOINT ["claude"]
|