(big one!) more than one wildcard may match a repo...

plus it can also be matched by a normal repo line.  In other words, with

    repo foo/bar
        RW  =   u1

    repo foo/..*
        RW  =   u2

user u2 has access to foo/bar (the non-wild does not cause the wild to
be completely ignored any longer)

implementation notes:

    get_memberships:

      - no more highlander ("there can only be one") for patterns in
        @repo_plus
      - return $wild as a space-separated list of matched patterns

    collect_repo_patts:

      - as of the last change to this section of code it appears we
        weren't using the values anyway, but I had forgotten :-)

    repo_rights: (big change: $wild no longer implies $creator present,
    or vice versa)

      - new type of "creator" (like "was_sitaram") is now possible
This commit is contained in:
Sitaram Chamarty 2010-08-08 22:08:46 +05:30
parent a5601970da
commit 79f0a5fd52
2 changed files with 43 additions and 43 deletions

View file

@ -131,8 +131,15 @@ sub collect_repo_patts
chomp ($repo); chomp ($repo);
$repo =~ s(\./(.*)\.git$)($1); $repo =~ s(\./(.*)\.git$)($1);
# the key has to be in the list, since the repo physically exists # the key has to be in the list, since the repo physically exists
my($perm, $creator, $wild) = &repo_rights($repo); # -- my($perm, $creator, $wild) = &repo_rights($repo);
$repo_patts{$repo} = $wild || $repo; # -- $repo_patts{$repo} = $wild || $repo;
# turns out we're not using the value anywhere, so no point wasting
# all those cycles getting all repos' rights, at least until a real
# use for it comes along. But when it does come along, remember that
# $wild is now a space separated list of matching patterns (or empty
# if no wild patterns matched $repo). It is NOT a single value
# anymore!
$repo_patts{$repo} = 1;
} }
return %repo_patts; return %repo_patts;
@ -389,10 +396,6 @@ sub parse_acl
# expand $repo and $gl_user into all possible matching values # expand $repo and $gl_user into all possible matching values
($wild, @repo_plus) = &get_memberships($repo, 1); ($wild, @repo_plus) = &get_memberships($repo, 1);
( @user_plus) = &get_memberships($gl_user, 0); ( @user_plus) = &get_memberships($gl_user, 0);
# XXX testing notes: the above should return just one entry during
# non-BC usage, whether wild or not
die "assert 1 failed" if (@repo_plus > 1 and $repo_plus[-1] ne '@all'
or @repo_plus > 2) and not $GL_BIG_CONFIG;
# the old "convenience copy" thing. Now on steroids :) # the old "convenience copy" thing. Now on steroids :)
@ -544,11 +547,16 @@ sub expand_wild
$wild = &parse_acl($GL_CONF_COMPILED, $repo, $ENV{GL_USER}, "NOBODY", "NOBODY"); $wild = &parse_acl($GL_CONF_COMPILED, $repo, $ENV{GL_USER}, "NOBODY", "NOBODY");
} }
if ($exists and not $wild) { if ($exists) {
$creator = '<gitolite>'; if ($creator and $wild) {
} elsif ($exists) {
# is a wildrepo, and it has already been created
$creator = "($creator)"; $creator = "($creator)";
} elsif ($creator and not $wild) {
# was created wild but then someone (a) removed the pattern
# from, and (b) added the actual reponame to, the config
$creator = "<was_$creator>"
} else {
$creator = "<gitolite>";
}
} else { } else {
# repo didn't exist; C perms need to be filled in # repo didn't exist; C perms need to be filled in
$perm = ( $repos{$repo}{C}{'@all'} ? ' @C' : ( $repos{$repo}{C}{$ENV{GL_USER}} ? ' =C' : ' ' )) if $GL_WILDREPOS; $perm = ( $repos{$repo}{C}{'@all'} ? ' @C' : ( $repos{$repo}{C}{$ENV{GL_USER}} ? ' =C' : ' ' )) if $GL_WILDREPOS;
@ -750,40 +758,39 @@ sub special_cmd
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# given a plain reponame or username, return: # given a plain reponame or username, return:
# - the name itself, plus all the groups it belongs to if $GL_BIG_CONFIG is # - the name itself if it's a user
# set # - the name itself if it's a repo and the repo exists in the config
# OR # plus, if $GL_BIG_CONFIG is set:
# - (for repos) if the name itself doesn't exist in the config, a wildcard # - all the groups the name belongs to
# matching it, plus all the groups that wildcard belongs to (again if # plus, for repos:
# $GL_BIG_CONFIG is set) # - all the wildcards matching it
# plus, if $GL_BIG_CONFIG is set:
# - all the groups those wildcards belong to
# A name can normally appear (repo example) (user example) # A name can normally appear (repo example) (user example)
# - directly (repo foo) (RW = bar) # - directly (repo foo) (RW = bob)
# - (only for repos) as a direct wildcard (repo foo/.*) # - (only for repos) as a direct wildcard (repo foo/.*)
# but if $GL_BIG_CONFIG is set, it can also appear: # but if $GL_BIG_CONFIG is set, it can also appear:
# - indirectly (@g = foo; repo @g) (@ug = bar; RW = @ug)) # - indirectly (@g = foo; repo @g) (@ug = bob; RW = @ug))
# - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g). # - (only for repos) as an indirect wildcard (@g = foo/.*; repo @g).
# things that may not be obvious from the above: # note: the wildcard stuff does not apply to username memberships
# - the wildcard stuff does not apply to username memberships
# - for repos, wildcard appearances are TOTALLY ignored if a non-wild
# appearance (direct or indirect) exists
sub get_memberships { sub get_memberships {
my $base = shift; # reponame or username my $base = shift; # reponame or username
my $is_repo = shift; # some true value means a repo name has been passed my $is_repo = shift; # some true value means a repo name has been passed
my $wild = ''; my $wild = ''; # will be a space-sep list of matching patterns
my (@ret, @ret_w); # maintain wild matches separately from non-wild my @ret; # list of matching groups/patterns
# direct # direct
push @ret, $base if not $is_repo or exists $repos{$base}; push @ret, $base if not $is_repo or exists $repos{$base};
if ($is_repo and $GL_WILDREPOS and not @ret) { if ($is_repo and $GL_WILDREPOS) {
for my $i (sort keys %repos) { for my $i (sort keys %repos) {
if ($base =~ /^$i$/) { next if $i eq $base; # "direct" name already done; skip
die "$ABRT $base matches $wild AND $i\n" if $wild and $wild ne $i;
$wild = $i;
# direct wildcard # direct wildcard
push @ret_w, $i; if ($base =~ /^$i$/) {
push @ret, $i;
$wild = ($wild ? "$wild $i" : $i);
} }
} }
} }
@ -794,11 +801,10 @@ sub get_memberships {
if ($base eq $i) { if ($base eq $i) {
# indirect # indirect
push @ret, $g; push @ret, $g;
} elsif ($is_repo and $GL_WILDREPOS and not @ret and $base =~ /^$i$/) { } elsif ($is_repo and $GL_WILDREPOS and $base =~ /^$i$/) {
die "$ABRT $base matches $wild AND $i\n" if $wild and $wild ne $i;
$wild = $i;
# indirect wildcard # indirect wildcard
push @ret_w, $g; push @ret, $g;
$wild = ($wild ? "$wild $i" : $i);
} }
} }
} }
@ -813,14 +819,9 @@ sub get_memberships {
return (@ret); return (@ret);
} }
# enforce the rule about ignoring all wildcard matches if a non-wild match # note that there is an extra return value when called for repos (as
# exists while returning. (The @ret gating above does not adequately # opposed to being called for usernames)
# ensure this, it is only an optimisation). return ($wild, @ret);
#
# Also note that there is an extra return value when called for repos
# (compared to usernames)
return ((@ret ? '' : $wild), (@ret ? @ret : @ret_w));
} }
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------

View file

@ -513,7 +513,6 @@ my %projlist = ();
# for each real repo (and remember this will be empty, thus skipping all this, # for each real repo (and remember this will be empty, thus skipping all this,
# if $GL_NO_DAEMON_NO_GITWEB is on!) # if $GL_NO_DAEMON_NO_GITWEB is on!)
for my $repo (keys %repo_patts) { for my $repo (keys %repo_patts) {
my $repo_patt = $repo_patts{$repo};
wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git"); wrap_chdir("$ENV{GL_REPO_BASE_ABS}/$repo.git");