diff options
author | Sitaram Chamarty <sitaram@atc.tcs.com> | 2013-03-03 18:56:41 +0530 |
---|---|---|
committer | Sitaram Chamarty <sitaram@atc.tcs.com> | 2013-03-05 11:55:59 +0530 |
commit | 79714c9c85d1321e6f4b0b3a3617bdb3503a98e1 (patch) | |
tree | 6347f476fb3e95ab08e7867279c8c97037f73af4 | |
parent | rc file format change: some inline doc/help text fixups (diff) | |
download | gitolite-gentoo-79714c9c85d1321e6f4b0b3a3617bdb3503a98e1.tar.gz gitolite-gentoo-79714c9c85d1321e6f4b0b3a3617bdb3503a98e1.tar.bz2 gitolite-gentoo-79714c9c85d1321e6f4b0b3a3617bdb3503a98e1.zip |
refex-expr
-rwxr-xr-x | src/VREF/refex-expr | 104 | ||||
-rw-r--r-- | src/lib/Gitolite/Rc.pm | 3 | ||||
-rw-r--r-- | src/lib/Gitolite/Triggers/RefexExpr.pm | 2 | ||||
-rw-r--r-- | src/syntactic-sugar/refex-expr | 39 | ||||
-rwxr-xr-x | t/refex-expr-test-1 | 62 | ||||
-rwxr-xr-x | t/refex-expr-test-2 | 60 | ||||
-rwxr-xr-x | t/refex-expr-test-3 | 55 | ||||
-rwxr-xr-x | t/refex-expr-test-9 | 107 |
8 files changed, 390 insertions, 42 deletions
diff --git a/src/VREF/refex-expr b/src/VREF/refex-expr index d0a51b7..8403469 100755 --- a/src/VREF/refex-expr +++ b/src/VREF/refex-expr @@ -2,6 +2,9 @@ use strict; use warnings; +# see bottom of this file for instructons and IMPORTANT WARNINGS! +# ---------------------------------------------------------------------- + my $rule = $ARGV[7]; die "\n\nFATAL: GL_REFEX_EXPR_ doesn't exist\n(your admin probably forgot the rc file change needed for this to work)\n\n" unless exists $ENV{"GL_REFEX_EXPR_" . $rule}; @@ -12,64 +15,85 @@ exit 0; __END__ -Documentation for the refex-expression evaluation feature +------------------------------------------------------------------------ +IMPORTANT WARNINGS: + * has not been tested heavily + * SO PLEASE TEST YOUR SPECIFIC USE CASE THOROUGHLY! + * read the NOTES section below + * syntax and semantics are to be considered beta and may change as I find + better use cases +------------------------------------------------------------------------ -First, make sure you have both the VREF and the trigger scripts -(src/VREF/refex-expr and src/lib/Gitolite/Triggers/RefexExpr.pm) +Refex expressions, like VREFs, are best used as additional "deny" rules, to +deny combinations that the normal ruleset cannot detect. -Next, add this to the ACCESS_2 list in the rc file: +To enable this, uncomment 'refex-expr' in the ENABLE list in the rc file. - 'RefexExpr::access_2', +It allows you to say things like "don't allow users u3 and u4 to change the +Makefile in the master branch" (i.e., they can change any other file in +master, or the Makefile in any other branch, but not that specific combo). -For the rest, we'll use this example: + repo foo + RW+ = u1 u2 # line 1 - * user u1 can push foo to some other branch, and anything else to the master - branch, but not foo to the master branch + RW+ master = u3 u4 # line 2 + RW+ = u3 u4 # line 3 + RW+ VREF/NAME/Makefile = u3 u4 # line 4 + - master and VREF/NAME/Makefile = u3 u4 # line 5 - * user u2 is allowed to push either 'doc/' or 'src/' but not both +Line 5 is a "refex expression". Here are the rules: + + * for each refex in the expression ("master" and "VREF/NAME/Makefile" in + this example), a count is kept of the number of times the EXACT refex was + matched and allowed in the *normal* rules (here, lines 2 and 4) during + this push. -Here's the conf file extract: + * the expression is evaluated based on these counts. 0 is false, and + any non-zero is true (see more examples later). The truth value of the + expression determines whether the refex expression matched. - repo testing - RW+ master = u1 # line 1 - RW+ = @all # line 2 + You can use any logical or arithmetic expression using refexes as operands + and using these operators: - RW+ VREF/NAME/foo = u1 - RW+ VREF/NAME/doc/ = u2 - RW+ VREF/NAME/src/ = u2 + not and or xor + - == -lt -gt -eq -le -ge -ne - # set up 2 refex expressions, named e1, e2 - option refex-expr.e1 = master and VREF/NAME/foo - option refex-expr.e2 = VREF/NAME/doc/ and VREF/NAME/src/ + Parens are not allowed. Precedence is as you might expect for those + operators. It's actually perl that is evaluating it (you can guess what + the '-lt' etc., get translated to) so if in doubt, check 'man perlop'. - # now deny users if the corresponding expression is true - - VREF/refex-expr/e1 = u1 - - VREF/refex-expr/e2 = u2 + * the refexes that form the terms of the expression (in this case, lines 2 + and 4) MUST come before the expression itself (i.e., line 5). -Here are some IMPORTANT notes: + * note the words "EXACT refex was matched" above. - * You MUST place VREF/refex-expr rules at the end. (Only 'partial-copy', if - you use it, must come later). + Let's say you add "u3" to line 1. Then the refex expression in line 5 + would never match for u3. This is because line 1 prevents line 2 from + matching (being more general *and* appearing earlier), so the count for + the "master" refex would be 0. If "master" is 0 (false), then "master and + <anything>" is also false. - * You MUST explicitly permit the refexes used in your refex expressions. If - you have more generic rules, the specific ones must come first. + (Same thing is you swap lines 2 and 3; i.e., put the "RW+ = ..." before + the "RW+ master = ..."). - For example, without line 1, the refex recorded for user u1 will come from - line 2, (so it will be 'refs/.*'), and 'master' in the refex expressions - will never have a true value. + Put another way, the terms in the refex expression are refexes, not refs. + Merely pushing the master branch does not mean the count for "master" + increases; it has to *match* on a line that has "master" as the refex. - * (corollary) make sure you use the exact same refex in the expression as - you did on the original rule line. E.g., a missing slash at the end will - mess things up. +Here are some more examples: + + * user u2 is allowed to push either 'doc/' or 'src/' but not both - * You can use any logical expression using refexes as operands and using - these operators: + repo foo + RW+ = u1 u2 u3 - and not xor or + RW+ VREF/NAME/doc/ = u2 + RW+ VREF/NAME/src/ = u2 + - VREF/NAME/doc/ and VREF/NAME/src/ = u2 - Parens are not allowed. + * user u3 is allowed to push at most 2 files to conf/ - If a refex has passed, it will have a 'true' value, else it will be false. + repo foo + RW+ = u1 u2 u3 - The result of the evaluation, after these substitutions, will be the - result of the refex-expr VREF. + RW+ VREF/NAME/conf/ = u3 + - VREF/NAME/conf/ -gt 2 = u3 diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index a408698..7d1f53d 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -374,6 +374,7 @@ BEGIN { $non_core = " continuation-lines SYNTACTIC_SUGAR . keysubdirs-as-groups SYNTACTIC_SUGAR . macros SYNTACTIC_SUGAR . + refex-expr SYNTACTIC_SUGAR . renice PRE_GIT . @@ -388,7 +389,7 @@ BEGIN { $non_core = " Mirroring PRE_GIT :: Mirroring POST_GIT :: - RefexExpr ACCESS_2 :: + refex-expr ACCESS_2 RefexExpr::access_2 RepoUmask PRE_GIT :: RepoUmask POST_CREATE :: diff --git a/src/lib/Gitolite/Triggers/RefexExpr.pm b/src/lib/Gitolite/Triggers/RefexExpr.pm index 687cb9e..5e2114f 100644 --- a/src/lib/Gitolite/Triggers/RefexExpr.pm +++ b/src/lib/Gitolite/Triggers/RefexExpr.pm @@ -4,7 +4,7 @@ use warnings; # track refexes passed and evaluate expressions on them # ---------------------------------------------------------------------- -# see instructions for use at the bottom of src/VREF/refex-expr +# see src/VREF/refex-expr for instructions and WARNINGS! use Gitolite::Easy; diff --git a/src/syntactic-sugar/refex-expr b/src/syntactic-sugar/refex-expr new file mode 100644 index 0000000..0713579 --- /dev/null +++ b/src/syntactic-sugar/refex-expr @@ -0,0 +1,39 @@ +# vim: syn=perl: + +# "sugar script" (syntactic sugar helper) for gitolite3 +# ---------------------------------------------------------------------- +# see src/VREF/refex-expr for instructions and WARNINGS! + +my $perm = qr(-|R|RW\+?C?D?M?); + +my $seq = 1; +sub sugar_script { + my $lines = shift; + + Gitolite::Common::dd ['lines', $lines]; + + # my @out = (); + for my $l (@$lines) { + push @out, $l; + + # quick check + next unless $l =~ /^($perm) /; + # more detailed check + next unless $l =~ /^($perm) (\S.*) = (\S.*)$/; + my ($perm, $refexes, $users) = ($1, $2, $3); + next unless $refexes =~ / (and|not|or|xor|\+|-|==|-lt|-gt|-eq|-le|-ge|-ne) /; + + print STDERR ">>>> $l\n"; + pop @out; # we need to replace that last line + + my @words = grep { $_ !~ /^(and|not|or|xor|\+|-|==|-lt|-gt|-eq|-le|-ge|-ne)$/ } split ' ', $refexes; + push @out, map { "RW+ $_ = $users" } @words; + push @out, "option refex-expr.sugar$seq = $refexes"; + push @out, "$perm VREF/refex-expr/sugar$seq = $users"; + + $seq++; + } + + Gitolite::Common::dd ['out', \@out]; + return \@out; +} diff --git a/t/refex-expr-test-1 b/t/refex-expr-test-1 new file mode 100755 index 0000000..1372a1e --- /dev/null +++ b/t/refex-expr-test-1 @@ -0,0 +1,62 @@ +#!/bin/bash + +# not part of the official test suite (yet); just some q&d testing + +# to be run from ~/gitolite as ./$0 + +set -e +exec 3>&2 +exec > /dev/null +exec 2> /dev/null +print2() { echo -n "$@" >&3; } +say2() { echo "$@" >&3; } +die() { echo FATAL: "$@" >&3; exit 1; } + +export od=$PWD +export tmp=$(mktemp -d) +echo $tmp >&3 +trap "rm -rf $tmp" 0 +cd $tmp + +print2 setting up... +( cd $od; t/reset ) +echo "push @{ \$RC{ENABLE} }, 'refex-expr';" >> ~/.gitolite.rc +cat <<EOF >> ~/.gitolite/conf/gitolite.conf + +repo r1 + RW+ = u1 u2 # line 1 + + RW+ master = u3 u4 # line 2 + RW+ = u3 u4 # line 3 + RW+ VREF/NAME/Makefile = u3 u4 # line 4 + - master and VREF/NAME/Makefile = u3 u4 # line 5 + +EOF +gitolite setup +say2 done + +# ---------------------------------------------------------------------- + +rm -rf u1 +git clone u1:r1 u1 +cd u1 +tsh 'tc f1' +git push u1:r1 master +tsh 'tc f2' +git push u2:r1 master +tsh 'tc f3' +git push u3:r1 master +tsh 'tc f4' +git push u4:r1 master +say2 everyone master no Makefile + +tsh 'tc f5 Makefile' +git push u1:r1 master +tsh 'tc f5 Makefile' +git push u1:r1 master:m1 +say2 u1 Makefile master + +tsh 'tc f5 Makefile' +git push u3:r1 master && die u3 r1 master should have failed +git push u3:r1 master:m2 +say2 u3 Makefile master fail m2 pass diff --git a/t/refex-expr-test-2 b/t/refex-expr-test-2 new file mode 100755 index 0000000..773e42c --- /dev/null +++ b/t/refex-expr-test-2 @@ -0,0 +1,60 @@ +#!/bin/bash + +# not part of the official test suite (yet); just some q&d testing + +# to be run from ~/gitolite as ./$0 + +set -e +exec 3>&2 +exec > /dev/null +exec 2> /dev/null +print2() { echo -n "$@" >&3; } +say2() { echo "$@" >&3; } +die() { echo FATAL: "$@" >&3; exit 1; } + +export od=$PWD +export tmp=$(mktemp -d) +echo $tmp >&3 +trap "rm -rf $tmp" 0 +cd $tmp + +print2 setting up... +( cd $od; t/reset ) +echo "push @{ \$RC{ENABLE} }, 'refex-expr';" >> ~/.gitolite.rc +cat <<EOF >> ~/.gitolite/conf/gitolite.conf + + repo r2 + RW+ = @all + + RW+ VREF/NAME/doc/ = u2 + RW+ VREF/NAME/src/ = u2 + - VREF/NAME/doc/ and VREF/NAME/src/ = u2 + +EOF +gitolite setup +say2 done + +# ---------------------------------------------------------------------- + +git clone u2:r2 +cd r2 + +tsh 'tc aa' +git push origin master +say2 aa pass + +mkdir doc src + +tsh 'tc doc/d1' +git push origin master +say2 doc pass + +tsh 'tc src/s1' +tsh 'tc src/s2' +git push origin master +say2 src src pass + +tsh 'tc doc/d2 src/s3' +git push origin master && die 1 +git push u1:r2 master +say2 doc src u2 fail u1 pass diff --git a/t/refex-expr-test-3 b/t/refex-expr-test-3 new file mode 100755 index 0000000..47599eb --- /dev/null +++ b/t/refex-expr-test-3 @@ -0,0 +1,55 @@ +#!/bin/bash + +# not part of the official test suite (yet); just some q&d testing + +# to be run from ~/gitolite as ./$0 + +set -e +exec 3>&2 +exec > /dev/null +exec 2> /dev/null +print2() { echo -n "$@" >&3; } +say2() { echo "$@" >&3; } +die() { echo FATAL: "$@" >&3; exit 1; } + +export od=$PWD +export tmp=$(mktemp -d) +echo $tmp >&3 +trap "rm -rf $tmp" 0 +cd $tmp + +print2 setting up... +( cd $od; t/reset ) +echo "push @{ \$RC{ENABLE} }, 'refex-expr';" >> ~/.gitolite.rc +cat <<EOF >> ~/.gitolite/conf/gitolite.conf + + repo r3 + RW+ = u1 u2 u3 + + RW+ VREF/NAME/conf/ = u3 + - VREF/NAME/conf/ -gt 2 = u3 + +EOF +gitolite setup +say2 done + +# ---------------------------------------------------------------------- + +git clone u3:r3 +cd r3 + +tsh 'tc aa' +git push origin master +say2 aa pass + +mkdir doc conf + +tsh 'tc doc/d1 doc/d2 doc/d3 doc/d4 conf/c1' +git push origin master +say2 4 doc 1 conf pass + +tsh 'tc conf/c2 conf/c3 conf/c4' +git push origin master && die 1 + +git push u2:r3 master +say2 3 conf u3 fail u2 pass diff --git a/t/refex-expr-test-9 b/t/refex-expr-test-9 new file mode 100755 index 0000000..b3a9f09 --- /dev/null +++ b/t/refex-expr-test-9 @@ -0,0 +1,107 @@ +#!/bin/bash + +# not part of the official test suite (yet); just some q&d testing + +# to be run from ~/gitolite as ./$0 + +set -e +exec 3>&2 +exec > /dev/null +exec 2> /dev/null +print2() { echo -n "$@" >&3; } +say2() { echo "$@" >&3; } +die() { echo FATAL: "$@" >&3; exit 1; } + +export od=$PWD +export tmp=$(mktemp -d) +echo $tmp >&3 +trap "rm -rf $tmp" 0 +cd $tmp + +print2 setting up... +( cd $od; t/reset ) +echo "push @{ \$RC{ENABLE} }, 'refex-expr';" >> ~/.gitolite.rc +cat <<EOF >> ~/.gitolite/conf/gitolite.conf + +repo r9 + + RW+ = u3 u4 + + # u1 and u2 have some restrictions + + # cant push master + - master = u1 u2 + # cant push versioned tags, but other tags are fine + - refs/tags/v[0-9] = u1 u2 + # everything else is fine, but we need to recognise when they're pushing + # tags, so that the refex expr will have the correct info + RW+ refs/tags/ = u1 u2 + RW+ = u1 u2 + + # can push files in "foo/" only to a tag + RW+ VREF/NAME/foo/ = u1 u2 + + RW+ VREF/NAME/foo/ and refs/tags/ = u1 u2 + - VREF/NAME/foo/ and not refs/tags/ = u1 u2 + +EOF +gitolite setup +say2 done + +# ---------------------------------------------------------------------- + +# make sure u3 is not constrained in any way + +git clone u3:r9 refex-test.repo +cd refex-test.repo + +tsh 'tc u3-f1' +git pom + +mkdir bar foo +tsh 'tc bar/thr' +git pom +git tag v3 +git push origin v3 +tsh 'tc foo/rht' +git pom +git tag 3v +git push origin 3v + +say2 u3 no limits + +# now test u1's constraints + +cd .. +rm -rf refex-test.repo + +rm -rf ~/repositories/r9.git +gitolite setup + +git clone u1:r9 refex-test.repo +cd refex-test.repo + +tsh 'tc u1-f1' +# cant push master +git pom && die 1 +# can push other branches +git push origin master:m1 +say2 master fail m1 pass + +mkdir bar foo +tsh 'tc bar/one' +git push origin master:m1 +git tag v1 +# cant push v-tag +git push origin v1 && die 2 +say2 v-tag fail + +# cant push foo/ to a branch +tsh 'tc foo/eno' +git push origin master:m1 && die 3 +say2 foo/ m1 fail + +# but can push to a non-v-tag +git tag 1v +git push origin 1v +say2 foo/ non-v-tag pass |