Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ Ralph uses modern Claude Code CLI flags for structured communication:
**Configuration Variables:**
```bash
CLAUDE_OUTPUT_FORMAT="json" # Output format: json (default) or text
CLAUDE_ALLOWED_TOOLS="Write,Bash(git *),Read" # Allowed tool permissions
CLAUDE_ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" # Allowed tool permissions
CLAUDE_USE_CONTINUE=true # Enable session continuity
CLAUDE_MIN_VERSION="2.0.76" # Minimum Claude CLI version
```
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,14 @@ Ralph is an implementation of the Geoffrey Huntley's technique for Claude Code t
- Expanding test coverage
- Log rotation functionality
- Dry-run mode
- Configuration file support (.ralphrc)
- Metrics and analytics tracking
- Desktop notifications
- Git backup and rollback system

**v0.11.2** (latest)
- `.ralphrc` configuration file now created by both `ralph-setup` and `ralph-enable`
- Updated default ALLOWED_TOOLS to include `Edit`, `Bash(npm *)`, and `Bash(pytest)`

Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
**Timeline to v1.0**: ~4 weeks | [Full roadmap](IMPLEMENTATION_PLAN.md) | **Contributions welcome!**

## Features
Expand Down Expand Up @@ -464,6 +467,7 @@ my-project/
│ ├── examples/ # Usage examples and test cases
│ ├── logs/ # Ralph execution logs
│ └── docs/generated/ # Auto-generated documentation
├── .ralphrc # Ralph configuration file (tool permissions, settings)
└── src/ # Source code implementation (at project root)
```

Expand Down Expand Up @@ -688,7 +692,7 @@ ralph [OPTIONS]
-v, --verbose Show detailed progress updates during execution
-t, --timeout MIN Set Claude Code execution timeout in minutes (1-120, default: 15)
--output-format FORMAT Set output format: json (default) or text
--allowed-tools TOOLS Set allowed Claude tools (default: Write,Bash(git *),Read)
--allowed-tools TOOLS Set allowed Claude tools (default: Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest))
--no-continue Disable session continuity (start fresh each loop)
--reset-circuit Reset the circuit breaker
--circuit-status Show circuit breaker status
Expand Down
4 changes: 2 additions & 2 deletions ralph_loop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ CLAUDE_TIMEOUT_MINUTES="${CLAUDE_TIMEOUT_MINUTES:-15}"

# Modern Claude CLI configuration (Phase 1.1)
CLAUDE_OUTPUT_FORMAT="${CLAUDE_OUTPUT_FORMAT:-json}"
CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-Write,Bash(git *),Read}"
CLAUDE_ALLOWED_TOOLS="${CLAUDE_ALLOWED_TOOLS:-Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)}"
CLAUDE_USE_CONTINUE="${CLAUDE_USE_CONTINUE:-true}"
CLAUDE_SESSION_FILE="$RALPH_DIR/.claude_session_id" # Session ID persistence file
CLAUDE_MIN_VERSION="2.0.76" # Minimum required Claude CLI version
Expand Down Expand Up @@ -217,7 +217,7 @@ setup_tmux_session() {
ralph_cmd="$ralph_cmd --timeout $CLAUDE_TIMEOUT_MINUTES"
fi
# Forward --allowed-tools if non-default
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Bash(git *),Read" ]]; then
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" ]]; then
ralph_cmd="$ralph_cmd --allowed-tools '$CLAUDE_ALLOWED_TOOLS'"
fi
# Forward --no-continue if session continuity disabled
Expand Down
47 changes: 47 additions & 0 deletions setup.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Critical

Issue on line in setup.sh:7:

PROJECT_NAME from user input is interpolated unsanitized into the heredoc. When .ralphrc is later sourced, malicious input like test"; rm -rf ~; # executes arbitrary commands. Consider validating PROJECT_NAME at line 7 to reject characters like ", ;, `, $, or newlines.

-PROJECT_NAME=${1:-"my-project"}
+PROJECT_NAME=${1:-"my-project"}
+
+# Validate PROJECT_NAME to prevent command injection when .ralphrc is sourced
+if [[ ! "$PROJECT_NAME" =~ ^[a-zA-Z0-9_-]+$ ]]; then
+    echo "❌ Error: PROJECT_NAME must contain only alphanumeric characters, hyphens, and underscores."
+    exit 1
+fi

🚀 Want me to fix this? Reply ex: "fix it for me".

Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ cd "$PROJECT_NAME"
# Determine templates directory location (checked AFTER cd into project)
# Check local ../templates first, then global ~/.ralph/templates
TEMPLATES_DIR=""
LIB_DIR=""
if [[ -d "../templates" ]]; then
TEMPLATES_DIR="../templates"
LIB_DIR="../lib"
elif [[ -d "$HOME/.ralph/templates" ]]; then
TEMPLATES_DIR="$HOME/.ralph/templates"
LIB_DIR="$HOME/.ralph/lib"
else
echo "❌ Error: Templates directory not found."
echo " Expected at: ../templates or ~/.ralph/templates"
Expand All @@ -44,6 +47,50 @@ cp "$TEMPLATES_DIR/fix_plan.md" .ralph/fix_plan.md
cp "$TEMPLATES_DIR/AGENT.md" .ralph/AGENT.md
cp -r "$TEMPLATES_DIR/specs"/* .ralph/specs/ 2>/dev/null || true

# Generate .ralphrc configuration file
# Source enable_core.sh if available for generate_ralphrc(), otherwise create inline
if [[ -f "$LIB_DIR/enable_core.sh" ]]; then
# Temporarily disable colors for cleaner output
export ENABLE_USE_COLORS=false
source "$LIB_DIR/enable_core.sh"
generate_ralphrc "$PROJECT_NAME" "generic" "local" > .ralphrc
else
Comment thread
coderabbitai[bot] marked this conversation as resolved.
# Fallback: create minimal .ralphrc inline (same content as generate_ralphrc)
cat > .ralphrc << RALPHRCEOF
# .ralphrc - Ralph project configuration
# Generated by: ralph-setup
# Documentation: https://github.com/frankbria/ralph-claude-code

# Project identification
PROJECT_NAME="${PROJECT_NAME}"
PROJECT_TYPE="generic"

# Loop settings
MAX_CALLS_PER_HOUR=100
CLAUDE_TIMEOUT_MINUTES=15
CLAUDE_OUTPUT_FORMAT="json"

# Tool permissions
# Comma-separated list of allowed tools
ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)"

# Session management
SESSION_CONTINUITY=true
SESSION_EXPIRY_HOURS=24

# Task sources (for ralph enable --sync)
# Options: local, beads, github (comma-separated for multiple)
TASK_SOURCES="local"
GITHUB_TASK_LABEL="ralph-task"
BEADS_FILTER="status:open"

# Circuit breaker thresholds
CB_NO_PROGRESS_THRESHOLD=3
CB_SAME_ERROR_THRESHOLD=5
CB_OUTPUT_DECLINE_THRESHOLD=70
RALPHRCEOF
fi

# Initialize git
git init
echo "# $PROJECT_NAME" > README.md
Expand Down
54 changes: 54 additions & 0 deletions tests/integration/test_project_setup.bats
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,57 @@ teardown() {
# The script properly quotes variables, so spaces should be handled correctly
[[ $status -eq 0 ]]
}

# =============================================================================
# Test: .ralphrc Generation (Issue #136)
# =============================================================================

@test "setup.sh creates .ralphrc file" {
run bash "$SETUP_SCRIPT" test-project

assert_success
assert_file_exists "test-project/.ralphrc"
}

@test "setup.sh .ralphrc contains ALLOWED_TOOLS with Edit" {
bash "$SETUP_SCRIPT" test-project

# .ralphrc should include Edit tool
grep -q "Edit" test-project/.ralphrc
}

@test "setup.sh .ralphrc contains ALLOWED_TOOLS with test execution capabilities" {
bash "$SETUP_SCRIPT" test-project

# .ralphrc should include Bash(npm *) or Bash(pytest) for test execution
grep -qE 'Bash\(npm \*\)|Bash\(pytest\)' test-project/.ralphrc
}

@test "setup.sh .ralphrc ALLOWED_TOOLS matches ralph-enable defaults" {
bash "$SETUP_SCRIPT" test-project

# The expected ALLOWED_TOOLS value that ralph-enable uses
local expected_tools='ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)"'

# Check that .ralphrc contains the expected ALLOWED_TOOLS line
# Use grep -F for literal string matching (avoids regex interpretation of *)
grep -qF "$expected_tools" test-project/.ralphrc
}

@test "setup.sh .ralphrc is committed in initial git commit" {
bash "$SETUP_SCRIPT" test-project

cd test-project
# Verify .ralphrc is tracked by git (not in untracked files)
run command git ls-files .ralphrc

assert_success
assert_equal "$output" ".ralphrc"
}

@test "setup.sh .ralphrc contains project name" {
bash "$SETUP_SCRIPT" my-custom-project

# .ralphrc should reference the project name
grep -q "my-custom-project" my-custom-project/.ralphrc
}
18 changes: 18 additions & 0 deletions tests/unit/test_cli_modern.bats
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ teardown() {
[[ "$output" == *"Read"* ]]
}

@test "CLAUDE_ALLOWED_TOOLS default includes Edit tool (issue #136)" {
# Verify the default includes Edit for file editing
run grep 'CLAUDE_ALLOWED_TOOLS=.*:-' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"

# The default should include Edit
[[ "$output" == *"Edit"* ]]
}

@test "CLAUDE_ALLOWED_TOOLS default includes test execution tools (issue #136)" {
# Verify the default includes test execution capabilities
run grep 'CLAUDE_ALLOWED_TOOLS=.*:-' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"

# Should include Bash(npm *) for npm test
[[ "$output" == *'Bash(npm *)'* ]]
# Should include Bash(pytest) for Python tests
[[ "$output" == *'Bash(pytest)'* ]]
}

@test "CLAUDE_USE_CONTINUE defaults to true" {
# Verify by checking the default in ralph_loop.sh via grep
run grep 'CLAUDE_USE_CONTINUE=' "${BATS_TEST_DIRNAME}/../../ralph_loop.sh"
Expand Down
6 changes: 3 additions & 3 deletions tests/unit/test_cli_parsing.bats
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ build_ralph_cmd_for_test() {
local CLAUDE_OUTPUT_FORMAT="${3:-json}"
local VERBOSE_PROGRESS="${4:-false}"
local CLAUDE_TIMEOUT_MINUTES="${5:-15}"
local CLAUDE_ALLOWED_TOOLS="${6:-Write,Bash(git *),Read}"
local CLAUDE_ALLOWED_TOOLS="${6:-Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)}"
local CLAUDE_USE_CONTINUE="${7:-true}"
local CLAUDE_SESSION_EXPIRY_HOURS="${8:-24}"
local RALPH_DIR=".ralph"
Expand All @@ -403,7 +403,7 @@ build_ralph_cmd_for_test() {
ralph_cmd="$ralph_cmd --timeout $CLAUDE_TIMEOUT_MINUTES"
fi
# Forward --allowed-tools if non-default
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Bash(git *),Read" ]]; then
if [[ "$CLAUDE_ALLOWED_TOOLS" != "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" ]]; then
ralph_cmd="$ralph_cmd --allowed-tools '$CLAUDE_ALLOWED_TOOLS'"
fi
# Forward --no-continue if session continuity disabled
Expand Down Expand Up @@ -460,7 +460,7 @@ build_ralph_cmd_for_test() {
}

@test "monitor does not forward default parameters" {
local result=$(build_ralph_cmd_for_test 100 ".ralph/PROMPT.md" "json" "false" "15" "Write,Bash(git *),Read" "true" "24")
local result=$(build_ralph_cmd_for_test 100 ".ralph/PROMPT.md" "json" "false" "15" "Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)" "true" "24")
# Should only be "ralph" with no extra flags
[[ "$result" == "ralph" ]]
}