diff --git a/app/services/scanner.py b/app/services/scanner.py index a79b819..915994a 100644 --- a/app/services/scanner.py +++ b/app/services/scanner.py @@ -159,21 +159,37 @@ class ScanOutcome: ) def to_response(self, include_details: bool = True) -> Dict[str, Any]: + """对外接口响应组装。 + + 设计原则:调用方拿了就用,不暴露内部权重、严重度、引擎层、 + 策略链等实现细节。保留追溯所需的 task_id / file 哈希 / 时间戳。 + + 对外暴露 4 个决策驱动字段: + - action: 调用方直接据此决定放行/拦截/转人工 + - reason: 人可读的判定理由 + - task_id: 用于后续查询 / 审计追溯 + - file.*: 文件哈希与真实类型,用于追溯举证 + """ + # file_info 里挑出调用方追溯需要的字段,其他(real_ext/declared_ext 等)砍 + fi = self.file_info or {} + file_out = {k: fi.get(k) for k in ( + "filename", "sha256", "md5", "size", "real_type", + ) if fi.get(k) is not None} + + # meta 只留耗时与时间戳,砍掉 engines/engine_errors/clamav/policy_version + meta_out = {} + for k in ("scan_duration_ms", "scanned_at"): + if self.meta and k in self.meta: + meta_out[k] = self.meta[k] + payload: Dict[str, Any] = { "task_id": self.task_id, - "verdict": self.verdict, - "score": self.score, "action": self.action, "reason": self.reason, "status": "completed", - "file": self.file_info, - "meta": self.meta, - "open_risk": self.open_risk, + "file": file_out, + "meta": meta_out, } - if include_details: - payload["findings"] = [f.to_dict() for f in self.findings] - payload["extracted"] = self.extracted - payload["triggered"] = self.triggered return payload