2525from vulnerabilities .importer import AdvisoryData
2626from vulnerabilities .importer import AffectedPackage
2727from vulnerabilities .importer import AffectedPackageV2
28+ from vulnerabilities .importer import CodeCommitData
2829from vulnerabilities .importer import Reference
2930from vulnerabilities .importer import ReferenceV2
3031from vulnerabilities .importer import VulnerabilitySeverity
@@ -132,7 +133,8 @@ def parse_advisory_data_v2(
132133 references = get_references_v2 (raw_data = raw_data )
133134
134135 affected_packages = []
135-
136+ fixed_by_commits = []
137+ affected_by_commits = []
136138 for affected_pkg in raw_data .get ("affected" ) or []:
137139 purl = get_affected_purl (affected_pkg = affected_pkg , raw_id = advisory_id )
138140
@@ -154,6 +156,10 @@ def parse_advisory_data_v2(
154156 )
155157 fixed_versions .extend ([v .string for v in fixed_version ])
156158
159+ introduced_commits , fixed_commits = get_code_commit (fixed_range , raw_id = advisory_id )
160+ fixed_by_commits .extend (fixed_commits )
161+ affected_by_commits .extend (introduced_commits )
162+
157163 fixed_version_range = (
158164 get_fixed_version_range (fixed_versions , purl .type ) if fixed_versions else None
159165 )
@@ -183,6 +189,8 @@ def parse_advisory_data_v2(
183189 affected_packages = affected_packages ,
184190 date_published = date_published ,
185191 weaknesses = weaknesses ,
192+ fixed_by_commits = fixed_by_commits ,
193+ affected_by_commits = affected_by_commits ,
186194 url = advisory_url ,
187195 original_advisory_text = advisory_text or json .dumps (raw_data , indent = 2 , ensure_ascii = False ),
188196 )
@@ -208,6 +216,17 @@ def extract_fixed_versions(fixed_range) -> Iterable[str]:
208216 yield fixed
209217
210218
219+ def extract_commits (introduced_range ) -> Iterable [str ]:
220+ """
221+ Return a list of fixed version strings given a ``fixed_range`` mapping of
222+ OSV data.
223+ """
224+ for event in introduced_range .get ("events" ) or []:
225+ introduced = event .get ("introduced" )
226+ fixed = event .get ("fixed" )
227+ yield introduced , fixed
228+
229+
211230def get_published_date (raw_data ):
212231 published = raw_data .get ("published" )
213232 return published and dateparser .parse (date_string = published )
@@ -398,11 +417,49 @@ def get_fixed_versions(fixed_range, raw_id, supported_ecosystem) -> List[Version
398417 fixed_versions .append (SemverVersion (version ))
399418 except InvalidVersion :
400419 logger .error (f"Invalid SemverVersion: { version !r} for OSV id: { raw_id !r} " )
420+
421+ if fixed_range_type == "GIT" :
422+ # We process this in the get_code_commit function.
423+ continue
401424 else :
402425 logger .error (f"Unsupported fixed version type: { version !r} for OSV id: { raw_id !r} " )
403426
404- # if fixed_range_type == "GIT":
405- # TODO add GitHubVersion univers fix_version
406- # logger.error(f"NotImplementedError GIT Version - {raw_id !r} - {i !r}")
407-
408427 return dedupe (fixed_versions )
428+
429+
430+ def get_code_commit (ranges , raw_id ):
431+ """
432+ Return two lists of unique code commits (introduced and fixed) extracted from a
433+ given vulnerability `ranges` dictionary.
434+ """
435+ if ranges .get ("type" ) != "GIT" :
436+ logger .debug (f"Skipping non-GIT range for OSV id: { raw_id !r} " )
437+ return [], []
438+
439+ repo = ranges .get ("repo" )
440+ if not repo :
441+ logger .error (f"Missing 'repo' field in range: { ranges } (OSV id: { raw_id !r} )" )
442+ return [], []
443+
444+ repo = ranges .get ("repo" )
445+ introduced_commits , fixed_commits = [], []
446+ for introduced , fixed in extract_commits (ranges ):
447+ # Git uses this magic hash for the empty tree
448+ if introduced == "0" :
449+ introduced = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
450+
451+ try :
452+ if introduced :
453+ introduced_commit = CodeCommitData (commit_hash = introduced , vcs_url = repo )
454+ introduced_commits .append (introduced_commit )
455+ except ValueError as e :
456+ logger .error (f"Failed to extract introduced commits: { e !r} " )
457+
458+ try :
459+ if fixed :
460+ fixed_commit = CodeCommitData (commit_hash = fixed , vcs_url = repo )
461+ fixed_commits .append (fixed_commit )
462+ except ValueError as e :
463+ logger .error (f"Failed to extract fixed commits: { e !r} " )
464+
465+ return introduced_commits , fixed_commits
0 commit comments