mirror of
https://github.com/msoedov/agentic_security.git
synced 2026-09-29 03:11:51 +02:00
feat: move to python 3.14 baseline, patch remaining dependabot alerts
- requires-python >=3.14, pyupgrade --py314-plus, Dockerfile python:3.14-slim - test matrix 3.14 only - fastapi ^0.141.1 + starlette 1.6.0 (unblocks 5 starlette alerts) - python-multipart ^0.0.31 (4 alerts) - fix TemplateResponse for starlette 1.x request-first signature - drop teyit hook: abandoned, incompatible with python 3.14
This commit is contained in:
@@ -16,7 +16,6 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version:
|
||||
- "3.12"
|
||||
- "3.14"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -6,7 +6,7 @@ repos:
|
||||
rev: v3.21.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
args: [--py312-plus]
|
||||
args: [--py314-plus]
|
||||
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 26.3.1
|
||||
@@ -64,11 +64,7 @@ repos:
|
||||
rev: v2.6.0
|
||||
hooks:
|
||||
- id: pycln
|
||||
|
||||
- repo: https://github.com/isidentical/teyit
|
||||
rev: 0.4.3
|
||||
hooks:
|
||||
- id: teyit
|
||||
language_version: python3.14
|
||||
|
||||
- repo: https://github.com/python-poetry/poetry
|
||||
rev: '2.4.1'
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
# Build stage
|
||||
FROM python:3.12-slim AS builder
|
||||
FROM python:3.14-slim AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -26,7 +26,7 @@ RUN pip install --upgrade pip setuptools wheel
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Runtime stage
|
||||
FROM python:3.12-slim
|
||||
FROM python:3.14-slim
|
||||
|
||||
# Set environment variables
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
@@ -35,7 +35,7 @@ ENV PYTHONUNBUFFERED=1
|
||||
WORKDIR /app
|
||||
|
||||
# Copy only the necessary files from the builder stage
|
||||
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
|
||||
COPY --from=builder /usr/local/lib/python3.14/site-packages /usr/local/lib/python3.14/site-packages
|
||||
COPY --from=builder /usr/local/bin /usr/local/bin
|
||||
|
||||
# Copy application code
|
||||
|
||||
@@ -9,7 +9,7 @@ class AttackRuleSeverity(Enum):
|
||||
HIGH = "high"
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, value: str) -> "AttackRuleSeverity":
|
||||
def from_string(cls, value: str) -> AttackRuleSeverity:
|
||||
try:
|
||||
return cls(value.lower())
|
||||
except ValueError:
|
||||
@@ -28,7 +28,7 @@ class AttackRule:
|
||||
metadata: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any]) -> "AttackRule":
|
||||
def from_dict(cls, data: dict[str, Any]) -> AttackRule:
|
||||
severity = AttackRuleSeverity.from_string(data.get("severity", "medium"))
|
||||
return cls(
|
||||
name=data["name"],
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Utilities to keep cache-to-disk storage in a writable, predictable location."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class LLMSpec(BaseModel):
|
||||
try:
|
||||
body_json = json.loads(self.body)
|
||||
return body_json.get("model", "unknown")
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
except json.JSONDecodeError, TypeError:
|
||||
return "unknown"
|
||||
|
||||
@property
|
||||
|
||||
@@ -28,7 +28,7 @@ class Scan(BaseModel):
|
||||
# Set and managed by the backend
|
||||
secrets: dict[str, str] = Field(default_factory=dict)
|
||||
|
||||
def with_secrets(self, secrets) -> "Scan":
|
||||
def with_secrets(self, secrets) -> Scan:
|
||||
match secrets:
|
||||
case dict():
|
||||
self.secrets.update(secrets)
|
||||
|
||||
@@ -66,7 +66,7 @@ MAX_INJECTION_ATTEMPTS = settings_var("fuzzer.max_injection_attempts", 20)
|
||||
|
||||
async def generate_prompts(
|
||||
prompts: list[str] | AsyncGenerator,
|
||||
) -> AsyncGenerator[str, None]:
|
||||
) -> AsyncGenerator[str]:
|
||||
"""
|
||||
Asynchronously generates and yields individual prompts.
|
||||
|
||||
@@ -227,7 +227,7 @@ async def scan_module(
|
||||
optimize: bool = False,
|
||||
stop_event: asyncio.Event | None = None,
|
||||
token_counter: dict[str, int] | None = None,
|
||||
) -> AsyncGenerator[dict[str, Any], None]:
|
||||
) -> AsyncGenerator[dict[str, Any]]:
|
||||
"""
|
||||
Scan a single module.
|
||||
|
||||
@@ -390,7 +390,7 @@ async def perform_single_shot_scan(
|
||||
stop_event: asyncio.Event | None = None,
|
||||
secrets: dict[str, str] | None = None,
|
||||
inline_datasets: list[dict[str, Any]] | None = None,
|
||||
) -> AsyncGenerator[str, None]:
|
||||
) -> AsyncGenerator[str]:
|
||||
"""
|
||||
Perform a standard security scan using a given request factory.
|
||||
|
||||
@@ -491,7 +491,7 @@ async def perform_many_shot_scan(
|
||||
probe_frequency: float = 0.2,
|
||||
max_ctx_length: int = 10_000,
|
||||
secrets: dict[str, str] | None = None,
|
||||
) -> AsyncGenerator[str, None]:
|
||||
) -> AsyncGenerator[str]:
|
||||
"""
|
||||
Perform a multi-step security scan with probe injection.
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class HybridRefusalClassifier:
|
||||
detector: RefusalDetector,
|
||||
weight: float = 1.0,
|
||||
name: str | None = None,
|
||||
) -> "HybridRefusalClassifier":
|
||||
) -> HybridRefusalClassifier:
|
||||
"""Add a detection method with specified weight.
|
||||
|
||||
Args:
|
||||
|
||||
@@ -4,8 +4,6 @@ Provides a small, dependency-free detector for responses that may contain
|
||||
sensitive personal or credential material.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from re import Pattern
|
||||
|
||||
@@ -27,8 +27,6 @@ Example configuration::
|
||||
threshold = 3
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Callable, Mapping
|
||||
|
||||
@@ -5,8 +5,6 @@ to break out of Docker/Kubernetes container isolation (capability probing,
|
||||
mount inspection, kernel/exploit reconnaissance).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from re import Pattern
|
||||
|
||||
@@ -70,7 +70,7 @@ def get_static_file(filepath: Path, content_type: str | None = None) -> FileResp
|
||||
@router.get("/", response_class=HTMLResponse)
|
||||
async def root(request: Request) -> Response:
|
||||
"""Serve the main index.html template."""
|
||||
return templates.TemplateResponse("index.html", {"request": request})
|
||||
return templates.TemplateResponse(request, "index.html")
|
||||
|
||||
|
||||
@router.get("/main.js")
|
||||
|
||||
Generated
+19
-24
@@ -148,7 +148,6 @@ attrs = ">=17.3.0"
|
||||
frozenlist = ">=1.1.1"
|
||||
multidict = ">=4.5,<7.0"
|
||||
propcache = ">=0.2.0"
|
||||
typing_extensions = {version = ">=4.4", markers = "python_version < \"3.13\""}
|
||||
yarl = ">=1.17.0,<2.0"
|
||||
|
||||
[package.extras]
|
||||
@@ -168,7 +167,6 @@ files = [
|
||||
|
||||
[package.dependencies]
|
||||
frozenlist = ">=1.1.0"
|
||||
typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""}
|
||||
|
||||
[[package]]
|
||||
name = "annotated-doc"
|
||||
@@ -239,7 +237,6 @@ files = [
|
||||
[package.dependencies]
|
||||
idna = ">=2.8"
|
||||
sniffio = ">=1.1"
|
||||
typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
trio = ["trio (>=0.26.1)"]
|
||||
@@ -987,26 +984,27 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.122.0"
|
||||
version = "0.141.1"
|
||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "fastapi-0.122.0-py3-none-any.whl", hash = "sha256:a456e8915dfc6c8914a50d9651133bd47ec96d331c5b44600baa635538a30d67"},
|
||||
{file = "fastapi-0.122.0.tar.gz", hash = "sha256:cd9b5352031f93773228af8b4c443eedc2ac2aa74b27780387b853c3726fb94b"},
|
||||
{file = "fastapi-0.141.1-py3-none-any.whl", hash = "sha256:bfb91aa2d334c61cb35ba9a116fc123b3d3df31640b801cf57a7a78ec3f603b3"},
|
||||
{file = "fastapi-0.141.1.tar.gz", hash = "sha256:e8822fc40db1e1858054d7a949a888695bc9bdce70139178e33bd2871a453ca1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-doc = ">=0.0.2"
|
||||
pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
|
||||
starlette = ">=0.40.0,<0.51.0"
|
||||
pydantic = ">=2.9.0"
|
||||
starlette = ">=0.46.0"
|
||||
typing-extensions = ">=4.8.0"
|
||||
typing-inspection = ">=0.4.2"
|
||||
|
||||
[package.extras]
|
||||
all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
|
||||
all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.32)", "httpx (>=0.23.0,<1.0.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.32)", "fastar (>=0.9.0)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
|
||||
standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.32)", "httpx (>=0.23.0,<1.0.0)", "jinja2 (>=3.1.5)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "fastjsonschema"
|
||||
@@ -3878,7 +3876,6 @@ files = [
|
||||
|
||||
[package.dependencies]
|
||||
pytest = ">=8.2,<10"
|
||||
typing-extensions = {version = ">=4.12", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"]
|
||||
@@ -3960,14 +3957,14 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pyt
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.27"
|
||||
version = "0.0.31"
|
||||
description = "A streaming multipart parser for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "python_multipart-0.0.27-py3-none-any.whl", hash = "sha256:6fccfad17a27334bd0193681b369f476eda3409f17381a2d65aa7df3f7275645"},
|
||||
{file = "python_multipart-0.0.27.tar.gz", hash = "sha256:9870a6a8c5a20a5bf4f07c017bd1489006ff8836cff097b6933355ee2b49b602"},
|
||||
{file = "python_multipart-0.0.31-py3-none-any.whl", hash = "sha256:8408153d68a9773291fc1da39a8b85a50044bddbabd2dd72e9229776b7b15e28"},
|
||||
{file = "python_multipart-0.0.31.tar.gz", hash = "sha256:fc631183bb13e56db3158a4909908dfb2e23565286744e798241e63750e5d680"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4266,7 +4263,6 @@ files = [
|
||||
[package.dependencies]
|
||||
attrs = ">=22.2.0"
|
||||
rpds-py = ">=0.7.0"
|
||||
typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""}
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
@@ -4761,22 +4757,21 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.50.0"
|
||||
version = "1.6.0"
|
||||
description = "The little ASGI library that shines."
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca"},
|
||||
{file = "starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca"},
|
||||
{file = "starlette-1.6.0-py3-none-any.whl", hash = "sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c"},
|
||||
{file = "starlette-1.6.0.tar.gz", hash = "sha256:d4e3ac5e546444960c710297a3c9fc3f7ebae1b7e963f3d36173b49da535be9b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = ">=3.6.2,<5"
|
||||
typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""}
|
||||
|
||||
[package.extras]
|
||||
full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
|
||||
full = ["httpx (>=0.27.0,<0.29.0)", "httpx2 (>=2.0.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"]
|
||||
|
||||
[[package]]
|
||||
name = "tabulate"
|
||||
@@ -5399,5 +5394,5 @@ propcache = ">=0.2.1"
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.12,<4.0"
|
||||
content-hash = "dc2edc6c72835e82a8954273da5ae9e1c231686ff73886a9f962410a384b3f1f"
|
||||
python-versions = ">=3.14,<4.0"
|
||||
content-hash = "c49467950cab4b9cc0f103ef570770421926fa223ecc155620d9863a9677407b"
|
||||
|
||||
+3
-3
@@ -6,7 +6,7 @@ authors = [{ name = "Alexander Miasoiedov", email = "msoedov@gmail.com" }]
|
||||
maintainers = [{ name = "Alexander Miasoiedov", email = "msoedov@gmail.com" }]
|
||||
license = "Apache-2.0"
|
||||
readme = "Readme.md"
|
||||
requires-python = ">=3.12,<4.0"
|
||||
requires-python = ">=3.14,<4.0"
|
||||
keywords = [
|
||||
"LLM vulnerability scanner",
|
||||
"llm security",
|
||||
@@ -32,7 +32,7 @@ agentic_security = "agentic_security.__main__:main"
|
||||
packages = [{ include = "agentic_security", from = "." }]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
fastapi = "^0.122.0"
|
||||
fastapi = "^0.141.1"
|
||||
uvicorn = "^0.38.0"
|
||||
fire = "0.7.1"
|
||||
loguru = "^0.7.3"
|
||||
@@ -48,7 +48,7 @@ scikit-optimize = "^0.10.2"
|
||||
scikit-learn = "^1.7.2"
|
||||
numpy = ">=1.24.3,<3.0.0"
|
||||
jinja2 = "^3.1.4"
|
||||
python-multipart = "^0.0.27"
|
||||
python-multipart = "^0.0.31"
|
||||
tomli = "^2.3.0"
|
||||
rich = "^14.2.0"
|
||||
gTTS = "^2.5.4"
|
||||
|
||||
Reference in New Issue
Block a user