feat: Migrate from Poetry to uv (#379)

This commit is contained in:
STJ
2026-03-31 17:20:41 -07:00
committed by GitHub
parent e78c931e4e
commit 38b2700553
16 changed files with 6323 additions and 8916 deletions

View File

@@ -30,15 +30,15 @@ jobs:
with: with:
python-version: '3.12' python-version: '3.12'
- uses: snok/install-poetry@v1 - uses: astral-sh/setup-uv@v5
- name: Build - name: Build
shell: bash shell: bash
run: | run: |
poetry install --with dev uv sync --frozen
poetry run pyinstaller strix.spec --noconfirm uv run pyinstaller strix.spec --noconfirm
VERSION=$(poetry version -s) VERSION=$(grep '^version' pyproject.toml | head -1 | sed 's/.*"\(.*\)"/\1/')
mkdir -p dist/release mkdir -p dist/release
if [[ "${{ runner.os }}" == "Windows" ]]; then if [[ "${{ runner.os }}" == "Windows" ]]; then

View File

@@ -31,6 +31,7 @@ repos:
- id: check-toml - id: check-toml
- id: check-merge-conflict - id: check-merge-conflict
- id: check-added-large-files - id: check-added-large-files
args: ['--maxkb=1024']
- id: debug-statements - id: debug-statements
- id: check-case-conflict - id: check-case-conflict
- id: check-docstring-first - id: check-docstring-first

View File

@@ -8,7 +8,7 @@ Thank you for your interest in contributing to Strix! This guide will help you g
- Python 3.12+ - Python 3.12+
- Docker (running) - Docker (running)
- Poetry (for dependency management) - [uv](https://docs.astral.sh/uv/) (for dependency management)
- Git - Git
### Local Development ### Local Development
@@ -24,8 +24,8 @@ Thank you for your interest in contributing to Strix! This guide will help you g
make setup-dev make setup-dev
# or manually: # or manually:
poetry install --with=dev uv sync
poetry run pre-commit install uv run pre-commit install
``` ```
3. **Configure your LLM provider** 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** 4. **Run Strix in development mode**
```bash ```bash
poetry run strix --target https://example.com uv run strix --target https://example.com
``` ```
## 📚 Contributing Skills ## 📚 Contributing Skills

View File

@@ -22,38 +22,38 @@ help:
@echo " clean - Clean up cache files and artifacts" @echo " clean - Clean up cache files and artifacts"
install: install:
poetry install --only=main uv sync --no-dev
dev-install: dev-install:
poetry install --with=dev uv sync
setup-dev: dev-install setup-dev: dev-install
poetry run pre-commit install uv run pre-commit install
@echo "✅ Development environment setup complete!" @echo "✅ Development environment setup complete!"
@echo "Run 'make check-all' to verify everything works correctly." @echo "Run 'make check-all' to verify everything works correctly."
format: format:
@echo "🎨 Formatting code with ruff..." @echo "🎨 Formatting code with ruff..."
poetry run ruff format . uv run ruff format .
@echo "✅ Code formatting complete!" @echo "✅ Code formatting complete!"
lint: lint:
@echo "🔍 Linting code with ruff..." @echo "🔍 Linting code with ruff..."
poetry run ruff check . --fix uv run ruff check . --fix
@echo "📝 Running additional linting with pylint..." @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!" @echo "✅ Linting complete!"
type-check: type-check:
@echo "🔍 Type checking with mypy..." @echo "🔍 Type checking with mypy..."
poetry run mypy strix/ uv run mypy strix/
@echo "🔍 Type checking with pyright..." @echo "🔍 Type checking with pyright..."
poetry run pyright strix/ uv run pyright strix/
@echo "✅ Type checking complete!" @echo "✅ Type checking complete!"
security: security:
@echo "🔒 Running security checks with bandit..." @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!" @echo "✅ Security checks complete!"
check-all: format lint type-check security check-all: format lint type-check security
@@ -61,18 +61,18 @@ check-all: format lint type-check security
test: test:
@echo "🧪 Running tests..." @echo "🧪 Running tests..."
poetry run pytest -v uv run pytest -v
@echo "✅ Tests complete!" @echo "✅ Tests complete!"
test-cov: test-cov:
@echo "🧪 Running tests with coverage..." @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 "✅ Tests with coverage complete!"
@echo "📊 Coverage report generated in htmlcov/" @echo "📊 Coverage report generated in htmlcov/"
pre-commit: pre-commit:
@echo "🔧 Running pre-commit hooks..." @echo "🔧 Running pre-commit hooks..."
poetry run pre-commit run --all-files uv run pre-commit run --all-files
@echo "✅ Pre-commit hooks complete!" @echo "✅ Pre-commit hooks complete!"
clean: clean:

View File

@@ -70,11 +70,7 @@ USER root
RUN cp /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt && \ RUN cp /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt && \
update-ca-certificates update-ca-certificates
RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python3 - && \ RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh
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
USER pentester USER pentester
WORKDIR /tmp WORKDIR /tmp
@@ -171,9 +167,8 @@ RUN apt-get autoremove -y && \
apt-get autoclean && \ apt-get autoclean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 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 PATH="/home/pentester/go/bin:/home/pentester/.local/bin:/home/pentester/.npm-global/bin:/app/.venv/bin:$PATH"
ENV VIRTUAL_ENV="/app/venv" ENV VIRTUAL_ENV="/app/.venv"
ENV POETRY_HOME="/opt/poetry"
WORKDIR /app 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 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 USER pentester
RUN poetry install --no-root --without dev --extras sandbox RUN uv sync --frozen --no-dev --extra sandbox
RUN poetry run playwright install chromium 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 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/__init__.py strix/
COPY strix/config/ /app/strix/config/ COPY strix/config/ /app/strix/config/
COPY strix/utils/ /app/strix/utils/ COPY strix/utils/ /app/strix/utils/

View File

@@ -155,12 +155,11 @@ echo "Starting tool server..."
cd /app cd /app
export PYTHONPATH=/app export PYTHONPATH=/app
export STRIX_SANDBOX_MODE=true export STRIX_SANDBOX_MODE=true
export POETRY_VIRTUALENVS_CREATE=false
export TOOL_SERVER_TIMEOUT="${STRIX_SANDBOX_EXECUTION_TIMEOUT:-120}" export TOOL_SERVER_TIMEOUT="${STRIX_SANDBOX_EXECUTION_TIMEOUT:-120}"
TOOL_SERVER_LOG="/tmp/tool_server.log" TOOL_SERVER_LOG="/tmp/tool_server.log"
sudo -E -u pentester \ 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" \ --token="$TOOL_SERVER_TOKEN" \
--host=0.0.0.0 \ --host=0.0.0.0 \
--port="$TOOL_SERVER_PORT" \ --port="$TOOL_SERVER_PORT" \

View File

@@ -9,7 +9,7 @@ description: "Contribute to Strix development"
- Python 3.12+ - Python 3.12+
- Docker (running) - Docker (running)
- Poetry - [uv](https://docs.astral.sh/uv/)
- Git - Git
### Local Development ### Local Development
@@ -26,8 +26,8 @@ description: "Contribute to Strix development"
make setup-dev make setup-dev
# or manually: # or manually:
poetry install --with=dev uv sync
poetry run pre-commit install uv run pre-commit install
``` ```
</Step> </Step>
<Step title="Configure LLM"> <Step title="Configure LLM">
@@ -38,7 +38,7 @@ description: "Contribute to Strix development"
</Step> </Step>
<Step title="Run Strix"> <Step title="Run Strix">
```bash ```bash
poetry run strix --target https://example.com uv run strix --target https://example.com
``` ```
</Step> </Step>
</Steps> </Steps>

8794
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,13 @@
[tool.poetry] [project]
name = "strix-agent" name = "strix-agent"
version = "0.8.3" version = "0.8.3"
description = "Open-source AI Hackers for your apps" description = "Open-source AI Hackers for your apps"
authors = ["Strix <hi@usestrix.com>"]
readme = "README.md" readme = "README.md"
license = "Apache-2.0" license = "Apache-2.0"
requires-python = ">=3.12"
authors = [
{ name = "Strix", email = "hi@usestrix.com" },
]
keywords = [ keywords = [
"cybersecurity", "cybersecurity",
"security", "security",
@@ -29,81 +32,62 @@ classifiers = [
"Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14", "Programming Language :: Python :: 3.14",
] ]
packages = [ dependencies = [
{ include = "strix", format = ["sdist", "wheel"] } "litellm[proxy]>=1.81.1,<1.82.0",
] "tenacity>=9.0.0",
include = [ "pydantic[email]>=2.11.3",
"LICENSE", "rich",
"README.md", "docker>=7.1.0",
"strix/agents/**/*.jinja", "textual>=6.0.0",
"strix/skills/**/*.md", "xmltodict>=0.13.0",
"strix/**/*.xml", "requests>=2.32.0",
"strix/**/*.tcss" "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" strix = "strix.interface.main:main"
[tool.poetry.dependencies] [project.optional-dependencies]
python = "^3.12" vertex = ["google-cloud-aiplatform>=1.38"]
# Core CLI dependencies sandbox = [
litellm = { version = "~1.81.1", extras = ["proxy"] } "fastapi",
tenacity = "^9.0.0" "uvicorn",
pydantic = {extras = ["email"], version = "^2.11.3"} "ipython>=9.3.0",
rich = "*" "openhands-aci>=0.3.0",
docker = "^7.1.0" "playwright>=1.48.0",
textual = "^4.0.0" "gql[requests]>=3.5.3",
xmltodict = "^0.13.0" "pyte>=0.8.1",
requests = "^2.32.0" "libtmux>=0.46.2",
cvss = "^3.2" "numpydoc>=1.8.0",
traceloop-sdk = "^0.53.0" ]
opentelemetry-exporter-otlp-proto-http = "^1.40.0"
scrubadub = "^2.0.1"
# Optional LLM provider dependencies [dependency-groups]
google-cloud-aiplatform = { version = ">=1.38", optional = true } dev = [
"mypy>=1.16.0",
# Sandbox-only dependencies (only needed inside Docker container) "ruff>=0.11.13",
fastapi = { version = "*", optional = true } "pyright>=1.1.401",
uvicorn = { version = "*", optional = true } "pylint>=3.3.7",
ipython = { version = "^9.3.0", optional = true } "bandit>=1.8.3",
openhands-aci = { version = "^0.3.0", optional = true } "pytest>=8.4.0",
playwright = { version = "^1.48.0", optional = true } "pytest-asyncio>=1.0.0",
gql = { version = "^3.5.3", extras = ["requests"], optional = true } "pytest-cov>=6.1.1",
pyte = { version = "^0.8.1", optional = true } "pytest-mock>=3.14.1",
libtmux = { version = "^0.46.2", optional = true } "pre-commit>=4.2.0",
numpydoc = { version = "^1.8.0", optional = true } "black>=25.1.0",
defusedxml = "^0.7.1" "isort>=6.0.1",
"pyinstaller>=6.17.0; python_version >= '3.12' and python_version < '3.15'",
[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" }
[build-system] [build-system]
requires = ["poetry-core"] requires = ["hatchling"]
build-backend = "poetry.core.masonry.api" build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["strix"]
# ============================================================================ # ============================================================================
# Type Checking Configuration # Type Checking Configuration

View File

@@ -33,23 +33,23 @@ echo -e "${YELLOW}Platform:${NC} $OS_NAME-$ARCH_NAME"
cd "$PROJECT_ROOT" cd "$PROJECT_ROOT"
if ! command -v poetry &> /dev/null; then if ! command -v uv &> /dev/null; then
echo -e "${RED}Error: Poetry is not installed${NC}" echo -e "${RED}Error: uv is not installed${NC}"
echo "Please install Poetry first: https://python-poetry.org/docs/#installation" echo "Please install uv first: https://docs.astral.sh/uv/getting-started/installation/"
exit 1 exit 1
fi fi
echo -e "\n${BLUE}Installing dependencies...${NC}" 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 "${YELLOW}Version:${NC} $VERSION"
echo -e "\n${BLUE}Cleaning previous builds...${NC}" echo -e "\n${BLUE}Cleaning previous builds...${NC}"
rm -rf build/ dist/ rm -rf build/ dist/
echo -e "\n${BLUE}Building binary with PyInstaller...${NC}" 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" RELEASE_DIR="dist/release"
mkdir -p "$RELEASE_DIR" mkdir -p "$RELEASE_DIR"

16
scripts/docker.sh Executable file
View 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"

View File

@@ -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). - 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: PROGRAMMING:
- Python 3, Poetry, Go, Node.js/npm - Python 3, uv, Go, Node.js/npm
- Full development environment - Full development environment
- Docker is NOT available inside the sandbox. Do not run docker; rely on provided tools to run locally. - 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.) - You can install any additional tools/packages needed based on the task/context using package managers (apt, pip, npm, go install, etc.)

View File

@@ -1077,7 +1077,7 @@ class StrixTUIApp(App): # type: ignore[misc]
combined.append("\n") combined.append("\n")
StrixTUIApp._append_renderable(combined, sub) StrixTUIApp._append_renderable(combined, sub)
else: else:
inner = getattr(item, "renderable", None) inner = getattr(item, "content", None) or getattr(item, "renderable", None)
if inner is not None: if inner is not None:
StrixTUIApp._append_renderable(combined, inner) StrixTUIApp._append_renderable(combined, inner)
else: else:
@@ -1171,7 +1171,7 @@ class StrixTUIApp(App): # type: ignore[misc]
renderer = get_tool_renderer(tool_name) renderer = get_tool_renderer(tool_name)
if renderer: if renderer:
widget = renderer.render(tool_data) widget = renderer.render(tool_data)
return widget.renderable return widget.content
return self._render_default_streaming_tool(tool_name, args, is_complete) return self._render_default_streaming_tool(tool_name, args, is_complete)
@@ -1709,7 +1709,7 @@ class StrixTUIApp(App): # type: ignore[misc]
if renderer: if renderer:
widget = renderer.render(tool_data) widget = renderer.render(tool_data)
return widget.renderable return widget.content
text = Text() text = Text()

View File

@@ -1,9 +1,10 @@
import json import json
import logging import logging
import threading import threading
from collections.abc import Callable
from datetime import UTC, datetime from datetime import UTC, datetime
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Optional from typing import Any, Optional
from uuid import uuid4 from uuid import uuid4
from opentelemetry import trace from opentelemetry import trace
@@ -36,6 +37,7 @@ _OTEL_BOOTSTRAP_LOCK = threading.Lock()
_OTEL_BOOTSTRAPPED = False _OTEL_BOOTSTRAPPED = False
_OTEL_REMOTE_ENABLED = False _OTEL_REMOTE_ENABLED = False
def get_global_tracer() -> Optional["Tracer"]: def get_global_tracer() -> Optional["Tracer"]:
return _global_tracer return _global_tracer

View File

@@ -124,7 +124,6 @@ def iso_from_unix_ns(unix_ns: int | None) -> str | None:
return None return None
def get_events_write_lock(output_path: Path) -> threading.Lock: def get_events_write_lock(output_path: Path) -> threading.Lock:
path_key = str(output_path.resolve(strict=False)) path_key = str(output_path.resolve(strict=False))
with _EVENTS_FILE_LOCKS_LOCK: with _EVENTS_FILE_LOCKS_LOCK:

6206
uv.lock generated Normal file

File diff suppressed because it is too large Load Diff