commit:     1e03a6b7d241a9eaa3f9950613b37d8c100602d1
Author:     Alex Legler <alex <AT> a3li <DOT> li>
AuthorDate: Wed Jun  1 17:56:44 2016 +0000
Commit:     Alex Legler <a3li <AT> gentoo <DOT> org>
CommitDate: Wed Jun  1 17:56:44 2016 +0000
URL:        https://gitweb.gentoo.org/proj/security.git/commit/?id=1e03a6b7

Add initial CVETool CLI utility

 bin/cvetool | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 130 insertions(+)

diff --git a/bin/cvetool b/bin/cvetool
new file mode 100755
index 0000000..8e388e0
--- /dev/null
+++ b/bin/cvetool
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# Copyright 2016 Alex Legler
+# Distributed under the terms of the GNU General Public License v3
+
+import json
+import re
+import string
+import sys
+import os
+import httplib2
+from base64 import b64encode
+
+URI_BASE = 'https://glsamaker.gentoo.org'
+
+class CVETool:
+    """ Interface to GLSAMaker's CVETool """
+
+    def __init__(self, auth, command, args):
+        self.auth = auth
+
+        if command == 'info':
+            self.info(self.cleanup_cve(sys.argv[2]))
+        elif command == 'assign':
+            if len(args) < 2:
+                print('Usage: assign <bug> <CVE> [<CVE>...]')
+                print('Assigns a set of CVEs to a bug')
+                sys.exit(1)
+
+            self.assign(args[0], [self.cleanup_cve(cve) for cve in args[1:]])
+        elif command == 'nfu':
+            if len(args) != 1:
+                print('Usage: nfu <CVE>')
+                print('Marks a CVE as not-for-us')
+                sys.exit(1)
+
+            self.nfu(self.cleanup_cve(args[0]))
+        elif command == 'pw':
+            if len(sys.argv) != 4:
+                print('Usage: pw <user> <password>')
+                print('Generates a base64-encoded credential for storing')
+                sys.exit(1)
+
+            self.pw(sys.argv[2], sys.argv[3])
+        else:
+            self.usage(sys.argv[0])
+            sys.exit(1)
+
+    def info(self, cve):
+        data = self.json_request('/cve/info/' + cve + '.json')
+
+        print('    CVE ID: ' + data['cve_id'])
+        print('   Summary: ' + data['summary'])
+        print(' Published: ' + data['published_at'])
+        print('-' * 80)
+        print('     State: ' + data['state'])
+        print('      Bugs: ' + ' , '.join(['https://bugs.gentoo.org/' + 
str(bug) for bug in data['bugs']]))
+
+    def assign(self, bug, cves):
+        cve_ids = [self.get_internal_cve_id(cve) for cve in cves]
+        response = self.request('/cve/assign/?bug=' + str(bug) + '&cves=' + 
','.join([str(c) for c in cve_ids]))
+
+        if (response == 'ok'):
+            print('Assigned bug {} to {}'.format(str(bug), ', '.join(cves)))
+        else:
+            print('Assigning likely failed: ' + response)
+            sys.exit(1)
+
+    def nfu(self, cve):
+        cve_id = self.get_internal_cve_id(cve)
+        response = self.request('/cve/nfu/?cves=' + str(cve_id) + '&reason=')
+
+        if (response == 'ok'):
+            print('Marked {} as NFU'.format(cve))
+        else:
+            print('Assigning likely failed: ' + response)
+            sys.exit(1)
+
+
+    def usage(self, programname):
+        """ Print usage information """
+        print('Usage: {} <command> <cve> [args]'.format(programname))
+        print('CLI for CVETool.')
+
+    def pw(self, user, password):
+        print(b64encode(bytes(user + ':' + password, 'utf-8')).decode('ascii'))
+
+    def get_internal_cve_id(self, cve):
+        """ Resolves a CVE id to the internal databse ID """
+        return self.json_request('/cve/info/' + cve + '.json')['id']
+
+    def json_request(self, uri, method='GET'):
+        return json.loads(self.request(uri, method))
+
+    def cleanup_cve(self, str):
+        regex = re.compile('^(CVE-)?\d{4}-\d{4,}$')
+        if not regex.match(str):
+            raise ValueError('Cannot parse CVE: ' + str)
+
+        if not str.startswith('CVE-'):
+            return 'CVE-' + str
+        else:
+            return str
+
+    def request(self, uri, method='GET'):
+        client = httplib2.Http('.cache')
+        full_uri = URI_BASE + uri
+        response, content = client.request(full_uri, method, headers = { 
'Authorization': 'Basic ' + self.auth })
+
+        status = response['status']
+        if (status[0] != '2' and status != '304'):
+            raise RuntimeError(full_uri + ': ' + status)
+
+        return content.decode('utf-8')
+
+def main():
+    if not 'CVETOOL_AUTH' in os.environ and not sys.argv[1] == 'pw':
+        print('CVETOOL_AUTH environment variable missing. Generate its 
contents with the pw subcommand.')
+        sys.exit(1)
+
+    auth = None
+    if 'CVETOOL_AUTH' in os.environ:
+        auth = os.environ['CVETOOL_AUTH']
+
+    CVETool(auth, sys.argv[1], sys.argv[2:])
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        print('\n ! Exiting.')

Reply via email to