1515from vulnerabilities .helpers import split_markdown_front_matter
1616from vulnerabilities .severity_systems import scoring_systems
1717
18-
1918REPOSITORY = "mozilla/foundation-security-advisories"
2019MFSA_FILENAME_RE = re .compile (r"mfsa(\d{4}-\d{2,3})\.(md|yml)$" )
2120
@@ -37,128 +36,146 @@ def updated_advisories(self) -> Set[Advisory]:
3736
3837 advisories = []
3938 for path in files :
40- advisories .extend (self . to_advisories (path ))
39+ advisories .extend (to_advisories (path ))
4140
4241 return self .batch_advisories (advisories )
4342
44- def to_advisories (self , path : str ) -> List [Advisory ]:
45- """
46- Convert a file to corresponding advisories.
47- This calls proper method to handle yml/md files.
48- """
49- mfsa_id = self .mfsa_id_from_filename (path )
50-
51- with open (path ) as lines :
52- if path .endswith (".md" ):
53- return self .get_advisories_from_md (mfsa_id , lines )
54- if path .endswith (".yml" ):
55- return self .get_advisories_from_yml (mfsa_id , lines )
5643
44+ def to_advisories (path : str ) -> List [Advisory ]:
45+ """
46+ Convert a file to corresponding advisories.
47+ This calls proper method to handle yml/md files.
48+ """
49+ mfsa_id = mfsa_id_from_filename (path )
50+ if not mfsa_id :
5751 return []
5852
59- def get_advisories_from_yml (self , mfsa_id , lines ) -> List [Advisory ]:
60- advisories = []
61- data = yaml .safe_load (lines )
62- data ["mfsa_id" ] = mfsa_id
63-
64- fixed_package_urls = self .get_package_urls (data .get ("fixed_in" ))
65- references = self .get_yml_references (data )
66-
67- if not data .get ("advisories" ):
68- return []
69-
70- for cve , advisory in data ["advisories" ].items ():
71- advisories .append (
72- Advisory (
73- summary = advisory .get ("description" ),
74- vulnerability_id = cve if is_cve (cve ) else "" ,
75- impacted_package_urls = [],
76- resolved_package_urls = fixed_package_urls ,
77- references = references ,
78- )
79- )
53+ with open (path ) as lines :
54+ if path .endswith (".md" ):
55+ return get_advisories_from_md (mfsa_id , lines )
56+ if path .endswith (".yml" ):
57+ return get_advisories_from_yml (mfsa_id , lines )
8058
81- return advisories
82-
83- def get_advisories_from_md (self , mfsa_id , lines ) -> List [Advisory ]:
84- yamltext , mdtext = split_markdown_front_matter (lines .read ())
85- data = yaml .safe_load (yamltext )
86- data ["mfsa_id" ] = mfsa_id
87-
88- fixed_package_urls = self .get_package_urls (data .get ("fixed_in" ))
89- references = self .get_yml_references (data )
90- cves = re .findall (r"CVE-\d+-\d+" , yamltext + mdtext , re .IGNORECASE )
91- for cve in cves :
92- references .append (
93- Reference (
94- reference_id = cve , url = f"https://cve.mitre.org/cgi-bin/cvename.cgi?name={ cve } "
95- )
96- )
59+ return []
60+
61+
62+ def get_advisories_from_yml (mfsa_id , lines ) -> List [Advisory ]:
63+ advisories = []
64+ data = yaml .safe_load (lines )
65+ data ["mfsa_id" ] = mfsa_id
9766
98- description = self .html_get_p_under_h3 (markdown (mdtext ), "description" )
67+ fixed_package_urls = get_package_urls (data .get ("fixed_in" ))
68+ references = get_yml_references (data )
9969
100- return [
70+ if not data .get ("advisories" ):
71+ return []
72+
73+ for cve , advisory in data ["advisories" ].items ():
74+ # These may contain HTML tags
75+ summary = BeautifulSoup (advisory .get ("description" , "" ), features = "lxml" ).get_text ()
76+
77+ advisories .append (
10178 Advisory (
102- summary = description ,
103- vulnerability_id = "" ,
79+ summary = summary ,
80+ vulnerability_id = cve if is_cve ( cve ) else "" ,
10481 impacted_package_urls = [],
10582 resolved_package_urls = fixed_package_urls ,
10683 references = references ,
10784 )
108- ]
109-
110- def html_get_p_under_h3 (self , html , h3 : str ):
111- soup = BeautifulSoup (html , features = "lxml" )
112- h3tag = soup .find ("h3" , text = lambda txt : txt .lower () == h3 )
113- p = ""
114- if h3tag :
115- for tag in h3tag .next_siblings :
116- if tag .name :
117- if tag .name != "p" :
118- break
119- p += tag .get_text ()
120- return p
121-
122- def mfsa_id_from_filename (self , filename ):
123- match = MFSA_FILENAME_RE .search (filename )
124- if match :
125- return "mfsa" + match .group (1 )
126-
127- return None
128-
129- def get_package_urls (self , pkgs : List [str ]) -> List [PackageURL ]:
130- package_urls = [
131- PackageURL (
132- type = "mozilla" ,
133- # pkg is of the form "Firefox ESR 1.21" or "Thunderbird 2.21"
134- name = pkg .rsplit (None , 1 )[0 ],
135- version = pkg .rsplit (None , 1 )[1 ],
136- )
137- for pkg in pkgs
138- ]
139- return package_urls
140-
141- def get_yml_references (self , data : any ) -> List [Reference ]:
142- """
143- Returns a list of references
144- Currently only considers the given mfsa as a reference
145- """
146- # FIXME: Needs improvement
147- # Should we add 'bugs' section in references too?
148- # Should we add 'impact'/severity of CVE in references too?
149- # If yes, then fix alpine_linux importer as well
150- # Otherwise, do we need severity field for adversary as well?
151-
152- # FIXME: Write a helper for cvssv3.1_qr severity detection ?
153- severities = ["critical" , "low" , "high" , "medium" , "none" ]
154- severity = [{severity in data .get ("impact" ): severity } for severity in severities ][0 ].get (
155- True
15685 )
15786
158- return [
87+ return advisories
88+
89+
90+ def get_advisories_from_md (mfsa_id , lines ) -> List [Advisory ]:
91+ yamltext , mdtext = split_markdown_front_matter (lines .read ())
92+ data = yaml .safe_load (yamltext )
93+ data ["mfsa_id" ] = mfsa_id
94+
95+ fixed_package_urls = get_package_urls (data .get ("fixed_in" ))
96+ references = get_yml_references (data )
97+ cves = re .findall (r"CVE-\d+-\d+" , yamltext + mdtext , re .IGNORECASE )
98+ for cve in cves :
99+ references .append (
159100 Reference (
160- reference_id = data ["mfsa_id" ],
161- url = "https://www.mozilla.org/en-US/security/advisories/{}" .format (data ["mfsa_id" ]),
162- severities = [VulnerabilitySeverity (scoring_systems ["cvssv3.1_qr" ], severity )],
101+ reference_id = cve ,
102+ url = f"https://cve.mitre.org/cgi-bin/cvename.cgi?name={ cve } " ,
163103 )
164- ]
104+ )
105+
106+ description = html_get_p_under_h3 (markdown (mdtext ), "description" )
107+
108+ return [
109+ Advisory (
110+ summary = description ,
111+ vulnerability_id = "" ,
112+ impacted_package_urls = [],
113+ resolved_package_urls = fixed_package_urls ,
114+ references = references ,
115+ )
116+ ]
117+
118+
119+ def html_get_p_under_h3 (html , h3 : str ):
120+ soup = BeautifulSoup (html , features = "lxml" )
121+ h3tag = soup .find ("h3" , text = lambda txt : txt .lower () == h3 )
122+ p = ""
123+ if h3tag :
124+ for tag in h3tag .next_siblings :
125+ if tag .name :
126+ if tag .name != "p" :
127+ break
128+ p += tag .get_text ()
129+ return p
130+
131+
132+ def mfsa_id_from_filename (filename ):
133+ match = MFSA_FILENAME_RE .search (filename )
134+ if match :
135+ return "mfsa" + match .group (1 )
136+
137+ return None
138+
139+
140+ def get_package_urls (pkgs : List [str ]) -> List [PackageURL ]:
141+ package_urls = [
142+ PackageURL (
143+ type = "mozilla" ,
144+ # pkg is of the form "Firefox ESR 1.21" or "Thunderbird 2.21"
145+ name = pkg .rsplit (None , 1 )[0 ],
146+ version = pkg .rsplit (None , 1 )[1 ],
147+ )
148+ for pkg in pkgs
149+ if pkg
150+ ]
151+ return package_urls
152+
153+
154+ def get_yml_references (data : any ) -> List [Reference ]:
155+ """
156+ Returns a list of references
157+ Currently only considers the given mfsa as a reference
158+ """
159+ # FIXME: Needs improvement
160+ # Should we add 'bugs' section in references too?
161+ # Should we add 'impact'/severity of CVE in references too?
162+ # If yes, then fix alpine_linux importer as well
163+ # Otherwise, do we need severity field for adversary as well?
164+
165+ severities = ["critical" , "high" , "medium" , "low" , "none" ]
166+ severity = "none"
167+ if data .get ("impact" ):
168+ impact = data .get ("impact" ).lower ()
169+ for s in severities :
170+ if s in impact :
171+ severity = s
172+ break
173+
174+ return [
175+ Reference (
176+ reference_id = data ["mfsa_id" ],
177+ url = "https://www.mozilla.org/en-US/security/advisories/{}" .format (data ["mfsa_id" ]),
178+ # severities=[VulnerabilitySeverity(scoring_systems["unspecified"], severity)],
179+ severities = [VulnerabilitySeverity (scoring_systems ["cvssv3.1_qr" ], severity )],
180+ )
181+ ]
0 commit comments