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
+58 -9
View File
@@ -119,6 +119,10 @@ def check_file(filepath: Path) -> list[str]:
except ValueError:
src_plugin = ""
# Core files (outside builtins) cannot declare plugin dependencies —
# any cross-plugin import from Core is always a violation.
is_core_file = src_plugin == ""
with open(filepath, encoding="utf-8") as f:
for line_num, line in enumerate(f, 1):
line_stripped = line.strip()
@@ -143,6 +147,30 @@ def check_file(filepath: Path) -> list[str]:
if tgt_plugin == src_plugin:
continue
# Core files cannot import plugin internals — always a violation
# regardless of any 'Declared dependency' annotation.
if is_core_file:
violations.append(
f"{rel_path}:{line_num}: {line_stripped}\n"
f" → Core→Plugin import forbidden: '{tgt_plugin}.{tgt_module}'. "
f"Use contracts: get_contract(\"{tgt_plugin}\")"
)
continue
# Plugin→Plugin: check if declared in manifest.dependencies
if not is_core_file and src_plugin:
import re as _re
manifest_path = BUILTINS_DIR / src_plugin / "plugin.py"
declared_deps: set[str] = set()
if manifest_path.exists():
with open(manifest_path, encoding="utf-8") as mf:
manifest_content = mf.read()
dep_match = _re.search(r'dependencies=\[([^\]]*)\]', manifest_content)
if dep_match:
declared_deps = set(_re.findall(r'"([^"]+)"', dep_match.group(1)))
if tgt_plugin in declared_deps:
continue # Declared dependency — allowed
# Skip if it's a contract import via the central registry
if CONTRACT_IMPORT_PATTERN.match(line):
continue
@@ -158,17 +186,38 @@ def check_file(filepath: Path) -> list[str]:
def find_python_files(search_path: Path | None = None) -> list[Path]:
"""Find all Python files in the search path."""
if search_path is None:
search_path = BUILTINS_DIR
"""Find all Python files in the search path.
Default: scans both app/plugins/builtins/ (Plugin→Plugin) and
app/core/, app/services/, app/routes/, app/commands/, app/ai/ (Core→Plugin).
"""
if search_path is not None:
files: list[Path] = []
for root, dirs, fnames in os.walk(search_path):
dirs[:] = [d for d in dirs if d not in EXEMPT_DIRS]
for fname in fnames:
if fname.endswith(".py"):
files.append(Path(root) / fname)
return sorted(files)
# Default: scan both plugin and core directories
files: list[Path] = []
for root, dirs, fnames in os.walk(search_path):
# Skip exempt directories
dirs[:] = [d for d in dirs if d not in EXEMPT_DIRS]
for fname in fnames:
if fname.endswith(".py"):
files.append(Path(root) / fname)
scan_dirs = [
BUILTINS_DIR,
PROJECT_ROOT / "app" / "core",
PROJECT_ROOT / "app" / "services",
PROJECT_ROOT / "app" / "routes",
PROJECT_ROOT / "app" / "commands",
PROJECT_ROOT / "app" / "ai",
]
for scan_dir in scan_dirs:
if not scan_dir.exists():
continue
for root, dirs, fnames in os.walk(scan_dir):
dirs[:] = [d for d in dirs if d not in EXEMPT_DIRS]
for fname in fnames:
if fname.endswith(".py"):
files.append(Path(root) / fname)
return sorted(files)