diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-07-31 00:16:34 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-07-31 00:16:34 +0300 |
commit | 6c604cdf5bb45a6a3d58f1f2eb985622ed39248a (patch) | |
tree | 54fd6a88949ba4b69bf866c41434e6291f01747f | |
parent | 99b83be1159294d7e05a9630b9b4babab52836e1 (diff) | |
download | gitaclhook-6c604cdf5bb45a6a3d58f1f2eb985622ed39248a.tar.gz gitaclhook-6c604cdf5bb45a6a3d58f1f2eb985622ed39248a.tar.bz2 |
Optionally test filenames of the files changed by the commit.
* gitacl.schema (gitAclTree): New attribute.
* gitaclhook: Document changes.
Accept four or more arguments in test mode.
* lib/GitACL.pm (git_values): New function.
(match_tree): New function.
(match_tuple): Match path pattern, if supplied.
(new): Fix initialization of the debug member.
Get remote IP address from the socket, if no envar
is defined. Default to 127.0.0.1.
* lib/GitACL/File.pm (check_acl): Allow up to 6 fields in
an ACL line.
* lib/GitACL/LDAP.pm: Get path pattern from the gitAclTree
attribute.
-rw-r--r-- | gitacl.schema | 9 | ||||
-rwxr-xr-x | gitaclhook | 31 | ||||
-rw-r--r-- | lib/GitACL.pm | 61 | ||||
-rw-r--r-- | lib/GitACL/File.pm | 2 | ||||
-rw-r--r-- | lib/GitACL/LDAP.pm | 2 |
5 files changed, 93 insertions, 12 deletions
diff --git a/gitacl.schema b/gitacl.schema index d8083e5..a9098d4 100644 --- a/gitacl.schema +++ b/gitacl.schema @@ -43,2 +43,8 @@ attributetype ( 1.3.6.1.4.1.9163.2.3.1.5 NAME 'gitAclUser' +attributetype ( 1.3.6.1.4.1.9163.2.3.1.6 NAME 'gitAclTree' + DESC 'Git subtree' + EQUALITY caseExactMatch + SUBSTR caseExactSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + objectclass ( 1.3.6.1.4.1.9163.2.3.2.0 NAME 'gitACL' @@ -47,3 +53,4 @@ objectclass ( 1.3.6.1.4.1.9163.2.3.2.0 NAME 'gitACL' MUST ( cn $ gitAclProject $ gitAclVerb ) - MAY ( gitAclUser $ gitAclOp $ gitAclRef $ gitAclOrder $ description ) ) + MAY ( gitAclUser $ gitAclOp $ gitAclRef $ gitAclOrder $ + gitAclTree $ description ) ) @@ -21,3 +21,3 @@ use Pod::Usage; use Getopt::Long qw(:config gnu_getopt no_ignore_case); - + =head1 NAME @@ -30,3 +30,3 @@ B<gitaclhook> I<refname> I<old-sha1> I<new-sha1> -B<gitacthook> [B<--debug>] B<--test> I<REPO> I<USER> I<OP> I<REF> +B<gitacthook> [B<--debug>] B<--test> I<REPO> I<USER> I<OP> I<REF> [I<FILE>...] @@ -67,3 +67,3 @@ Non-empty lines introduce ACL rules. The syntax is: -I<VERB> I<PROJECT> I<USER> [I<OP> I<REF>] +I<VERB> I<PROJECT> I<USER> [I<OP> I<REF> [I<PATH>]] @@ -144,2 +144,8 @@ Otherwise, it must match exactly the affected ref. +=item I<PATH> + +Pathname pattern. If present, the names of all files affected by the commit +must match it in order for the rule to apply. Matching algorithm is the same +as for I<REF>. + =back @@ -151,3 +157,7 @@ which is being updated and the user who requests the update, its I<OP> contains the opcode of the requested operation and I<REF> matches the affected -ref. Missing I<REF> and/or I<OP> are treated as a match. +ref. If I<PATH> is present each file changed by the commit is compared with +it and removed from the list if it matches. The rule applies only if the +list of files becomes empty. + +Missing I<REF>, I<OP> and I<PATH> are treated as a match. @@ -205,2 +215,6 @@ The list of operation codes. Git ref. + +=item B<gitAclPath> [optional] + +Pathname pattern. @@ -289,3 +303,4 @@ lists from the command line. The syntax is: B<gitacthook> [B<--debug>] [B<-d>] B<--test> I<REPO> I<USER> I<OP> I<REF> - + [I<FILE>...] + =back @@ -293,3 +308,4 @@ B<gitacthook> [B<--debug>] [B<-d>] B<--test> I<REPO> I<USER> I<OP> I<REF> I<REPO> is a pathname of the repository to test, I<USER> is the username, -I<OP> is the operation code and I<REF> is the reference. +I<OP> is the operation code and I<REF> is the reference. Optional I<FILE> +arguments supply names of the files changed by the commit. @@ -360,3 +376,3 @@ unless ($ENV{GIT_DIR}) { if ($test) { - abend("--test requires four arguments") unless ($#ARGV == 3); + abend("--test requires four or more arguments") unless ($#ARGV >= 3); $args{git_dir} = $ENV{GIT_DIR} = $ARGV[0]; @@ -365,2 +381,3 @@ unless ($ENV{GIT_DIR}) { $args{ref} = $ARGV[3]; + $args{files} = [@ARGV[4..$#ARGV]] if ($#ARGV > 3); $args{old} = '0000000000000000000000000000000000000000'; diff --git a/lib/GitACL.pm b/lib/GitACL.pm index d3f6b35..f7743d5 100644 --- a/lib/GitACL.pm +++ b/lib/GitACL.pm @@ -19,2 +19,3 @@ package GitACL; use strict; +use feature "state"; use File::Spec; @@ -101,2 +102,12 @@ sub get_project_name($) { +sub git_values(@) { + my $fd; + + open($fd,'-|','git',@_); + local $_; + my @ret = map { chomp; $_; } <$fd>; + close($fd); + return @ret; +} + sub git_value(@) { @@ -155,2 +166,34 @@ sub match_ref($$) { +sub match_tree($$) { + my ($self, $expr) = @_; + state @tree; + state $init; + + unless (defined($init)) { + if (defined($self->{files})) { + @tree = @{$self->{files}}; + } else { + @tree = git_values("diff-tree", + "--no-commit-id", "--name-only", "-r", + $self->{new}); + } + $init = 1; + } + + for (my $i = 0; $i <= $#tree; ) { + my $dir = $tree[$i]; + + if (($expr =~ /^\^/ and $dir =~ /$expr/) + or ($expr =~ /\/$/ + and ("$dir/" eq $expr or index($dir, $expr) == 0)) + or $dir eq $expr) { + splice(@tree, $i, 1); + } else { + ++$i; + } + } + + return $#tree == -1; +} + sub match_tuple($$) { @@ -159,3 +202,3 @@ sub match_tuple($$) { - return ( \&deny, "malformed line" ) unless $#x >= 2; + return ( \&deny, "malformed line: " . join(' ', @x) ) unless $#x >= 2; return ( \&deny, "unknown keyword" ) @@ -170,3 +213,5 @@ sub match_tuple($$) { return ( 0, "ref mismatch" ) - if ($#x == 4 && !$self->match_ref($x[4])); + if ($#x >= 4 && !$self->match_ref($x[4])); + return ( 0, "tree mismatch" ) + if ($#x == 5 && !$self->match_tree($x[5])); if ($x[0] eq 'allow') { @@ -203,3 +248,3 @@ sub new { } else { - $obj->{debug} = git_value('config', '--bool', 'hooks.acl.debug') || + $obj->{debug} = git_value('config', '--int', 'hooks.acl.debug') || $ENV{GIT_UPDATE_DEBUG} > 0; @@ -239,2 +284,10 @@ sub new { $obj->{ip} = $a[0]; + } else { + my $sa = getpeername(STDIN); + if ($sa) { + my ($port, $addr) = sockaddr_in($sa); + $obj->{ip} = inet_ntoa($addr); + } else { + $obj->{ip} = "127.0.0.1"; + } } @@ -271,2 +324,4 @@ sub new { } + + $obj->{files} = $args{files} if defined($args{files}); diff --git a/lib/GitACL/File.pm b/lib/GitACL/File.pm index f72c16d..423efea 100644 --- a/lib/GitACL/File.pm +++ b/lib/GitACL/File.pm @@ -38,3 +38,3 @@ sub check_acl { next if ($_ eq ""); - my @x = split(/\s+/, $_, 5); + my @x = split(/\s+/, $_, 6); diff --git a/lib/GitACL/LDAP.pm b/lib/GitACL/LDAP.pm index ac8fd06..b219efa 100644 --- a/lib/GitACL/LDAP.pm +++ b/lib/GitACL/LDAP.pm @@ -95,2 +95,4 @@ sub check_acl($) { if $ent->exists('gitAclRef'); + push(@x, $ent->get_value('gitAclTree')) + if $ent->exists('gitAclTree'); |