"""检测引擎公共数据结构与基类。""" from __future__ import annotations from dataclasses import dataclass, field from enum import Enum from typing import Any, Dict, List, Optional class Severity(str, Enum): INFO = "info" LOW = "low" MEDIUM = "medium" HIGH = "high" CRITICAL = "critical" class Layer(str, Enum): L0 = "L0" L1 = "L1" L2 = "L2" L2B = "L2B" L3 = "L3" @dataclass class Finding: """单条检测信号。""" engine: str layer: str severity: str rule: str detail: str = "" extracted_path: str = "" weight: float = 0.0 meta: Dict[str, Any] = field(default_factory=dict) def to_dict(self) -> Dict[str, Any]: return { "engine": self.engine, "layer": self.layer, "severity": self.severity, "rule": self.rule, "detail": self.detail, "extracted_path": self.extracted_path, "weight": self.weight, "meta": self.meta, } @dataclass class EngineResult: """单个引擎对单个文件的检测结果。""" engine: str ok: bool = True findings: List[Finding] = field(default_factory=list) meta: Dict[str, Any] = field(default_factory=dict) error: str = "" def to_dict(self) -> Dict[str, Any]: return { "engine": self.engine, "ok": self.ok, "findings": [f.to_dict() for f in self.findings], "meta": self.meta, "error": self.error, } @dataclass class ScanTarget: """待检测文件。""" path: str filename: str declared_ext: str = "" logical_path: str = "" depth: int = 0 is_extracted: bool = False class Engine: """引擎基类。 子类实现 ``scan`` 方法,捕获所有异常并转换为 ``EngineResult.error``, 保证单个引擎故障不会导致整个扫描任务失败。 """ name: str = "base" layer: str = "L0" def scan(self, target: ScanTarget, ctx: Any) -> EngineResult: raise NotImplementedError def safe_scan(self, target: ScanTarget, ctx: Any) -> EngineResult: try: return self.scan(target, ctx) except Exception as exc: # noqa: BLE001 return EngineResult(engine=self.name, ok=False, error=f"{type(exc).__name__}: {exc}") def health(self) -> Dict[str, Any]: """引擎健康状态。子类可覆盖以提供更丰富的探测(如 ClamAV/PING)。 返回结构约定(控制台 dashboard 模板依赖此 schema): { "engine": "clamav", # 引擎名(= self.name) "version": "ClamAV 1.0.x", # 版本描述 "ok": True/False, # 是否可用 "status": "ok"|"error"|"degraded", "error": None | "...", "info": None | "...", } """ return { "engine": self.name, "version": "builtin", "ok": True, "status": "ok", "error": None, "info": None, }