| #!/usr/bin/env python3 |
| |
| # Script to convert CVEs as published for Apache projects |
| # from CVE JSON 5.0 format to OSV format. |
| |
| import json |
| import sys |
| |
| # TODO get from arg |
| cve = json.load(open(sys.argv[1])) |
| |
| def mavenPackage(groupId, artifactId): |
| return { |
| 'ecosystem': 'Maven', |
| 'name': f"{groupId}:{artifactId}", |
| 'purl': f"pkg:maven/{groupId}/{artifactId}" |
| } |
| |
| def package(product): |
| if product == 'Apache Commons IO': |
| return mavenPackage('org.apache.commons', 'commons-io') |
| else: |
| # https://github.com/ossf/osv-schema/issues/94 |
| return None |
| |
| def range(versions): |
| if versions['status'] != 'affected': |
| raise "TODO support for explicitly 'unaffected' ranges" |
| if 'lessThan' in versions: |
| events = [{ |
| 'introduced': versions['version'] |
| },{ |
| 'fixed': versions['lessThan'] |
| }] |
| else: |
| events = [{ |
| 'introduced': versions['version'] |
| },{ |
| 'last_affected': versions['version'] |
| }] |
| |
| return { |
| 'type': 'SEMVER', |
| 'events': events |
| } |
| |
| def convert_affected(affected): |
| result = {} |
| p = package(affected['product']) |
| if p: |
| result['package'] = p |
| result['ranges'] = list(map(range, affected['versions'])) |
| # TODO severity |
| return result |
| |
| def reference(reference): |
| url = reference['url'] |
| if 'jira' in url: |
| t = 'REPORT' |
| elif 'x_refsource_CONFIRM' in reference['tags']: |
| t = 'ADVISORY' |
| else: |
| t = 'WEB' |
| return { |
| 'type': t, |
| 'url': reference['url'] |
| } |
| |
| cna = cve['containers']['cna'] |
| osv = { |
| 'schema_version': '1.6.1', |
| 'id': cve['cveMetadata']['cveId'], |
| 'summary': cna['title'], |
| 'details': cna['descriptions'][0]['value'], |
| # TODO 'severity' |
| 'affected': list(map(convert_affected, cna['affected'])), |
| 'references': list(map(reference, cna['references'])) |
| # TODO 'credits' |
| } |
| |
| with open(sys.argv[2], 'w', encoding='utf-8') as f: |
| json.dump(osv, f, ensure_ascii=False) |