summaryrefslogtreecommitdiffstats
path: root/bin/contact-maintainers
blob: 7940c5a5127e99151f3a644b9212c5a764123348 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/python

import argparse
import os
import pwd
import subprocess
import sys
import tempfile
import warnings

from jinja2 import Template


def get_full_name():
    full_name = os.getenv('DEBFULLNAME')
    if full_name:
        return full_name.decode('utf-8')
    return pwd.getpwuid(os.getuid()).pw_gecos.split(',')[0].decode('utf-8')


try:
    import rdflib

except ImportError:
    warnings.warn('python-rdflib not installed; will fall back to PTS email address')
    def get_maintainers(pkg):
        return u'{}@packages.debian.org'.format(pkg)

else:
    def get_maintainers(pkg):
        import re, urllib

        # RDF object and predicate references used on PTS
        project = rdflib.term.URIRef(u'http://packages.qa.debian.org/{}#project'.format(pkg))
        has_contributor = rdflib.term.URIRef(u'http://schema.org/contributor')
        is_named = rdflib.term.URIRef(u'http://xmlns.com/foaf/0.1/name')
        is_same_as = rdflib.term.URIRef(u'http://www.w3.org/2002/07/owl#sameAs')

        maint = []

        graph = rdflib.Graph()
        graph.parse('https://packages.qa.debian.org/{}/{}.rdf'
                    .format(re.match('((?:lib)?.)', pkg).group(1), pkg))
        for contrib in graph[project : has_contributor]:
            names = [n for n in graph[contrib : is_named]]
            addresses = [urllib.unquote(m.group(1)) for m in
                         map(re.compile(r'http://webid\.debian\.net/maintainers/(.*)#agent$').match,
                             graph[contrib : is_same_as])
                         if m]
            if not names or not addresses:
                warnings.warn('found contributor missing name and/or address')
                continue
            address = addresses[0]
            if '@' not in address:
                address += '@debian.org'
            maint.append(u'"{}" <{}>'.format(names[0], address))

        return u', '.join(maint)


# Parse command line
parser = argparse.ArgumentParser(
    description='Get in touch with package maintainers')
parser.add_argument('--force', action='store_true',
                    help='Ignore safety checks')
parser.add_argument('--lts', action='store_true',
                    help='Act as a member of the LTS team')
parser.add_argument('--no-dsa', dest='no_dsa', action='store_true',
                    help='Say that issues are low severity (no need for DSA/DLA)')
parser.add_argument('--mailer', action='store', default='mutt -H {}',
                    help='Command executed. Must contain {} to be replaced '
                    'by the filename of the draft contact mail')
parser.add_argument('package')
parser.add_argument('cve', nargs='*')
args = parser.parse_args()

cc = 'debian-lts@lists.debian.org' if args.lts else 'team@security.debian.org'
team = 'lts' if args.lts else 'sec'
model = 'no-dsa' if args.no_dsa else 'update-planned'
template_file = 'templates/{}-{}.txt'.format(team, model)

# Basic check
instructions = "packages/{}.txt".format(args.package)
if os.path.exists(instructions) and not args.force:
    print("Have a look at {}".format(instructions))
    print("If you still want to run this script, run it with --force.")
    sys.exit(1)

# Generate the context

# XXX: Once that 761859 is fixed, improve the logic here to:
# - retrieve the current list of CVE dynamically
# - check whether we should use the no-dsa variant of the template
# - check whether we have an open bug report, in which case we should
#   include it in the recipients of the mail

context = {
    'package': args.package,
    'sender': get_full_name(),
    'cve': args.cve,
    'to': get_maintainers(args.package),
    'cc': cc,
    'uploaders': ''
}

# Generate the mail
with open(template_file) as f:
    template = Template(f.read().decode('utf-8'))

fd, filename = tempfile.mkstemp(prefix='contact-maintainers', suffix='.txt')
draft = os.fdopen(fd, 'w')
draft.write(template.render(context).encode('utf-8'))
draft.close()

os.system(args.mailer.format(filename))
os.unlink(filename)

© 2014-2024 Faster IT GmbH | imprint | privacy policy