/testing/hooks/pre_commit/test_check_owners.py
Python | 333 lines | 292 code | 10 blank | 31 comment | 0 complexity | 55f1629dfb53be5a1524042a9903c07f MD5 | raw file
Possible License(s): Apache-2.0
- #! /usr/bin/python2.4
- # Copyright 2007 Google Inc.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """check_owners.py unittest"""
- import unittest
- import svn.fs
- import svn.repos
- import gvn.hooks.info
- from gvn.hooks.pre_commit.check_owners import RunHook
- import testing.hooks.common
- SUPER_GROUP = "super-group"
- """
- Our testdata/test-checkin1 tree looks like this:
- test-checkin1
- test-checkin1/file1
- test-checkin1/B
- test-checkin1/B/dir
- test-checkin1/B/dir/fileB_dir
- test-checkin1/B/fileB
- test-checkin1/C
- test-checkin1/C/fileC
- test-checkin1/D
- test-checkin1/D/fileD
- The relevant portion of public/projects/greek-tree looks like this:
- public/projects/greek-tree/ +
- OWNERS < "user1 \n group: group1"
- A
- A/B
- A/B/OWNERS < "set noparen \n userAB \n userAB2"
- A/B/E
- A/B/F
- A/C/OWNERS < "file" (unsupported for now)
- A/D
- A/D/OWNERS < "groupAD" (missing "group:", so looks like a username)
- A/D/G
- A/D/G/OWNERS < "bad owners syntax ADG" (ignored)
- Depending on which piece of it we try to check in, we trigger different
- allow rules. See below for which users belong to which groups.
- """
- class TestOwners(testing.hooks.common.HookTestCase):
- def setUp(self):
- # HookTestCase creates and sets a _logger object based on whether
- # GVN_TEST_DEBUG is exported or not
- testing.hooks.common.HookTestCase.setUp(self)
- # create group pickle to use as our group file
- user_groups= {
- "user1": [ "group1", "group2", "group3" ],
- "user2": [ "group1", "group2" ],
- "user3": [ "group1" ],
- "user4": [ ],
- "user5": [ "group5" ],
- "userAB2": [ "group1" ],
- "userAD": [ "groupAD" ],
- "adminuser": [ SUPER_GROUP ],
- }
- for user in user_groups:
- self.userdb.WriteUserGroups(user, user_groups[user])
- def testNoOwner(self):
- """check a commit outside of OWNERS controlled tree.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/dir", "user1"), 0)
- def testGoodOwner(self):
- """check an OWNERs commit with correct owner.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "user1"), 0)
- def testUserNotInOwner(self):
- """check an OWNERS commit with incorrect owner.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "baduser"),
- "baduser not authorized in any OWNERS file")
- def testGroupOwner(self):
- """check an OWNERS commit with a group allowed owner (group1).
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "user2"), 0)
- def testBadGroupOwner(self):
- """check an OWNERS commit with an owner in the group file without perms.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "user5"),
- "user5 not authorized in any OWNERS file")
- def testInheritGoodOwner(self):
- """check an inherited OWNERs commit with correct owner.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A", "user1"), 0)
- def testInheritGroupOwner(self):
- """check an inherited OWNERS commit with a group allowed owner (group1).
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A", "user2"), 0)
- def testBadOwnerInherit(self):
- """check an inherited OWNERS commit with a disallowed owner.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A", "baduser"),
- "baduser not authorized in any OWNERS file")
- def testBadGroupOwnerInherit(self):
- """check an inherited OWNERS commit with a group file user without perms.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A", "user5"),
- "user5 not authorized in any OWNERS file")
- def testNoParentGoodOwner(self):
- """check an OWNER inside a file with noparent.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/B", "userAB"), 0)
- def testNoParentOwner(self):
- """check that noparent works for denying users higher up.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/B", "user1"),
- "user1 not authorized in any OWNERS file")
- def testNoParentGroupOwner(self):
- """check that noparent works for denying groups higher up.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/B", "user2"),
- "user2 not authorized in any OWNERS file")
- def testBadGroupSyntax(self):
- """check that group OWNERShip is not granted by group without group prefix.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/D", "userAD"),
- "userAD not authorized in any OWNERS file")
- def testBadOwnerSyntaxGoodUser(self):
- """check that a syntax error in OWNERS doesn't reject an otherwise ok user.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/D/G", "user1"), 0)
- def testBadOwnerSyntaxBadUser(self):
- """check that a syntax error in OWNERS doesn't mistakenly allow a user.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree/A/D/G", "userAD"),
- "userAD not authorized in any OWNERS file")
- def testGvnApprove(self):
- """check an OWNERS commit with incorrect owner but with correct approve.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "baduser", "user1"), 0)
- def testGvnApproveSuperuser(self):
- """check that superuser can approve even though not in OWNERS"""
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "baduser",
- "adminuser"),
- 0)
- def testBadSuperuser(self):
- """check that superuser can't commit when not in OWNERS"""
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree",
- "adminuser", approve_user=None),
- "adminuser not authorized in any OWNERS file")
- def testBadGvnApprove(self):
- """check an OWNERS submit with incorrect owner but with incorrect approve.
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata",
- "public/projects/greek-tree", "baduser", "user4"),
- "baduser not authorized in any OWNERS file")
- def testMixedAllowDisallow(self):
- """do a mixed allowed/disallow submit: user2 ok in /, but not in A/B
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata/test-checkin1",
- "public/projects/greek-tree/A", "user2"),
- "user2 not authorized in any OWNERS file")
- def testMixedAllowDisallow2(self):
- """do a mixed allowed/disallow submit: userAB ok in / & A/B, but not in A/D
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata/test-checkin1",
- "public/projects/greek-tree/A", "userAB"),
- "userAB not authorized in any OWNERS file")
- def testMixedAllow(self):
- """do a dual allow with different files allowed by different OWNERS files
- """
- self.assertHookResult(self._TestPaths(RunHook, "testdata/test-checkin1",
- "public/projects/greek-tree/A", "userAB2"), 0)
- def testGoodOwnerProp(self):
- """check an OWNERs prop set with correct owner and no upper restriction
- """
- self.assertHookResult(self._TestProp(RunHook, "proptest", "propvalue",
- "user1", "public/projects/greek-tree"), 0)
- def testPropUserNotInOwner(self):
- """check an OWNERS propset with incorrect owner.
- """
- self.assertHookResult(self._TestProp(RunHook, "proptest", "propvalue",
- "baduser", "public/projects/greek-tree"),
- "baduser not authorized in any OWNERS file")
- def testPropUserInOwner(self):
- """check an OWNERS propset with correct owner.
- """
- self.assertHookResult(self._TestProp(RunHook, "proptest", "propvalue",
- "userAB", "public/projects/greek-tree/A/B"), 0)
- def testPropUserInParentOwner(self):
- """check propset with correct owner for the parent but not current dir.
-
- This test is a bit tricky, when setting properties on a directory, we
- have special code that checks the OWNERS in that same directory and not
- OWNERS in the parent trees.
- This is why this test is meant to fail.
- """
- self.assertHookResult(self._TestProp(RunHook, "proptest", "propvalue",
- "user1", "public/projects/greek-tree/A/B"),
- "user1 not authorized in any OWNERS file")
- def testSnapshotWithOwners(self):
- """check that a non-OWNER of a project can still snapshot from it
- This is to avoid the following bug:
- 0. trunk/OWNERS forbids me from modifying trunk
- 1. create changebranch from trunk, mail for approval
- - //changes/epg/foo/trunk does not exist, so no OWNERS, so allow
- 2. gvn snap more changes to my changebranch
- - //changes/epg/foo/trunk *does* exist, and so does
- //changes/epg/foo/trunk/OWNERS, so I get locked out!
- """
- # Mock up a HookInfo.
- class mock_userdb:
- def UserInGroup(self, user, group):
- return False
- hi = gvn.hooks.info.HookInfo(['pre-commit', 'unused-repo', 'unused-txn'],
- userdb=mock_userdb())
- hi._author = 'basil'
- hi._head_root = object()
- hi._txn = object()
- # Mock svn.fs.node_prop for hi.project_config's gvn:project search.
- def mock_node_prop(root, path, propname, pool=None):
- return None
- # Mock svn.fs.txn_prop for RunHook's gvn:change check.
- def mock_txn_prop(txn, propname, pool=None):
- return None
- # Mock svn.fs.check_path for RunHook.
- def mock_check_path(root, path, pool=None):
- if path.endswith('OWNERS'):
- return svn.core.svn_node_file
- # Our test modification path is a directory.
- return svn.core.svn_node_dir
- # Mock svn.core.Stream and svn.fs.file_contents to return an
- # OWNERS list excluding our intrepid hacker, basil.
- class mock_Stream:
- def __init__(self, data): self.data = data
- def read(self): return self.data
- def mock_file_contents(root, path, pool=None):
- return 'sybil\n'
- class mock_path_change_t:
- change_kind = svn.fs.path_change_modify
- # Save the originals...
- orig_node_prop = svn.fs.node_prop
- orig_txn_prop = svn.fs.txn_prop
- orig_check_path = svn.fs.check_path
- orig_Stream = svn.core.Stream
- orig_file_contents = svn.fs.file_contents
- try:
- # ...and install the mocks.
- svn.fs.node_prop = mock_node_prop
- svn.fs.txn_prop = mock_txn_prop
- svn.fs.check_path = mock_check_path
- svn.core.Stream = mock_Stream
- svn.fs.file_contents = mock_file_contents
- # First, check that basil cannot submit to the project.
- hi._paths_changed = {'/trunk': mock_path_change_t()}
- self.assertEqual(RunHook(hi, self._logger), 'basil not authorized in'
- ' any OWNERS file for trunk, sorry')
- # Reset for next test.
- hi._prefix_changed = None
- # Now, check that basil can snapshot it.
- hi._paths_changed = {'/changes/basil/test/trunk': mock_path_change_t()}
- self.assertEqual(RunHook(hi, self._logger), 0)
- finally:
- svn.fs.node_prop = orig_node_prop
- svn.fs.txn_prop = orig_txn_prop
- svn.fs.check_path = orig_check_path
- svn.core.Stream = orig_Stream
- svn.fs.file_contents = orig_file_contents