fix(security): remove eval-based config parsing
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""ASV benchmarks for SEC1 config security scanner.
|
||||
|
||||
Measures performance of the security scanner across varying content sizes
|
||||
and numbers of violations to establish a baseline for config parsing
|
||||
performance.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from cleveragents.config.security_scanner import (
|
||||
scan_content,
|
||||
scan_file,
|
||||
validate_config_safety,
|
||||
)
|
||||
except ModuleNotFoundError:
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
from cleveragents.config.security_scanner import (
|
||||
scan_content,
|
||||
scan_file,
|
||||
validate_config_safety,
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fixtures
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_CLEAN_SMALL = "name: project\nversion: 1.0.0\ndescription: safe\n"
|
||||
|
||||
_CLEAN_LARGE = "\n".join(f"key_{i}: value_{i}" for i in range(500))
|
||||
|
||||
_DIRTY_SMALL = "safe: true\ntransform: eval('1+1')\nrunner: exec('import os')\n"
|
||||
|
||||
_DIRTY_LARGE = "\n".join(
|
||||
f"item_{i}: eval('x')" if i % 50 == 0 else f"item_{i}: safe" for i in range(500)
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Benchmark suites
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TimeScanContent:
|
||||
"""Benchmark scan_content on in-memory strings."""
|
||||
|
||||
def time_clean_small(self) -> None:
|
||||
"""Scan a small clean config string."""
|
||||
scan_content(_CLEAN_SMALL, "<bench>")
|
||||
|
||||
def time_clean_large(self) -> None:
|
||||
"""Scan a large clean config string (500 lines)."""
|
||||
scan_content(_CLEAN_LARGE, "<bench>")
|
||||
|
||||
def time_dirty_small(self) -> None:
|
||||
"""Scan a small config with violations."""
|
||||
scan_content(_DIRTY_SMALL, "<bench>")
|
||||
|
||||
def time_dirty_large(self) -> None:
|
||||
"""Scan a large config with scattered violations."""
|
||||
scan_content(_DIRTY_LARGE, "<bench>")
|
||||
|
||||
|
||||
class TimeValidateConfigSafety:
|
||||
"""Benchmark validate_config_safety (raises on violations)."""
|
||||
|
||||
def time_clean_content(self) -> None:
|
||||
"""Validate clean content (no exception)."""
|
||||
validate_config_safety(_CLEAN_SMALL, "<bench>")
|
||||
|
||||
def time_dirty_content_caught(self) -> None:
|
||||
"""Validate dirty content (exception caught)."""
|
||||
with contextlib.suppress(Exception):
|
||||
validate_config_safety(_DIRTY_SMALL, "<bench>")
|
||||
|
||||
|
||||
class TimeScanFile:
|
||||
"""Benchmark scan_file on actual project files."""
|
||||
|
||||
def setup(self) -> None:
|
||||
"""Locate a real config file for benchmarking."""
|
||||
self.pyproject_path = Path("pyproject.toml")
|
||||
if not self.pyproject_path.exists():
|
||||
self.pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
||||
if not self.pyproject_path.exists():
|
||||
raise FileNotFoundError(
|
||||
"pyproject.toml not found — TimeScanFile benchmark cannot run"
|
||||
)
|
||||
|
||||
def time_scan_pyproject_toml(self) -> None:
|
||||
"""Scan pyproject.toml for violations."""
|
||||
scan_file(self.pyproject_path)
|
||||
Reference in New Issue
Block a user