main
py 155 lines 6.9 KB
Raw
1 from typing import Dict
2 from typing import List
3 from typing import Optional
4
5 from pydantic import BaseModel
6 from pydantic import Field
7
8
9 # Request schemas
10 class PatchTuesdayRequest(BaseModel):
11 """Request to fetch Patch Tuesday data for a specific cycle"""
12
13 cycle: Optional[str] = Field(
14 None,
15 description="CVRF doc id in format YYYY-Mmm (e.g., 2026-Jan). Defaults to current month.",
16 pattern=r"^\d{4}-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)$",
17 )
18 include_epss: bool = Field(True, description="Include EPSS scores in the response")
19 include_kev: bool = Field(True, description="Include CISA KEV data in the response")
20
21
22 class PatchTuesdayCVESearchRequest(BaseModel):
23 """Request to search for specific CVEs in Patch Tuesday data"""
24
25 cve_ids: List[str] = Field(..., description="List of CVE IDs to search for")
26 cycle: Optional[str] = Field(None, description="Optional cycle to limit search to")
27
28
29 # Response component schemas
30 class CVSSInfo(BaseModel):
31 """CVSS score information"""
32
33 base: Optional[float] = Field(None, description="CVSS base score")
34 vector: Optional[str] = Field(None, description="CVSS vector string")
35
36
37 class EPSSInfo(BaseModel):
38 """EPSS score information"""
39
40 score: Optional[float] = Field(None, description="EPSS probability score")
41 percentile: Optional[float] = Field(None, description="EPSS percentile ranking")
42 date: Optional[str] = Field(None, description="Date of EPSS score")
43
44
45 class KEVInfo(BaseModel):
46 """CISA Known Exploited Vulnerabilities information"""
47
48 in_kev: bool = Field(False, description="Whether the CVE is in CISA KEV")
49 date_added: Optional[str] = Field(None, description="Date added to KEV")
50 due_date: Optional[str] = Field(None, description="Required remediation due date")
51 required_action: Optional[str] = Field(None, description="Required remediation action")
52 known_ransomware_campaign_use: Optional[str] = Field(None, description="Known ransomware usage")
53 vendor_project: Optional[str] = Field(None, description="Vendor or project name")
54 product: Optional[str] = Field(None, description="Product name")
55 vulnerability_name: Optional[str] = Field(None, description="Vulnerability name")
56 short_description: Optional[str] = Field(None, description="Short description")
57 notes: Optional[str] = Field(None, description="Additional notes")
58
59
60 class AffectedProduct(BaseModel):
61 """Affected product information"""
62
63 product: str = Field(..., description="Product name")
64 family: str = Field(..., description="Product family classification")
65 component_hint: Optional[str] = Field(None, description="Component hint from title")
66
67
68 class RemediationInfo(BaseModel):
69 """Remediation information"""
70
71 kbs: List[str] = Field(default_factory=list, description="Related KB article numbers")
72
73
74 class PrioritizationInfo(BaseModel):
75 """Prioritization recommendation"""
76
77 priority: str = Field(..., description="Priority level (P0-P3)")
78 reason: List[str] = Field(default_factory=list, description="Reasons for priority assignment")
79 suggested_sla: str = Field(..., description="Suggested SLA for remediation")
80
81
82 class SourceInfo(BaseModel):
83 """Source information for the vulnerability data"""
84
85 msrc_cvrf_id: str = Field(..., description="MSRC CVRF document ID")
86 msrc_cvrf_url: str = Field(..., description="MSRC CVRF document URL")
87 cisa_kev_url: str = Field(..., description="CISA KEV feed URL")
88
89
90 class PatchTuesdayItem(BaseModel):
91 """Individual Patch Tuesday vulnerability item"""
92
93 cycle: str = Field(..., description="Patch Tuesday cycle (e.g., 2026-Jan)")
94 release_type: str = Field("patch_tuesday", description="Release type")
95 cve: str = Field(..., description="CVE identifier")
96 title: Optional[str] = Field(None, description="Vulnerability title")
97 severity: Optional[str] = Field(None, description="Microsoft severity rating")
98 cvss: CVSSInfo = Field(default_factory=CVSSInfo, description="CVSS information")
99 epss: EPSSInfo = Field(default_factory=EPSSInfo, description="EPSS information")
100 kev: KEVInfo = Field(default_factory=KEVInfo, description="KEV information")
101 affected: AffectedProduct = Field(..., description="Affected product information")
102 remediation: RemediationInfo = Field(default_factory=RemediationInfo, description="Remediation information")
103 prioritization: PrioritizationInfo = Field(..., description="Prioritization recommendation")
104 source: SourceInfo = Field(..., description="Data source information")
105 timestamp_utc: str = Field(..., description="Timestamp when data was fetched")
106
107
108 class PriorityCounts(BaseModel):
109 """Counts by priority level"""
110
111 P0: int = Field(0, description="Emergency priority count")
112 P1: int = Field(0, description="High priority count")
113 P2: int = Field(0, description="Medium priority count")
114 P3: int = Field(0, description="Low priority count")
115
116
117 class PatchTuesdaySummary(BaseModel):
118 """Summary of Patch Tuesday data"""
119
120 cycle: str = Field(..., description="Patch Tuesday cycle")
121 patch_tuesday_date: str = Field(..., description="Date of Patch Tuesday")
122 generated_utc: str = Field(..., description="When the summary was generated")
123 unique_cves: int = Field(..., description="Number of unique CVEs")
124 total_records: int = Field(..., description="Total CVE x product records")
125 by_priority: PriorityCounts = Field(..., description="Counts by priority level")
126 by_family: Dict[str, int] = Field(default_factory=dict, description="Counts by product family")
127 by_severity: Dict[str, int] = Field(default_factory=dict, description="Counts by severity")
128
129
130 class PatchTuesdayResponse(BaseModel):
131 """Full Patch Tuesday response"""
132
133 success: bool = Field(..., description="Whether the request was successful")
134 message: str = Field(..., description="Response message")
135 summary: Optional[PatchTuesdaySummary] = Field(None, description="Summary of the data")
136 items: List[PatchTuesdayItem] = Field(default_factory=list, description="Vulnerability items")
137
138
139 class PatchTuesdaySummaryResponse(BaseModel):
140 """Summary-only Patch Tuesday response (without full items)"""
141
142 success: bool = Field(..., description="Whether the request was successful")
143 message: str = Field(..., description="Response message")
144 summary: Optional[PatchTuesdaySummary] = Field(None, description="Summary of the data")
145 top_items: List[PatchTuesdayItem] = Field(default_factory=list, description="Top prioritized items")
146
147
148 class AvailableCyclesResponse(BaseModel):
149 """Response with available Patch Tuesday cycles"""
150
151 success: bool = Field(..., description="Whether the request was successful")
152 message: str = Field(..., description="Response message")
153 cycles: List[str] = Field(default_factory=list, description="Available cycles")
154 current_cycle: str = Field(..., description="Current/default cycle")
155 next_patch_tuesday: str = Field(..., description="Date of next Patch Tuesday")