aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Helmert III <ajak@gentoo.org>2021-07-18 21:49:49 -0500
committerJohn Helmert III <ajak@gentoo.org>2021-07-18 21:54:53 -0500
commitf1634540fe60edd3cbcff258b04d3b4e3aa31577 (patch)
treeab925018eb698f101c854c3eb8a9d2a1bf024453
parentcvetool: fix missing import (diff)
downloadsecurity-f1634540fe60edd3cbcff258b04d3b4e3aa31577.tar.gz
security-f1634540fe60edd3cbcff258b04d3b4e3aa31577.tar.bz2
security-f1634540fe60edd3cbcff258b04d3b4e3aa31577.zip
glsatool: add partial releasing functionality
This separates the previous functionality into a `glsatool new` and adds some new functionality as `glsatool release`. Currently only fetches the GLSA XML and text, places the XML in your glsa.git repository, and adds the necessary headers to the mail text. Signed-off-by: John Helmert III <ajak@gentoo.org>
-rw-r--r--bin/GLSATool.py99
1 files changed, 90 insertions, 9 deletions
diff --git a/bin/GLSATool.py b/bin/GLSATool.py
index c7fc804..a2a1b1b 100644
--- a/bin/GLSATool.py
+++ b/bin/GLSATool.py
@@ -2,6 +2,7 @@ from configparser import ConfigParser
import argparse
import os
import re
+import sys
import bugzilla
import requests
@@ -19,9 +20,15 @@ class GLSATool:
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')
+ config_path = os.path.join(os.path.expanduser('~'),
+ '.config', 'glsatool')
+ c = ConfigParser()
+ c.read(config_path)
+ self.glsa_path = c['default']['glsa']
+ self.from_str = c['default']['from']
+
+ def get_csrf_token(self, path):
+ soup = bs(self.request(path), features='lxml')
csrf_token = \
soup.find('input', {'name': 'authenticity_token'})['value']
return csrf_token
@@ -45,6 +52,64 @@ class GLSATool:
raise RuntimeError(path + ': ' + str(response.status_code))
return response.text
+ def get_int_input(self, msg):
+ while True:
+ i = input(msg)
+ try:
+ return int(i)
+ except (ValueError, EOFError):
+ continue
+
+ def release_glsa(self, num=None):
+ if not num:
+ soup = bs(self.request('/glsas/drafts'), features='lxml')
+ glsas = soup.find_all('tr', {'class': True})
+ for idx, item in enumerate(glsas):
+ print('[{0}] {1}'.format(idx, item.find('a').text))
+ i = self.get_int_input("Which GLSA to release? ")
+ print("Selected '{0}'".format(glsas[i].a.text))
+ num = glsas[i].a['href'][-4:]
+
+ prepare_path = '/glsas/{}/prepare_release'.format(num)
+ release_path = '/glsas/{}/release'.format(num)
+ xml_path = '/glsas/{}/download.xml'.format(num)
+ txt_path = '/glsas/{}/download.txt'.format(num)
+
+ data = {
+ 'value': 'Release &gt;',
+ 'authenticity_token': self.get_csrf_token(prepare_path)
+ }
+
+ # Click the "release" button
+ released_soup = bs(self.request(release_path, method='POST', data=data),
+ features='lxml')
+ glsa_id = 'glsa-' + released_soup.find('strong').text.split()[1]
+
+ # Grab the xml
+ xml = self.request(xml_path)
+ xml_filename = '{}.xml'.format(glsa_id)
+ xml_path = os.path.join(self.glsa_path, xml_filename)
+
+ # Write and (TODO) commit it
+ with open(xml_path, 'w') as f:
+ f.write(xml)
+ print("Wrote {}".format(xml_filename))
+
+ # Grab the mail text
+ txt = self.request(txt_path)
+ txt_filename = '{}.txt'.format(glsa_id)
+
+ # Write it
+ with open(txt_filename, 'w') as f:
+ f.write('From: {}\n'.format(self.from_str))
+ f.write('Reply-To: security@gentoo.org\n')
+ f.write(txt)
+ print("Wrote {}".format(txt_filename))
+
+ # TODO:
+ # Mail it
+ # Close bugs
+
def new_whiteboard(self, old_whiteboard):
regex = re.compile('[A-C~][0-4] \[.*\]')
severity = old_whiteboard[:2]
@@ -78,7 +143,7 @@ class GLSATool:
'access': 'public',
'import_references': '1',
'what': 'request', # ???
- 'authenticity_token': self.get_csrf_token()
+ 'authenticity_token': self.get_csrf_token('/glsas/new')
}
self.request('/glsas', method='POST', data=data)
print("GLSA request filed")
@@ -104,10 +169,26 @@ def bgo_key():
def glsatool():
parser = argparse.ArgumentParser()
- parser.add_argument('-b', '--bugs', required=True, nargs='+')
- parser.add_argument('-t', '--title', required=True)
+ subparsers = parser.add_subparsers(dest='command')
+
+ new_parser = subparsers.add_parser('new')
+ new_parser.add_argument('-b', '--bugs', required=True, nargs='+')
+ new_parser.add_argument('-t', '--title', required=True)
+
+ release_parser = subparsers.add_parser('release')
+ release_parser.add_argument('-i', '--id')
+
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)
+ gtool = GLSATool(auth, bgo_key())
+ if args.command == 'new':
+ for bug in args.bugs:
+ CVETool(auth, 'dobug', [bug])
+ gtool.new_glsa(args.title, args.bugs)
+ elif args.command == 'release':
+ if args.id:
+ gtool.release_glsa(num=args.id)
+ else:
+ gtool.release_glsa()
+ else:
+ print("No command given!")