← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~flacoste/launchpad/bug-365098 into lp:launchpad

 

Francis J. Lacoste has proposed merging lp:~flacoste/launchpad/bug-365098 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~flacoste/launchpad/bug-365098/+merge/63305

= Summary =

We want to use regular distribution objects to coordinate the Ensemble
Principia collections. (https://launchpad.net/principia) In this context,
each source package represent an Ensemble formula which can have a dedicated
community, bug tracker, code branches, etc. There are a couple of bugs to fix
in Launchpad to make this experience as smooth as possible.

The first hurdle I encountered was that only Ubuntu-branches are allowed to
set the official package branch for a source package. Bug 365098 captured that
limitation.

== Proposed fix ==

Anyone who can upload the source package to the distribution should be able to
set the official branch for the package.

== Pre-implementation notes ==

I discussed this changes with Robert who said that this wouldn't introduce any
performance problems. I also validated the new policy with the tech-board and
James Westby (who was the only non-tech board member part of Ubuntu Branches).
Following the package upload rules here will allow the package-importer (the
script managing UDD branches for Ubuntu) to continue working without any
changes.

== Implementation details ==

This branch is slightly above the line limit, but you'll please to know that
it's more than 50% code removal! (There was also a bunch of lint fixes, that I
should have refrained from doing before review. Sorry about that.)

ISourcePackage.setBranch is the public API to change the official package
branch. So I defined a launchpad.Edit security adapter to implement the
correct policy (using the Soyuz IArchive.checkUpload API to check 
upload permission.)

To protect setBranch using that permission, I had to split the ISourcePackage
into a ISourcePackagePublic and ISourcePackageEdit interface (a pattern used
in several places).

New tests for the permission change are in
test_sourcepackage.TestSourcePackageSecurity

The Ubuntu Branches policy was implemented by a security adapter over the
IMakeOfficialBranchLinks utility. I nuked those as well as removed the
definition of that utility. Tests and setBranch use the
SeriesSourcePackageBranchSet directly for the implementation. This allowed me
to simplify a bunch of tests.

I added some readonly=True for expliciteness on fields that aren't meant to be
changed over API.

SourcePackage provides a __hash__ method which uses the sourcepackagename and
distroseries ID. It caused a weird failure during permission checking when
storm flush are blocked and the object is inserted into the security check
cache. Saving the IDs of the object and using that instead of traversing the
storm objects solved the issue.

== Tests ==

 test.py -vvt 'test_sourcepackage|test_seriessourcepackagebranch|test_branchlisting'


== Demo and Q/A ==

I'll QA this by validating that the package importer can still set official
package branches on Ubuntu and by setting official package branches on
principia formula.


= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/code/configure.zcml
  database/sampledata/current.sql
  database/sampledata/current-dev.sql
  lib/lp/registry/interfaces/role.py
  lib/canonical/launchpad/security.py
  lib/lp/code/tests/test_seriessourcepackagebranch.py
  lib/lp/code/tests/helpers.py
  lib/lp/code/browser/tests/test_branchlisting.py
  lib/lp/registry/configure.zcml
  lib/lp/registry/interfaces/sourcepackage.py
  lib/lp/registry/tests/test_sourcepackage.py
  lib/lp/code/model/seriessourcepackagebranch.py
  lib/lp/registry/model/sourcepackage.py
  lib/lp/code/interfaces/seriessourcepackagebranch.py
  lib/canonical/launchpad/interfaces/_schema_circular_imports.py
  lib/lp/app/utilities/celebrities.py
-- 
https://code.launchpad.net/~flacoste/launchpad/bug-365098/+merge/63305
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~flacoste/launchpad/bug-365098 into lp:launchpad.
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql	2011-05-04 16:46:43 +0000
+++ database/sampledata/current-dev.sql	2011-06-02 21:49:29 +0000
@@ -843,6 +843,9 @@
 
 
 
+
+
+
 SET SESSION AUTHORIZATION DEFAULT;
 
 ALTER TABLE account DISABLE TRIGGER ALL;
@@ -1828,8 +1831,6 @@
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243624, 'Commercial Subscription Approvers', 243623, NULL, 'commercial-approvers', NULL, NULL, NULL, NULL, 1, NULL, '2008-06-27 14:49:38.676264', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243625, 'PPA key guard', NULL, NULL, 'ppa-key-guard', NULL, NULL, NULL, NULL, 1, NULL, '2008-11-04 12:59:26.965843', NULL, NULL, NULL, true, 1, '', NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436241);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243626, 'Launchpad Users', 12, NULL, 'launchpad-users', NULL, NULL, NULL, NULL, 2, NULL, '2008-11-26 18:19:53.547918', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
-INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243627, 'Ubuntu-branches-owner', NULL, NULL, 'ubuntu-branches-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-03-17 07:26:14.024613', NULL, NULL, NULL, false, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436242);
-INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243628, 'Ubuntu branches', 243627, 'Celebrity team that controls official source package branches.', 'ubuntu-branches', NULL, NULL, NULL, NULL, 3, NULL, '2009-03-17 07:27:39.306182', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243629, 'Ubuntu Security Team', 4, NULL, 'ubuntu-security', NULL, NULL, NULL, NULL, 2, NULL, '2009-07-14 20:23:59.698654', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243630, 'HWDB Team', 16, NULL, 'hwdb-team', NULL, NULL, NULL, NULL, 3, NULL, '2009-07-09 09:12:39.400351', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243631, 'Techboard Owner', NULL, NULL, 'techboard-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-08-04 10:50:39.370018', NULL, NULL, NULL, true, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436243);
@@ -3800,6 +3801,13 @@
 ALTER TABLE bugsubscriptionfilterimportance ENABLE TRIGGER ALL;
 
 
+ALTER TABLE bugsubscriptionfiltermute DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE bugsubscriptionfiltermute ENABLE TRIGGER ALL;
+
+
 ALTER TABLE bugsubscriptionfilterstatus DISABLE TRIGGER ALL;
 
 
@@ -4236,6 +4244,13 @@
 ALTER TABLE distroseriespackagecache ENABLE TRIGGER ALL;
 
 
+ALTER TABLE distroseriesparent DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE distroseriesparent ENABLE TRIGGER ALL;
+
+
 ALTER TABLE emailaddress DISABLE TRIGGER ALL;
 
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (1, 'mark@xxxxxxxxxxx', 1, 4, '2006-10-16 18:31:43.540582', 11);
@@ -4316,7 +4331,6 @@
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (78, 'bac@xxxxxxxxxxxxx', 243623, 4, '2008-06-27 14:49:11.149508', 2436231);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (79, 'admin@xxxxxxxxxxxxx', 16, 2, '2008-08-05 12:01:32.086327', 161);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (80, 'ppa-key-guard@xxxxxxxxxxxxx', 243625, 4, '2008-11-04 12:59:26.965843', 2436241);
-INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (81, 'ubuntu-branches-owner@xxxxxxxxxxx', 243627, 4, '2009-03-17 07:26:14.024613', 2436242);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (82, 'techboard-owner@xxxxxxxxxxx', 243631, 4, '2009-08-04 10:50:39.383407', 2436243);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (93, 'software-center-agent@xxxxxxxxxxx', 243651, 4, '2010-07-12 09:48:27.198885', 243637);
 
@@ -5271,8 +5285,6 @@
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243624, 'Commercial Subscription Approvers', 243623, NULL, 'commercial-approvers', NULL, NULL, NULL, NULL, 1, NULL, '2008-06-27 14:49:38.676264', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243625, 'PPA key guard', NULL, NULL, 'ppa-key-guard', NULL, NULL, NULL, NULL, 1, NULL, '2008-11-04 12:59:26.965843', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 1, '', NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436241);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243626, 'Launchpad Users', 12, NULL, 'launchpad-users', NULL, NULL, NULL, NULL, 2, NULL, '2008-11-26 18:19:53.547918', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
-INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243627, 'Ubuntu-branches-owner', NULL, NULL, 'ubuntu-branches-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-03-17 07:26:14.024613', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436242);
-INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243628, 'Ubuntu branches', 243627, 'Celebrity team that controls official source package branches.', 'ubuntu-branches', NULL, NULL, NULL, NULL, 3, NULL, '2009-03-17 07:27:39.306182', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243629, 'Ubuntu Security Team', 4, NULL, 'ubuntu-security', NULL, NULL, NULL, NULL, 2, NULL, '2009-07-14 20:23:59.698654', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243630, 'HWDB Team', 16, NULL, 'hwdb-team', NULL, NULL, NULL, NULL, 3, NULL, '2009-07-09 09:12:39.400351', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243631, 'Techboard Owner', NULL, NULL, 'techboard-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-08-04 10:50:39.370018', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436243);

=== modified file 'database/sampledata/current.sql'
--- database/sampledata/current.sql	2011-05-04 16:46:43 +0000
+++ database/sampledata/current.sql	2011-06-02 21:49:29 +0000
@@ -843,6 +843,9 @@
 
 
 
+
+
+
 SET SESSION AUTHORIZATION DEFAULT;
 
 ALTER TABLE account DISABLE TRIGGER ALL;
@@ -1828,8 +1831,6 @@
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243624, 'Commercial Subscription Approvers', 243623, NULL, 'commercial-approvers', NULL, NULL, NULL, NULL, 1, NULL, '2008-06-27 14:49:38.676264', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243625, 'PPA key guard', NULL, NULL, 'ppa-key-guard', NULL, NULL, NULL, NULL, 1, NULL, '2008-11-04 12:59:26.965843', NULL, NULL, NULL, true, 1, '', NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436241);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243626, 'Launchpad Users', 12, NULL, 'launchpad-users', NULL, NULL, NULL, NULL, 2, NULL, '2008-11-26 18:19:53.547918', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
-INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243627, 'Ubuntu-branches-owner', NULL, NULL, 'ubuntu-branches-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-03-17 07:26:14.024613', NULL, NULL, NULL, false, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436242);
-INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243628, 'Ubuntu branches', 243627, 'Celebrity team that controls official source package branches.', 'ubuntu-branches', NULL, NULL, NULL, NULL, 3, NULL, '2009-03-17 07:27:39.306182', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243629, 'Ubuntu Security Team', 4, NULL, 'ubuntu-security', NULL, NULL, NULL, NULL, 2, NULL, '2009-07-14 20:23:59.698654', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243630, 'HWDB Team', 16, NULL, 'hwdb-team', NULL, NULL, NULL, NULL, 3, NULL, '2009-07-09 09:12:39.400351', NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243631, 'Techboard Owner', NULL, NULL, 'techboard-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-08-04 10:50:39.370018', NULL, NULL, NULL, true, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436243);
@@ -3736,6 +3737,13 @@
 ALTER TABLE bugsubscriptionfilterimportance ENABLE TRIGGER ALL;
 
 
+ALTER TABLE bugsubscriptionfiltermute DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE bugsubscriptionfiltermute ENABLE TRIGGER ALL;
+
+
 ALTER TABLE bugsubscriptionfilterstatus DISABLE TRIGGER ALL;
 
 
@@ -4169,6 +4177,13 @@
 ALTER TABLE distroseriespackagecache ENABLE TRIGGER ALL;
 
 
+ALTER TABLE distroseriesparent DISABLE TRIGGER ALL;
+
+
+
+ALTER TABLE distroseriesparent ENABLE TRIGGER ALL;
+
+
 ALTER TABLE emailaddress DISABLE TRIGGER ALL;
 
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (1, 'mark@xxxxxxxxxxx', 1, 4, '2006-10-16 18:31:43.540582', 11);
@@ -4249,7 +4264,6 @@
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (78, 'bac@xxxxxxxxxxxxx', 243623, 4, '2008-06-27 14:49:11.149508', 2436231);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (79, 'admin@xxxxxxxxxxxxx', 16, 2, '2008-08-05 12:01:32.086327', 161);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (80, 'ppa-key-guard@xxxxxxxxxxxxx', 243625, 4, '2008-11-04 12:59:26.965843', 2436241);
-INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (81, 'ubuntu-branches-owner@xxxxxxxxxxx', 243627, 4, '2009-03-17 07:26:14.024613', 2436242);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (82, 'techboard-owner@xxxxxxxxxxx', 243631, 4, '2009-08-04 10:50:39.383407', 2436243);
 INSERT INTO emailaddress (id, email, person, status, date_created, account) VALUES (93, 'software-center-agent@xxxxxxxxxxx', 243651, 4, '2010-07-12 09:48:27.198885', 243637);
 
@@ -5203,8 +5217,6 @@
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243624, 'Commercial Subscription Approvers', 243623, NULL, 'commercial-approvers', NULL, NULL, NULL, NULL, 1, NULL, '2008-06-27 14:49:38.676264', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243625, 'PPA key guard', NULL, NULL, 'ppa-key-guard', NULL, NULL, NULL, NULL, 1, NULL, '2008-11-04 12:59:26.965843', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 1, '', NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436241);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243626, 'Launchpad Users', 12, NULL, 'launchpad-users', NULL, NULL, NULL, NULL, 2, NULL, '2008-11-26 18:19:53.547918', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
-INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243627, 'Ubuntu-branches-owner', NULL, NULL, 'ubuntu-branches-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-03-17 07:26:14.024613', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436242);
-INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243628, 'Ubuntu branches', 243627, 'Celebrity team that controls official source package branches.', 'ubuntu-branches', NULL, NULL, NULL, NULL, 3, NULL, '2009-03-17 07:27:39.306182', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243629, 'Ubuntu Security Team', 4, NULL, 'ubuntu-security', NULL, NULL, NULL, NULL, 2, NULL, '2009-07-14 20:23:59.698654', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243630, 'HWDB Team', 16, NULL, 'hwdb-team', NULL, NULL, NULL, NULL, 3, NULL, '2009-07-09 09:12:39.400351', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, false, NULL, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, NULL);
 INSERT INTO lp_person (id, displayname, teamowner, teamdescription, name, language, fti, defaultmembershipperiod, defaultrenewalperiod, subscriptionpolicy, merged, datecreated, addressline1, addressline2, organization, city, province, country, postcode, phone, homepage_content, icon, mugshot, hide_email_addresses, creation_rationale, creation_comment, registrant, logo, renewal_policy, personal_standing, personal_standing_reason, mail_resumption_date, mailing_list_auto_subscribe_policy, mailing_list_receive_duplicates, visibility, verbose_bugnotifications, account) VALUES (243631, 'Techboard Owner', NULL, NULL, 'techboard-owner', NULL, NULL, NULL, NULL, 1, NULL, '2009-08-04 10:50:39.370018', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 1, NULL, NULL, NULL, 10, 0, NULL, NULL, 1, true, 1, true, 2436243);

=== modified file 'lib/canonical/launchpad/interfaces/_schema_circular_imports.py'
--- lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-05-17 14:27:34 +0000
+++ lib/canonical/launchpad/interfaces/_schema_circular_imports.py	2011-06-02 21:49:29 +0000
@@ -160,7 +160,11 @@
     IProjectGroup,
     IProjectGroupSet,
     )
-from lp.registry.interfaces.sourcepackage import ISourcePackage
+from lp.registry.interfaces.sourcepackage import (
+    ISourcePackage,
+    ISourcePackageEdit,
+    ISourcePackagePublic,
+    )
 from lp.registry.interfaces.ssh import ISSHKey
 from lp.registry.interfaces.teammembership import ITeamMembership
 from lp.registry.interfaces.wikiname import IWikiName
@@ -226,9 +230,9 @@
 IBranch['landing_candidates'].value_type.schema = IBranchMergeProposal
 IBranch['landing_targets'].value_type.schema = IBranchMergeProposal
 IBranch['linkBug'].queryTaggedValue(
-    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema= IBug
+    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema = IBug
 IBranch['linkSpecification'].queryTaggedValue(
-    LAZR_WEBSERVICE_EXPORTED)['params']['spec'].schema= ISpecification
+    LAZR_WEBSERVICE_EXPORTED)['params']['spec'].schema = ISpecification
 IBranch['product'].schema = IProduct
 
 patch_plain_parameter_type(
@@ -243,9 +247,9 @@
     LAZR_WEBSERVICE_EXPORTED)['return_type'].schema = IBranchSubscription
 IBranch['subscriptions'].value_type.schema = IBranchSubscription
 IBranch['unlinkBug'].queryTaggedValue(
-    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema= IBug
+    LAZR_WEBSERVICE_EXPORTED)['params']['bug'].schema = IBug
 IBranch['unlinkSpecification'].queryTaggedValue(
-    LAZR_WEBSERVICE_EXPORTED)['params']['spec'].schema= ISpecification
+    LAZR_WEBSERVICE_EXPORTED)['params']['spec'].schema = ISpecification
 
 patch_entry_return_type(IBranch, '_createMergeProposal', IBranchMergeProposal)
 patch_plain_parameter_type(
@@ -316,17 +320,17 @@
     LAZR_WEBSERVICE_EXPORTED)[
         'return_type'].value_type.schema = IBinaryPackageBuild
 
-ISourcePackage['distroseries'].schema = IDistroSeries
-ISourcePackage['productseries'].schema = IProductSeries
-ISourcePackage['getBranch'].queryTaggedValue(
+ISourcePackagePublic['distroseries'].schema = IDistroSeries
+ISourcePackagePublic['productseries'].schema = IProductSeries
+ISourcePackagePublic['getBranch'].queryTaggedValue(
     LAZR_WEBSERVICE_EXPORTED)[
         'params']['pocket'].vocabulary = PackagePublishingPocket
-ISourcePackage['getBranch'].queryTaggedValue(
+ISourcePackagePublic['getBranch'].queryTaggedValue(
     LAZR_WEBSERVICE_EXPORTED)['return_type'].schema = IBranch
-ISourcePackage['setBranch'].queryTaggedValue(
+ISourcePackageEdit['setBranch'].queryTaggedValue(
     LAZR_WEBSERVICE_EXPORTED)[
         'params']['pocket'].vocabulary = PackagePublishingPocket
-ISourcePackage['setBranch'].queryTaggedValue(
+ISourcePackageEdit['setBranch'].queryTaggedValue(
     LAZR_WEBSERVICE_EXPORTED)['params']['branch'].schema = IBranch
 patch_reference_property(ISourcePackage, 'distribution', IDistribution)
 

=== modified file 'lib/canonical/launchpad/security.py'
--- lib/canonical/launchpad/security.py	2011-05-27 21:12:25 +0000
+++ lib/canonical/launchpad/security.py	2011-06-02 21:49:29 +0000
@@ -79,10 +79,6 @@
     )
 from lp.code.interfaces.codereviewvote import ICodeReviewVoteReference
 from lp.code.interfaces.diff import IPreviewDiff
-from lp.code.interfaces.seriessourcepackagebranch import (
-    IMakeOfficialBranchLinks,
-    ISeriesSourcePackageBranch,
-    )
 from lp.code.interfaces.sourcepackagerecipe import ISourcePackageRecipe
 from lp.code.interfaces.sourcepackagerecipebuild import (
     ISourcePackageRecipeBuild,
@@ -122,6 +118,7 @@
     INameBlacklistSet,
     )
 from lp.registry.interfaces.packaging import IPackaging
+from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.person import (
     IPerson,
     IPersonSet,
@@ -2505,38 +2502,6 @@
         return user.in_admin or user.in_ubuntu_techboard
 
 
-class LinkOfficialSourcePackageBranches(AuthorizationBase):
-    """Who can source packages to their official branches?
-
-    Only members of the ~ubuntu-branches celebrity team! Or admins.
-    """
-
-    permission = 'launchpad.Edit'
-    usedfor = IMakeOfficialBranchLinks
-
-    def checkUnauthenticated(self):
-        return False
-
-    def checkAuthenticated(self, user):
-        return user.in_ubuntu_branches or user.in_admin
-
-
-class ChangeOfficialSourcePackageBranchLinks(AuthorizationBase):
-    """Who can change the links from source packages to their branches?
-
-    Only members of the ~ubuntu-branches celebrity team! Or admins.
-    """
-
-    permission = 'launchpad.Edit'
-    usedfor = ISeriesSourcePackageBranch
-
-    def checkUnauthenticated(self):
-        return False
-
-    def checkAuthenticated(self, user):
-        return user.in_ubuntu_branches or user.in_admin
-
-
 class ViewPackageset(AnonymousAuthorization):
     """Anyone can view an IPackageset."""
     usedfor = IPackageset
@@ -2611,3 +2576,25 @@
 
 class ViewPublisherConfig(AdminByAdminsTeam):
     usedfor = IPublisherConfig
+
+
+class EditSourcePackage(AuthorizationBase):
+    permission = 'launchpad.Edit'
+    usedfor = ISourcePackage
+
+    def checkAuthenticated(self, user):
+        """Anyone who can upload a package can edit it."""
+        if user.in_admin:
+            return True
+
+        distribution = self.obj.distribution
+        if user.inTeam(distribution.owner):
+            return True
+
+        # checkUpload() returns the reason the user can't upload
+        # or None if they are allowed.
+        reason = distribution.main_archive.checkUpload(
+            user.person, self.obj.distroseries, self.obj.sourcepackagename,
+            component=None, pocket=PackagePublishingPocket.RELEASE,
+            strict_component=False)
+        return reason is None

=== modified file 'lib/lp/app/utilities/celebrities.py'
--- lib/lp/app/utilities/celebrities.py	2011-05-27 21:12:25 +0000
+++ lib/lp/app/utilities/celebrities.py	2011-06-02 21:49:29 +0000
@@ -101,7 +101,7 @@
     This descriptor maintains a list of names so code can detect
     if a given person is a celebrity for special handling.
     """
-    names = set() # Populated by the constructor.
+    names = set()  # Populated by the constructor.
 
     def __init__(self, name):
         PersonCelebrityDescriptor.names.add(name)
@@ -153,7 +153,6 @@
     savannah_tracker = CelebrityDescriptor(IBugTrackerSet, 'savannah')
     sourceforge_tracker = CelebrityDescriptor(IBugTrackerSet, 'sf')
     ubuntu = CelebrityDescriptor(IDistributionSet, 'ubuntu')
-    ubuntu_branches = PersonCelebrityDescriptor('ubuntu-branches')
     ubuntu_bugzilla = CelebrityDescriptor(IBugTrackerSet, 'ubuntu-bugzilla')
     ubuntu_security = PersonCelebrityDescriptor('ubuntu-security')
     ubuntu_techboard = PersonCelebrityDescriptor('techboard')

=== modified file 'lib/lp/code/browser/tests/test_branchlisting.py'
--- lib/lp/code/browser/tests/test_branchlisting.py	2010-10-26 15:47:24 +0000
+++ lib/lp/code/browser/tests/test_branchlisting.py	2011-06-02 21:49:29 +0000
@@ -16,7 +16,6 @@
     Desc,
     )
 from zope.component import getUtility
-from zope.security.proxy import removeSecurityProxy
 
 from canonical.launchpad.testing.pages import (
     extract_text,
@@ -32,8 +31,8 @@
     SourcePackageBranchesView,
     )
 from lp.code.enums import BranchVisibilityRule
-from lp.code.interfaces.seriessourcepackagebranch import (
-    IMakeOfficialBranchLinks,
+from lp.code.model.seriessourcepackagebranch import (
+    SeriesSourcePackageBranchSet,
     )
 from lp.code.model.branch import Branch
 from lp.registry.interfaces.person import (
@@ -270,15 +269,12 @@
             for i in range(branch_count)]
 
         official = []
-        # We don't care about who can make things official, so get rid of the
-        # security proxy.
-        series_set = removeSecurityProxy(getUtility(IMakeOfficialBranchLinks))
         # Sort the pocket items so RELEASE is last, and thus first popped.
         pockets = sorted(PackagePublishingPocket.items, reverse=True)
         for i in range(official_count):
             branch = branches.pop()
             pocket = pockets.pop()
-            sspb = series_set.new(
+            SeriesSourcePackageBranchSet.new(
                 distroseries, pocket, self.sourcepackagename,
                 branch, branch.owner)
             official.append(branch)
@@ -354,8 +350,7 @@
     def test_package_development_focus(self):
         # Check the bzr_identity of a development focus package branch.
         branch = self.factory.makePackageBranch()
-        series_set = removeSecurityProxy(getUtility(IMakeOfficialBranchLinks))
-        sspb = series_set.new(
+        SeriesSourcePackageBranchSet.new(
             branch.distroseries, PackagePublishingPocket.RELEASE,
             branch.sourcepackagename, branch, branch.owner)
         identity = "lp://dev/%s/%s" % (

=== modified file 'lib/lp/code/configure.zcml'
--- lib/lp/code/configure.zcml	2011-05-13 16:08:03 +0000
+++ lib/lp/code/configure.zcml	2011-06-02 21:49:29 +0000
@@ -398,21 +398,10 @@
   <class
       class="lp.code.model.seriessourcepackagebranch.SeriesSourcePackageBranch">
     <allow interface="lp.code.interfaces.seriessourcepackagebranch.ISeriesSourcePackageBranch"/>
-    <require
-        permission="launchpad.Edit"
-        set_schema="lp.code.interfaces.seriessourcepackagebranch.ISeriesSourcePackageBranch"/>
   </class>
 
   <securedutility
      class="lp.code.model.seriessourcepackagebranch.SeriesSourcePackageBranchSet"
-     provides="lp.code.interfaces.seriessourcepackagebranch.IMakeOfficialBranchLinks">
-    <allow interface="lp.code.interfaces.seriessourcepackagebranch.IMakeOfficialBranchLinks"/>
-    <require
-       permission="launchpad.Edit"
-       interface="lp.code.interfaces.seriessourcepackagebranch.IMakeOfficialBranchLinks"/>
-  </securedutility>
-  <securedutility
-     class="lp.code.model.seriessourcepackagebranch.SeriesSourcePackageBranchSet"
      provides="lp.code.interfaces.seriessourcepackagebranch.IFindOfficialBranchLinks">
     <allow interface="lp.code.interfaces.seriessourcepackagebranch.IFindOfficialBranchLinks"/>
   </securedutility>

=== modified file 'lib/lp/code/interfaces/seriessourcepackagebranch.py'
--- lib/lp/code/interfaces/seriessourcepackagebranch.py	2011-03-03 01:13:47 +0000
+++ lib/lp/code/interfaces/seriessourcepackagebranch.py	2011-06-02 21:49:29 +0000
@@ -9,7 +9,6 @@
 __all__ = [
     'IFindOfficialBranchLinks',
     'ISeriesSourcePackageBranch',
-    'IMakeOfficialBranchLinks',
     ]
 
 
@@ -33,17 +32,20 @@
     id = Int()
 
     distroseries = Choice(
-        title=_("Series"), required=True, vocabulary='DistroSeries')
+        title=_("Series"), required=True, readonly=True,
+        vocabulary='DistroSeries')
 
     pocket = Choice(
-        title=_("Pocket"), required=True, vocabulary=PackagePublishingPocket)
+        title=_("Pocket"), required=True, readonly=True,
+        vocabulary=PackagePublishingPocket)
 
     sourcepackage = Attribute('The source package')
 
     suite_sourcepackage = Attribute('The suite source package')
 
     sourcepackagename = Choice(
-        title=_("Package"), required=True, vocabulary='SourcePackageName')
+        title=_("Package"), required=True,
+        readonly=True, vocabulary='SourcePackageName')
 
     branchID = Attribute('The ID of the branch.')
     branch = Choice(
@@ -52,7 +54,8 @@
     registrant = Attribute("The person who registered this link.")
 
     date_created = Datetime(
-        title=_("When the branch was linked to the distribution suite."))
+        title=_("When the branch was linked to the distribution suite."),
+        readonly=True)
 
 
 class IFindOfficialBranchLinks(Interface):
@@ -86,22 +89,3 @@
         :param distrosourcepackage: An `IDistributionSourcePackage`.
         :return: An `IResultSet` of `ISeriesSourcePackageBranch` objects.
         """
-
-
-class IMakeOfficialBranchLinks(Interface):
-    """A set of links from source packages in distribution suites to branches.
-
-    This doesn't really make sense as an interface, but is provided to match
-    the rest of Launchpad.
-    """
-
-    def delete(sourcepackage, pocket):
-        """Remove the SeriesSourcePackageBranch for sourcepackage and pocket.
-
-        :param sourcepackage: An `ISourcePackage`.
-        :param pocket: A `PackagePublishingPocket` enum item.
-        """
-
-    def new(distroseries, pocket, sourcepackagename, branch, registrant,
-            date_created=None):
-        """Link a source package in a distribution suite to a branch."""

=== modified file 'lib/lp/code/model/seriessourcepackagebranch.py'
--- lib/lp/code/model/seriessourcepackagebranch.py	2011-03-03 01:13:47 +0000
+++ lib/lp/code/model/seriessourcepackagebranch.py	2011-06-02 21:49:29 +0000
@@ -32,7 +32,6 @@
     )
 from lp.code.interfaces.seriessourcepackagebranch import (
     IFindOfficialBranchLinks,
-    IMakeOfficialBranchLinks,
     ISeriesSourcePackageBranch,
     )
 from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -44,7 +43,6 @@
     __storm_table__ = 'SeriesSourcePackageBranch'
     implements(ISeriesSourcePackageBranch)
 
-
     id = Int(primary=True)
     distroseriesID = Int('distroseries')
     distroseries = Reference(distroseriesID, 'DistroSeries.id')
@@ -85,11 +83,12 @@
 class SeriesSourcePackageBranchSet:
     """See `ISeriesSourcePackageBranchSet`."""
 
-    implements(IFindOfficialBranchLinks, IMakeOfficialBranchLinks)
+    implements(IFindOfficialBranchLinks)
 
-    def new(self, distroseries, pocket, sourcepackagename, branch, registrant,
+    @staticmethod
+    def new(distroseries, pocket, sourcepackagename, branch, registrant,
             date_created=None):
-        """See `IMakeOfficialBranchLinks`."""
+        """Link a source package in a distribution suite to a branch."""
         if date_created is None:
             date_created = datetime.now(pytz.UTC)
         sspb = SeriesSourcePackageBranch(
@@ -136,8 +135,13 @@
             SeriesSourcePackageBranch.sourcepackagename ==
             sourcepackagename.id)
 
-    def delete(self, sourcepackage, pocket):
-        """See `IMakeOfficialBranchLinks`."""
+    @staticmethod
+    def delete(sourcepackage, pocket):
+        """Remove the SeriesSourcePackageBranch for sourcepackage and pocket.
+
+        :param sourcepackage: An `ISourcePackage`.
+        :param pocket: A `PackagePublishingPocket` enum item.
+        """
         store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
         distroseries = sourcepackage.distroseries
         sourcepackagename = sourcepackage.sourcepackagename

=== modified file 'lib/lp/code/tests/helpers.py'
--- lib/lp/code/tests/helpers.py	2011-05-27 19:53:20 +0000
+++ lib/lp/code/tests/helpers.py	2011-06-02 21:49:29 +0000
@@ -34,8 +34,8 @@
     )
 from lp.code.interfaces.linkedbranch import ICanHasLinkedBranch
 from lp.code.interfaces.revision import IRevisionSet
-from lp.code.interfaces.seriessourcepackagebranch import (
-    IMakeOfficialBranchLinks,
+from lp.code.model.seriessourcepackagebranch import (
+    SeriesSourcePackageBranchSet
     )
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.registry.interfaces.series import SeriesStatus
@@ -89,7 +89,6 @@
 
     :return: a dict of objects to put into local scope.
     """
-    result = {}
     eric = factory.makePerson(
         name='eric', displayname='Eric the Viking',
         email='eric@xxxxxxxxxxx', password='test')
@@ -135,10 +134,7 @@
     # It is possible for the param to be None, so reset to the factory
     # generated one.
     sourcepackagename = source_package.sourcepackagename
-    # We don't care about who can make things official, so get rid of the
-    # security proxy.
-    series_set = removeSecurityProxy(getUtility(IMakeOfficialBranchLinks))
-    series_set.new(
+    SeriesSourcePackageBranchSet.new(
         distro_series, pocket, sourcepackagename, branch, branch.owner)
     return branch
 
@@ -177,9 +173,6 @@
         for i in range(branch_count)]
 
     official = []
-    # We don't care about who can make things official, so get rid of the
-    # security proxy.
-    series_set = removeSecurityProxy(getUtility(IMakeOfficialBranchLinks))
     # Sort the pocket items so RELEASE is last, and thus first popped.
     pockets = sorted(PackagePublishingPocket.items, reverse=True)
     # Since there can be only one link per pocket, max out the number of
@@ -187,7 +180,7 @@
     for i in range(min(official_count, len(pockets))):
         branch = branches.pop()
         pocket = pockets.pop()
-        sspb = series_set.new(
+        SeriesSourcePackageBranchSet.new(
             series, pocket, sourcepackagename, branch, branch.owner)
         official.append(branch)
 

=== modified file 'lib/lp/code/tests/test_seriessourcepackagebranch.py'
--- lib/lp/code/tests/test_seriessourcepackagebranch.py	2011-05-27 21:12:25 +0000
+++ lib/lp/code/tests/test_seriessourcepackagebranch.py	2011-06-02 21:49:29 +0000
@@ -11,22 +11,15 @@
 import pytz
 import transaction
 from zope.component import getUtility
-from zope.security.interfaces import Unauthorized
-from zope.security.proxy import removeSecurityProxy
 
-from canonical.launchpad.ftests import (
-    ANONYMOUS,
-    login,
-    login_person,
-    logout,
-    )
 from canonical.testing.layers import DatabaseFunctionalLayer
-from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.code.interfaces.seriessourcepackagebranch import (
     IFindOfficialBranchLinks,
-    IMakeOfficialBranchLinks,
     ISeriesSourcePackageBranch,
     )
+from lp.code.model.seriessourcepackagebranch import (
+    SeriesSourcePackageBranchSet,
+    )
 from lp.registry.interfaces.pocket import PackagePublishingPocket
 from lp.testing import TestCaseWithFactory
 
@@ -36,25 +29,15 @@
 
     layer = DatabaseFunctionalLayer
 
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        person = self.factory.makePerson()
-        ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
-        removeSecurityProxy(ubuntu_branches).addMember(
-            person, ubuntu_branches.teamowner)
-        login_person(person)
-        self.addCleanup(logout)
-
     def test_new_sets_attributes(self):
-        # ISeriesSourcePackageBranchSet.new sets all the defined attributes on
+        # SeriesSourcePackageBranchSet.new sets all the defined attributes on
         # the interface.
-        series_set = getUtility(IMakeOfficialBranchLinks)
         distroseries = self.factory.makeDistroRelease()
         sourcepackagename = self.factory.makeSourcePackageName()
         registrant = self.factory.makePerson()
         branch = self.factory.makeAnyBranch()
         now = datetime.now(pytz.UTC)
-        sspb = series_set.new(
+        sspb = SeriesSourcePackageBranchSet.new(
             distroseries, PackagePublishingPocket.RELEASE, sourcepackagename,
             branch, registrant, now)
         self.assertEqual(distroseries, sspb.distroseries)
@@ -65,28 +48,26 @@
         self.assertEqual(now, sspb.date_created)
 
     def test_new_inserts_into_db(self):
-        # IMakeOfficialBranchLinks.new inserts the new object into the
+        # SeriesSourcePackageBranchSet.new inserts the new object into the
         # database, giving it an ID.
-        series_set = getUtility(IMakeOfficialBranchLinks)
         distroseries = self.factory.makeDistroRelease()
         sourcepackagename = self.factory.makeSourcePackageName()
         registrant = self.factory.makePerson()
         branch = self.factory.makeAnyBranch()
-        sspb = series_set.new(
+        sspb = SeriesSourcePackageBranchSet.new(
             distroseries, PackagePublishingPocket.RELEASE, sourcepackagename,
             branch, registrant)
         transaction.commit()
         self.assertIsNot(sspb.id, None)
 
     def test_new_returns_ISeriesSourcePackageBranch(self):
-        # IMakeOfficialBranchLinks.new returns an
+        # SeriesSourcePackageBranchSet.new returns an
         # ISeriesSourcePackageBranch, know what I mean?
-        series_set = getUtility(IMakeOfficialBranchLinks)
         distroseries = self.factory.makeDistroRelease()
         sourcepackagename = self.factory.makeSourcePackageName()
         registrant = self.factory.makePerson()
         branch = self.factory.makeAnyBranch()
-        sspb = series_set.new(
+        sspb = SeriesSourcePackageBranchSet.new(
             distroseries, PackagePublishingPocket.RELEASE, sourcepackagename,
             branch, registrant)
         self.assertProvides(sspb, ISeriesSourcePackageBranch)
@@ -102,10 +83,9 @@
         # IFindOfficialBranchLinks.findForSourcePackage returns a result
         # set of links from the source package. Each link is an
         # ISeriesSourcePackageBranch.
-        make_branch_links = getUtility(IMakeOfficialBranchLinks)
         branch = self.factory.makePackageBranch()
         package = branch.sourcepackage
-        make_branch_links.new(
+        SeriesSourcePackageBranchSet.new(
             package.distroseries, PackagePublishingPocket.RELEASE,
             package.sourcepackagename, branch, self.factory.makePerson())
         find_branch_links = getUtility(IFindOfficialBranchLinks)
@@ -119,10 +99,9 @@
         # IFindOfficialBranchLinks.findForBranch returns a result set of
         # links from the branch to source packages & pockets. Each link is an
         # ISeriesSourcePackageBranch.
-        make_branch_links = getUtility(IMakeOfficialBranchLinks)
         branch = self.factory.makePackageBranch()
         package = branch.sourcepackage
-        make_branch_links.new(
+        SeriesSourcePackageBranchSet.new(
             package.distroseries, PackagePublishingPocket.RELEASE,
             package.sourcepackagename, branch, self.factory.makePerson())
         find_branch_links = getUtility(IFindOfficialBranchLinks)
@@ -135,35 +114,17 @@
     def test_delete(self):
         # `delete` ensures that there is no branch associated with that
         # sourcepackage and pocket.
-        make_branch_links = getUtility(IMakeOfficialBranchLinks)
         branch = self.factory.makePackageBranch()
         package = branch.sourcepackage
-        make_branch_links.new(
+        SeriesSourcePackageBranchSet.new(
             package.distroseries, PackagePublishingPocket.RELEASE,
             package.sourcepackagename, branch, self.factory.makePerson())
-        make_branch_links.delete(package, PackagePublishingPocket.RELEASE)
+        SeriesSourcePackageBranchSet.delete(
+            package, PackagePublishingPocket.RELEASE)
         find_branch_links = getUtility(IFindOfficialBranchLinks)
         self.assertEqual(
             [], list(find_branch_links.findForSourcePackage(package)))
 
-    def test_cannot_edit_branch_link(self):
-        # You can only edit an ISeriesSourcePackageBranch if you have edit
-        # permissions, which almost no one has.
-        series_set = getUtility(IMakeOfficialBranchLinks)
-        distroseries = self.factory.makeDistroRelease()
-        sourcepackagename = self.factory.makeSourcePackageName()
-        registrant = self.factory.makePerson()
-        branch = self.factory.makeAnyBranch()
-        sspb = series_set.new(
-            distroseries, PackagePublishingPocket.RELEASE, sourcepackagename,
-            branch, registrant)
-        logout()
-        login(ANONYMOUS)
-        self.assertRaises(
-            Unauthorized, setattr, sspb, 'pocket',
-            PackagePublishingPocket.BACKPORTS)
-
 
 def test_suite():
     return unittest.TestLoader().loadTestsFromName(__name__)
-

=== modified file 'lib/lp/registry/configure.zcml'
--- lib/lp/registry/configure.zcml	2011-05-31 07:11:18 +0000
+++ lib/lp/registry/configure.zcml	2011-06-02 21:49:29 +0000
@@ -1585,15 +1585,17 @@
     </securedutility>
 
     <!-- SourcePackage -->
-
     <class
         class="lp.registry.model.sourcepackage.SourcePackage">
         <allow
-            interface="lp.registry.interfaces.sourcepackage.ISourcePackage"/>
+            interface="lp.registry.interfaces.sourcepackage.ISourcePackagePublic"/>
         <allow
             interface="lp.bugs.interfaces.bugtarget.IHasBugHeat"/>
         <allow
             interface="lp.soyuz.interfaces.buildrecords.IHasBuildRecords"/>
+        <require
+            permission="launchpad.Edit"
+            interface="lp.registry.interfaces.sourcepackage.ISourcePackageEdit"/>
     </class>
     <securedutility
         component="lp.registry.model.sourcepackage.SourcePackage"

=== modified file 'lib/lp/registry/interfaces/role.py'
--- lib/lp/registry/interfaces/role.py	2011-05-27 21:25:58 +0000
+++ lib/lp/registry/interfaces/role.py	2011-06-02 21:49:29 +0000
@@ -112,9 +112,6 @@
     in_rosetta_experts = Bool(
         title=_("True if this person is a rosetta expert."),
         required=True, readonly=True)
-    in_ubuntu_branches = Bool(
-        title=_("True if this person is on the Ubuntu branches team."),
-        required=True, readonly=True)
     in_ubuntu_security = Bool(
         title=_("True if this person is on the Ubuntu security team."),
         required=True, readonly=True)

=== modified file 'lib/lp/registry/interfaces/sourcepackage.py'
--- lib/lp/registry/interfaces/sourcepackage.py	2011-05-12 14:55:54 +0000
+++ lib/lp/registry/interfaces/sourcepackage.py	2011-06-02 21:49:29 +0000
@@ -9,6 +9,8 @@
 
 __all__ = [
     'ISourcePackage',
+    'ISourcePackagePublic',
+    'ISourcePackageEdit',
     'ISourcePackageFactory',
     'SourcePackageFileType',
     'SourcePackageType',
@@ -65,26 +67,21 @@
     )
 
 
-class ISourcePackage(IBugTarget, IHasBranches, IHasMergeProposals,
-                     IHasOfficialBugTags, IHasCodeImports,
-                     IHasTranslationImports, IHasTranslationTemplates):
-    """A SourcePackage. See the MagicSourcePackage specification. This
-    interface preserves as much as possible of the old SourcePackage
-    interface from the SourcePackage table, with the new table-less
-    implementation."""
-
-    export_as_webservice_entry()
+class ISourcePackagePublic(IBugTarget, IHasBranches, IHasMergeProposals,
+                           IHasOfficialBugTags, IHasCodeImports,
+                           IHasTranslationImports, IHasTranslationTemplates):
+    """Public attributes for SourcePackage."""
 
     id = Attribute("ID")
 
     name = exported(
         TextLine(
-            title=_("Name"), required=True,
+            title=_("Name"), required=True, readonly=True,
             description=_("The text name of this source package.")))
 
     displayname = exported(
         TextLine(
-            title=_("Display name"), required=True,
+            title=_("Display name"), required=True, readonly=True,
             description=_("A displayname, constructed, for this package")))
 
     path = Attribute("A path to this package, <distro>/<series>/<package>")
@@ -107,7 +104,7 @@
             Interface,
             # Really IDistribution, circular import fixed in
             # _schema_circular_imports.
-            title=_("Distribution"), required=True,
+            title=_("Distribution"), required=True, readonly=True,
             description=_("The distribution for this source package.")))
 
     # The interface for this is really IDistroSeries, but importing that would
@@ -115,6 +112,7 @@
     distroseries = exported(
         Reference(
             Interface, title=_("Distribution Series"), required=True,
+            readonly=True,
             description=_("The DistroSeries for this SourcePackage")))
 
     sourcepackagename = Attribute("SourcePackageName")
@@ -130,7 +128,7 @@
     productseries = exported(
         ReferenceChoice(
             title=_("Project series"), required=False,
-            vocabulary="ProductSeries",
+            vocabulary="ProductSeries", readonly=True,
             schema=Interface,
             description=_(
                 "The registered project series that this source package "
@@ -265,25 +263,6 @@
         :return: An `IBranch`.
         """
 
-    # 'pocket' should actually be a PackagePublishingPocket, and 'branch'
-    # should be IBranch, but we use the base classes to avoid circular
-    # imports. Correct interface specific in _schema_circular_imports.
-    @operation_parameters(
-        pocket=Choice(
-            title=_("Pocket"), required=True,
-            vocabulary=DBEnumeratedType),
-        branch=Reference(Interface, title=_("Branch"), required=False))
-    @call_with(registrant=REQUEST_USER)
-    @export_write_operation()
-    def setBranch(pocket, branch, registrant):
-        """Set the official branch for the given pocket of this package.
-
-        :param pocket: A `PackagePublishingPocket`.
-        :param branch: The branch to set as the official branch.
-        :param registrant: The individual who created this link.
-        :return: None
-        """
-
     shouldimport = Attribute("""Whether we should import this or not.
         By 'import' we mean sourcerer analysis resulting in a manifest and a
         set of Bazaar branches which describe the source package release.
@@ -329,6 +308,34 @@
         """
 
 
+class ISourcePackageEdit(Interface):
+    """SourcePackage attributes requiring launchpad.Edit."""
+
+    # 'pocket' should actually be a PackagePublishingPocket, and 'branch'
+    # should be IBranch, but we use the base classes to avoid circular
+    # imports. Correct interface specific in _schema_circular_imports.
+    @operation_parameters(
+        pocket=Choice(
+            title=_("Pocket"), required=True,
+            vocabulary=DBEnumeratedType),
+        branch=Reference(Interface, title=_("Branch"), required=False))
+    @call_with(registrant=REQUEST_USER)
+    @export_write_operation()
+    def setBranch(pocket, branch, registrant):
+        """Set the official branch for the given pocket of this package.
+
+        :param pocket: A `PackagePublishingPocket`.
+        :param branch: The branch to set as the official branch.
+        :param registrant: The individual who created this link.
+        :return: None
+        """
+
+
+class ISourcePackage(ISourcePackagePublic, ISourcePackageEdit):
+    """A source package associated to a particular distribution series."""
+    export_as_webservice_entry()
+
+
 class ISourcePackageFactory(Interface):
     """A creator of source packages."""
 

=== modified file 'lib/lp/registry/model/sourcepackage.py'
--- lib/lp/registry/model/sourcepackage.py	2011-05-14 15:03:04 +0000
+++ lib/lp/registry/model/sourcepackage.py	2011-06-02 21:49:29 +0000
@@ -46,8 +46,8 @@
     )
 from lp.bugs.model.bugtask import BugTask
 from lp.buildmaster.enums import BuildStatus
-from lp.code.interfaces.seriessourcepackagebranch import (
-    IMakeOfficialBranchLinks,
+from lp.code.model.seriessourcepackagebranch import (
+    SeriesSourcePackageBranchSet,
     )
 from lp.code.model.branch import Branch
 from lp.code.model.hasbranches import (
@@ -202,8 +202,14 @@
     classProvides(ISourcePackageFactory)
 
     def __init__(self, sourcepackagename, distroseries):
+        # We store the ID of the sourcepackagename and distroseries
+        # simply because Storm can break when accessing them
+        # with implicit flush is blocked (like in a permission check when
+        # storing the object in the permission cache).
+        self.sourcepackagenameID = sourcepackagename.id
         self.sourcepackagename = sourcepackagename
         self.distroseries = distroseries
+        self.distroseriesID = distroseries.id
 
     @classmethod
     def new(cls, sourcepackagename, distroseries):
@@ -585,7 +591,7 @@
 
     def __hash__(self):
         """See `ISourcePackage`."""
-        return hash(self.distroseries.id) ^ hash(self.sourcepackagename.id)
+        return hash(self.distroseriesID) ^ hash(self.sourcepackagenameID)
 
     def __eq__(self, other):
         """See `ISourcePackage`."""
@@ -725,10 +731,9 @@
 
     def setBranch(self, pocket, branch, registrant):
         """See `ISourcePackage`."""
-        series_set = getUtility(IMakeOfficialBranchLinks)
-        series_set.delete(self, pocket)
+        SeriesSourcePackageBranchSet.delete(self, pocket)
         if branch is not None:
-            series_set.new(
+            SeriesSourcePackageBranchSet.new(
                 self.distroseries, pocket, self.sourcepackagename, branch,
                 registrant)
 

=== modified file 'lib/lp/registry/tests/test_sourcepackage.py'
--- lib/lp/registry/tests/test_sourcepackage.py	2011-05-27 21:12:25 +0000
+++ lib/lp/registry/tests/test_sourcepackage.py	2011-06-02 21:49:29 +0000
@@ -14,17 +14,14 @@
 from storm.locals import Store
 import transaction
 from zope.component import getUtility
+from zope.security.checker import canAccess
 from zope.security.interfaces import Unauthorized
-from zope.security.proxy import removeSecurityProxy
+from zope.security.management import checkPermission
 
-from canonical.launchpad.ftests import (
-    login_person,
-    logout,
-    )
 from canonical.testing.layers import DatabaseFunctionalLayer
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
-from lp.code.interfaces.seriessourcepackagebranch import (
-    IMakeOfficialBranchLinks,
+from lp.code.model.seriessourcepackagebranch import (
+    SeriesSourcePackageBranchSet,
     )
 from lp.registry.interfaces.distribution import NoPartnerArchive
 from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -48,15 +45,6 @@
 
     layer = DatabaseFunctionalLayer
 
-    def setUp(self):
-        TestCaseWithFactory.setUp(self)
-        person = self.factory.makePerson()
-        ubuntu_branches = getUtility(ILaunchpadCelebrities).ubuntu_branches
-        removeSecurityProxy(ubuntu_branches).addMember(
-            person, ubuntu_branches.teamowner)
-        login_person(person)
-        self.addCleanup(logout)
-
     def test_path(self):
         sourcepackage = self.factory.makeSourcePackage()
         self.assertEqual(
@@ -79,7 +67,7 @@
         sourcepackage = self.factory.makeSourcePackage()
         registrant = self.factory.makePerson()
         branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
-        getUtility(IMakeOfficialBranchLinks).new(
+        SeriesSourcePackageBranchSet.new(
             sourcepackage.distroseries, PackagePublishingPocket.RELEASE,
             sourcepackage.sourcepackagename, branch, registrant)
         official_branch = sourcepackage.getBranch(
@@ -92,7 +80,8 @@
         pocket = PackagePublishingPocket.RELEASE
         registrant = self.factory.makePerson()
         branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
-        sourcepackage.setBranch(pocket, branch, registrant)
+        with person_logged_in(sourcepackage.distribution.owner):
+            sourcepackage.setBranch(pocket, branch, registrant)
         self.assertEqual(branch, sourcepackage.getBranch(pocket))
 
     def test_change_branch_once_set(self):
@@ -104,8 +93,9 @@
         branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
         new_branch = self.factory.makePackageBranch(
             sourcepackage=sourcepackage)
-        sourcepackage.setBranch(pocket, branch, registrant)
-        sourcepackage.setBranch(pocket, new_branch, registrant)
+        with person_logged_in(sourcepackage.distribution.owner):
+            sourcepackage.setBranch(pocket, branch, registrant)
+            sourcepackage.setBranch(pocket, new_branch, registrant)
         self.assertEqual(new_branch, sourcepackage.getBranch(pocket))
 
     def test_unsetBranch(self):
@@ -115,8 +105,9 @@
         pocket = PackagePublishingPocket.RELEASE
         registrant = self.factory.makePerson()
         branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
-        sourcepackage.setBranch(pocket, branch, registrant)
-        sourcepackage.setBranch(pocket, None, registrant)
+        with person_logged_in(sourcepackage.distribution.owner):
+            sourcepackage.setBranch(pocket, branch, registrant)
+            sourcepackage.setBranch(pocket, None, registrant)
         self.assertIs(None, sourcepackage.getBranch(pocket))
 
     def test_linked_branches(self):
@@ -125,7 +116,8 @@
         pocket = PackagePublishingPocket.RELEASE
         registrant = self.factory.makePerson()
         branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
-        sourcepackage.setBranch(pocket, branch, registrant)
+        with person_logged_in(sourcepackage.distribution.owner):
+            sourcepackage.setBranch(pocket, branch, registrant)
         self.assertEqual(
             [(pocket, branch)], list(sourcepackage.linked_branches))
 
@@ -270,7 +262,7 @@
         store = Store.of(packaging)
         with person_logged_in(packaging.owner):
             packaging.sourcepackage.deletePackaging()
-        result = store.find(Packaging, Packaging.id==packaging_id)
+        result = store.find(Packaging, Packaging.id == packaging_id)
         self.assertIs(None, result.one())
 
     def test_setPackaging__new(self):
@@ -469,8 +461,9 @@
             'user_can_change_branch': False,
             'user_can_change_translation_usage': False,
             'user_can_change_translations_autoimport_mode': False}
-        self.assertEqual(
-            expected, sourcepackage.getSharingDetailPermissions())
+        with person_logged_in(self.factory.makePerson()):
+            self.assertEqual(
+                expected, sourcepackage.getSharingDetailPermissions())
 
     def test_getSharingDetailPermissions_no_user(self):
         sourcepackage = self.factory.makeSourcePackage()
@@ -479,7 +472,6 @@
             'user_can_change_branch': False,
             'user_can_change_translation_usage': False,
             'user_can_change_translations_autoimport_mode': False}
-        logout()
         self.assertEqual(
             expected, sourcepackage.getSharingDetailPermissions())
 
@@ -518,17 +510,53 @@
 
 
 class TestSourcePackageSecurity(TestCaseWithFactory):
-    """Tests for source package branch linking security."""
+    """Tests for source package security."""
 
     layer = DatabaseFunctionalLayer
 
+    def test_admins_have_launchpad_Edit(self):
+        admin = self.factory.makeAdministrator()
+        sourcepackage = self.factory.makeSourcePackage()
+        with person_logged_in(admin):
+            self.failUnless(
+                checkPermission('launchpad.Edit', sourcepackage),
+                "Administrators should have launchpad.Edit on source "
+                "packages.")
+
+    def test_distro_owner_have_launchpad_Edit(self):
+        sourcepackage = self.factory.makeSourcePackage()
+        with person_logged_in(sourcepackage.distribution.owner):
+            self.failUnless(
+                checkPermission('launchpad.Edit', sourcepackage),
+                "Distribution owner should have launchpad.Edit on source "
+                "packages.")
+
+    def test_uploader_have_launchpad_edit(self):
+        sourcepackage = self.factory.makeSourcePackage()
+        uploader = self.factory.makePerson()
+        archive = sourcepackage.get_default_archive()
+        with person_logged_in(sourcepackage.distribution.main_archive.owner):
+            archive.newPackageUploader(uploader, sourcepackage.name)
+        with person_logged_in(uploader):
+            self.failUnless(
+                checkPermission('launchpad.Edit', sourcepackage),
+                "Uploader to the package should have launchpad.Edit on "
+                "source packages.")
+
+    def test_john_doe_can_t_edit(self):
+        sourcepackage = self.factory.makeSourcePackage()
+        john_doe = self.factory.makePerson()
+        with person_logged_in(john_doe):
+            self.failIf(
+                checkPermission('launchpad.Edit', sourcepackage),
+                "Random user shouldn't have launchpad.Edit on source "
+                "packages.")
+
     def test_cannot_setBranch(self):
         sourcepackage = self.factory.makeSourcePackage()
-        pocket = PackagePublishingPocket.RELEASE
-        registrant = self.factory.makePerson()
-        branch = self.factory.makePackageBranch(sourcepackage=sourcepackage)
-        self.assertRaises(
-            Unauthorized, sourcepackage.setBranch, pocket, branch, registrant)
+        self.failIf(
+            canAccess(sourcepackage, 'setBranch'),
+            "setBranch should only be available to admins and uploaders")
 
 
 class TestSourcePackageViews(TestCaseWithFactory):