fix(audit): P0-P3 audit fixes — 838 ruff errors → 0, 30 F821 bugs fixed, 118 files changed

- P0: hooks.py 3-tuple fix, trigger_dispatcher Contract, contacts/plugin unregister_actions_by_owner
- P0: 5 test files — check_permission mocks removed, hardcoded DB credential → env var
- P1: attachment_service DmsFile via Contract helper, restore_registry/history_hooks dedup
- P1: mail/plugin restore unregister, mcp_client datetime.now(UTC), saved_views/filters patterns
- P1: ProtectedRoute fail-closed, 13 test assertion fixes (bcrypt, DB-URLs, SECRET_KEYs)
- P2: deprecated notifications → post_system_message (3 files), forgejo Base, report_generator lazy import
- P2: webhooks permissions, deps.py/roles.py plugin perms removed, import_export default
- P2: address/tags/entity_links patterns removed, worker.py Contract-Umgehungen fixed
- P2: 28 frontend TODOs (hardcoded constants, deprecated notification API)
- P3: dead code, duplicates, deprecated imports, private attr, __import__ inline
- P3: 8 frontend TODOs (LucideIcons, inline styles, XSS, i18n)
- ruff: 838 → 0 (612 auto-fix + 246 manual + 27 F821 regression fix)
- F821: 30 → 0 (AutomationDefinition, DmsFile, user_id, Path, Any, String)
- Contract-Umgehungen: 2 neue gefunden (worker.py:169, worker.py:280) und gefixt
This commit is contained in:
Agent Zero
2026-08-16 01:17:18 +02:00
parent 3d9b76cea4
commit abbe7a18fc
306 changed files with 5912 additions and 1827 deletions
+21 -18
View File
@@ -21,8 +21,8 @@ import json
import logging
import os
import uuid
from datetime import datetime, timezone
from typing import Any, TYPE_CHECKING
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any
import litellm
@@ -100,7 +100,7 @@ _PERMANENT_KEYWORDS = frozenset(
def _get_cost_key(tenant_id: uuid.UUID | str) -> str:
"""Build the Redis cost-tracking key for the current month."""
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
month_str = now.strftime("%Y-%m")
return f"cost:tenant:{tenant_id}:month:{month_str}"
@@ -204,7 +204,7 @@ async def _check_cost_alerts(
return
thresholds = [0.50, 0.80, 1.00]
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
month_str = now.strftime("%Y-%m")
try:
@@ -226,11 +226,11 @@ async def _check_cost_alerts(
# Best-effort system notification
if db is not None:
try:
from app.core.notifications import post_system_message
# Need a user_id — try to find an admin for this tenant
from sqlalchemy import select as sa_select
from app.core.notifications import post_system_message
from app.models.user import User, UserTenant
from app.models.role import Role
async with db.begin_nested() if db.in_transaction() else _NoopCtx():
result = await db.execute(
@@ -289,11 +289,12 @@ async def get_api_credentials(
# Fallback to DB provider
if db and tenant_id:
try:
from app.plugins.builtins.ai_assistant.contracts import get_default_provider
provider = await get_default_provider(db, tenant_id)
if provider and provider.api_key:
return provider.api_key, provider.base_url, provider.provider_type
from app.plugins.builtins.contracts import get_contract
ai_contract = get_contract("ai_assistant")
if ai_contract is not None:
provider = await ai_contract.get_default_provider(db, tenant_id)
if provider and provider.api_key:
return provider.api_key, provider.base_url, provider.provider_type
except Exception:
logger.debug("Failed to get provider from DB, falling back to env")
@@ -316,9 +317,11 @@ async def get_provider_compliance(
if not (db and tenant_id):
return None
try:
from app.plugins.builtins.ai_assistant.contracts import get_default_provider
provider = await get_default_provider(db, tenant_id)
from app.plugins.builtins.contracts import get_contract
ai_contract = get_contract("ai_assistant")
if ai_contract is None:
return None
provider = await ai_contract.get_default_provider(db, tenant_id)
if provider is None:
return None
return {
@@ -449,7 +452,7 @@ def _extract_usage(response: Any) -> dict[str, int]:
# ──────────────────────────────────────────────────────────────────────────
async def llm_complete(
async def llm_complete( # noqa: ASYNC109
model: str,
messages: list[dict[str, Any]],
tools: list[dict[str, Any]] | None = None,
@@ -459,7 +462,7 @@ async def llm_complete(
api_base: str | None = None,
provider: str | None = None,
response_format: dict[str, Any] | None = None,
timeout: int = DEFAULT_TIMEOUT,
timeout: int = DEFAULT_TIMEOUT, # noqa: ASYNC109
max_retries: int = DEFAULT_MAX_RETRIES,
trace_id: str | None = None,
tenant_id: uuid.UUID | str | None = None,
@@ -578,7 +581,7 @@ async def llm_complete(
raise last_exc
async def llm_embed(
async def llm_embed( # noqa: ASYNC109
texts: str | list[str],
model: str | None = None,
db: AsyncSession | None = None,
@@ -587,7 +590,7 @@ async def llm_embed(
api_base: str | None = None,
provider: str | None = None,
dimensions: int | None = None,
timeout: int = DEFAULT_TIMEOUT,
timeout: int = DEFAULT_TIMEOUT, # noqa: ASYNC109
trace_id: str | None = None,
) -> list[list[float]]:
"""Generic text embedding via LiteLLM.