From 063e29fe2e12a306be51755e994d8eb10b2d3614 Mon Sep 17 00:00:00 2001 From: VictorRodriguez Date: Wed, 27 Nov 2019 17:39:51 -0600 Subject: [PATCH] Add feature to check if a CVE has an open launchpad This change enables the capability to track if a CVE to be fixed already has an open launchpad in starlingx: https://bugs.launchpad.net/starlingx/ This will help the security team to focus on the CVEs that do not have a launchpad already open, reducing the overhead of analysis of CVEs already presented to the development team. Story:2006971 Change-Id: I494f0221cb52a4bf7ace20d75e067b17c719d749 Signed-off-by: VictorRodriguez --- cve_support/cve_policy_filter.py | 20 ++++++- cve_support/lp.py | 92 ++++++++++++++++++++++++++++++++ cve_support/template.txt | 32 +++++++++-- 3 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 cve_support/lp.py diff --git a/cve_support/cve_policy_filter.py b/cve_support/cve_policy_filter.py index a5a2b126..ab982b82 100644 --- a/cve_support/cve_policy_filter.py +++ b/cve_support/cve_policy_filter.py @@ -12,6 +12,7 @@ Create documentation as pydoc -w cve_policy_filter import json import sys import os +from lp import find_lp_assigned def print_html_report(cves_report, title): """ @@ -25,6 +26,7 @@ def print_html_report(cves_report, title): template = template_env.get_template(template_file) heads = ["cve_id", "status", "cvss2Score", "av", "ac", "au", "ai"] output_text = template.render(cves_to_fix=cves_report["cves_to_fix"],\ + cves_to_fix_lp=cves_report["cves_to_fix_lp"],\ cves_to_track=cves_report["cves_to_track"],\ cves_w_errors=cves_report["cves_w_errors"],\ cves_to_omit=cves_report["cves_to_omit"],\ @@ -40,7 +42,7 @@ def print_report(cves_report, title): Print the txt STDOUT report """ print("\n%s report:" % (title)) - print("\nValid CVEs to take action immediately: %d\n" \ + print("\nCVEs to fix w/o a launchpad assigned: %d\n" \ % (len(cves_report["cves_to_fix"]))) for cve in cves_report["cves_to_fix"]: print("\n") @@ -57,6 +59,15 @@ def print_report(cves_report, title): if cve["sourcelink"]: print(cve["sourcelink"]) + print("\nCVEs to fix w/ a launchpad assigned: %d \n" \ + % (len(cves_report["cves_to_fix_lp"]))) + for cve in cves_report["cves_to_fix_lp"]: + cve_line = [] + for key, value in cve.items(): + if key != "summary": + cve_line.append(key + ":" + str(value)) + print(cve_line) + print("\nCVEs to track for incoming fix: %d \n" \ % (len(cves_report["cves_to_track"]))) for cve in cves_report["cves_to_track"]: @@ -128,6 +139,7 @@ def main(): cves = [] cves_valid = [] cves_to_fix = [] + cves_to_fix_lp = [] cves_to_track = [] cves_w_errors = [] cves_to_omit = [] @@ -197,13 +209,17 @@ def main(): and ("N" in cve["au"] or "S" in cve["au"]) and ("P" in cve["ai"] or "C" in cve["ai"])): if cve["status"] == "fixed": - cves_to_fix.append(cve) + if find_lp_assigned(cve["id"]): + cves_to_fix_lp.append(cve) + else: + cves_to_fix.append(cve) else: cves_to_track.append(cve) else: cves_to_omit.append(cve) cves_report["cves_to_fix"] = cves_to_fix + cves_report["cves_to_fix_lp"] = cves_to_fix_lp cves_report["cves_to_track"] = cves_to_track cves_report["cves_w_errors"] = cves_w_errors cves_report["cves_to_omit"] = cves_to_omit diff --git a/cve_support/lp.py b/cve_support/lp.py new file mode 100644 index 00000000..6a2d2edd --- /dev/null +++ b/cve_support/lp.py @@ -0,0 +1,92 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2019 Intel Corporation +# + +""" +Implement system to detect if CVEs has launchpad assigned +""" +import json +import os +from os import path +from launchpadlib.launchpad import Launchpad + + +# Filter the open bugs +STATUSES = [ + 'New', + 'Incomplete', + 'Confirmed', + 'Triaged', + 'In Progress', + 'Fix Committed', + 'Fix Released', +] + +CACHEDIR = path.join('/tmp', os.environ['USER'], '.launchpadlib/cache') +CVES_FILE = path.join(CACHEDIR, 'cves_open.json') +DATA = [] + + +def search_upstrem_lps(): + """ + Search for launchpads open with CVE or cve in title + """ + launchpad = Launchpad.login_anonymously\ + ('lplib.cookbook.json_fetcher', 'production', + CACHEDIR, version='devel') + project = launchpad.projects['starlingx'] + tasks = project.searchTasks(status=STATUSES) + for task in tasks: + bug = task.bug + if ("cve" in bug.title.lower()): + bug_dic = {} + bug_dic['id'] = bug.id + bug_dic['title'] = bug.title + bug_dic['link'] = bug.self_link + DATA.append(bug_dic) + + with open(CVES_FILE, 'w') as outfile: + json.dump(DATA, outfile) + +def find_lp_assigned(cve_id): + """ + Check if a launchpad for CVE exist in DATA + DATA must came from file or from upstream launchpad DB + """ + global DATA + + if not DATA: + if path.isfile(CVES_FILE): + DATA = json.load(open(CVES_FILE, "r")) + else: + search_upstrem_lps() + + for bug in DATA: + if cve_id in bug["title"]: + return bug + + return None + +def main(): + + """ + Sanity test + """ + cve_ids = ["CVE-2019-0160",\ + "CVE-2019-11810",\ + "CVE-2019-11811",\ + "CVE-2018-15686",\ + "CVE-2019-10126"] + + for cve_id in cve_ids: + bug = find_lp_assigned(cve_id) + if bug: + print("\n") + print(bug) + else: + print("\n%s has no LP assigned\n" % (cve_id)) + +if __name__ == "__main__": + main() diff --git a/cve_support/template.txt b/cve_support/template.txt index 207dbd4e..298f8419 100644 --- a/cve_support/template.txt +++ b/cve_support/template.txt @@ -1,9 +1,9 @@

Security report from vuls scan from {{title}}

-

Valid CVEs to take action immediately: {{cves_to_fix | length}}

+

CVEs to fix w/o a launchpad assigned: {{cves_to_fix | length}}

- {% if cves_to_fix|length > 1 %} + {% if cves_to_fix|length >= 1 %} {% for head in heads %} @@ -23,9 +23,31 @@ {% endfor %} {% endif %}
{{head}}
+

CVEs to fix w/ a launchpad assigend: {{cves_to_fix_lp | length}}

+ + {% if cves_to_fix_lp|length >= 1 %} + + {% for head in heads %} + + {% endfor %} + + + {% for cve in cves_to_fix_lp %} + + + + + + + + + + {% endfor %} + {% endif %} +
{{head}}
{{cve["id"]}}{{cve["status"]}}{{cve["cvss2Score"]}}{{cve["av"]}}{{cve["ac"]}}{{cve["au"]}}{{cve["ai"]}}

CVEs to track for incoming fix: {{cves_to_track | length}}

- {% if cves_to_track|length > 1 %} + {% if cves_to_track|length >= 1 %} {% for head in heads %} @@ -47,7 +69,7 @@
{{head}}

CVEs to omit: {{cves_to_omit | length}}

- {% if cves_to_omit|length > 1 %} + {% if cves_to_omit|length >= 1 %} {% for head in heads %} @@ -70,7 +92,7 @@

ERROR: CVEs that have no cvss2Score or cvss2Vector:{{cves_w_errors | length}}

{{head}}
- {% if cves_w_errors|length > 1 %} + {% if cves_w_errors|length >= 1 %} {% for cve in cves_to_track %}
{{cve["id"]}}