Skip to content

Commit 0dba30e

Browse files
committed
feat(config): improve config validation and clarify volume mounts
- Centralize config error handling - Stricter validation and error reporting - Clarify /home/claude/ mounts and security in README - Suppress Node.js proxy warnings
1 parent cb8bc70 commit 0dba30e

2 files changed

Lines changed: 54 additions & 38 deletions

File tree

README.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Claude Code YOLO solves the permission friction of Claude CLI by running it insi
3939
4. **Non-root Execution**: Runs as a non-root user inside container with UID/GID mapping
4040
5. **Safety Checks**: Warns before running in dangerous directories like `$HOME`
4141

42+
**Container Info**: Claude runs as `claude` user in `/home/claude/` (not root). Mount configs to `/home/claude/` paths.
43+
4244
This gives you full Claude Code power without compromising your system security.
4345

4446
## Usage
@@ -143,12 +145,12 @@ Claude YOLO supports configuration files to persist your volume mounts, environm
143145

144146
Example `.claude-yolo` file:
145147
```bash
146-
# Git integration
148+
# Git integration - mount to claude user's home
147149
VOLUME=~/.ssh:/home/claude/.ssh:ro
148150
VOLUME=~/.gitconfig:/home/claude/.gitconfig:ro
149151

150-
# Environment settings
151-
ENV=NODE_ENV=development
152+
# Environment settings with expansion support
153+
ENV=NODE_ENV=${NODE_ENV:-development}
152154
ENV=DEBUG=myapp:*
153155

154156
# Pass through host env (either form works)
@@ -162,36 +164,46 @@ USE_TRACE=true
162164

163165
See `.claude-yolo.example` and `.claude-yolo.full` for more examples.
164166

167+
### Security Features
168+
169+
Configuration files include security protections:
170+
- **Path Traversal Prevention**: Blocks dangerous paths like `../../`
171+
- **Command Injection Protection**: Only allows safe variable expansion
172+
- **Sensitive Value Masking**: API keys, tokens, and secrets are masked in output (e.g., `API_KEY=sk-a***key`)
173+
- **Input Validation**: Environment variable names and values are validated
174+
165175
## Custom Volume Mounting
166176

167177
You can mount additional configuration files or directories using the `-v` flag:
168178

169179
```bash
170-
# Mount Git configuration
171-
claude-yolo -v ~/.gitconfig:/root/.gitconfig
180+
# Mount Git configuration to claude user's home
181+
claude-yolo -v ~/.gitconfig:/home/claude/.gitconfig:ro
172182

173183
# Mount SSH keys (read-only)
174-
claude-yolo -v ~/.ssh:/root/.ssh:ro
184+
claude-yolo -v ~/.ssh:/home/claude/.ssh:ro
175185

176186
# Resume with SSH keys and tracing enabled
177-
claude-yolo -v ~/.ssh:/root/.ssh:ro --trace --continue
187+
claude-yolo -v ~/.ssh:/home/claude/.ssh:ro --trace --continue
178188

179189
# Multiple mounts
180190
claude-yolo -v ~/tools:/tools -v ~/data:/data
181191

182-
# Mount custom tool configs
183-
claude-yolo -v ~/.config/gh:/root/.config/gh
184-
claude-yolo -v ~/.terraform.d:/root/.terraform.d
192+
# Mount custom tool configs to claude user paths
193+
claude-yolo -v ~/.config/gh:/home/claude/.config/gh:ro
194+
claude-yolo -v ~/.terraform.d:/home/claude/.terraform.d:ro
185195
```
186196

187-
**Note**: Volumes mounted to `/root/*` are automatically symlinked to `/home/claude/*` for non-root user access.
197+
**Note**: Mount personal configs to `/home/claude/` paths since Claude Code runs as the `claude` user, not root.
188198

189199
## Key Features
190200

191201
- **Full Dev Environment**: Python, Node.js, Go, Rust, and common tools pre-installed
192202
- **Proxy Support**: Automatic `localhost``host.docker.internal` translation
193203
- **Model Selection**: Use any Claude model via `ANTHROPIC_MODEL` env var
194204
- **Request Tracing**: Debug with `--trace` flag using claude-trace
205+
- **Security-First**: Sensitive environment variable masking and path validation
206+
- **Environment Expansion**: Support for `${VAR:-default}` syntax in config files
195207
- **Docker Socket**: Optional mounting with `CCYOLO_DOCKER_SOCKET=true`
196208

197209

@@ -231,7 +243,7 @@ make build
231243
### Custom Claude Version
232244

233245
```bash
234-
make CLAUDE_CODE_VERSION=1.0.45 build # Specific version
246+
make CLAUDE_CODE_VERSION=1.0.93 build # Specific version
235247
make CLAUDE_CODE_VERSION=latest build # Latest version
236248
```
237249

claude.sh

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ CONFIG_DIR=""
217217
SKIP_CONFIG=false
218218
QUIET=false
219219
DOCKER_ONLY_WARNINGS=()
220+
CONFIG_ERRORS=()
220221

221222
green() { echo -e "\033[32m$1\033[0m"; }
222223
yellow() { echo -e "\033[33m$1\033[0m"; }
@@ -355,13 +356,11 @@ validate_config_value() {
355356

356357
process_volume_config() {
357358
local value="$1"
358-
local errors_var="$2"
359-
declare -n errors_ref="$errors_var"
360-
359+
361360
value="${value//\"/}"
362361

363362
if ! validate_config_value "VOLUME" "$value"; then
364-
errors_ref+=("Invalid volume: $value")
363+
CONFIG_ERRORS+=("Invalid volume: $value")
365364
return 1
366365
fi
367366

@@ -373,19 +372,17 @@ process_volume_config() {
373372
EXTRA_VOLUMES+=("-v" "$value")
374373
DOCKER_ONLY_WARNINGS+=("Config volume mount: $value (ignored in local mode)")
375374
else
376-
errors_ref+=("Volume validation failed: $value")
375+
CONFIG_ERRORS+=("Volume validation failed: $value")
377376
fi
378377
}
379378

380379
process_env_config() {
381380
local value="$1"
382-
local errors_var="$2"
383-
declare -n errors_ref="$errors_var"
384-
381+
385382
value="${value//\"/}"
386383

387384
if ! validate_config_value "ENV" "$value"; then
388-
errors_ref+=("Invalid env: $value")
385+
CONFIG_ERRORS+=("Invalid env: $value")
389386
return 1
390387
fi
391388

@@ -396,7 +393,8 @@ process_env_config() {
396393
EXTRA_ENV_VARS+=("-e" "$name=$val")
397394
DOCKER_ONLY_WARNINGS+=("Config environment variable: $name=$val (ignored in local mode)")
398395
else
399-
errors_ref+=("Invalid env name: $name")
396+
CONFIG_ERRORS+=("Invalid env name: $name")
397+
fi
400398
else
401399
# Shorthand pass-through: ENV=${VAR} or ENV=$VAR
402400
if [[ "$value" =~ ^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$ ]] || [[ "$value" =~ ^\$([A-Za-z_][A-Za-z0-9_]*)$ ]]; then
@@ -417,18 +415,15 @@ process_env_config() {
417415
process_var_config() {
418416
local name="$1"
419417
local value="$2"
420-
local errors_var="$3"
421-
declare -n errors_ref="$errors_var"
422-
423418
if ! [[ "$name" =~ ^[A-Z][A-Z0-9_]*$ ]]; then
424-
errors_ref+=("Invalid variable name: $name")
419+
CONFIG_ERRORS+=("Invalid variable name: $name")
425420
return 1
426421
fi
427422

428423
value="${value//\"/}"
429424

430425
if ! validate_config_value "$name" "$value"; then
431-
errors_ref+=("Validation failed for $name=$value")
426+
CONFIG_ERRORS+=("Validation failed for $name=$value")
432427
return 1
433428
fi
434429

@@ -441,14 +436,14 @@ process_var_config() {
441436
CONFIG_DIR="$value"
442437
if [ ! -d "$CONFIG_DIR" ]; then
443438
mkdir -p "$CONFIG_DIR" 2>/dev/null || {
444-
errors_ref+=("Cannot create CONFIG_DIR: $CONFIG_DIR")
439+
CONFIG_ERRORS+=("Cannot create CONFIG_DIR: $CONFIG_DIR")
445440
CONFIG_DIR=""
446441
return 1
447442
}
448443
fi
449444
if [ -n "$CONFIG_DIR" ] && [ ! -f "$CONFIG_DIR/.claude.json" ]; then
450445
echo '{}' >"$CONFIG_DIR/.claude.json" 2>/dev/null || {
451-
errors_ref+=("Cannot create $CONFIG_DIR/.claude.json")
446+
CONFIG_ERRORS+=("Cannot create $CONFIG_DIR/.claude.json")
452447
}
453448
fi
454449
;;
@@ -481,7 +476,7 @@ process_var_config() {
481476
if [[ "$name" =~ ^(DISABLE_|MAX_|ANTHROPIC_|CLAUDE_|AWS_|GOOGLE_) ]]; then
482477
export "$name"="$value"
483478
else
484-
errors_ref+=("Unknown config variable: $name")
479+
CONFIG_ERRORS+=("Unknown config variable: $name")
485480
fi
486481
;;
487482
esac
@@ -496,25 +491,28 @@ load_config_file() {
496491
# we would need to read the file once into memory and process from there.
497492
# However, given the nature of config files (user-controlled, local),
498493
# the security impact is minimal and the current approach is pragmatic.
499-
local errors=()
494+
local initial_error_count=${#CONFIG_ERRORS[@]}
500495

501496
while IFS= read -r line || [ -n "$line" ]; do
502497
[[ "$line" =~ ^[[:space:]]*#|^[[:space:]]*$ ]] && continue
503498

504499
if [[ "$line" =~ ^[[:space:]]*VOLUME[[:space:]]*=[[:space:]]*(.+)$ ]]; then
505-
process_volume_config "${BASH_REMATCH[1]}" errors
500+
process_volume_config "${BASH_REMATCH[1]}"
506501
elif [[ "$line" =~ ^[[:space:]]*ENV[[:space:]]*=[[:space:]]*(.+)$ ]]; then
507-
process_env_config "${BASH_REMATCH[1]}" errors
502+
process_env_config "${BASH_REMATCH[1]}"
508503
elif [[ "$line" =~ ^[[:space:]]*([A-Z_]+)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
509-
process_var_config "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" errors
504+
process_var_config "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
510505
else
511-
errors+=("Invalid line format: $line")
506+
CONFIG_ERRORS+=("Invalid line format: $line")
512507
fi
513508
done <"$config_file"
514509

515-
if [ ${#errors[@]} -gt 0 ]; then
516-
echo "ERROR: Config file $config_file has ${#errors[@]} error(s):" >&2
517-
printf '%s\n' "${errors[@]}" >&2
510+
# Check if new errors were added during this file's processing
511+
if [ ${#CONFIG_ERRORS[@]} -gt "$initial_error_count" ]; then
512+
echo "ERROR: Config file $config_file has $((${#CONFIG_ERRORS[@]} - initial_error_count)) error(s):" >&2
513+
for ((i=initial_error_count; i<${#CONFIG_ERRORS[@]}; i++)); do
514+
echo " ${CONFIG_ERRORS[$i]}" >&2
515+
done
518516
exit 1
519517
fi
520518
}
@@ -839,6 +837,9 @@ run_claude_local() {
839837
blue '────────────────────────────────────'
840838
echo ""
841839

840+
# Suppress Node.js experimental proxy warnings from Claude Code CLI
841+
export NODE_NO_WARNINGS=1
842+
842843
if [ "$USE_TRACE" = true ]; then
843844
if command -v "$CLAUDE_TRACE_PATH" >/dev/null 2>&1; then
844845
CLAUDE_CMD="$CLAUDE_TRACE_PATH"
@@ -968,6 +969,9 @@ if [ ${#EXTRA_VOLUMES[@]} -gt 0 ]; then
968969
DOCKER_ARGS+=("-e" "CCYOLO_EXTRA_VOLUMES=$CCYOLO_EXTRA_VOLUMES")
969970
fi
970971

972+
# Suppress Node.js experimental proxy warnings from Claude Code CLI
973+
DOCKER_ARGS+=("-e" "NODE_NO_WARNINGS=1")
974+
971975
# Pass extra environment variables specified with -e
972976
if [ ${#EXTRA_ENV_VARS[@]} -gt 0 ]; then
973977
for env_var in "${EXTRA_ENV_VARS[@]}"; do

0 commit comments

Comments
 (0)