[PATCH 1 of 2] acl: add support for branch-based access control
elifarley at gmail.com
elifarley at gmail.com
Sat May 1 03:09:07 UTC 2010
hgext/acl.py | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 77 insertions(+), 15 deletions(-)
# HG changeset patch
# User Elifarley Callado Coelho Cruz <elifarley at gmail.com>
# Date 1272682174 10800
# Node ID e0e1b2b42e3a1e5a003ae6701232109690fa6d07
# Parent bf7e63fedca12ab725af8a5cb0d0eced403bc7ec
acl: add support for branch-based access control
diff --git a/hgext/acl.py b/hgext/acl.py
--- a/hgext/acl.py
+++ b/hgext/acl.py
@@ -7,9 +7,9 @@
'''hooks for controlling repository access
-This hook makes it possible to allow or deny write access to portions
-of a repository when receiving incoming changesets via pretxnchangegroup and
-pretxncommit.
+This hook makes it possible to allow or deny write access to given branches and
+paths of a repository when receiving incoming changesets via pretxnchangegroup
+and pretxncommit.
The authorization is matched based on the local user name on the
system where the hook runs, and not the committer of the original
@@ -22,12 +22,34 @@
Nor is it safe if remote users share an account, because then there
is no way to distinguish them.
-The deny list is checked before the allow list is.
+The order in which access checks are performed is:
+1) Deny list for branches (section [acl.deny.branches])
+2) Allow list for branches (section [acl.allow.branches])
+3) Deny list for paths (section [acl.deny])
+4) Allow list for paths (section [acl.allow])
-The allow and deny sections take key-value pairs, having a subtree pattern
-as key (with a glob syntax by default). The corresponding value can be either:
-1) an asterisk, to match everyone;
-2) a comma-separated list containing users and groups.
+The allow and deny sections take key-value pairs.
+
+--- Branch-based Access Control ---
+
+Use the [acl.deny.branches] and [acl.allow.branches] sections to have
+branch-based access control.
+
+Keys in these sections can be either:
+1) a branch name
+2) an asterisk, to match any branch;
+
+The corresponding values can be either:
+1) a comma-separated list containing users and groups.
+2) an asterisk, to match anyone;
+
+--- Path-based Access Control ---
+
+Use the [acl.deny] and [acl.allow] sections to have path-based access control.
+Keys in these sections accept a subtree pattern (with a glob syntax by default).
+The corresponding values follow the same syntax as the other sections above.
+
+--- Groups ---
Group names must be prefixed with an @ symbol.
Specifying a group name has the same effect as specifying all the users in
@@ -35,10 +57,7 @@
The set of users for a group is taken from "grp.getgrnam"
(see http://docs.python.org/library/grp.html#grp.getgrnam).
-To use this hook, configure the acl extension in your hgrc like this:
-
- [extensions]
- acl =
+--- Example Configuration ---
[hooks]
@@ -54,9 +73,30 @@
# ("serve" == ssh or http, "push", "pull", "bundle")
sources = serve
+ [acl.deny.branches]
+
+ # Everyone is denied to the frozen branch:
+ frozen-branch = *
+
+ # A bad user is denied on all branches:
+ * = bad-user
+
+ [acl.allow.branches]
+
+ # A few users are allowed on branch-a:
+ branch-a = user-1, user-2, user-3
+
+ # Only one user is allowed on branch-b:
+ branch-b = user-1
+
+ # The super user is allowed on any branch:
+ * = super-user
+
+ # Everyone is allowed on branch-for-tests:
+ branch-for-tests = *
+
[acl.deny]
- # This list is checked first. If a match is found, 'acl.allow' will not be
- # checked.
+ # If a match is found, 'acl.allow' will not be checked.
# if acl.deny is not present, no users denied by default
# empty acl.deny = all users allowed
# Format for both lists: glob pattern = user4, user5, @group1
@@ -121,6 +161,12 @@
if _usermatch(user, users)]
ui.debug('acl: %s enabled, %d entries for user %s\n' %
(key, len(pats), user))
+
+ if not repo:
+ if pats:
+ return lambda b: '*' in pats or b in pats
+ return lambda b: False
+
if pats:
return match.match(repo.root, '', pats)
return match.exact(repo.root, '', [])
@@ -146,12 +192,28 @@
cfg = ui.config('acl', 'config')
if cfg:
- ui.readconfig(cfg, sections = ['acl.allow', 'acl.deny'])
+ ui.readconfig(cfg, sections = ['acl.allow.branches', 'acl.deny.branches',
+ 'acl.allow', 'acl.deny'])
+
+ allowbranches = buildmatch(ui, None, user, 'acl.allow.branches')
+ denybranches = buildmatch(ui, None, user, 'acl.deny.branches')
allow = buildmatch(ui, repo, user, 'acl.allow')
deny = buildmatch(ui, repo, user, 'acl.deny')
for rev in xrange(repo[node], len(repo)):
ctx = repo[rev]
+ branch = ctx.branch()
+ if denybranches and denybranches(branch):
+ raise util.Abort(_('acl: user "%s" denied on branch "%s"'
+ ' (changeset "%s")')
+ % (user, branch, ctx))
+ if allowbranches and not allowbranches(branch):
+ raise util.Abort(_('acl: user "%s" not allowed on branch "%s"'
+ ' (changeset "%s")')
+ % (user, branch, ctx))
+ ui.debug('acl: branch access granted: "%s" on branch "%s"\n'
+ % (ctx, branch))
+
for f in ctx.files():
if deny and deny(f):
ui.debug('acl: user %s denied on %s\n' % (user, f))
More information about the Mercurial-devel
mailing list