[python-bugzilla/f18] Don't upload scrambled attachments (bz #915318)

Cole Robinson crobinso at fedoraproject.org
Mon Mar 4 21:07:43 UTC 2013


commit 843f8f31732d5505ab90b82e6c0669e940f70389
Author: Cole Robinson <crobinso at redhat.com>
Date:   Mon Mar 4 16:07:40 2013 -0500

    Don't upload scrambled attachments (bz #915318)

 ...loading-attachments-as-base64-and-test-it.patch |  205 ++++++++++++++++++++
 python-bugzilla.spec                               |   11 +-
 2 files changed, 215 insertions(+), 1 deletions(-)
---
diff --git a/0001-Fix-uploading-attachments-as-base64-and-test-it.patch b/0001-Fix-uploading-attachments-as-base64-and-test-it.patch
new file mode 100644
index 0000000..3f83c09
--- /dev/null
+++ b/0001-Fix-uploading-attachments-as-base64-and-test-it.patch
@@ -0,0 +1,205 @@
+From 23b5b373ec18974bde6ce4dba006e81b8af1169f Mon Sep 17 00:00:00 2001
+Message-Id: <23b5b373ec18974bde6ce4dba006e81b8af1169f.1362430417.git.crobinso at redhat.com>
+From: Cole Robinson <crobinso at redhat.com>
+Date: Tue, 26 Feb 2013 17:47:37 -0500
+Subject: [PATCH] Fix uploading attachments as base64, and test it
+
+Use xmlrpclib's base64 support, rather than a hand rolled one.
+---
+ bugzilla/base.py       | 47 +++++++++++++----------------------------
+ tests/rw_functional.py | 57 +++++++++++++++++++++++++-------------------------
+ 2 files changed, 43 insertions(+), 61 deletions(-)
+
+diff --git a/bugzilla/base.py b/bugzilla/base.py
+index 60480dc..faddd0a 100644
+--- a/bugzilla/base.py
++++ b/bugzilla/base.py
+@@ -9,7 +9,6 @@
+ # option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
+ # the full text of the license.
+ 
+-import base64
+ import cookielib
+ import os
+ import tempfile
+@@ -834,14 +833,22 @@ class BugzillaBase(object):
+     # Methods for working with attachments #
+     ########################################
+ 
++    def _attachment_uri(self, attachid):
++        '''Returns the URI for the given attachment ID.'''
++        att_uri = self.url.replace('xmlrpc.cgi', 'attachment.cgi')
++        att_uri = att_uri + '?id=%s' % attachid
++        return att_uri
++
+     def attachfile(self, idlist, attachfile, description, **kwargs):
+         '''
+         Attach a file to the given bug IDs. Returns the ID of the attachment
+         or raises xmlrpclib.Fault if something goes wrong.
++
+         attachfile may be a filename (which will be opened) or a file-like
+         object, which must provide a 'read' method. If it's not one of these,
+         this method will raise a TypeError.
+         description is the short description of this attachment.
++
+         Optional keyword args are as follows:
+             file_name:  this will be used as the filename for the attachment.
+                        REQUIRED if attachfile is a file-like object with no
+@@ -851,9 +858,9 @@ class BugzillaBase(object):
+             is_private: Set to True if the attachment should be marked private.
+             is_patch:   Set to True if the attachment is a patch.
+             content_type: The mime-type of the attached file. Defaults to
+-                         application/octet-stream if not set. NOTE that text
+-                         files will *not* be viewable in bugzilla unless you
+-                         remember to set this to text/plain. So remember that!
++                          application/octet-stream if not set. NOTE that text
++                          files will *not* be viewable in bugzilla unless you
++                          remember to set this to text/plain. So remember that!
+ 
+         Returns the list of attachment ids that were added. If only one
+         attachment was added, we return the single int ID for back compat
+@@ -876,15 +883,14 @@ class BugzillaBase(object):
+             kwargs["file_name"] = kwargs.pop("filename")
+ 
+         kwargs['summary'] = description
++        kwargs['data'] = xmlrpclib.Binary(f.read())
++        kwargs['ids'] = self._listify(idlist)
++
+         if 'file_name' not in kwargs:
+             kwargs['file_name'] = os.path.basename(f.name)
+-
+         if 'content_type' not in kwargs:
+             kwargs['content_type'] = 'application/octet-stream'
+ 
+-        kwargs['data'] = self._attachment_encode(f)
+-        kwargs['ids'] = self._listify(idlist)
+-
+         ret = self._proxy.Bug.add_attachment(kwargs)
+ 
+         if "attachments" in ret:
+@@ -916,31 +922,6 @@ class BugzillaBase(object):
+         # Hooray, now we have a file-like object with .read() and .name
+         return att
+ 
+-    def _attachment_uri(self, attachid):
+-        '''Returns the URI for the given attachment ID.'''
+-        att_uri = self.url.replace('xmlrpc.cgi', 'attachment.cgi')
+-        att_uri = att_uri + '?id=%s' % attachid
+-        return att_uri
+-
+-    def _attachment_encode(self, fh):
+-        '''Return the contents of the file-like object fh in a form
+-        appropriate for attaching to a bug in bugzilla. This is the default
+-        encoding method, base64.'''
+-        # Read data in chunks so we don't end up with two copies of the file
+-        # in RAM.
+-
+-        # base64 encoding wants input in multiples of 3
+-        chunksize = 3072
+-        data = ''
+-        chunk = fh.read(chunksize)
+-        while chunk:
+-            # we could use chunk.encode('base64') but that throws a newline
+-            # at the end of every output chunk, which increases the size of
+-            # the output.
+-            data = data + base64.b64encode(chunk)
+-            chunk = fh.read(chunksize)
+-        return data
+-
+     def updateattachmentflags(self, bugid, attachid, flagname, **kwargs):
+         '''
+         Updates a flag for the given attachment ID.
+diff --git a/tests/rw_functional.py b/tests/rw_functional.py
+index 1b8997d..82e444f 100644
+--- a/tests/rw_functional.py
++++ b/tests/rw_functional.py
+@@ -357,43 +357,16 @@ class RHPartnerTest(BaseTest):
+             os.chdir("..")
+             os.system("rm -r %s" % tmpdir)
+ 
+-
+     def _test8Attachments(self):
+         """
+         Get and set attachments for a bug
+         """
+         bz = self.bzclass(url=self.url, cookiefile=cf)
+-        getbugid = "663674"
++        getallbugid = "663674"
+         setbugid = "461686"
+-        attachid = "469147"
+         cmd = "bugzilla attach "
+         testfile = "../tests/data/bz-attach-get1.txt"
+ 
+-        # Get first attachment
+-        out = tests.clicomm(cmd + "--get %s" % attachid, bz).splitlines()
+-
+-        # Expect format:
+-        #   Wrote <filename>
+-        fname = out[2].split()[1].strip()
+-
+-        self.assertEquals(len(out), 3)
+-        self.assertEquals(fname, "bugzilla-filename.patch")
+-        self.assertEquals(file(fname).read(),
+-                          file(testfile).read())
+-
+-        # Get all attachments
+-        getbug = bz.getbug(getbugid)
+-        numattach = len(getbug.attachments)
+-        out = tests.clicomm(cmd + "--getall %s" % getbugid, bz).splitlines()
+-
+-        self.assertEquals(len(out), numattach + 2)
+-        fnames = [l.split(" ", 1)[1].strip() for l in out[2:]]
+-        self.assertEquals(len(fnames), numattach)
+-        for f in fnames:
+-            if not os.path.exists(f):
+-                raise AssertionError("filename '%s' not found" % f)
+-            os.unlink(f)
+-
+         # Add attachment as CLI option
+         setbug = bz.getbug(setbugid)
+         orignumattach = len(setbug.attachments)
+@@ -418,6 +391,7 @@ class RHPartnerTest(BaseTest):
+         self.assertEquals(setbug.attachments[-1]["description"], desc2)
+         self.assertEquals(setbug.attachments[-1]["id"],
+                           int(out2.splitlines()[2].split()[2]))
++        attachid = setbug.attachments[-2]["id"]
+ 
+         # Set attachment flags
+         self.assertEquals(setbug.attachments[-1]["flags"], [])
+@@ -435,6 +409,33 @@ class RHPartnerTest(BaseTest):
+         self.assertEquals(setbug.attachments[-1]["flags"], [])
+ 
+ 
++        # Get attachment, verify content
++        out = tests.clicomm(cmd + "--get %s" % attachid, bz).splitlines()
++
++        # Expect format:
++        #   Wrote <filename>
++        fname = out[2].split()[1].strip()
++
++        self.assertEquals(len(out), 3)
++        self.assertEquals(fname, "bz-attach-get1.txt")
++        self.assertEquals(file(fname).read(),
++                          file(testfile).read())
++        os.unlink(fname)
++
++        # Get all attachments
++        getbug = bz.getbug(getallbugid)
++        numattach = len(getbug.attachments)
++        out = tests.clicomm(cmd + "--getall %s" % getallbugid, bz).splitlines()
++
++        self.assertEquals(len(out), numattach + 2)
++        fnames = [l.split(" ", 1)[1].strip() for l in out[2:]]
++        self.assertEquals(len(fnames), numattach)
++        for f in fnames:
++            if not os.path.exists(f):
++                raise AssertionError("filename '%s' not found" % f)
++            os.unlink(f)
++
++
+     def test9Whiteboards(self):
+         bz = self.bzclass(url=self.url, cookiefile=cf)
+         bug_id = "663674"
+-- 
+1.8.1.4
+
diff --git a/python-bugzilla.spec b/python-bugzilla.spec
index deb4455..d1b1654 100644
--- a/python-bugzilla.spec
+++ b/python-bugzilla.spec
@@ -2,7 +2,7 @@
 
 Name:           python-bugzilla
 Version:        0.8.0
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        A python library for interacting with Bugzilla
 
 Group:          Development/Languages
@@ -10,6 +10,9 @@ License:        GPLv2+
 URL:            https://fedorahosted.org/python-bugzilla
 Source0:        https://fedorahosted.org/releases/p/y/%{name}/%{name}-%{version}.tar.gz
 
+# Don't upload scrambled attachments (bz #915318)
+Patch0001: 0001-Fix-uploading-attachments-as-base64-and-test-it.patch
+
 
 BuildArch:      noarch
 BuildRequires:  python-devel
@@ -27,6 +30,9 @@ for interacting with bugzilla from shell scripts.
 %prep
 %setup -q
 
+# Don't upload scrambled attachments (bz #915318)
+%patch0001 -p1
+
 
 %build
 %{__python} setup.py build
@@ -45,6 +51,9 @@ for interacting with bugzilla from shell scripts.
 
 
 %changelog
+* Mon Mar 04 2013 Cole Robinson <crobinso at redhat.com> - 0.8.0-2
+- Don't upload scrambled attachments (bz #915318)
+
 * Fri Feb 15 2013 Cole Robinson <crobinso at redhat.com> - 0.8.0-1
 - Rebased to version 0.8.0
 - Drop most usage of non-upstream RH Bugzilla API


More information about the scm-commits mailing list