mirror of
https://github.com/aljazceru/Auditor.git
synced 2025-12-17 03:24:18 +01:00
81 lines
3.6 KiB
Python
81 lines
3.6 KiB
Python
"""Detect universal runtime, DB, and logic patterns in code."""
|
|
|
|
import click
|
|
from pathlib import Path
|
|
from theauditor.utils.helpers import get_self_exclusion_patterns
|
|
|
|
|
|
@click.command("detect-patterns")
|
|
@click.option("--project-path", default=".", help="Root directory to analyze")
|
|
@click.option("--patterns", multiple=True, help="Pattern categories to use (e.g., runtime_issues, db_issues)")
|
|
@click.option("--output-json", help="Path to output JSON file")
|
|
@click.option("--file-filter", help="Glob pattern to filter files")
|
|
@click.option("--max-rows", default=50, type=int, help="Maximum rows to display in table")
|
|
@click.option("--print-stats", is_flag=True, help="Print summary statistics")
|
|
@click.option("--with-ast/--no-ast", default=True, help="Enable AST-based pattern matching")
|
|
@click.option("--with-frameworks/--no-frameworks", default=True, help="Enable framework detection and framework-specific patterns")
|
|
@click.option("--exclude-self", is_flag=True, help="Exclude TheAuditor's own files (for self-testing)")
|
|
def detect_patterns(project_path, patterns, output_json, file_filter, max_rows, print_stats, with_ast, with_frameworks, exclude_self):
|
|
"""Detect universal runtime, DB, and logic patterns in code."""
|
|
from theauditor.pattern_loader import PatternLoader
|
|
from theauditor.universal_detector import UniversalPatternDetector
|
|
|
|
try:
|
|
# Initialize detector
|
|
project_path = Path(project_path).resolve()
|
|
pattern_loader = PatternLoader()
|
|
|
|
# Get exclusion patterns using centralized function
|
|
exclude_patterns = get_self_exclusion_patterns(exclude_self)
|
|
|
|
detector = UniversalPatternDetector(
|
|
project_path,
|
|
pattern_loader,
|
|
with_ast=with_ast,
|
|
with_frameworks=with_frameworks,
|
|
exclude_patterns=exclude_patterns
|
|
)
|
|
|
|
# Run detection
|
|
categories = list(patterns) if patterns else None
|
|
findings = detector.detect_patterns(categories=categories, file_filter=file_filter)
|
|
|
|
# Always save results to default location
|
|
patterns_output = project_path / ".pf" / "raw" / "patterns.json"
|
|
patterns_output.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Save to user-specified location if provided
|
|
if output_json:
|
|
detector.to_json(Path(output_json))
|
|
click.echo(f"\n[OK] Full results saved to: {output_json}")
|
|
|
|
# Save to default location
|
|
detector.to_json(patterns_output)
|
|
click.echo(f"[OK] Full results saved to: {patterns_output}")
|
|
|
|
# Display table
|
|
table = detector.format_table(max_rows=max_rows)
|
|
click.echo(table)
|
|
|
|
# Print statistics if requested
|
|
if print_stats:
|
|
stats = detector.get_summary_stats()
|
|
click.echo("\n--- Summary Statistics ---")
|
|
click.echo(f"Total findings: {stats['total_findings']}")
|
|
click.echo(f"Files affected: {stats['files_affected']}")
|
|
|
|
if stats['by_severity']:
|
|
click.echo("\nBy severity:")
|
|
for severity, count in sorted(stats['by_severity'].items()):
|
|
click.echo(f" {severity}: {count}")
|
|
|
|
if stats['by_category']:
|
|
click.echo("\nBy category:")
|
|
for category, count in sorted(stats['by_category'].items()):
|
|
click.echo(f" {category}: {count}")
|
|
|
|
# Successfully completed - found and reported all issues
|
|
|
|
except Exception as e:
|
|
click.echo(f"Error: {e}", err=True)
|
|
raise click.ClickException(str(e)) from e |