forked from envoyproxy/envoy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenerate_external_dep_rst.py
executable file
·83 lines (64 loc) · 2.67 KB
/
generate_external_dep_rst.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/usr/bin/env python3
# Generate RST lists of external dependencies.
from collections import defaultdict, namedtuple
import pathlib
import sys
import urllib.parse
from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader
# bazel/repository_locations.bzl must have a .bzl suffix for Starlark import, so
# we are forced to do this workaround.
_repository_locations_spec = spec_from_loader(
'repository_locations',
SourceFileLoader('repository_locations', 'bazel/repository_locations.bzl'))
repository_locations = module_from_spec(_repository_locations_spec)
_repository_locations_spec.loader.exec_module(repository_locations)
# Render a CSV table given a list of table headers, widths and list of rows
# (each a list of strings).
def CsvTable(headers, widths, rows):
csv_rows = '\n '.join(', '.join(row) for row in rows)
return f'''.. csv-table::
:header: {', '.join(headers)}
:widths: {', '.join(str(w) for w in widths) }
{csv_rows}
'''
# Anonymous external RST link for a given URL.
def RstLink(text, url):
return f'`{text} <{url}>`__'
# NIST CPE database search URL for a given CPE.
def NistCpeUrl(cpe):
encoded_cpe = urllib.parse.quote(cpe)
return 'https://nvd.nist.gov/products/cpe/search/results?keyword=%s&status=FINAL&orderBy=CPEURI&namingFormat=2.3' % encoded_cpe
# Render version strings human readable.
def RenderVersion(version):
# Heuristic, almost certainly a git SHA
if len(version) == 40:
# Abbreviate git SHA
return version[:7]
return version
if __name__ == '__main__':
security_rst_root = sys.argv[1]
Dep = namedtuple('Dep', ['name', 'sort_name', 'version', 'cpe'])
use_categories = defaultdict(list)
# Bin rendered dependencies into per-use category lists.
for k, v in repository_locations.DEPENDENCY_REPOSITORIES.items():
cpe = v.get('cpe', '')
if cpe == 'N/A':
cpe = ''
if cpe:
cpe = RstLink(cpe, NistCpeUrl(cpe))
project_name = v['project_name']
project_url = v['project_url']
name = RstLink(project_name, project_url)
version = RstLink(RenderVersion(v['version']), v['urls'][0])
dep = Dep(name, project_name.lower(), version, cpe)
for category in v['use_category']:
use_categories[category].append(dep)
def CsvRow(dep):
return [dep.name, dep.version, dep.cpe]
# Generate per-use category RST with CSV tables.
for category, deps in use_categories.items():
output_path = pathlib.Path(security_rst_root, f'external_dep_{category}.rst')
content = CsvTable(['Name', 'Version', 'CPE'], [2, 1, 2],
[CsvRow(dep) for dep in sorted(deps, key=lambda d: d.sort_name)])
output_path.write_text(content)