Fix docker container creation issue
This commit is contained in:
@@ -1,126 +0,0 @@
|
|||||||
---
|
|
||||||
description:
|
|
||||||
globs:
|
|
||||||
alwaysApply: true
|
|
||||||
---
|
|
||||||
# Strix Cybersecurity Agent - Project Rules
|
|
||||||
|
|
||||||
## Project Overview
|
|
||||||
|
|
||||||
### Goal and Purpose
|
|
||||||
Strix is a sophisticated cybersecurity agent specialized in vulnerability scanning and security assessment. It provides:
|
|
||||||
- Automated cybersecurity scans and assessments
|
|
||||||
- Web application security testing
|
|
||||||
- Infrastructure vulnerability analysis
|
|
||||||
- Comprehensive security reporting
|
|
||||||
- RESTful API for scan management
|
|
||||||
- CLI interface for direct usage
|
|
||||||
|
|
||||||
The project implements an AI-powered ReAct (Reasoning and Acting) framework for autonomous security testing.
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
### High-Level Architecture
|
|
||||||
```
|
|
||||||
strix-agent/
|
|
||||||
├── strix/ # Core application package
|
|
||||||
│ ├── agents/ # AI agent implementations
|
|
||||||
│ ├── api/ # FastAPI web service
|
|
||||||
│ ├── cli/ # Command-line interface
|
|
||||||
│ ├── llm/ # Language model configurations
|
|
||||||
│ └── tools/ # Security testing tools
|
|
||||||
├── tests/ # Test suite
|
|
||||||
├── evaluation/ # Evaluation framework
|
|
||||||
├── containers/ # Docker configuration
|
|
||||||
└── docs/ # Documentation
|
|
||||||
```
|
|
||||||
|
|
||||||
### Low-Level Structure
|
|
||||||
|
|
||||||
#### Core Components
|
|
||||||
- **[strix/agents/StrixAgent/strix_agent.py](mdc:strix/agents/StrixAgent/strix_agent.py)** - Main cybersecurity agent
|
|
||||||
- **[strix/agents/base_agent.py](mdc:strix/agents/base_agent.py)** - Base agent framework
|
|
||||||
- **[strix/api/main.py](mdc:strix/api/main.py)** - FastAPI application entry point
|
|
||||||
- **[strix/cli/main.py](mdc:strix/cli/main.py)** - CLI entry point
|
|
||||||
- **[pyproject.toml](mdc:pyproject.toml)** - Project configuration and dependencies
|
|
||||||
|
|
||||||
#### API Structure
|
|
||||||
- **[strix/api/routers/](mdc:strix/api/routers)** - API endpoint definitions
|
|
||||||
- **[strix/api/models/](mdc:strix/api/models)** - Pydantic data models
|
|
||||||
- **[strix/api/services/](mdc:strix/api/services)** - Business logic services
|
|
||||||
|
|
||||||
#### Security Tools
|
|
||||||
- **[strix/tools/browser/](mdc:strix/tools/browser)** - Web browser automation
|
|
||||||
- **[strix/tools/terminal/](mdc:strix/tools/terminal)** - Terminal command execution
|
|
||||||
- **[strix/tools/python/](mdc:strix/tools/python)** - Python code execution
|
|
||||||
- **[strix/tools/web_search/](mdc:strix/tools/web_search)** - Web reconnaissance
|
|
||||||
- **[strix/tools/reporting/](mdc:strix/tools/reporting)** - Security report generation
|
|
||||||
|
|
||||||
## Development Guidelines
|
|
||||||
|
|
||||||
### Code Standards
|
|
||||||
- **Simplicity**: Write simple, clean, and modular code
|
|
||||||
- **Functionality**: Prefer functional programming patterns where appropriate
|
|
||||||
- **Efficiency**: Optimize for performance without premature optimization
|
|
||||||
- **No Bloat**: Avoid unnecessary complexity or over-engineering
|
|
||||||
- **Minimal Comments**: Code should be self-documenting; use comments sparingly for complex business logic only
|
|
||||||
|
|
||||||
### Code Quality Requirements
|
|
||||||
- All code MUST pass `make pre-commit` checks
|
|
||||||
- All code MUST pass Ruff linting without warnings
|
|
||||||
- All code MUST pass MyPy type checking without errors
|
|
||||||
- Type hints are required for all function signatures
|
|
||||||
- Follow the strict configuration in [pyproject.toml](mdc:pyproject.toml)
|
|
||||||
|
|
||||||
### Execution Environment
|
|
||||||
- **ALWAYS** use `poetry run` for executing Python scripts and commands
|
|
||||||
- **NEVER** run Python directly with `python` command
|
|
||||||
- Use `poetry run strix-agent` for CLI operations
|
|
||||||
- Use `poetry run uvicorn strix.api.main:app` for API server
|
|
||||||
|
|
||||||
### File Management Rules
|
|
||||||
- **DO NOT** create or edit README.md or any .md documentation files unless explicitly requested
|
|
||||||
- Focus on code implementation, not documentation
|
|
||||||
- Keep docstrings concise and functional
|
|
||||||
|
|
||||||
### Testing and Quality Assurance
|
|
||||||
- Run `make pre-commit` before any commits
|
|
||||||
- Ensure all tests pass with `poetry run pytest`
|
|
||||||
- Use `poetry run mypy .` for type checking
|
|
||||||
- Use `poetry run ruff check .` for linting
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
- All dependencies managed through [pyproject.toml](mdc:pyproject.toml)
|
|
||||||
- Use Poetry for dependency management
|
|
||||||
- Pin versions for production dependencies
|
|
||||||
- Keep dev dependencies in separate group
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
- Application settings in [strix/api/core/config.py](mdc:strix/api/core/config.py)
|
|
||||||
- LLM configuration in [strix/llm/config.py](mdc:strix/llm/config.py)
|
|
||||||
- Agent system prompts in [strix/agents/StrixAgent/system_prompt.jinja](mdc:strix/agents/StrixAgent/system_prompt.jinja)
|
|
||||||
|
|
||||||
## Key Implementation Patterns
|
|
||||||
|
|
||||||
### Agent Framework
|
|
||||||
- Inherit from BaseAgent for new agent implementations
|
|
||||||
- Use ReAct pattern for reasoning and action loops
|
|
||||||
- Implement tools through the registry system in [strix/tools/registry.py](mdc:strix/tools/registry.py)
|
|
||||||
|
|
||||||
### API Development
|
|
||||||
- Use FastAPI with Pydantic models
|
|
||||||
- Implement proper error handling and validation
|
|
||||||
- Follow REST conventions for endpoints
|
|
||||||
- Use Beanie ODM for MongoDB operations
|
|
||||||
|
|
||||||
### Security Tools
|
|
||||||
- Implement tools as action classes with clear interfaces
|
|
||||||
- Use async/await for I/O operations
|
|
||||||
- Implement proper cleanup and resource management
|
|
||||||
- Follow principle of least privilege
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
- Use structured exception handling
|
|
||||||
- Provide meaningful error messages
|
|
||||||
- Log errors appropriately without exposing sensitive information
|
|
||||||
- Implement graceful degradation where possible
|
|
||||||
@@ -21,8 +21,6 @@ INTER-AGENT MESSAGES:
|
|||||||
|
|
||||||
USER INTERACTION:
|
USER INTERACTION:
|
||||||
- Work autonomously by default
|
- Work autonomously by default
|
||||||
- BRIEFLY update user about current state in ONE SENTENCE and don't be repetitive/redundant (e.g., "Scanning port 443 for SSL vulnerabilities..." or "Found SQLi in login form, validating...")
|
|
||||||
- Keep updates concise and informative - no lengthy explanations
|
|
||||||
- NEVER be redundant or repeat information - say it once and move on
|
- NEVER be redundant or repeat information - say it once and move on
|
||||||
- If you need user input, IMMEDIATELY call wait_for_message tool
|
- If you need user input, IMMEDIATELY call wait_for_message tool
|
||||||
- Never ask questions without calling wait_for_message in the same response
|
- Never ask questions without calling wait_for_message in the same response
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import secrets
|
import secrets
|
||||||
@@ -78,11 +79,24 @@ class DockerRuntime(AbstractRuntime):
|
|||||||
|
|
||||||
def _create_container_with_retry(self, scan_id: str, max_retries: int = 3) -> Container:
|
def _create_container_with_retry(self, scan_id: str, max_retries: int = 3) -> Container:
|
||||||
last_exception = None
|
last_exception = None
|
||||||
|
container_name = f"strix-scan-{scan_id}"
|
||||||
|
|
||||||
for attempt in range(max_retries):
|
for attempt in range(max_retries):
|
||||||
try:
|
try:
|
||||||
self._verify_image_available(STRIX_IMAGE)
|
self._verify_image_available(STRIX_IMAGE)
|
||||||
|
|
||||||
|
try:
|
||||||
|
existing_container = self.client.containers.get(container_name)
|
||||||
|
logger.warning(f"Container {container_name} already exists, removing it")
|
||||||
|
with contextlib.suppress(Exception):
|
||||||
|
existing_container.stop(timeout=5)
|
||||||
|
existing_container.remove(force=True)
|
||||||
|
time.sleep(1)
|
||||||
|
except NotFound:
|
||||||
|
pass
|
||||||
|
except DockerException as e:
|
||||||
|
logger.warning(f"Error checking/removing existing container: {e}")
|
||||||
|
|
||||||
caido_port = self._find_available_port()
|
caido_port = self._find_available_port()
|
||||||
tool_server_port = self._find_available_port()
|
tool_server_port = self._find_available_port()
|
||||||
tool_server_token = self._generate_sandbox_token()
|
tool_server_token = self._generate_sandbox_token()
|
||||||
@@ -94,7 +108,7 @@ class DockerRuntime(AbstractRuntime):
|
|||||||
STRIX_IMAGE,
|
STRIX_IMAGE,
|
||||||
command="sleep infinity",
|
command="sleep infinity",
|
||||||
detach=True,
|
detach=True,
|
||||||
name=f"strix-scan-{scan_id}",
|
name=container_name,
|
||||||
hostname=f"strix-scan-{scan_id}",
|
hostname=f"strix-scan-{scan_id}",
|
||||||
ports={
|
ports={
|
||||||
f"{caido_port}/tcp": caido_port,
|
f"{caido_port}/tcp": caido_port,
|
||||||
@@ -137,7 +151,9 @@ class DockerRuntime(AbstractRuntime):
|
|||||||
f"Failed to create Docker container after {max_retries} attempts: {last_exception}"
|
f"Failed to create Docker container after {max_retries} attempts: {last_exception}"
|
||||||
) from last_exception
|
) from last_exception
|
||||||
|
|
||||||
def _get_or_create_scan_container(self, scan_id: str) -> Container:
|
def _get_or_create_scan_container(self, scan_id: str) -> Container: # noqa: PLR0912
|
||||||
|
container_name = f"strix-scan-{scan_id}"
|
||||||
|
|
||||||
if self._scan_container:
|
if self._scan_container:
|
||||||
try:
|
try:
|
||||||
self._scan_container.reload()
|
self._scan_container.reload()
|
||||||
@@ -149,7 +165,43 @@ class DockerRuntime(AbstractRuntime):
|
|||||||
self._tool_server_token = None
|
self._tool_server_token = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
containers = self.client.containers.list(filters={"label": f"strix-scan-id={scan_id}"})
|
container = self.client.containers.get(container_name)
|
||||||
|
container.reload()
|
||||||
|
|
||||||
|
if (
|
||||||
|
"strix-scan-id" not in container.labels
|
||||||
|
or container.labels["strix-scan-id"] != scan_id
|
||||||
|
):
|
||||||
|
logger.warning(
|
||||||
|
f"Container {container_name} exists but missing/wrong label, updating"
|
||||||
|
)
|
||||||
|
|
||||||
|
if container.status != "running":
|
||||||
|
logger.info(f"Starting existing container {container_name}")
|
||||||
|
container.start()
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
|
self._scan_container = container
|
||||||
|
|
||||||
|
for env_var in container.attrs["Config"]["Env"]:
|
||||||
|
if env_var.startswith("TOOL_SERVER_PORT="):
|
||||||
|
self._tool_server_port = int(env_var.split("=")[1])
|
||||||
|
elif env_var.startswith("TOOL_SERVER_TOKEN="):
|
||||||
|
self._tool_server_token = env_var.split("=")[1]
|
||||||
|
|
||||||
|
logger.info(f"Reusing existing container {container_name}")
|
||||||
|
|
||||||
|
except NotFound:
|
||||||
|
pass
|
||||||
|
except DockerException as e:
|
||||||
|
logger.warning(f"Failed to get container by name {container_name}: {e}")
|
||||||
|
else:
|
||||||
|
return container
|
||||||
|
|
||||||
|
try:
|
||||||
|
containers = self.client.containers.list(
|
||||||
|
all=True, filters={"label": f"strix-scan-id={scan_id}"}
|
||||||
|
)
|
||||||
if containers:
|
if containers:
|
||||||
container = cast("Container", containers[0])
|
container = cast("Container", containers[0])
|
||||||
if container.status != "running":
|
if container.status != "running":
|
||||||
@@ -163,9 +215,10 @@ class DockerRuntime(AbstractRuntime):
|
|||||||
elif env_var.startswith("TOOL_SERVER_TOKEN="):
|
elif env_var.startswith("TOOL_SERVER_TOKEN="):
|
||||||
self._tool_server_token = env_var.split("=")[1]
|
self._tool_server_token = env_var.split("=")[1]
|
||||||
|
|
||||||
|
logger.info(f"Found existing container by label for scan {scan_id}")
|
||||||
return container
|
return container
|
||||||
except DockerException as e:
|
except DockerException as e:
|
||||||
logger.warning("Failed to find existing container for scan %s: %s", scan_id, e)
|
logger.warning("Failed to find existing container by label for scan %s: %s", scan_id, e)
|
||||||
|
|
||||||
logger.info("Creating new Docker container for scan %s", scan_id)
|
logger.info("Creating new Docker container for scan %s", scan_id)
|
||||||
return self._create_container_with_retry(scan_id)
|
return self._create_container_with_retry(scan_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user