@@ -131,97 +131,49 @@ def finding_to_dict(finding: Finding) -> Dict[str, Any]:
131131 return result
132132
133133 def print_summary (self , max_preview : int = 10 ) -> None :
134- """Print a human-readable summary of the diff."""
135- # Print new findings
136- print ("\n === New Findings ===" )
137- print (f"Count: { len (self .new_findings )} " )
138- if self .new_findings :
139- finding_ids = [finding .finding_id for finding in self .new_findings ]
140- print (f"Finding IDs: { ', ' .join (finding_ids )} " )
134+ """Print a human-readable summary of the diff.
141135
142- # Print existing matches
143- print ("\n === Existing Matches ===" )
144- print (f"Count: { len (self .existing_matches )} " )
145- if self .existing_matches :
146- matches = [f"{ match .finding .finding_id } -> { match .poam .poam_id } "
147- for match in self .existing_matches [:max_preview ]]
148- print (f"Preview of matches: { ', ' .join (matches )} " )
149- if len (self .existing_matches ) > max_preview :
150- print (f"... and { len (self .existing_matches ) - max_preview } more" )
151-
152- # Print reopened findings
153- print ("\n === Reopened Findings ===" )
154- print (f"Count: { len (self .reopened_findings )} " )
155- if self .reopened_findings :
156- matches = [f"{ match .finding .finding_id } -> { match .poam .poam_id } "
157- for match in self .reopened_findings [:max_preview ]]
158- print (f"Preview of matches: { ', ' .join (matches )} " )
159- if len (self .reopened_findings ) > max_preview :
160- print (f"... and { len (self .reopened_findings ) - max_preview } more" )
136+ Categories that don't represent newly (re)opened items are shown as
137+ compact counts. Opened and reopened items get a scannable bulleted
138+ list since those are what typically need reviewing.
139+ """
140+ def format_date (date : Union [datetime , str , None ]) -> str :
141+ if isinstance (date , datetime ):
142+ return date .strftime ('%Y-%m-%d' )
143+ return date or "unknown date"
161144
162- # Print closed POAMs
163- print ("\n === Closed POAMs ===" )
164- print (f"Count: { len (self .closed_poams )} " )
165- if self .closed_poams :
166- poam_ids = [poam .poam_id for poam in self .closed_poams ]
167- print (f"POAM IDs no longer active: { ', ' .join (poam_ids )} " )
145+ print ("\n === Summary ===" )
146+ print (f"New findings (unmatched, pre-grouping): { len (self .new_findings )} " )
147+ print (f"Existing matches (no change): { len (self .existing_matches )} " )
148+ print (f"Closed POAMs: { len (self .closed_poams )} " )
149+ print (f"Closed configuration findings: { len (self .closed_configuration_findings )} " )
168150
169- # Print proposed POAMs
170- print ("\n === Proposed POAMs ===" )
171- print (f"Count: { len (self .proposed_poams )} " )
151+ print ("\n === Opened POAMs ({}) ===" .format (len (self .proposed_poams )))
172152 if self .proposed_poams :
173153 for findings , poam in self .proposed_poams [:max_preview ]:
174- finding_ids = [f .finding_id for f in findings ]
175- print (f"{ ', ' .join (finding_ids )} => { poam .poam_id } " )
154+ finding_ids = ', ' .join (f .finding_id for f in findings )
155+ date = format_date (poam .original_detection_date )
156+ print (f"- [{ poam .poam_id } ] { poam .weakness_name } "
157+ f"({ poam .original_risk_rating } , { date } ) — { finding_ids } " )
176158 if len (self .proposed_poams ) > max_preview :
177- print (f"... and { len (self .proposed_poams ) - max_preview } more" )
178-
179- # Show sample of first proposed POAM
180- print ("\n Sample new POAM:" )
181- sample_findings , sample_poam = self .proposed_poams [0 ]
182- print (f"POAM ID: { sample_poam .poam_id } " )
183- print (f"Weakness Name: { sample_poam .weakness_name } " )
184- print (f"Asset Identifiers: { sample_poam .asset_identifier } " )
185- print (f"Finding IDs: { sample_poam .comments } " )
186- # Handle case where date might already be a string
187- detection_date = sample_poam .original_detection_date
188- if isinstance (detection_date , datetime ):
189- detection_date = detection_date .strftime ('%Y-%m-%d' )
190- print (f"Detection Date: { detection_date } " )
191- print (f"Risk Rating: { sample_poam .original_risk_rating } " )
192- if sample_poam .cve :
193- print (f"CVE: { sample_poam .cve } " )
159+ print (f" ... and { len (self .proposed_poams ) - max_preview } more" )
194160
195- # Print configuration findings if present
196- print ("\n === Proposed Configuration Findings ===" )
197- print (f"Count: { len (self .proposed_configuration_findings )} " )
161+ print ("\n === Opened Configuration Findings ({}) ===" .format (len (self .proposed_configuration_findings )))
198162 if self .proposed_configuration_findings :
199163 for findings , poam in self .proposed_configuration_findings [:max_preview ]:
200- finding_ids = [f .finding_id for f in findings ]
201- print (f"{ ', ' .join (finding_ids )} => { poam .poam_id } " )
164+ finding_ids = ', ' .join (f .finding_id for f in findings )
165+ date = format_date (poam .original_detection_date )
166+ print (f"- [{ poam .poam_id } ] { poam .weakness_name } "
167+ f"({ poam .original_risk_rating } , { date } ) — { finding_ids } " )
202168 if len (self .proposed_configuration_findings ) > max_preview :
203- print (f"... and { len (self .proposed_configuration_findings ) - max_preview } more" )
204-
205- # Show sample of first proposed configuration finding
206- print ("\n Sample new Configuration Finding:" )
207- sample_findings , sample_poam = self .proposed_configuration_findings [0 ]
208- print (f"POAM ID: { sample_poam .poam_id } " )
209- print (f"Weakness Name: { sample_poam .weakness_name } " )
210- print (f"Asset Identifiers: { sample_poam .asset_identifier } " )
211- print (f"Finding IDs: { sample_poam .comments } " )
212- detection_date = sample_poam .original_detection_date
213- if isinstance (detection_date , datetime ):
214- detection_date = detection_date .strftime ('%Y-%m-%d' )
215- print (f"Detection Date: { detection_date } " )
216- print (f"Risk Rating: { sample_poam .original_risk_rating } " )
217- if sample_poam .cve :
218- print (f"CVE: { sample_poam .cve } " )
169+ print (f" ... and { len (self .proposed_configuration_findings ) - max_preview } more" )
219170
220- print ("\n === Closed Configuration Findings ===" )
221- print (f"Count: { len (self .closed_configuration_findings )} " )
222- if self .closed_configuration_findings :
223- poam_ids = [poam .poam_id for poam in self .closed_configuration_findings ]
224- print (f"Configuration Finding IDs no longer active: { ', ' .join (poam_ids )} " )
171+ print ("\n === Reopened Findings ({}) ===" .format (len (self .reopened_findings )))
172+ if self .reopened_findings :
173+ for match in self .reopened_findings [:max_preview ]:
174+ print (f"- [{ match .poam .poam_id } ] { match .poam .weakness_name } — { match .finding .finding_id } " )
175+ if len (self .reopened_findings ) > max_preview :
176+ print (f" ... and { len (self .reopened_findings ) - max_preview } more" )
225177
226178def _is_exact_match (str1 : str , str2 : str ) -> bool :
227179 """Check if two strings match exactly, ignoring case."""
0 commit comments