> === modified file 'lib/canonical/launchpad/webapp/configure.zcml' > --- lib/canonical/launchpad/webapp/configure.zcml 2009-11-18 00:22:41 +0000 > +++ lib/canonical/launchpad/webapp/configure.zcml 2010-01-12 22:36:26 +0000 > @@ -809,6 +809,7 @@ > > <class class="canonical.launchpad.webapp.vocabulary.CountableIterator"> > <allow interface="canonical.launchpad.webapp.vocabulary.ICountableIterator" /> > + <allow attributes="__getslice__"/>
Wouldn't it make sense to add __getslice__ to CountableIterator?
> </class> > > <class class="canonical.launchpad.webapp.vocabulary.BatchedCountableIterator"> > > === modified file 'lib/lp/registry/doc/vocabularies.txt' > --- lib/lp/registry/doc/vocabularies.txt 2009-12-24 01:41:54 +0000 > +++ lib/lp/registry/doc/vocabularies.txt 2010-01-12 22:36:26 +0000 > @@ -20,7 +20,9 @@ > The active mailing lists vocabulary matches and returns only those mailing > lists which are active. > > - >>> list_vocabulary = vocabulary_registry.get(None, 'ActiveMailingList') > + >>> from zope.security.proxy import removeSecurityProxy > + >>> list_vocabulary = removeSecurityProxy( > + ... vocabulary_registry.get(None, 'ActiveMailingList')) > >>> from canonical.launchpad.webapp.testing import verifyObject > >>> from canonical.launchpad.webapp.vocabulary import IHugeVocabulary > >>> verifyObject(IHugeVocabulary, list_vocabulary) > @@ -203,6 +205,7 @@ > u'The Hoary Hedgehog Release' > > >>> def getTerms(vocab, search_text): > + ... vocab = removeSecurityProxy(vocab) > ... [vocab.toTerm(item) for item in vocab.search(search_text)] > > >>> getTerms(distroseries_vocabulary, 'woody') > @@ -508,7 +511,8 @@ > > The list of selectable projects. The results are ordered by displayname. > > - >>> project_vocabulary = vocabulary_registry.get(None, "Project") > + >>> project_vocabulary = removeSecurityProxy( > + ... vocabulary_registry.get(None, "Project"))
I think we wought to have a wrapper around vocabulary_registry.get() to remove the security proxy of the vocab before returning. Something like
def get_naked_vocab(context, name): return removeSecurityProxy(vocab_registry.get(context, name))
That way we don't have to repeat the removeSecurityProxy() call in all the places we call vocabulary_registry.get.
> >>> project_vocabulary.displayname > 'Select a project group' > > @@ -542,7 +546,8 @@ > > The list of selectable products. Results are ordered by displayname. > > - >>> product_vocabulary = vocabulary_registry.get(None, "Product") > + >>> product_vocabulary = removeSecurityProxy( > + ... vocabulary_registry.get(None, "Product")) > >>> product_vocabulary.displayname > 'Select a project' > > @@ -583,8 +588,8 @@ > > The list of selectable products releases. > > - >>> productrelease_vocabulary = vocabulary_registry.get(None, > - ... "ProductRelease") > + >>> productrelease_vocabulary = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ProductRelease")) > >>> productrelease_vocabulary.displayname > 'Select a Product Release' > > @@ -603,7 +608,8 @@ > All non-merged people with at least one email address. This vocabulary is > meant to be used only in the people merge form. > > - >>> vocab = vocabulary_registry.get(None, "PersonAccountToMerge") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "PersonAccountToMerge")) > >>> vocab.displayname > 'Select a Person to Merge' > > @@ -693,7 +699,8 @@ > > The set of non-merged people. > > - >>> vocab = vocabulary_registry.get(None, "AdminMergeablePerson") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "AdminMergeablePerson")) > >>> vocab.displayname > 'Select a Person to Merge' > > @@ -712,7 +719,8 @@ > > All non-merged people and teams. > > - >>> vocab = vocabulary_registry.get(None, "NonMergedPeopleAndTeams") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "NonMergedPeopleAndTeams")) > >>> vocab.displayname > 'Select a Person or Team' > > @@ -746,7 +754,8 @@ > None). It also includes all public teams and private teams the > user has permission to view. > > - >>> vocab = vocabulary_registry.get(None, "ValidPersonOrTeam") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ValidPersonOrTeam")) > >>> vocab.displayname > 'Select a Person or Team' > > @@ -794,7 +803,8 @@ > A PRIVATE team is displayed when the logged in user is a member of the team. > > >>> commercial = person_set.getByEmail('<email address hidden>') > - >>> vocab = vocabulary_registry.get(commercial, "ValidPersonOrTeam") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(commercial, "ValidPersonOrTeam")) > >>> login('<email address hidden>') > >>> priv_team = factory.makeTeam( > ... name='private-team', > @@ -861,7 +871,8 @@ > one of its email addresses. > > >>> login('<email address hidden>') > - >>> vocab = vocabulary_registry.get(None, "ValidPersonOrTeam") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ValidPersonOrTeam")) > >>> sorted(person.name for person in vocab.search('support')) > [u'ubuntu-team'] > > @@ -932,7 +943,8 @@ > All valid persons and teams are also valid owners. > > >>> login(ANONYMOUS) > - >>> vocab = vocabulary_registry.get(None, "ValidOwner") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ValidOwner")) > >>> vocab.displayname > 'Select a Person or Team' > > @@ -955,7 +967,8 @@ > except that its terms are limited only to teams. No non-team Persons will be > returned. > > - >>> vocab = vocabulary_registry.get(None, 'ValidTeam') > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, 'ValidTeam')) > >>> vocab.displayname > 'Select a Team' > >>> sorted((team.displayname, team.teamowner.displayname) > @@ -1076,7 +1089,8 @@ > > 'name16' is a valid member for 'ubuntu-team': > > - >>> vocab = vocabulary_registry.get(team, "ValidTeamMember") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(team, "ValidTeamMember")) > >>> vocab.displayname > 'Select a Person or Team' > > @@ -1126,7 +1140,8 @@ > > 'ubuntu-team' is not a valid owner for itself. > > - >>> vocab = vocabulary_registry.get(team, "ValidTeamOwner") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(team, "ValidTeamOwner")) > >>> vocab.displayname > 'Select a Person or Team' > > @@ -1147,7 +1162,8 @@ > > All 'valid' persons who are not a team. > > - >>> vocab = vocabulary_registry.get(None, "ValidPerson") > + >>> vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ValidPerson")) > >>> vocab.displayname > 'Select a Person' > >>> people = vocab.search(None) > @@ -1172,8 +1188,8 @@ > >>> carlos = getUtility(IPersonSet).getByName('carlos') > >>> carlos_team = factory.makeTeam( > ... owner=carlos, name='carlos-team') > - >>> person_or_team_vocab = vocabulary_registry.get( > - ... None, "ValidPersonOrTeam") > + >>> person_or_team_vocab = removeSecurityProxy( > + ... vocabulary_registry.get(None, "ValidPersonOrTeam")) > >>> carlos_people_or_team = person_or_team_vocab.search('carlos') > >>> # The people or team search yields our one Carlos person and > >>> # the new team. > > === added file 'lib/lp/services/tests/test_vocabularies.py' > --- lib/lp/services/tests/test_vocabularies.py 1970-01-01 00:00:00 +0000 > +++ lib/lp/services/tests/test_vocabularies.py 2010-01-12 22:36:26 +0000 > @@ -0,0 +1,33 @@ > +# Copyright 2010 Canonical Ltd. This software is licensed under the > +# GNU Affero General Public License version 3 (see the file LICENSE). > + > +"""Test registered vocabularies.""" > + > +__metaclass__ = type > +__all__ = [] > + > +import unittest > + > +from zope.component import getUtilitiesFor > +from zope.schema.interfaces import IVocabularyFactory > +from zope.security._proxy import _Proxy > + > +from canonical.testing.layers import FunctionalLayer > +from lp.testing import TestCase > + > + > +class TestVocabularies(TestCase): > + layer = FunctionalLayer > + > + def test_security_proxy(self): > + """Our vocabularies should be registered with <securedutility>.""" > + vocabularies = getUtilitiesFor(IVocabularyFactory) > + for name, vocab in vocabularies: > + if type(vocab) != _Proxy and vocab.__module__[:5] != 'zope.': > + raise AssertionError( > + '%s.%s vocabulary is not wrapped in a security proxy.' % ( > + vocab.__module__, name))
Isn't there a simpler way to check that a given object is wrapped in a security proxy? Let's check with Gary...
> + > + > +def test_suite(): > + return unittest.TestLoader().loadTestsFromName(__name__) >
« Back to merge proposal
> === modified file 'lib/canonical/ launchpad/ webapp/ configure. zcml' launchpad/ webapp/ configure. zcml 2009-11-18 00:22:41 +0000 launchpad/ webapp/ configure. zcml 2010-01-12 22:36:26 +0000 canonical. launchpad. webapp. vocabulary. CountableIterat or"> "canonical. launchpad. webapp. vocabulary. ICountableItera tor" /> "__getslice_ _"/>
> --- lib/canonical/
> +++ lib/canonical/
> @@ -809,6 +809,7 @@
>
> <class class="
> <allow interface=
> + <allow attributes=
Wouldn't it make sense to add __getslice__ to CountableIterator?
> </class> canonical. launchpad. webapp. vocabulary. BatchedCountabl eIterator" > registry/ doc/vocabularie s.txt' registry/ doc/vocabularie s.txt 2009-12-24 01:41:54 +0000 registry/ doc/vocabularie s.txt 2010-01-12 22:36:26 +0000 registry. get(None, 'ActiveMailingL ist') roxy( registry. get(None, 'ActiveMailingL ist')) launchpad. webapp. testing import verifyObject launchpad. webapp. vocabulary import IHugeVocabulary IHugeVocabulary , list_vocabulary) roxy(vocab) search_ text)] distroseries_ vocabulary, 'woody') registry. get(None, "Project") roxy( registry. get(None, "Project"))
>
> <class class="
>
> === modified file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -20,7 +20,9 @@
> The active mailing lists vocabulary matches and returns only those mailing
> lists which are active.
>
> - >>> list_vocabulary = vocabulary_
> + >>> from zope.security.proxy import removeSecurityProxy
> + >>> list_vocabulary = removeSecurityP
> + ... vocabulary_
> >>> from canonical.
> >>> from canonical.
> >>> verifyObject(
> @@ -203,6 +205,7 @@
> u'The Hoary Hedgehog Release'
>
> >>> def getTerms(vocab, search_text):
> + ... vocab = removeSecurityP
> ... [vocab.toTerm(item) for item in vocab.search(
>
> >>> getTerms(
> @@ -508,7 +511,8 @@
>
> The list of selectable projects. The results are ordered by displayname.
>
> - >>> project_vocabulary = vocabulary_
> + >>> project_vocabulary = removeSecurityP
> + ... vocabulary_
I think we wought to have a wrapper around vocabulary_ registry. get() to remove
the security proxy of the vocab before returning. Something like
def get_naked_ vocab(context, name): roxy(vocab_ registry. get(context, name))
return removeSecurityP
That way we don't have to repeat the removeSecurityP roxy() call in all the registry. get.
places we call vocabulary_
> >>> project_ vocabulary. displayname registry. get(None, "Product") roxy( registry. get(None, "Product")) vocabulary. displayname vocabulary = vocabulary_ registry. get(None, vocabulary = removeSecurityP roxy( registry. get(None, "ProductRelease")) vocabulary. displayname registry. get(None, "PersonAccountT oMerge" ) roxy( registry. get(None, "PersonAccountT oMerge" )) registry. get(None, "AdminMergeable Person" ) roxy( registry. get(None, "AdminMergeable Person" )) registry. get(None, "NonMergedPeopl eAndTeams" ) roxy( registry. get(None, "NonMergedPeopl eAndTeams" )) registry. get(None, "ValidPersonOrT eam") roxy( registry. get(None, "ValidPersonOrT eam")) set.getByEmail( '<email address hidden>') registry. get(commercial, "ValidPersonOrT eam") roxy( registry. get(commercial, "ValidPersonOrT eam")) team', registry. get(None, "ValidPersonOrT eam") roxy( registry. get(None, "ValidPersonOrT eam")) 'support' )) registry. get(None, "ValidOwner") roxy( registry. get(None, "ValidOwner")) registry. get(None, 'ValidTeam') roxy( registry. get(None, 'ValidTeam')) (team.displayna me, team.teamowner. displayname) registry. get(team, "ValidTeamMember") roxy( registry. get(team, "ValidTeamMember")) registry. get(team, "ValidTeamOwner") roxy( registry. get(team, "ValidTeamOwner")) registry. get(None, "ValidPerson") roxy( registry. get(None, "ValidPerson")) IPersonSet) .getByName( 'carlos' ) or_team_ vocab = vocabulary_ registry. get( eam") or_team_ vocab = removeSecurityP roxy( registry. get(None, "ValidPersonOrT eam")) people_ or_team = person_ or_team_ vocab.search( 'carlos' ) services/ tests/test_ vocabularies. py' services/ tests/test_ vocabularies. py 1970-01-01 00:00:00 +0000 services/ tests/test_ vocabularies. py 2010-01-12 22:36:26 +0000 interfaces import IVocabularyFactory _proxy import _Proxy testing. layers import FunctionalLayer s(TestCase) : proxy(self) : >.""" (IVocabularyFac tory) _module_ _[:5] != 'zope.':
> 'Select a project group'
>
> @@ -542,7 +546,8 @@
>
> The list of selectable products. Results are ordered by displayname.
>
> - >>> product_vocabulary = vocabulary_
> + >>> product_vocabulary = removeSecurityP
> + ... vocabulary_
> >>> product_
> 'Select a project'
>
> @@ -583,8 +588,8 @@
>
> The list of selectable products releases.
>
> - >>> productrelease_
> - ... "ProductRelease")
> + >>> productrelease_
> + ... vocabulary_
> >>> productrelease_
> 'Select a Product Release'
>
> @@ -603,7 +608,8 @@
> All non-merged people with at least one email address. This vocabulary is
> meant to be used only in the people merge form.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person to Merge'
>
> @@ -693,7 +699,8 @@
>
> The set of non-merged people.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person to Merge'
>
> @@ -712,7 +719,8 @@
>
> All non-merged people and teams.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person or Team'
>
> @@ -746,7 +754,8 @@
> None). It also includes all public teams and private teams the
> user has permission to view.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person or Team'
>
> @@ -794,7 +803,8 @@
> A PRIVATE team is displayed when the logged in user is a member of the team.
>
> >>> commercial = person_
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> login('<email address hidden>')
> >>> priv_team = factory.makeTeam(
> ... name='private-
> @@ -861,7 +871,8 @@
> one of its email addresses.
>
> >>> login('<email address hidden>')
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> sorted(person.name for person in vocab.search(
> [u'ubuntu-team']
>
> @@ -932,7 +943,8 @@
> All valid persons and teams are also valid owners.
>
> >>> login(ANONYMOUS)
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person or Team'
>
> @@ -955,7 +967,8 @@
> except that its terms are limited only to teams. No non-team Persons will be
> returned.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Team'
> >>> sorted(
> @@ -1076,7 +1089,8 @@
>
> 'name16' is a valid member for 'ubuntu-team':
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person or Team'
>
> @@ -1126,7 +1140,8 @@
>
> 'ubuntu-team' is not a valid owner for itself.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person or Team'
>
> @@ -1147,7 +1162,8 @@
>
> All 'valid' persons who are not a team.
>
> - >>> vocab = vocabulary_
> + >>> vocab = removeSecurityP
> + ... vocabulary_
> >>> vocab.displayname
> 'Select a Person'
> >>> people = vocab.search(None)
> @@ -1172,8 +1188,8 @@
> >>> carlos = getUtility(
> >>> carlos_team = factory.makeTeam(
> ... owner=carlos, name='carlos-team')
> - >>> person_
> - ... None, "ValidPersonOrT
> + >>> person_
> + ... vocabulary_
> >>> carlos_
> >>> # The people or team search yields our one Carlos person and
> >>> # the new team.
>
> === added file 'lib/lp/
> --- lib/lp/
> +++ lib/lp/
> @@ -0,0 +1,33 @@
> +# Copyright 2010 Canonical Ltd. This software is licensed under the
> +# GNU Affero General Public License version 3 (see the file LICENSE).
> +
> +"""Test registered vocabularies."""
> +
> +__metaclass__ = type
> +__all__ = []
> +
> +import unittest
> +
> +from zope.component import getUtilitiesFor
> +from zope.schema.
> +from zope.security.
> +
> +from canonical.
> +from lp.testing import TestCase
> +
> +
> +class TestVocabularie
> + layer = FunctionalLayer
> +
> + def test_security_
> + """Our vocabularies should be registered with <securedutility
> + vocabularies = getUtilitiesFor
> + for name, vocab in vocabularies:
> + if type(vocab) != _Proxy and vocab._
> + raise AssertionError(
> + '%s.%s vocabulary is not wrapped in a security proxy.' % (
> + vocab.__module__, name))
Isn't there a simpler way to check that a given object is wrapped in a
security proxy? Let's check with Gary...
> + TestLoader( ).loadTestsFrom Name(__ name__)
> +
> +def test_suite():
> + return unittest.
>