main
py 212 lines 5.69 KB
Raw
1 from datetime import datetime
2 from typing import Any
3 from typing import Dict
4 from typing import List
5 from typing import Optional
6
7 from pydantic import BaseModel
8 from pydantic import ConfigDict
9 from pydantic import Field
10
11
12 class AgentScaOverviewItem(BaseModel):
13 """Individual SCA item from overview search results"""
14
15 agent_id: str
16 agent_name: str
17 customer_code: Optional[str] = None
18 policy_id: str
19 policy_name: str
20 description: str
21 total_checks: int
22 pass_count: int = Field(..., alias="pass")
23 fail_count: int = Field(..., alias="fail")
24 invalid_count: int = Field(..., alias="invalid")
25 score: int
26 start_scan: str
27 end_scan: str
28 references: Optional[str] = None
29 hash_file: Optional[str] = None
30 model_config = ConfigDict(populate_by_name=True)
31
32
33 class ScaOverviewResponse(BaseModel):
34 """Response schema for SCA overview search results with pagination and stats"""
35
36 sca_results: List[AgentScaOverviewItem]
37 total_count: int
38 # Summary stats across all results
39 total_agents: int
40 total_policies: int
41 average_score: float
42 total_checks_all_agents: int
43 total_passes_all_agents: int
44 total_fails_all_agents: int
45 total_invalid_all_agents: int
46 # Pagination
47 page: int
48 page_size: int
49 total_pages: int
50 has_next: bool
51 has_previous: bool
52 success: bool
53 message: str
54 filters_applied: dict = {}
55
56
57 class ScaOverviewRequest(BaseModel):
58 """Request schema for searching SCA results across agents"""
59
60 customer_code: Optional[str] = Field(None, description="Filter by customer code")
61 agent_name: Optional[str] = Field(None, description="Filter by agent hostname")
62 policy_id: Optional[str] = Field(None, description="Filter by specific policy ID")
63 policy_name: Optional[str] = Field(None, description="Filter by policy name (partial matching)")
64 min_score: Optional[int] = Field(None, description="Filter by minimum score", ge=0, le=100)
65 max_score: Optional[int] = Field(None, description="Filter by maximum score", ge=0, le=100)
66 page: int = Field(1, description="Page number for pagination", ge=1)
67 page_size: int = Field(50, description="Number of results per page", ge=1, le=1000)
68
69
70 class ScaStatsResponse(BaseModel):
71 """Response schema for SCA statistics"""
72
73 total_agents_with_sca: int
74 total_policies: int
75 average_score_across_all: float
76 total_checks_all_agents: int
77 total_passes_all_agents: int
78 total_fails_all_agents: int
79 total_invalid_all_agents: int
80 by_customer: dict = {}
81 success: bool
82 message: str
83
84
85 class SCAReportGenerateRequest(BaseModel):
86 """Request schema for generating SCA report"""
87
88 customer_code: str
89 report_name: Optional[str] = None # Auto-generate if not provided
90 agent_name: Optional[str] = None
91 policy_id: Optional[str] = None
92 min_score: Optional[int] = Field(None, ge=0, le=100, description="Minimum score filter")
93 max_score: Optional[int] = Field(None, ge=0, le=100, description="Maximum score filter")
94
95
96 class SCAReportResponse(BaseModel):
97 """Response schema for SCA report details"""
98
99 id: int
100 report_name: str
101 customer_code: str
102 file_name: str
103 file_size: int
104 generated_at: datetime
105 generated_by: int
106 total_policies: int
107 total_checks: int
108 passed_count: int
109 failed_count: int
110 invalid_count: int
111 filters_applied: Dict[str, Any]
112 status: str # processing, completed, failed
113 error_message: Optional[str] = None
114 download_url: Optional[str] = None
115
116
117 class SCAReportListResponse(BaseModel):
118 """Response schema for listing SCA reports"""
119
120 reports: List[SCAReportResponse]
121 total_count: int
122 success: bool
123 message: str
124
125
126 class SCAReportGenerateResponse(BaseModel):
127 """Response schema for report generation"""
128
129 success: bool
130 message: str
131 report: Optional[SCAReportResponse] = None
132 error: Optional[str] = None
133
134
135 # ── Available SCA Policies (from CoPilot-SCA GitHub repo) ──
136
137
138 class ScaPolicyItem(BaseModel):
139 """A single SCA policy entry from the CoPilot-SCA index"""
140
141 id: str
142 name: str
143 description: str
144 file: str
145 application: str
146 app_version: str
147 platform: str
148 cis_version: str
149
150
151 class ScaPoliciesIndexResponse(BaseModel):
152 """Response for listing all available SCA policies from the public repo"""
153
154 version: str
155 last_updated: str
156 policies: List[ScaPolicyItem]
157 success: bool
158 message: str
159
160
161 class ScaPolicyContentResponse(BaseModel):
162 """Response for fetching the raw YAML content of a single SCA policy"""
163
164 policy_id: str
165 file_path: str
166 content: str
167 success: bool
168 message: str
169
170
171 # ── SCA Package Registry & Agent Detection ──
172
173
174 class ScaPackageRegistryItem(BaseModel):
175 """A single entry from the SCA package registry."""
176
177 key: str
178 display_name: str
179 sca_application: str
180 package_patterns: List[str]
181
182
183 class ScaPackageRegistryResponse(BaseModel):
184 """Response listing all tracked SCA-relevant packages."""
185
186 entries: List[ScaPackageRegistryItem]
187 total: int
188 success: bool
189 message: str
190
191
192 class AgentPackageMatch(BaseModel):
193 """An agent that was found running a tracked SCA package."""
194
195 agent_id: Optional[str] = None
196 agent_name: Optional[str] = None
197 package_name: Optional[str] = None
198 package_version: Optional[str] = None
199 package_architecture: Optional[str] = None
200
201
202 class ScaPackageAgentsResponse(BaseModel):
203 """Response listing agents that have a particular SCA-relevant package installed."""
204
205 registry_key: str
206 display_name: str
207 sca_application: str
208 matched_agents: List[AgentPackageMatch] = []
209 total: int = 0
210 applicable_policies: List[ScaPolicyItem] = []
211 success: bool
212 message: str