Merge ~sbeattie/ubuntu-cve-tracker/+git/ubuntu-cve-tracker:check-cves_ignore_cache into ubuntu-cve-tracker:master

Proposed by Steve Beattie
Status: Merged
Merged at revision: fbb11d1762fcbfd1d2114b2d745736d7108eb165
Proposed branch: ~sbeattie/ubuntu-cve-tracker/+git/ubuntu-cve-tracker:check-cves_ignore_cache
Merge into: ubuntu-cve-tracker:master
Diff against target: 106 lines (+46/-7)
2 files modified
scripts/check-cves (+9/-7)
scripts/check_cves/ignored_cache.py (+37/-0)
Reviewer Review Type Date Requested Status
Alex Murray Approve
Seth Arnold Approve
Review via email: mp+422708@code.launchpad.net

Commit message

[WIP] check-cves: add a cache of 5 last ignored reasons

Often times when performing triage I bounce between CVEs of a few
different products from the same vendor that end up being ignored. It's
useful to have roughly a cache of five or so entries, plus the debian
reason if available plus the heuristic guess.

Implement a small cache of previously used reasons for ignoring a cve.
It keeps the ordering the same as before, with the cache entries added
last, orted in most recently used order.

Using this results in things looking like:

   Debian CVE Tracker: NOT-FOR-US: Node sds

  A]dd (or R]epeat), I]gnore forever, S]kip for now, or Q]uit? [ignore]
  Reason to be ignored?
     a) Node sds
     b) sds from
     c) BlogEngine.NET
     d) InHand Networks InRouter302
     e) OpenClinica
     f) Intel(R) NUCs
     g) Check Point Enterprise Endpoint

Signed-off-by: Steve Beattie <email address hidden>
TODO: unit tests. Sorry.

To post a comment you must log in.
Revision history for this message
Paulo Flabiano Smorigo (pfsmorigo) wrote :

Need unit tests, otherwise LGTM :P

Revision history for this message
Seth Arnold (seth-arnold) wrote :

Nice :)

review: Approve
Revision history for this message
Alex Murray (alexmurray) wrote :

Would it be possible to also add this in the "experimental" mode as well?

Revision history for this message
Steve Beattie (sbeattie) wrote :

On Wed, May 18, 2022 at 01:11:48AM -0000, Alex Murray wrote:
> Would it be possible to also add this in the "experimental" mode as well?

I'm open to the idea, but I'm not sure how. In interactive mode,
whatever reason you give to ignore a cve is added to the cache (limited
to 5 entries), and the next time you attempt to ignore a CVE, it shows
you the last five you entered.

Since the experimental mode is non-interactive and thus all proposed
interactions are pre-computed, I'm not sure how to do something similar.

Now, there are some ways we could improve both interactive and
non-interactive, given that we have a gigantic saved history of entries
from people in the not-for-us.txt file.

For interactive mode, I'd like to make full use of readline's
capabilities with possibly two history files[1], one for ignored reasons,
and one for packages entered, so that similar to bash and other
shells, you could search through history for an appropriate entry
(and also to make interactive editing better).

There's probably more processing we could do for the non-interactive
version.

[1] unfortunately, libreadline only supports one global history per
    process, so when switching between adding a CVE and ignoring a CVE
    or vice versa, we'd need to flush the history and reload the saved
    history from the other save file.

--
Steve Beattie
<email address hidden>

Revision history for this message
Alex Murray (alexmurray) wrote :

Bah of course, this doesn't really make sense in the non-interactive case - sorry I wasn't thinking this through properly. That is a good idea re combing not-for-us.txt but that sounds like something for a future piece of work.

review: Approve
Revision history for this message
Eduardo Barretto (ebarretto) wrote :

This was merged back in fbb11d1762fcbfd1d2114b2d745736d7108eb165

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/scripts/check-cves b/scripts/check-cves
index 7f061f2..975b1cd 100755
--- a/scripts/check-cves
+++ b/scripts/check-cves
@@ -8,7 +8,7 @@
8# Author: Jamie Strandboge <jamie@ubuntu.com>8# Author: Jamie Strandboge <jamie@ubuntu.com>
9# Author: Marc Deslauriers <marc.deslauriers@ubuntu.com>9# Author: Marc Deslauriers <marc.deslauriers@ubuntu.com>
10# Author: Steve Beattie <sbeattie@ubuntu.com>10# Author: Steve Beattie <sbeattie@ubuntu.com>
11# Copyright (C) 2005-2021 Canonical Ltd.11# Copyright (C) 2005-2022 Canonical Ltd.
12#12#
13# This script is distributed under the terms and conditions of the GNU General13# This script is distributed under the terms and conditions of the GNU General
14# Public License, Version 2 or later. See http://www.gnu.org/copyleft/gpl.html14# Public License, Version 2 or later. See http://www.gnu.org/copyleft/gpl.html
@@ -38,6 +38,7 @@ import progressbar
3838
39import cve_lib39import cve_lib
40import source_map40import source_map
41from check_cves.ignored_cache import IgnoredCache
4142
42# load settings, if any43# load settings, if any
43cve_lib.read_config()44cve_lib.read_config()
@@ -550,6 +551,7 @@ def cvss_source_from_filename(name):
550 return source551 return source
551 return 'unknown'552 return 'unknown'
552553
554
553class CVEHandler(xml.sax.handler.ContentHandler):555class CVEHandler(xml.sax.handler.ContentHandler):
554 """SAX handler for processing mitre's CVE database XML."""556 """SAX handler for processing mitre's CVE database XML."""
555557
@@ -574,7 +576,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
574 self.cve_seen = set()576 self.cve_seen = set()
575 self.cve_list = []577 self.cve_list = []
576 self.cve_data = dict()578 self.cve_data = dict()
577 self.saved_ignore_reason = ""579 self.saved_ignore_cache = IgnoredCache()
578 self.saved_package = ""580 self.saved_package = ""
579 self.saved_cve = ""581 self.saved_cve = ""
580 self.debian = None582 self.debian = None
@@ -1127,11 +1129,11 @@ class CVEHandler(xml.sax.handler.ContentHandler):
1127 prompts = []1129 prompts = []
11281130
1129 # Show debian reason first, then automatically determined1131 # Show debian reason first, then automatically determined
1130 # reason, then saved reason. This makes more sense1132 # reason, then saved reasons. This makes more sense
1131 # than sorting the reasons and is more predictable1133 # than sorting the reasons and is more predictable
1132 for choice in [reason, 1134 choices = [reason, self.get_ignore_suggestion(self.cve_data[cve]['desc'])]
1133 self.get_ignore_suggestion(self.cve_data[cve]['desc']),1135 choices.extend(self.saved_ignore_cache.get())
1134 self.saved_ignore_reason]:1136 for choice in choices:
1135 if choice != "" and choice not in prompts:1137 if choice != "" and choice not in prompts:
1136 prompts.append(choice)1138 prompts.append(choice)
11371139
@@ -1153,7 +1155,7 @@ class CVEHandler(xml.sax.handler.ContentHandler):
1153 elif len(info) < 3: # Fat fingers protection1155 elif len(info) < 3: # Fat fingers protection
1154 print('\nError: Reason must be at least 3 characters long!\n')1156 print('\nError: Reason must be at least 3 characters long!\n')
1155 info = ""1157 info = ""
1156 self.saved_ignore_reason = info1158 self.saved_ignore_cache.insert(info)
1157 self.ignore_cve(cve, info)1159 self.ignore_cve(cve, info)
11581160
1159 elif info.startswith('s'):1161 elif info.startswith('s'):
diff --git a/scripts/check_cves/ignored_cache.py b/scripts/check_cves/ignored_cache.py
1160new file mode 1006441162new file mode 100644
index 0000000..6130994
--- /dev/null
+++ b/scripts/check_cves/ignored_cache.py
@@ -0,0 +1,37 @@
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (C) 2022 Canonical Ltd.
5#
6# Implements a simple cache for recent reasons for ignoring CVE
7# entries, as used by check-cves
8
9
10class IgnoredCache():
11 # Keeps a list of ignored entries with a maximum length
12
13 _ignored = list()
14
15 def __init__(self, initial_list=None, max_len=5):
16 if initial_list:
17 self._ignored = initial_list
18 self.max_len = max_len
19 self._prune_cache()
20
21 # ensure list is less than or equal to the maximum length, and prune
22 # if not
23 def _prune_cache(self):
24 if len(self._ignored) > self.max_len:
25 self._ignored = self._ignored[:self.max_len]
26
27 def insert(self, reason):
28 # if the reason already exists, remove it so it can be
29 # reinserted at the head of the list
30 if reason in self._ignored:
31 self._ignored.remove(reason)
32
33 self._ignored.insert(0, reason)
34 self._prune_cache()
35
36 def get(self):
37 return self._ignored

Subscribers

People subscribed via source and target branches