Skip to content

Commit ef41468

Browse files
committed
Add RST documentation page
1 parent beea361 commit ef41468

File tree

1 file changed

+153
-140
lines changed

1 file changed

+153
-140
lines changed

misc/scripts/generate-csv-coverage-report.py

Lines changed: 153 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def create_empty_database(lang, extension, database):
1919
subprocess_run(["codeql", "database", "init", "--language=" + lang,
2020
"--source-root=/tmp/empty", "--allow-missing-source-root", database])
2121
subprocess_run(["mkdir", "-p", database + "/src/tmp/empty"])
22-
subprocess_run(["touch", database + "/src/tmp/empty/empty." + extension])
22+
subprocess_run(["touch", database + "/src/tmp/empty/empty" + extension])
2323
subprocess_run(["codeql", "database", "finalize",
2424
database, "--no-pre-finalize"])
2525

@@ -89,8 +89,9 @@ def add_package_stats_to_row(row, sorted_cwes, collect):
8989

9090

9191
class LanguageConfig:
92-
def __init__(self, lang, ext, ql_path):
92+
def __init__(self, lang, capitalized_lang, ext, ql_path):
9393
self.lang = lang
94+
self.capitalized_lang = capitalized_lang
9495
self.ext = ext
9596
self.ql_path = ql_path
9697

@@ -108,151 +109,163 @@ def __init__(self, lang, ext, ql_path):
108109
# Languages for which we want to generate coverage reports.
109110
configs = [
110111
LanguageConfig(
111-
"java", "java", prefix + "java/ql/src/meta/frameworks/Coverage.ql")
112+
"java", "Java", ".java", prefix + "java/ql/src/meta/frameworks/Coverage.ql")
112113
]
113114

114-
for config in configs:
115-
lang = config.lang
116-
ext = config.ext
117-
query_path = config.ql_path
118-
db = "empty-" + lang
119-
ql_output = "output-" + lang + ".csv"
120-
# create_empty_database(lang, ext, db)
121-
run_codeql_query(query_path, db, ql_output)
122-
123-
packages = {}
124-
parts = set()
125-
kinds = set()
126-
127-
# Read the generated CSV file, and collect package statistics.
128-
with open(ql_output) as csvfile:
129-
reader = csv.reader(csvfile)
130-
for row in reader:
131-
package = row[0]
132-
if package not in packages:
133-
packages[package] = {
134-
"count": row[1],
135-
"part": {},
136-
"kind": {}
137-
}
138-
part = row[3]
139-
parts.add(part)
140-
if part not in packages[package]["part"]:
141-
packages[package]["part"][part] = 0
142-
packages[package]["part"][part] += int(row[4])
143-
kind = part + ":" + row[2]
144-
kinds.add(kind)
145-
if kind not in packages[package]["kind"]:
146-
packages[package]["kind"][kind] = 0
147-
packages[package]["kind"][kind] += int(row[4])
148-
149-
# Write the denormalized package statistics to a CSV file.
150-
with open("csv-flow-model-coverage-" + lang + ".csv", 'w', newline='') as csvfile:
151-
csvwriter = csv.writer(csvfile)
152-
153-
parts = sorted(parts)
154-
kinds = sorted(kinds)
155-
156-
columns = ["package"]
157-
columns.extend(parts)
158-
columns.extend(kinds)
159-
160-
csvwriter.writerow(columns)
161-
162-
for package in sorted(packages):
163-
row = [package]
164-
for part in parts:
165-
append_csv_dict_item(row, packages[package]["part"], part)
166-
for kind in kinds:
167-
append_csv_dict_item(row, packages[package]["kind"], kind)
168-
csvwriter.writerow(row)
169-
170-
# Read the additional framework data, such as URL, friendly name
171-
frameworks = {}
172-
173-
with open(prefix + "misc/scripts/frameworks-" + lang + ".csv") as csvfile:
174-
reader = csv.reader(csvfile)
175-
next(reader)
176-
for row in reader:
177-
framwork = row[0]
178-
if framwork not in frameworks:
179-
frameworks[framwork] = {
180-
"package": row[2],
181-
"url": row[1]
182-
}
183-
184-
# Read the additional CWE data
185-
cwes = {}
186-
187-
with open(prefix + "misc/scripts/cwe-sink-" + lang + ".csv") as csvfile:
188-
reader = csv.reader(csvfile)
189-
next(reader)
190-
for row in reader:
191-
cwe = row[0]
192-
if cwe not in cwes:
193-
cwes[cwe] = {
194-
"sink": row[1],
195-
"label": row[2]
196-
}
197-
198-
with open("rst-csv-flow-model-coverage-" + lang + ".csv", 'w', newline='') as csvfile:
199-
csvwriter = csv.writer(csvfile)
200-
201-
columns = ["Framework / library", "package",
202-
"remote flow sources", "taint & value steps", "sinks (total)"]
203-
for cwe in sorted(cwes):
204-
columns.append("`" + cwe + "` :sub:`" + cwes[cwe]["label"] + "`")
205-
csvwriter.writerow(columns)
206-
207-
processed_packages = set()
208-
209-
for framework in sorted(frameworks):
210-
row = []
211-
# Add the framework name to the row
212-
if not frameworks[framework]["url"]:
213-
row.append(framework)
214-
else:
215-
row.append(
216-
"`" + framework + " <" + frameworks[framework]["url"] + ">`_")
217-
218-
# Add the package name to the row
219-
row.append(frameworks[framework]["package"])
220-
221-
prefix = frameworks[framework]["package"]
222-
223-
# Collect statistics on the current framework
224-
def collect_framework(): return collect_package_stats(
115+
with open("csv-flow-model-coverage.rst", 'w') as rst_file:
116+
for config in configs:
117+
lang = config.lang
118+
db = "empty-" + lang
119+
ql_output = "output-" + lang + ".csv"
120+
create_empty_database(lang, config.ext, db)
121+
run_codeql_query(config.ql_path, db, ql_output)
122+
123+
packages = {}
124+
parts = set()
125+
kinds = set()
126+
127+
# Read the generated CSV file, and collect package statistics.
128+
with open(ql_output) as csvfile:
129+
reader = csv.reader(csvfile)
130+
for row in reader:
131+
package = row[0]
132+
if package not in packages:
133+
packages[package] = {
134+
"count": row[1],
135+
"part": {},
136+
"kind": {}
137+
}
138+
part = row[3]
139+
parts.add(part)
140+
if part not in packages[package]["part"]:
141+
packages[package]["part"][part] = 0
142+
packages[package]["part"][part] += int(row[4])
143+
kind = part + ":" + row[2]
144+
kinds.add(kind)
145+
if kind not in packages[package]["kind"]:
146+
packages[package]["kind"][kind] = 0
147+
packages[package]["kind"][kind] += int(row[4])
148+
149+
# Write the denormalized package statistics to a CSV file.
150+
with open("csv-flow-model-coverage-" + lang + ".csv", 'w', newline='') as csvfile:
151+
csvwriter = csv.writer(csvfile)
152+
153+
parts = sorted(parts)
154+
kinds = sorted(kinds)
155+
156+
columns = ["package"]
157+
columns.extend(parts)
158+
columns.extend(kinds)
159+
160+
csvwriter.writerow(columns)
161+
162+
for package in sorted(packages):
163+
row = [package]
164+
for part in parts:
165+
append_csv_dict_item(row, packages[package]["part"], part)
166+
for kind in kinds:
167+
append_csv_dict_item(row, packages[package]["kind"], kind)
168+
csvwriter.writerow(row)
169+
170+
# Read the additional framework data, such as URL, friendly name
171+
frameworks = {}
172+
173+
with open(prefix + "misc/scripts/frameworks-" + lang + ".csv") as csvfile:
174+
reader = csv.reader(csvfile)
175+
next(reader)
176+
for row in reader:
177+
framwork = row[0]
178+
if framwork not in frameworks:
179+
frameworks[framwork] = {
180+
"package": row[2],
181+
"url": row[1]
182+
}
183+
184+
# Read the additional CWE data
185+
cwes = {}
186+
187+
with open(prefix + "misc/scripts/cwe-sink-" + lang + ".csv") as csvfile:
188+
reader = csv.reader(csvfile)
189+
next(reader)
190+
for row in reader:
191+
cwe = row[0]
192+
if cwe not in cwes:
193+
cwes[cwe] = {
194+
"sink": row[1],
195+
"label": row[2]
196+
}
197+
198+
file_name = "rst-csv-flow-model-coverage-" + lang + ".csv"
199+
200+
rst_file.write(
201+
config.capitalized_lang + " framework & library support\n")
202+
rst_file.write("================================\n\n")
203+
rst_file.write(".. csv-table:: \n")
204+
rst_file.write(" :file: " + file_name + "\n")
205+
rst_file.write(" :header-rows: 1\n")
206+
rst_file.write(" :class: fullWidthTable\n")
207+
rst_file.write(" :widths: auto\n\n")
208+
209+
# Write CSV file with package statistics and framework data to be used in RST file.
210+
with open(file_name, 'w', newline='') as csvfile:
211+
csvwriter = csv.writer(csvfile)
212+
213+
columns = ["Framework / library", "package",
214+
"remote flow sources", "taint & value steps", "sinks (total)"]
215+
for cwe in sorted(cwes):
216+
columns.append("`" + cwe + "` :sub:`" +
217+
cwes[cwe]["label"] + "`")
218+
csvwriter.writerow(columns)
219+
220+
processed_packages = set()
221+
222+
for framework in sorted(frameworks):
223+
row = []
224+
# Add the framework name to the row
225+
if not frameworks[framework]["url"]:
226+
row.append(framework)
227+
else:
228+
row.append(
229+
"`" + framework + " <" + frameworks[framework]["url"] + ">`_")
230+
231+
# Add the package name to the row
232+
row.append(frameworks[framework]["package"])
233+
234+
prefix = frameworks[framework]["package"]
235+
236+
# Collect statistics on the current framework
237+
def collect_framework(): return collect_package_stats(
238+
packages,
239+
lambda p: (prefix.endswith("*") and p.startswith(prefix[:-1])) or (not prefix.endswith("*") and prefix == p))
240+
241+
row, f_processed_packages = add_package_stats_to_row(
242+
row, sorted(cwes), collect_framework)
243+
244+
csvwriter.writerow(row)
245+
processed_packages.update(f_processed_packages)
246+
247+
# Collect statistics on all packages that are not part of a framework
248+
row = ["Others", None]
249+
250+
def collect_others(): return collect_package_stats(
225251
packages,
226-
lambda p: (prefix.endswith("*") and p.startswith(prefix[:-1])) or (not prefix.endswith("*") and prefix == p))
227-
228-
row, f_processed_packages = add_package_stats_to_row(
229-
row, sorted(cwes), collect_framework)
230-
231-
csvwriter.writerow(row)
232-
processed_packages.update(f_processed_packages)
252+
lambda p: p not in processed_packages)
233253

234-
# Collect statistics on all packages that are not part of a framework
235-
row = ["Others", None]
254+
row, other_packages = add_package_stats_to_row(
255+
row, sorted(cwes), collect_others)
236256

237-
def collect_others(): return collect_package_stats(
238-
packages,
239-
lambda p: p not in processed_packages)
257+
row[1] = ", ".join(sorted(other_packages))
240258

241-
row, _ = add_package_stats_to_row(
242-
row, sorted(cwes), collect_others)
243-
244-
csvwriter.writerow(row)
245-
246-
# Collect statistics on all packages
247-
row = ["Total", None]
259+
csvwriter.writerow(row)
248260

249-
def collect_total(): return collect_package_stats(
250-
packages,
251-
lambda p: True)
261+
# Collect statistics on all packages
262+
row = ["Total", None]
252263

253-
row, _ = add_package_stats_to_row(
254-
row, sorted(cwes), collect_total)
264+
def collect_total(): return collect_package_stats(
265+
packages,
266+
lambda p: True)
255267

256-
csvwriter.writerow(row)
268+
row, _ = add_package_stats_to_row(
269+
row, sorted(cwes), collect_total)
257270

258-
# todo: generate rst page referencing the csv files
271+
csvwriter.writerow(row)

0 commit comments

Comments
 (0)