You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2015/12/06 00:22:20 UTC
svn commit: r1718134 - in /subversion/trunk/tools/dist: README.advisory
advisory.py security/mailinglist.py
Author: brane
Date: Sat Dec 5 23:22:20 2015
New Revision: 1718134
URL: http://svn.apache.org/viewvc?rev=1718134&view=rev
Log:
Finally wrote the script for sending advisory mails.
* tools/dist/advisory.py: New; the all-in-one script.
* tools/dist/README.advisory: Instructions for using said script.
* tools/dist/security/mailinglist.py:
Tweak interface to match the other scripts in this module.
Added:
subversion/trunk/tools/dist/README.advisory (with props)
subversion/trunk/tools/dist/advisory.py (with props)
Modified:
subversion/trunk/tools/dist/security/mailinglist.py
Added: subversion/trunk/tools/dist/README.advisory
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dist/README.advisory?rev=1718134&view=auto
==============================================================================
--- subversion/trunk/tools/dist/README.advisory (added)
+++ subversion/trunk/tools/dist/README.advisory Sat Dec 5 23:22:20 2015
@@ -0,0 +1,78 @@
+A guide to sending security advisory e-mails
+============================================
+
+--------------------------------------------------------
+Step 1: Prepare the advisory texts, patches and metadata
+--------------------------------------------------------
+
+[details are covered elsewhere]
+
+----------------------------------
+Step 2: Prepare the website update
+----------------------------------
+
+ $ cd ${PMC_AREA_WC}/security
+ $ ${TRUNK_WC}/tools/dist/advisory.py generate \
+ --destinatio=${SITE_WC}/publish/security \
+ CVE-2015-5259 CVE-2015-5343 ...
+
+This will generate a plain-text version of the advisories, including
+patches etc., suiatble for publishing on our web site. Once these
+are generated, make sure you add the links to the new files to:
+
+ ${SITE_WC}/publish/security/index.html
+
+
+-----------------------------------------------
+Step 3: Check the advisories and their metadata
+-----------------------------------------------
+
+ $ cd ${PMC_AREA_WC}/security
+ $ ${TRUNK_WC}/tools/dist/advisory.py test \
+ --username=someone \
+ --revision=22091347 \
+ --release-versions=1.8.15,1.9.3 \
+ --release-date=2015-12-15 \
+ CVE-2015-5259 CVE-2015-5343 ...
+
+Assuming all the required bits are in place, this will generate the
+complete text of a GPG-signed e-mail message, signed by and sent from
+someone@apache.org, for all the listed CVE numbers.
+
+Note the arguments:
+
+ --revision is the revision on
+ https://dist.apache.org/repos/dist/dev/subversion
+ in which the tarballs are/will be available
+ (see: notice-template.txt in ${PMC_AREA_WC}/security).
+
+ --release-versions is a comma-separated list of version numbers
+ in which fixes for the CVE numbers will be
+ available.
+
+ --release-date is the expected date of the release(s).
+
+
+----------------------
+Step 4: Send teh mails
+----------------------
+
+ $ cd ${PMC_AREA_WC}/security
+ $ ${TRUNK_WC}/tools/dist/advisory.py test \
+ (the rest of the arguments are as in step 3).
+
+The mails will be sent one at a time to each recipient separately.
+
+
+--------------------------------------------------
+Step 5: Wait for the release. Release.
+ Commit the site update prepared in step 1.
+--------------------------------------------------
+
+
+
+TODO: security/mailer.py does not calculate the micalg= PGP/MIME
+ parameter based on the properties of the actual PGP key
+ used. It's currently hard-coded as "pgp-sha512" which *should*
+ be correct for anyone signing these mails with their ASF release
+ signing key.
Propchange: subversion/trunk/tools/dist/README.advisory
------------------------------------------------------------------------------
svn:eol-style = native
Added: subversion/trunk/tools/dist/advisory.py
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dist/advisory.py?rev=1718134&view=auto
==============================================================================
--- subversion/trunk/tools/dist/advisory.py (added)
+++ subversion/trunk/tools/dist/advisory.py Sat Dec 5 23:22:20 2015
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+"""
+Send GPG-signed security advisory e-mayails from an @apache.org address
+to a known list of recipients, or write the advisory text in a
+form suitable for publishing on http://subversion.apache.org/.
+
+Usage: cd to the root directory of the advisory descriptions, then:
+
+ $ ${TRUNK_WC}/tools/dist/advisory.py send \
+ --username=<ASF-username> \
+ --revision=<dist-dev-revision-number>
+ --release-versions=<target-releases> \
+ --release-date=<expected-release-date> <CVE-number>...
+
+or
+
+ $ ${TRUNK_WC}/tools/dist/advisory.py test \
+ (... --username, etc. as above)
+
+or
+
+ $ ${TRUNK_WC}/tools/dist/advisory.py generate \
+ --destination=${SITE_WC}/publish/security \
+ <CVE-number>...
+"""
+
+from __future__ import absolute_import
+
+import os
+import sys
+import argparse
+import datetime
+import getpass
+import re
+
+import security.parser
+import security.adviser
+import security.mailer
+import security.mailinglist
+
+ROOTDIR = os.path.abspath(os.getcwd())
+NOTICE_TEMPLATE = 'notice-template.txt'
+MAILING_LIST = 'pre-notifications.txt'
+
+
+def parse_args(argv):
+ parser = argparse.ArgumentParser(
+ prog=os.path.basename(__file__), add_help=True,
+ description="""\
+Send GPG-signed security advisory e-mayails from an @apache.org address
+to a known list of recipients, or write the advisory text in a
+form suitable for publishing on http://subversion.apache.org/.
+""")
+ parser.add_argument(
+ 'command', action='store',
+ choices=['send', 'test', 'generate'],
+ help=('send: send mail; '
+ 'test: write the mail to standard output; '
+ 'generate: write an advisory for the website'))
+ parser.add_argument(
+ '--username', action='store', required=False,
+ help='the @apache.org username of the sender')
+ parser.add_argument(
+ '--revision', action='store', required=False, type=int,
+ help=('revision on dist.a.o./repos/dist/dev/subversion '
+ 'in which the patched tarballs are available'))
+ parser.add_argument(
+ '--release-versions', action='store', required=False,
+ help=('comma-separated list of future released versions '
+ 'that will contain the fix(es)'))
+ parser.add_argument(
+ '--release-date', action='store', required=False,
+ help=('expected release date for the above mentioned'
+ ' versions (in ISO format, YYYY-MM-DD)'))
+ parser.add_argument(
+ '--destination', action='store', required=False,
+ help=('the directory where the website advisory should be '
+ 'written; usually ${SITE_WC}/publish/security'))
+ parser.add_argument('cve', nargs='+')
+
+ return parser.parse_args(argv)
+
+
+def check_root():
+ if not os.path.isfile(os.path.join(ROOTDIR, NOTICE_TEMPLATE)):
+ sys.stderr.write('Missing file: ' + NOTICE_TEMPLATE + '\n')
+ sys.exit(1)
+ if not os.path.isfile(os.path.join(ROOTDIR, MAILING_LIST)):
+ sys.stderr.write('Missing file: ' + MAILING_LIST + '\n')
+ sys.exit(1)
+
+
+def check_sendmail(args):
+ if (not (args.username and args.revision
+ and args.release_versions
+ and args.release_date and args.cve)
+ or args.destination):
+ sys.stderr.write(
+ 'The "' + args.command + '" command requires the '
+ 'following options:\n'
+ ' --username, --revision, --release-versions, --release-date\n'
+ ' and a list of CVE numbers.\n')
+ sys.exit(1)
+ args.release_versions = re.split(r'\s*,\s*', args.release_versions)
+ args.release_date = datetime.datetime.strptime(args.release_date,
+ '%Y-%m-%d')
+
+
+def sendmail(really_send, args):
+ notice_template = os.path.join(ROOTDIR, NOTICE_TEMPLATE)
+ mailing_list = os.path.join(ROOTDIR, MAILING_LIST)
+ sender = args.username + '@apache.org'
+ notification = security.parser.Notification(ROOTDIR, *args.cve)
+ mailer = security.mailer.Mailer(notification,
+ args.username + '@apache.org',
+ notice_template,
+ args.release_date,
+ args.revision,
+ *args.release_versions)
+ message = mailer.generate_message()
+ recipients = security.mailinglist.MailingList(mailing_list)
+ if (not really_send):
+ sys.stdout.write(message.as_string())
+ return
+
+ password = getpass.getpass('Password for ' + args.username
+ + ' at mail-relay.apache.org: ')
+ mailer.send_mail(message, args.username, password,
+ recipients=recipients)
+
+
+def check_generate(args):
+ if (not (args.destination and args.cve)
+ or args.username or args.revision
+ or args.release_versions
+ or args.release_date):
+ sys.stderr.write(
+ 'The "generate" command requires the '
+ '--destination option '
+ 'and a list of CVE numbers.\n')
+ sys.exit(1)
+ if not os.path.isdir(args.destination):
+ sys.stderr.write(args.destination + ' is not a directory')
+ sys.exit(1)
+
+def generate(args):
+ notification = security.parser.Notification(ROOTDIR, *args.cve)
+ security.adviser.generate(notification, args.destination);
+
+
+def main():
+ check_root()
+ args = parse_args(sys.argv[1:])
+ if args.command in ('send', 'test'):
+ check_sendmail(args)
+ sendmail(args.command == 'send', args)
+ elif args.command == 'generate':
+ check_generate(args)
+ generate(args)
+
+
+if __name__ == '__main__':
+ main()
Propchange: subversion/trunk/tools/dist/advisory.py
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/trunk/tools/dist/advisory.py
------------------------------------------------------------------------------
svn:executable = *
Modified: subversion/trunk/tools/dist/security/mailinglist.py
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/dist/security/mailinglist.py?rev=1718134&r1=1718133&r2=1718134&view=diff
==============================================================================
--- subversion/trunk/tools/dist/security/mailinglist.py (original)
+++ subversion/trunk/tools/dist/security/mailinglist.py Sat Dec 5 23:22:20 2015
@@ -34,12 +34,11 @@ class MailingList(object):
Parses ^/pmc/subversion/security/pre-notifications.txt
"""
- __PRE_NOTIFICATIONS = 'pre-notifications.txt'
__ADDRESS_LINE = re.compile(r'^\s{6}(?:[^<]+)?<[^<>]+>\s*$')
- def __init__(self, rootdir):
+ def __init__(self, mailing_list):
self.__addresses = []
- self.__parse_addresses(rootdir)
+ self.__parse_addresses(mailing_list)
def __iter__(self):
return self.__addresses.__iter__()
@@ -47,9 +46,8 @@ class MailingList(object):
def __len__(self):
return len(self.__addresses)
- def __parse_addresses(self, rootdir):
- pre_notifications = os.path.join(rootdir, self.__PRE_NOTIFICATIONS)
- with open(pre_notifications, 'rt') as pn:
+ def __parse_addresses(self, mailing_list):
+ with open(mailing_list, 'rt') as pn:
for line in pn:
m = self.__ADDRESS_LINE.match(line)
if not m: