diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
commit | 458120dd40db6b4df55a4e96b650e16798ef06a0 (patch) | |
tree | 8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/hg/hgext/acl.py | |
parent | 3a742c699f6806c1145aea5149bf15de15a0afd7 (diff) |
add hg and python
Diffstat (limited to 'sys/src/cmd/hg/hgext/acl.py')
-rw-r--r-- | sys/src/cmd/hg/hgext/acl.py | 107 |
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) |