commit:     6dc80e16f0f208b7bbe143160186c930b151d8e1
Author:     John Helmert III <ajak <AT> gentoo <DOT> org>
AuthorDate: Tue Jul  6 02:03:14 2021 +0000
Commit:     John Helmert III <ajak <AT> gentoo <DOT> org>
CommitDate: Tue Jul  6 02:03:43 2021 +0000
URL:        https://gitweb.gentoo.org/proj/security.git/commit/?id=6dc80e16

glsatool: new tool

Signed-off-by: John Helmert III <ajak <AT> gentoo.org>

 bin/glsatool | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/bin/glsatool b/bin/glsatool
new file mode 100755
index 0000000..f1d69c6
--- /dev/null
+++ b/bin/glsatool
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+
+from configparser import ConfigParser
+import argparse
+import os
+import re
+
+import bugzilla
+import requests
+from bs4 import BeautifulSoup as bs
+
+from CVETool import CVETool
+
+GLSAMAKER_URI = 'https://glsamaker.gentoo.org'
+
+
+class GLSATool:
+    """ Utility to ease GLSA handling in GLSAMaker """
+
+    def __init__(self, glsamaker_key, bgo_key):
+        self.auth = glsamaker_key
+        self.bgo = bugzilla.Bugzilla('https://bugs.gentoo.org',
+                                     api_key=bgo_key, force_rest=True)
+
+    def get_csrf_token(self):
+        soup = bs(self.request('/glsas/new'), features='lxml')
+        csrf_token = \
+            soup.find('input', {'name': 'authenticity_token'})['value']
+        return csrf_token
+
+    def request(self, path, method='GET', data=None):
+        if method == 'GET':
+            response = requests.get(GLSAMAKER_URI + path,
+                                    headers={'Authorization':
+                                             'Basic ' + self.auth})
+        elif method == 'POST':
+            if data:
+                response = requests.post(GLSAMAKER_URI + path,
+                                         data=data,
+                                         headers={'Authorization':
+                                                  'Basic ' + self.auth})
+            else:
+                response = requests.post(GLSAMAKER_URI + path,
+                                         headers={'Authorization':
+                                                  'Basic ' + self.auth})
+        if not response.ok:
+            raise RuntimeError(path + ': ' + str(response.status_code))
+        return response.text
+
+    def new_whiteboard(self, old_whiteboard):
+        regex = re.compile('[A-C~][0-4] \[.*\]')
+        severity = old_whiteboard[:2]
+        new = ['glsa']
+
+        if not regex.match(old_whiteboard):
+            # Don't even try to operate on a whiteboard with a strange
+            # format
+            raise RuntimeError("Bad whiteboard! '" + old_whiteboard + "'")
+
+        # Iterate over words within the [] part of whiteboard
+        for word in re.sub('[\[\]]', '', old_whiteboard[2:]).split():
+            if 'glsa' not in word:
+                new += [word]
+        if 'cve' not in new:
+            new.append('cve')
+        return severity + ' [' + ' '.join(new) + ']'
+
+    def update_bugs(self, bugs):
+        for bug in self.bgo.getbugs(bugs):
+            update = {'whiteboard': self.new_whiteboard(bug.whiteboard)}
+            update['comment'] = {'comment': 'GLSA request filed.'}
+            print('https://bugs.gentoo.org/' + str(bug.id) + ': ' +
+                  bug.whiteboard + ' -> ' + update['whiteboard'])
+            self.bgo.update_bugs([bug.id], update)
+
+    def new_glsa(self, title, bugs):
+        data = {
+            'title': title + ' [DRAFT]',
+            'bugs': ','.join(bugs),
+            'access': 'public',
+            'import_references': '1',
+            'what': 'request',  # ???
+            'authenticity_token': self.get_csrf_token()
+        }
+        self.request('/glsas', method='POST', data=data)
+        print("GLSA request filed")
+        self.update_bugs(bugs)
+
+
+def glsamaker_key():
+    authpath = os.path.join(os.path.expanduser('~'), '.config', 'cvetool_auth')
+    if 'CVETOOL_AUTH' in os.environ:
+        return os.environ['CVETOOL_AUTH']
+    if os.path.isfile(authpath):
+        with open(authpath, 'r') as authfile:
+            return authfile.readlines()[0]
+
+
+def bgo_key():
+    bugzrc = os.path.expanduser("~/.bugzrc")
+    config = ConfigParser()
+    config.read(bugzrc)
+    apikey = config['default']['key']
+    return apikey
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument('-b', '--bugs', required=True, nargs='+')
+    parser.add_argument('-t', '--title', required=True)
+    args = parser.parse_args()
+    auth = glsamaker_key()
+    for bug in args.bugs:
+        CVETool(auth, 'dobug', [bug])
+    GLSATool(auth, bgo_key()).new_glsa(args.title, args.bugs)

Reply via email to