Commit 3c731ce7 authored by Jérome Perrin's avatar Jérome Perrin

new --audit option for sbom output

query OSV API for vulnerabilities and (just) print a summary
parent 7b09c882
Pipeline #35254 failed with stage
in 0 seconds
...@@ -37,6 +37,8 @@ import json ...@@ -37,6 +37,8 @@ import json
import sys, configparser, re, codecs import sys, configparser, re, codecs
import uuid import uuid
import requests
# PkgInfo represents information about a package # PkgInfo represents information about a package
PkgInfo = namedtuple('PkgInfo', [ PkgInfo = namedtuple('PkgInfo', [
...@@ -546,7 +548,7 @@ def fmt_bom(bom): # -> str ...@@ -546,7 +548,7 @@ def fmt_bom(bom): # -> str
return ''.join(outv) return ''.join(outv)
def fmt_bom_cyclonedx_json(bom, software_path): def fmt_bom_cyclonedx_json(bom, software_path, audit=False):
# possible future extensions: # possible future extensions:
# - describe patches applied to components (using components[*].pedigree.patches ) # - describe patches applied to components (using components[*].pedigree.patches )
...@@ -595,6 +597,7 @@ def fmt_bom_cyclonedx_json(bom, software_path): ...@@ -595,6 +597,7 @@ def fmt_bom_cyclonedx_json(bom, software_path):
} }
} }
components = bom_json["components"] = [] components = bom_json["components"] = []
with requests.Session() as session:
for _, pkginfo in sorted(bom.items()): for _, pkginfo in sorted(bom.items()):
cpe = None cpe = None
externalReferences = [] externalReferences = []
...@@ -628,7 +631,20 @@ def fmt_bom_cyclonedx_json(bom, software_path): ...@@ -628,7 +631,20 @@ def fmt_bom_cyclonedx_json(bom, software_path):
if externalReferences: if externalReferences:
component['externalReferences'] = externalReferences component['externalReferences'] = externalReferences
components.append(component) components.append(component)
if audit:
resp = session.post(
'https://api.osv.dev/v1/query',
json={"package": {"purl": purl}})
for vuln in resp.json().get('vulns', []):
reference = sorted(
vuln['references'] + [{'url': 'N/A'}],
key=lambda r: not r.get('type') == 'ADVISORY')[0]['url']
print("WARNING: {} {} {} {}".format(
pkginfo.name,
reference,
vuln['id'],
vuln.get('summary', vuln.get('details', '')),
))
return bom_json return bom_json
...@@ -638,6 +654,7 @@ def main(): ...@@ -638,6 +654,7 @@ def main():
description=__doc__ description=__doc__
) )
parser.add_argument('-f', '--format', choices=['text', 'cyclonedx-json'], default='text') parser.add_argument('-f', '--format', choices=['text', 'cyclonedx-json'], default='text')
parser.add_argument('--audit', action="store_true", help='Query OSV database for known vulnerabilities')
parser.add_argument('-o', '--output', parser.add_argument('-o', '--output',
type=argparse.FileType('w', encoding='UTF-8'), type=argparse.FileType('w', encoding='UTF-8'),
default=sys.stdout) default=sys.stdout)
...@@ -659,7 +676,7 @@ def main(): ...@@ -659,7 +676,7 @@ def main():
print(fmt_bom(bom), file=args.output) print(fmt_bom(bom), file=args.output)
else: else:
assert args.format == 'cyclonedx-json' assert args.format == 'cyclonedx-json'
json.dump(fmt_bom_cyclonedx_json(bom, args.software_path), args.output, indent=True) json.dump(fmt_bom_cyclonedx_json(bom, args.software_path, args.audit), args.output, indent=True)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -13,6 +13,7 @@ setup( ...@@ -13,6 +13,7 @@ setup(
keywords = 'Nexedi software build BOM', keywords = 'Nexedi software build BOM',
packages = find_packages(), packages = find_packages(),
requires = [ 'requests', ],
extras_require = { extras_require = {
'test': ['pytest'], 'test': ['pytest'],
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment