Merge lp:~stevenk/launchpad/fixes-bug-451396 into lp:launchpad

Proposed by Steve Kowalik
Status: Merged
Approved by: Steve Kowalik
Approved revision: no longer in the source branch.
Merged at revision: not available
Proposed branch: lp:~stevenk/launchpad/fixes-bug-451396
Merge into: lp:launchpad
Diff against target: 212 lines (+75/-40)
5 files modified
lib/lp/archiveuploader/tests/test_ppauploadprocessor.py (+3/-20)
lib/lp/archiveuploader/tests/test_uploadprocessor.py (+50/-1)
lib/lp/registry/model/distroseries.py (+9/-10)
lib/lp/soyuz/model/publishing.py (+2/-2)
lib/lp/soyuz/model/queue.py (+11/-7)
To merge this branch: bzr merge lp:~stevenk/launchpad/fixes-bug-451396
Reviewer Review Type Date Requested Status
Abel Deuring (community) code Approve
William Grant Pending
Review via email: mp+21706@code.launchpad.net

Commit message

Strips PGP signatures unilaterally, instead of just from PPA uploads, which means users can't download code from the ACCEPTED/REJECTED Ubuntu queue and throw it to the sponsors/uploaders PPA.

Description of the change

This branch strips PGP signatures unilaterally, instead of just from PPA uploads, which means users can't download code from the ACCEPTED/REJECTED Ubuntu queue and throw it to the sponsors/uploaders PPA.

To post a comment you must log in.
Revision history for this message
Abel Deuring (adeuring) wrote :

Hi Steve,

out of curiosity, I reverted the change in lib/lp/soyuz/model/queue.py and then ran "./bin/test -vvt test_uploadprocessor". The result: All tests passed. So, either your test is wrong, or the signature is already stripped elsewhere...

And a few nitpicks:

I think you don't need the super(ThisClass, self).method(...) pattern here. A simple self.method(...) should work fine.

You should include TestUploadProcessorBase in the __all__ list of lib/lp/archiveuploader/tests/test_uploadprocessor.py , because you import this class lib/lp/archiveuploader/tests/test_ppauploadprocessor.py.

Please remove the trailing blank in this line:

+ # Leaving the PGP signature on a package uploaded

review: Needs Fixing
Revision history for this message
Abel Deuring (adeuring) wrote :

Steve,

thanks for you patience with all my complaints. the branch fine now.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/archiveuploader/tests/test_ppauploadprocessor.py'
2--- lib/lp/archiveuploader/tests/test_ppauploadprocessor.py 2010-04-15 17:18:25 +0000
3+++ lib/lp/archiveuploader/tests/test_ppauploadprocessor.py 2010-04-22 16:42:37 +0000
4@@ -682,31 +682,14 @@
5 'https://help.launchpad.net/Packaging/PPA for more information.')
6
7 def testPGPSignatureNotPreserved(self):
8- """PGP signatures should be removed from PPA changesfiles.
9+ """PGP signatures should be removed from PPA .changes files.
10
11- Email notifications and the librarian file for the changesfile should
12+ Email notifications and the librarian file for .changes file should
13 both have the PGP signature removed.
14 """
15 upload_dir = self.queueUpload("bar_1.0-1", "~name16/ubuntu")
16 self.processUpload(self.uploadprocessor, upload_dir)
17-
18- # Check the email.
19- from_addr, to_addrs, raw_msg = stub.test_emails.pop()
20- msg = message_from_string(raw_msg)
21-
22- # This is now a MIMEMultipart message.
23- body = msg.get_payload(0)
24- body = body.get_payload(decode=True)
25-
26- self.assertTrue(
27- "-----BEGIN PGP SIGNED MESSAGE-----" not in body,
28- "Unexpected PGP header found")
29- self.assertTrue(
30- "-----BEGIN PGP SIGNATURE-----" not in body,
31- "Unexpected start of PGP signature found")
32- self.assertTrue(
33- "-----END PGP SIGNATURE-----" not in body,
34- "Unexpected end of PGP signature found")
35+ self.PGPSignatureNotPreserved(archive=self.name16.archive)
36
37 def doCustomUploadToPPA(self):
38 """Helper method to do a custom upload to a PPA.
39
40=== modified file 'lib/lp/archiveuploader/tests/test_uploadprocessor.py'
41--- lib/lp/archiveuploader/tests/test_uploadprocessor.py 2010-02-26 16:52:46 +0000
42+++ lib/lp/archiveuploader/tests/test_uploadprocessor.py 2010-04-22 16:42:37 +0000
43@@ -7,6 +7,7 @@
44 __all__ = [
45 "MockOptions",
46 "MockLogger",
47+ "TestUploadProcessorBase",
48 ]
49
50 import os
51@@ -44,7 +45,8 @@
52 from lp.registry.interfaces.sourcepackage import SourcePackageFileType
53 from lp.soyuz.interfaces.archive import ArchivePurpose, IArchiveSet
54 from lp.soyuz.interfaces.queue import PackageUploadStatus
55-from lp.soyuz.interfaces.publishing import PackagePublishingStatus
56+from lp.soyuz.interfaces.publishing import (
57+ IPublishingSet, PackagePublishingStatus)
58 from lp.soyuz.interfaces.queue import QueueInconsistentStateError
59 from canonical.launchpad.interfaces import ILibraryFileAliasSet
60 from lp.soyuz.interfaces.packageset import IPackagesetSet
61@@ -294,6 +296,29 @@
62 content in body,
63 "Expect: '%s'\nGot:\n%s" % (content, body))
64
65+ def PGPSignatureNotPreserved(self, archive=None):
66+ """PGP signatures should be removed from .changes files.
67+
68+ Email notifications and the librarian file for .changes file should
69+ both have the PGP signature removed.
70+ """
71+ bar = archive.getPublishedSources(
72+ name='bar', version="1.0-1", exact_match=True)
73+ changes_lfa = getUtility(IPublishingSet).getChangesFileLFA(
74+ bar[0].sourcepackagerelease)
75+ changes_file = changes_lfa.read()
76+ self.assertTrue(
77+ "Format: " in changes_file, "Does not look like a changes file")
78+ self.assertTrue(
79+ "-----BEGIN PGP SIGNED MESSAGE-----" not in changes_file,
80+ "Unexpected PGP header found")
81+ self.assertTrue(
82+ "-----BEGIN PGP SIGNATURE-----" not in changes_file,
83+ "Unexpected start of PGP signature found")
84+ self.assertTrue(
85+ "-----END PGP SIGNATURE-----" not in changes_file,
86+ "Unexpected end of PGP signature found")
87+
88
89 class TestUploadProcessor(TestUploadProcessorBase):
90 """Basic tests on uploadprocessor class.
91@@ -1695,6 +1720,30 @@
92 ]
93 self.assertEmail(contents, recipients=recipients)
94
95+ def testPGPSignatureNotPreserved(self):
96+ """PGP signatures should be removed from .changes files.
97+
98+ Email notifications and the librarian file for the .changes file
99+ should both have the PGP signature removed.
100+ """
101+ uploadprocessor = self.setupBreezyAndGetUploadProcessor(
102+ policy='insecure')
103+ upload_dir = self.queueUpload("bar_1.0-1")
104+ self.processUpload(uploadprocessor, upload_dir)
105+ # ACCEPT the upload
106+ queue_items = self.breezy.getQueueItems(
107+ status=PackageUploadStatus.NEW, name="bar",
108+ version="1.0-1", exact_match=True)
109+ self.assertEqual(queue_items.count(), 1)
110+ queue_item = queue_items[0]
111+ queue_item.setAccepted()
112+ pubrec = queue_item.sources[0].publish(self.log)
113+ pubrec.status = PackagePublishingStatus.PUBLISHED
114+ pubrec.datepublished = UTC_NOW
115+ queue_item.setDone()
116+ self.PGPSignatureNotPreserved(archive=self.breezy.main_archive)
117+
118+
119 def test_suite():
120 return unittest.TestLoader().loadTestsFromName(__name__)
121
122
123=== modified file 'lib/lp/registry/model/distroseries.py'
124--- lib/lp/registry/model/distroseries.py 2010-04-09 15:46:09 +0000
125+++ lib/lp/registry/model/distroseries.py 2010-04-22 16:42:37 +0000
126@@ -1391,16 +1391,15 @@
127 # at best, causing unpredictable corruption), and simply pass it
128 # off to the librarian.
129
130- # The PGP signature is stripped from all changesfiles for PPAs
131- # to avoid replay attacks (see bug 159304).
132- if archive.is_ppa:
133- signed_message = signed_message_from_string(changesfilecontent)
134- if signed_message is not None:
135- # Overwrite `changesfilecontent` with the text stripped
136- # of the PGP signature.
137- new_content = signed_message.signedContent
138- if new_content is not None:
139- changesfilecontent = signed_message.signedContent
140+ # The PGP signature is stripped from all changesfiles
141+ # to avoid replay attacks (see bugs 159304 and 451396).
142+ signed_message = signed_message_from_string(changesfilecontent)
143+ if signed_message is not None:
144+ # Overwrite `changesfilecontent` with the text stripped
145+ # of the PGP signature.
146+ new_content = signed_message.signedContent
147+ if new_content is not None:
148+ changesfilecontent = signed_message.signedContent
149
150 changes_file = getUtility(ILibraryFileAliasSet).create(
151 changesfilename, len(changesfilecontent),
152
153=== modified file 'lib/lp/soyuz/model/publishing.py'
154--- lib/lp/soyuz/model/publishing.py 2010-04-12 11:37:48 +0000
155+++ lib/lp/soyuz/model/publishing.py 2010-04-22 16:42:37 +0000
156@@ -1515,8 +1515,8 @@
157 LibraryFileAlias,
158 LibraryFileAlias.id == PackageUpload.changesfileID,
159 PackageUpload.status == PackageUploadStatus.DONE,
160- PackageUpload.distroseriesID == spr.upload_distroseriesID,
161- PackageUpload.archiveID == spr.upload_archiveID,
162+ PackageUpload.distroseriesID == spr.upload_distroseries.id,
163+ PackageUpload.archiveID == spr.upload_archive.id,
164 PackageUpload.id == PackageUploadSource.packageuploadID,
165 PackageUploadSource.sourcepackagereleaseID == spr.id)
166 return result_set.one()
167
168=== modified file 'lib/lp/soyuz/model/queue.py'
169--- lib/lp/soyuz/model/queue.py 2010-04-14 11:45:13 +0000
170+++ lib/lp/soyuz/model/queue.py 2010-04-22 16:42:37 +0000
171@@ -398,9 +398,12 @@
172
173 self.setAccepted()
174 changes_file_object = StringIO.StringIO(self.changesfile.read())
175+ # We explicitly allow unsigned uploads here since the .changes file
176+ # is pulled from the librarian which are stripped of their
177+ # signature just before being stored.
178 self.notify(
179 announce_list=announce_list, logger=logger, dry_run=dry_run,
180- changes_file_object=changes_file_object)
181+ changes_file_object=changes_file_object, allow_unsigned=True)
182 self.syncUpdate()
183
184 # If this is a single source upload we can create the
185@@ -431,9 +434,11 @@
186 """See `IPackageUpload`."""
187 self.setRejected()
188 changes_file_object = StringIO.StringIO(self.changesfile.read())
189+ # We allow unsigned uploads since they come from the librarian,
190+ # which are now stored unsigned.
191 self.notify(
192 logger=logger, dry_run=dry_run,
193- changes_file_object=changes_file_object)
194+ changes_file_object=changes_file_object, allow_unsigned=True)
195 self.syncUpdate()
196
197 @property
198@@ -700,11 +705,10 @@
199 unsigned = allow_unsigned
200 changes = parse_tagfile_lines(changes_lines, allow_unsigned=unsigned)
201
202- if self.isPPA():
203- # Leaving the PGP signature on a package uploaded to a PPA
204- # leaves the possibility of someone hijacking the notification
205- # and uploading to the Ubuntu archive as the signer.
206- changes_lines = self._stripPgpSignature(changes_lines)
207+ # Leaving the PGP signature on a package uploaded
208+ # leaves the possibility of someone hijacking the notification
209+ # and uploading to any archive as the signer.
210+ changes_lines = self._stripPgpSignature(changes_lines)
211
212 return changes, changes_lines
213