feat: Migrate from Poetry to uv (#379)
This commit is contained in:
8
.github/workflows/build-release.yml
vendored
8
.github/workflows/build-release.yml
vendored
@@ -30,15 +30,15 @@ jobs:
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- uses: snok/install-poetry@v1
|
||||
- uses: astral-sh/setup-uv@v5
|
||||
|
||||
- name: Build
|
||||
shell: bash
|
||||
run: |
|
||||
poetry install --with dev
|
||||
poetry run pyinstaller strix.spec --noconfirm
|
||||
uv sync --frozen
|
||||
uv run pyinstaller strix.spec --noconfirm
|
||||
|
||||
VERSION=$(poetry version -s)
|
||||
VERSION=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
||||
mkdir -p dist/release
|
||||
|
||||
if [[ "${{ runner.os }}" == "Windows" ]]; then
|
||||
|
||||
@@ -31,6 +31,7 @@ repos:
|
||||
- id: check-toml
|
||||
- id: check-merge-conflict
|
||||
- id: check-added-large-files
|
||||
args: ['--maxkb=1024']
|
||||
- id: debug-statements
|
||||
- id: check-case-conflict
|
||||
- id: check-docstring-first
|
||||
|
||||
@@ -8,7 +8,7 @@ Thank you for your interest in contributing to Strix! This guide will help you g
|
||||
|
||||
- Python 3.12+
|
||||
- Docker (running)
|
||||
- Poetry (for dependency management)
|
||||
- [uv](https://docs.astral.sh/uv/) (for dependency management)
|
||||
- Git
|
||||
|
||||
### Local Development
|
||||
@@ -24,8 +24,8 @@ Thank you for your interest in contributing to Strix! This guide will help you g
|
||||
make setup-dev
|
||||
|
||||
# or manually:
|
||||
poetry install --with=dev
|
||||
poetry run pre-commit install
|
||||
uv sync
|
||||
uv run pre-commit install
|
||||
```
|
||||
|
||||
3. **Configure your LLM provider**
|
||||
@@ -36,7 +36,7 @@ Thank you for your interest in contributing to Strix! This guide will help you g
|
||||
|
||||
4. **Run Strix in development mode**
|
||||
```bash
|
||||
poetry run strix --target https://example.com
|
||||
uv run strix --target https://example.com
|
||||
```
|
||||
|
||||
## 📚 Contributing Skills
|
||||
|
||||
24
Makefile
24
Makefile
@@ -22,38 +22,38 @@ help:
|
||||
@echo " clean - Clean up cache files and artifacts"
|
||||
|
||||
install:
|
||||
poetry install --only=main
|
||||
uv sync --no-dev
|
||||
|
||||
dev-install:
|
||||
poetry install --with=dev
|
||||
uv sync
|
||||
|
||||
setup-dev: dev-install
|
||||
poetry run pre-commit install
|
||||
uv run pre-commit install
|
||||
@echo "✅ Development environment setup complete!"
|
||||
@echo "Run 'make check-all' to verify everything works correctly."
|
||||
|
||||
format:
|
||||
@echo "🎨 Formatting code with ruff..."
|
||||
poetry run ruff format .
|
||||
uv run ruff format .
|
||||
@echo "✅ Code formatting complete!"
|
||||
|
||||
lint:
|
||||
@echo "🔍 Linting code with ruff..."
|
||||
poetry run ruff check . --fix
|
||||
uv run ruff check . --fix
|
||||
@echo "📝 Running additional linting with pylint..."
|
||||
poetry run pylint strix/ --score=no --reports=no
|
||||
uv run pylint strix/ --score=no --reports=no
|
||||
@echo "✅ Linting complete!"
|
||||
|
||||
type-check:
|
||||
@echo "🔍 Type checking with mypy..."
|
||||
poetry run mypy strix/
|
||||
uv run mypy strix/
|
||||
@echo "🔍 Type checking with pyright..."
|
||||
poetry run pyright strix/
|
||||
uv run pyright strix/
|
||||
@echo "✅ Type checking complete!"
|
||||
|
||||
security:
|
||||
@echo "🔒 Running security checks with bandit..."
|
||||
poetry run bandit -r strix/ -c pyproject.toml
|
||||
uv run bandit -r strix/ -c pyproject.toml
|
||||
@echo "✅ Security checks complete!"
|
||||
|
||||
check-all: format lint type-check security
|
||||
@@ -61,18 +61,18 @@ check-all: format lint type-check security
|
||||
|
||||
test:
|
||||
@echo "🧪 Running tests..."
|
||||
poetry run pytest -v
|
||||
uv run pytest -v
|
||||
@echo "✅ Tests complete!"
|
||||
|
||||
test-cov:
|
||||
@echo "🧪 Running tests with coverage..."
|
||||
poetry run pytest -v --cov=strix --cov-report=term-missing --cov-report=html
|
||||
uv run pytest -v --cov=strix --cov-report=term-missing --cov-report=html
|
||||
@echo "✅ Tests with coverage complete!"
|
||||
@echo "📊 Coverage report generated in htmlcov/"
|
||||
|
||||
pre-commit:
|
||||
@echo "🔧 Running pre-commit hooks..."
|
||||
poetry run pre-commit run --all-files
|
||||
uv run pre-commit run --all-files
|
||||
@echo "✅ Pre-commit hooks complete!"
|
||||
|
||||
clean:
|
||||
|
||||
@@ -70,11 +70,7 @@ USER root
|
||||
RUN cp /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt && \
|
||||
update-ca-certificates
|
||||
|
||||
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python3 - && \
|
||||
ln -s /opt/poetry/bin/poetry /usr/local/bin/poetry && \
|
||||
chmod +x /usr/local/bin/poetry && \
|
||||
python3 -m venv /app/venv && \
|
||||
chown -R pentester:pentester /app/venv /opt/poetry
|
||||
RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh
|
||||
|
||||
USER pentester
|
||||
WORKDIR /tmp
|
||||
@@ -171,9 +167,8 @@ RUN apt-get autoremove -y && \
|
||||
apt-get autoclean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
ENV PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:/app/venv/bin:$PATH"
|
||||
ENV VIRTUAL_ENV="/app/venv"
|
||||
ENV POETRY_HOME="/opt/poetry"
|
||||
ENV PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:/app/.venv/bin:$PATH"
|
||||
ENV VIRTUAL_ENV="/app/.venv"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -198,17 +193,16 @@ ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
||||
RUN mkdir -p /workspace && chown -R pentester:pentester /workspace /app
|
||||
|
||||
COPY pyproject.toml poetry.lock ./
|
||||
COPY pyproject.toml uv.lock ./
|
||||
RUN echo "# Sandbox Environment" > README.md && mkdir -p strix && touch strix/__init__.py
|
||||
|
||||
USER pentester
|
||||
RUN poetry install --no-root --without dev --extras sandbox
|
||||
RUN poetry run playwright install chromium
|
||||
RUN uv sync --frozen --no-dev --extra sandbox
|
||||
RUN /app/.venv/bin/python -m playwright install chromium
|
||||
|
||||
RUN /app/venv/bin/pip install -r /home/pentester/tools/jwt_tool/requirements.txt && \
|
||||
RUN uv pip install -r /home/pentester/tools/jwt_tool/requirements.txt && \
|
||||
ln -s /home/pentester/tools/jwt_tool/jwt_tool.py /home/pentester/.local/bin/jwt_tool
|
||||
|
||||
RUN echo "# Sandbox Environment" > README.md
|
||||
|
||||
COPY strix/__init__.py strix/
|
||||
COPY strix/config/ /app/strix/config/
|
||||
COPY strix/utils/ /app/strix/utils/
|
||||
|
||||
@@ -155,12 +155,11 @@ echo "Starting tool server..."
|
||||
cd /app
|
||||
export PYTHONPATH=/app
|
||||
export STRIX_SANDBOX_MODE=true
|
||||
export POETRY_VIRTUALENVS_CREATE=false
|
||||
export TOOL_SERVER_TIMEOUT="${STRIX_SANDBOX_EXECUTION_TIMEOUT:-120}"
|
||||
TOOL_SERVER_LOG="/tmp/tool_server.log"
|
||||
|
||||
sudo -E -u pentester \
|
||||
poetry run python -m strix.runtime.tool_server \
|
||||
/app/.venv/bin/python -m strix.runtime.tool_server \
|
||||
--token="$TOOL_SERVER_TOKEN" \
|
||||
--host=0.0.0.0 \
|
||||
--port="$TOOL_SERVER_PORT" \
|
||||
|
||||
@@ -9,7 +9,7 @@ description: "Contribute to Strix development"
|
||||
|
||||
- Python 3.12+
|
||||
- Docker (running)
|
||||
- Poetry
|
||||
- [uv](https://docs.astral.sh/uv/)
|
||||
- Git
|
||||
|
||||
### Local Development
|
||||
@@ -26,8 +26,8 @@ description: "Contribute to Strix development"
|
||||
make setup-dev
|
||||
|
||||
# or manually:
|
||||
poetry install --with=dev
|
||||
poetry run pre-commit install
|
||||
uv sync
|
||||
uv run pre-commit install
|
||||
```
|
||||
</Step>
|
||||
<Step title="Configure LLM">
|
||||
@@ -38,7 +38,7 @@ description: "Contribute to Strix development"
|
||||
</Step>
|
||||
<Step title="Run Strix">
|
||||
```bash
|
||||
poetry run strix --target https://example.com
|
||||
uv run strix --target https://example.com
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
8794
poetry.lock
generated
8794
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
124
pyproject.toml
124
pyproject.toml
@@ -1,10 +1,13 @@
|
||||
[tool.poetry]
|
||||
[project]
|
||||
name = "strix-agent"
|
||||
version = "0.8.3"
|
||||
description = "Open-source AI Hackers for your apps"
|
||||
authors = ["Strix <hi@usestrix.com>"]
|
||||
readme = "README.md"
|
||||
license = "Apache-2.0"
|
||||
requires-python = ">=3.12"
|
||||
authors = [
|
||||
{ name = "Strix", email = "hi@usestrix.com" },
|
||||
]
|
||||
keywords = [
|
||||
"cybersecurity",
|
||||
"security",
|
||||
@@ -29,81 +32,62 @@ classifiers = [
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
]
|
||||
packages = [
|
||||
{ include = "strix", format = ["sdist", "wheel"] }
|
||||
]
|
||||
include = [
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"strix/agents/**/*.jinja",
|
||||
"strix/skills/**/*.md",
|
||||
"strix/**/*.xml",
|
||||
"strix/**/*.tcss"
|
||||
dependencies = [
|
||||
"litellm[proxy]>=1.81.1,<1.82.0",
|
||||
"tenacity>=9.0.0",
|
||||
"pydantic[email]>=2.11.3",
|
||||
"rich",
|
||||
"docker>=7.1.0",
|
||||
"textual>=6.0.0",
|
||||
"xmltodict>=0.13.0",
|
||||
"requests>=2.32.0",
|
||||
"cvss>=3.2",
|
||||
"traceloop-sdk>=0.53.0",
|
||||
"opentelemetry-exporter-otlp-proto-http>=1.40.0",
|
||||
"scrubadub>=2.0.1",
|
||||
"defusedxml>=0.7.1",
|
||||
]
|
||||
|
||||
[tool.poetry.scripts]
|
||||
[project.scripts]
|
||||
strix = "strix.interface.main:main"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
# Core CLI dependencies
|
||||
litellm = { version = "~1.81.1", extras = ["proxy"] }
|
||||
tenacity = "^9.0.0"
|
||||
pydantic = {extras = ["email"], version = "^2.11.3"}
|
||||
rich = "*"
|
||||
docker = "^7.1.0"
|
||||
textual = "^4.0.0"
|
||||
xmltodict = "^0.13.0"
|
||||
requests = "^2.32.0"
|
||||
cvss = "^3.2"
|
||||
traceloop-sdk = "^0.53.0"
|
||||
opentelemetry-exporter-otlp-proto-http = "^1.40.0"
|
||||
scrubadub = "^2.0.1"
|
||||
[project.optional-dependencies]
|
||||
vertex = ["google-cloud-aiplatform>=1.38"]
|
||||
sandbox = [
|
||||
"fastapi",
|
||||
"uvicorn",
|
||||
"ipython>=9.3.0",
|
||||
"openhands-aci>=0.3.0",
|
||||
"playwright>=1.48.0",
|
||||
"gql[requests]>=3.5.3",
|
||||
"pyte>=0.8.1",
|
||||
"libtmux>=0.46.2",
|
||||
"numpydoc>=1.8.0",
|
||||
]
|
||||
|
||||
# Optional LLM provider dependencies
|
||||
google-cloud-aiplatform = { version = ">=1.38", optional = true }
|
||||
|
||||
# Sandbox-only dependencies (only needed inside Docker container)
|
||||
fastapi = { version = "*", optional = true }
|
||||
uvicorn = { version = "*", optional = true }
|
||||
ipython = { version = "^9.3.0", optional = true }
|
||||
openhands-aci = { version = "^0.3.0", optional = true }
|
||||
playwright = { version = "^1.48.0", optional = true }
|
||||
gql = { version = "^3.5.3", extras = ["requests"], optional = true }
|
||||
pyte = { version = "^0.8.1", optional = true }
|
||||
libtmux = { version = "^0.46.2", optional = true }
|
||||
numpydoc = { version = "^1.8.0", optional = true }
|
||||
defusedxml = "^0.7.1"
|
||||
|
||||
[tool.poetry.extras]
|
||||
vertex = ["google-cloud-aiplatform"]
|
||||
sandbox = ["fastapi", "uvicorn", "ipython", "openhands-aci", "playwright", "gql", "pyte", "libtmux", "numpydoc"]
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
# Type checking and static analysis
|
||||
mypy = "^1.16.0"
|
||||
ruff = "^0.11.13"
|
||||
pyright = "^1.1.401"
|
||||
pylint = "^3.3.7"
|
||||
bandit = "^1.8.3"
|
||||
|
||||
# Testing
|
||||
pytest = "^8.4.0"
|
||||
pytest-asyncio = "^1.0.0"
|
||||
pytest-cov = "^6.1.1"
|
||||
pytest-mock = "^3.14.1"
|
||||
|
||||
# Development tools
|
||||
pre-commit = "^4.2.0"
|
||||
black = "^25.1.0"
|
||||
isort = "^6.0.1"
|
||||
|
||||
# Build tools
|
||||
pyinstaller = { version = "^6.17.0", python = ">=3.12,<3.15" }
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"mypy>=1.16.0",
|
||||
"ruff>=0.11.13",
|
||||
"pyright>=1.1.401",
|
||||
"pylint>=3.3.7",
|
||||
"bandit>=1.8.3",
|
||||
"pytest>=8.4.0",
|
||||
"pytest-asyncio>=1.0.0",
|
||||
"pytest-cov>=6.1.1",
|
||||
"pytest-mock>=3.14.1",
|
||||
"pre-commit>=4.2.0",
|
||||
"black>=25.1.0",
|
||||
"isort>=6.0.1",
|
||||
"pyinstaller>=6.17.0; python_version >= '3.12' and python_version < '3.15'",
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["strix"]
|
||||
|
||||
# ============================================================================
|
||||
# Type Checking Configuration
|
||||
|
||||
@@ -33,23 +33,23 @@ echo -e "${YELLOW}Platform:${NC} $OS_NAME-$ARCH_NAME"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
if ! command -v poetry &> /dev/null; then
|
||||
echo -e "${RED}Error: Poetry is not installed${NC}"
|
||||
echo "Please install Poetry first: https://python-poetry.org/docs/#installation"
|
||||
if ! command -v uv &> /dev/null; then
|
||||
echo -e "${RED}Error: uv is not installed${NC}"
|
||||
echo "Please install uv first: https://docs.astral.sh/uv/getting-started/installation/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n${BLUE}Installing dependencies...${NC}"
|
||||
poetry install --with dev
|
||||
uv sync --frozen
|
||||
|
||||
VERSION=$(poetry version -s)
|
||||
VERSION=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
|
||||
echo -e "${YELLOW}Version:${NC} $VERSION"
|
||||
|
||||
echo -e "\n${BLUE}Cleaning previous builds...${NC}"
|
||||
rm -rf build/ dist/
|
||||
|
||||
echo -e "\n${BLUE}Building binary with PyInstaller...${NC}"
|
||||
poetry run pyinstaller strix.spec --noconfirm
|
||||
uv run pyinstaller strix.spec --noconfirm
|
||||
|
||||
RELEASE_DIR="dist/release"
|
||||
mkdir -p "$RELEASE_DIR"
|
||||
|
||||
16
scripts/docker.sh
Executable file
16
scripts/docker.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
IMAGE="strix-sandbox"
|
||||
TAG="${1:-dev}"
|
||||
|
||||
echo "Building $IMAGE:$TAG ..."
|
||||
docker build \
|
||||
-f "$PROJECT_ROOT/containers/Dockerfile" \
|
||||
-t "$IMAGE:$TAG" \
|
||||
"$PROJECT_ROOT"
|
||||
|
||||
echo "Done: $IMAGE:$TAG"
|
||||
@@ -484,7 +484,7 @@ PROXY & INTERCEPTION:
|
||||
- Ignore Caido proxy-generated 50x HTML error pages; these are proxy issues (might happen when requesting a wrong host or SSL/TLS issues, etc).
|
||||
|
||||
PROGRAMMING:
|
||||
- Python 3, Poetry, Go, Node.js/npm
|
||||
- Python 3, uv, Go, Node.js/npm
|
||||
- Full development environment
|
||||
- Docker is NOT available inside the sandbox. Do not run docker; rely on provided tools to run locally.
|
||||
- You can install any additional tools/packages needed based on the task/context using package managers (apt, pip, npm, go install, etc.)
|
||||
|
||||
@@ -1077,7 +1077,7 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
combined.append("\n")
|
||||
StrixTUIApp._append_renderable(combined, sub)
|
||||
else:
|
||||
inner = getattr(item, "renderable", None)
|
||||
inner = getattr(item, "content", None) or getattr(item, "renderable", None)
|
||||
if inner is not None:
|
||||
StrixTUIApp._append_renderable(combined, inner)
|
||||
else:
|
||||
@@ -1171,7 +1171,7 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
renderer = get_tool_renderer(tool_name)
|
||||
if renderer:
|
||||
widget = renderer.render(tool_data)
|
||||
return widget.renderable
|
||||
return widget.content
|
||||
|
||||
return self._render_default_streaming_tool(tool_name, args, is_complete)
|
||||
|
||||
@@ -1709,7 +1709,7 @@ class StrixTUIApp(App): # type: ignore[misc]
|
||||
|
||||
if renderer:
|
||||
widget = renderer.render(tool_data)
|
||||
return widget.renderable
|
||||
return widget.content
|
||||
|
||||
text = Text()
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Optional
|
||||
from typing import Any, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from opentelemetry import trace
|
||||
@@ -36,6 +37,7 @@ _OTEL_BOOTSTRAP_LOCK = threading.Lock()
|
||||
_OTEL_BOOTSTRAPPED = False
|
||||
_OTEL_REMOTE_ENABLED = False
|
||||
|
||||
|
||||
def get_global_tracer() -> Optional["Tracer"]:
|
||||
return _global_tracer
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ def iso_from_unix_ns(unix_ns: int | None) -> str | None:
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def get_events_write_lock(output_path: Path) -> threading.Lock:
|
||||
path_key = str(output_path.resolve(strict=False))
|
||||
with _EVENTS_FILE_LOCKS_LOCK:
|
||||
|
||||
Reference in New Issue
Block a user