wildrepos: teach auth and update hook about wildcard repos

- new_repo now takes a "creater" parameter; if given, this user is
    recorded (in a file called "gl-creater") as the creater of the repo.
    Only applicable to wildcards

  - repo_rights reads "gl-creater" and "gl-perms" to tell you who
    created it, and whether you (the $user) are in the list of READERS
    or WRITERS

    **NOTE** that the mechanism to create/update gl-perms has not been
    written yet... (as of this commit)

  - parse_acl takes 4 more arguments, all optional.  The repo name we're
    interested in (set by all except the access reporting function), and
    the names to be interpolated as $creater, $readers, writers

  - report_basic now knows about the "C" permission and shows it

  - auth now autovivifies a repo if the user has "C" and it's a wildcard
    match, or (the old case) the user has "W" and it's not a wildcard.
    In the former case, the creater is also set

IMPLEMENTATION NOTES:

  - the Dumper code now uses a custom hash key sort to make sure
    $creater etc land up at the *end*

  - a wee bit of duplication exists in the update hook; it borrows a
    little code from parse_acl.  I dont (yet) want to include all of
    gitolite.pm for that little piece...
This commit is contained in:
Sitaram Chamarty 2009-12-05 22:39:56 +05:30
parent 77306567e9
commit f49eddd660
4 changed files with 121 additions and 24 deletions

View file

@ -81,7 +81,7 @@ sub where_is_rc
# NOTE: this sub will change your cwd; caller beware!
sub new_repo
{
my ($repo, $hooks_dir) = @_;
my ($repo, $hooks_dir, $creater) = @_;
umask($REPO_UMASK);
@ -89,19 +89,81 @@ sub new_repo
# erm, note that's "and die" not "or die" as is normal in perl
wrap_chdir("$repo.git");
system("git --bare init >&2");
system("echo $creater > gl-creater") if $creater;
# propagate our own, plus any local admin-defined, hooks
system("cp $hooks_dir/* hooks/");
chmod 0755, "hooks/update";
}
# ----------------------------------------------------------------------------
# metaphysics (like, "is there a god?", "who created me?", etc)
# ----------------------------------------------------------------------------
# "who created this repo", "am I on the R list", and "am I on the RW list"?
sub repo_rights
{
my ($repo_base_abs, $repo, $user) = @_;
# creater
my $c = '';
if ( -f "$repo_base_abs/$repo.git/gl-creater") {
my $fh = wrap_open("<", "$repo_base_abs/$repo.git/gl-creater");
chomp($c = <$fh>);
}
# $user's R and W rights
my ($r, $w); $r = ''; $w = '';
if ($user and -f "$repo_base_abs/$repo.git/gl-perms") {
my $fh = wrap_open("<", "$repo_base_abs/$repo.git/gl-perms");
my $perms = join ("", <$fh>);
if ($perms) {
$r = $user if $perms =~ /^\s*R(?=\s).*\s$user(\s|$)/m;
$w = $user if $perms =~ /^\s*RW(?=\s).*\s$user(\s|$)/m;
}
}
return ($c, $r, $w);
}
# ----------------------------------------------------------------------------
# parse the compiled acl
# ----------------------------------------------------------------------------
sub parse_acl
{
my $GL_CONF_COMPILED = shift;
# IMPLEMENTATION NOTE: a wee bit of this is duplicated in the update hook;
# please update that also if the interface or the env vars change
my ($GL_CONF_COMPILED, $repo, $c, $r, $w) = @_;
# void $r if same as $w (otherwise "readers" overrides "writers"; this is
# the same problem that needed a sort sub for the Dumper in the compile
# script, but localised to just $readers and $writers)
$r = "" if $r eq $w;
# set up the variables for a parse to interpolate stuff from the dumped
# hash (remember the selective conversion of single to double quotes?).
# if they're not passed in, then we look for an env var of that name, else
# we default to "NOBODY" (we hope there isn't a real user called NOBODY!)
# And in any case, we set those env vars so level 2 can redo the last
# parse without any special code
our $creater = $ENV{GL_CREATER} = $c || $ENV{GL_CREATER} || "NOBODY";
our $readers = $ENV{GL_READERS} = $r || $ENV{GL_READERS} || "NOBODY";
our $writers = $ENV{GL_WRITERS} = $w || $ENV{GL_WRITERS} || "NOBODY";
die "parse $GL_CONF_COMPILED failed: " . ($! or $@) unless do $GL_CONF_COMPILED;
# access reporting doesn't send $repo, and doesn't need to
return unless $repo;
return $ENV{GL_REPOPATT} = "" if $repos{$repo};
my @matched = grep { $repo =~ /^$_$/ } sort keys %repos;
die "$repo has no matches\n" unless @matched;
die "$repo has multiple matches\n@matched\n" if @matched > 1;
# found exactly one pattern that matched, copy its ACL
$repos{$repo} = $repos{$matched[0]};
# and return the pattern
return $ENV{GL_REPOPATT} = $matched[0];
}
# ----------------------------------------------------------------------------
@ -114,16 +176,18 @@ sub report_basic
{
my($GL_ADMINDIR, $GL_CONF_COMPILED, $user) = @_;
&parse_acl($GL_CONF_COMPILED);
&parse_acl($GL_CONF_COMPILED, "", "CREATER", "READERS", "WRITERS");
# send back some useful info if no command was given
print "hello $user, the gitolite version here is ";
system("cat", "$GL_ADMINDIR/src/VERSION");
print "\ryou have the following permissions:\n\r";
for my $r (sort keys %repos) {
my $perm .= ( $repos{$r}{R}{'@all'} ? ' @' : ( $repos{$r}{R}{$user} ? ' R' : '' ) );
$perm .= ( $repos{$r}{W}{'@all'} ? ' @' : ( $repos{$r}{W}{$user} ? ' W' : '' ) );
print "$perm\t$r\n\r" if $perm;
my $perm .= ( $repos{$r}{C}{'@all'} ? ' @' : ( $repos{$r}{C}{$user} ? ' C' : ' ' ) );
$perm .= ( $repos{$r}{R}{'@all'} ? ' @' : ( $repos{$r}{R}{$user} ? ' R' : ' ' ) );
$perm .= ( $repos{$r}{W}{'@all'} ? ' @' : ( $repos{$r}{W}{$user} ? ' W' : ' ' ) );
print "$perm\t$r\n\r" if $perm =~ /\S/;
}
}
1;