2424from vulnerabilities .importer import AdvisoryData
2525from vulnerabilities .importer import AffectedPackage
2626from vulnerabilities .importer import AffectedPackageV2
27+ from vulnerabilities .importer import CodeCommitData
2728from vulnerabilities .importer import Reference
2829from vulnerabilities .importer import ReferenceV2
2930from vulnerabilities .importer import VulnerabilitySeverity
@@ -131,7 +132,8 @@ def parse_advisory_data_v2(
131132 references = get_references_v2 (raw_data = raw_data )
132133
133134 affected_packages = []
134-
135+ fixed_by_commits = []
136+ affected_by_commits = []
135137 for affected_pkg in raw_data .get ("affected" ) or []:
136138 purl = get_affected_purl (affected_pkg = affected_pkg , raw_id = advisory_id )
137139
@@ -153,6 +155,10 @@ def parse_advisory_data_v2(
153155 )
154156 fixed_versions .extend ([v .string for v in fixed_version ])
155157
158+ introduced_commits , fixed_commits = get_code_commit (fixed_range , raw_id = advisory_id )
159+ fixed_by_commits .extend (fixed_commits )
160+ affected_by_commits .extend (introduced_commits )
161+
156162 fixed_version_range = (
157163 get_fixed_version_range (fixed_versions , purl .type ) if fixed_versions else None
158164 )
@@ -182,6 +188,8 @@ def parse_advisory_data_v2(
182188 affected_packages = affected_packages ,
183189 date_published = date_published ,
184190 weaknesses = weaknesses ,
191+ fixed_by_commits = fixed_by_commits ,
192+ affected_by_commits = affected_by_commits ,
185193 url = advisory_url ,
186194 original_advisory_text = advisory_text or json .dumps (raw_data , indent = 2 , ensure_ascii = False ),
187195 )
@@ -207,6 +215,17 @@ def extract_fixed_versions(fixed_range) -> Iterable[str]:
207215 yield fixed
208216
209217
218+ def extract_commits (introduced_range ) -> Iterable [str ]:
219+ """
220+ Return a list of fixed version strings given a ``fixed_range`` mapping of
221+ OSV data.
222+ """
223+ for event in introduced_range .get ("events" ) or []:
224+ introduced = event .get ("introduced" )
225+ fixed = event .get ("fixed" )
226+ yield introduced , fixed
227+
228+
210229def get_published_date (raw_data ):
211230 published = raw_data .get ("published" )
212231 return published and dateparser .parse (date_string = published )
@@ -392,11 +411,49 @@ def get_fixed_versions(fixed_range, raw_id, supported_ecosystem) -> List[Version
392411 fixed_versions .append (SemverVersion (version ))
393412 except InvalidVersion :
394413 logger .error (f"Invalid SemverVersion: { version !r} for OSV id: { raw_id !r} " )
414+
415+ if fixed_range_type == "GIT" :
416+ # We process this in the get_code_commit function.
417+ continue
395418 else :
396419 logger .error (f"Unsupported fixed version type: { version !r} for OSV id: { raw_id !r} " )
397420
398- # if fixed_range_type == "GIT":
399- # TODO add GitHubVersion univers fix_version
400- # logger.error(f"NotImplementedError GIT Version - {raw_id !r} - {i !r}")
401-
402421 return dedupe (fixed_versions )
422+
423+
424+ def get_code_commit (ranges , raw_id ):
425+ """
426+ Return two lists of unique code commits (introduced and fixed) extracted from a
427+ given vulnerability `ranges` dictionary.
428+ """
429+ if ranges .get ("type" ) != "GIT" :
430+ logger .debug (f"Skipping non-GIT range for OSV id: { raw_id !r} " )
431+ return [], []
432+
433+ repo = ranges .get ("repo" )
434+ if not repo :
435+ logger .error (f"Missing 'repo' field in range: { ranges } (OSV id: { raw_id !r} )" )
436+ return [], []
437+
438+ repo = ranges .get ("repo" )
439+ introduced_commits , fixed_commits = [], []
440+ for introduced , fixed in extract_commits (ranges ):
441+ # Git uses this magic hash for the empty tree
442+ if introduced == "0" :
443+ introduced = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
444+
445+ try :
446+ if introduced :
447+ introduced_commit = CodeCommitData (commit_hash = introduced , vcs_url = repo )
448+ introduced_commits .append (introduced_commit )
449+ except ValueError as e :
450+ logger .error (f"Failed to extract introduced commits: { e !r} " )
451+
452+ try :
453+ if fixed :
454+ fixed_commit = CodeCommitData (commit_hash = fixed , vcs_url = repo )
455+ fixed_commits .append (fixed_commit )
456+ except ValueError as e :
457+ logger .error (f"Failed to extract fixed commits: { e !r} " )
458+
459+ return introduced_commits , fixed_commits
0 commit comments