Skip to content

Commit 5f79d23

Browse files
committed
Merge branch 'master' of https://github.com/The-OpenROAD-Project-private/OpenROAD-flow-scripts into secure-yosys_fix
2 parents 3124684 + 6dbbfc7 commit 5f79d23

7 files changed

Lines changed: 460 additions & 9 deletions

File tree

claude.sh

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#!/usr/bin/env bash
2+
# Wrapper to run Claude Code inside a Docker container with
3+
# --dangerously-skip-permissions. The repo is volume-mounted so all
4+
# edits are reflected on the host.
5+
#
6+
# Usage:
7+
# ./claude.sh --build # build the Docker image (one-time)
8+
# ./claude.sh # start Claude Code interactively
9+
# ./claude.sh --shell # get a bash shell instead
10+
# ./claude.sh -- -p "prompt" # pass extra args to claude
11+
12+
set -euo pipefail
13+
14+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15+
16+
# --- Defaults (overridable via environment) ---
17+
CLAUDE_IMAGE="${CLAUDE_IMAGE:-openroad/flow-claude:latest}"
18+
CONTAINER_NAME="${CONTAINER_NAME:-claude-orfs}"
19+
20+
# --- Argument parsing ---
21+
SHELL_MODE=0
22+
BUILD_IMAGE=0
23+
CLAUDE_ARGS=()
24+
25+
usage() {
26+
cat <<EOF
27+
Usage: $0 [OPTIONS] [-- CLAUDE_ARGS...]
28+
29+
Options:
30+
--build Build the Docker image
31+
--shell Start a bash shell instead of Claude Code
32+
--image NAME Override Docker image (default: ${CLAUDE_IMAGE})
33+
--name NAME Override container name (default: ${CONTAINER_NAME})
34+
-h, --help Show this help
35+
36+
Environment:
37+
CLAUDE_IMAGE Docker image override (same as --image).
38+
CONTAINER_NAME Container name override (same as --name).
39+
ANTHROPIC_API_KEY Optional. Passed through if set.
40+
41+
Examples:
42+
$0 --build # build the image
43+
$0 # interactive Claude Code
44+
$0 -- -p "fix the floorplan" # Claude with a prompt
45+
$0 --shell # bash inside the container
46+
EOF
47+
exit 0
48+
}
49+
50+
while [[ $# -gt 0 ]]; do
51+
case "$1" in
52+
--build) BUILD_IMAGE=1; shift ;;
53+
--shell) SHELL_MODE=1; shift ;;
54+
--image) CLAUDE_IMAGE="$2"; shift 2 ;;
55+
--name) CONTAINER_NAME="$2"; shift 2 ;;
56+
-h|--help) usage ;;
57+
--) shift; CLAUDE_ARGS=("$@"); break ;;
58+
*) CLAUDE_ARGS+=("$1"); shift ;;
59+
esac
60+
done
61+
62+
# --- Build image (explicitly or automatically if missing) ---
63+
_build_image() {
64+
echo "Building Claude Code Docker image: ${CLAUDE_IMAGE}"
65+
docker build \
66+
-f "${SCRIPT_DIR}/docker/Dockerfile.claude" \
67+
-t "${CLAUDE_IMAGE}" \
68+
"${SCRIPT_DIR}/docker"
69+
echo "Done. Image: ${CLAUDE_IMAGE}"
70+
}
71+
72+
if [[ "${BUILD_IMAGE}" -eq 1 ]]; then
73+
_build_image
74+
# If only --build was given, exit.
75+
if [[ "${SHELL_MODE}" -eq 0 ]] && [[ ${#CLAUDE_ARGS[@]} -eq 0 ]]; then
76+
exit 0
77+
fi
78+
elif ! docker image inspect "${CLAUDE_IMAGE}" > /dev/null 2>&1; then
79+
echo "Image ${CLAUDE_IMAGE} not found. Building automatically..."
80+
_build_image
81+
fi
82+
83+
# --- Determine the user's home inside the container ---
84+
# The entrypoint creates /home/claude-user for the mapped user.
85+
CONTAINER_HOME="/home/claude-user"
86+
87+
# --- Assemble docker run arguments ---
88+
DOCKER_RUN_ARGS=(
89+
--rm
90+
--name "${CONTAINER_NAME}"
91+
-v "${SCRIPT_DIR}:/workspace"
92+
-e "HOST_UID=$(id -u)"
93+
-e "HOST_GID=$(id -g)"
94+
-w /workspace
95+
)
96+
97+
# TTY/stdin handling for interactive, CI, and piped-input cases:
98+
# * terminal in + terminal out → -it (normal interactive use)
99+
# * anything else → -i (pass stdin through; no TTY)
100+
# Forcing -it unconditionally breaks non-interactive use
101+
# ("cannot attach stdin to a TTY-enabled container"), and dropping -i
102+
# would silently discard piped input like `cat prompt.txt | claude.sh ...`.
103+
if [[ -t 0 && -t 1 ]]; then
104+
DOCKER_RUN_ARGS+=(-it)
105+
else
106+
DOCKER_RUN_ARGS+=(-i)
107+
fi
108+
109+
# Pass through optional environment variables
110+
for var in ANTHROPIC_API_KEY ANTHROPIC_MODEL CLAUDE_CODE_MAX_TURNS \
111+
CLAUDE_CODE_USE_BEDROCK \
112+
AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_REGION \
113+
GOOGLE_APPLICATION_CREDENTIALS; do
114+
if [[ -v "$var" ]] && [[ -n "${!var}" ]]; then
115+
DOCKER_RUN_ARGS+=(-e "${var}=${!var}")
116+
fi
117+
done
118+
119+
# SSH agent forwarding (for git push/pull over SSH)
120+
if [[ -n "${SSH_AUTH_SOCK:-}" ]]; then
121+
DOCKER_RUN_ARGS+=(
122+
-v "${SSH_AUTH_SOCK}:/tmp/ssh-agent.sock"
123+
-e "SSH_AUTH_SOCK=/tmp/ssh-agent.sock"
124+
)
125+
fi
126+
127+
# Host gitconfig (read-only, for user.name / user.email)
128+
if [[ -f "${HOME}/.gitconfig" ]]; then
129+
DOCKER_RUN_ARGS+=(-v "${HOME}/.gitconfig:${CONTAINER_HOME}/.gitconfig:ro")
130+
fi
131+
132+
# Persist Claude Code settings / history / memory across runs
133+
CLAUDE_CONFIG_DIR="${HOME}/.claude"
134+
mkdir -p "${CLAUDE_CONFIG_DIR}"
135+
DOCKER_RUN_ARGS+=(-v "${CLAUDE_CONFIG_DIR}:${CONTAINER_HOME}/.claude")
136+
137+
# Claude Code config file (lives next to ~/.claude/, not inside it)
138+
if [[ -f "${HOME}/.claude.json" ]]; then
139+
DOCKER_RUN_ARGS+=(-v "${HOME}/.claude.json:${CONTAINER_HOME}/.claude.json")
140+
fi
141+
142+
# Persist Bazel cache (avoids re-downloading hundreds of MB each run)
143+
BAZEL_CACHE_DIR="${BAZEL_CACHE_DIR:-${HOME}/.cache/bazel-claude}"
144+
mkdir -p "${BAZEL_CACHE_DIR}"
145+
DOCKER_RUN_ARGS+=(-v "${BAZEL_CACHE_DIR}:${CONTAINER_HOME}/.cache/bazel")
146+
147+
# --- Run ---
148+
if [[ "${SHELL_MODE}" -eq 1 ]]; then
149+
exec docker run \
150+
"${DOCKER_RUN_ARGS[@]}" \
151+
"${CLAUDE_IMAGE}" \
152+
bash
153+
else
154+
exec docker run \
155+
"${DOCKER_RUN_ARGS[@]}" \
156+
"${CLAUDE_IMAGE}" \
157+
claude --dangerously-skip-permissions "${CLAUDE_ARGS[@]}"
158+
fi

docker/Dockerfile.claude

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Docker image for running Claude Code with --dangerously-skip-permissions
2+
# inside a container that can build/test OpenROAD (CMake + Bazel) and run ORFS.
3+
#
4+
# Usage: see claude.sh at the repo root.
5+
6+
ARG fromImage=openroad/flow-ubuntu22.04-dev:latest
7+
8+
FROM ${fromImage}
9+
10+
# --- Bazel support ---
11+
12+
# Java 21 (required by Bazel 8.x)
13+
RUN apt-get update \
14+
&& apt-get install -y --no-install-recommends openjdk-21-jre-headless \
15+
&& rm -rf /var/lib/apt/lists/*
16+
17+
# Bazelisk (respects .bazelversion to download the correct Bazel release)
18+
RUN curl -Lo /usr/local/bin/bazelisk \
19+
https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 \
20+
&& chmod +x /usr/local/bin/bazelisk \
21+
&& ln -sf /usr/local/bin/bazelisk /usr/local/bin/bazel
22+
23+
# --- Claude Code support ---
24+
25+
# Node.js 22 LTS (Claude Code requires Node 18+)
26+
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
27+
&& apt-get install -y --no-install-recommends nodejs \
28+
&& rm -rf /var/lib/apt/lists/*
29+
30+
# Claude Code CLI
31+
RUN npm install -g @anthropic-ai/claude-code
32+
33+
# --- Convenience ---
34+
35+
RUN apt-get update \
36+
&& apt-get install -y --no-install-recommends \
37+
sudo \
38+
less \
39+
jq \
40+
ripgrep \
41+
&& rm -rf /var/lib/apt/lists/*
42+
43+
# VS Code CLI (code-tunnel for remote editing).
44+
# Use the glibc build to match the Ubuntu base image. (The cli-alpine-x64
45+
# variant on code.visualstudio.com is statically linked and also works,
46+
# but the linux-x64 build from update.code.visualstudio.com is the
47+
# canonical match for glibc distros.)
48+
RUN curl -fsSL "https://update.code.visualstudio.com/latest/cli-linux-x64/stable" \
49+
-o /tmp/vscode-cli.tar.gz \
50+
&& tar -xzf /tmp/vscode-cli.tar.gz -C /usr/local/bin \
51+
&& rm /tmp/vscode-cli.tar.gz
52+
53+
# Trust all directories (safe inside container; the container IS the boundary)
54+
RUN git config --system safe.directory '*'
55+
56+
# Entrypoint that maps host UID/GID then drops privileges
57+
COPY claude-entrypoint.sh /usr/local/bin/claude-entrypoint.sh
58+
RUN chmod +x /usr/local/bin/claude-entrypoint.sh
59+
60+
WORKDIR /workspace
61+
ENTRYPOINT ["claude-entrypoint.sh"]

docker/claude-entrypoint.sh

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env bash
2+
# Entrypoint for the Claude Code container.
3+
# Creates a user matching the host UID/GID so that files created
4+
# inside the container have the correct ownership on the host volume.
5+
set -e
6+
7+
if [ -n "${HOST_UID}" ] && [ -n "${HOST_GID}" ]; then
8+
USER_NAME="claude-user"
9+
USER_HOME="/home/${USER_NAME}"
10+
11+
# Create group (reuse existing if GID is taken)
12+
if ! getent group "${HOST_GID}" > /dev/null 2>&1; then
13+
groupadd --gid "${HOST_GID}" "${USER_NAME}"
14+
fi
15+
GROUP_NAME=$(getent group "${HOST_GID}" | cut -d: -f1)
16+
17+
# Create user (reuse existing if UID is taken)
18+
if ! getent passwd "${HOST_UID}" > /dev/null 2>&1; then
19+
mkdir -p "${USER_HOME}"
20+
useradd \
21+
--uid "${HOST_UID}" \
22+
--gid "${HOST_GID}" \
23+
--groups sudo \
24+
--no-create-home \
25+
--home-dir "${USER_HOME}" \
26+
--shell /bin/bash \
27+
"${USER_NAME}"
28+
else
29+
USER_NAME=$(getent passwd "${HOST_UID}" | cut -d: -f1)
30+
USER_HOME=$(getent passwd "${HOST_UID}" | cut -d: -f6)
31+
fi
32+
33+
# Passwordless sudo
34+
echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/claude-user
35+
chmod 0440 /etc/sudoers.d/claude-user
36+
37+
export HOME="${USER_HOME}"
38+
chown "${HOST_UID}:${HOST_GID}" "${USER_HOME}"
39+
touch "${USER_HOME}/.hushlogin"
40+
41+
# Set up ORFS environment (PATH to tools, FLOW_HOME, etc.)
42+
# Sourced here; inherited through setpriv into all child processes.
43+
if [ -f /workspace/env.sh ]; then
44+
set +e
45+
. /workspace/env.sh > /dev/null
46+
set -e
47+
fi
48+
49+
exec setpriv \
50+
--reuid "${HOST_UID}" \
51+
--regid "${HOST_GID}" \
52+
--init-groups \
53+
-- "$@"
54+
else
55+
# No UID/GID mapping requested; run as root
56+
if [ -f /workspace/env.sh ]; then
57+
set +e
58+
. /workspace/env.sh > /dev/null
59+
set -e
60+
fi
61+
exec "$@"
62+
fi

docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ entries:
1111
entries:
1212
- file: user/DockerShell.md
1313
title: Docker Shell utility
14+
- file: user/ClaudeCode.md
15+
title: Claude Code in Docker
1416
- file: user/BuildLocally.md
1517
title: Build Locally
1618
- file: user/BuildWithWSL.md

0 commit comments

Comments
 (0)