Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
52 changes: 52 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
FROM mcr.microsoft.com/devcontainers/base:ubuntu

# Set environment variables
ENV DEBIAN_FRONTEND=noninteractive
ENV JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
ENV GHIDRA_INSTALL_DIR=/opt/ghidra
ENV GRADLE_VERSION=9.0
ENV PATH=$PATH:/opt/ghidra:/opt/gradle/bin

# Install basic dependencies including build tools for Ghidra
RUN apt-get update && apt-get install -y \
curl \
wget \
unzip \
git \
build-essential \
python3 \
python3-pip \
python3-venv \
openjdk-21-jdk \
bison \
flex \
&& rm -rf /var/lib/apt/lists/*

# Install Gradle
RUN wget -q https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip -O /tmp/gradle.zip && \
unzip -q /tmp/gradle.zip -d /opt && \
mv /opt/gradle-${GRADLE_VERSION} /opt/gradle && \
rm /tmp/gradle.zip

# Create ghidra directories
RUN mkdir -p /opt/ghidra /opt/ghidra-src

# Create a Python virtual environment and install MCP SDK
RUN python3 -m venv /opt/venv && \
. /opt/venv/bin/activate && \
pip install --upgrade pip setuptools wheel && \
pip install mcp pytest requests

# Set up vscode user permissions
RUN chown -R vscode:vscode /opt/ghidra /opt/ghidra-src /opt/gradle /opt/venv

# Switch to vscode user
USER vscode

# Add virtual environment to PATH for vscode user
ENV PATH="/opt/venv/bin:${PATH}"

# Verify installations
RUN java -version && gradle --version && python3 --version

WORKDIR /workspaces/reverse-engineering-assistant
51 changes: 51 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "ReVa Development Environment",
"dockerFile": "Dockerfile",
"runArgs": [
"--init"
],
"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"forwardPorts": [8080],
"portsAttributes": {
"8080": {
"label": "ReVa MCP Server",
"onAutoForward": "notify"
}
},
"customizations": {
"vscode": {
"extensions": [
"vscjava.vscode-java-pack",
"redhat.java",
"vscjava.vscode-gradle",
"ms-python.python",
"ms-python.pylint",
"ms-python.black-formatter",
"ms-vscode.hexeditor",
"charliermarsh.ruff",
"github.copilot"
],
"settings": {
"java.jdt.ls.java.home": "/usr/lib/jvm/java-21-openjdk-amd64",
"java.configuration.runtimes": [
{
"name": "JavaSE-21",
"path": "/usr/lib/jvm/java-21-openjdk-amd64"
}
],
"java.compile.nullAnalysis.mode": "automatic",
"java.gradle.java.home": "/usr/lib/jvm/java-21-openjdk-amd64"
}
}
},
"containerEnv": {
"GHIDRA_INSTALL_DIR": "/opt/ghidra",
"GHIDRA_SRC_DIR": "/opt/ghidra-src",
"JAVA_HOME": "/usr/lib/jvm/java-21-openjdk-amd64",
"PATH": "${containerEnv:PATH}:/opt/ghidra:/opt/gradle/bin"
},
"postCreateCommand": ".devcontainer/postCreateCommand.sh",
"remoteUser": "vscode"
}
101 changes: 101 additions & 0 deletions .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/bash

# Post-create command script for ReVa devcontainer
set -e

echo "🚀 Setting up ReVa development environment..."

# Ensure we're in the correct directory
cd /workspaces/reverse-engineering-assistant

# Verify installations
echo "📋 Verifying installations..."
echo "Java version:"
java -version
echo "Gradle version:"
gradle --version
echo "Python version:"
python3 --version

# Clone and build Ghidra from source if not already done
if [ ! -d "/opt/ghidra-src/.git" ]; then
echo "📦 Cloning Ghidra source code..."
git clone https://github.com/NationalSecurityAgency/ghidra.git /opt/ghidra-src
fi

if [ ! -f "/opt/ghidra/ghidraRun" ]; then
echo "🔨 Building Ghidra from source (this may take a while)..."
cd /opt/ghidra-src
gradle --no-daemon -I gradle/support/fetchDependencies.gradle init
gradle --no-daemon buildGhidra

echo "📦 Extracting Ghidra build..."
unzip -q build/dist/ghidra_*_DEV_*.zip -d /opt
mv /opt/ghidra_*_DEV* /opt/ghidra
chmod +x /opt/ghidra/ghidraRun

cd /workspaces/reverse-engineering-assistant
echo "✅ Ghidra build complete!"
else
echo "✅ Ghidra is already built and available"
fi

# Check if GHIDRA_INSTALL_DIR is properly set
if [ -z "$GHIDRA_INSTALL_DIR" ]; then
echo "❌ GHIDRA_INSTALL_DIR is not set!"
exit 1
fi

if [ ! -d "$GHIDRA_INSTALL_DIR" ]; then
echo "❌ Ghidra directory does not exist at $GHIDRA_INSTALL_DIR"
exit 1
fi
Comment on lines +43 to +52
Copy link

Copilot AI Sep 4, 2025

Choose a reason for hiding this comment

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

The script checks if $GHIDRA_INSTALL_DIR directory exists before Ghidra is actually built and installed. Since Ghidra is built in the previous section (lines 26-41), this check should come after the Ghidra build completion, not before.

Copilot uses AI. Check for mistakes.

echo "✅ GHIDRA_INSTALL_DIR is properly set to: $GHIDRA_INSTALL_DIR"
echo "📂 Ghidra source is available at: /opt/ghidra-src"

# Activate Python virtual environment
echo "🐍 Activating Python virtual environment..."
source /opt/venv/bin/activate

# Install any additional Python dependencies if requirements files exist
if [ -f "cli/requirements.txt" ]; then
echo "📦 Installing Python dependencies from cli/requirements.txt..."
pip install -r cli/requirements.txt
fi

if [ -f "requirements.txt" ]; then
echo "📦 Installing Python dependencies from requirements.txt..."
pip install -r requirements.txt
fi

# Verify MCP SDK is installed
echo "🔧 Verifying MCP SDK installation..."
python3 -c "import mcp; print('✅ MCP SDK is installed')" || echo "❌ MCP SDK installation failed"

# Build the project
echo "🔨 Building ReVa extension..."
if gradle clean build; then
echo "✅ Build successful!"
else
echo "❌ Build failed!"
exit 1
fi

# Run tests to verify everything is working
echo "🧪 Running unit tests..."
if gradle test --info; then
echo "✅ Unit tests passed!"
else
echo "⚠️ Unit tests failed - this might be expected in some environments"
Comment on lines +86 to +90
Copy link

Copilot AI Sep 4, 2025

Choose a reason for hiding this comment

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

[nitpick] The test failure is dismissed as potentially expected without providing specific guidance on when this is acceptable. Consider adding a comment explaining specific scenarios where test failures are expected (e.g., headless environments, missing GUI dependencies) or make the test execution conditional based on environment capabilities.

Suggested change
echo "🧪 Running unit tests..."
if gradle test --info; then
echo "✅ Unit tests passed!"
else
echo "⚠️ Unit tests failed - this might be expected in some environments"
# In headless environments (e.g., CI, devcontainers without GUI), some tests may fail due to missing GUI dependencies.
# We skip running tests if DISPLAY is not set (Linux) or if running in a known headless environment.
echo "🧪 Running unit tests..."
if [ -z "$DISPLAY" ]; then
echo "⚠️ Skipping unit tests: headless environment detected (no DISPLAY variable set)."
else
if gradle test --info; then
echo "✅ Unit tests passed!"
else
echo "⚠️ Unit tests failed - this might be expected in headless environments or if GUI dependencies are missing."
fi

Copilot uses AI. Check for mistakes.
fi

# Create Extensions directory if it doesn't exist
mkdir -p "$GHIDRA_INSTALL_DIR/Ghidra/Extensions"

echo "🎉 Setup complete! You can now:"
echo " • Build the extension with: gradle"
echo " • Install the extension with: gradle install"
echo " • Run tests with: gradle test"
echo " • Run integration tests with: gradle integrationTest --info"
echo " • Start developing ReVa!"
25 changes: 17 additions & 8 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

ReVa (Reverse Engineering Assistant) is a Ghidra extension that provides a Model Context Protocol (MCP) server for AI-assisted reverse engineering. It uses a streamable transport (SSE) and implements various tools for interacting with Ghidra's capabilities.
ReVa (Reverse Engineering Assistant) is a Ghidra extension that provides a Model Context Protocol (MCP) server for AI-assisted reverse engineering. It uses a streamable transport and implements various tools for interacting with Ghidra's capabilities. ReVa is designed to handle large binaries and entire firmware images efficiently by using smaller, targeted tools that reduce context usage and hallucination.

## Build and Test Commands

Expand Down Expand Up @@ -107,16 +107,16 @@ When adding new tools to DecompilerToolProvider:

## MCP Server Configuration

The server uses streamable transport (SSE) on port 8080 by default. Configuration is managed through:
The server uses streamable transport on port 8080 by default. Configuration is managed through:
- `ConfigManager` - Handles server configuration
- `McpServerManager` - Manages the MCP server lifecycle
- Transport: HttpServletStreamableServerTransportProvider (streamable transport)
- Transport: HttpServletStreamableServerTransportProvider (streamable transport, not SSE)

## External Dependencies
- Ghidra source code location: `../ghidra`
- MCP SDK: io.modelcontextprotocol.sdk v0.11.1 (uses MCP BOM)
- Jackson: 2.17.0 (forced version for compatibility)
- Jetty: 11.0.25 (embedded servlet support)
- MCP SDK: io.modelcontextprotocol.sdk v0.11.2 (uses MCP BOM)
- Jackson: 2.19.2 (forced version for compatibility)
- Jetty: 11.0.26 (embedded servlet support)
- Target: Java 21, Ghidra 11.3+

## Program Identification
Expand All @@ -139,11 +139,20 @@ The server uses streamable transport (SSE) on port 8080 by default. Configuratio
- **Java**: Target Java 21, minimum Ghidra 11.3+
- **Testing**: Integration tests require `java.awt.headless=false` (GUI environment)
- **Build**: Use `gradle` directly, not gradle wrapper
- **MCP SDK**: v0.11.1 with forced Jackson 2.17.0 for compatibility
- **MCP SDK**: v0.11.2 with forced Jackson 2.19.2 for compatibility

## Important Notes
- Don't revert to SSE transport (already using streamable)
- Fork every integration test to prevent configuration conflicts
- **Memory Management**: Always dispose DecompInterface instances to prevent leaks
- **Read-Before-Modify**: Decompiler tools enforce function reading before modification
- **Error Messages**: Provide specific, actionable error messages with suggestions
- **Error Messages**: Provide specific, actionable error messages with suggestions

## Installation Commands
After building, install the extension in Ghidra:
```bash
# Install directly to Ghidra extensions directory
gradle install
```

Or install manually via Ghidra's extension manager using the zip file in `dist/`.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,16 @@ export GHIDRA_INSTALL_DIR=/path/to/ghidra
gradle
```

Then install the extension (in `dist/`) using the Ghidra extension manager. You can also extract the release zip to
the Ghidra extensions directory globally at `${GHIDRA_INSTALL_DIR}/Ghidra/Extensions`.
### Installation Options

**Option 1: Automatic Installation (Recommended)**
```bash
# Build and install directly to Ghidra
gradle install
```

**Option 2: Manual Installation**
Install the extension (in `dist/`) using the Ghidra extension manager, or extract the release zip to the Ghidra extensions directory at `${GHIDRA_INSTALL_DIR}/Ghidra/Extensions`.

After installing the extension you need to activate it in two places:

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/reva/server/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ The `reva.server` package contains the core MCP (Model Context Protocol) server

### Key Architecture Components

- **MCP Server**: Built on MCP SDK v0.11.0 with streamable transport
- **HTTP Server**: Jetty 11.0.25 embedded servlet container
- **MCP Server**: Built on MCP SDK v0.11.2 with streamable transport
- **HTTP Server**: Jetty 11.0.26 embedded servlet container
- **Transport Layer**: HttpServletStreamableServerTransportProvider for real-time streaming
- **Service Registry**: Integration with RevaInternalServiceRegistry for component coordination
- **Configuration Management**: Dynamic configuration with hot-reload capabilities
Expand Down
31 changes: 28 additions & 3 deletions src/test.slow/java/reva/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,28 @@
- When writing integration tests, make sure to set up the program, call the tool and then validate the output. If the tool modifies the program, validate the modification.
- Don't write useless tests, make sure they have a purpose.
- **CRITICAL**: Integration tests should validate actual Ghidra program state changes, not just MCP tool responses
# Integration Test Development Guidelines

## Test Design Philosophy

- **State Validation**: Always validate actual Ghidra program state changes, not just MCP tool responses
- **Purpose-Driven Testing**: Only write tests that verify meaningful functionality
- **End-to-End Validation**: Set up program state, execute tools, validate both response and program modifications

## Critical Testing Requirements

1. **Program State Validation**:
- Use `Function.getParameters()` and `Function.getAllVariables()` to validate variable changes
- Use `DataType.isEquivalent()` to compare datatypes before/after changes
- Check actual symbol table entries, not just tool responses

2. **Shared Test Environment**:
- Tests use shared Ghidra environment for faster execution
- Each test gets a fresh program via `createDefaultProgram()`
- MCP server persists across tests within the same class

3. **Test Isolation**:
- Fork every test to prevent configuration conflicts
- Programs are automatically registered/unregistered with MCP server
- Always wrap program modifications in transactions

## Test Requirements
- Tests run with `java.awt.headless=false` (GUI environment required)
- **You are not finished until all tests pass!**
Loading