[project] name = "strix-agent" version = "1.0.4" description = "Open-source AI Hackers for your apps" readme = "README.md" license = "Apache-2.0" requires-python = ">=3.12" authors = [ { name = "Strix", email = "hi@usestrix.com" }, ] keywords = [ "cybersecurity", "security", "vulnerability", "scanner", "pentest", "agent", "ai", "cli", ] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "Topic :: Security", "License :: OSI Approved :: Apache Software License", "Environment :: Console", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", ] dependencies = [ "openai-agents[litellm]==0.14.6", "pydantic>=2.11.3", "pydantic-settings>=2.13.0", "rich", "docker>=7.1.0", "textual>=6.0.0", "requests>=2.32.0", "cvss>=3.2", "caido-sdk-client>=0.2.0", ] [project.scripts] strix = "strix.interface.main:main" [dependency-groups] dev = [ "mypy>=1.16.0", "ruff>=0.11.13", "pyright>=1.1.401", "bandit>=1.8.3", "pre-commit>=4.2.0", "pyinstaller>=6.17.0; python_version >= '3.12' and python_version < '3.15'", "pytest>=8.3", "pytest-asyncio>=0.24", ] [tool.pytest.ini_options] asyncio_mode = "auto" [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["strix"] # ============================================================================ # Type Checking Configuration # ============================================================================ [tool.mypy] python_version = "3.12" strict = true strict_optional = true warn_redundant_casts = true warn_unused_ignores = true warn_return_any = true warn_unreachable = true disallow_untyped_defs = true disallow_any_generics = true disallow_subclassing_any = true disallow_untyped_calls = true disallow_incomplete_defs = true check_untyped_defs = true disallow_untyped_decorators = true no_implicit_optional = true warn_unused_configs = true show_error_codes = true show_column_numbers = true pretty = true # Allow some flexibility for third-party libraries [[tool.mypy.overrides]] module = [ "litellm.*", "rich.*", "jinja2.*", "textual.*", "cvss.*", "docker.*", "caido_sdk_client.*", "pydantic_settings.*", ] ignore_missing_imports = true disable_error_code = ["import-untyped"] [[tool.mypy.overrides]] module = ["tests.*"] disallow_untyped_decorators = false # ============================================================================ # Ruff Configuration (Fast Python Linter & Formatter) # ============================================================================ [tool.ruff] target-version = "py312" line-length = 100 extend-exclude = [ ".git", ".mypy_cache", ".ruff_cache", "__pycache__", "build", "dist", "migrations", ] [tool.ruff.lint] # Enable comprehensive rule sets select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # Pyflakes "I", # isort "N", # pep8-naming "UP", # pyupgrade "YTT", # flake8-2020 "S", # flake8-bandit "BLE", # flake8-blind-except "FBT", # flake8-boolean-trap "B", # flake8-bugbear "A", # flake8-builtins "COM", # flake8-commas "C4", # flake8-comprehensions "DTZ", # flake8-datetimez "T10", # flake8-debugger "EM", # flake8-errmsg "FA", # flake8-future-annotations "ISC", # flake8-implicit-str-concat "ICN", # flake8-import-conventions "G", # flake8-logging-format "INP", # flake8-no-pep420 "PIE", # flake8-pie "T20", # flake8-print "PYI", # flake8-pyi "Q", # flake8-quotes "RSE", # flake8-raise "RET", # flake8-return "SLF", # flake8-self "SIM", # flake8-simplify "TID", # flake8-tidy-imports "TCH", # flake8-type-checking "ARG", # flake8-unused-arguments "PTH", # flake8-use-pathlib "ERA", # eradicate "PD", # pandas-vet "PGH", # pygrep-hooks "PL", # Pylint "TRY", # tryceratops "FLY", # flynt "PERF", # Perflint "RUF", # Ruff-specific rules ] ignore = [ "S101", # Use of assert "S104", # Possible binding to all interfaces "S301", # Use of pickle "COM812", # Missing trailing comma (handled by formatter) "ISC001", # Single line implicit string concatenation (handled by formatter) "PLR0913", # Too many arguments to function call "TRY003", # Avoid specifying long messages outside the exception class "EM101", # Exception must not use a string literal "EM102", # Exception must not use an f-string literal "FBT001", # Boolean positional arg in function definition "FBT002", # Boolean default positional argument in function definition "G004", # Logging statement uses f-string "PLR2004", # Magic value used in comparison "SLF001", # Private member accessed ] [tool.ruff.lint.per-file-ignores] # Lazy imports inside functions to avoid circular dependency with # strix.telemetry / strix.report.dedupe / cvss. "strix/tools/notes/tools.py" = ["PLC0415", "TC002"] "strix/tools/finish/tool.py" = ["PLC0415", "TC002"] "strix/tools/reporting/tool.py" = ["PLC0415", "TC002"] "strix/tools/**/*.py" = [ "ARG001", # Unused function argument (tools may have unused args for interface consistency) ] # Custom Docker subclass duplicates parent body; some imports are for annotations. # Backend factories import their backend's deps lazily so deployments # that pick a different backend don't need every backend's libs installed. "strix/runtime/backends.py" = ["PLC0415"] "strix/runtime/docker_client.py" = [ "TC002", # Manifest, Container imported for annotations "TC003", # uuid imported for annotation ] # SDK function-tool wrappers: the SDK calls get_type_hints() at registration # time to derive the JSON schema, which evaluates annotations at runtime — # so RunContextWrapper / Tool / TResponseInputItem must be imported eagerly, # not under TYPE_CHECKING. "strix/tools/todo/tools.py" = ["TC002"] "strix/tools/thinking/tool.py" = ["TC002"] "strix/tools/web_search/tool.py" = ["TC002"] "strix/tools/proxy/tools.py" = ["TC002", "PLR0911"] "strix/tools/agents_graph/tools.py" = ["TC002"] "strix/agents/factory.py" = ["TC002"] # Entry point: ``Path`` is used at runtime by the typing of the # session_manager call; importing under TYPE_CHECKING would defer # resolution past where mypy needs it. "strix/core/runner.py" = ["TC003", "PLR0912", "PLR0915", "PLC0415"] # ReportState carries scan artifact/report fields and # a runtime ``Callable`` annotation on ``vulnerability_found_callback``. "strix/report/state.py" = ["TC003", "PLR0912", "PLR0915", "E501", "PERF401"] "strix/report/usage.py" = ["PLC0415"] "strix/config/models.py" = ["PLC0415"] # Interface utility branches per scope-mode / target-type combination; # splitting would obscure the decision tree without simplifying it. "strix/interface/utils.py" = ["PLR0912", "BLE001", "PLC0415"] # CLI / TUI / main keep extensive lazy imports + broad exception # swallows for resilience around terminal-rendering errors. "strix/interface/cli.py" = ["BLE001", "PLC0415"] "strix/interface/tui/app.py" = ["BLE001", "PLC0415", "PLR0912", "PLR0915", "SIM105"] "strix/interface/main.py" = ["BLE001", "PLC0415", "PLR0912", "PLR0915"] "strix/interface/tui/renderers/agent_message_renderer.py" = ["PLC0415"] [tool.ruff.lint.isort] force-single-line = false lines-after-imports = 2 known-first-party = ["strix"] known-third-party = ["pydantic"] [tool.ruff.lint.pylint] max-args = 8 [tool.ruff.format] quote-style = "double" indent-style = "space" skip-magic-trailing-comma = false line-ending = "auto" # ============================================================================ # PyRight Configuration (Alternative type checker) # ============================================================================ [tool.pyright] include = ["strix"] exclude = ["**/__pycache__", "build", "dist"] pythonVersion = "3.12" pythonPlatform = "Linux" typeCheckingMode = "strict" reportMissingImports = true reportMissingTypeStubs = false reportGeneralTypeIssues = true reportPropertyTypeMismatch = true reportFunctionMemberAccess = true reportMissingParameterType = true reportMissingTypeArgument = true reportIncompatibleMethodOverride = true reportIncompatibleVariableOverride = true reportInconsistentConstructor = true reportOverlappingOverload = true reportConstantRedefinition = true reportImportCycles = true reportUnusedImport = true reportUnusedClass = true reportUnusedFunction = true reportUnusedVariable = true reportDuplicateImport = true # ============================================================================ # Black Configuration (Code Formatter) # ============================================================================ [tool.black] line-length = 100 target-version = ['py312'] include = '\\.pyi?$' extend-exclude = ''' /( # directories \.eggs | \.git | \.hg | \.mypy_cache | \.tox | \.venv | build | dist )/ ''' # ============================================================================ # isort Configuration (Import Sorting) # ============================================================================ [tool.isort] profile = "black" line_length = 100 multi_line_output = 3 include_trailing_comma = true force_grid_wrap = 0 use_parentheses = true ensure_newline_before_comments = true known_first_party = ["strix"] known_third_party = ["pydantic", "litellm"] # ============================================================================ # Bandit Configuration (Security Linting) # ============================================================================ [tool.bandit] exclude_dirs = ["docs", "build", "dist"] skips = ["B101", "B601", "B404", "B603", "B607"] # Skip assert, shell injection, subprocess import and partial path checks severity = "medium"