[PATCH - BACL] Branch access control extension
Elifarley Callado Coelho Cruz
elifarley at gmail.com
Mon Apr 12 15:22:44 CDT 2010
The BACL hook makes it possible to allow or deny write access to named
branches of a repository when receiving incoming changesets.
This functionality is found on Subversion, so users migrating from it
may find it useful.
Example configuration:
[bacl]
sources = serve
# check if source of incoming changes in this list
# ("serve" == ssh or http, "push", "pull", "bundle")
[bacl.allow]
#branch-a = user-1, user-2, user-3
#branch-b = user-1
#* = super-user
#branch-for-tests = *
[bacl.deny]
#frozen-branch = *
#* = bad-user
---------------------------------------
# HG changeset patch
# User Elifarley Callado Coelho Cruz <elifarley at gmail.com>
# Date 1271103110 10800
# Node ID 7d74df0a1c99e824def8e4ebd003bd0175a8ee50
# Parent bbf496db07668450aa342186eebde13cebd86e4c
Created bacl - branch access control for mercurial.
diff --git a/hgext/bacl.py b/hgext/bacl.py
new file mode 100644
--- /dev/null
+++ b/hgext/bacl.py
@@ -0,0 +1,82 @@
+# bacl.py - branch access control for mercurial
+#
+# Copyright 2010 Elifarley Cruz <elifarley at gmail.com>
+# Based on acl.py by Vadim Gelfer <vadim.gelfer at gmail.com>
+
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''hooks for controlling branch access
+
+This hook makes it possible to allow or deny write access to named branches
+of a repository when receiving incoming changesets.
+
+Example configuration:
+
+[bacl]
+sources = serve
+# check if source of incoming changes in this list
+# ("serve" == ssh or http, "push", "pull", "bundle")
+
+[bacl.allow]
+#branch-a = user-1, user-2, user-3
+#branch-b = user-1
+#* = super-user
+#branch-for-tests = *
+
+[bacl.deny]
+#frozen-branch = *
+#* = bad-user
+
+'''
+
+from mercurial.i18n import _
+from mercurial import util, match
+import getpass, urllib
+
+def buildmatch(ui, user, key):
+ '''return tuple of (match function, list enabled).'''
+ if not ui.has_section(key):
+ ui.debug('bacl: "%s" not enabled\n' % key)
+ return None
+
+ branches = [branch for branch, users in ui.configitems(key)
+ if users == '*' or user in users.replace(',', ' ').split()]
+ ui.debug('bacl: "%s" enabled, %d entries for user "%s"\n' %
+ (key, len(branches), user))
+ if branches:
+ return lambda b: '*' in branches or b in branches
+ return lambda b: False
+
+def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
+ if hooktype not in ['pretxnchangegroup', 'pretxncommit']:
+ raise util.Abort(_('config error - hook type "%s" cannot stop '
+ 'incoming changesets nor commits') % hooktype)
+ if 'pretxnchangegroup' == hooktype and source not in
ui.config('bacl', 'sources', 'serve').split():
+ ui.debug('bacl: changes have source "%s" - skipping\n' % source)
+ return
+
+ user = None
+ if source == 'serve' and 'url' in kwargs:
+ url = kwargs['url'].split(':')
+ if url[0] == 'remote' and url[1].startswith('http'):
+ user = urllib.unquote(url[3])
+ ui.debug('bacl: got user "%s" from url.\n' % user)
+
+ if user is None:
+ user = getpass.getuser()
+ ui.debug('bacl: got user "%s" from getpass.\n')
+
+ cfg = ui.config('bacl', 'config')
+ if cfg:
+ ui.readconfig(cfg, sections = ['bacl.allow', 'bacl.deny'])
+ allow = buildmatch(ui, user, 'bacl.allow')
+ deny = buildmatch(ui, user, 'bacl.deny')
+
+ for rev in xrange(repo[node], len(repo)):
+ branch = repo[rev].branch()
+ if deny and deny(branch):
+ raise util.Abort(_('bacl: user "%s" denied on branch
"%s"') % (user, branch))
+ if allow and not allow(branch):
+ raise util.Abort(_('bacl: user "%s" not allowed on branch
"%s"') % (user, branch))
+ ui.debug('bacl: allowing user "%s" on branch "%s"\n' % (user, branch))
---------------------------------------
More information about the Mercurial-devel
mailing list