from __future__ import annotations from dataclasses import dataclass from pathlib import Path import tomllib from .models import Severity DEFAULT_EXCLUDES = (".git", ".venv", "__pycache__", "build", "dist", "node_modules") @dataclass(frozen=True, slots=True) class Config: max_file_bytes: int = 2 * 1024 * 1024 minimum_severity: Severity = Severity.LOW exclude: tuple[str, ...] = DEFAULT_EXCLUDES enabled_rules: tuple[str, ...] | None = None @classmethod def from_file(cls, path: Path | None) -> "Config": if path is None: return cls() with path.open("rb") as handle: data = tomllib.load(handle) scan = data.get("scan", {}) rules = data.get("rules", {}) max_bytes = int(scan.get("max_file_bytes", cls.max_file_bytes)) if max_bytes < 1: raise ValueError("scan.max_file_bytes must be positive") excluded = tuple(str(item) for item in scan.get("exclude", DEFAULT_EXCLUDES)) enabled = rules.get("enabled") return cls( max_file_bytes=max_bytes, minimum_severity=Severity.parse(str(scan.get("minimum_severity", "low"))), exclude=excluded, enabled_rules=tuple(str(item) for item in enabled) if enabled is not None else None, ) STARTER_CONFIG = """[scan] max_file_bytes = 2097152 minimum_severity = "low" exclude = [".git", ".venv", "__pycache__", "build", "dist", "node_modules"] [rules] enabled = [ "AAISA-SECRET-001", "AAISA-PROMPT-001", "AAISA-DEPENDENCY-001", "AAISA-CONTAINER-001", "AAISA-PROVENANCE-001", "AAISA-AGENT-001", "AAISA-PROVENANCE-002", "AAISA-MLBOM-001", ] """