summaryrefslogtreecommitdiff
path: root/sys/src/cmd/hg/hgext/acl.py
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
commit458120dd40db6b4df55a4e96b650e16798ef06a0 (patch)
tree8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/hg/hgext/acl.py
parent3a742c699f6806c1145aea5149bf15de15a0afd7 (diff)
add hg and python
Diffstat (limited to 'sys/src/cmd/hg/hgext/acl.py')
-rw-r--r--sys/src/cmd/hg/hgext/acl.py107
1 files changed, 107 insertions, 0 deletions
diff --git a/sys/src/cmd/hg/hgext/acl.py b/sys/src/cmd/hg/hgext/acl.py
new file mode 100644
index 000000000..f9b3927af
--- /dev/null
+++ b/sys/src/cmd/hg/hgext/acl.py
@@ -0,0 +1,107 @@
+# acl.py - changeset access control for mercurial
+#
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2, incorporated herein by reference.
+#
+
+'''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.
+
+The authorization is matched based on the local user name on the
+system where the hook runs, and not the committer of the original
+changeset (since the latter is merely informative).
+
+The acl hook is best used along with a restricted shell like hgsh,
+preventing authenticating users from doing anything other than
+pushing or pulling. The hook is not safe to use if users have
+interactive shell access, as they can then disable the hook.
+Nor is it safe if remote users share an account, because then there
+is no way to distinguish them.
+
+To use this hook, configure the acl extension in your hgrc like this::
+
+ [extensions]
+ hgext.acl =
+
+ [hooks]
+ pretxnchangegroup.acl = python:hgext.acl.hook
+
+ [acl]
+ # Check whether the source of incoming changes is in this list
+ # ("serve" == ssh or http, "push", "pull", "bundle")
+ sources = serve
+
+The allow and deny sections take a subtree pattern as key (with a glob
+syntax by default), and a comma separated list of users as the
+corresponding value. The deny list is checked before the allow list
+is. ::
+
+ [acl.allow]
+ # If acl.allow is not present, all users are allowed by default.
+ # An empty acl.allow section means no users allowed.
+ docs/** = doc_writer
+ .hgtags = release_engineer
+
+ [acl.deny]
+ # If acl.deny is not present, no users are refused by default.
+ # An empty acl.deny section means all users allowed.
+ glob pattern = user4, user5
+ ** = user6
+'''
+
+from mercurial.i18n import _
+from mercurial import util, match
+import getpass, urllib
+
+def buildmatch(ui, repo, user, key):
+ '''return tuple of (match function, list enabled).'''
+ if not ui.has_section(key):
+ ui.debug(_('acl: %s not enabled\n') % key)
+ return None
+
+ pats = [pat for pat, users in ui.configitems(key)
+ if user in users.replace(',', ' ').split()]
+ ui.debug(_('acl: %s enabled, %d entries for user %s\n') %
+ (key, len(pats), user))
+ if pats:
+ return match.match(repo.root, '', pats)
+ return match.exact(repo.root, '', [])
+
+
+def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
+ if hooktype != 'pretxnchangegroup':
+ raise util.Abort(_('config error - hook type "%s" cannot stop '
+ 'incoming changesets') % hooktype)
+ if source not in ui.config('acl', 'sources', 'serve').split():
+ ui.debug(_('acl: 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])
+
+ if user is None:
+ user = getpass.getuser()
+
+ cfg = ui.config('acl', 'config')
+ if cfg:
+ ui.readconfig(cfg, sections = ['acl.allow', 'acl.deny'])
+ 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]
+ for f in ctx.files():
+ if deny and deny(f):
+ ui.debug(_('acl: user %s denied on %s\n') % (user, f))
+ raise util.Abort(_('acl: access denied for changeset %s') % ctx)
+ if allow and not allow(f):
+ ui.debug(_('acl: user %s not allowed on %s\n') % (user, f))
+ raise util.Abort(_('acl: access denied for changeset %s') % ctx)
+ ui.debug(_('acl: allowing changeset %s\n') % ctx)