mirror of
https://github.com/KeygraphHQ/shannon.git
synced 2026-05-27 02:43:09 +02:00
refactor: replace Taskfile with bash CLI script
- Add shannon bash script with start/logs/query/stop/help commands - Remove Taskfile.yml dependency (no longer requires Task installation) - Update README.md and CLAUDE.md to use ./shannon commands - Update client.ts output to show ./shannon commands
This commit is contained in:
@@ -10,7 +10,6 @@ This is an AI-powered penetration testing agent designed for defensive security
|
||||
|
||||
### Prerequisites
|
||||
- **Docker** - Container runtime
|
||||
- **Task** - Task runner ([Install Task](https://taskfile.dev/installation/))
|
||||
- **Anthropic API key** - Set in `.env` file
|
||||
|
||||
### Running the Penetration Testing Agent (Docker + Temporal)
|
||||
@@ -22,27 +21,27 @@ cp .env.example .env
|
||||
# CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000 # Prevents token limits during long reports
|
||||
|
||||
# Start a pentest workflow
|
||||
task start URL=<url> REPO=<path>
|
||||
./shannon start URL=<url> REPO=<path>
|
||||
```
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
task start URL=https://example.com REPO=/path/to/repo
|
||||
task start URL=https://example.com REPO=/path/to/repo CONFIG=./configs/my-config.yaml
|
||||
task start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports
|
||||
./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
|
||||
```
|
||||
|
||||
### Monitoring Progress
|
||||
```bash
|
||||
task logs # View real-time worker logs
|
||||
task query ID=<workflow-id> # Query specific workflow progress
|
||||
./shannon logs # View real-time worker logs
|
||||
./shannon query ID=<workflow-id> # Query specific workflow progress
|
||||
# Temporal Web UI available at http://localhost:8233
|
||||
```
|
||||
|
||||
### Stopping Shannon
|
||||
```bash
|
||||
task stop # Stop containers (preserves workflow data)
|
||||
task stop CLEAN=true # Full cleanup including volumes
|
||||
./shannon stop # Stop containers (preserves workflow data)
|
||||
./shannon stop CLEAN=true # Full cleanup including volumes
|
||||
```
|
||||
|
||||
### Options
|
||||
@@ -68,7 +67,7 @@ TOTP generation is handled automatically via the `generate_totp` MCP tool during
|
||||
npm run build
|
||||
|
||||
# Run with pipeline testing mode (fast, minimal deliverables)
|
||||
task start URL=<url> REPO=<path> PIPELINE_TESTING=true
|
||||
./shannon start URL=<url> REPO=<path> PIPELINE_TESTING=true
|
||||
```
|
||||
|
||||
## Architecture & Components
|
||||
@@ -94,7 +93,7 @@ Shannon uses Temporal for durable workflow orchestration:
|
||||
|
||||
Key features:
|
||||
- **Crash recovery** - Workflows resume automatically after worker restart
|
||||
- **Queryable progress** - Real-time status via `task query` or Temporal Web UI
|
||||
- **Queryable progress** - Real-time status via `./shannon query` or Temporal Web UI
|
||||
- **Intelligent retry** - Distinguishes transient vs permanent errors
|
||||
- **Parallel execution** - 5 concurrent agents in vulnerability/exploitation phases
|
||||
|
||||
@@ -243,7 +242,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
|
||||
task start URL=<url> REPO=<path> PIPELINE_TESTING=true
|
||||
./shannon start URL=<url> REPO=<path> PIPELINE_TESTING=true
|
||||
```
|
||||
|
||||
### Security Focus
|
||||
@@ -271,7 +270,7 @@ The tool should only be used on systems you own or have explicit permission to t
|
||||
- `src/audit/` - Crash-safe logging and metrics system
|
||||
|
||||
**Configuration:**
|
||||
- `Taskfile.yml` - Task runner commands
|
||||
- `shannon` - CLI script for running pentests
|
||||
- `docker-compose.yml` - Temporal server + worker containers
|
||||
- `configs/` - YAML configs with `config-schema.json` for validation
|
||||
- `prompts/` - AI prompt templates (`vuln-*.txt`, `exploit-*.txt`, etc.)
|
||||
@@ -289,7 +288,7 @@ The tool should only be used on systems you own or have explicit permission to t
|
||||
### Temporal & Docker Issues
|
||||
- **"Temporal not ready"**: Wait for health check or run `docker compose logs temporal`
|
||||
- **Worker not processing**: Ensure worker container is running with `docker compose ps`
|
||||
- **Reset workflow state**: `task stop CLEAN=true` removes all Temporal data and volumes
|
||||
- **Reset workflow state**: `./shannon stop CLEAN=true` removes all Temporal data and volumes
|
||||
- **Local apps unreachable**: Use `host.docker.internal` instead of `localhost` for URLs
|
||||
- **Container permissions**: On Linux, may need `sudo` for docker commands
|
||||
|
||||
@@ -308,4 +307,4 @@ Missing tools can be skipped using `PIPELINE_TESTING=true` mode during developme
|
||||
open http://localhost:8233
|
||||
```
|
||||
|
||||
Note: For recovery from corrupted state, simply delete `.shannon-store.json` or run `task stop CLEAN=true`.
|
||||
Note: For recovery from corrupted state, simply delete `.shannon-store.json` or run `./shannon stop CLEAN=true`.
|
||||
|
||||
@@ -100,7 +100,6 @@ Shannon is available in two editions:
|
||||
### Prerequisites
|
||||
|
||||
- **Docker** - Container runtime ([Install Docker](https://docs.docker.com/get-docker/))
|
||||
- **Task** - Task runner for simplified commands ([Install Task](https://taskfile.dev/installation/))
|
||||
- **Anthropic API key or Claude Code OAuth token** - Get from [Anthropic Console](https://console.anthropic.com)
|
||||
|
||||
### Quick Start
|
||||
@@ -123,7 +122,7 @@ CLAUDE_CODE_MAX_OUTPUT_TOKENS=64000
|
||||
EOF
|
||||
|
||||
# 3. Run a pentest
|
||||
task start URL=https://your-app.com REPO=/path/to/your/repo
|
||||
./shannon start URL=https://your-app.com REPO=/path/to/your/repo
|
||||
```
|
||||
|
||||
Shannon will build the containers, start the workflow, and return a workflow ID. The pentest runs in the background.
|
||||
@@ -132,10 +131,10 @@ Shannon will build the containers, start the workflow, and return a workflow ID.
|
||||
|
||||
```bash
|
||||
# View real-time worker logs
|
||||
task logs
|
||||
./shannon logs
|
||||
|
||||
# Query a specific workflow's progress
|
||||
task query ID=shannon-1234567890
|
||||
./shannon query ID=shannon-1234567890
|
||||
|
||||
# Open the Temporal Web UI for detailed monitoring
|
||||
open http://localhost:8233
|
||||
@@ -145,23 +144,23 @@ open http://localhost:8233
|
||||
|
||||
```bash
|
||||
# Stop all containers (preserves workflow data)
|
||||
task stop
|
||||
./shannon stop
|
||||
|
||||
# Full cleanup (removes all data)
|
||||
task stop CLEAN=true
|
||||
./shannon stop CLEAN=true
|
||||
```
|
||||
|
||||
### Usage Examples
|
||||
|
||||
```bash
|
||||
# Basic pentest
|
||||
task start URL=https://example.com REPO=/path/to/repo
|
||||
./shannon start URL=https://example.com REPO=/path/to/repo
|
||||
|
||||
# With a configuration file
|
||||
task start URL=https://example.com REPO=/path/to/repo CONFIG=./configs/my-config.yaml
|
||||
./shannon start URL=https://example.com REPO=/path/to/repo CONFIG=./configs/my-config.yaml
|
||||
|
||||
# Custom output directory
|
||||
task start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports
|
||||
./shannon start URL=https://example.com REPO=/path/to/repo OUTPUT=./my-reports
|
||||
```
|
||||
|
||||
### Prepare Your Repository
|
||||
@@ -191,7 +190,7 @@ git clone https://github.com/your-org/api.git
|
||||
|
||||
**For Linux (Native Docker):**
|
||||
|
||||
You may need to run Task commands with `sudo` depending on your Docker setup. If you encounter permission issues with output files, ensure your user has access to the Docker socket.
|
||||
You may need to run commands with `sudo` depending on your Docker setup. If you encounter permission issues with output files, ensure your user has access to the Docker socket.
|
||||
|
||||
**For macOS:**
|
||||
|
||||
@@ -202,7 +201,7 @@ 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
|
||||
task start URL=http://host.docker.internal:3000 REPO=/path/to/repo
|
||||
./shannon start URL=http://host.docker.internal:3000 REPO=/path/to/repo
|
||||
```
|
||||
|
||||
### Configuration (Optional)
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
version: '3'
|
||||
|
||||
dotenv: ['.env']
|
||||
|
||||
vars:
|
||||
COMPOSE_FILE: docker-compose.yml
|
||||
|
||||
tasks:
|
||||
default:
|
||||
silent: true
|
||||
cmds: [task help]
|
||||
|
||||
help:
|
||||
desc: Show usage information
|
||||
silent: true
|
||||
cmds:
|
||||
- |
|
||||
echo "Shannon - AI Penetration Testing Framework"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " task start URL=<url> REPO=<path> Start a pentest workflow"
|
||||
echo " task logs View real-time worker logs"
|
||||
echo " task query ID=<workflow-id> Query workflow progress"
|
||||
echo " task stop Stop all containers"
|
||||
echo " task help Show this help message"
|
||||
echo ""
|
||||
echo "Options for 'start':"
|
||||
echo " CONFIG=<path> Configuration file (YAML)"
|
||||
echo " OUTPUT=<path> Output directory for reports"
|
||||
echo ""
|
||||
echo "Options for 'stop':"
|
||||
echo " CLEAN=true Remove all data including volumes"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " task start URL=https://example.com REPO=/path/to/repo"
|
||||
echo " task start URL=https://example.com REPO=/path/to/repo CONFIG=./config.yaml"
|
||||
echo " task query ID=shannon-1234567890"
|
||||
echo " task stop CLEAN=true"
|
||||
echo ""
|
||||
echo "Monitor workflows at http://localhost:8233"
|
||||
|
||||
start:
|
||||
desc: Start a pentest workflow
|
||||
silent: true
|
||||
requires:
|
||||
vars: [URL, REPO]
|
||||
cmds:
|
||||
- |
|
||||
if [ -z "$ANTHROPIC_API_KEY" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
||||
echo "ERROR: Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in .env"
|
||||
exit 1
|
||||
fi
|
||||
- TARGET_REPO={{.REPO}} docker compose -f {{.COMPOSE_FILE}} up -d --build
|
||||
- |
|
||||
for i in $(seq 1 30); do
|
||||
docker compose -f {{.COMPOSE_FILE}} exec -T temporal \
|
||||
temporal operator cluster health --address localhost:7233 2>/dev/null | grep -q "SERVING" && break
|
||||
[ $i -eq 30 ] && echo "Timeout waiting for Temporal" && exit 1
|
||||
sleep 2
|
||||
done
|
||||
- |
|
||||
ARGS=""
|
||||
{{if .CONFIG}}ARGS="$ARGS --config {{.CONFIG}}"{{end}}
|
||||
{{if .OUTPUT}}ARGS="$ARGS --output {{.OUTPUT}}"{{end}}
|
||||
{{if eq .PIPELINE_TESTING "true"}}ARGS="$ARGS --pipeline-testing"{{end}}
|
||||
docker compose -f {{.COMPOSE_FILE}} exec -T worker \
|
||||
node dist/temporal/client.js "{{.URL}}" "/target-repo" $ARGS {{.CLI_ARGS}}
|
||||
|
||||
logs:
|
||||
desc: View real-time worker logs
|
||||
silent: true
|
||||
cmds:
|
||||
- docker compose -f {{.COMPOSE_FILE}} logs -f worker {{.CLI_ARGS}}
|
||||
|
||||
query:
|
||||
desc: Query workflow progress
|
||||
silent: true
|
||||
requires:
|
||||
vars: [ID]
|
||||
cmds:
|
||||
- |
|
||||
docker compose -f {{.COMPOSE_FILE}} exec -T worker \
|
||||
node dist/temporal/query.js "{{.ID}}"
|
||||
|
||||
stop:
|
||||
desc: Stop all containers
|
||||
silent: true
|
||||
cmds:
|
||||
- |
|
||||
{{if eq .CLEAN "true"}}
|
||||
docker compose -f {{.COMPOSE_FILE}} down -v
|
||||
{{else}}
|
||||
docker compose -f {{.COMPOSE_FILE}} down
|
||||
{{end}}
|
||||
@@ -0,0 +1,151 @@
|
||||
#!/bin/bash
|
||||
# Shannon CLI - AI Penetration Testing Framework
|
||||
|
||||
set -e
|
||||
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
|
||||
# Load .env if present
|
||||
if [ -f .env ]; then
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
fi
|
||||
|
||||
show_help() {
|
||||
cat << 'EOF'
|
||||
Shannon - AI Penetration Testing Framework
|
||||
|
||||
Usage:
|
||||
./shannon start URL=<url> REPO=<path> Start a pentest workflow
|
||||
./shannon logs View real-time worker logs
|
||||
./shannon query ID=<workflow-id> Query workflow progress
|
||||
./shannon stop Stop all containers
|
||||
./shannon help Show this help message
|
||||
|
||||
Options for 'start':
|
||||
CONFIG=<path> Configuration file (YAML)
|
||||
OUTPUT=<path> Output directory for reports
|
||||
PIPELINE_TESTING=true Use minimal prompts for fast testing
|
||||
|
||||
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 query ID=shannon-1234567890
|
||||
./shannon stop CLEAN=true
|
||||
|
||||
Monitor workflows at http://localhost:8233
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse KEY=value arguments into variables
|
||||
parse_args() {
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
URL=*) URL="${arg#URL=}" ;;
|
||||
REPO=*) REPO="${arg#REPO=}" ;;
|
||||
CONFIG=*) CONFIG="${arg#CONFIG=}" ;;
|
||||
OUTPUT=*) OUTPUT="${arg#OUTPUT=}" ;;
|
||||
ID=*) ID="${arg#ID=}" ;;
|
||||
CLEAN=*) CLEAN="${arg#CLEAN=}" ;;
|
||||
PIPELINE_TESTING=*) PIPELINE_TESTING="${arg#PIPELINE_TESTING=}" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
parse_args "$@"
|
||||
|
||||
# Validate required vars
|
||||
if [ -z "$URL" ] || [ -z "$REPO" ]; then
|
||||
echo "ERROR: URL and REPO are required"
|
||||
echo "Usage: ./shannon start URL=<url> REPO=<path>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for API key
|
||||
if [ -z "$ANTHROPIC_API_KEY" ] && [ -z "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
||||
echo "ERROR: Set ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in .env"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start containers
|
||||
TARGET_REPO="$REPO" docker compose -f "$COMPOSE_FILE" up -d --build
|
||||
|
||||
# Wait for Temporal to be ready
|
||||
echo "Waiting for Temporal to be ready..."
|
||||
for i in $(seq 1 30); do
|
||||
if docker compose -f "$COMPOSE_FILE" exec -T temporal \
|
||||
temporal operator cluster health --address localhost:7233 2>/dev/null | grep -q "SERVING"; then
|
||||
break
|
||||
fi
|
||||
if [ "$i" -eq 30 ]; then
|
||||
echo "Timeout waiting for Temporal"
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Build optional args
|
||||
ARGS=""
|
||||
[ -n "$CONFIG" ] && ARGS="$ARGS --config $CONFIG"
|
||||
[ -n "$OUTPUT" ] && ARGS="$ARGS --output $OUTPUT"
|
||||
[ "$PIPELINE_TESTING" = "true" ] && ARGS="$ARGS --pipeline-testing"
|
||||
|
||||
# Run the client
|
||||
docker compose -f "$COMPOSE_FILE" exec -T worker \
|
||||
node dist/temporal/client.js "$URL" "/target-repo" $ARGS
|
||||
}
|
||||
|
||||
cmd_logs() {
|
||||
docker compose -f "$COMPOSE_FILE" logs -f worker "$@"
|
||||
}
|
||||
|
||||
cmd_query() {
|
||||
parse_args "$@"
|
||||
|
||||
if [ -z "$ID" ]; then
|
||||
echo "ERROR: ID is required"
|
||||
echo "Usage: ./shannon query ID=<workflow-id>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
docker compose -f "$COMPOSE_FILE" exec -T worker \
|
||||
node dist/temporal/query.js "$ID"
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
parse_args "$@"
|
||||
|
||||
if [ "$CLEAN" = "true" ]; then
|
||||
docker compose -f "$COMPOSE_FILE" down -v
|
||||
else
|
||||
docker compose -f "$COMPOSE_FILE" down
|
||||
fi
|
||||
}
|
||||
|
||||
# Main command dispatch
|
||||
case "${1:-help}" in
|
||||
start)
|
||||
shift
|
||||
cmd_start "$@"
|
||||
;;
|
||||
logs)
|
||||
shift
|
||||
cmd_logs "$@"
|
||||
;;
|
||||
query)
|
||||
shift
|
||||
cmd_query "$@"
|
||||
;;
|
||||
stop)
|
||||
shift
|
||||
cmd_stop "$@"
|
||||
;;
|
||||
help|--help|-h|*)
|
||||
show_help
|
||||
;;
|
||||
esac
|
||||
@@ -163,8 +163,8 @@ async function startPipeline(): Promise<void> {
|
||||
if (!waitForCompletion) {
|
||||
console.log(chalk.bold('Monitor progress:'));
|
||||
console.log(chalk.white(' Web UI: ') + chalk.blue(`http://localhost:8233/namespaces/default/workflows/${workflowId}`));
|
||||
console.log(chalk.white(' Logs: ') + chalk.gray('task logs'));
|
||||
console.log(chalk.white(' Query: ') + chalk.gray(`task query ID=${workflowId}`));
|
||||
console.log(chalk.white(' Logs: ') + chalk.gray('./shannon logs'));
|
||||
console.log(chalk.white(' Query: ') + chalk.gray(`./shannon query ID=${workflowId}`));
|
||||
console.log();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user