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:
ajmallesh
2026-01-12 17:42:06 -08:00
parent 1f303b02b8
commit 89cc30bb94
5 changed files with 177 additions and 122 deletions
+14 -15
View File
@@ -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`.
+10 -11
View File
@@ -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)
-94
View File
@@ -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}}
Executable
+151
View File
@@ -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
+2 -2
View File
@@ -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;
}