11from typing import List , Set , Optional , Any , get_args
22from enum import Enum , auto
3+ import uuid
4+
35from pydantic import BaseModel , Field , PrivateAttr
46from data .Solution import Solution
5- from data .Categories import Category , TechnologyStack , SecurityAspect , SeverityLevel , RemediationType , \
6- AffectedComponent , Compliance , Environment
7+ from data .Categories import (
8+ Category ,
9+ TechnologyStack ,
10+ SecurityAspect ,
11+ SeverityLevel ,
12+ RemediationType ,
13+ AffectedComponent ,
14+ Compliance ,
15+ Environment ,
16+ )
717import json
818
919import logging
1222
1323
1424class Finding (BaseModel ):
25+ id : str = Field (default_factory = lambda : f"{ str (uuid .uuid4 ())} " )
1526 title : List [str ] = Field (default_factory = list )
1627 source : Set [str ] = Field (default_factory = set )
1728 descriptions : List [str ] = Field (default_factory = list )
@@ -21,7 +32,7 @@ class Finding(BaseModel):
2132 severity : Optional [int ] = None
2233 priority : Optional [int ] = None
2334 location_list : List [str ] = Field (default_factory = list )
24- category : Category = None
35+ category : Optional [ Category ] = None
2536 unsupervised_cluster : Optional [int ] = None
2637 solution : Optional ["Solution" ] = None
2738 _llm_service : Optional [Any ] = PrivateAttr (default = None )
@@ -35,7 +46,9 @@ def combine_descriptions(self) -> "Finding":
3546 logger .error ("LLM Service not set, cannot combine descriptions." )
3647 return self
3748
38- self .description = self .llm_service .combine_descriptions (self .descriptions , self .cve_ids , self .cwe_ids )
49+ self .description = self .llm_service .combine_descriptions (
50+ self .descriptions , self .cve_ids , self .cwe_ids
51+ )
3952 return self
4053
4154 def add_category (self ) -> "Finding" :
@@ -47,34 +60,45 @@ def add_category(self) -> "Finding":
4760
4861 # Classify technology stack
4962 technology_stack_options = list (TechnologyStack )
50- self .category .technology_stack = self .llm_service .classify_kind (self , "technology_stack" ,
51- technology_stack_options )
63+ self .category .technology_stack = self .llm_service .classify_kind (
64+ self , "technology_stack" , technology_stack_options
65+ )
5266
5367 # Classify security aspect
5468 security_aspect_options = list (SecurityAspect )
55- self .category .security_aspect = self .llm_service .classify_kind (self , "security_aspect" , security_aspect_options )
69+ self .category .security_aspect = self .llm_service .classify_kind (
70+ self , "security_aspect" , security_aspect_options
71+ )
5672
5773 # Classify severity level
5874 severity_level_options = list (SeverityLevel )
59- self .category .severity_level = self .llm_service .classify_kind (self , "severity_level" , severity_level_options )
75+ self .category .severity_level = self .llm_service .classify_kind (
76+ self , "severity_level" , severity_level_options
77+ )
6078
6179 # Classify remediation type
6280 remediation_type_options = list (RemediationType )
63- self .category .remediation_type = self .llm_service .classify_kind (self , "remediation_type" ,
64- remediation_type_options )
81+ self .category .remediation_type = self .llm_service .classify_kind (
82+ self , "remediation_type" , remediation_type_options
83+ )
6584
6685 # Classify affected component
6786 affected_component_options = list (AffectedComponent )
68- self .category .affected_component = self .llm_service .classify_kind (self , "affected_component" ,
69- affected_component_options )
87+ self .category .affected_component = self .llm_service .classify_kind (
88+ self , "affected_component" , affected_component_options
89+ )
7090
7191 # Classify compliance
7292 compliance_options = list (Compliance )
73- self .category .compliance = self .llm_service .classify_kind (self , "compliance" , compliance_options )
93+ self .category .compliance = self .llm_service .classify_kind (
94+ self , "compliance" , compliance_options
95+ )
7496
7597 # Classify environment
7698 environment_options = list (Environment )
77- self .category .environment = self .llm_service .classify_kind (self , "environment" , environment_options )
99+ self .category .environment = self .llm_service .classify_kind (
100+ self , "environment" , environment_options
101+ )
78102
79103 return self
80104
@@ -213,17 +237,19 @@ def to_html(self, table=False):
213237 result += "<tr><th>Name</th><th>Value</th></tr>"
214238 result += f"<tr><td>Title</td><td>{ ', ' .join (self .title )} </td></tr>"
215239 result += f"<tr><td>Source</td><td>{ ', ' .join (self .source )} </td></tr>"
216- result += (
217- f"<tr><td>Description</td><td>{ self .description } </td></tr>"
218- )
240+ result += f"<tr><td>Description</td><td>{ self .description } </td></tr>"
219241 if len (self .location_list ) > 0 :
220242 result += f"<tr><td>Location List</td><td>{ ' & ' .join (map (str , self .location_list ))} </td></tr>"
221243 result += f"<tr><td>CWE IDs</td><td>{ ', ' .join (self .cwe_ids )} </td></tr>"
222244 result += f"<tr><td>CVE IDs</td><td>{ ', ' .join (self .cve_ids )} </td></tr>"
223245 result += f"<tr><td>Severity</td><td>{ self .severity } </td></tr>"
224246 result += f"<tr><td>Priority</td><td>{ self .priority } </td></tr>"
225247 if self .category is not None :
226- result += '<tr><td>Category</td><td>' + str (self .category ).replace ("\n " , "<br />" ) + '</td></tr>'
248+ result += (
249+ "<tr><td>Category</td><td>"
250+ + str (self .category ).replace ("\n " , "<br />" )
251+ + "</td></tr>"
252+ )
227253 if self .unsupervised_cluster is not None :
228254 result += f"<tr><td>Unsupervised Cluster</td><td>{ self .unsupervised_cluster } </td></tr>"
229255 result += "</table>"
0 commit comments