Rush has submitted this change and it was merged.

Change subject: phab email pipe cleanup and allow maint
......................................................................


phab email pipe cleanup and allow maint

* If maint is true it rejects mail bound for phab.
* Cleaned out env variable to reflect upstream
  best practice
* Updated settings in puppet role

Change-Id: Ia86643c00b3c27db5ecd01b4ee005de80330c018
---
M manifests/role/phabricator.pp
M modules/phabricator/files/phab_epipe.py
M modules/phabricator/manifests/mailrelay.pp
3 files changed, 122 insertions(+), 80 deletions(-)

Approvals:
  Rush: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/manifests/role/phabricator.pp b/manifests/role/phabricator.pp
index 9b07fcd..8df17da 100644
--- a/manifests/role/phabricator.pp
+++ b/manifests/role/phabricator.pp
@@ -89,12 +89,14 @@
     include phabricator::monitoring
 
     class { '::phabricator::mailrelay':
-        default                   => { security => 'default'},
+        default                   => { security => 'users',
+                                       maint    => 'false',
+                                       save     => 'false',
+        },
         address_routing           => { testproj => 'demoproject'},
         phab_bot                  => { root_dir    => '/srv/phab/phabricator/',
-                                       env         => 'default',
                                        username    => 'emailbot',
-                                       host        => "http://${domain}";,
+                                       host        => "https://${domain}/api/";,
                                        certificate => $emailbotcert,
         },
     }
diff --git a/modules/phabricator/files/phab_epipe.py 
b/modules/phabricator/files/phab_epipe.py
index 3022a25..f3995f2 100644
--- a/modules/phabricator/files/phab_epipe.py
+++ b/modules/phabricator/files/phab_epipe.py
@@ -10,22 +10,30 @@
 * direct comments allows non-phabricator recognized emails to attach comments
   to a ticket for a specific project from allowed domains
 
--> custom attachments to be handled later by direct attach script
-
 Looks for configuration file: /etc/phab_epipe.conf
 
+    [default]
+    security = users
+    # if 'true' will reject all email to phab
+    maint = false
+    # saves every message overwriting /tmp/rawmail
+    save = false
+    # saves particular messages from a comma
+    # separated list of users
+    debug = <emails_to_dump_for_debug>
+
     [address_routing]
-    <dest_email_address> = <project_id_to_route_for_task_creation>
+    <dest_email_address> = <project_name/security>
 
     [direct_comments_allowed]
     <project_name> = <comma_separated_list_of_allowed_email_domains>
 
     [phab_bot]
     root_dir = <path_on_disk_to_phabricator
-    env = <phab_env>
     username    = <phab_user>
     certificate = <phab_user_cert>
     host        = <phab_host>
+
 """
 import os
 import re
@@ -63,9 +71,12 @@
     pass
 
 
+class EmailStatusError(Exception):
+    pass
+
+
 def main():
 
-    save = '-s' in sys.argv
     log = lambda m: output(m, verbose='-v' in sys.argv)
 
     # if stdin is empty we bail to avoid a loop
@@ -97,13 +108,6 @@
         :param name: str of project name
         """
         return phab.project.query(names=[name])
-
-    def get_proj_phid_by_id(pid):
-        """return project name by project id
-        :param pid: int project id
-        :returns: string
-        """
-        return phab.project.query(ids=[pid])['data'].keys()[0]
 
     def external_user_comment(task, text):
         """update a task with a comment by id
@@ -137,7 +141,6 @@
         block = "**`%s`** created via email on `%s`\n\n" % (sender, date)
         block += '\n'.join(['> ' + s for s in body.splitlines()])
         project_info = get_proj_by_name(project)
-
         if not project_info['data']:
             raise EmailParsingError("project %s does not exist" % (project))
 
@@ -165,12 +168,90 @@
         upload = phab.file.upload(name=name, data_base64=data)
         return phab.file.info(phid=upload.response).response
 
+    def extract_payload_and_upload(payload):
+        """ extract content and upload from MIME object
+        :param payload: MIME payload object
+        :return: str of created phab oject
+        """
+        name = None
+        # Some attachments have the field but it is None type
+        if not name and 'Content-Description' in payload:
+            name = payload['Content-Description']
+        if not name and 'Content-Disposition' in payload:
+            namex = re.search('name=\"(.*)\"', payload['Content-Type'])
+            if namex:
+                name = namex.group(1)
+        if not name and 'Content-Disposition' in payload:
+            fnamex = re.search('filename=(.*)', payload['Content-Disposition'])
+            if fnamex:
+                name = fnamex.group(1)
+
+        if name:
+            data = payload.get_payload()
+            upload = upload_file(name, data)
+            return upload['objectName']
+
+    def extract_body_and_attached(msg):
+        """ get body and payload objects
+        :param msg: email msg type
+        :return: str and list
+        """
+        attached = []
+        # https://docs.python.org/2/library/email.message.html
+        if msg.is_multipart():
+            for payload in msg.get_payload():
+                log('content type: %s' % (payload.get_content_type(),))
+                if payload.get_content_type() == 'text/plain':
+                    body = payload.get_payload()
+                elif payload.get_content_type() == 'multipart/alternative':
+                    msgparts = payload.get_payload()
+                    if not isinstance(msgparts, list):
+                        body = 'unknown body format'
+                        continue
+                    else:
+                        for e in msgparts:
+                            known_body_types = ['text/plain']
+                            # text/plain; charset="utf-8"
+                            # Inconsistent content-types so we
+                            # try to match only basic string
+                            type = e['Content-Type'].split(';')[0]
+                            if type in known_body_types:
+                                body = e.get_payload()
+                                break
+                        else:
+                            err = 'Unknown email body format: from %s to %s'
+                            dest = str(dest_addresses)
+                            raise EmailParsingError(error % (src_address,
+                                                             dest))
+
+                else:
+                    log('attaching file')
+                    attached.append(payload)
+
+        else:
+            body = msg.get_payload()
+        return body, attached
+
+    # If maint is true then reject all email interaction
+    if defaults['maint'].lower() == 'true':
+        raise EmailStatusError('Email interaction is currently disabled.')
+
+    if '-s' in sys.argv:
+        save = '/tmp/maildump'
+    elif 'save' in defaults:
+        save = defaults['save']
+    else:
+        save = False
+
+    if 'debug' in defaults:
+        defaults['debug'] = defaults['debug'].split(',')
+
+    # Reading in the message
     stdin = sys.stdin.read()
 
     if save:
-        dump = '/tmp/rawmail'
-        log('saving raw email to %s' % dump)
-        with open(dump, 'w') as r:
+        log('saving raw email to %s' % save)
+        with open(save, 'w') as r:
             r.write(stdin)
 
     # ['Received', 'DKIM-Signature', 'X-Google-DKIM-Signature',
@@ -182,62 +263,9 @@
     src_name, src_addy = parse_from_string(src_address)
     dest_addresses = msg['to'].split(',')
 
-    attached = []
-    # https://docs.python.org/2/library/email.message.html
-    if msg.is_multipart():
-        for payload in msg.get_payload():
-            log('content type: %s' % (payload.get_content_type(),))
-            if payload.get_content_type() == 'text/plain':
-                body = payload.get_payload()
-            elif payload.get_content_type() == 'multipart/alternative':
-                msgparts = payload.get_payload()
-                if not isinstance(msgparts, list):
-                    body = 'unknown body format'
-                    continue
-                else:
-                    for e in msgparts:
-                        known_body_types = ['text/plain']
-                        # text/plain; charset="utf-8"
-                        # Inconsistent content-types so we
-                        # try to match only basic string
-                        type = e['Content-Type'].split(';')[0]
-                        if type in known_body_types:
-                            body = e.get_payload()
-                            break
-                    else:
-                        err = 'Unknown email body format: from %s to %s'
-                        raise EmailParsingError(error % (src_address,
-                                                         str(dest_addresses)))
-
-            else:
-                log('attaching file')
-                attached.append(payload)
-
-    else:
-        body = msg.get_payload()
-
-    uploads = []
-    for payload in attached:
-
-        name = None
-        # Some attachments have the field but it is None type
-        if not name and 'Content-Description' in payload:
-            name = payload['Content-Description']
-
-        if not name and 'Content-Disposition' in payload:
-            namex = re.search('name=\"(.*)\"', payload['Content-Type'])
-            if namex:
-                name = namex.group(1)
-
-        if not name and 'Content-Disposition' in payload:
-            fnamex = re.search('filename=(.*)', payload['Content-Disposition'])
-            if fnamex:
-                name = fnamex.group(1)
-
-        if name:
-            data = payload.get_payload()
-            upload = upload_file(name, data)
-            uploads.append(upload['objectName'])
+    if 'debug' in defaults and src_address in defaults['debug']:
+        with open('/tmp/%s' % (src_address + '.txt'), 'w') as r:
+            r.write(stdin)
 
     # does this email have a direct to task addresss
     dtask = extract_direct_task(dest_addresses)
@@ -248,6 +276,11 @@
 
     if dtask:
         log('found direct task: %s' % (dtask,))
+        body, attached = extract_body_and_attached(msg)
+        uploads = []
+        for payload in attached:
+            uploads.append(extract_payload_and_upload(payload))
+
         # extra check for address validity for this process
         if src_address.count('@') > 1:
             error = 'invalid source address: %s' % (src_address,)
@@ -281,6 +314,13 @@
 
     elif routed_addresses:
         route_address = routed_addresses[0]
+        body, attached = extract_body_and_attached(msg)
+
+        # XXX: handle secure uploads for routed tasks
+        # uploads = []
+        # for payload in attached:
+        #    uploads.append(extract_payload_and_upload(payload))
+
         log('found routed address: %s' % (route_address,))
         if '/' in address_routing[route_address]:
             project, security = address_routing[route_address].split('/')
@@ -295,11 +335,9 @@
                       project,
                       security))
     else:
-        log('found phab default')
         handler = os.path.join(parser.get(parser_mode, 'root_dir'),
                                "scripts/mail/mail_handler.php")
-        process = subprocess.Popen([handler, parser.get(parser_mode, 'env')],
-                                   stdin=subprocess.PIPE)
+        process = subprocess.Popen([handler], stdin=subprocess.PIPE)
         process.communicate(stdin)
 
 
@@ -312,6 +350,9 @@
     # output to the sender, in order to not reveal internal
     # errors we only respond directly for defined errors
     # otherwise swallow, return generic, and go for syslog
+    except EmailStatusError as e:
+        print "%s\n\n%s" % (e, contact)
+        exit(1)
     except EmailParsingError as e:
         syslog.syslog("EmailParsingError: %s" % (str(e)))
         print "%s\n\n%s" % (e, contact)
diff --git a/modules/phabricator/manifests/mailrelay.pp 
b/modules/phabricator/manifests/mailrelay.pp
index 1d855c6..eda838c 100644
--- a/modules/phabricator/manifests/mailrelay.pp
+++ b/modules/phabricator/manifests/mailrelay.pp
@@ -19,10 +19,9 @@
 # === Examples
 #
 #    class { '::phabricator::mailrelay':
-#        address_routing         => { maint-announce => 3},
+#        address_routing         => { maint-announce => ops-maint-announce},
 #        direct_comments_allowed => { testproj => 'cisco.com,gmail.com'},
 #        phab_bot => { root_dir   => '/srv/phab/phabricator/',
-#                      env         => 'default',
 #                      username    => 'phabot',
 #                      host        => 'http://myhost/api/',
 #                      certificate => $certificate,

-- 
To view, visit https://gerrit.wikimedia.org/r/172915
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ia86643c00b3c27db5ecd01b4ee005de80330c018
Gerrit-PatchSet: 6
Gerrit-Project: operations/puppet
Gerrit-Branch: production
Gerrit-Owner: Rush <[email protected]>
Gerrit-Reviewer: Rush <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to