diff --git a/hooks/common/update b/hooks/common/update index 0699540..1048208 100755 --- a/hooks/common/update +++ b/hooks/common/update @@ -53,6 +53,21 @@ $att_acc = 'D' if ( $repos{$ENV{GL_REPO}}{DELETE_IS_D} or $repos{'@all'}{DELETE_ # similarly C for create a branch $att_acc = 'C' if ( $repos{$ENV{GL_REPO}}{CREATE_IS_C} or $repos{'@all'}{CREATE_IS_C} ) and $oldsha eq '0' x 40; +# and now "M" commits. This presents a bit of a problem. All the other +# accesses (W, +, C, D) were mutually exclusive in some sense. Sure a W could +# be a C or a + could be a D but that's by design. A merge commit, however, +# could still be any of the others (except a "D"). + +# so we have to *append* 'M' to $att_acc (if the repo has MERGE_CHECK in +# effect and this push contains a merge inside) +if ( $repos{ $ENV{GL_REPO} }{MERGE_CHECK} or $repos{'@all'}{MERGE_CHECK} ) { + if ( $oldsha eq '0' x 40 or $newsha eq '0' x 40 ) { + warn "ref create/delete ignored for purposes of merge-check\n"; + } else { + $att_acc .= 'M' if `git rev-list -n 1 --merges $oldsha..$newsha` =~ /./; + } +} + my @allowed_refs; # @all repos: see comments in similar code in check_access push @allowed_refs, @ { $repos{$ENV{GL_REPO}}{$ENV{GL_USER}} || [] }; diff --git a/src/gitolite.pm b/src/gitolite.pm index e891766..802e86f 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -234,8 +234,12 @@ sub check_ref { return "$perm $ref $repo $ENV{GL_USER} DENIED by $refex" if $ar->[2] eq '-' and $dry_run; die "$perm $ref $repo $ENV{GL_USER} DENIED by $refex\n" if $ar->[2] eq '-'; + # $ar->[2] can be RW\+?(C|D|CD|DC)?M?. $perm can be W, +, C or + # D, or any of these followed by "M". + ( my $permq = $perm ) =~ s/\+/\\+/; + $permq =~ s/M/.*M/; # as far as *this* ref is concerned we're ok - return $refex if ($ar->[2] =~ /\Q$perm/); + return $refex if ($ar->[2] =~ /$permq/); } return "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru" if $dry_run; die "$perm $ref $repo $ENV{GL_USER} DENIED by fallthru\n"; @@ -721,6 +725,7 @@ sub parse_acl $repos{$dr}{DELETE_IS_D} = 1 if $repos{$r}{DELETE_IS_D}; $repos{$dr}{CREATE_IS_C} = 1 if $repos{$r}{CREATE_IS_C}; $repos{$dr}{NAME_LIMITS} = 1 if $repos{$r}{NAME_LIMITS}; + $repos{$dr}{MERGE_CHECK} = 1 if $repos{$r}{MERGE_CHECK}; # this needs to copy the key-value pairs from RHS to LHS, not just # assign RHS to LHS! However, we want to roll in '@all' configs also # into the actual $repo; there's no need to preserve the distinction diff --git a/src/gl-compile-conf b/src/gl-compile-conf index 910a2a9..2f652ef 100755 --- a/src/gl-compile-conf +++ b/src/gl-compile-conf @@ -163,7 +163,7 @@ sub parse_conf_line s/\bCREAT[EO]R\b/\$creator/g for @{ $repos_p }; } # actual permission line - elsif ($line =~ /^(-|C|R|RW\+?(?:C?D?|D?C?)) (.* )?= (.+)/) + elsif ($line =~ /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/) { my $perms = $1; my @refs; @refs = split( ' ', $2 ) if $2; @@ -223,6 +223,7 @@ sub parse_conf_line # to no longer permit deletes (see update hook) $repos{$repo}{DELETE_IS_D} = 1 if $perms =~ /D/; $repos{$repo}{CREATE_IS_C} = 1 if $perms =~ /RW.*C/; + $repos{$repo}{MERGE_CHECK} = 1 if $perms =~ /M/; # for 2nd level check, store each "ref, perms" pair in order for my $ref (@refs)