Merge lp:~cjwatson/launchpad/fix-check-copy-permissions into lp:launchpad

Proposed by Colin Watson
Status: Merged
Approved by: William Grant
Approved revision: no longer in the source branch.
Merged at revision: 15530
Proposed branch: lp:~cjwatson/launchpad/fix-check-copy-permissions
Merge into: lp:launchpad
Diff against target: 219 lines (+84/-43)
6 files modified
lib/lp/archiveuploader/nascentupload.py (+1/-1)
lib/lp/soyuz/interfaces/queue.py (+1/-1)
lib/lp/soyuz/model/queue.py (+5/-6)
lib/lp/soyuz/scripts/packagecopier.py (+33/-25)
lib/lp/soyuz/tests/test_archive.py (+33/-0)
lib/lp/soyuz/tests/test_packagecopyjob.py (+11/-10)
To merge this branch: bzr merge lp:~cjwatson/launchpad/fix-check-copy-permissions
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+112832@code.launchpad.net

Commit message

Always check copy permissions based on the component in the target archive, not the source archive.

Description of the change

== Summary ==

William Grant pointed out that my change in https://code.launchpad.net/~cjwatson/launchpad/copy-packages-with-default-series/+merge/112557 has incorrect semantics, because it checks the component of the source rather than of the target in the "series is None" (i.e. copy to same series as source) case.

== Proposed fix ==

Check the target component instead. This requires using archive.getPublishedSources; with some care, we can consolidate duplicate code again.

== LOC Rationale ==

+32. Same rationale as https://code.launchpad.net/~cjwatson/launchpad/copy-packages-with-default-series/+merge/112557 - removing delayed copies, which this is part of the road to, is worth at least 1100 lines.

== Tests ==

bin/test -vvct test_archive.TestSyncSource

== Demo and Q/A ==

As https://code.launchpad.net/~cjwatson/launchpad/copy-packages-with-default-series/+merge/112557, but copy into a distribution archive with various permissions. PPA publications are always in main, so the ability to copy a new version of a package in universe with only universe component upload permissions is a good indicator that this is working.

== Lint ==

''Paste output from `make lint` here - if there's lint related to your code, fix it so that you don't have to paste it here!''

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) wrote :

Thanks.

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/nascentupload.py'
2--- lib/lp/archiveuploader/nascentupload.py 2012-06-26 12:25:42 +0000
3+++ lib/lp/archiveuploader/nascentupload.py 2012-07-01 17:22:21 +0000
4@@ -953,7 +953,7 @@
5 sourcepackagerelease = self.changes.dsc.storeInDatabase(build)
6 package_upload_source = self.queue_root.addSource(
7 sourcepackagerelease)
8- ancestry = package_upload_source.getSourceAncestry()
9+ ancestry = package_upload_source.getSourceAncestryForDiffs()
10 if ancestry is not None:
11 to_sourcepackagerelease = ancestry.sourcepackagerelease
12 diff = to_sourcepackagerelease.requestDiffTo(
13
14=== modified file 'lib/lp/soyuz/interfaces/queue.py'
15--- lib/lp/soyuz/interfaces/queue.py 2012-05-30 08:50:50 +0000
16+++ lib/lp/soyuz/interfaces/queue.py 2012-07-01 17:22:21 +0000
17@@ -426,7 +426,7 @@
18 readonly=False,
19 )
20
21- def getSourceAncestry():
22+ def getSourceAncestryForDiffs():
23 """Return a suitable ancestry publication for this context.
24
25 The possible ancestries locations for a give source upload, assuming
26
27=== modified file 'lib/lp/soyuz/model/queue.py'
28--- lib/lp/soyuz/model/queue.py 2012-06-19 03:26:57 +0000
29+++ lib/lp/soyuz/model/queue.py 2012-07-01 17:22:21 +0000
30@@ -1091,7 +1091,7 @@
31 dbName='sourcepackagerelease',
32 foreignKey='SourcePackageRelease')
33
34- def getSourceAncestry(self):
35+ def getSourceAncestryForDiffs(self):
36 """See `IPackageUploadSource`."""
37 primary_archive = self.packageupload.distroseries.main_archive
38 release_pocket = PackagePublishingPocket.RELEASE
39@@ -1103,18 +1103,17 @@
40 (primary_archive, None, release_pocket),
41 ]
42
43- ancestry = None
44 for archive, distroseries, pocket in ancestry_locations:
45 ancestries = archive.getPublishedSources(
46 name=self.sourcepackagerelease.name,
47 distroseries=distroseries, pocket=pocket,
48 exact_match=True)
49 try:
50- ancestry = ancestries[0]
51+ return ancestries[0]
52 except IndexError:
53- continue
54- break
55- return ancestry
56+ pass
57+
58+ return None
59
60 def verifyBeforeAccept(self):
61 """See `IPackageUploadSource`."""
62
63=== modified file 'lib/lp/soyuz/scripts/packagecopier.py'
64--- lib/lp/soyuz/scripts/packagecopier.py 2012-06-29 01:03:10 +0000
65+++ lib/lp/soyuz/scripts/packagecopier.py 2012-07-01 17:22:21 +0000
66@@ -16,6 +16,7 @@
67 'update_files_privacy',
68 ]
69
70+from itertools import repeat
71 from operator import attrgetter
72 import os
73 import tempfile
74@@ -231,34 +232,41 @@
75 # the destination (archive, component, pocket). This check is done
76 # here rather than in the security adapter because it requires more
77 # info than is available in the security adapter.
78+ sourcepackagenames = [
79+ source.sourcepackagerelease.sourcepackagename for source in sources]
80 if series is None:
81 # Use each source's series as the destination for that source.
82- for source in sources:
83- reason = archive.checkUpload(
84- person, source.distroseries,
85- source.sourcepackagerelease.sourcepackagename,
86- source.component, pocket, strict_component=True)
87-
88- if reason is not None:
89- raise CannotCopy(reason)
90+ series_iter = map(attrgetter("distroseries"), sources)
91 else:
92- sourcepackagenames = [
93- source.sourcepackagerelease.sourcepackagename
94- for source in sources]
95- for spn in set(sourcepackagenames):
96- package = series.getSourcePackage(spn)
97- destination_component = package.latest_published_component
98-
99- # If destination_component is not None, make sure the person
100- # has upload permission for this component. Otherwise, any
101- # upload permission on this archive will do.
102- strict_component = destination_component is not None
103- reason = archive.checkUpload(
104- person, series, spn, destination_component, pocket,
105- strict_component=strict_component)
106-
107- if reason is not None:
108- raise CannotCopy(reason)
109+ series_iter = repeat(series)
110+ for spn, dest_series in set(zip(sourcepackagenames, series_iter)):
111+ # XXX cjwatson 20120630: We should do a proper ancestry check
112+ # instead of simply querying for publications in any pocket.
113+ # Unfortunately there are currently at least three different
114+ # implementations of ancestry lookup:
115+ # NascentUpload.getSourceAncestry,
116+ # PackageUploadSource.getSourceAncestryForDiffs, and
117+ # PublishingSet.getNearestAncestor, none of which is obviously
118+ # correct here. Instead of adding a fourth, we should consolidate
119+ # these.
120+ ancestries = archive.getPublishedSources(
121+ name=spn.name, exact_match=True, status=active_publishing_status,
122+ distroseries=dest_series)
123+ try:
124+ destination_component = ancestries[0].component
125+ except IndexError:
126+ destination_component = None
127+
128+ # If destination_component is not None, make sure the person
129+ # has upload permission for this component. Otherwise, any
130+ # upload permission on this archive will do.
131+ strict_component = destination_component is not None
132+ reason = archive.checkUpload(
133+ person, dest_series, spn, destination_component, pocket,
134+ strict_component=strict_component)
135+
136+ if reason is not None:
137+ raise CannotCopy(reason)
138
139
140 class CopyChecker:
141
142=== modified file 'lib/lp/soyuz/tests/test_archive.py'
143--- lib/lp/soyuz/tests/test_archive.py 2012-06-28 12:21:01 +0000
144+++ lib/lp/soyuz/tests/test_archive.py 2012-07-01 17:22:21 +0000
145@@ -2548,6 +2548,39 @@
146 [source.distroseries for source in sources],
147 [copy_job.target_distroseries for copy_job in copy_jobs])
148
149+ def test_copyPackages_with_default_distroseries_and_override(self):
150+ # If to_series is None, copyPackages checks permissions based on the
151+ # component in the target archive, not the component in the source
152+ # archive.
153+ (source, source_archive, source_name, target_archive, to_pocket,
154+ to_series, version) = self._setup_copy_data(
155+ target_purpose=ArchivePurpose.PRIMARY)
156+ sources = [source]
157+ uploader = self.factory.makePerson()
158+ main = self.factory.makeComponent(name="main")
159+ universe = self.factory.makeComponent(name="universe")
160+ ComponentSelection(distroseries=to_series, component=main)
161+ ComponentSelection(distroseries=to_series, component=universe)
162+ with person_logged_in(target_archive.owner):
163+ target_archive.newComponentUploader(uploader, universe)
164+ self.factory.makeSourcePackagePublishingHistory(
165+ distroseries=source.distroseries, archive=target_archive,
166+ pocket=to_pocket, status=PackagePublishingStatus.PUBLISHED,
167+ sourcepackagename=source_name, version="%s~1" % version,
168+ component=universe)
169+ names = [source.sourcepackagerelease.sourcepackagename.name
170+ for source in sources]
171+
172+ with person_logged_in(uploader):
173+ target_archive.copyPackages(
174+ names, source_archive, to_pocket.name, include_binaries=False,
175+ person=uploader)
176+
177+ # There should be a copy job with the correct target series.
178+ job_source = getUtility(IPlainPackageCopyJobSource)
179+ copy_job = job_source.getActiveJobs(target_archive).one()
180+ self.assertEqual(source.distroseries, copy_job.target_distroseries)
181+
182
183 class TestgetAllPublishedBinaries(TestCaseWithFactory):
184
185
186=== modified file 'lib/lp/soyuz/tests/test_packagecopyjob.py'
187--- lib/lp/soyuz/tests/test_packagecopyjob.py 2012-06-28 12:21:01 +0000
188+++ lib/lp/soyuz/tests/test_packagecopyjob.py 2012-07-01 17:22:21 +0000
189@@ -1030,19 +1030,20 @@
190 spr.changelog = self.factory.makeLibraryFileAlias(content=changelog)
191 spr.changelog_entry = "dummy"
192 self.layer.txn.commit() # Librarian.
193+
194+ # Now put the same named package in the target archive at the
195+ # oldest version in the changelog.
196+ target_source_pub = self.publisher.getPubSource(
197+ distroseries=self.distroseries, sourcename="libc",
198+ version="2.8-0", status=PackagePublishingStatus.PUBLISHED,
199+ archive=target_archive)
200+
201 bugtask280 = self.factory.makeBugTask(
202- target=spr.sourcepackage, bug=bug280)
203+ target=spr.sourcepackage, bug=bug280, publish=False)
204 bugtask281 = self.factory.makeBugTask(
205- target=spr.sourcepackage, bug=bug281)
206+ target=spr.sourcepackage, bug=bug281, publish=False)
207 bugtask282 = self.factory.makeBugTask(
208- target=spr.sourcepackage, bug=bug282)
209-
210- # Now put the same named package in the target archive at the
211- # oldest version in the changelog.
212- self.publisher.getPubSource(
213- distroseries=self.distroseries, sourcename="libc",
214- version="2.8-0", status=PackagePublishingStatus.PUBLISHED,
215- archive=target_archive)
216+ target=spr.sourcepackage, bug=bug282, publish=False)
217
218 # Run the copy job.
219 requester = self.factory.makePerson()