@@ -23,14 +23,16 @@ def explain(project_type, src_dir, bom_dir, vdr_result):
2323 :param bom_dir: BOM directory
2424 """
2525 pattern_methods = {}
26+ has_any_explanation = False
27+ has_any_crypto_flows = False
2628 slices_files = glob .glob (f"{ bom_dir } /**/*reachables.slices.json" , recursive = True )
2729 openapi_spec_files = glob .glob (f"{ bom_dir } /*openapi*.json" , recursive = False )
2830 if not openapi_spec_files :
2931 openapi_spec_files = glob .glob (f"{ src_dir } /*openapi*.json" , recursive = False )
3032 if openapi_spec_files :
3133 rsection = Markdown ("""## Service Endpoints
3234
33- The following endpoints and code hotspots were identified by depscan. Ensure proper authentication and authorization mechanisms are implemented to secure them.""" )
35+ The following endpoints and code hotspots were identified by depscan. Verify that proper authentication and authorization mechanisms are in place to secure them.""" )
3436 console .print (rsection )
3537 for ospec in openapi_spec_files :
3638 pattern_methods = print_endpoints (ospec )
@@ -42,18 +44,28 @@ def explain(project_type, src_dir, bom_dir, vdr_result):
4244 rsection = Markdown (
4345 """## Reachable Flows
4446
45- Below are some reachable flows, including endpoint-reachable ones , identified by depscan. Use the generated OpenAPI specification file to assess these endpoints for vulnerabilities and risk.
47+ Below are some reachable flows, including those accessible via endpoints , identified by depscan. Use the generated OpenAPI specification to evaluate these endpoints for vulnerabilities and risk.
4648 """
4749 )
4850 else :
4951 rsection = Markdown (
5052 """## Reachable Flows
5153
52- Below are some reachable flows identified by depscan. Use the provided tips to enhance your application' s security posture.
54+ Below are several data flows identified by depscan, including reachable ones . Use the tips provided to strengthen your application’ s security posture.
5355 """
5456 )
55- console .print (rsection )
56- explain_reachables (reachables_data , project_type , vdr_result )
57+ has_explanation , has_crypto_flows = explain_reachables (
58+ reachables_data ,
59+ project_type ,
60+ vdr_result ,
61+ rsection if not has_any_explanation else None ,
62+ )
63+ if not has_any_explanation and has_explanation :
64+ has_any_explanation = True
65+ if not has_any_crypto_flows and has_crypto_flows :
66+ has_any_crypto_flows = True
67+ if slices_files and not has_any_explanation and not has_any_crypto_flows :
68+ console .print ("depscan did not find any reachable flow in this scan." )
5769
5870
5971def _track_usage_targets (usage_targets , usages_object ):
@@ -110,17 +122,34 @@ def print_endpoints(ospec):
110122 return pattern_methods
111123
112124
113- def explain_reachables (reachables , project_type , vdr_result ):
125+ def is_cpp_flow (flows ):
126+ if not flows :
127+ return False
128+ attempts = 0
129+ for idx , aflow in enumerate (flows ):
130+ if aflow .get ("parentFileName" , "" ).endswith (".c" ) or aflow .get (
131+ "parentFileName" , ""
132+ ).endswith (".cpp" ):
133+ return True
134+ attempts += 1
135+ if attempts > 3 :
136+ return False
137+ return False
138+
139+
140+ def explain_reachables (reachables , project_type , vdr_result , header_section = None ):
114141 """"""
115142 reachable_explanations = 0
116143 checked_flows = 0
117144 has_crypto_flows = False
118145 purls_reachable_explanations = defaultdict (int )
146+ has_explanation = False
147+ header_shown = False
119148 for areach in reachables .get ("reachables" , []):
120149 if (
121150 not areach .get ("flows" )
122151 or len (areach .get ("flows" )) < 2
123- or not areach .get ("purls" )
152+ or ( not areach .get ("purls" ) and not is_cpp_flow ( areach . get ( "flows" )) )
124153 ):
125154 continue
126155 # Focus only on the prioritized list if available
@@ -145,10 +174,13 @@ def explain_reachables(reachables, project_type, vdr_result):
145174 continue
146175 purls_str = "," .join (sorted (areach .get ("purls" , [])))
147176 if (
148- purls_reachable_explanations [purls_str ] + 1
177+ purls_str
178+ and purls_reachable_explanations [purls_str ] + 1
149179 > max_purls_reachable_explanations
150180 ):
151181 continue
182+ if not has_explanation :
183+ has_explanation = True
152184 # Did we find any crypto flows
153185 if is_crypto_flow and not has_crypto_flows :
154186 has_crypto_flows = True
@@ -163,15 +195,21 @@ def explain_reachables(reachables, project_type, vdr_result):
163195 )
164196 rtable .add_column (header = "Flow" , vertical = "top" )
165197 rtable .add_row (flow_tree )
198+ # Print the header first in case we haven't
199+ if not header_shown and header_section :
200+ console .print ()
201+ console .print (header_section )
202+ header_shown = True
166203 console .print ()
167204 console .print (rtable )
168205 reachable_explanations += 1
169- purls_reachable_explanations [purls_str ] += 1
206+ if purls_str :
207+ purls_reachable_explanations [purls_str ] += 1
170208 if has_check_tag :
171209 checked_flows += 1
172210 if reachable_explanations + 1 > max_reachable_explanations :
173211 break
174- if reachable_explanations :
212+ if has_explanation :
175213 tips = """## Secure Design Tips"""
176214
177215 if has_crypto_flows :
@@ -183,12 +221,18 @@ def explain_reachables(reachables, project_type, vdr_result):
183221- Review the validation and sanitization methods used in the application.
184222- To enhance the security posture, implement a common validation middleware.
185223"""
186- else :
224+ elif purls_reachable_explanations :
187225 tips += """
188226- Consider implementing a common validation and sanitization library to reduce the risk of exploitability.
227+ """
228+ else :
229+ tips += """
230+ - Enhance your unit and integration tests to cover the flows listed above.
231+ - Additionally, set up an appropriate fuzzer to continuously evaluate the performance of the parser and validation functions across various payloads.
189232"""
190233 rsection = Markdown (tips )
191234 console .print (rsection )
235+ return has_explanation , has_crypto_flows
192236
193237
194238def flow_to_source_sink (idx , flow , purls , project_type , vdr_result ):
@@ -200,9 +244,8 @@ def flow_to_source_sink(idx, flow, purls, project_type, vdr_result):
200244 reached_services = vdr_result .reached_services
201245 is_endpoint_reachable = False
202246 possible_reachable_service = False
203- is_crypto_flow = "crypto" in flow .get ("tags" , []) or "crypto-generate" in flow .get (
204- "tags" , []
205- )
247+ tags = flow .get ("tags" , [])
248+ is_crypto_flow = "crypto" in tags or "crypto-generate" in tags
206249 method_in_emoji = ":right_arrow_curving_left:"
207250 for p in purls :
208251 if endpoint_reached_purls and endpoint_reached_purls .get (p ):
@@ -256,6 +299,9 @@ def flow_to_source_sink(idx, flow, purls, project_type, vdr_result):
256299 "middleware" in source_sink_desc .lower () or "route" in source_sink_desc .lower ()
257300 ):
258301 source_sink_desc = "The flow originates from middleware."
302+ elif len (purls ) == 0 :
303+ if tags :
304+ source_sink_desc = f"{ source_sink_desc } can be used to reach packages with tags { ',' .join (tags [:2 ])} "
259305 elif len (purls ) == 1 :
260306 if is_endpoint_reachable :
261307 source_sink_desc = f"{ source_sink_desc } can be used to reach this package from certain endpoints."
@@ -369,8 +415,9 @@ def explain_flows(flows, purls, project_type, vdr_result):
369415 comments .append (
370416 ":exclamation_mark: Refactor this flow to minimize the use of external libraries."
371417 )
372- purls_str = "\n " .join (purls )
373- comments .append (f"[info]Reachable Packages:[/info]\n { purls_str } " )
418+ if purls :
419+ purls_str = "\n " .join (purls )
420+ comments .append (f"[info]Reachable Packages:[/info]\n { purls_str } " )
374421 added_flows = []
375422 has_check_tag = False
376423 last_file_loc = None
0 commit comments