Gentoo Archives: gentoo-commits

From: John Helmert III <ajak@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/security:ajak-cvetool commit in: bin/
Date: Mon, 19 Jul 2021 02:55:08
Message-Id: 1626663293.f1634540fe60edd3cbcff258b04d3b4e3aa31577.ajak@gentoo
1 commit: f1634540fe60edd3cbcff258b04d3b4e3aa31577
2 Author: John Helmert III <ajak <AT> gentoo <DOT> org>
3 AuthorDate: Mon Jul 19 02:49:49 2021 +0000
4 Commit: John Helmert III <ajak <AT> gentoo <DOT> org>
5 CommitDate: Mon Jul 19 02:54:53 2021 +0000
6 URL: https://gitweb.gentoo.org/proj/security.git/commit/?id=f1634540
7
8 glsatool: add partial releasing functionality
9
10 This separates the previous functionality into a `glsatool new` and adds
11 some new functionality as `glsatool release`. Currently only fetches the
12 GLSA XML and text, places the XML in your glsa.git repository, and adds
13 the necessary headers to the mail text.
14
15 Signed-off-by: John Helmert III <ajak <AT> gentoo.org>
16
17 bin/GLSATool.py | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++------
18 1 file changed, 90 insertions(+), 9 deletions(-)
19
20 diff --git a/bin/GLSATool.py b/bin/GLSATool.py
21 index c7fc804..a2a1b1b 100644
22 --- a/bin/GLSATool.py
23 +++ b/bin/GLSATool.py
24 @@ -2,6 +2,7 @@ from configparser import ConfigParser
25 import argparse
26 import os
27 import re
28 +import sys
29
30 import bugzilla
31 import requests
32 @@ -19,9 +20,15 @@ class GLSATool:
33 self.auth = glsamaker_key
34 self.bgo = bugzilla.Bugzilla('https://bugs.gentoo.org',
35 api_key=bgo_key, force_rest=True)
36 -
37 - def get_csrf_token(self):
38 - soup = bs(self.request('/glsas/new'), features='lxml')
39 + config_path = os.path.join(os.path.expanduser('~'),
40 + '.config', 'glsatool')
41 + c = ConfigParser()
42 + c.read(config_path)
43 + self.glsa_path = c['default']['glsa']
44 + self.from_str = c['default']['from']
45 +
46 + def get_csrf_token(self, path):
47 + soup = bs(self.request(path), features='lxml')
48 csrf_token = \
49 soup.find('input', {'name': 'authenticity_token'})['value']
50 return csrf_token
51 @@ -45,6 +52,64 @@ class GLSATool:
52 raise RuntimeError(path + ': ' + str(response.status_code))
53 return response.text
54
55 + def get_int_input(self, msg):
56 + while True:
57 + i = input(msg)
58 + try:
59 + return int(i)
60 + except (ValueError, EOFError):
61 + continue
62 +
63 + def release_glsa(self, num=None):
64 + if not num:
65 + soup = bs(self.request('/glsas/drafts'), features='lxml')
66 + glsas = soup.find_all('tr', {'class': True})
67 + for idx, item in enumerate(glsas):
68 + print('[{0}] {1}'.format(idx, item.find('a').text))
69 + i = self.get_int_input("Which GLSA to release? ")
70 + print("Selected '{0}'".format(glsas[i].a.text))
71 + num = glsas[i].a['href'][-4:]
72 +
73 + prepare_path = '/glsas/{}/prepare_release'.format(num)
74 + release_path = '/glsas/{}/release'.format(num)
75 + xml_path = '/glsas/{}/download.xml'.format(num)
76 + txt_path = '/glsas/{}/download.txt'.format(num)
77 +
78 + data = {
79 + 'value': 'Release &gt;',
80 + 'authenticity_token': self.get_csrf_token(prepare_path)
81 + }
82 +
83 + # Click the "release" button
84 + released_soup = bs(self.request(release_path, method='POST', data=data),
85 + features='lxml')
86 + glsa_id = 'glsa-' + released_soup.find('strong').text.split()[1]
87 +
88 + # Grab the xml
89 + xml = self.request(xml_path)
90 + xml_filename = '{}.xml'.format(glsa_id)
91 + xml_path = os.path.join(self.glsa_path, xml_filename)
92 +
93 + # Write and (TODO) commit it
94 + with open(xml_path, 'w') as f:
95 + f.write(xml)
96 + print("Wrote {}".format(xml_filename))
97 +
98 + # Grab the mail text
99 + txt = self.request(txt_path)
100 + txt_filename = '{}.txt'.format(glsa_id)
101 +
102 + # Write it
103 + with open(txt_filename, 'w') as f:
104 + f.write('From: {}\n'.format(self.from_str))
105 + f.write('Reply-To: security@g.o\n')
106 + f.write(txt)
107 + print("Wrote {}".format(txt_filename))
108 +
109 + # TODO:
110 + # Mail it
111 + # Close bugs
112 +
113 def new_whiteboard(self, old_whiteboard):
114 regex = re.compile('[A-C~][0-4] \[.*\]')
115 severity = old_whiteboard[:2]
116 @@ -78,7 +143,7 @@ class GLSATool:
117 'access': 'public',
118 'import_references': '1',
119 'what': 'request', # ???
120 - 'authenticity_token': self.get_csrf_token()
121 + 'authenticity_token': self.get_csrf_token('/glsas/new')
122 }
123 self.request('/glsas', method='POST', data=data)
124 print("GLSA request filed")
125 @@ -104,10 +169,26 @@ def bgo_key():
126
127 def glsatool():
128 parser = argparse.ArgumentParser()
129 - parser.add_argument('-b', '--bugs', required=True, nargs='+')
130 - parser.add_argument('-t', '--title', required=True)
131 + subparsers = parser.add_subparsers(dest='command')
132 +
133 + new_parser = subparsers.add_parser('new')
134 + new_parser.add_argument('-b', '--bugs', required=True, nargs='+')
135 + new_parser.add_argument('-t', '--title', required=True)
136 +
137 + release_parser = subparsers.add_parser('release')
138 + release_parser.add_argument('-i', '--id')
139 +
140 args = parser.parse_args()
141 auth = glsamaker_key()
142 - for bug in args.bugs:
143 - CVETool(auth, 'dobug', [bug])
144 - GLSATool(auth, bgo_key()).new_glsa(args.title, args.bugs)
145 + gtool = GLSATool(auth, bgo_key())
146 + if args.command == 'new':
147 + for bug in args.bugs:
148 + CVETool(auth, 'dobug', [bug])
149 + gtool.new_glsa(args.title, args.bugs)
150 + elif args.command == 'release':
151 + if args.id:
152 + gtool.release_glsa(num=args.id)
153 + else:
154 + gtool.release_glsa()
155 + else:
156 + print("No command given!")