55from application .defs import cre_defs as defs
66import os
77import re
8+ import json
9+ from pathlib import Path
10+ import logging
811from application .utils .external_project_parsers .base_parser_defs import (
912 ParserInterface ,
1013 ParseResult ,
1417
1518class Cheatsheets (ParserInterface ):
1619 name = "OWASP Cheat Sheets"
20+ cheatsheetseries_base_url = "https://cheatsheetseries.owasp.org/cheatsheets"
21+ supplement_data_file = (
22+ Path (__file__ ).resolve ().parent .parent
23+ / "data"
24+ / "owasp_cheatsheets_supplement.json"
25+ )
26+ logger = logging .getLogger (__name__ )
1727
1828 def cheatsheet (
1929 self , section : str , hyperlink : str , tags : List [str ]
@@ -25,13 +35,29 @@ def cheatsheet(
2535 hyperlink = hyperlink ,
2636 )
2737
38+ def official_cheatsheet_url (self , markdown_filename : str ) -> str :
39+ html_name = os .path .splitext (markdown_filename )[0 ] + ".html"
40+ return f"{ self .cheatsheetseries_base_url } /{ html_name } "
41+
2842 def parse (self , cache : db .Node_collection , ph : prompt_client .PromptHandler ):
2943 c_repo = "https://github.com/OWASP/CheatSheetSeries.git"
3044 cheatsheets_path = "cheatsheets/"
31- repo = git .clone (c_repo )
32- cheatsheets = self .register_cheatsheets (
33- repo = repo , cache = cache , cheatsheets_path = cheatsheets_path , repo_path = c_repo
34- )
45+ cheatsheets = []
46+ try :
47+ repo = git .clone (c_repo )
48+ cheatsheets = self .register_cheatsheets (
49+ repo = repo ,
50+ cache = cache ,
51+ cheatsheets_path = cheatsheets_path ,
52+ repo_path = c_repo ,
53+ )
54+ except Exception as exc :
55+ self .logger .warning (
56+ "Unable to clone OWASP CheatSheetSeries, continuing with supplemental cheat sheets only: %s" ,
57+ exc ,
58+ )
59+ cheatsheets .extend (self .register_supplemental_cheatsheets (cache = cache ))
60+ cheatsheets = self .deduplicate_entries (cheatsheets )
3561 return ParseResult (results = {self .name : cheatsheets })
3662
3763 def register_cheatsheets (
@@ -55,7 +81,7 @@ def register_cheatsheets(
5581 name = title .group ("title" )
5682 cre_id = cre .group ("cre" )
5783 cres = cache .get_CREs (external_id = cre_id )
58- hyperlink = f" { repo_path . replace ( '.git' , '' ) } /tree/master/ { cheatsheets_path } { mdfile } "
84+ hyperlink = self . official_cheatsheet_url ( mdfile )
5985 cs = self .cheatsheet (section = name , hyperlink = hyperlink , tags = [])
6086 for cre in cres :
6187 cs .add_link (
@@ -65,3 +91,36 @@ def register_cheatsheets(
6591 )
6692 standard_entries .append (cs )
6793 return standard_entries
94+
95+ def register_supplemental_cheatsheets (self , cache : db .Node_collection ):
96+ with self .supplement_data_file .open ("r" , encoding = "utf-8" ) as handle :
97+ supplement_entries = json .load (handle )
98+
99+ standard_entries = []
100+ for entry in supplement_entries :
101+ cs = self .cheatsheet (
102+ section = entry ["section" ],
103+ hyperlink = entry ["hyperlink" ],
104+ tags = [],
105+ )
106+ for cre_id in entry .get ("cre_ids" , []):
107+ cres = cache .get_CREs (external_id = cre_id )
108+ for cre in cres :
109+ try :
110+ cs .add_link (
111+ defs .Link (
112+ document = cre .shallow_copy (),
113+ ltype = defs .LinkTypes .AutomaticallyLinkedTo ,
114+ )
115+ )
116+ except Exception :
117+ continue
118+ if cs .links :
119+ standard_entries .append (cs )
120+ return standard_entries
121+
122+ def deduplicate_entries (self , entries : List [defs .Standard ]) -> List [defs .Standard ]:
123+ deduped = {}
124+ for entry in entries :
125+ deduped [(entry .section , entry .hyperlink )] = entry
126+ return list (deduped .values ())
0 commit comments