launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #05773
[Merge] lp:~mbp/launchpad/feature-admin-party into lp:launchpad
Martin Pool has proposed merging lp:~mbp/launchpad/feature-admin-party into lp:launchpad.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #790025 in Launchpad itself: "provide LP developers full access to QAS/Staging feature flags"
https://bugs.launchpad.net/launchpad/+bug/790025
For more details, see:
https://code.launchpad.net/~mbp/launchpad/feature-admin-party/+merge/84044
per bug 790025, this lets members of ~registry edit things on demo instances.
It also deduplicates and separates out a test fixture for demo instances.
Of course I welcome feedback on how the security is done. I probably could have hooked this in zcml or config, but it seemed no easier to change and to me less clear.
--
https://code.launchpad.net/~mbp/launchpad/feature-admin-party/+merge/84044
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~mbp/launchpad/feature-admin-party into lp:launchpad.
=== modified file 'lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt'
--- lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt 2011-09-29 10:23:29 +0000
+++ lib/canonical/launchpad/pagetests/basics/demo-and-lpnet.txt 2011-12-01 01:32:29 +0000
@@ -27,15 +27,9 @@
information and styles.
# Set config to pretend we're on a demo site:
- >>> from textwrap import dedent
- >>> site_message = ('This is a demo site mmk. '
- ... '<a href="http://example.com">File a bug</a>.')
- >>> test_data = dedent("""
- ... [launchpad]
- ... is_demo: True
- ... site_message: %s
- ... """ % site_message)
- >>> config.push('test_data', test_data)
+ >>> from lp.testing.fixture import DemoMode
+ >>> demo_mode_fixture = DemoMode()
+ >>> demo_mode_fixture.setUp()
>>> print config.launchpad.is_demo
True
@@ -61,8 +55,7 @@
When you are not on a demo site, the text no longer appears.
- >>> # Restore the previous config:
- >>> config_data = config.pop('test_data')
+ >>> demo_mode_fixture.cleanUp()
>>> print config.launchpad.is_demo
False
=== modified file 'lib/lp/registry/browser/tests/test_product.py'
--- lib/lp/registry/browser/tests/test_product.py 2011-11-28 05:14:57 +0000
+++ lib/lp/registry/browser/tests/test_product.py 2011-12-01 01:32:29 +0000
@@ -27,6 +27,9 @@
person_logged_in,
TestCaseWithFactory,
)
+from lp.testing.fixture import (
+ DemoMode,
+ )
from lp.testing.mail_helpers import pop_notifications
from lp.testing.service_usage_helpers import set_service_usage
from lp.testing.views import (
@@ -164,10 +167,7 @@
self.assertTrue(message is not None)
def test_staging_message_is_demo(self):
- config.push('staging-test', '''
- [launchpad]
- is_demo: true
- ''')
+ self.useFixture(DemoMode())
view = create_initialized_view(self.product_set, '+new')
message = find_tag_by_id(view.render(), 'staging-message')
self.assertEqual(None, message)
=== modified file 'lib/lp/services/features/browser/configure.zcml'
--- lib/lp/services/features/browser/configure.zcml 2011-02-16 22:03:30 +0000
+++ lib/lp/services/features/browser/configure.zcml 2011-12-01 01:32:29 +0000
@@ -1,5 +1,7 @@
-<!-- Copyright 2010 Canonical Ltd. This software is licensed under the
- GNU Affero General Public License version 3 (see the file LICENSE).
+<!-- Copyright 2010, 2011 Canonical Ltd.
+
+ This software is licensed under the GNU Affero General Public License
+ version 3 (see the file LICENSE).
-->
<configure
@@ -13,7 +15,8 @@
Readonly access is guarded by launchpad.Edit on ILaunchpadRoot, which
limits it to ~admins + ~registry, which are all trusted users. Write
- access is for admins only.
+ access is for admins only on production sites, and also launchpad.Edit
+ on demo sites.
-->
<browser:page
for="canonical.launchpad.webapp.interfaces.ILaunchpadRoot"
=== modified file 'lib/lp/services/features/browser/edit.py'
--- lib/lp/services/features/browser/edit.py 2011-03-23 16:28:51 +0000
+++ lib/lp/services/features/browser/edit.py 2011-12-01 01:32:29 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""View and edit feature rules."""
@@ -14,16 +14,20 @@
import logging
from zope.app.form.browser import TextAreaWidget
+from zope.component import getUtility
from zope.interface import Interface
from zope.schema import Text
+from canonical import config
from canonical.launchpad.webapp.authorization import check_permission
+
from lp.app.browser.launchpadform import (
action,
custom_widget,
LaunchpadFormView,
)
from lp.app.browser.stringformatter import FormattersAPI
+from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.services.features.changelog import ChangeLog
from lp.services.features.rulesource import DuplicatePriorityError
@@ -69,7 +73,16 @@
return []
def canSubmit(self, action):
- """Is the user authorized to change the rules?"""
+ """Is the user authorized to change the rules?
+
+ On development machines, developers can change the rules; on
+ production machines only admins can change them.
+ """
+ if config.config['launchpad']['is_demo']:
+ celebrities = getUtility(ILaunchpadCelebrities)
+ if self.user.inTeam(celebrities.registry_experts):
+ return True
+ # Edit permission on the root object: an admin.
return check_permission('launchpad.Admin', self.context)
@action(u"Change", name="change", condition=canSubmit)
=== modified file 'lib/lp/services/features/browser/tests/test_feature_editor.py'
--- lib/lp/services/features/browser/tests/test_feature_editor.py 2011-05-27 21:12:25 +0000
+++ lib/lp/services/features/browser/tests/test_feature_editor.py 2011-12-01 01:32:29 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for feature rule editor"""
@@ -7,7 +7,16 @@
from textwrap import dedent
-from testtools.matchers import Equals
+from soupmatchers import (
+ HTMLContains,
+ Tag,
+ )
+
+from testtools.matchers import (
+ Equals,
+ MatchesAll,
+ Not,
+ )
from zope.component import getUtility
from zope.security.interfaces import Unauthorized
@@ -26,6 +35,7 @@
BrowserTestCase,
person_logged_in,
)
+from lp.testing.fixture import DemoMode
from lp.testing.matchers import Contains
@@ -54,7 +64,6 @@
def getUserBrowserAsAdmin(self):
"""Make a new TestBrowser logged in as an admin user."""
- url = self.getFeatureRulesViewURL()
admin_team = getUtility(ILaunchpadCelebrities).admin
return self.getUserBrowserAsTeamMember([admin_team])
@@ -102,18 +111,20 @@
browser.open,
self.getFeatureRulesViewURL())
- def test_feature_page_can_view(self):
+ def test_feature_page_html_is_readonly(self):
"""User that can only view the rules do not see the form."""
browser = self.getUserBrowserAsTeamMember(
[getUtility(ILaunchpadCelebrities).registry_experts])
browser.open(self.getFeatureRulesViewURL())
- content = find_main_content(browser.contents)
- self.assertEqual(
- None, find_tag_by_id(content, 'field.feature_rules'))
- self.assertEqual(
- None, find_tag_by_id(content, 'field.actions.change'))
- self.assertTrue(
- find_tag_by_id(content, 'feature-rules'))
+ self.assertThat(
+ browser.contents,
+ MatchesAll(
+ Not(HTMLContains(Tag(
+ 'rules textarea', 'textarea',
+ dict(id='field.feature_rules')))),
+ Not(HTMLContains(Tag(
+ 'submit button', 'input',
+ dict(id='field.actions.change', type='submit'))))))
def test_feature_page_submit_changes(self):
"""Submitted changes show up in the db."""
@@ -207,6 +218,19 @@
view = FeatureControlView(None, None)
self.assertFalse(view.change_action.available())
+ def test_feature_view_not_for_registry_on_lpnet(self):
+ """Registry cannot change features on lpnet"""
+ with person_logged_in(self.factory.makeRegistryExpert()):
+ view = FeatureControlView(None, None)
+ self.assertFalse(view.change_action.available())
+
+ def test_feature_view_for_registry_on_demo(self):
+ """Registry cannot change features on lpnet"""
+ self.useFixture(DemoMode())
+ with person_logged_in(self.factory.makeRegistryExpert()):
+ view = FeatureControlView(None, None)
+ self.assertTrue(view.change_action.available())
+
def test_error_for_duplicate_priority(self):
"""Duplicate priority values for a flag result in a nice error."""
browser = self.getUserBrowserAsAdmin()
=== modified file 'lib/lp/testing/fixture.py'
--- lib/lp/testing/fixture.py 2011-11-23 07:29:09 +0000
+++ lib/lp/testing/fixture.py 2011-12-01 01:32:29 +0000
@@ -6,6 +6,7 @@
__metaclass__ = type
__all__ = [
'CaptureOops',
+ 'DemoMode',
'PGBouncerFixture',
'Urllib2Fixture',
'ZopeAdapterFixture',
@@ -344,3 +345,21 @@
self.timeline = get_request_timeline(
get_current_browser_request())
self.addCleanup(webapp.adapter.clear_request_started)
+
+
+class DemoMode(Fixture):
+ """Run with an is_demo configuration.
+
+ This changes the page styling, feature flag permissions, and perhaps
+ other things.
+ """
+
+ def setUp(self):
+ Fixture.setUp(self)
+ config.push('demo-fixture', '''
+[launchpad]
+is_demo: true
+site_message = This is a demo site mmk. \
+<a href="http://example.com">File a bug</a>.
+ ''')
+ self.addCleanup(lambda: config.pop('demo-fixture'))
Follow ups