| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- """可信报告元数据测试。"""
- from datetime import date
- from pathlib import Path
- from tempfile import TemporaryDirectory
- import unittest
- from vendor_guard.report_metadata import (
- stamp_report_date,
- validate_report_risk_semantics,
- )
- class ReportMetadataTests(unittest.TestCase):
- def setUp(self) -> None:
- self.temp_dir = TemporaryDirectory()
- self.addCleanup(self.temp_dir.cleanup)
- self.report_path = Path(self.temp_dir.name) / "report.md"
- def test_replaces_model_generated_report_date(self) -> None:
- self.report_path.write_text(
- "# ACME 报告\n\n**报告日期:2026-05-12**\n",
- encoding="utf-8",
- )
- changed = stamp_report_date(self.report_path, date(2026, 7, 23))
- self.assertTrue(changed)
- report = self.report_path.read_text(encoding="utf-8")
- self.assertIn("**报告日期:** 2026-07-23", report)
- self.assertNotIn("2026-05-12", report)
- def test_inserts_date_when_model_omits_it(self) -> None:
- self.report_path.write_text("# ACME 报告\n\n正文\n", encoding="utf-8")
- stamp_report_date(self.report_path, date(2026, 7, 23))
- report = self.report_path.read_text(encoding="utf-8")
- self.assertTrue(
- report.startswith("# ACME 报告\n\n**报告日期:** 2026-07-23")
- )
- def test_canonical_date_is_idempotent(self) -> None:
- self.report_path.write_text(
- "# ACME 报告\n\n**报告日期:** 2026-07-23\n",
- encoding="utf-8",
- )
- self.assertFalse(
- stamp_report_date(self.report_path, date(2026, 7, 23))
- )
- def test_requires_separate_evidence_status_column(self) -> None:
- self.report_path.write_text(
- "# 报告\n\n### 安全域\n\n| 风险项 | 等级 | 证据位置 |\n",
- encoding="utf-8",
- )
- with self.assertRaisesRegex(ValueError, "证据状态"):
- validate_report_risk_semantics(self.report_path)
- def test_rejects_low_domain_with_medium_detail(self) -> None:
- self.report_path.write_text(
- "# 报告\n\n"
- "| 专业域 | 风险等级 |\n"
- "|---|---|\n"
- "| **安全 (Security)** | **LOW** |\n\n"
- "### 安全域\n\n"
- "| 风险项 | 风险等级 | 证据状态 |\n"
- "|---|---|---|\n"
- "| PT-02 | Medium | 已验证 |\n",
- encoding="utf-8",
- )
- with self.assertRaisesRegex(ValueError, "总评为 low"):
- validate_report_risk_semantics(self.report_path)
- def test_accepts_medium_domain_with_separated_evidence_status(self) -> None:
- self.report_path.write_text(
- "# 报告\n\n"
- "| 专业域 | 风险等级 |\n"
- "|---|---|\n"
- "| **安全 (Security)** | **MEDIUM** |\n\n"
- "### 安全域\n\n"
- "| 风险项 | 风险等级 | 证据状态 |\n"
- "|---|---|---|\n"
- "| PT-02 | Medium | 已验证 |\n"
- "| MFA | Low | 自述待验证 |\n",
- encoding="utf-8",
- )
- validate_report_risk_semantics(self.report_path)
- def test_accepts_numbered_security_domain_heading(self) -> None:
- self.report_path.write_text(
- "# 报告\n\n"
- "| 专业域 | 风险等级 |\n"
- "|---|---|\n"
- "| **安全 (Security)** | **MEDIUM** |\n\n"
- "### 2.1 安全域 — 风险等级:medium\n\n"
- "| 风险项 | 风险等级 | 证据状态 |\n"
- "|---|---|---|\n"
- "| PT-02 | Medium | 已验证 |\n",
- encoding="utf-8",
- )
- validate_report_risk_semantics(self.report_path)
- def test_accepts_numbered_security_review_heading(self) -> None:
- self.report_path.write_text(
- "# UNKNOWN 报告\n\n"
- "| 专业域 | 风险等级 |\n"
- "|---|---|\n"
- "| 安全审查 | high |\n\n"
- "### 3.1 安全审查(Security Review)\n\n"
- "| 风险领域 | 风险等级 | 证据状态 |\n"
- "|---|---|---|\n"
- "| 身份与访问控制 | unknown | 缺失 |\n",
- encoding="utf-8",
- )
- validate_report_risk_semantics(self.report_path)
- def test_accepts_level_two_security_review_with_subsections(self) -> None:
- self.report_path.write_text(
- "# ACME 报告\n\n"
- "| 专业域 | 风险等级 |\n"
- "|---|---|\n"
- "| 安全审查 | medium |\n\n"
- "## 3. 安全审查(Security Review)\n\n"
- "### 3.1 总体评价\n\n"
- "风险等级:medium\n\n"
- "### 3.2 逐项风险\n\n"
- "| 风险项 | 风险等级 | 证据状态 |\n"
- "|---|---|---|\n"
- "| PT-02 | medium | 已验证 |\n\n"
- "## 4. 法务审查\n",
- encoding="utf-8",
- )
- validate_report_risk_semantics(self.report_path)
- if __name__ == "__main__":
- unittest.main()
|