From b05c505e7599a29a7659bf05d5c69a28b2e230fd Mon Sep 17 00:00:00 2001 From: ezl-keygraph Date: Tue, 10 Feb 2026 00:05:41 +0530 Subject: [PATCH] fix: mount repos and configs directories into worker container (#107) * feat: use static repos/ folder mount instead of dynamic TARGET_REPO Replace dynamic per-run TARGET_REPO bind mount with a static ./repos:/repos mount. Users place target repositories under ./repos/ and reference them by folder name. This fixes stale mounts when switching targets and enables running multiple scans concurrently against different repos. * feat: mount configs directory into worker container * docs: add instructions for repos and configs directory setup --- .gitignore | 1 + CLAUDE.md | 14 +++++++------- README.md | 27 ++++++++++++++------------- deliverables/.gitkeep | 0 docker-compose.yml | 3 ++- sessions/.gitkeep | 0 shannon | 27 ++++++++++++++++----------- 7 files changed, 40 insertions(+), 32 deletions(-) delete mode 100644 deliverables/.gitkeep delete mode 100644 sessions/.gitkeep diff --git a/.gitignore b/.gitignore index e28c076..785ad38 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules/ .env audit-logs/ dist/ +repos/ diff --git a/CLAUDE.md b/CLAUDE.md index c73d3c9..096c0bb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -21,14 +21,14 @@ cp .env.example .env # CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 # Prevents token limits during long reports # Start a pentest workflow -./shannon start URL= REPO= +./shannon start URL= REPO= ``` Examples: ```bash -./shannon start URL=https://example.com REPO=/path/to/repo -./shannon start URL=https://example.com REPO=/path/to/repo CONFIG=./configs/my-config.yaml -./shannon start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports +./shannon start URL=https://example.com REPO=repo-name +./shannon start URL=https://example.com REPO=repo-name CONFIG=./configs/my-config.yaml +./shannon start URL=https://example.com REPO=repo-name OUTPUT=./my-reports ``` ### Monitoring Progress @@ -62,7 +62,7 @@ TOTP generation is handled automatically via the `generate_totp` MCP tool during npm run build # Run with pipeline testing mode (fast, minimal deliverables) -./shannon start URL= REPO= PIPELINE_TESTING=true +./shannon start URL= REPO= PIPELINE_TESTING=true ``` ## Architecture & Components @@ -232,7 +232,7 @@ The application uses a comprehensive error handling system with: ### Testing Mode The agent includes a testing mode that skips external tool execution for faster development cycles: ```bash -./shannon start URL= REPO= PIPELINE_TESTING=true +./shannon start URL= REPO= PIPELINE_TESTING=true ``` ### Security Focus @@ -274,7 +274,7 @@ Shannon supports routing Claude Agent SDK requests through alternative LLM provi **Enable router mode:** ```bash -./shannon start URL= REPO= ROUTER=true +./shannon start URL= REPO= ROUTER=true ``` **Supported Providers:** diff --git a/README.md b/README.md index 1ec4552..89e2bfa 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 EOF # 3. Run a pentest -./shannon start URL=https://your-app.com REPO=/path/to/your/repo +./shannon start URL=https://your-app.com REPO=your-repo ``` Shannon will build the containers, start the workflow, and return a workflow ID. The pentest runs in the background. @@ -160,33 +160,34 @@ open http://localhost:8233 ```bash # Basic pentest -./shannon start URL=https://example.com REPO=/path/to/repo +./shannon start URL=https://example.com REPO=repo-name # With a configuration file -./shannon start URL=https://example.com REPO=/path/to/repo CONFIG=./configs/my-config.yaml +./shannon start URL=https://example.com REPO=repo-name CONFIG=./configs/my-config.yaml # Custom output directory -./shannon start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports +./shannon start URL=https://example.com REPO=repo-name OUTPUT=./my-reports ``` ### Prepare Your Repository -Shannon is designed for **web application security testing** and expects all application code to be available in a single directory structure. This works well for: +Shannon expects target repositories to be placed under the `./repos/` directory at the project root. The `REPO` flag refers to a folder name inside `./repos/`. Copy the repository you want to scan into `./repos/`, or clone it directly there: -- **Monorepos** - Single repository containing all components -- **Consolidated setups** - Multiple repositories organized in a shared folder +```bash +git clone https://github.com/your-org/your-repo.git ./repos/your-repo +``` **For monorepos:** ```bash -git clone https://github.com/your-org/your-monorepo.git /path/to/your-app +git clone https://github.com/your-org/your-monorepo.git ./repos/your-monorepo ``` **For multi-repository applications** (e.g., separate frontend/backend): ```bash -mkdir /path/to/your-app -cd /path/to/your-app +mkdir ./repos/your-app +cd ./repos/your-app git clone https://github.com/your-org/frontend.git git clone https://github.com/your-org/backend.git git clone https://github.com/your-org/api.git @@ -207,12 +208,12 @@ Works out of the box with Docker Desktop installed. Docker containers cannot reach `localhost` on your host machine. Use `host.docker.internal` in place of `localhost`: ```bash -./shannon start URL=http://host.docker.internal:3000 REPO=/path/to/repo +./shannon start URL=http://host.docker.internal:3000 REPO=repo-name ``` ### Configuration (Optional) -While you can run without a config file, creating one enables authenticated testing and customized analysis. +While you can run without a config file, creating one enables authenticated testing and customized analysis. Place your configuration files inside the `./configs/` directory — this folder is mounted into the Docker container automatically. #### Create Configuration File @@ -281,7 +282,7 @@ ROUTER_DEFAULT=openai,gpt-5.2 # provider,model format 2. Run with `ROUTER=true`: ```bash -./shannon start URL=https://example.com REPO=/path/to/repo ROUTER=true +./shannon start URL=https://example.com REPO=repo-name ROUTER=true ``` #### Experimental Models diff --git a/deliverables/.gitkeep b/deliverables/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/docker-compose.yml b/docker-compose.yml index 26cbdfa..e54ba1f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,10 +29,11 @@ services: temporal: condition: service_healthy volumes: + - ./configs:/app/configs - ./prompts:/app/prompts - ./audit-logs:/app/audit-logs - ${OUTPUT_DIR:-./audit-logs}:/app/output - - ${TARGET_REPO:-.}:/target-repo + - ./repos:/repos - ${BENCHMARKS_BASE:-.}:/benchmarks shm_size: 2gb ipc: host diff --git a/sessions/.gitkeep b/sessions/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/shannon b/shannon index b1a7ffe..0c4cf9b 100755 --- a/shannon +++ b/shannon @@ -25,13 +25,14 @@ show_help() { AI Penetration Testing Framework Usage: - ./shannon start URL= REPO= Start a pentest workflow + ./shannon start URL= REPO= Start a pentest workflow ./shannon logs ID= Tail logs for a specific workflow ./shannon query ID= Query workflow progress ./shannon stop Stop all containers ./shannon help Show this help message Options for 'start': + REPO= Folder name under ./repos/ (e.g. REPO=repo-name) CONFIG= Configuration file (YAML) OUTPUT= Output directory for reports (default: ./audit-logs/) PIPELINE_TESTING=true Use minimal prompts for fast testing @@ -41,9 +42,9 @@ Options for 'stop': CLEAN=true Remove all data including volumes Examples: - ./shannon start URL=https://example.com REPO=/path/to/repo - ./shannon start URL=https://example.com REPO=/path/to/repo CONFIG=./config.yaml - ./shannon start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports + ./shannon start URL=https://example.com REPO=repo-name + ./shannon start URL=https://example.com REPO=repo-name CONFIG=./config.yaml + ./shannon start URL=https://example.com REPO=repo-name OUTPUT=./my-reports ./shannon logs ID=example.com_shannon-1234567890 ./shannon query ID=shannon-1234567890 ./shannon stop CLEAN=true @@ -119,7 +120,7 @@ cmd_start() { # Validate required vars if [ -z "$URL" ] || [ -z "$REPO" ]; then echo "ERROR: URL and REPO are required" - echo "Usage: ./shannon start URL= REPO=" + echo "Usage: ./shannon start URL= REPO=" exit 1 fi @@ -136,16 +137,20 @@ cmd_start() { fi # Determine container path for REPO - # - If REPO is already a container path (/benchmarks/*, /target-repo), use as-is - # - Otherwise, it's a host path - mount to /target-repo and use that + # - If REPO is already a container path (/benchmarks/*, /repos/*), use as-is + # - Otherwise, treat as a folder name under ./repos/ (mounted at /repos in container) case "$REPO" in - /benchmarks/*|/target-repo|/target-repo/*) + /benchmarks/*|/repos/*) CONTAINER_REPO="$REPO" ;; *) - # Host path - export for docker-compose mount - export TARGET_REPO="$REPO" - CONTAINER_REPO="/target-repo" + if [ ! -d "./repos/$REPO" ]; then + echo "ERROR: Repository not found at ./repos/$REPO" + echo "" + echo "Place your target repository under the ./repos/ directory" + exit 1 + fi + CONTAINER_REPO="/repos/$REPO" ;; esac