Skip to content
Merged
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
28 changes: 24 additions & 4 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
# Pushes to Docker Hub only on: push to main/release_* (not on pull_request), or workflow_dispatch.
# PRs build the image for CI but intentionally do not push (no registry credentials / avoid polluting tags).

name: Build and Push Deadend Docker Image

on:
push:
branches: [ main, release_* ]
paths:
- 'setup/images/kalilinux.Dockerfile'
- 'environments/images/kalilinux.Dockerfile'
- '.github/workflows/docker-build.yml'
pull_request:
branches: [ main ]
paths:
- 'setup/images/kalilinux.Dockerfile'
- 'environments/images/kalilinux.Dockerfile'
- '.github/workflows/docker-build.yml'
workflow_dispatch:
inputs:
Expand All @@ -20,7 +23,7 @@ on:

env:
REGISTRY: docker.io
IMAGE_NAME: bargacy/deadend-pentest
IMAGE_NAME: xoxruns/sandboxed_kali

jobs:
build-and-push:
Expand All @@ -36,6 +39,22 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Explain no push on pull requests
if: github.event_name == 'pull_request'
run: |
echo "PR workflow: image is built only (push=false). After merge to main or release_*, a push event will build and push to Docker Hub."

- name: Require Docker Hub secrets when pushing
if: github.event_name != 'pull_request'
env:
DOCKER_USER: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASS: ${{ secrets.DOCKER_TOKEN }}
run: |
if [ -z "$DOCKER_USER" ] || [ -z "$DOCKER_PASS" ]; then
echo "::error::Add repository Actions secrets DOCKER_USERNAME and DOCKER_TOKEN (Docker Hub access token). Without them, the job cannot log in and nothing is pushed to Docker Hub."
exit 1
fi

- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
Expand All @@ -58,10 +77,11 @@ jobs:
type=raw,value=${{ github.event.inputs.tag }},enable=${{ github.event.inputs.tag != '' }}

- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
file: ./setup/images/kalilinux.Dockerfile
file: ./environments/images/kalilinux.Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "benchmarks/xbow/validation-benchmarks-xbow"]
path = benchmarks/xbow/validation-benchmarks-xbow
url = https://github.com/xoxruns/validation-benchmarks-xbow.git
[submodule "deadend_cli/simple-python-interpreter-sandbox"]
path = deadend_cli/simple-python-interpreter-sandbox
url = https://github.com/xoxruns/simple-python-interpreter-sandbox.git
2 changes: 1 addition & 1 deletion benchmarks/run_xbow_benchmark.sh
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ echo "[+] Launching eval agent with uv run"
echo "[+] Logging uv run output to: $LOG_FILE"
(
cd "$REPO_ROOT/deadend_cli/src/deadend_cli" && \
uv run main.py eval-agent --eval-metadata-file "$META_FILE" --llm-providers azure_ai
uv run main.py eval-agent --eval-metadata-file "$META_FILE" --provider azure_ai --model-name Kimi-K2.5
) 2>&1 | tee "$LOG_FILE"

echo "[+] Stopping benchmark services with make stop"
Expand Down
4 changes: 2 additions & 2 deletions cli/deadend_cli/components/ComponentHealth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface ComponentHealthProps {
// Short display names for components
const COMPONENT_NAMES: Record<string, string> = {
docker: "Docker",
pgvector: "pgvector",
rag: "RAG",
config: "Config",
python_sandbox: "Python",
shell_sandbox: "Shell",
Expand All @@ -31,8 +31,8 @@ const COMPONENT_NAMES: Record<string, string> = {
// Order to display components
const COMPONENT_ORDER = [
"docker",
"pgvector",
"config",
"rag",
"python_sandbox",
"shell_sandbox",
];
Expand Down
8 changes: 4 additions & 4 deletions cli/deadend_cli/hooks/useComponentHealth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { DeadEndRpcClient } from "../runtime/deadend-rpc-client.ts";

export type ComponentName =
| "docker"
| "pgvector"
| "rag"
| "config"
| "python_sandbox"
| "shell_sandbox";
Expand Down Expand Up @@ -104,8 +104,8 @@ export function useComponentHealth(
case "docker":
result = await rpcClient.initDocker();
break;
case "pgvector":
result = await rpcClient.initPgvector();
case "rag":
result = await rpcClient.initRag();
break;
case "config":
result = await rpcClient.initConfig();
Expand Down Expand Up @@ -154,8 +154,8 @@ export function useComponentHealth(

const components: ComponentName[] = [
"docker",
"pgvector",
"config",
"rag",
"python_sandbox",
"shell_sandbox",
];
Expand Down
4 changes: 2 additions & 2 deletions cli/deadend_cli/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function App({ cliArgs }: AppProps) {

// Initialize all components at once using init_all
setInitStatus("Initializing all components...");
// We can wait longer here for pgvector and the sandbox
// Allow time for sandboxes and Playwright during init_all
const initResult = await client.initAll(300000);

// Store component results for display
Expand All @@ -125,7 +125,7 @@ function App({ cliArgs }: AppProps) {
}

// Check for critical failures (all components required for task execution)
const criticalComponents = ["docker", "config", "model_registry", "pgvector", "shell_sandbox"];
const criticalComponents = ["docker", "config", "model_registry", "rag", "shell_sandbox"];
const criticalFailures = initResult.failed_components.filter(
(c) => criticalComponents.includes(c)
);
Expand Down
38 changes: 17 additions & 21 deletions cli/deadend_cli/runtime/deadend-rpc-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
* │ ┌─────────────────────────────────────────────────────────────────────────┐│
* │ │ DeadEndRpcClient ││
* │ │ - runTask() / runTaskWithCallbacks() ││
* │ │ - healthAll() / initDocker() / initPgvector() / ... ││
* │ │ - healthAll() / initDocker() / initRag() / ... ││
* │ │ - subscribeEvents() / interrupt() / approve() ││
* │ └────────────────────────────────────────────────────────────────────────┘│
* │ │ │
Expand Down Expand Up @@ -67,7 +67,7 @@
*
* // Initialize components
* await client.initDocker();
* await client.initPgvector();
* await client.initRag();
* await client.initShellSandbox();
*
* // Run security testing task
Expand Down Expand Up @@ -301,8 +301,8 @@ export interface DeadEndRpcClientOptions extends StdioRpcClientOptions {
*
* Before running tasks, components must be initialized in order:
* 1. `initDocker()` - Docker daemon connection (required)
* 2. `initPgvector()` - Vector database for RAG (optional)
* 3. `initConfig()` - Load LLM API keys and settings
* 2. `initConfig()` - Load LLM API keys and settings
* 3. `initRag()` - SQLite-backed RAG session manager (after config, for storage paths)
* 4. `initShellSandbox()` - Prepare Kali container for shell commands
* 5. `initPythonSandbox()` - Start Python interpreter sandbox
* 6. `initPlaywright()` - Browser automation (optional)
Expand Down Expand Up @@ -443,7 +443,7 @@ export class DeadEndRpcClient {
*
* Returns a comprehensive health report including:
* - Docker daemon connectivity
* - pgvector database status
* - RAG (SQLite) session manager status
* - Python sandbox process status
* - Shell sandbox readiness
* - Playwright browser status
Expand All @@ -466,12 +466,12 @@ export class DeadEndRpcClient {
}

/**
* Checks pgvector database health.
* Checks RAG (SQLite) session manager health.
*
* @returns Promise resolving to HealthResult for pgvector
* @returns Promise resolving to HealthResult for RAG
*/
async healthPgvector(): Promise<HealthResult> {
const result = await this.client.call("health_pgvector");
async healthRag(): Promise<HealthResult> {
const result = await this.client.call("health_rag");
return result as HealthResult;
}

Expand Down Expand Up @@ -523,17 +523,14 @@ export class DeadEndRpcClient {
}

/**
* Initializes the pgvector database container.
* Initializes the SQLite-backed RAG session manager.
*
* Starts the pgvector container if not running and verifies
* database connectivity. Used for RAG (retrieval-augmented generation).
*
* Requires: initDocker() must be called first
* Prefer calling after `initConfig()` so storage paths from config apply.
*
* @returns Promise resolving to InitResult with success status
*/
async initPgvector(): Promise<InitResult> {
const result = await this.client.call("init_pgvector");
async initRag(): Promise<InitResult> {
const result = await this.client.call("init_rag");
return result as InitResult;
}

Expand Down Expand Up @@ -611,9 +608,9 @@ export class DeadEndRpcClient {
* proper dependency order and provides a comprehensive result.
*
* Initialization order:
* 1. Docker (required by pgvector and shell_sandbox)
* 2. Config (required by model_registry)
* 3. pgvector (requires Docker)
* 1. Docker (required by shell_sandbox)
* 2. Config (required by model_registry and RAG paths)
* 3. RAG session manager (SQLite, no Docker)
* 4. Model Registry (requires Config)
* 5. Python sandbox (standalone)
* 6. Shell sandbox (requires Docker)
Expand Down Expand Up @@ -1093,8 +1090,7 @@ export class DeadEndRpcClient {
* - Playwright browser
* - Python sandbox process
* - Shell sandbox containers
* - pgvector database (optional)
* - RAG connector
* - RAG session manager (SQLite)
*
* @returns Promise resolving to shutdown status for each component
*/
Expand Down
4 changes: 1 addition & 3 deletions cli/deadend_cli/types/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,12 +501,10 @@ export interface AgentErrorData {
*
* @property thought - The full reasoning text
* @property summary - Condensed version of the thought
* @property relevance - How relevant this thought is to the task (0.0-1.0)
*/
export interface AgentThoughtData {
thought: string;
summary?: string;
relevance: number;
}

/**
Expand Down Expand Up @@ -647,7 +645,7 @@ export type ComponentStatus =
*
* Returned by health_* RPC methods to report component status.
*
* @property component - Name of the component (docker, pgvector, etc.)
* @property component - Name of the component (docker, rag, config, etc.)
* @property healthy - Whether the component is functioning correctly
* @property status - Current lifecycle state of the component
* @property message - Human-readable status message
Expand Down
Loading
Loading