diff options
Diffstat (limited to '')
72 files changed, 8096 insertions, 0 deletions
diff --git a/t/0-me-first.t b/t/0-me-first.t new file mode 100755 index 0000000..8c9d12b --- /dev/null +++ b/t/0-me-first.t @@ -0,0 +1,94 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +# initial smoke tests +# ---------------------------------------------------------------------- + +try "plan 71"; + +# basic push admin repo +confreset;confadd ' + repo aa + RW+ = u1 + RW = u2 u3 + + repo cc/..* + C = u4 + RW+ = CREATOR u5 + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + /Initialized empty Git repository in .*/aa.git// + + # basic clone + cd .. + glt clone u1 file:///aa u1aa; ok; /Cloning into 'u1aa'.../ + /warning: You appear to have cloned an empty repository/ + [ -d u1aa ]; ok + + # basic clone deny + glt clone u4 file:///aa u4aa; !ok; /R any aa u4 DENIED by fallthru/ + [ -d u4aa ]; !ok + + # basic push + cd u1aa; ok + tc z-507; ok; /master .root-commit. 7cf7624. z-507/ + glt push u1 origin HEAD; ok; /To file:///aa/ + /\\[new branch\\] *HEAD -> master/ + + # basic rewind + tc o-866 o-867 o-868; ok; /master 2d066fb. o-868/ + glt push u1 origin HEAD; ok; /7cf7624..2d066fb HEAD -> master/ + git reset --hard HEAD^; ok; /HEAD is now at 8b1456b o-867/ + tc x-967; ok; /master 284951d. x-967/ + glt push u1 -f origin HEAD; ok; /\\+ 2d066fb...284951d HEAD -> master \\(forced update\\)/ + + # log file + cat \$(gitolite query-rc GL_LOGFILE); + ok; /\tupdate\t/ + /aa\tu1\t\\+\trefs/heads/master/ + /2d066fb4860c29cf321170c17695c6883f3d50e8/ + /284951dfa11d58f99ab76b9f4e4c1ad2f2461236/ + + # basic rewind deny + cd .. + glt clone u2 file:///aa u2aa; ok; /Cloning into 'u2aa'.../ + cd u2aa; ok + tc g-776 g-777 g-778; ok; /master 9cbc181. g-778/ + glt push u2 origin HEAD; ok; /284951d..9cbc181 HEAD -> master/ + git reset --hard HEAD^; ok; /HEAD is now at 2edf7fc g-777/ + tc d-485; ok; /master 1c01d32. d-485/ + glt push u2 -f origin HEAD; !ok; reject + /\\+ refs/heads/master aa u2 DENIED by fallthru/ + + # non-existent repos etc + glt ls-remote u4 file:///bb; !ok; /DENIED by fallthru/ + glt ls-remote u4 file:///cc/1; ok; /Initialized empty/ + glt ls-remote u5 file:///cc/1; ok; perl s/TRACE.*//g; !/\\S/ + glt ls-remote u5 file:///cc/2; !ok; /DENIED by fallthru/ + glt ls-remote u6 file:///cc/2; !ok; /DENIED by fallthru/ + + # command + glt perms u4 -c cc/bar/baz/frob + READERS u2; + ok; /Initialized empty .*cc/bar/baz/frob.git/ + + # path traversal + glt ls-remote u4 file:///cc/dd/../ee + !ok; /FATAL: 'cc/dd/\\.\\./ee' contains '\\.\\.'/ + glt ls-remote u5 file:///cc/../../../../../..$rb/gitolite-admin + !ok; /FATAL: 'cc/../../../../../..$rb/gitolite-admin' contains '\\.\\.'/ + + glt perms u4 -c cc/bar/baz/../frob + READERS u2 + !ok; /FATAL: no relative paths allowed anywhere!/ + +"; diff --git a/t/C-vs-C.t b/t/C-vs-C.t new file mode 100644 index 0000000..fee5cc4 --- /dev/null +++ b/t/C-vs-C.t @@ -0,0 +1,43 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# the commit message in which this test is introduced should have details, but +# briefly, this test makes sure that access() does not get confused by +# repo-create permissions being allowed, when looking for branch-create +# permissions. + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# branch permissions test +# ---------------------------------------------------------------------- + +try "plan 25"; + +confreset;confadd ' + repo foo/..* + C = @all + RW+CD = CREATOR + RW = u2 + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd ..; ok + glt clone u1 file:///foo/aa; ok + cd aa; ok + tc l-1; ok; /master/ + glt push u1 origin master:m1; ok; /To file:///foo/aa/ + /\\* \\[new branch\\] master -> m1/ + + tc l-2; ok; /master/ + glt push u2 origin master:m2; !ok; /FATAL: C/ + /DENIED by fallthru/ + glt push u2 origin master:m1; ok; /To file:///foo/aa/ + /8cd302a..29b8683/ + /master -> m1/ +"; diff --git a/t/README b/t/README new file mode 100644 index 0000000..4dc1594 --- /dev/null +++ b/t/README @@ -0,0 +1,116 @@ +# instructions for running the tests + +# Pre-requisites + +Install the following packages: + +* Manjaro (and probably Arch): + + pacman -S perl-json perl-json-xs apache + +* Fedora (and probably CentOS): + + dnf install -y perl-Test-Harness perl-JSON perl-JSON-XS httpd httpd-tools + +* others: + + (TBD) + +# RUNNING THE MAIN TEST SUITE + + ====================================== + WARNING: THE TEST SUITE DELETES STUFF! + ====================================== + +Please run the tests ONLY on a userid where it's ok to LOSE DATA. + +On such a userid, clone gitolite then run this command in the clone: + + GITOLITE_TEST=y prove + +http://gitolite.com/gitolite/testing.html has more details. Alternatively, +http://gitolite.com/gitolite/req.html#trying will help you try out gitolite if +you want to play with gitolite safely. + +# RUNNING THE HTTP AND MIRROR TESTS + + ====================================== + WARNING: THE TEST SUITE DELETES STUFF! + ====================================== + +The http and mirror tests require a lot more preparation, including commands +and/or scripts to be run as root, so they're not invoked when you simply run +"prove" as above. + +## Manjaro + +1. Create 3 users: sam, frodo, and gollum (`useradd -m`). + +2. Assuming you're running the tests using a local user called `g3`, run + `visudo` and add the following line: + + g3 ALL = (sam,frodo,gollum) NOPASSWD: ALL + + Test this by running this command from within `g3` and making sure you get + the correct results: + + sudo -u sam -i pwd + # should print /home/sam + # similarly make sure frodo and gollum also give correct results + + The mirror test will not run if this does not work. That does not mean + *mirroring* will not work; only the test suite depends on this feature. + +3. Manjaro does not, by default, add $HOME/bin to $PATH, so you will need the + following on at least sam, frodo, and gollum: + + # copy-paste this into a root terminal + for u in frodo sam gollum; do + grep '$HOME/bin' /home/$u/.bash_profile || echo 'export PATH="$HOME/bin:$PATH"' >> /home/$u/.bash_profile + done + + Again, test this by running: + + sudo -u sam -i echo '$PATH' + + and making sure the output starts with `/home/sam/bin:` (and similarly for + frodo and gollum). + +4. Take a look inside `t/manjaro-root-smart-http-test-setup` to make sure + everything looks sane (because you have to run it as root!!), then run it + as root. + +5. Now you are ready to run the last two tests: + + GITOLITE_TEST=y prove t/smart-http + GITOLITE_TEST=y prove t/mirror-test + +## Fedora + +1. Create 3 users: sam, frodo, and gollum (`useradd`). + +2. Assuming you're running the tests using a local user called `g3`, run + `visudo` and add the following line: + + g3 ALL = (sam,frodo,gollum) NOPASSWD: ALL + + Test this by running this command from within `g3` and making sure you get + the correct results: + + sudo -u sam -i pwd + # should print /home/sam + # similarly make sure frodo and gollum also give correct results + + The mirror test will not run if this does not work. That does not mean + *mirroring* will not work; only the test suite depends on this feature. + +3. Take a look inside `t/fedora-root-smart-http-test-setup` to make sure + everything looks sane (because you have to run it as root!!), then run it + as root. + +4. Now you are ready to run the last two tests: + + prove t/smart-http + prove t/mirror-test + +vim: ft=markdown diff --git a/t/access.t b/t/access.t new file mode 100755 index 0000000..c3f3341 --- /dev/null +++ b/t/access.t @@ -0,0 +1,253 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# test 'gitolite access' +# ---------------------------------------------------------------------- + +try "plan 254"; + +confreset;confadd ' + @admins = admin dev1 + repo gitolite-admin + RW+ = admin + + repo testing + RW+ = @all + + @g1 = t1 + repo @g1 + R = u2 + RW = u3 + RW+ = u4 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + + gitolite access -q t1 u1; !ok; !/./ + gitolite access -q t1 u1 R; !ok; !/./ + gitolite access -q t1 u1 W; !ok; !/./ + gitolite access -q t1 u1 +; !ok; !/./ + gitolite access -q t1 u2; !ok; !/./ + gitolite access -q t1 u2 R; ok; !/./ + gitolite access -q t1 u2 W; !ok; !/./ + gitolite access -q t1 u2 +; !ok; !/./ + gitolite access -q t1 u3; !ok; !/./ + gitolite access -q t1 u3 R; ok; !/./ + gitolite access -q t1 u3 W; ok; !/./ + gitolite access -q t1 u3 +; !ok; !/./ + gitolite access -q t1 u4; ok; !/./ + gitolite access -q t1 u4 R; ok; !/./ + gitolite access -q t1 u4 W; ok; !/./ + gitolite access -q t1 u4 +; ok; !/./ + + gitolite access t1 u1; !ok; /\\+ any t1 u1 DENIED by fallthru/ + gitolite access t1 u1 R; !ok; /R any t1 u1 DENIED by fallthru/ + gitolite access t1 u1 W; !ok; /W any t1 u1 DENIED by fallthru/ + gitolite access t1 u1 +; !ok; /\\+ any t1 u1 DENIED by fallthru/ + gitolite access t1 u2; !ok; /\\+ any t1 u2 DENIED by fallthru/ + gitolite access t1 u2 R; ok; /refs/\.\*/ + gitolite access t1 u2 W; !ok; /W any t1 u2 DENIED by fallthru/ + gitolite access t1 u2 +; !ok; /\\+ any t1 u2 DENIED by fallthru/ + gitolite access t1 u3; !ok; /\\+ any t1 u3 DENIED by fallthru/ + gitolite access t1 u3 R; ok; /refs/\.\*/ + gitolite access t1 u3 W; ok; /refs/\.\*/ + gitolite access t1 u3 +; !ok; /\\+ any t1 u3 DENIED by fallthru/ + gitolite access t1 u4; ok; /refs/\.\*/ + gitolite access t1 u4 R; ok; /refs/\.\*/ + gitolite access t1 u4 W; ok; /refs/\.\*/ + gitolite access t1 u4 +; ok; /refs/\.\*/ + +"; + +confreset;confadd ' + @admins = admin dev1 + repo gitolite-admin + RW+ = admin + + @g1 = u1 + @g2 = u2 + @g3 = u3 + @gaa = aa + repo @gaa + RW+ = @g1 + RW = @g2 + RW+ master = @g3 + RW master = u4 + - master = u5 + RW+ dev = u5 + RW = u5 +'; + +try "ADMIN_PUSH set2; !/FATAL/" or die text(); + +try " + gitolite access \@gaa \@g1 + any ; ok; /refs/.*/; !/DENIED/ + gitolite access aa \@g1 + refs/heads/master ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa \@g1 + refs/heads/next ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa \@g1 W refs/heads/next ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa u1 + refs/heads/dev ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa u1 + refs/heads/next ; ok; /refs/.*/; !/DENIED/ + gitolite access aa u1 W refs/heads/next ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa \@g2 + refs/heads/master ; !ok; /\\+ refs/heads/master \@gaa \@g2 DENIED by fallthru/ + gitolite access \@gaa \@g2 + refs/heads/next ; !ok; /\\+ refs/heads/next \@gaa \@g2 DENIED by fallthru/ + gitolite access aa \@g2 W refs/heads/master ; ok; /refs/.*/; !/DENIED/ + gitolite access aa u2 + any ; !ok; /\\+ any aa u2 DENIED by fallthru/ + gitolite access \@gaa u2 + refs/heads/master ; !ok; /\\+ refs/heads/master \@gaa u2 DENIED by fallthru/ + gitolite access \@gaa u2 W refs/heads/master ; ok; /refs/.*/; !/DENIED/ + gitolite access \@gaa \@g3 + refs/heads/master ; ok; /refs/heads/master/; !/DENIED/ + gitolite access \@gaa \@g3 W refs/heads/next ; !ok; /W refs/heads/next \@gaa \@g3 DENIED by fallthru/ + gitolite access \@gaa \@g3 W refs/heads/dev ; !ok; /W refs/heads/dev \@gaa \@g3 DENIED by fallthru/ + gitolite access aa u3 + refs/heads/dev ; !ok; /\\+ refs/heads/dev aa u3 DENIED by fallthru/ + gitolite access aa u3 + refs/heads/next ; !ok; /\\+ refs/heads/next aa u3 DENIED by fallthru/ + gitolite access \@gaa u4 + refs/heads/master ; !ok; /\\+ refs/heads/master \@gaa u4 DENIED by fallthru/ + gitolite access \@gaa u4 W refs/heads/master ; ok; /refs/heads/master/; !/DENIED/ + gitolite access aa u4 + refs/heads/next ; !ok; /\\+ refs/heads/next aa u4 DENIED by fallthru/ + gitolite access \@gaa u4 W refs/heads/next ; !ok; /W refs/heads/next \@gaa u4 DENIED by fallthru/ + gitolite access \@gaa u5 R any ; ok; /refs/heads/dev/; !/DENIED/ + gitolite access aa u5 R any ; ok; /refs/heads/dev/; !/DENIED/ + gitolite access \@gaa u5 + refs/heads/dev ; ok; /refs/heads/dev/; !/DENIED/ + gitolite access \@gaa u5 + refs/heads/master ; !ok; /\\+ refs/heads/master \@gaa u5 DENIED by refs/heads/master/ + gitolite access aa u5 + refs/heads/next ; !ok; /\\+ refs/heads/next aa u5 DENIED by fallthru/ + gitolite access \@gaa u5 R refs/heads/dev ; ok; /refs/heads/dev/; !/DENIED/ + gitolite access \@gaa u5 R refs/heads/master ; !ok; /R refs/heads/master \@gaa u5 DENIED by refs/heads/master/ + gitolite access \@gaa u5 R refs/heads/next ; ok; /refs/.*/; !/DENIED/ + gitolite access aa u5 W refs/heads/dev ; ok; /refs/heads/dev/; !/DENIED/ + gitolite access aa u5 W refs/heads/master ; !ok; /W refs/heads/master aa u5 DENIED by refs/heads/master/ + gitolite access \@gaa u5 W refs/heads/next ; ok; /refs/.*/; !/DENIED/ +"; + +confreset;confadd ' + @admins = admin dev1 + repo gitolite-admin + RW+ = admin + + @gr1 = r1 + repo @gr1 + RW refs/heads/v[0-9] = u1 + RW refs/heads = tester + + @gr2 = r2 + repo @gr2 + RW refs/heads/v[0-9] = u1 + - refs/heads/v[0-9] = tester + RW refs/heads = tester +'; + +try "ADMIN_PUSH set3; !/FATAL/" or die text(); + +try " + gitolite access \@gr2 tester W refs/heads/v1; !ok; /W refs/heads/v1 \@gr2 tester DENIED by refs/heads/v\\[0-9\\]/ + gitolite access \@gr1 tester W refs/heads/v1; ok; /refs/heads/; !/DENIED/ + gitolite access r1 tester W refs/heads/v1; ok; /refs/heads/; !/DENIED/ + gitolite access r2 tester W refs/heads/v1; !ok; /W refs/heads/v1 r2 tester DENIED by refs/heads/v\\[0-9\\]/ + gitolite access r2 tester W refs/heads/va; ok; /refs/heads/; !/DENIED/ +"; + +confreset;confadd ' + repo foo + RW+ = u1 + + @gr1 = foo bar + + repo @gr1 + RW = u2 + R = u3 + + repo @all + R = gitweb + + repo c0 + RW+ = @all + repo c1 + RWC = u1 + RW+ = @all +'; + +try "ADMIN_PUSH set4; !/FATAL/" or die text(); + +try " + gitolite access foo u1 +; ok + gitolite access foo u2 +; !ok + gitolite access foo u3 +; !ok + gitolite access foo u4 +; !ok + gitolite access foo gitweb +; !ok + + gitolite access foo u1 W; ok + gitolite access foo u2 W; ok + gitolite access foo u3 W; !ok + gitolite access foo u4 W; !ok + gitolite access foo gitweb W; !ok + + gitolite access foo u1 R; ok + gitolite access foo u2 R; ok + gitolite access foo u3 R; ok + gitolite access foo u4 R; !ok + gitolite access foo gitweb R; ok + + gitolite access c0 u1 +; ok + gitolite access c0 u1 C; ok + gitolite access c0 u2 +; ok + gitolite access c0 u2 C; ok + gitolite access c1 u1 +; ok + gitolite access c1 u1 C; ok + gitolite access c1 u2 +; ok + gitolite access c1 u2 C; !ok +"; + +confreset;confadd ' + repo foo + R = u1 + RW = u2 + RW+ = u3 + + repo bar + R = u1 + RW = u2 + RW+ = u3 + RW+CDM = u6 + +'; + +try "ADMIN_PUSH set4; !/FATAL/" or die text(); + +try " + gitolite access foo u1 +; !ok + gitolite access foo u2 +; !ok + gitolite access foo u3 +; ok + gitolite access foo u1 C; !ok + gitolite access foo u2 C; ok + gitolite access foo u3 C; ok + gitolite access foo u1 D; !ok + gitolite access foo u2 D; !ok + gitolite access foo u3 D; ok + gitolite access foo u1 M; !ok + gitolite access foo u2 M; ok + gitolite access foo u3 M; ok + + gitolite access bar u1 +; !ok + gitolite access bar u2 +; !ok + gitolite access bar u3 +; ok + gitolite access bar u1 C; !ok + gitolite access bar u2 C; !ok + gitolite access bar u3 C; !ok + gitolite access bar u1 D; !ok + gitolite access bar u2 D; !ok + gitolite access bar u3 D; !ok + gitolite access bar u1 M; !ok + gitolite access bar u2 M; !ok + gitolite access bar u3 M; !ok + + gitolite access bar u6 R; ok + gitolite access bar u6 W; ok + gitolite access bar u6 +; ok + gitolite access bar u6 C; ok + gitolite access bar u6 D; ok + gitolite access bar u6 M; ok +"; diff --git a/t/all-yall.t b/t/all-yall.t new file mode 100755 index 0000000..901b1c2 --- /dev/null +++ b/t/all-yall.t @@ -0,0 +1,89 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# could anything be clearer than "all y'all"? +# ---------------------------------------------------------------------- + +try "plan 26"; + +confreset;confadd ' + repo @all + R = @all + repo foo + RW+ = u1 + repo bar + RW+ = u2 + repo dev/..* + C = u3 u4 + RW+ = CREATOR +'; + +try " + rm $ENV{HOME}/projects.list +"; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + glt ls-remote u1 file:///dev/wild1 + /FATAL: R any dev/wild1 u1 DENIED by fallthru/ + + glt clone u3 file:///dev/wild1 + /Cloning into 'wild1'.../ + /Initialized empty Git repository in .*/dev/wild1.git// + /warning: You appear to have cloned an empty repository./ + + cd wild1 + tc n-855 n-856 + glt push u3 origin master:wild1 + /To file:///dev/wild1/ + /\\* \\[new branch\\] master -> wild1/ + glt push u1 file:///foo master:br-foo + /To file:///foo/ + /\\* \\[new branch\\] master -> br-foo/ + glt push u2 file:///bar master:br-bar + /To file:///bar/ + /\\* \\[new branch\\] master -> br-bar/ + + glt ls-remote u6 file:///foo + /refs/heads/br-foo/ + + glt ls-remote u6 file:///bar + /refs/heads/br-bar/ + + glt ls-remote u6 file:///dev/wild1 + /refs/heads/wild1/ +"; + +try " + gitolite ../triggers/post-compile/update-git-daemon-access-list; ok + gitolite ../triggers/post-compile/update-gitweb-access-list; ok + cat $ENV{HOME}/projects.list; ok +"; +cmp 'bar.git +dev/wild1.git +foo.git +gitolite-admin.git +testing.git +'; + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +try " + cd .. + cd .. + echo $rb + find $rb -name git-daemon-export-ok | sort + perl s,$rb/,,g +"; + +cmp 'bar.git/git-daemon-export-ok +dev/wild1.git/git-daemon-export-ok +foo.git/git-daemon-export-ok +gitolite-admin.git/git-daemon-export-ok +testing.git/git-daemon-export-ok +'; diff --git a/t/basic.t b/t/basic.t new file mode 100755 index 0000000..7579935 --- /dev/null +++ b/t/basic.t @@ -0,0 +1,284 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# some more basic tests +# ---------------------------------------------------------------------- + +try " + plan 217 + CHECK_SETUP + + # subtest 1 + cd .. + CLONE dev2 gitolite-admin ga2 + !ok; gsh + /DENIED by fallthru/ + /fatal: Could not read from remote repository/ + glt clone admin --progress file:///gitolite-admin ga2 + ok; gsh + /Counting/; /Compressing/; /Total/ + cd gitolite-admin; ok + "; + +put "conf/gitolite.conf", " + \@admins = admin dev1 + repo gitolite-admin + - mm = \@admins + RW = \@admins + RW+ = admin + + repo testing + RW+ = \@all +"; + +try " + # push + git add conf; ok + git status -s; ok; /M conf/gitolite.conf/ + git commit -m t01a; ok; /master.*t01a/ + PUSH dev2; !ok; gsh + /DENIED by fallthru/ + /fatal: Could not read from remote repository/ + PUSH admin; ok; /master -> master/ + empty; ok; + PUSH admin master:mm + !ok; gsh + /DENIED by refs/heads/mm/ + reject + "; + +put "conf/gitolite.conf", " + \@admins = admin dev1 + repo gitolite-admin + RW+ = admin + + repo testing + RW+ = \@all + + repo t1 + R = u2 + RW = u3 + RW+ = u4 +"; + +try " + # subtest 2 + ADMIN_PUSH t01b + + # clone + cd ..; ok; + CLONE u1 t1; !ok; gsh + /DENIED by fallthru/ + /fatal: Could not read from remote repository/ + CLONE u2 t1; ok; gsh + /warning: You appear to have cloned an empty repository./ + [ -d t1/.git ]; ok + cd t1; ok; + + # push + test-commit tc1 tc2 tc2; ok; /a530e66/ + PUSH u2; !ok; gsh + /DENIED by fallthru/ + /fatal: Could not read from remote repository/ + PUSH u3 master; ok; gsh + /master -> master/ + + # rewind + reset-h HEAD^; ok; /HEAD is now at aa2b5c5 tc2/ + test-tick; test-commit tc3; ok; /3ffced1/ + PUSH u3; !ok; gsh + /rejected.*master -> master.*non-fast-forward./ + PUSH u3 -f; !ok; gsh + reject + /DENIED by fallthru/ + PUSH u4 +master; ok; gsh + / \\+ a530e66...3ffced1 master -> master.*forced update./ +"; + +put "../gitolite-admin/conf/gitolite.conf", " + \@admins = admin dev1 + repo gitolite-admin + RW+ = admin + + include 'i1.conf' +"; + +put "../gitolite-admin/conf/i1.conf", " + \@g1 = u1 + \@g2 = u2 + \@g3 = u3 + \@gaa = aa + repo \@gaa + RW+ = \@g1 + RW = \@g2 + RW+ master = \@g3 + RW master = u4 + - master = u5 + RW+ dev = u5 + RW = u5 +"; + +try " + # subtest 3 + ADMIN_PUSH t01c + + cd ..; ok +"; + +try " + CLONE u1 aa; ok; gsh + cd aa; ok + test-commit set3 t1 t2 t3 t4 t5 t6 t7 t8 t9 + ok + PUSH u1 HEAD; ok; gsh + /To file:///aa/ + /\\* \\[new branch\\] HEAD -> master/ + branch dev; ok + branch foo; ok + + # u1 rewind master ok + reset-h HEAD^; ok + test-commit r1; ok + PUSH u1 +master; ok; gsh + /To file:///aa/ + /\\+ 27ed463...05adfb0 master -> master .forced update./ + + # u2 rewind master !ok + reset-h HEAD^; ok + test-commit r2; ok + PUSH u2 +master; !ok; gsh + reject + /DENIED by fallthru/ + + # u3 rewind master ok + reset-h HEAD^; ok + test-commit r3; ok + PUSH u3 +master; ok; gsh + /To file:///aa/ + /\\+ 05adfb0...6a532fe master -> master .forced update./ + + # u4 push master ok + test-commit u4; ok + PUSH u4 master; ok; gsh + /To file:///aa/ + /6a532fe..f929773 +master -> master/ + + # u4 rewind master !ok + reset-h HEAD^; ok + PUSH u4 +master; !ok; gsh + reject + /DENIED by fallthru/ + + # u3,u4 push other branches !ok + PUSH u3 dev; !ok; gsh + reject + /DENIED by fallthru/ + PUSH u4 dev; !ok; gsh + reject + /DENIED by fallthru/ + PUSH u3 foo; !ok; gsh + reject + /DENIED by fallthru/ + PUSH u4 foo; !ok; gsh + reject + /DENIED by fallthru/ + + # clean up for next set + glt push u1 -f origin master dev foo + ok; gsh + /f929773...6a532fe master -> master .forced update./ + /new branch.*dev -> dev/ + /new branch.*foo -> foo/ + + # u5 push master !ok + test-commit u5 + PUSH u5 master; !ok; gsh + reject + /DENIED by refs/heads/master/ + + # u5 rewind dev ok + PUSH u5 +dev^:dev + ok; gsh + /\\+ 27ed463...1ad477a dev\\^ -> dev .forced update./ + + + # u5 rewind foo !ok + PUSH u5 +foo^:foo + !ok; gsh + reject + /remote: FATAL: \\+ refs/heads/foo aa u5 DENIED by fallthru/ + + # u5 push foo ok + git checkout foo + /Switched to branch 'foo'/ + + test-commit u5 + PUSH u5 foo; ok; gsh + /27ed463..83da62c *foo -> foo/ + + # u1 delete dev ok + PUSH u1 :dev; ok; gsh + / - \\[deleted\\] *dev/ + + # push it back + PUSH u1 dev; ok; gsh + /\\* \\[new branch\\] *dev -> dev/ + +"; + +put "| cat >> ../gitolite-admin/conf/gitolite.conf", " + \@gr1 = r1 + repo \@gr1 + RW refs/heads/v[0-9] = u1 + RW refs/heads = tester +"; + +try " + # subtest 4 + ADMIN_PUSH t01d + + cd ..; ok + + CLONE tester r1; ok; gsh + /Cloning into 'r1'.../ + cd r1; ok + test-commit r1a r1b r1c r1d r1e r1f + ok + PUSH tester HEAD; ok; gsh + /\\* \\[new branch\\] *HEAD -> master/ + git branch v1 + PUSH tester v1; ok; gsh + /\\* \\[new branch\\] *v1 -> v1/ + +"; + +put "| cat >> ../gitolite-admin/conf/gitolite.conf", " + \@gr2 = r2 + repo \@gr2 + RW refs/heads/v[0-9] = u1 + - refs/heads/v[0-9] = tester + RW refs/heads = tester +"; + +try " + # subtest 5 + ADMIN_PUSH t01e + + cd ..; ok + + CLONE tester r2; ok; gsh + /Cloning into 'r2'.../ + cd r2; ok + test-commit r2a r2b r2c r2d r2e r2f + ok + PUSH tester HEAD; ok; gsh + /\\* \\[new branch\\] *HEAD -> master/ + git branch v1 + PUSH tester v1; !ok; gsh + /W refs/heads/v1 r2 tester DENIED by refs/heads/v\\[0-9\\]/ +" diff --git a/t/branch-perms.t b/t/branch-perms.t new file mode 100755 index 0000000..e59baea --- /dev/null +++ b/t/branch-perms.t @@ -0,0 +1,122 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# branch permissions test +# ---------------------------------------------------------------------- + +try "plan 82"; + +confreset;confadd ' + @g1 = u1 + @g2 = u2 + @g3 = u3 + @gaa = aa + repo @gaa + RW+ = @g1 + RW = @g2 + RW+ master = @g3 + RW master = u4 + - master = u5 + RW+ dev = u5 + RW = u5 + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd ..; ok + glt clone u1 file:///aa; ok + cd aa; ok + tc l-995 l-996 l-997 l-998 l-999 l-1000 l-1001 l-1002 l-1003; + ok; /master a788db9. l-1003/ + glt push u1 origin HEAD; ok; /To file:///aa/ + /\\* \\[new branch\\] HEAD -> master/ + + git branch dev; ok + git branch foo; ok + + # u1 rewind master succeed + git reset --hard HEAD^; ok; /HEAD is now at 65d5f4a l-1002/ + tc v-865; ok; /master 3053bb4. v-865/ + glt push u1 origin +master; ok; /\\+ a788db9...3053bb4 master -> master \\(forced update\\)/ + + # u2 rewind master fail + git reset --hard HEAD^; ok; /HEAD is now at 65d5f4a l-1002/ + tc s-361; ok; /master b331651. s-361/ + glt push u2 file:///aa +master; !ok; reject + /\\+ refs/heads/master aa u2 DENIED by fallthru/ + + # u3 rewind master succeed + git reset --hard HEAD^; ok + tc m-508; ok + glt push u3 file:///aa +master; ok; /\\+ .* master -> master \\(forced update\\)/ + + # u4 push master succeed + tc f-526; ok; + glt push u4 file:///aa master; ok; /master -> master/ + + # u4 rewind master fail + git reset --hard HEAD^; ok; + glt push u4 file:///aa +master; !ok; /\\+ refs/heads/master aa u4 DENIED by fallthru/ + + # u3 and u4 / dev foo -- all 4 fail + glt push u3 file:///aa dev; !ok; /W refs/heads/dev aa u3 DENIED by fallthru/ + glt push u4 file:///aa dev; !ok; /W refs/heads/dev aa u4 DENIED by fallthru/ + glt push u3 file:///aa foo; !ok; /W refs/heads/foo aa u3 DENIED by fallthru/ + glt push u4 file:///aa foo; !ok; /W refs/heads/foo aa u4 DENIED by fallthru/ + + # clean up for next set + glt push u1 -f origin master dev foo + ok + + # u5 push master fail + tc l-417; ok + glt push u5 file:///aa master; !ok; /W refs/heads/master aa u5 DENIED by refs/heads/master/ + + # u5 rewind dev succeed + glt push u5 file:///aa +dev^:dev + ok; /\\+ .* dev\\^ -> dev \\(forced update\\)/ + + # u5 rewind foo fail + glt push u5 file:///aa +foo^:foo + !ok; /\\+ refs/heads/foo aa u5 DENIED by fallthru/ + + # u5 tries to push foo; succeeds + git checkout foo; ok; /Switched to branch 'foo'/ + + # u5 push foo succeed + tc e-530; ok; + glt push u5 file:///aa foo; ok; /foo -> foo/ + + # u1 delete branch dev succeed + glt push u1 origin :dev; ok; / - \\[deleted\\] *dev/ + + # quietly push it back again + glt push u1 origin dev; ok; / * \\[new branch\\] dev -> dev/ + + "; + + confadd ' + repo @gaa + RWD dev = u4 + '; + +try "ADMIN_PUSH set2; !/FATAL/" or die text(); + +try " + # u1 tries to delete dev on a new setup + cd ../aa; ok; /master -> master/ + + # u1 delete branch dev fail + glt push u1 origin :dev; !ok; /D refs/heads/dev aa u1 DENIED by fallthru/ + + # u4 delete branch dev succeed + glt push u4 file:///aa :dev; ok; / - \\[deleted\\] *dev/ + +"; diff --git a/t/daemon-gitweb-via-perms.t b/t/daemon-gitweb-via-perms.t new file mode 100755 index 0000000..8707e19 --- /dev/null +++ b/t/daemon-gitweb-via-perms.t @@ -0,0 +1,78 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# basic tests +# ---------------------------------------------------------------------- + +try "plan 24"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +confreset;confadd ' + +@leads = u1 u2 +@devs = u1 u2 u3 u4 + +@gbar = bar/CREATOR/..* +repo @gbar + C = @leads + RW+ = @leads + RW = WRITERS @devs + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; +chdir($rb); +my $h = $ENV{HOME}; + +try " + glt ls-remote u1 file:///bar/u1/try1 + /Initialized empty Git repository in .*/bar/u1/try1.git/ + + find . -name git-daemon-export-ok + /testing.git/git-daemon-export-ok/ + + cat $h/projects.list + /testing.git/ + + glt ls-remote u1 file:///bar/u1/try2 + /Initialized empty Git repository in .*/bar/u1/try2.git/ + + find $h/repositories -name git-daemon-export-ok + /testing.git/git-daemon-export-ok/ + + cat $h/projects.list + /testing.git/ + + glt perms u1 bar/u1/try1 + READERS daemon + !/./ + + glt perms u1 bar/u1/try1 -l + /READERS daemon/ + + find $h/repositories -name git-daemon-export-ok + /repositories/testing.git/git-daemon-export-ok/ + /repositories/bar/u1/try1.git/git-daemon-export-ok/ + + cat $h/projects.list + /testing.git/ + + glt perms u1 bar/u1/try2 + READERS gitweb + + glt perms u1 bar/u1/try2 -l + /READERS gitweb/ + + find $h/repositories -name git-daemon-export-ok + /testing.git/git-daemon-export-ok/ + /bar/u1/try1.git/git-daemon-export-ok/ + + cat $h/projects.list + /bar/u1/try2.git/ + /testing.git/ +"; diff --git a/t/deleg-1.t b/t/deleg-1.t new file mode 100755 index 0000000..89da137 --- /dev/null +++ b/t/deleg-1.t @@ -0,0 +1,100 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# delegation tests -- part 1 +# ---------------------------------------------------------------------- + +try "plan 54"; + +try " + DEF SP_1 = git add conf ; ok; git commit -m %1; ok; /master.* %1/ + DEF SUBCONF_PUSH = SP_1 %2; glt push %1 origin; gsh; /master -> master/ +"; + +confreset;confadd ' + @u1r = r1a r1b + @u2r = r2a r2b + @u3r = r3a r3b + + # the admin repo access was probably like this to start with: + repo gitolite-admin + RW = u1 u2 u3 + RW+ NAME/ = admin + RW NAME/conf/fragments/u1r = u1 + RW NAME/conf/fragments/u2r = u2 + RW NAME/conf/fragments/u3r = u3 + - NAME/ = @all + + subconf "fragments/*.conf" +'; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +mkdir "conf/fragments"; +put "conf/fragments/u1r.conf", ' + repo @u1r + RW+ = tester +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); +try " + /Initialized empty Git repository in .*/r1a.git// + /Initialized empty Git repository in .*/r1b.git// +"; + +# u1 push u1r pass +put "conf/fragments/u1r.conf", ' + repo @u1r + RW+ = u5 +'; +try "SUBCONF_PUSH u1 u1; !/FATAL/" or die text(); + +# u2 main push fail +confadd ' + repo @u1r + RW+ = u6 +'; +try "SUBCONF_PUSH u2 u2; /FATAL/; + /W VREF/NAME/conf/gitolite.conf gitolite-admin u2 DENIED by VREF/NAME// +"; + +try "git reset --hard origin/master; ok"; + +# u2 push u1r fail +put "conf/fragments/u1r.conf", ' + repo @u1r + RW+ = u6 +'; +try "SUBCONF_PUSH u2 u2; /FATAL/ + /W VREF/NAME/conf/fragments/u1r.conf gitolite-admin u2 DENIED by VREF/NAME// +"; + +try "git reset --hard origin/master; ok"; + +# u3 set perms for r2a fail +put "conf/fragments/u3r.conf", ' + repo r2a + RW+ = u6 +'; +try "SUBCONF_PUSH u3 u3; + /WARNING: subconf 'u3r' attempting to set access for r2a/ +"; + +try "git reset --hard origin/master; ok"; + +# u3 add r2b to u3r fail + +put "conf/fragments/u3r.conf", ' + @u3r = r2b + repo @u3r + RW+ = u6 +'; + +try "SUBCONF_PUSH u3 u3 + /WARNING: expanding '\@u3r'/ + /WARNING: subconf 'u3r' attempting to set access for r2b/ +"; diff --git a/t/deleg-2.t b/t/deleg-2.t new file mode 100755 index 0000000..98fb02e --- /dev/null +++ b/t/deleg-2.t @@ -0,0 +1,122 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# delegation tests -- part 2 +# ---------------------------------------------------------------------- + +try "plan 55"; + +try " + DEF SP_1 = git add conf ; ok; git commit -m %1; ok; /master.* %1/ + DEF SUBCONF_PUSH = SP_1 %2; glt push %1 origin; gsh; /master -> master/ +"; + +confreset;confadd ' + # group your projects/repos however you want + @u1r = r1[ab] + @u2r = r2[ab] + @u3r = r3[ab] + + # the admin repo access was probably like this to start with: + repo gitolite-admin + RW = u1 u2 u3 + RW+ NAME/ = admin + RW NAME/conf/fragments/u1r = u1 + RW NAME/conf/fragments/u2r = u2 + RW NAME/conf/fragments/u3r = u3 + - NAME/ = @all + + subconf "fragments/*.conf" +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try "mkdir -p conf/fragments; ok"; + +put "conf/fragments/u1r.conf", ' + repo r1a r1b + C = @all + RW+ = CREATOR + repo @u1r + RW+ = tester +'; + +put "conf/fragments/u2r.conf", ' + repo @u2r + C = @all + RW+ = CREATOR + repo @u2r + RW+ = tester +'; + +put "conf/fragments/u3r.conf", ' + repo @u3r + C = @all + RW+ = CREATOR + repo @u3r + RW+ = tester +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); +try " + /Initialized empty Git repository in .*/r1a.git// + /Initialized empty Git repository in .*/r1b.git// +"; + +# u1 push u1r pass +put "conf/fragments/u1r.conf", ' + repo @u1r + RW+ = u5 +'; +try "SUBCONF_PUSH u1 u1; !/FATAL/" or die text(); + +# u2 main push fail +confadd ' + repo @u1r + RW+ = u6 +'; +try "SUBCONF_PUSH u2 u2; /FATAL/; + /W VREF/NAME/conf/gitolite.conf gitolite-admin u2 DENIED by VREF/NAME// +"; + +try "git reset --hard origin/master; ok"; + +# u2 push u1r fail +put "conf/fragments/u1r.conf", ' + repo @u1r + RW+ = u6 +'; +try "SUBCONF_PUSH u2 u2; /FATAL/ + /W VREF/NAME/conf/fragments/u1r.conf gitolite-admin u2 DENIED by VREF/NAME// +"; + +try "git reset --hard origin/master; ok"; + +# u3 set perms for r2a fail +put "conf/fragments/u3r.conf", ' + repo r2a + RW+ = u6 +'; +try "SUBCONF_PUSH u3 u3; + /WARNING: subconf 'u3r' attempting to set access for r2a/ +"; + +try "git reset --hard origin/master; ok"; + +# u3 add r2b to u3r fail + +put "conf/fragments/u3r.conf", ' + @u3r = r2b + repo @u3r + RW+ = u6 +'; + +try "SUBCONF_PUSH u3 u3 + /WARNING: expanding '\@u3r'/ + /WARNING: subconf 'u3r' attempting to set access for r2b/ +"; diff --git a/t/deny-create.t b/t/deny-create.t new file mode 100755 index 0000000..a4b7e4f --- /dev/null +++ b/t/deny-create.t @@ -0,0 +1,137 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# deny-create, the RW.*C flag +# ---------------------------------------------------------------------- + +try "plan 72"; + +try "DEF POK = !/DENIED/; !/failed to push/"; + +# test "C" permissions + +confreset; confadd ' + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gfoo = foo + repo @gfoo + RW+C = @leads + RW+C personal/USER/ = @devs + RW = @devs +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + glt clone u1 file:///foo + + cd foo + tc t-413 t-414 t-415 t-416 t-417 + + # u1 can push/rewind master on foo + glt push u1 origin master + POK; /master -> master/ + glt push u1 -f origin master^^:master + POK; /master\\^\\^ -> master/ + + # u2 can create newbr1 on foo + glt push u2 file:///foo master:newbr1 + POK; /master -> newbr1/ + + # u2 can create newtag on foo + git tag newtag + glt push u2 file:///foo newtag + POK; /newtag -> newtag/ + + # u3 can push newbr1 on foo + tc u-962 u-963 u-964 u-965 u-966 + glt push u3 file:///foo master:newbr1 + POK; /master -> newbr1/ + + # u4 canNOT create newbr2 on foo + tc e-615 e-616 e-617 e-618 e-619 + glt push u3 file:///foo master:newbr2 + /C refs/heads/newbr2 foo u3 DENIED by fallthru/ + reject + + # u4 canNOT create newtag2 on foo + git tag newtag2 + glt push u3 file:///foo newtag2 + /C refs/tags/newtag2 foo u3 DENIED by fallthru/ + reject + + # u4 can create/rewind personal/u4/newbr3 on foo + tc f-664 f-665 f-666 f-667 f-668 + glt push u4 file:///foo master:personal/u4/newbr3 + POK; /master -> personal/u4/newbr3/ + glt push u4 -f origin master^^:personal/u4/newbr3 + POK; /master\\^\\^ -> personal/u4/newbr3/ +"; + +# bar, without "C" permissions, should behave like old + +confadd ' + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gbar = bar + repo @gbar + RW+ = @leads + RW+ personal/USER/ = @devs + RW = @devs +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + glt clone u1 file:///bar + + cd bar + tc u-907 u-908 u-909 u-910 u-911 + + # u1 can push/rewind master on bar + glt push u1 origin master + POK; /master -> master/ + glt push u1 -f origin master^^:master + POK; /master\\^\\^ -> master/ + + # u2 can create newbr1 on bar + glt push u2 file:///bar master:newbr1 + POK; /master -> newbr1/ + + # u2 can create newtag on bar + git tag newtag + glt push u2 file:///bar newtag + POK; /newtag -> newtag/ + + # u3 can push newbr1 on bar + tc y-862 y-863 y-864 y-865 y-866 + glt push u3 file:///bar master:newbr1 + POK; /master -> newbr1/ + + # u4 can create newbr2 on bar + tc q-417 q-418 q-419 q-420 q-421 + glt push u3 file:///bar master:newbr2 + POK; /master -> newbr2/ + + # u4 can create newtag2 on bar + git tag newtag2 + glt push u3 file:///bar newtag2 + POK; /newtag2 -> newtag2/ + + # u4 can create/rewind personal/u4/newbr3 on bar + tc v-605 v-606 v-607 v-608 v-609 + glt push u4 file:///bar master:personal/u4/newbr3 + POK; /master -> personal/u4/newbr3/ + glt push u4 -f origin master^^:personal/u4/newbr3 + POK; /master\\^\\^ -> personal/u4/newbr3/ + +"; diff --git a/t/deny-rules-2.t b/t/deny-rules-2.t new file mode 100755 index 0000000..0ca15fe --- /dev/null +++ b/t/deny-rules-2.t @@ -0,0 +1,172 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# more on deny-rules +# ---------------------------------------------------------------------- + +try "plan 126"; + +try " + DEF GOOD = /refs/\\.\\*/ + DEF BAD = /DENIED/ + + DEF Ryes = gitolite access %1 %2 R any; ok; GOOD + DEF Rno = gitolite access %1 %2 R any; !ok; BAD + + DEF Wyes = gitolite access %1 %2 W any; ok; GOOD + DEF Wno = gitolite access %1 %2 W any; !ok; BAD + + DEF GWyes = Ryes %1 gitweb + DEF GWno = Rno %1 gitweb + + DEF GDyes = Ryes %1 daemon + DEF GDno = Rno %1 daemon +"; + +confreset;confadd ' + repo one + RW+ = u1 + R = u2 + - = u2 u3 + R = @all +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + Wyes one u1 + + Ryes one u2 + Wno one u2 + + Ryes one u3 + Wno one u3 + + Ryes one u6 + Wno one u6 + + GDyes one + GWyes one +"; + +confadd ' + option deny-rules = 1 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + Wyes one u1 + + Ryes one u2 + Wno one u2 + + Rno one u3 + + Ryes one u6 + Wno one u6 + + GDyes one + GWyes one +"; + +confadd ' + repo two + RW+ = u1 + R = u2 + - = u2 u3 gitweb daemon + R = @all +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + GWyes two + GDyes two +"; + +confadd ' + option deny-rules = 1 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + GWno two + GDno two +"; + +# set 3 -- allow gitweb to all but admin repo + +confadd ' + repo gitolite-admin + - = gitweb daemon + option deny-rules = 1 + + repo three + RW+ = u3 + R = gitweb daemon +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + GDyes three + GWyes three + GDno gitolite-admin + GWno gitolite-admin +"; + +# set 4 -- allow gitweb to all but admin repo + +confadd ' + repo four + RW+ = u4 + - = gitweb daemon + + repo @all + R = @all +'; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + GDyes four + GWyes four + GDno gitolite-admin + GWno gitolite-admin +"; + +# set 5 -- go wild + +confreset; confadd ' + repo foo/..* + C = u1 + RW+ = CREATOR + - = gitweb daemon + R = @all + + repo bar/..* + C = u2 + RW+ = CREATOR + - = gitweb daemon + R = @all + option deny-rules = 1 +'; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + glt ls-remote u1 file:///foo/one + glt ls-remote u2 file:///bar/two + Wyes foo/one u1 + Wyes bar/two u2 + + GDyes foo/one + GDyes foo/one + GWno bar/two + GWno bar/two +"; diff --git a/t/deny-rules.t b/t/deny-rules.t new file mode 100755 index 0000000..c0e7cbb --- /dev/null +++ b/t/deny-rules.t @@ -0,0 +1,67 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# deny rules +# ---------------------------------------------------------------------- + +try "plan 11"; + +confreset;confadd ' + # start with... + + repo gitolite-admin + - = gitweb daemon + option deny-rules = 1 + + # main ruleset goes here + + @ga = a + @gb = b + @gc = c + + # and end with + + repo @ga + RW = u1 + - = @all + option deny-rules = 1 + + repo @gb + RW = u2 + - = daemon + option deny-rules = 1 + + repo @gc + RW = u3 + + repo @all + R = @all + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; +try " + cat $ENV{HOME}/projects.list; ok +"; +cmp 'b.git +c.git +testing.git +'; + +try " + cd .. + cd .. + echo $rb + find $rb -name git-daemon-export-ok | sort + perl s,$rb/,,g +"; +cmp 'c.git/git-daemon-export-ok +testing.git/git-daemon-export-ok +' diff --git a/t/easy.t b/t/easy.t new file mode 100755 index 0000000..dcd6c1a --- /dev/null +++ b/t/easy.t @@ -0,0 +1,181 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Easy; +use Gitolite::Test; +# put this after ::Easy because it chdirs away from where you were and the +# 'use lib "src"', not being absolute, fails + +# smoke tests for Easy.pm +# ---------------------------------------------------------------------- +# for a change these are actual perl tests, so not much call for tsh here, +# although I still need the basic infrastructure for setting up the repos and +# I still can't intermix this with perl's Test.pm or Test::More etc +sub ok { (+shift) ? print "ok\n" : print "not ok\n"; } +sub nok { (+shift) ? print "not ok\n" : print "ok\n"; } +sub msg { return unless $ENV{D}; print STDERR "#" . +shift . "\n"; } + +try "plan 98"; + +try " + cat $ENV{HOME}/.gitolite.rc + perl s/GIT_CONFIG_KEYS.*/GIT_CONFIG_KEYS => '.*',/ + put $ENV{HOME}/.gitolite.rc +"; + +# basic push admin repo +confreset;confadd ' + repo gitolite-admin + RW+ VREF/NAME/ = admin + RW+ VREF/NAME/u5/ = u5 + + repo aa + RW+ = u1 + RW = u2 + R = u4 + + config for.aa = 1 + + repo cc/..* + C = u4 + RW+ = CREATOR u5 + R = u6 + + config for.cc = 1 + + @oddguys = u1 u3 u5 + @evensout = u2 u4 u6 + + repo cc/sub/..* + config sub.cc = 1 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# valid_user() -- an internal function but still worth testing by itself first +eval { Gitolite::Easy::valid_user(); }; +ok($@ =~ /FATAL.*GL_USER not set/); +$ENV{GL_USER} = "u2"; +eval { Gitolite::Easy::valid_user(); }; +nok($@ =~ /FATAL.*GL_USER not set/); + +# is_admin +msg('is_admin'); +$ENV{GL_USER} = "admin"; ok(is_admin()); +$ENV{GL_USER} = "u5"; ok(is_admin()); +$ENV{GL_USER} = "u2"; nok(is_admin()); + +# is_super_admin -- not sure how useful it is right now +msg('is_super_admin'); +$ENV{GL_USER} = "admin"; ok( is_super_admin() ); +$ENV{GL_USER} = "u5"; nok( is_super_admin() ); +$ENV{GL_USER} = "u2"; nok( is_super_admin() ); + +# in_group +msg('in_group'); +$ENV{GL_USER} = "u1"; ok( in_group('oddguys') ); nok( in_group('evensout') ); +$ENV{GL_USER} = "u3"; ok( in_group('oddguys') ); nok( in_group('evensout') ); +$ENV{GL_USER} = "u4"; nok( in_group('oddguys') ); ok( in_group('evensout') ); +$ENV{GL_USER} = "u2"; nok( in_group('oddguys') ); ok( in_group('evensout') ); + +# owns +msg('owns'); +try("glt ls-remote u4 cc/u4; /Initialized empty.*cc/u4/"); +$ENV{GL_USER} = "u3"; nok( owns("cc/u3") ); nok( owns("cc/u4") ); +$ENV{GL_USER} = "u4"; nok( owns("cc/u3") ); ok( owns("cc/u4") ); +$ENV{GL_USER} = "u5"; nok( owns("cc/u3") ); nok( owns("cc/u4") ); + +# can_read +msg('can_read'); +$ENV{GL_USER} = "u1"; ok(can_read("aa")); +$ENV{GL_USER} = "u2"; ok(can_read("aa")); +$ENV{GL_USER} = "u3"; nok(can_read("aa")); +$ENV{GL_USER} = "u4"; ok(can_read("aa")); + +$ENV{GL_USER} = "u1"; nok(can_read("bb")); +$ENV{GL_USER} = "u2"; nok(can_read("bb")); +$ENV{GL_USER} = "u3"; nok(can_read("bb")); +$ENV{GL_USER} = "u4"; nok(can_read("bb")); + +$ENV{GL_USER} = "u3"; nok(can_read("cc/u3")); +$ENV{GL_USER} = "u4"; nok(can_read("cc/u3")); +$ENV{GL_USER} = "u5"; nok(can_read("cc/u3")); +$ENV{GL_USER} = "u6"; nok(can_read("cc/u3")); + +$ENV{GL_USER} = "u3"; nok(can_read("cc/u4")); +$ENV{GL_USER} = "u4"; ok(can_read("cc/u4")); +$ENV{GL_USER} = "u5"; ok(can_read("cc/u4")); +$ENV{GL_USER} = "u6"; ok(can_read("cc/u4")); + +# can_write +msg('can_write'); +$ENV{GL_USER} = "u1"; ok(can_write("aa")); +$ENV{GL_USER} = "u2"; ok(can_write("aa")); +$ENV{GL_USER} = "u3"; nok(can_write("aa")); +$ENV{GL_USER} = "u4"; nok(can_write("aa")); + +$ENV{GL_USER} = "u1"; ok(can_write("aa", "+")); +$ENV{GL_USER} = "u2"; nok(can_write("aa", "+")); +$ENV{GL_USER} = "u3"; nok(can_write("aa", "+")); +$ENV{GL_USER} = "u4"; nok(can_write("aa", "+")); + +$ENV{GL_USER} = "u1"; nok(can_write("bb")); +$ENV{GL_USER} = "u2"; nok(can_write("bb")); +$ENV{GL_USER} = "u3"; nok(can_write("bb")); +$ENV{GL_USER} = "u4"; nok(can_write("bb")); + +$ENV{GL_USER} = "u3"; nok(can_write("cc/u3")); +$ENV{GL_USER} = "u4"; nok(can_write("cc/u3")); +$ENV{GL_USER} = "u5"; nok(can_write("cc/u3")); +$ENV{GL_USER} = "u6"; nok(can_write("cc/u3")); + +$ENV{GL_USER} = "u3"; nok(can_write("cc/u4")); +$ENV{GL_USER} = "u4"; ok(can_write("cc/u4")); +$ENV{GL_USER} = "u5"; ok(can_write("cc/u4")); +$ENV{GL_USER} = "u6"; nok(can_write("cc/u4")); + +$ENV{GL_USER} = "u3"; nok(can_write("cc/u4", "+")); +$ENV{GL_USER} = "u4"; ok(can_write("cc/u4", "+")); +$ENV{GL_USER} = "u5"; ok(can_write("cc/u4", "+")); +$ENV{GL_USER} = "u6"; nok(can_write("cc/u4", "+")); + +# config +try("glt ls-remote u4 cc/sub/one; /Initialized empty.*cc/sub/one/"); +try("glt ls-remote u4 cc/two; /Initialized empty.*cc/two/"); +ok(1); +my @a; +@a = config("aa", "fo..aa"); ok($a[0] eq 'for.aa' and $a[1] eq '1'); +@a = config("aa", "for.aa"); ok($a[0] eq 'for.aa' and $a[1] eq '1'); +@a = config("aa", "fo\\..aa"); ok(scalar(@a) == 0); + +@a = config("aa", "fo..cc"); ok(scalar(@a) == 0); +@a = config("aa", "for.cc"); ok(scalar(@a) == 0); +@a = config("aa", "fo\\..cc"); ok(scalar(@a) == 0); + +@a = config("bb", "fo..aa"); ok(scalar(@a) == 0); +@a = config("bb", "for.aa"); ok(scalar(@a) == 0); +@a = config("bb", "fo\\..aa"); ok(scalar(@a) == 0); + +@a = config("cc/u4", "fo..aa"); ok(scalar(@a) == 0); +@a = config("cc/u4", "for.aa"); ok(scalar(@a) == 0); +@a = config("cc/u4", "fo\\..aa"); ok(scalar(@a) == 0); + +@a = config("cc/u4", "fo..cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/u4", "for.cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/u4", "fo\\..cc"); ok(scalar(@a) == 0); + +@a = config("cc/two", "fo..cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/two", "for.cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/two", "fo\\..cc"); ok(scalar(@a) == 0); + +@a = config("cc/sub/one", "fo..cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/sub/one", "for.cc"); ok($a[0] eq 'for.cc' and $a[1] eq '1'); +@a = config("cc/sub/one", "fo\\..cc"); ok(scalar(@a) == 0); + +@a = config("cc/sub/one", "su..cc"); ok($a[0] eq 'sub.cc' and $a[1] eq '1'); +@a = config("cc/sub/one", "sub.cc"); ok($a[0] eq 'sub.cc' and $a[1] eq '1'); +@a = config("cc/sub/one", "su\\..cc"); ok(scalar(@a) == 0); + diff --git a/t/fedora-root-smart-http-test-setup b/t/fedora-root-smart-http-test-setup new file mode 100755 index 0000000..869d13d --- /dev/null +++ b/t/fedora-root-smart-http-test-setup @@ -0,0 +1,95 @@ +#!/bin/bash + +# gitolite http mode TESTING setup for Fedora +# - Probably works for CentOS also; if someone tests it let me know +# - Use the comments to create a version for your distro if needed + +# CAUTION: This script needs to be run as root, so you best eyeball it at +# least once to make sure you know what changes it is making. + +# WARNING: clobbers /usr/share/httpd/gitolite-home, and also creates 7 http +# users with trivial passwords FOR TESTING. + +# HOWEVER: if you remove some of that, especially the part that creates test +# users, this *should* work as a quick "setup gitolite http mode" script. + +# CAUTION: This script assumes the httpd.conf file is pretty much the default +# "as shipped" version. If you fiddled with it, this script *may* break. +# It's on you to determine if that is the case and manually simulate the +# actions of this script. It's not that hard, and anyway it's just once (for +# a given server) so it's not too bad. + +# ---------------------------------------------------------------------- + +cd ~apache +# should be /usr/share/httpd; you may want to check just to be safe +export GITOLITE_HTTP_HOME=$PWD/gitolite-home + +[[ -d gitolite-home ]] && { + [[ $GITOLITE_TEST != y ]] && { + echo "If you're OK with clobbering $GITOLITE_HTTP_HOME, please rerun with +environment variable GITOLITE_TEST set to 'y'." + exit 1; + } +} + +rm -rf gitolite-home +mkdir gitolite-home + +# setup apache conf for gitolite +cd /etc/httpd/conf.d +[[ -f gitolite.conf ]] || { + cat > gitolite.conf <<-EOF + SetEnv GIT_PROJECT_ROOT $GITOLITE_HTTP_HOME/repositories + ScriptAlias /git/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ + ScriptAlias /gitmob/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ + SetEnv GITOLITE_HTTP_HOME $GITOLITE_HTTP_HOME + SetEnv GIT_HTTP_EXPORT_ALL + + <Location /git> + AuthType Basic + AuthName "Private Git Access" + Require valid-user + AuthUserFile $GITOLITE_HTTP_HOME/gitolite-http-authuserfile + </Location> + EOF +} + +# get the gitolite sources +cd $GITOLITE_HTTP_HOME + +if [[ -d /tmp/gitolite.git ]]; then + git clone /tmp/gitolite.git gitolite-source + # I do this because I have to test stuff *before* it gets to github, so I + # can't simply clone what's on github. Instead, I use a local + # world-readable bare repo cloned from my dev environment. +else + git clone 'https://github.com/sitaramc/gitolite' gitolite-source +fi + +# make the bin directory, and add it to PATH +cd gitolite-source +mkdir $GITOLITE_HTTP_HOME/bin +./install -ln $GITOLITE_HTTP_HOME/bin +export PATH=$PATH:$GITOLITE_HTTP_HOME/bin + +# come back to base, then run setup. Notice that you have to point HOME to +# the right place, even if it is just for this command +cd $GITOLITE_HTTP_HOME +HOME=$GITOLITE_HTTP_HOME gitolite setup -a admin + +# insert some essential lines at the beginning of the rc file +echo '$ENV{PATH} .= ":$ENV{GITOLITE_HTTP_HOME}/bin";' > 1 +echo >> 1 +cat .gitolite.rc >> 1 +\mv 1 .gitolite.rc + +# create users "admin" and "u1" thru "u6" for testing +htpasswd -bc $GITOLITE_HTTP_HOME/gitolite-http-authuserfile admin admin +seq 6 | xargs -I % htpasswd -b $GITOLITE_HTTP_HOME/gitolite-http-authuserfile u% u% + +# fix up ownership +chown -R apache:apache $GITOLITE_HTTP_HOME + +# restart httpd to make it pick up all the new stuff +systemctl restart httpd diff --git a/t/fork.t b/t/fork.t new file mode 100755 index 0000000..2a7a7b7 --- /dev/null +++ b/t/fork.t @@ -0,0 +1,89 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; +my $h = $ENV{HOME}; + +# fork command +# ---------------------------------------------------------------------- + +try "plan 38"; + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +confreset;confadd ' + + repo foo/CREATOR/..* + C = u1 u2 + RW+ = CREATOR +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + + # make the initial repo + glt ls-remote u1 file:///foo/u1/u1a;ok; gsh + /Initialized empty Git repository in .*/foo/u1/u1a.git/ + # vrc doesn't have the fork command + glt fork u1 foo/u1/u1a foo/u1/u1a2; !ok; /FATAL: unknown git/gitolite command: \\'fork/ +"; + +# allow fork as a valid command +$ENV{G3T_RC} = "$ENV{HOME}/g3trc"; +put "$ENV{G3T_RC}", "\$rc{COMMANDS}{fork} = 1;\n"; + +# enable set-default-roles feature, add options, push +try " + cat $h/.gitolite.rc + perl s/# 'set-default-roles'/'set-default-roles'/ + put $h/.gitolite.rc +"; +try "cd gitolite-admin"; +confadd ' + repo foo/CREATOR/..* + C = u1 u2 + RW+ = CREATOR + option default.roles-1 = READERS @all +'; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); +try "cd .."; + +try " + # now the fork succeeds + glt fork u1 foo/u1/u1a foo/u1/u1a2; ok; /Cloning into bare repository '.*/foo/u1/u1a2.git'/ + /foo/u1/u1a forked to foo/u1/u1a2/ + + # now the actual testing starts + # read error + glt fork u1 foo/u1/u1c foo/u1/u1d; !ok; /'foo/u1/u1c' does not exist or you are not allowed to read it/ + glt fork u2 foo/u1/u1a foo/u1/u1d; !ok; /'foo/u1/u1a' does not exist or you are not allowed to read it/ + + # write error + glt fork u1 foo/u1/u1a foo/u2/u1d; !ok; /'foo/u2/u1d' already exists or you are not allowed to create it/ + + # no error + glt fork u1 foo/u1/u1a foo/u1/u1e; ok; /Cloning into bare repository '.*/foo/u1/u1e.git'/ + /warning: You appear to have cloned an empty repository/ + /foo/u1/u1a forked to foo/u1/u1e/ + # both exist + glt fork u1 foo/u1/u1a foo/u1/u1e; !ok; /'foo/u1/u1e' already exists or you are not allowed to create it/ +"; + +# now check the various files that should have been produced + +my $t; +try "cd $rb; find . -name gl-perms"; $t = md5sum(sort (lines())); cmp $t, +'59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1a2.git/gl-perms +59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1e.git/gl-perms +'; + +try "cd $rb; find . -name gl-creator"; $t = md5sum(sort (lines())); cmp $t, +'e4774cdda0793f86414e8b9140bb6db4 ./foo/u1/u1a.git/gl-creator +346955ff2eadbf76e19373f07dd370a9 ./foo/u1/u1a2.git/gl-creator +346955ff2eadbf76e19373f07dd370a9 ./foo/u1/u1e.git/gl-creator +'; diff --git a/t/git-config.t b/t/git-config.t new file mode 100755 index 0000000..fb5097e --- /dev/null +++ b/t/git-config.t @@ -0,0 +1,191 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# git config settings +# ---------------------------------------------------------------------- + +try "plan 57"; + +try "pwd"; +my $od = text(); +chomp($od); + +my $t; # temp + +# try an invalid config key +confreset;confadd ' + + repo @all + config foo.bar = dft +'; + +try "ADMIN_PUSH set1; /FATAL/" or die text(); +try " + /git config \\'foo.bar\\' not allowed/ + /check GIT_CONFIG_KEYS in the rc file/ +"; + +# make foo.bar a valid gc key +$ENV{G3T_RC} = "$ENV{HOME}/g3trc"; +put "$ENV{G3T_RC}", "\$rc{GIT_CONFIG_KEYS} = 'foo\.bar';\n"; + +confreset;confadd ' + + repo @all + config foo.bar = dft + + repo gitolite-admin + RW+ = admin + config foo.bar = + + repo testing + RW+ = @all + + repo foo + RW = u1 + config foo.bar = f1 + + repo frob + RW = u3 + + repo bar + RW = u2 + config foo.bar = one + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; +try " + cd $rb; ok + egrep foo\\|bar *.git/config +"; +$t = join("\n", sort (lines())); + +cmp $t, 'bar.git/config: bar = one +bar.git/config: bare = true +bar.git/config:[foo] +foo.git/config: bar = f1 +foo.git/config: bare = true +foo.git/config:[foo] +frob.git/config: bar = dft +frob.git/config: bare = true +frob.git/config:[foo] +gitolite-admin.git/config: bare = true +testing.git/config: bar = dft +testing.git/config: bare = true +testing.git/config:[foo]'; + +try "cd $od; ok"; + +confadd ' + + repo frob + RW = u3 + config foo.bar = none + + repo bar + RW = u2 + config foo.bar = one + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd $rb; ok + egrep foo\\|bar *.git/config +"; +$t = join("\n", sort (lines())); + +cmp $t, 'bar.git/config: bar = one +bar.git/config: bare = true +bar.git/config:[foo] +foo.git/config: bar = f1 +foo.git/config: bare = true +foo.git/config:[foo] +frob.git/config: bar = none +frob.git/config: bare = true +frob.git/config:[foo] +gitolite-admin.git/config: bare = true +testing.git/config: bar = dft +testing.git/config: bare = true +testing.git/config:[foo]'; + +try "cd $od; ok"; + +confadd ' + + repo bar + RW = u2 + config foo.bar = + +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd $rb; ok + egrep foo\\|bar *.git/config +"; +$t = join("\n", sort (lines())); + +cmp $t, 'bar.git/config: bare = true +foo.git/config: bar = f1 +foo.git/config: bare = true +foo.git/config:[foo] +frob.git/config: bar = none +frob.git/config: bare = true +frob.git/config:[foo] +gitolite-admin.git/config: bare = true +testing.git/config: bar = dft +testing.git/config: bare = true +testing.git/config:[foo]'; + +try "cd $od; ok"; + +confreset;confadd ' + + repo @gr1 + RW = u1 + config foo.bar = f1 + + repo bar/CREATOR/[one].* + C = u2 + RW = u2 + config foo.bar = one + + @gr1 = foo frob + +'; +try "ADMIN_PUSH set1; !/FATAL/" or die text(); +try " + glt ls-remote u2 file:///bar/u2/one; ok; /Initialized empty/ + glt ls-remote u2 file:///bar/u2/two; !ok; /DENIED by fallthru/ +"; + +try " + cd $rb; ok + find . -name config | xargs egrep foo\\|bar +"; +$t = join("\n", sort (lines())); + +cmp $t, './bar/u2/one.git/config: bar = one +./bar/u2/one.git/config: bare = true +./bar/u2/one.git/config:[foo] +./foo.git/config: bar = f1 +./foo.git/config: bare = true +./foo.git/config:[foo] +./frob.git/config: bar = f1 +./frob.git/config: bare = true +./frob.git/config:[foo] +./gitolite-admin.git/config: bare = true +./testing.git/config: bar = dft +./testing.git/config: bare = true +./testing.git/config:[foo]'; diff --git a/t/gitolite-receive-pack b/t/gitolite-receive-pack new file mode 100755 index 0000000..a4cc5be --- /dev/null +++ b/t/gitolite-receive-pack @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +use strict; +use warnings; +print STDERR "TRACE: grp(", join( ")(", @ARGV ), ")\n"; + +my $repo = shift; +$repo =~ s/\.git$//; +my $user = $ENV{G3T_USER} || 'no-such-user'; + +$ENV{SSH_ORIGINAL_COMMAND} = "git-receive-pack '$repo'"; +exec( "$ENV{GL_BINDIR}/../src/gitolite-shell", $user ); diff --git a/t/gitolite-upload-pack b/t/gitolite-upload-pack new file mode 100755 index 0000000..5981f17 --- /dev/null +++ b/t/gitolite-upload-pack @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +use strict; +use warnings; +print STDERR "TRACE: gup(", join( ")(", @ARGV ), ")\n"; + +my $repo = shift; +$repo =~ s/\.git$//; +my $user = $ENV{G3T_USER} || 'no-such-user'; + +$ENV{SSH_ORIGINAL_COMMAND} = "git-upload-pack '$repo'"; +exec( "$ENV{GL_BINDIR}/../src/gitolite-shell", $user ); @@ -0,0 +1,43 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use FindBin; +BEGIN { $ENV{GL_BINDIR} = $FindBin::RealBin; } + +my $cmd = shift or die "need command"; +my $user = shift or die "need user"; +my $rc; + +my %extcmds = ( + help => 1, + info => 1, + desc => 1, + fork => 1, + perms => 1, + writable => 1, +); + +$ENV{G3T_USER} = $user; +if ($extcmds{$cmd}) { + $ENV{SSH_ORIGINAL_COMMAND} = join(" ", $cmd, @ARGV); + exec( "$ENV{GL_BINDIR}/../src/gitolite-shell", $user ); +} elsif ( $cmd eq 'push' ) { + print STDERR "TRACE: glt(", join( ")(", @ARGV ), ")\n"; + $rc = system( "git", $cmd, "--receive-pack=$ENV{GL_BINDIR}/gitolite-receive-pack", @ARGV ); +} else { + print STDERR "TRACE: glt(", join( ")(", @ARGV ), ")\n"; + $rc = system( "git", $cmd, "--upload-pack=$ENV{GL_BINDIR}/gitolite-upload-pack", @ARGV ); +} + +if ( $? == -1 ) { + die "F: failed to execute: $!\n"; +} elsif ( $? & 127 ) { + printf STDERR "E: child died with signal %d\n", ( $? & 127 ); + exit 1; +} else { + printf STDERR "W: child exited with value %d\n", $? >> 8 if $? >> 8; + exit( $? >> 8 ); +} + +exit 0; diff --git a/t/hostname.t b/t/hostname.t new file mode 100755 index 0000000..dfb8885 --- /dev/null +++ b/t/hostname.t @@ -0,0 +1,77 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# %HOSTNAME tests +# ---------------------------------------------------------------------- + +try "plan 60"; + +try "pwd"; +my $od = text(); +chomp($od); + +# without setting HOSTNAME in rc +confreset;confadd ' + + repo foo + RW dev/%HOSTNAME = u1 +'; + +try "ADMIN_PUSH set1; /FATAL/"; +try "/bad ref 'refs/heads/dev/%HOSTNAME'/"; + +# make a hostname entry +$ENV{G3T_RC} = "$ENV{HOME}/g3trc"; +put "$ENV{G3T_RC}", "\$rc{HOSTNAME} = 'frodo';\n"; + +confreset;confadd ' + + repo bar + RW %HOSTNAME_baz = u1 +'; + +try "ADMIN_PUSH set1; /FATAL/"; +try "/bad ref 'refs/heads/%HOSTNAME_baz'/"; + +confreset;confadd ' + + repo bar + RW %HOSTNAME/ = u1 + RW %HOSTNAME-baz = u1 +'; + +try "ADMIN_PUSH set1; !/FATAL/"; +try " + gitolite access bar u2 R any; /R any bar u2 DENIED by fallthru/ + gitolite access bar u2 W any; /W any bar u2 DENIED by fallthru/ + gitolite access bar u1 W any; !/DENIED/; /refs/heads/frodo/; !/baz/ + gitolite access bar u1 R any; !/DENIED/; /refs/heads/frodo/; !/baz/ + gitolite access bar u1 R refs/heads/frodo; /R refs/heads/frodo bar u1 DENIED by fallthru/ + gitolite access bar u1 W refs/heads/frodo; /W refs/heads/frodo bar u1 DENIED by fallthru/ + gitolite access bar u1 R refs/heads/frodo/1; !/DENIED/; /refs/heads/frodo/; !/baz/ + gitolite access bar u1 W refs/heads/frodo/1; !/DENIED/; /refs/heads/frodo/; !/baz/ + gitolite access bar u1 R refs/heads/sam; /R refs/heads/sam bar u1 DENIED by fallthru/ + gitolite access bar u1 W refs/heads/sam; /W refs/heads/sam bar u1 DENIED by fallthru/ + gitolite access bar u1 R refs/heads/master; /R refs/heads/master bar u1 DENIED by fallthru/ + gitolite access bar u1 W refs/heads/master; /W refs/heads/master bar u1 DENIED by fallthru/ + + gitolite access bar u1 R refs/heads/frodo-baz; !/DENIED/; /refs/heads/frodo-baz/ + gitolite access bar u1 W refs/heads/frodo-baz; !/DENIED/; /refs/heads/frodo-baz/ +"; + +confreset;confadd ' + + repo foo-%HOSTNAME + RW = u1 +'; + +try "ADMIN_PUSH set1; !/FATAL/"; +try " + gitolite list-repos; /foo-frodo/ + gitolite list-phy-repos; /foo-frodo/ +"; diff --git a/t/include-subconf.t b/t/include-subconf.t new file mode 100755 index 0000000..48bdaee --- /dev/null +++ b/t/include-subconf.t @@ -0,0 +1,120 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# include and subconf +# ---------------------------------------------------------------------- + +try 'plan 58'; + +confreset; confadd ' + include "i1.conf" + @i2 = b1 + subconf "i2.conf" + include "i1.conf" +'; +confadd 'i1.conf', ' + @g1 = a1 a2 + repo foo + RW = u1 + + include "j1.conf" +'; +confadd 'i2.conf', ' + @g2 = b1 b2 + repo bar b1 b2 i1 i2 @i1 @i2 @g2 + RW = u2 +'; +confadd 'j1.conf', ' + @h2 = c1 c2 + repo baz + RW = u3 +'; + +try "ADMIN_PUSH set2; !/FATAL/" or die text(); + +try " + /i1.conf already included/ + /subconf 'i2' attempting to set access for \@i1, b2, bar, i1/ + /WARNING: expanding '\@g2'/ + + !/attempting to set access.*i2/ + /Initialized.*empty.*baz.git/ + /Initialized.*empty.*foo.git/ + /Initialized.*empty.*b1.git/ + /Initialized.*empty.*i2.git/ + !/Initialized.*empty.*b2.git/ + !/Initialized.*empty.*i1.git/ + !/Initialized.*empty.*bar.git/ +"; + +confreset;confadd ' + @g2 = i1 i2 i3 + subconf "g2.conf" +'; +confadd 'g2.conf', ' + @g2 = g2 h2 i2 + repo @g2 + RW = u1 +'; + +try "ADMIN_PUSH set3; !/FATAL/" or die text(); +try " + /WARNING: expanding '\@g2'/ + /WARNING: subconf 'g2' attempting to set access for h2/ + /Initialized.*empty.*g2.git/ + /Initialized.*empty.*i2.git/ +"; + +confreset;confadd ' + @g2 = i1 i2 i3 + subconf "g2.conf" +'; +confadd 'g2.conf', ' + subconf master + @g2 = g2 h2 i2 + repo @g2 + RW = u1 +'; + +try " + ADMIN_PUSH set3; ok; /FATAL: subconf \\'g2\\' attempting to run 'subconf'/ +"; + +# ---------------------------------------------------------------------- + +confreset; confadd ' + include "i1.conf" + @i2 = b1 + subconf i2 "eye2.conf" +'; +confadd 'eye2.conf', ' + repo @eye2 + RW = u2 +'; + +try "ADMIN_PUSH set2; !/FATAL/" or die text(); + +try " + /subconf 'i2' attempting to set access for \@eye2/ +"; + +confreset; confadd ' + include "i1.conf" + @i2 = b1 + subconf i2 "eye2.conf" +'; +confadd 'eye2.conf', ' + repo @i2 + RW = u2 +'; + +try "ADMIN_PUSH set2; !/FATAL/" or die text(); + +try " + !/subconf 'i2' attempting to set access for \@eye2/ +"; diff --git a/t/info-json.t b/t/info-json.t new file mode 100755 index 0000000..74fbdf4 --- /dev/null +++ b/t/info-json.t @@ -0,0 +1,183 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; +use JSON; + +# the info command +# ---------------------------------------------------------------------- + +try 'plan 162'; + +try "## info"; + +confreset;confadd ' + @t1 = t1 + repo @t1 + RW = u1 + R = u2 + repo t2 + RW = u2 + R = u1 + repo t3 + RW = u3 + R = u4 + + repo foo/..* + C = u1 + RW = CREATOR u3 +'; + +try "ADMIN_PUSH info; !/FATAL/" or die text(); +try " + /Initialized.*empty.*t1.git/ + /Initialized.*empty.*t2.git/ + /Initialized.*empty.*t3.git/ +"; + +my $href; # semi-global (or at least file scoped lexical!) + +# testing for info -json is a bit unusual. The actual tests are done within +# this test script itself, and we send Tsh just enough for it to decide if +# it's 'ok' or 'not ok' and print that. + +try "glt info u1 -json; ok"; +$href = from_json(text()); +try "## u1 test_gs"; +test_gs('u1'); +try "## u1"; +perm('foo/..*', 'r w C'); +perm('testing', 'R W c'); +perm('t1', 'R W c'); +perm('t2', 'R w c'); +perm('t3', 'r w c'); + +try "## u2"; +try "glt info u2 -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('testing', 'R W c'); +perm('t1', 'R w c'); +perm('t2', 'R W c'); +perm('t3', 'r w c'); + +try "## u3"; +try "glt info u3 -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'R W c'); +perm('testing', 'R W c'); +perm('t1', 'r w c'); +perm('t2', 'r w c'); +perm('t3', 'R W c'); + +try "## u4"; +try "glt info u4 -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('testing', 'R W c'); +perm('t1', 'r w c'); +perm('t2', 'r w c'); +perm('t3', 'R w c'); + +try "## u5"; +try "glt info u5 -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('testing', 'R W c'); +perm('t1', 'r w c'); +perm('t2', 'r w c'); +perm('t3', 'r w c'); + +try "## u6"; +try "glt info u6 -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('testing', 'R W c'); +perm('t1', 'r w c'); +perm('t2', 'r w c'); +perm('t3', 'r w c'); + +try "## ls-remote foo/one"; +try "glt ls-remote u1 file:///foo/one; ok"; + +try "## u1"; +try "glt info u1 -json; ok; !/creator..:/"; +$href = from_json(text()); +perm('foo/..*', 'r w C'); +perm('foo/one', 'R W c'); +test_creator('foo/one', 'u1', 'undef'); + +try "## u2"; +try "glt info u2 -json; ok; !/creator..:/"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('foo/one', 'r w c'); +test_creator('foo/one', 'u1', 'undef'); + +try "## u3"; +try "glt info u3 -json; ok; !/creator..:/"; +$href = from_json(text()); +perm('foo/..*', 'R W c'); +perm('foo/one', 'R W c'); +test_creator('foo/one', 'u1', 'undef'); + +try("## with -lc now"); + +try "## u1"; +try "glt info u1 -lc -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w C'); +perm('foo/one', 'R W c'); +test_creator('foo/one', 'u1', 1); + +try "## u2"; +try "glt info u2 -lc -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'r w c'); +perm('foo/one', 'r w c'); +test_creator('foo/one', 'u1', 'undef'); + +try "## u3"; +try "glt info u3 -lc -json; ok"; +$href = from_json(text()); +perm('foo/..*', 'R W c'); +perm('foo/one', 'R W c'); +test_creator('foo/one', 'u1', 1); + +# ---------------------------------------------------------------------- + +# test perms given repo and expected perms. (lowercase r/w/c means NOT +# expected, uppercase means expected) +sub perm { + my ($repo, $aa) = @_; + for my $aa1 (split ' ', $aa) { + my $exp = 1; + if ($aa1 =~ /[a-z]/) { + $exp = 'undef'; # we can't use 0, though I'd like to + $aa1 = uc($aa1); + } + my $perm = $href->{repos}{$repo}{perms}{$aa1} || 'undef'; + try 'perl $_ = "' . $perm . '"; /' . $exp . '/'; + } +} + +# test versions in greeting string +sub test_gs { + my $glu = shift; + my $res = ( $href->{GL_USER} eq $glu ? 1 : 'undef' ); + try 'perl $_ = "' . $res . '"; /1/'; + $res = ( $href->{gitolite_version} =~ /^v3.[5-9]/ ? 1 : 'undef' ); + try 'perl $_ = "' . $res . '"; /1/'; + $res = ( $href->{git_version} =~ /^1.[6-9]|^2./ ? 1 : 'undef' ); + try 'perl $_ = "' . $res . '"; /1/'; +} + +# test creator +sub test_creator { + my ($r, $c, $exp) = @_; + my $res = ( ($href->{repos}{$r}{creator} || '') eq $c ? 1 : 'undef' ); + try 'perl $_ = "' . $res . '"; /' . $exp . '/'; +} diff --git a/t/info.t b/t/info.t new file mode 100755 index 0000000..22b5b94 --- /dev/null +++ b/t/info.t @@ -0,0 +1,105 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# the info command +# ---------------------------------------------------------------------- + +try 'plan 78'; + +try "## info"; + +confreset;confadd ' + @t1 = t1 + repo @t1 + RW = u1 + R = u2 + repo t2 + RW = u2 + R = u1 + repo t3 + RW = u3 + R = u4 + + repo foo/..* + C = u1 + RW = CREATOR u3 +'; + +try "ADMIN_PUSH info; !/FATAL/" or die text(); +try " + /Initialized.*empty.*t1.git/ + /Initialized.*empty.*t2.git/ + /Initialized.*empty.*t3.git/ +"; + +# GS == greeting string +try "DEF GS = /hello %1, this is $ENV{USER}\\@.* running gitolite/"; + +try " + glt info u1; ok; GS u1 + /C\tfoo/\\.\\.\\*/ + /R W *\tt1/ + /R *\tt2/ + /R W *\ttesting/ + !/R W *\tt3/ + glt info u2; ok; GS u2 + !/C\tfoo/ + /R *\tt1/ + /R W *\tt2/ + /R W *\ttesting/ + !/R W *\tt3/ + glt info u3; ok; GS u3 + /R W *\tt3/ + /R W *\ttesting/ + !/R *\tt1/ + !/R W *\tt2/ + glt info u4; ok; GS u4 + /R *\tt3/ + /R W *\ttesting/ + !/R *\tt1/ + !/R W *\tt2/ + glt info u5; ok; GS u5 + /R W *\ttesting/ + !/R *\tt1/ + !/R W *\tt2/ + !/R W *\tt3/ + glt info u6; ok; GS u6 + /R W *\ttesting/ + !/R *\tt1/ + !/R W *\tt2/ + !/R W *\tt3/ +"; + +try " + glt ls-remote u1 file:///foo/one; ok + glt info u1; ok; GS u1 + /C\tfoo/\\.\\.\\*/ + /R W *\tfoo/one/ + !/R W *\tfoo/one\tu1/ + glt info u2; ok; GS u2 + !/C\tfoo/ + !/R W *\tfoo/one/ + glt info u3; ok; GS u3 + !/C\tfoo/ + /R W *\tfoo/one/ + !/R W *\tfoo/one\tu1/ +"; + +try " + glt ls-remote u1 file:///foo/one; ok + glt info u1 -lc; ok; GS u1 + /C\tfoo/\\.\\.\\*/ + !/C\tfoo.*u1/ + /R W *\tfoo/one\tu1/ + glt info u2 -lc; ok; GS u2 + !/C\tfoo/ + !/R W *\tfoo/one/ + glt info u3 -lc; ok; GS u3 + !/C\tfoo/ + /R W *\tfoo/one\tu1/ +"; diff --git a/t/invalid-refnames-filenames.t b/t/invalid-refnames-filenames.t new file mode 100755 index 0000000..19267fe --- /dev/null +++ b/t/invalid-refnames-filenames.t @@ -0,0 +1,100 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# invalid refnames +# ---------------------------------------------------------------------- + +try "plan 56"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +confreset; confadd ' + repo aa + RW+ = @all +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + +cd .. +rm -rf aa +glt clone u1 file:///aa +cd aa +tc v-869 + +glt push u1 origin HEAD + /To file:///aa/ + POK; /\\* \\[new branch\\] HEAD -> master/ + +# push file aa,bb ok +tc aa,bb +glt push u1 origin HEAD + /To file:///aa/ + POK; /HEAD -> master/ + +# push file aa=bb ok +tc aa=bb +glt push u1 origin HEAD + /To file:///aa/ + POK; /HEAD -> master/ + +# push to branch dd,ee ok +glt push u1 origin master:dd,ee + /To file:///aa/ + POK; /\\* \\[new branch\\] master -> dd,ee/ + +# push to branch dd=ee fail +glt push u1 origin master:dd=ee + /invalid characters in ref or filename: \\'refs/heads/dd=ee/ + reject +"; + +confreset; confadd ' + repo aa + RW+ = @all + RW+ NAME/ = @all +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + +cd .. +rm -rf aa +glt clone u1 file:///aa +cd aa +tc file-1 + +glt push u1 origin HEAD + /To file:///aa/ + POK; /\\* \\[new branch\\] HEAD -> master/ + +# push file aa,bb ok +tc aa,bb +glt push u1 origin HEAD + /To file:///aa/ + POK; /HEAD -> master/ + +# push file aa=bb fail +tc aa=bb +glt push u1 origin HEAD + /To file:///aa/ + POK; /HEAD -> master/ + +# push to branch dd,ee ok +git reset --hard HEAD^ +tc some-file +glt push u1 origin master:dd,ee + /To file:///aa/ + POK; /\\* \\[new branch\\] master -> dd,ee/ + +# push to branch dd=ee fail +glt push u1 origin master:dd=ee + /invalid characters in ref or filename: \\'refs/heads/dd=ee/ + reject +"; diff --git a/t/keys/admin b/t/keys/admin new file mode 100644 index 0000000..676a711 --- /dev/null +++ b/t/keys/admin @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEA0/X7uwd7xOvC3UTZaAnFOR5xqhdgcyc8vk3d1bXXthiuUSmq +5t4uhS9qj0ismcPX0YRNhSDElotG1KSWp8DceJpR2c7GYmELpqoE7ebVPnEBKY0c +PX+G9KZNgbJyyx35QlpJmlO+LimM0oO8XarRphn3kc0jCTLKaI5ndEjGDHH4fsOe +wlryW7a0RR/brMNiJYYzy5ADCOkAnyXQmbrQW4nROCPqFojBFTEBLpe8EuODlJXE +mRHpa1k+k/grFgp/c1xbOrjox127LZT4vkLf5+lSwkhq8oyzWHUrQ+rUJZssi1LC +GEZSudhX5reqksmIlTwX0GPIIwSwZFNVxhj51wIDAQABAoIBAFFLlzE0vZPZmPOk +5H2ywaIWuyGxtZx1ACc9VkgRZprA/JrEkHfb35vVg9lQ1mJjavNA+zqERuI2qQQF +3IKaxfS7u4j+dbhl4EIcE6frUP6R+RAmvx4XO3u6DSAhgUXGSUPZvUEjvV2XMhvL +ywNh8Ob0LrANLdLpWBiiBavj/ZHnsVZj7y+39GKEtLm8BbsH8L7GanPl4uQDNruR +Ef2L2pSEqml+Iva6yk5a22U293JCVZ/aqDdGvrnbjkaxqin5jBgL47D91A3xo4SW +zFZkJR5SDYnFLdwnwTPvxSA9IXj6TZ2ZdnTNvI5Utpd0Wy5N4GlfXS3TBPBD4kP+ ++pS1vgECgYEA/D7k1IyOM2hGamHc0qG+sIxMHge6rJE8pYtW2suB2KX0bJvAeBY8 +eHM+pPFMbjjZHlU7qB9qmGbZ++ZVlEv/SqqHizvwLzth0P4MJ6/UjAcmAdEUclV0 +YSzMRFk/g0J7aMlJb5NXgA5xlArHLsmV3Zc+QwFPECgzz5LHwD5nTMcCgYEA1x2Y +qb7FXwcQPDcs4Qwux12tCUaExQMZbNoLHWrXw7ktHRfR9sI8TcEErLzc2wnZbdyZ +av/GYSTR9UCeq12kUhmTL4SNryktHKNKEfDEvR7wK6sa9iffzZH8FDe5JktLXnu7 +Oe5SNfLDHA5X7qQefz8s2658+xVJmdp+uasNOnECgYEAlzBXVbJ9VQCuG/tWMQVz +VzxwLxuw3tgagprWz0NlK2ak7ygXn6KsUgG5TYG3ruTx9gVeQXG7IWecRiiTqNQ4 +SxeVMHYXiyfLhEmRHYR9IAT02efomnLv04LXWCwqLlF9yJvFIVQuAPonR3WCV1/K +LMwHLIAvVF7UVxkCEw8UOWcCgYEAwiUH/0sZvuYVFQOHEaV5Ip286b4nXdeqPr+b +gHVJPnAF81foO5iZ7GLj4TKi8V02SxzpqdQmKs6cX4huq6LcBuzmFeDALvIusMX+ +t6phJX6irAbFUpwyNMoog+a2x4T1BNUO6P3aXK44wT2AxvSAQb+2sJ4OVl2kC6NS +9CcYzUECgYEAzqbWlJIbjJx5620Q95bu+lpessOUtoVcYryO6dQNZOiis8aDZjJk +RKdB9qhJlcUeFqnvJS5L5gohaJoyx0wMSYVB7MrO6kAIMHo/OriEQ6CTsQOTqa8n +q4cV9Wuk9pRb1b/x5eXCcHe8P7wBt8KKIh/VBB4aDyeIwGbO0NODYr4= +-----END RSA PRIVATE KEY----- diff --git a/t/keys/admin.pub b/t/keys/admin.pub new file mode 100644 index 0000000..b50a5b9 --- /dev/null +++ b/t/keys/admin.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDT9fu7B3vE68LdRNloCcU5HnGqF2BzJzy+Td3Vtde2GK5RKarm3i6FL2qPSKyZw9fRhE2FIMSWi0bUpJanwNx4mlHZzsZiYQumqgTt5tU+cQEpjRw9f4b0pk2BsnLLHflCWkmaU74uKYzSg7xdqtGmGfeRzSMJMspojmd0SMYMcfh+w57CWvJbtrRFH9usw2IlhjPLkAMI6QCfJdCZutBbidE4I+oWiMEVMQEul7wS44OUlcSZEelrWT6T+CsWCn9zXFs6uOjHXbstlPi+Qt/n6VLCSGryjLNYdStD6tQlmyyLUsIYRlK52Ffmt6qSyYiVPBfQY8gjBLBkU1XGGPnX g3@sita-lt.atc.tcs.com diff --git a/t/keys/config b/t/keys/config new file mode 100644 index 0000000..fc75580 --- /dev/null +++ b/t/keys/config @@ -0,0 +1,20 @@ +host * + stricthostkeychecking no +host admin + identityfile ~/.ssh/admin + +host u? admin + user %USER + hostname localhost +host u1 + identityfile ~/.ssh/u1 +host u2 + identityfile ~/.ssh/u2 +host u3 + identityfile ~/.ssh/u3 +host u4 + identityfile ~/.ssh/u4 +host u5 + identityfile ~/.ssh/u5 +host u6 + identityfile ~/.ssh/u6 diff --git a/t/keys/u1 b/t/keys/u1 new file mode 100644 index 0000000..828d1c3 --- /dev/null +++ b/t/keys/u1 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAuB8HmJ5UX30xFktmvlLgSrzsGIzSiYiAYH8eU6epJGr/xjYD +9GE6G9EcL+/NTc0ziPhIUtVm+h+kFEHtQ1VeOFEuVuWAukPNXRFDrYOMfeR4U1h7 +olT58U3+IlctreKavXr+7bPPhbhvdB7FPM8xusaPfwT6BG4sTqHyOPL5a3eXW7Sp +tuVD87KNHKo3skWcbb78EVQt7MfCMTam6X2O4Y0y1da51kOht6qRaeJHoaAjXB4V +pY9lJSQA+Km5uYu+FIwn89z7P4j2aUNZFq2UOSwuViekSR6lfHvortyh8YFrSRUs +Q4berZUICDp0Ek2BiJirWiPXAp9uxwXms9UbvQIDAQABAoIBAAUTnfMAUpU7b3IM +7C1NPa/x25SltVxjbh67AowN8GT3qku9y4geciq4Lk3ID+IYSVZ6egwGpEs7Ohvw +4Wjc3rcwzdVJiK4aFnx9cF9FZEdIWGT76JTGQQn9O4eY3cKQn/GfhY3qSkuGlVQf +URLnJ5jdxrEa4wXiP8h/QJ1/XY8v9en0uWf/18fMHyzImpd8dqgtTdomSQLjM2ie +1k9Fllh/5Q6e1Kd5mn5QP1QPC65Z78IskOot9Wrg0sk19sWiFMsopgJkQg66BlnM +Fj8A4HPS8Yylt0oXJ5yytUYfvZNDRANZRiAz9mfgQw9oapJLnCLt3Awi5bcKJIVk +/nTccEECgYEA8lSPFeTyzid0sIextXjjHvV4riSZKAHAa5M5DfsPkXLQfbEF4zog +FLZ6c85jUCk7/vTzDRXr38XKaGbAg/1M3UJk7lS9shh1Zdo0+Hshq7rNICNLKz5H +/u1/0gkxqqJcpXaoOHYN1hM7HJrP3uZFDIA5ZrB7JD20YDCQ/2PWrS0CgYEAwoHi +qEKKXOol7FIiG1upTjPaWMTmxtmSs2/pobMVf+ZGDMPts0pbqDegXruaNFUrUQOG +9yvrjA3a2QaKt7R5eDvHAafeMeu0WcHaqUWtIueTtEuduK4fXsCGONBPEGJu+Ct/ +BOCV/W8MAmzIOvffT7Jg1HWsZyAstoikPi1w4tECgYEAuvVmFxw1/7sNGgz2m+2S +PJZh7uipiOYhEF3bTN//mNWd6PskcbSsf45xVttKX9QQR5mv0s6w1koA6R8tNCe+ +n43T1NRoLfkUyenZqENHLPjHvR29prU8Un/ld6REP0NYewfarQTXk+vuVRlTesLp +TsW2g3Vw6/r3KKcPlxntzFkCgYEAqqkH1BY+DHQtPgJ6hoKQNFtuswBgdAymmOYS +mZvlu0iyIbUvNGaDsT7NaRE1pcEstnJf0zMoAsSNRmpk//ZLteDNJXjCjg5/OVnL +n0XROZTylfjatBWi1KIbonGzTW7warLPSdo8ABeU8/O6Y3Lk7qpWJ1PwJrOmR6nw +YdXA/GECgYEAsSokOABGGLQ2zOmDYPDKrRenLho8cSe4g/CF5b6x5MXfJvvBfI/M +hOS/2AFj7UkOSVM9B9QH607F67YJuBPNGvciCatqY/Bcs6ViuuyqG9U4O13OrrmA +oG8Cho3Zy2v3udaLJ6O5JYcpX+hdvkwoG5j/8hLrzkD/3AA12z6QnV0= +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u1.pub b/t/keys/u1.pub new file mode 100644 index 0000000..264c1f0 --- /dev/null +++ b/t/keys/u1.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4HweYnlRffTEWS2a+UuBKvOwYjNKJiIBgfx5Tp6kkav/GNgP0YTob0Rwv781NzTOI+EhS1Wb6H6QUQe1DVV44US5W5YC6Q81dEUOtg4x95HhTWHuiVPnxTf4iVy2t4pq9ev7ts8+FuG90HsU8zzG6xo9/BPoEbixOofI48vlrd5dbtKm25UPzso0cqjeyRZxtvvwRVC3sx8IxNqbpfY7hjTLV1rnWQ6G3qpFp4kehoCNcHhWlj2UlJAD4qbm5i74UjCfz3Ps/iPZpQ1kWrZQ5LC5WJ6RJHqV8e+iu3KHxgWtJFSxDht6tlQgIOnQSTYGImKtaI9cCn27HBeaz1Ru9 g3@sita-lt.atc.tcs.com diff --git a/t/keys/u2 b/t/keys/u2 new file mode 100644 index 0000000..02486a6 --- /dev/null +++ b/t/keys/u2 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEA4/t3WV4q98MlYV9Jbvbf7gE2Dzit6dD8xHsWBh2wTmggQM9I +2RsPp1tTIoOpt4YdlTzV41577BKLVMvqG7AxnVljC7+m7PrT2YmxEGrrbcrHebHu ++pwh0lkN/CIz6MHjWzLbFiRoHhKh9LyfSiKxCgJ3dyjFgAnA+wrXkwIfPRG8qOLk +sb1KUsMdfYm0OUEC/mHU2dsIS5HIY6xhy5Q5BXWgkfYUK7LL7Eyw6ffLhvq4U9tv +Qv+u64Qowew4BY4B8rvyb73iEGcInIF2JRY0jVC8yJFejTJo2KKlXxu8MyAtAhth +cHE6gA7xmn1d8TF7sxHDNqprvD9mLTjUVdz1owIDAQABAoIBAQDEGaWLZYioHV+l +5gSQQiJT4w7RAPv3RyBlEUrcb+UbTE2R8brDpJdOaSuVYJM3nVEM8Ys5TChj43+d +rNjugBvtMNoVXQEEjqxzThDUAmQHyIjUkMzzHCGrgZaZ7gGgkEY0SAZTgXVdiMFu +dmC9sCGAbqa8BIH9pGYuiiDr/sNIDr3ekyqyuSA0Aa2JIrEx1TKFXF5JtGseU9S6 +bUfesCpoWGyVdulr3NbsLM26eDCsZo45OF5QdpTtU99xc9K4gsOre0ZtqEJMVGlR +2nDQILCroH93GabSIW+fiUZD2lO9BxXAM0NA730ODQWyM8IgoWrqxGUuFz40l7X1 +teB7yRwBAoGBAPkkF//ZaEUUyCX6+a6TjaPQ1atemQCxHtIm1phfIM/u2uANqeOP +Z+N3dM0TL53lRx/xbT0dO4sfF73XcF0sYkQj9rep28Q04W8Z6iC/I+jQAJJ0bYl5 +skUGTECxIPLmKOciQF7N5PUGvxhI4oq/0vgDYFc+NW18mow1Z66H1PkjAoGBAOpC +P9EJXEFKZY1lK6ZL6wvJ6tJaPWAuiQlkOdj9wLvvzywQPlEdBJ1k0q+ndAqpR6WJ +eTlkP/bzDpLRi+l4PEVTsFlpxjcfVn19RRabsKTNIS0usl1el/uQP7u4rRimBCz5 +MO72GD4ARM5CgMZZMGU5AXmxKEM9feTcUNss3RmBAoGBALTYsmMRmVKr5y1KpPtI +OER1TuR6Ym3SJCE/9/3a76KAK3j/8hYw/qRrDenex23CBIL3aOg31AUEqOMxA2te +0GXOBUUEk3Y1PH69POpQVOymMAQfZ3OnVvQrwiYjbVtkHsTIZBltM4l5QDWMkoVN +AQLu0HwDuBylmjm0enKCPuIpAoGBAObd257bprwB4gtzhY0ijMbVfENLA+nictN6 +nzgm/Oc68+XtLD0sZ/vl/W13jnljU2TlEz9oeVGbQOWY9lZlVKDOVaIJCHwSul56 +MriRP4lrUCMDPm2eaBJYmzcaTh1YoAzimUMn7cRM54KPL/JKu9NGVxnjala6J3SB +XH5kvJIBAoGBAITZe45tIbVkGjK3jTjgBfaqFfhyws4L3QgRbjqpy2h9nLEGHMYV +RkIt6bCkw6cy+8TnYB0iG9lcGP1S5E4C6zpTdldi/5tGl7uu9qfEz4hxRpRbJ4Q0 +nwZzUkgBaLxAiLHfntBpwk16UvHkCpo5hiKzSLzxfReXzQPUUudGRnsG +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u2.pub b/t/keys/u2.pub new file mode 100644 index 0000000..916dcf5 --- /dev/null +++ b/t/keys/u2.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDj+3dZXir3wyVhX0lu9t/uATYPOK3p0PzEexYGHbBOaCBAz0jZGw+nW1Mig6m3hh2VPNXjXnvsEotUy+obsDGdWWMLv6bs+tPZibEQauttysd5se76nCHSWQ38IjPoweNbMtsWJGgeEqH0vJ9KIrEKAnd3KMWACcD7CteTAh89Ebyo4uSxvUpSwx19ibQ5QQL+YdTZ2whLkchjrGHLlDkFdaCR9hQrssvsTLDp98uG+rhT229C/67rhCjB7DgFjgHyu/JvveIQZwicgXYlFjSNULzIkV6NMmjYoqVfG7wzIC0CG2FwcTqADvGafV3xMXuzEcM2qmu8P2YtONRV3PWj g3@sita-lt.atc.tcs.com diff --git a/t/keys/u3 b/t/keys/u3 new file mode 100644 index 0000000..163bdef --- /dev/null +++ b/t/keys/u3 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEArK6uQkgoAnS+w6vs4DmvdOfcGdFUzh3ivHAXHug7sjjKGUB2 +KwcXNwcmJPtyNXM0BJ9ZoOJSqJo5cWLMl7Qn1HBubuyM02Id9EqeJu1Ytn/i1XFY +NMp8fj4wma3LZTdeOy3ockbefkw6VQUq3cheXIeaVpT91jsuyIaE0ejWkjGMu596 +zXFQZYTSO28TIYghRvhXGq5W9hJ3V2k+ZAQ/AsWQqjK4XruICi+RGRpKj59ECI7V +zIrq4MUEti+3LldaY6tyYsTGQLtFJYu+l/ZavkrM979cPOxLeoi8ZHPTPKh6asdr +ZXA2J6++IyIgNy2Q4sNxTmkIlU/EDysvTTGdMwIDAQABAoIBABF+NJr0UlFFYFnU +Hc/tKBAQuORIp22l62Upeb4gyoNYa2i5df8P3dMuPzf53Oz7OabKObspkjQQQ4dv ++cfYcTx9E0LbZby4MM6hjHnnC1iZhfIXZFccuBXV2PiIeZVMUZhvIyAIe9uRf0tD +lb8X4C9BcWoZ98ju/+NCdUwKaUov3jXc32hmsAhK+dtqBE+lwccX9keJQcncf+6j ++2znpDAJdaF70dM0DidbkmXmOTgH6LjjqrYRTAUnVsvUyDsr5YhopwOHs0E95YB4 +RzO7V/DA8H7DQ+XE20Iqp2i6dSbRQQPxbQLvJG4BaITIqb1L8/WJ6N75O/uns4rE +Y8WVwWECgYEA1gDDP70DqvVMu6KDvn18pvfxzxJ3jccYcBZITV/E6xgj1AbH7fdA +0iwvG6jQ26DTUBfLBquZ2fCCyI44OUpZ8GZu/wYBn5CQjYtr1vJ7zHKM3dVf+POT +cGgOVDIHopCCX5Dwb74OpbkTV4g/WxouClvz0Ovobq8NncSkJJkyGEMCgYEAzpIF +oj2AVMWDd6NL+P8e+QXPYEvJ/trAHoAteI83Eof4ZOC/sBr7Gf3c6nM7ZJbCXGhJ +NCCr4teHJMg9DThQ1KxKn9qEf9dWiAE+HCouaZU98Z0UcLQ+tgPeBh/Dw7rTF3M2 +7A/LtLYbg1MoPCZNj6V4qGjmNWCy2lku1ZGBUFECgYBD/4oKvqxjrf3rwP/Lj2QE +SdRzz5JdYl3Jf8sJityvNsRropv0aRQXtCJjz4hNwRRj5quEOxJvxZRI1afXzGA3 +mtS6A9aQNQc5couZiQL9O4i3FA2itQKsPOQQrLTwWqqSYyOC3gkZb21N6uT2taLb +d8xJHiyEvuq8rrbZSjQ4sQKBgEkUDZws58aVrYHYqlrnXny4mnm1tjtMBiWEMRHy +kIgkxDJj9EyH7wdt8QacR4m5b/8jAarIWCbDGtNfZ4HSx33FigztUGytsLYiwmdS +YOMHYkeky4NnsLvRuG0wNaB76ovkPazblbRTrH4UICrPXicQYhQqMC74C64FWPVD +KZ1RAoGAE/vKCHCzPegTT9gr2aaIrhLPUUZboOF4gHajYr9Scr176nJhpIvP/0Y2 +yQtqfas5lID8ouqXb+oL0Q4Yi00hdu+TRYQHm3M+2UL7wgffR5H2vfhk24UUDfV5 +0qQjNKp3pNUWZdiZ2J+RGUszXt0THfWbWI/ntwnG5QchqXCqYEA= +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u3.pub b/t/keys/u3.pub new file mode 100644 index 0000000..e97645c --- /dev/null +++ b/t/keys/u3.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsrq5CSCgCdL7Dq+zgOa9059wZ0VTOHeK8cBce6DuyOMoZQHYrBxc3ByYk+3I1czQEn1mg4lKomjlxYsyXtCfUcG5u7IzTYh30Sp4m7Vi2f+LVcVg0ynx+PjCZrctlN147LehyRt5+TDpVBSrdyF5ch5pWlP3WOy7IhoTR6NaSMYy7n3rNcVBlhNI7bxMhiCFG+Fcarlb2EndXaT5kBD8CxZCqMrheu4gKL5EZGkqPn0QIjtXMiurgxQS2L7cuV1pjq3JixMZAu0Uli76X9lq+Ssz3v1w87Et6iLxkc9M8qHpqx2tlcDYnr74jIiA3LZDiw3FOaQiVT8QPKy9NMZ0z g3@sita-lt.atc.tcs.com diff --git a/t/keys/u4 b/t/keys/u4 new file mode 100644 index 0000000..a669e34 --- /dev/null +++ b/t/keys/u4 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA2Wg3bl7T0C8VuR8HdbAqmwvQH4/T/maaqlQeJqcATRgWQNDv +VthEasW5Kx8DzcSVRWS0cJ5EpTLGvrs84aXgdvg6TwFZKO/ujrkFDZmw9hd4I/Dv +0dp/Y7himS8vAvnnWfYyqJBiX4plEx9Kg8oWHwy8KK3HHKoO8jAWAHOWO3GMB8BV +128VLovGB6Sp99GrgltzP9UhNRHt/doa3ve8+fDk782SandVTTR9MNLt7qhMSOKr +bmoFWtL36W5hmVjFGTZC1ZNIU6PiqygUqPtyAYblwv/nZ35s72KmxP7Seag3SsuZ +UPnRjM4PZ+7YE7tcPTOUxcct8xuTZXgjh2WiNwIDAQABAoIBADSrR8qIVJ452fRo +LQF49UlsmjYbPQuDxfJ/wHIywSLsM+/t7h3G9QQ89Hga4mwGNPeDxycFYLH41Cc+ +6yfrbK7FwjKDrBr7zXpsHmpGEpX755Ile6QGYBhDgjeEM8pvynmD6I/nsr1cpNH2 +IbI90hAhoK/mMbejB03rEll3pyytCgEvJQsu847dTNTZN+PHsumPr9HERi/dDrbw +JrDSH2tbOvYw4UW9HLFfZAB+IgMo34WXf6kcUY69wWQbxnv1e7KHnYkxIuLCGZ6x +Lc9APM97f4atlGt+mAtqK97CJB1AqoIE3KpPq1x+gpFSBNEE+9U9KnItuSqF3mG4 +vq/VjIkCgYEA+ASubOgzJaAldNz3dinLYK6MLB+V1R+RpkDc3+OgfF5mgg11ZtpE +/DO1Ndpf5dOYB4JYGfhC9+xomHGsQmbOsIUprWaAR/xaO6Bgxw7cxkOBIadsrdwu +MWJ6h3gN72zuhKPERpUVVH7ZH5KQfZwxEMgquUkGdEwumU4rMXeCFqsCgYEA4GdX +qI/5UNXEPnXk3dDWNzNJO7gRoonU228IM18qz5ZKMRIKp6Sq+wIuO8+aQMr2K0rO +RMQk+lLOZ17omaWh9ysDPzTCWRrjOiDOnYWDPCclTeqSnEk8uuWyppDGNXgQ6osM +LnwJSeP8+1EDgkKf5zoiQfcyBc0v8PSRSdTfEqUCgYEA2PqHeqHd9UHY4xdZq1e/ +JLMv0H5Ff/GhY7iFQ54JziRsO8T4e+Xiyl2WYCnPEer+qzseRoIKXInHq+5uzJzS +oF2va5MsEU41xsp1QFDBVvbBpyapDqV9CBlmptOiJV/Af+wiD7nnskdTPqrjm/Ck +gFEOB5Fagy4O6nIXmaw69AcCgYEAhVSBndKlZKUOa7oqmKzLipK7UXNFbxiL0zE+ +Yx+JVTvLqyo4EHFjca5TABCSayrsZr6UngEYo27t2jdm5lumRzBURoq3aq/yEIiL +msZIOkZcANZ988QEBFwT8KmWSxCipGinfTsPXcrLdhslhZDGZ2GAF0ejfhTzBiyZ +4o9LV00CgYBf46Z2M1fWI6Tc8HUKr9WoyUmTmUtHUFPt9IZ2CKm2czoltpku7cC7 +ztlt4LmVPKv1UUavbC/nCz6s1ylOkY0rdm45FSYXKDYPMQqzQix1jG4GZJjM9En+ +M848LupnHBFsmHyQqyyRlsg1gb+wtvAw7Y44wcfAhGbiAT5DVX+zxg== +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u4.pub b/t/keys/u4.pub new file mode 100644 index 0000000..06f3648 --- /dev/null +++ b/t/keys/u4.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDZaDduXtPQLxW5Hwd1sCqbC9Afj9P+ZpqqVB4mpwBNGBZA0O9W2ERqxbkrHwPNxJVFZLRwnkSlMsa+uzzhpeB2+DpPAVko7+6OuQUNmbD2F3gj8O/R2n9juGKZLy8C+edZ9jKokGJfimUTH0qDyhYfDLworcccqg7yMBYAc5Y7cYwHwFXXbxUui8YHpKn30auCW3M/1SE1Ee392hre97z58OTvzZJqd1VNNH0w0u3uqExI4qtuagVa0vfpbmGZWMUZNkLVk0hTo+KrKBSo+3IBhuXC/+dnfmzvYqbE/tJ5qDdKy5lQ+dGMzg9n7tgTu1w9M5TFxy3zG5NleCOHZaI3 g3@sita-lt.atc.tcs.com diff --git a/t/keys/u5 b/t/keys/u5 new file mode 100644 index 0000000..ed65131 --- /dev/null +++ b/t/keys/u5 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA41A0bY6+0akNSJlR2PeRATNtncARXVOUar7CNaxwPqVXQR1+ +TmU9evmIEkRLf0kFAa7L3QDFroFu4sDiSJjvfYIkHdoxO4Fk128PJBhObIXaarKc +UBIZ29/8I3dTedq5CY/YHL/AjaT+0VktWX7YwigvGDamrXAKqjnW1mWKp6TNj8bp +vppBvj3yvdYoOLYvCs/SKfKdlayngiihTbKELPcRu8NzYxHiF2b/u0t31evdP0fA +/apAslKhHdCm8ScZJuyIdztcogBFE5dGm0h3qlbJKvKT8JmTcgQ5TBBcmqPVmUkm +nPvIzd2G7D1smbExG7LnqekHcS9dvaPnF0B3oQIDAQABAoIBAGl1e21crXDN0mjd +INjdOnvpJTDru+KldRT0/VszbjvSL6H5EfFDDPvxqsx2vOQHt3fpZZFZ21yzlgND +Y3g0499BsonbAb5OsL82OjsPv8qfaw7XYKfRTgfxaaP2p1bAP9qMzsG/wJC2fLYZ +fm2n6N5jED5WlIugkIIbJW4AXAycDB2ZU0xtPTHJ8nrSj1otDCsD2VbbVHXN7H6g +HrTqP4RqD+uVDIxSrXllz4Udwe/I1wUrvY9HjH2qS6Liqb5kw8SOf4a2et18+KB2 +NNk6ZEAlmOx1ddC2eZPxm8XxAxdSwTggcwvtixCeoXR53OwTZAZ8BBzwusrMklZm +/n5zPWUCgYEA88Lf4i0WFu9h4FnQ6qxCAKDS1XyRpCYt5cyTpZPMV3LuUV0DPS3K ++EZeU689BSOiwav8omCtrrrOHtE9fHjOH85Gd4IRyOwUQWI7RLpFiI8Lbs4tMbP5 +k1UOzzTji++N47XfTTQVdwHbx4jac80LVavbRd3AKd6oRjc/gQOpgasCgYEA7rnr +uoWqT76xVNLmE+g93x33hzES2HitgjHzvm5B2Cu6fwlXi7cSnLEWVn7W5QXEuhek +6uhq4NC0ahL/qAyJsFhVve32qrR7yacDVlMWZ5iQPfqtvS9CsxyafADBWsgeN4L1 +5oqQofNlh0l+UvMFp8INNbKfxTOPKCMfGxIEd+MCgYEA7UsJky380PrbtwD4JVrn +LaFhXL3VMYyRJaFPIeKNC5wwbzgyjP3lFme6L5Dpv/T+3bZFSvT+XpgvS0S5rFAV +qFSvuGsAUS2wUi4EMFV8lwFZSdafnEDtdgVZU1DTKkhbQg6sgIVxV9aRUt7gedZj +cFTKMms6RAgim6fww/ECs90CgYBdI1pt9jJhVHPZNUMgpy5ke0uUijfhDwwazKRd +OqUj0sO7RojKcM2pJoohivEKf3qmZA0qvSzds2+AJxNpnCKoE364UDw5k5rsLOXn +axlFp8c29zOLqQGr4c//60eExKjNXaHUpWESXmTRKIJJmJkvP01qEtu0043ZygIb +zKbDowKBgHhacDR3aat3kkaTp/4AhekhDhMgZ1u2NIi0ycsA6zRlmFucHMwtKCM0 +VMuu40D9N1lTmcdndNKkTJx6CpbS7g/y0ctkyGwgFdmTjjHYl1nATt9G2oRzKx6I +nQ+sBUwBPieIqEmiFh+KAsDox6plrtvhSSwp8FYLWBJXZHlLJIsd +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u5.pub b/t/keys/u5.pub new file mode 100644 index 0000000..96a0045 --- /dev/null +++ b/t/keys/u5.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDjUDRtjr7RqQ1ImVHY95EBM22dwBFdU5RqvsI1rHA+pVdBHX5OZT16+YgSREt/SQUBrsvdAMWugW7iwOJImO99giQd2jE7gWTXbw8kGE5shdpqspxQEhnb3/wjd1N52rkJj9gcv8CNpP7RWS1ZftjCKC8YNqatcAqqOdbWZYqnpM2Pxum+mkG+PfK91ig4ti8Kz9Ip8p2VrKeCKKFNsoQs9xG7w3NjEeIXZv+7S3fV690/R8D9qkCyUqEd0KbxJxkm7Ih3O1yiAEUTl0abSHeqVskq8pPwmZNyBDlMEFyao9WZSSac+8jN3YbsPWyZsTEbsuep6QdxL129o+cXQHeh g3@sita-lt.atc.tcs.com diff --git a/t/keys/u6 b/t/keys/u6 new file mode 100644 index 0000000..86deee7 --- /dev/null +++ b/t/keys/u6 @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxyRjRT8RoSDnAnbZdrTjXhBMrkfNfolWFqc3qAjAo8Tmp7Ns +n7R+KCl31RDkC9u4ll4AOfF9bIdP9ovDVvXoTMoiOdPTYqsnaMBBpDH04vxID2U5 +rEOhSzbvTazzaSlYNFED2a9bMfULuF6WxchFPBQGhTZaC8cDAkS5YYXvjHXAn1GN +kpv0k5qltD8vjJoM7Mg5JLm84WejPQ5CmwOXqsQj69ZUZEyA8J3oqWVYkEhpYkbK +IuzaHkrTC0PUQJ8MS3wM8358bWp53zYFJMkyL1a/zJQPOMaDiFTXXj1Uue/5ZkIM +/fkkOMLbaCgEFCMbL8HkVEq4Q0dLhJKl1IdzbQIDAQABAoIBACQd91shuyLMAtmx +kHM1D1+J+T5Ki3x9j/1/ylpRbA7HsUWNBxBX/eFu0+ryq0lzSiELX2Mi5yp9yATh +CEaHRuBWcKqoPlhQzk7zP3R2EwHv22nfY/xYL7KiffhKe8MA2pxybQ5X/WQsGzoO +/a1VSylAQIZ8ewxTxbntmOmVDwMcLZdY5X4NAmzUw1lFD2TVOlHyhjvhgIzhO1tp +fBvsX3OL+Pk0tTQebuhoqEy2R01BLc+0ZFAKAFZpZgualqZqjyIU0isQsEo+EK4s +Pn7Ccxy+156aWAEdgD5Aj7oMn3zA9YIt/JoX8muaceUOj3E7B5ZKBtYZkFPVnKO9 +rPMNTIkCgYEA/v5IeFDZjcAMLWqhuPekcUQYMXc+I0ZTn7vT3aksWxhARG96CPdG +HNLMw4y8yZLnCAsdKUJGtrVcn4y4K0FzUYn0tDm9cmtFoFcQvLPp4mR1kB84urIG +7qEwv4djeLhl0cYsqMpyl7qflbTVwKa09Fy7HX9ZFL58nXVX63uRXlMCgYEAx+2o +L/GKkKgRPpCudsGoplECjzqP4SWHXaYVOupVzpnvxFKVcpBl6Un6p6U9V6W16k2C +XUg9XqFdleawfAwGQ2D/Ip/u4r8GKOphv0QCjO88ld15Ky9mr9Sk4/Z2EAMUrmKg +CS4hGBF7VIeA3FnzJwLkYL0+WQKpKBt/zojQLz8CgYEAnmtEgttYDeTeq+iviMbx +9xyjGzhF9oxer8J1oiTUVdP/OYU4gBGAEbA1Xtg1AdauiiS9fUCbxi9u2AEI+naz +OllHGiE1Pby/iRoOX+42xFw9XcjH6dVo0SB7tMJcXkfRmj5QyJzeDL35H301v3bS +vW5PIchYg7bEnN6mPLqMWdkCgYBVWaX1Yb5v5vAFr6prVF11MxxOnQeTbHwPhLmH +f0bGfn0XaNIYKID5SPXS3/4CDuJMdm5y+EYKwgS729H4AwIhfaUt2O0Yq8gra3Pz +PUuBcxiAOh5iS0ghRDxofW0FhOstTzlW8fR62+u0uGxQpa3iN5/blK6rPTGNx7+W +Il4N7QKBgHRTxUZraVt3n0kJ4+tdc+F8XK1wLyVC9PmtW+28tiyx14k8o8H/6W94 +r3lyI13sUnvW6zU0VMAALQujRcJDLac/zSUdFGmgU3P3QatU5yUm0Xpt1uFM49Zw +xZLBTDJxe2Qrc3Z3SKReRqxLz6tTU1soH7TVw/S36tBovKjTw7Cc +-----END RSA PRIVATE KEY----- diff --git a/t/keys/u6.pub b/t/keys/u6.pub new file mode 100644 index 0000000..de5b06b --- /dev/null +++ b/t/keys/u6.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDHJGNFPxGhIOcCdtl2tONeEEyuR81+iVYWpzeoCMCjxOans2yftH4oKXfVEOQL27iWXgA58X1sh0/2i8NW9ehMyiI509NiqydowEGkMfTi/EgPZTmsQ6FLNu9NrPNpKVg0UQPZr1sx9Qu4XpbFyEU8FAaFNloLxwMCRLlhhe+MdcCfUY2Sm/STmqW0Py+MmgzsyDkkubzhZ6M9DkKbA5eqxCPr1lRkTIDwneipZViQSGliRsoi7NoeStMLQ9RAnwxLfAzzfnxtannfNgUkyTIvVr/MlA84xoOIVNdePVS57/lmQgz9+SQ4wttoKAQUIxsvweRUSrhDR0uEkqXUh3Nt g3@sita-lt.atc.tcs.com diff --git a/t/listers.t b/t/listers.t new file mode 100755 index 0000000..5fbf0ae --- /dev/null +++ b/t/listers.t @@ -0,0 +1,134 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# the various list-* commands +# ---------------------------------------------------------------------- + +try 'plan 30'; + +try "## info"; + +confreset;confadd ' + @oss = git gitolite gitolite3 + @prop = cc p4 + @crypto = alice bob carol + @dilbert = alice wally ashok + + repo @oss + RW = u1 @crypto + R = u2 @dilbert + repo @prop + RW = u2 @dilbert + R = u1 + repo t3 + RW = u3 + R = u4 +'; + +try "ADMIN_PUSH info; !/FATAL/" or die text(); +try " + /Initialized.*empty.*cc.git/ + /Initialized.*empty.*p4.git/ + /Initialized.*empty.*git.git/ + /Initialized.*empty.*gitolite.git/ + /Initialized.*empty.*gitolite3.git/ + /Initialized.*empty.*t3.git/ +"; + +try "gitolite list-groups"; cmp +'@crypto +@dilbert +@oss +@prop +'; + +try "gitolite list-users"; cmp +'@all +@crypto +@dilbert +admin +u1 +u2 +u3 +u4 +'; +try "gitolite list-repos"; cmp +'@oss +@prop +gitolite-admin +t3 +testing +'; + +try "gitolite list-phy-repos"; cmp +'cc +git +gitolite +gitolite-admin +gitolite3 +p4 +t3 +testing +'; + +try "gitolite list-memberships -u alice"; cmp +'@crypto +@dilbert +'; + +try "gitolite list-memberships -u ashok"; cmp +'@dilbert +'; + +try "gitolite list-memberships -u carol"; cmp +'@crypto +'; + +try "gitolite list-memberships -r git"; cmp +'@oss +'; + +try "gitolite list-memberships -r gitolite"; cmp +'@oss +'; + +try "gitolite list-memberships -r gitolite3"; cmp +'@oss +'; + +try "gitolite list-memberships -r cc"; cmp +'@prop +'; + +try "gitolite list-memberships -r p4"; cmp +'@prop +'; + +try "gitolite list-members \@crypto"; cmp +'alice +bob +carol +'; + +try "gitolite list-members \@dilbert"; cmp +'alice +ashok +wally +'; + +try "gitolite list-members \@oss"; cmp +'git +gitolite +gitolite3 +'; + +try "gitolite list-members \@prop"; cmp +'cc +p4 +'; + diff --git a/t/manjaro-root-smart-http-test-setup b/t/manjaro-root-smart-http-test-setup new file mode 100755 index 0000000..f254b55 --- /dev/null +++ b/t/manjaro-root-smart-http-test-setup @@ -0,0 +1,114 @@ +#!/bin/bash + +# gitolite http mode TESTING setup for Manjaro +# - Probably works for Arch also; if someone tests it let me know +# - Use the comments to create a version for your distro if needed + +# CAUTION: This script needs to be run as root, so you best eyeball it at +# least once to make sure you know what changes it is making. + +# WARNING: clobbers /srv/http/gitolite-home, and also creates 7 http +# users with trivial passwords FOR TESTING. + +# HOWEVER: if you remove some of that, especially the part that creates test +# users, this *should* work as a quick "setup gitolite http mode" script. + +# CAUTION: This script assumes the httpd.conf file is pretty much the default +# "as shipped" version. If you fiddled with it, this script *may* break. +# It's on you to determine if that is the case and manually simulate the +# actions of this script. It's not that hard, and anyway it's just once (for +# a given server) so it's not too bad. + +# ---------------------------------------------------------------------- +# BEGIN APACHE CONF CHANGES + +# Unlike Fedora, Manjaro's default httpd.conf does not contain a wildcard +# include for stuff in conf.d; they're all explicitly included, so we need to +# include gitolite.conf. +cd /etc/httpd/conf +grep ^Include.*gitolite.conf httpd.conf || + printf "\n%s\n%s\n" '# gitolite http mode' 'Include conf/extra/gitolite.conf' >> httpd.conf + +# Again, unlike Fedora, Manjaro's default conf does not come with cgi enabled. +# In fact, the directive is both commented out *and* inside an "IF" block for +# some other module. Since I don't plan to be an expert on apache, I will +# punt by including the required LoadModule line before the first LoadModule +# line that is not in an "if" block (i.e., not indented). +grep '^LoadModule cgi_module modules/mod_cgi.so' httpd.conf || + perl -i -pE 'say "LoadModule cgi_module modules/mod_cgi.so" if /^LoadModule/ and not $flag++' httpd.conf + +# END APACHE CONF CHANGES +# ---------------------------------------------------------------------- + +cd ~http +# should be /srv/http; you may want to check just to be safe +export GITOLITE_HTTP_HOME=$PWD/gitolite-home + +[[ -d gitolite-home ]] && { + [[ $GITOLITE_TEST != y ]] && { + echo "If you're OK with clobbering $GITOLITE_HTTP_HOME, please rerun with +environment variable GITOLITE_TEST set to 'y'." + exit 1; + } +} + +rm -rf gitolite-home +mkdir gitolite-home + +# setup apache conf for gitolite +cd /etc/httpd/conf/extra +[[ -f gitolite.conf ]] || { + cat > gitolite.conf <<-EOF + SetEnv GIT_PROJECT_ROOT $GITOLITE_HTTP_HOME/repositories + ScriptAlias /git/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ + ScriptAlias /gitmob/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ + SetEnv GITOLITE_HTTP_HOME $GITOLITE_HTTP_HOME + SetEnv GIT_HTTP_EXPORT_ALL + + <Location /git> + AuthType Basic + AuthName "Private Git Access" + Require valid-user + AuthUserFile $GITOLITE_HTTP_HOME/gitolite-http-authuserfile + </Location> + EOF +} + +# get the gitolite sources +cd $GITOLITE_HTTP_HOME + +if [[ -d /tmp/gitolite.git ]]; then + git clone /tmp/gitolite.git gitolite-source + # I do this because I have to test stuff *before* it gets to github, so I + # can't simply clone what's on github. Instead, I use a local + # world-readable bare repo cloned from my dev environment. +else + git clone 'https://github.com/sitaramc/gitolite' gitolite-source +fi + +# make the bin directory, and add it to PATH +cd gitolite-source +mkdir $GITOLITE_HTTP_HOME/bin +./install -ln $GITOLITE_HTTP_HOME/bin +export PATH=$PATH:$GITOLITE_HTTP_HOME/bin + +# come back to base, then run setup. Notice that you have to point HOME to +# the right place, even if it is just for this command +cd $GITOLITE_HTTP_HOME +HOME=$GITOLITE_HTTP_HOME gitolite setup -a admin + +# insert some essential lines at the beginning of the rc file +echo '$ENV{PATH} .= ":$ENV{GITOLITE_HTTP_HOME}/bin";' > 1 +echo >> 1 +cat .gitolite.rc >> 1 +\mv 1 .gitolite.rc + +# create users "admin" and "u1" thru "u6" for testing +htpasswd -bc $GITOLITE_HTTP_HOME/gitolite-http-authuserfile admin admin +seq 6 | xargs -I % htpasswd -b $GITOLITE_HTTP_HOME/gitolite-http-authuserfile u% u% + +# fix up ownership +chown -R http:http $GITOLITE_HTTP_HOME + +# restart httpd to make it pick up all the new stuff +systemctl restart httpd diff --git a/t/merge-check.t b/t/merge-check.t new file mode 100755 index 0000000..fdea318 --- /dev/null +++ b/t/merge-check.t @@ -0,0 +1,95 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# merge check -- the M flag +# ---------------------------------------------------------------------- + +try "plan 55"; + +confreset;confadd ' + repo foo + RW+M = u1 + RW+ = u2 + RWM .= u3 + RW = u4 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# setup a merged push + +try " + cd .. + [ -d foo ]; !ok + glt clone u1 file:///foo + ok; /Cloning into/ + /You appear to have cloned an empty/ +"; + +try " + cd foo; ok + [ -d .git ]; ok + test-commit aa; ok; /1 file changed, 1 insertion/ + tag start; ok + glt push u1 origin master + ok; /new branch.*master.-..master/ + /create.delete ignored.*merge-check/ + checkout -b new; ok; /Switched to a new branch 'new'/ + test-commit bb cc; ok + checkout master; ok; /Switched to branch 'master'/ + test-commit dd ee; ok + git merge new; ok; /Merge made.*recursive/ + test-commit ff; ok + tag end; ok +"; + +# push by u4 should fail +try " + glt push u4 file:///foo master + !ok; /WM refs/heads/master foo u4 DENIED by fallthru/ + /To file:///foo/ + /remote rejected.*hook declined/ + /failed to push some refs/ +"; + +# push by u3 should succeed +try " + glt push u3 file:///foo master + ok; /To file:///foo/; /master.-..master/ +"; + +# rewind by u3 should fail +try " + reset-h start; ok; /HEAD is now at .* aa / + glt push u3 file:///foo +master + !ok; /rejected.*hook declined/ + /failed to push some refs/ +"; + +# rewind by u2 should succeed +try " + glt push u2 file:///foo +master + ok; /To file:///foo/ + /forced update/ +"; + +# push by u2 should fail +try " + reset-h end; ok; /HEAD is now at .* ff / + glt push u2 file:///foo master + !ok; /WM refs/heads/master foo u2 DENIED by fallthru/ + /To file:///foo/ + /remote rejected.*hook declined/ + /failed to push some refs/ +"; + +# push by u1 should succeed +try " + glt push u1 file:///foo master + ok; /master.-..master/ +"; diff --git a/t/mirror-test b/t/mirror-test new file mode 100755 index 0000000..3ace59b --- /dev/null +++ b/t/mirror-test @@ -0,0 +1,445 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# you need 3 disposable userids: sam, frodo, gollum. Then the test user (say +# "g3") needs to be able to sudo into them. Put this in /etc/sudoers: + +# g3 ALL = (sam,frodo,gollum) NOPASSWD: ALL + +$ENV{TSH_ERREXIT} = 1; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; +use Cwd; +my $workdir = getcwd(); +my $h = $ENV{HOME}; +my ($t, $t2); # temp vars + +# basic tests +# ---------------------------------------------------------------------- + +try "plan 152"; +## try "DEF POK = !/DENIED/; !/failed to push/"; + +## confreset;confadd ' + +## '; + +## try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# ---------------------------------------------------------------------- + +# switch keys +sub swk { + my $h = $ENV{HOME}; + my $k = shift; + system("cp $h/.ssh/$k $h/.ssh/id_rsa"); + system("cp $h/.ssh/$k.pub $h/.ssh/id_rsa.pub"); +} + +sub all { + try "F " . join(" ", @_); + try "S " . join(" ", @_); + try "G " . join(" ", @_); +} + +try " + DEF F = sudo -u frodo -i + DEF S = sudo -u sam -i + DEF G = sudo -u gollum -i +"; + +my $bd = `gitolite query-rc -n GL_BINDIR`; + +try " + $bd/../t/mirror-test-setup.sh; ok or die mirror setup shell script failed + /hello server-frodo, this is frodo/ + /hello server-sam, this is frodo/ + /hello server-gollum, this is frodo/ + /hello server-frodo, this is sam/ + /hello server-sam, this is sam/ + /hello server-gollum, this is sam/ + /hello server-frodo, this is gollum/ + /hello server-sam, this is gollum/ + /hello server-gollum, this is gollum/ + /hello admin, this is frodo/ + /Initialized empty .*/gitolite-admin.git/ + /Initialized empty .*/r1.git/ + /Initialized empty .*/r2.git/ + /Initialized empty .*/testing.git/ + /Initialized empty .*/gitolite-admin.git/ + /Initialized empty .*/r1.git/ + /Initialized empty .*/r2.git/ + /Initialized empty .*/testing.git/ + /Initialized empty .*/gitolite-admin.git/ + /Initialized empty .*/r1.git/ + /Initialized empty .*/r2.git/ + /Initialized empty .*/testing.git/ +"; + +# ---------------------------------------------------------------------- +# SECTION 1: gitolite-admin shenanigans + +# push to frodo and see sam and gollum change +try " + git clone frodo\@localhost:gitolite-admin fga + ok; /Cloning into 'fga'.../ + cd fga; ok + cp $h/.ssh/u?.pub keydir; ok + git add keydir; ok + git commit -m 6keys; ok + git push; ok + /To localhost:gitolite-admin/ + /master -> master/ + sleep 5 + git rev-parse HEAD +"; + +chomp($t = text()); + +try " + git ls-remote sam\@localhost:gitolite-admin + ok; /$t/ + git ls-remote gollum\@localhost:gitolite-admin + ok; /$t/ +"; + +try " + cd .. + +"; + +# push to sam and see frodo and gollum change +try " + git clone sam\@localhost:gitolite-admin sga + ok; /Cloning into 'sga'.../ + cd sga; ok + empty; ok + git push; ok + /To localhost:gitolite-admin/ + /master -> master/ + sleep 5 + git rev-parse HEAD +"; + +chomp($t = text()); + +try " + git ls-remote frodo\@localhost:gitolite-admin + ok; /$t/ + git ls-remote gollum\@localhost:gitolite-admin + ok; /$t/ +"; + +try " + cd .. + +"; + +# push to gollum and fail at gollum +try " + git clone gollum\@localhost:gitolite-admin gga + ok; /Cloning into 'gga'.../ + cd gga; ok + empty; ok + git push; !ok + !/To localhost:gitolite-admin/ + !/master -> master/ + /gollum: pushing 'gitolite-admin' to copy 'gollum' not allowed/ + git rev-parse HEAD +"; + +chomp($t2 = text()); + +try " + git ls-remote frodo\@localhost:gitolite-admin + ok; /$t/; !/$t2/ + git ls-remote sam\@localhost:gitolite-admin + ok; /$t/; !/$t2/ + git ls-remote gollum\@localhost:gitolite-admin + ok; /$t/; !/$t2/ +"; + +# fake out the gollum failure to continue the redirected push and fail at frodo +try " + sudo -u gollum -i gitolite git-config -r gitolite-admin . + ok + /redirectOK.*sam/ + !/redirectOK.*gollum/ + + sudo -u gollum -i bash -c 'echo repo gitolite-admin > junk' + sudo -u gollum -i bash -c 'echo option mirror.redirectOK-1 = gollum >> junk' + sudo -u gollum -i bash -c 'cat junk >> .gitolite/conf/gitolite.conf' + sudo -u gollum -i gitolite compile + sudo -u gollum -i gitolite git-config -r gitolite-admin . + ok + /redirectOK.*sam/ + /redirectOK.*gollum/ + + git push; !ok + /frodo: redirection not allowed from 'gollum'/ + !/To gollum\@localhost:gitolite-admin/ + !/master -> master/ +"; + +# reset gollum via frodo +try " + cd .. + rm -rf fga + git clone frodo\@localhost:gitolite-admin fga + ok; /Cloning into 'fga'.../ + cd fga; ok + empty; ok + git push; ok + /To localhost:gitolite-admin/ + /master -> master/ + sleep 5 + + sudo -u gollum -i gitolite git-config -r gitolite-admin . + ok + /redirectOK.*sam/ + !/redirectOK.*gollum/ + + git rev-parse HEAD +"; + +chomp($t = text()); + +try " + git ls-remote sam\@localhost:gitolite-admin + ok; /$t/ + git ls-remote gollum\@localhost:gitolite-admin + ok; /$t/ +"; + +# ---------------------------------------------------------------------- +# user repo shenanigans + +# for a recap of the perms see t/mirror-test-setup.sh + +try " + cd .. + pwd + /tmp/tsh_tempdir/ or die not in the right place +" or die; + +swk('u1'); + +# u1 sam r1, R ok, W ok +try " + rm -rf fga sga gga + + git clone sam\@localhost:r1 sr1 + /Cloning into 'sr1'.../ + /warning: You appear to have cloned an empty repository/ + cd sr1 + empty + git push origin master + /new branch/; /master -> master/ + sleep 5 + git rev-parse HEAD +"; +chomp($t = text()); + +# u1 sam r1, W mirrors to frodo but not gollum +try " + git ls-remote sam\@localhost:r1 + /$t/ + git ls-remote frodo\@localhost:r1 + /$t/ + git ls-remote gollum\@localhost:r1 + /gollum: 'r1' is mirrored but not here/ +"; + +swk("u2"); +try " + empty + git rev-parse HEAD +"; +chomp($t2 = text()); + +# u2 sam r2 W ok, mirrors to all +try " + git push sam\@localhost:r2 master + /new branch/; /master -> master/ + /master -> master/ + sleep 5 + git ls-remote frodo\@localhost:r2 + !/$t/ + /$t2/ + git ls-remote gollum\@localhost:r2 + !/$t/ + /$t2/ +"; + +swk("u1"); + +# u1 gollum r1 -- "known unknown" :-) +# u1 frodo r1 R ok, W not ok +# u1 sam r1 R ok, W ok +try " + cd .. + rm -rf sr1 + + git clone gollum\@localhost:r1 fr1 + /gollum: 'r1' is mirrored but not here/ + + git clone frodo\@localhost:r1 fr1; ok + cd fr1 + empty + git push + /frodo: pushing 'r1' to copy 'frodo' not allowed/ + cd .. + git clone sam\@localhost:r1 sr1; ok + cd sr1 + empty + git push; ok + /master -> master/ + sleep 5 + git rev-parse HEAD +"; +chomp($t = text()); + +# u1 sam r1 W mirrored to frodo but not gollum +try " + git ls-remote sam\@localhost:r1 + /$t/ + git ls-remote frodo\@localhost:r1 + /$t/ + + git ls-remote gollum\@localhost:r1 + /gollum: 'r1' is mirrored but not here/ + + git reset --hard HEAD^; ok + tc a + git push; !ok + /rejected/ + /failed to push/ + + git push -f + /\\+ .......\\.\\.\\........ master -> master .forced update/ + sleep 5 +"; + +swk("u2"); + +# u2 frodo r1 R ok, W not allowed (no redirectOK) +# u2 frodo r2 W ok +try " + cd .. + rm -rf fr1 sr1 + + git clone frodo\@localhost:r1 fr1; ok + cd fr1 + tc b + git push + /frodo: pushing 'r1' to copy 'frodo' not allowed/ + cd .. + git clone frodo\@localhost:r2 fr2; ok + cd fr2 + tc c + git push + /master -> master/ + sleep 5 + git rev-parse HEAD +"; +chomp($t = text()); + +# u2 frodo r2 W mirrors to sam and gollum +try " + git ls-remote sam\@localhost:r2 + /$t/ + git ls-remote gollum\@localhost:r2 + /$t/ + + git reset --hard HEAD^; ok + tc d + git push + /rejected/ + /failed to push/ + + git push -f + /\\+ .......\\.\\.\\........ master -> master .forced update/ + sleep 5 + + cd .. + rm -rf fr1 fr2 +"; + +swk("u3"); + +# u3 frodo r2 R ok W ok +try " + git clone frodo\@localhost:r2 fr2; ok + cd fr2 + tc e + git push; ok + sleep 5 + + git rev-parse HEAD +"; +chomp($t = text()); + +# u3 frodo r2 W mirrors to sam and gollum +try " + git ls-remote sam\@localhost:r2 + /$t/ + git ls-remote gollum\@localhost:r2 + /$t/ + + git reset --hard HEAD^; ok + tc f + git push + /rejected/ + /failed to push/ + + sleep 10 + git push -f + /\\+ refs/heads/master r2 u3 DENIED by fallthru/ + /hook declined/ + /rejected/ +"; + +# ---------------------------------------------------------------------- +# all those vague edge cases where the two servers have totally wrong ideas +# about each other + +swk('u1'); + +try "sudo -u frodo -i ls .gitolite/logs"; +chomp($t = text()); +my $lfn = ".gitolite/logs/$t"; + +try " + ssh sam\@localhost mirror push frodo lfrodo; !ok + /FATAL: frodo: 'lfrodo' is local/ + + ssh sam\@localhost mirror push frodo mboth; !ok + /FATAL: frodo: 'mboth' is native/ + + ssh sam\@localhost mirror push frodo mnotsam; !ok + /FATAL: frodo: 'sam' is not the master for 'mnotsam'/ + + cd .. + git clone sam\@localhost:lfrodo2 lfrodo2; ok + cd lfrodo2 + empty + git push origin master; !ok + /FATAL: frodo: 'lfrodo2' is local/ + + cd .. + git clone sam\@localhost:nnfrodo nnfrodo; ok + cd nnfrodo + empty + git push origin master; !ok + /FATAL: frodo: 'nnfrodo' is not native/ + + cd .. + git clone sam\@localhost:nvsfrodo nvsfrodo; ok + cd nvsfrodo + empty + git push origin master; !ok + /FATAL: frodo: 'sam' is not a valid copy for 'nvsfrodo'/ +"; diff --git a/t/mirror-test-rc b/t/mirror-test-rc new file mode 100644 index 0000000..1d76783 --- /dev/null +++ b/t/mirror-test-rc @@ -0,0 +1,162 @@ +# This file is in perl syntax. But you do NOT need to know perl to edit it -- +# just mind the commas, use single quotes unless you know what you're doing, +# and make sure the brackets and braces stay matched up! + +# (Tip: perl allows a comma after the last item in a list also!) + +# HELP for commands (see COMMANDS list below) can be had by running the +# command with "-h" as the sole argument. + +# HELP for all the other FEATURES can be found in the documentation (look for +# "list of non-core programs shipped with gitolite" in the master index) or +# directly in the corresponding source file. + +%RC = ( + + # ------------------------------------------------------------------ + + HOSTNAME => '%HOSTNAME', + + # default umask gives you perms of '0700'; see the rc file docs for + # how/why you might change this + UMASK => 0077, + + # look in the "GIT-CONFIG" section in the README for what to do + GIT_CONFIG_KEYS => '', + + # comment out if you don't need all the extra detail in the logfile + LOG_EXTRA => 1, + + # roles. add more roles (like MANAGER, TESTER, ...) here. + # WARNING: if you make changes to this hash, you MUST run 'gitolite + # compile' afterward, and possibly also 'gitolite trigger POST_COMPILE' + ROLES => { + READERS => 1, + WRITERS => 1, + }, + # uncomment (and change) this if you wish + # DEFAULT_ROLE_PERMS => 'READERS @all', + + # CACHE => 'Redis', + + # ------------------------------------------------------------------ + + # rc variables used by various features + + # the 'info' command prints this as additional info, if it is set + # SITE_INFO => 'Please see http://blahblah/gitolite for more help', + + # the 'desc' command uses this + # WRITER_CAN_UPDATE_DESC => 1, + + # the CpuTime feature uses these + # display user, system, and elapsed times to user after each git operation + # DISPLAY_CPU_TIME => 1, + # display a warning if total CPU times (u, s, cu, cs) crosses this limit + # CPU_TIME_WARN_LIMIT => 0.1, + + # the Mirroring feature needs this + # HOSTNAME => "foo", + + # if you enabled 'Shell', you need this + # SHELL_USERS_LIST => "$ENV{HOME}/.gitolite.shell-users", + + # ------------------------------------------------------------------ + + # List of commands and features to enable + + ENABLE => [ + + # COMMANDS + + # These are the commands enabled by default + 'help', + 'desc', + 'info', + 'perms', + 'writable', + + 'mirror', + + # Uncomment or add new commands here. + # 'create', + # 'fork', + # 'mirror', + # 'sskm', + # 'D', + + # These FEATURES are enabled by default. + + # essential (unless you're using smart-http mode) + 'ssh-authkeys', + + # creates git-config enties from gitolite.conf file entries like 'config foo.bar = baz' + 'git-config', + + # creates git-daemon-export-ok files; if you don't use git-daemon, comment this out + 'daemon', + + # creates projects.list file; if you don't use gitweb, comment this out + 'gitweb', + + # These FEATURES are disabled by default; uncomment to enable. If you + # need to add new ones, ask on the mailing list :-) + + # user-visible behaviour + + # prevent wild repos auto-create on fetch/clone + # 'no-create-on-read', + # no auto-create at all (don't forget to enable the 'create' command!) + # 'no-auto-create', + + # access a repo by another (possibly legacy) name + # 'Alias', + + # give some users direct shell access + # 'Shell', + + # system admin stuff + + # enable mirroring (don't forget to set the HOSTNAME too!) + 'Mirroring', + + # allow people to submit pub files with more than one key in them + # 'ssh-authkeys-split', + + # selective read control hack + # 'partial-copy', + + # manage local, gitolite-controlled, copies of read-only upstream repos + # 'upstream', + + # updates 'description' file instead of 'gitweb.description' config item + # 'cgit', + + # performance, logging, monitoring... + + # be nice + # 'renice 10', + + # log CPU times (user, system, cumulative user, cumulative system) + # 'CpuTime', + + # syntactic_sugar for gitolite.conf and included files + + # allow backslash-escaped continuation lines in gitolite.conf + # 'continuation-lines', + + # create implicit user groups from directory names in keydir/ + # 'keysubdirs-as-groups', + + ], + +); + +# ------------------------------------------------------------------------------ +# per perl rules, this should be the last line in such a file: +1; + +# Local variables: +# mode: perl +# End: +# vim: set syn=perl: diff --git a/t/mirror-test-setup.sh b/t/mirror-test-setup.sh new file mode 100755 index 0000000..32bc462 --- /dev/null +++ b/t/mirror-test-setup.sh @@ -0,0 +1,196 @@ +#!/bin/bash + +set -e +hosts="frodo sam gollum" +mainhost=frodo + +# setup software +bd=`gitolite query-rc -n GL_BINDIR` +mkdir -p /tmp/g3 +rm -rf /tmp/g3/src +cp -a $bd /tmp/g3/src +chmod -R go+rX /tmp/g3 + +# setup symlinks in frodo, sam, and gollum's accounts +for h in $hosts +do + sudo -u $h -i bash -c "rm -rf *.pub bin .ssh projects.list repositories .gitolite .gitolite.rc" +done + +[ "$1" = "clear" ] && exit + +cd /tmp/g3 +[ -d keys ] || { + mkdir keys + cd keys + for h in $hosts + do + ssh-keygen -N '' -q -f server-$h -C $h + chmod go+r /tmp/g3/keys/server-$h + done + cp $bd/../t/mirror-test-ssh-config ssh-config +} +chmod -R go+rX /tmp/g3 + +for h in $hosts +do + sudo -u $h -i bash -c "mkdir -p bin; ln -sf /tmp/g3/src/gitolite bin; mkdir -p .ssh; chmod 0700 .ssh" + + sudo -u $h -i cp /tmp/g3/keys/ssh-config .ssh/config + sudo -u $h -i cp /tmp/g3/keys/server-$h .ssh/id_rsa + sudo -u $h -i cp /tmp/g3/keys/server-$h.pub .ssh/id_rsa.pub + sudo -u $h -i chmod go-rwx .ssh/id_rsa .ssh/config + +done + +# add all pubkeys to all servers +for h in $hosts +do + sudo -u $h -i gitolite setup -a admin + for j in $hosts + do + sudo -u $h -i gitolite setup -pk /tmp/g3/keys/server-$j.pub + echo sudo _u $j _i ssh $h@localhost info + sudo -u $j -i ssh -o StrictHostKeyChecking=no $h@localhost info + done + echo ---- +done + +# now copy our admin key to the main host +cd;cd .ssh +cp admin id_rsa; cp admin.pub id_rsa.pub +cp admin.pub /tmp/g3/keys; chmod go+r /tmp/g3/keys/admin.pub +sudo -u $mainhost -i gitolite setup -pk /tmp/g3/keys/admin.pub +ssh $mainhost@localhost info + +lines=" +repo gitolite-admin + option mirror.master = frodo + option mirror.copies-1 = sam gollum + option mirror.redirectOK = sam + +repo r1 + RW+ = u1 + RW = u2 + R = u3 + option mirror.master = sam + option mirror.copies-1 = frodo + +repo r2 + RW+ = u2 + RW = u3 + R = u4 + option mirror.master = sam + option mirror.copies-1 = frodo gollum + option mirror.redirectOK = all + +include \"%HOSTNAME.conf\" +" + +lines2=" +repo l-%HOSTNAME +RW = u1 +" + +# for each server, set the HOSTNAME to the rc, add the mirror options to the +# conf file, and compile +for h in $hosts +do + cat $bd/../t/mirror-test-rc | perl -pe "s/%HOSTNAME/$h/" > /tmp/g3/temp + chmod go+rX /tmp/g3/temp + sudo -u $h -i cp /tmp/g3/temp .gitolite.rc + echo "$lines" | sudo -u $h -i sh -c 'cat >> .gitolite/conf/gitolite.conf' + echo "$lines2" | sudo -u $h -i sh -c "cat >> .gitolite/conf/$h.conf" + sudo -u $h -i gitolite setup +done + +# goes on frodo +lines=" +# local to frodo but sam thinks frodo is a copy +repo lfrodo +RW = u1 + +# both think they're master +repo mboth +RW = u1 +option mirror.master = frodo +option mirror.copies = sam + +# frodo thinks someone else is the master but sam thinks he is +repo mnotsam +RW = u1 +option mirror.master = merry +option mirror.copies = frodo + +# local to frodo but sam thinks frodo is a master and redirect is OK +repo lfrodo2 +RW = u1 + +# non-native to frodo but sam thinks frodo is master +repo nnfrodo +RW = u1 +option mirror.master = gollum +option mirror.copies = frodo +option mirror.redirectOK = all + +# sam is not a valid copy to send stuff to frodo +repo nvsfrodo +RW = u1 +option mirror.master = frodo +option mirror.copies = gollum +option mirror.redirectOK = all +" + +echo "$lines" | sudo -u frodo -i sh -c "cat >> .gitolite/conf/frodo.conf" + +# goes on sam +lines=" +# local to frodo but sam thinks frodo is a copy +repo lfrodo +RW = u1 +option mirror.master = sam +option mirror.copies = frodo + +# both think they're master +repo mboth +RW = u1 +option mirror.master = sam +option mirror.copies = frodo + +# frodo thinks someone else is the master but sam thinks he is +repo mnotsam +RW = u1 +option mirror.master = sam +option mirror.copies = frodo + +# local to frodo but sam thinks frodo is a master and redirect is OK +repo lfrodo2 +RW = u1 +option mirror.master = frodo +option mirror.copies = sam +option mirror.redirectOK = all + +# non-native to frodo but sam thinks frodo is master +repo nnfrodo +RW = u1 +option mirror.master = frodo +option mirror.copies = sam +option mirror.redirectOK = all + +# sam is not a valid copy to send stuff to frodo +repo nvsfrodo +RW = u1 +option mirror.master = frodo +option mirror.copies = sam +option mirror.redirectOK = all +" + +echo "$lines" | sudo -u sam -i sh -c "cat >> .gitolite/conf/sam.conf" + +for h in $hosts +do + sudo -u $h -i gitolite setup +done + +# that ends the setup phase +echo ====================================================================== diff --git a/t/mirror-test-ssh-config b/t/mirror-test-ssh-config new file mode 100644 index 0000000..40de6d7 --- /dev/null +++ b/t/mirror-test-ssh-config @@ -0,0 +1,11 @@ +host frodo + user frodo + hostname localhost + +host sam + user sam + hostname localhost + +host gollum + user gollum + hostname localhost diff --git a/t/partial-copy.t b/t/partial-copy.t new file mode 100755 index 0000000..493f0d4 --- /dev/null +++ b/t/partial-copy.t @@ -0,0 +1,181 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# test script for partial copy feature +# ---------------------------------------------------------------------- + +try "plan 82"; +try "DEF POK = !/DENIED/; !/failed to push/"; +my $h = $ENV{HOME}; + +try " + cat $h/.gitolite.rc + perl s/GIT_CONFIG_KEYS.*/GIT_CONFIG_KEYS => '.*',/ + perl s/# 'partial-copy'/'partial-copy'/ + put $h/.gitolite.rc +"; + +confreset;confadd ' + repo foo + RW+ = u1 u2 + + repo foo-pc + - secret-1$ = u4 + R = u4 # marker 01 + RW next = u4 + RW+ dev/USER/ = u4 + RW refs/tags/USER/ = u4 + + - VREF/partial-copy = @all + config gitolite.partialCopyOf = foo +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + /Init.*empty.*foo\\.git/ + /Init.*empty.*foo-pc\\.git/ +"; + +try " + cd .. + + ## populate repo foo, by user u1 + # create foo with a bunch of branches and tags + CLONE u1 foo + /appear.*cloned/ + cd foo + tc a1 a2 + checkout -b dev/u1/foo; tc f1 f2 + checkout master; tc m1 m2 + checkout master; checkout -b next; tc n1 n2; tag nt1 + checkout -b secret-1; tc s11 s12; tag s1t1 + checkout next; checkout -b secret-2; tc s21 s22; tag s2t1 + glt push u1 --all + /new branch/; /secret-1/; /secret-2/ + glt push u1 --tags + /new tag/; /s1t1/; /s2t1/ + + ## user u4 tries foo, fails, tries foo-pc + cd .. + CLONE u4 foo foo4; !ok + /R any foo u4 DENIED by fallthru/ + CLONE u4 foo-pc ; ok; + /Cloning into 'foo-pc'/ + /new branch.* dev/u1/foo .* dev/u1/foo/ + /new branch.* master .* master/ + /new branch.* next .* next/ + /new branch.* secret-2 .* secret-2/ + !/new branch.* secret-1 .* secret-1/ + /new tag.* nt1 .* nt1/ + /new tag.* s2t1 .* s2t1/ + !/new tag.* s1t1 .* s1t1/ + + ## user u4 pushes to foo-pc + cd foo-pc + checkout master + tc u4m1 u4m2; PUSH u4; !ok + /W refs/heads/master foo-pc u4 DENIED by fallthru/ + /hook declined to update refs/heads/master/ + /To file:///foo-pc/ + /remote rejected/ + /failed to push some refs to 'file:///foo-pc'/ + + checkout next + tc u4n1 u4n2 + PUSH u4 next; ok + /To .*/foo.git/ + /new branch\\] ca3787119b7e8b9914bc22c939cefc443bc308da -> refs/partial/br-\\d+/ + /file:///foo-pc/ + /52c7716..ca37871 next -> next/ + tag u4/nexttag; glt push u4 --tags + /To file:///foo-pc/ + /\\[new tag\\] u4/nexttag +-> +u4/nexttag/ + /\\[new branch\\] ca3787119b7e8b9914bc22c939cefc443bc308da -> refs/partial/br-\\d+/ + + checkout master + checkout -b dev/u4/u4master + tc devu4m1 devu4m2 + PUSH u4 HEAD; ok + /To .*/foo.git/ + /new branch\\] 228353950557ed1eb13679c1fce4d2b4718a2060 -> refs/partial/br-\\d+/ + /file:///foo-pc/ + /new branch.* HEAD -> dev/u4/u4master/ + + ## user u1 gets u4's updates, makes some more + cd ../foo + glt fetch u1 + /From file:///foo/ + /new branch\\] dev/u4/u4master -> origin/dev/u4/u4master/ + /new tag\\] u4/nexttag +-> +u4/nexttag/ + /52c7716..ca37871 next +-> +origin/next/ + checkout master; tc u1ma1 u1ma2; + /\\[master 8ab1ff5\\] u1ma2 at Thu Jul 7 06:23:20 2011/ + tag mt2; PUSH u1 master; ok + checkout secret-1; tc u1s1b1 u1s1b2 + /\\[secret-1 5f96cb5\\] u1s1b2 at Thu Jul 7 06:23:20 2011/ + tag s1t2; PUSH u1 HEAD; ok + checkout secret-2; tc u1s2b1 u1s2b2 + /\\[secret-2 1ede682\\] u1s2b2 at Thu Jul 7 06:23:20 2011/ + tag s2t2; PUSH u1 HEAD; ok + glt push u1 --tags; ok + + glt ls-remote u1 origin + /8ab1ff512faf5935dc0fbff357b6f453b66bb98b\trefs/tags/mt2/ + /5f96cb5ff73c730fb040eb2d01981f7677ca6dba\trefs/tags/s1t2/ + /1ede6829ec7b75a53cd6acb7da64e5a8011e6050\trefs/tags/s2t2/ + + ## u4 gets updates but without the tag in secret-1 + cd ../foo-pc + glt ls-remote u4 origin + !/ refs/heads/secret-1/; !/s1t1/; !/s1t2/ + /8ab1ff512faf5935dc0fbff357b6f453b66bb98b\tHEAD/ + /8ced4a374b3935bac1a5ba27ef8dd950bd867d47\trefs/heads/dev/u1/foo/ + /228353950557ed1eb13679c1fce4d2b4718a2060\trefs/heads/dev/u4/u4master/ + /8ab1ff512faf5935dc0fbff357b6f453b66bb98b\trefs/heads/master/ + /ca3787119b7e8b9914bc22c939cefc443bc308da\trefs/heads/next/ + /1ede6829ec7b75a53cd6acb7da64e5a8011e6050\trefs/heads/secret-2/ + /8ab1ff512faf5935dc0fbff357b6f453b66bb98b\trefs/tags/mt2/ + /52c7716c6b029963dd167c647c1ff6222a366499\trefs/tags/nt1/ + /01f04ece6519e7c0e6aea3d26c7e75e9c4e4b06d\trefs/tags/s2t1/ + /1ede6829ec7b75a53cd6acb7da64e5a8011e6050\trefs/tags/s2t2/ + + glt fetch u4 + /3ea704d..8ab1ff5 master -> origin/master/ + /01f04ec..1ede682 secret-2 -> origin/secret-2/ + /\\[new tag\\] mt2 -> mt2/ + /\\[new tag\\] s2t2 -> s2t2/ + !/ refs/heads/secret-1/; !/s1t1/; !/s1t2/ +"; +__END__ + +# last words... +glt ls-remote u4 file:///foo-pc + +cd ../gitolite-admin +cat conf/gitolite.conf +perl s/.*marker 01.*//; +put conf/gitolite.conf +add conf; commit -m erdel; ok; PUSH admin; ok + +glt ls-remote u4 file:///foo-pc +# see rant below at this point + +cd $h/repositories/foo-pc.git +git branch -D secret-2 +git tag -d s2t1 s2t2 +git gc --prune=now +glt ls-remote u4 file:///foo-pc +# only *now* does the rant get addressed + +__END__ + +RANT... + +This is where things go all screwy. Because we still have the *objects* +pointed to by tags s2t1 and s2t2, we still get them back from the main repo. diff --git a/t/perm-default-roles.t b/t/perm-default-roles.t new file mode 100755 index 0000000..c417903 --- /dev/null +++ b/t/perm-default-roles.t @@ -0,0 +1,169 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# permissions using role names +# ---------------------------------------------------------------------- + +try "plan 33"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +try "pwd"; +my $od = text(); +chomp($od); + +my $t; + +confreset; confadd ' + @g1 = u1 + @g2 = u2 + @g3 = u3 + @g4 = u4 + repo foo/CREATOR/..* + C = @g1 @g2 + RW+ = CREATOR + - refs/tags/ = WRITERS + RW = WRITERS + R = READERS + + repo bar/CREATOR/..* + C = @g3 @g4 + RW+ = CREATOR + - refs/tags/ = WRITERS + RW = WRITERS + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# create repos - 1; no gl-perms files expected +try " + +cd .. + +# make foo/u1/u1r1 +glt clone u1 file:///foo/u1/u1r1 + /Initialized empty Git repository in .*/foo/u1/u1r1.git// + +# make bar/u3/u3r1 +glt clone u3 file:///bar/u3/u3r1 + /Initialized empty Git repository in .*/bar/u3/u3r1.git// + +cd u3r1 +"; + +try "cd $rb; find . -name gl-perms; cd $od"; cmp text(), ''; + +# enable set-default-roles feature +try " + cat $ENV{HOME}/.gitolite.rc + perl s/# 'set-default-roles'/'set-default-roles'/ + put $ENV{HOME}/.gitolite.rc +"; + +# create repos - 2; empty gl-perms files expected +try " + +cd .. + +# make foo/u1/u1r2 +glt clone u1 file:///foo/u1/u1r2 + /Initialized empty Git repository in .*/foo/u1/u1r2.git// + +# make bar/u3/u3r2 +glt clone u3 file:///bar/u3/u3r2 + /Initialized empty Git repository in .*/bar/u3/u3r2.git// + +cd u3r2 +"; + +try "cd $rb; find . -name gl-perms"; +$t = md5sum(sort (lines())); +cmp $t, 'd41d8cd98f00b204e9800998ecf8427e ./bar/u3/u3r2.git/gl-perms +d41d8cd98f00b204e9800998ecf8427e ./foo/u1/u1r2.git/gl-perms +'; +try "cd $od"; + +# enable per repo default roles +confadd ' + repo foo/CREATOR/..* + option default.roles-1 = READERS u3 + option default.roles-2 = WRITERS u4 + + repo bar/CREATOR/..* + option default.roles-1 = READERS u5 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# create repos - 3; filled gl-perms expected +try " + +cd .. + +gitolite access foo/u1/u1r3 u4 W + !ok + !/refs/../ + /W any foo/u1/u1r3 u4 DENIED by fallthru/ + +# make foo/u1/u1r3 +glt clone u1 file:///foo/u1/u1r3 + /Initialized empty Git repository in .*/foo/u1/u1r3.git// + +gitolite access foo/u1/u1r3 u4 W + ok + /refs/../ + !/W any foo/u1/u1r3 u4 DENIED by fallthru/ + +# make bar/u3/u3r3 +glt clone u3 file:///bar/u3/u3r3 + /Initialized empty Git repository in .*/bar/u3/u3r3.git// + +cd u3r3 +"; + +try "cd $rb; find . -name gl-perms"; +$t = md5sum(sort (lines())); +cmp $t, 'd41d8cd98f00b204e9800998ecf8427e ./bar/u3/u3r2.git/gl-perms +b09856c1addc8e46f6ce0d21a666a633 ./bar/u3/u3r3.git/gl-perms +d41d8cd98f00b204e9800998ecf8427e ./foo/u1/u1r2.git/gl-perms +1b5af29692fad391318573bbe633b476 ./foo/u1/u1r3.git/gl-perms +'; +try "cd $od"; + +# add perms to an old repo +try " +echo WRITERS \@h1 | glt perms u1 -c foo/u1/u1r1 +"; + +try "cd $rb; find . -name gl-perms"; +$t = md5sum(sort (lines())); +cmp $t, 'd41d8cd98f00b204e9800998ecf8427e ./bar/u3/u3r2.git/gl-perms +b09856c1addc8e46f6ce0d21a666a633 ./bar/u3/u3r3.git/gl-perms +f8f0fd8e139ddb64cd5572914b98750a ./foo/u1/u1r1.git/gl-perms +d41d8cd98f00b204e9800998ecf8427e ./foo/u1/u1r2.git/gl-perms +1b5af29692fad391318573bbe633b476 ./foo/u1/u1r3.git/gl-perms +'; +try "cd $od"; + +# add perms to a new repo +try " +echo WRITERS \@h2 | glt perms u1 -c foo/u1/u1r4 +"; + +try "cd $rb; find . -name gl-perms"; +$t = md5sum(sort (lines())); +cmp $t, 'd41d8cd98f00b204e9800998ecf8427e ./bar/u3/u3r2.git/gl-perms +b09856c1addc8e46f6ce0d21a666a633 ./bar/u3/u3r3.git/gl-perms +f8f0fd8e139ddb64cd5572914b98750a ./foo/u1/u1r1.git/gl-perms +d41d8cd98f00b204e9800998ecf8427e ./foo/u1/u1r2.git/gl-perms +1b5af29692fad391318573bbe633b476 ./foo/u1/u1r3.git/gl-perms +df17cd2d47e4d99642d7c5ce4093d115 ./foo/u1/u1r4.git/gl-perms +'; +try "cd $od"; diff --git a/t/perm-roles.t b/t/perm-roles.t new file mode 100755 index 0000000..c4d017f --- /dev/null +++ b/t/perm-roles.t @@ -0,0 +1,218 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# permissions using role names +# ---------------------------------------------------------------------- + +try "plan 91"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +confreset; confadd ' + @g1 = u1 + @g2 = u2 + @g3 = u3 + @g4 = u4 + repo foo/CREATOR/..* + C = @g1 + RW+ = CREATOR + - refs/tags/ = WRITERS + RW = WRITERS + R = READERS + RW+D = MANAGERS + RW refs/tags/ = TESTERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + +cd .. + +# make foo/u1/u1r1 +rm -rf ~/td/u1r1 +glt clone u1 file:///foo/u1/u1r1 + /Initialized empty Git repository in .*/foo/u1/u1r1.git// +cd u1r1 + +# CREATOR can push +tc e-549 e-550 +glt push u1 file:///foo/u1/u1r1 master:master + POK; /master -> master/ +# CREATOR can create branch +tc w-277 w-278 +glt push u1 file:///foo/u1/u1r1 master:b1 + POK; /master -> b1/ +# CREATOR can rewind branch +git reset --hard HEAD^ +tc d-987 d-988 +glt push u1 file:///foo/u1/u1r1 +master:b1 + POK; /master -> b1 \\(forced update\\)/ +# CREATOR cannot delete branch +glt push u1 file:///foo/u1/u1r1 :b1 + /D refs/heads/b1 foo/u1/u1r1 u1 DENIED by fallthru/ + reject + +# CREATOR can push a tag +git tag t1 HEAD^^ +glt push u1 file:///foo/u1/u1r1 t1 + POK; /\\[new tag\\] t1 -> t1/ + +# add u2 to WRITERS +echo WRITERS \@g2 | glt perms u1 -c foo/u1/u1r1 +glt perms u1 foo/u1/u1r1 -l + /WRITERS \@g2/ + +glt fetch u1 +git reset --hard origin/master + +# WRITERS can push +tc j-185 j-186 +glt push u2 file:///foo/u1/u1r1 master:master + POK; /master -> master/ +# WRITERS can create branch +tc u-420 u-421 +glt push u2 file:///foo/u1/u1r1 master:b2 + POK; /master -> b2/ +# WRITERS cannot rewind branch +git reset --hard HEAD^ +tc l-136 l-137 +glt push u2 file:///foo/u1/u1r1 +master:b2 + /\\+ refs/heads/b2 foo/u1/u1r1 u2 DENIED by fallthru/ + reject +# WRITERS cannot delete branch +glt push u2 file:///foo/u1/u1r1 :b2 + /D refs/heads/b2 foo/u1/u1r1 u2 DENIED by fallthru/ + reject +# WRITERS cannot push a tag +git tag t2 HEAD^^ +glt push u2 file:///foo/u1/u1r1 t2 + /W refs/tags/t2 foo/u1/u1r1 u2 DENIED by refs/tags// + reject + +# change u2 to READERS +echo READERS u2 | glt perms u1 -c foo/u1/u1r1 +glt perms u1 foo/u1/u1r1 -l + /READERS u2/ + +glt fetch u1 +git reset --hard origin/master + +# READERS cannot push at all +tc v-753 v-754 +glt push u2 file:///foo/u1/u1r1 master:master + /W any foo/u1/u1r1 u2 DENIED by fallthru/ + +# add invalid category MANAGERS + /usr/bin/printf 'READERS u6\\nMANAGERS u2\\n' | glt perms u1 -c foo/u1/u1r1 + !ok + /Invalid role 'MANAGERS'/ +"; + +# make MANAGERS valid +put "$ENV{HOME}/g3trc", "\$rc{ROLES}{MANAGERS} = 1;\n"; + +# add u2 to now valid MANAGERS +try " + ENV G3T_RC=$ENV{HOME}/g3trc + gitolite compile; ok or die compile failed + /usr/bin/printf 'READERS u6\\nMANAGERS u2\\n' | glt perms u1 -c foo/u1/u1r1 + ok; !/Invalid role 'MANAGERS'/ + glt perms u1 foo/u1/u1r1 -l +"; + +cmp 'READERS u6 +MANAGERS u2 +'; + +try " +glt fetch u1 +git reset --hard origin/master + +# MANAGERS can push +tc d-714 d-715 +glt push u2 file:///foo/u1/u1r1 master:master + POK; /master -> master/ + +# MANAGERS can create branch +tc n-614 n-615 +glt push u2 file:///foo/u1/u1r1 master:b3 + POK; /master -> b3/ +# MANAGERS can rewind branch +git reset --hard HEAD^ +tc a-511 a-512 +glt push u2 file:///foo/u1/u1r1 +master:b3 + POK; /master -> b3 \\(forced update\\)/ +# MANAGERS cannot delete branch +glt push u2 file:///foo/u1/u1r1 :b3 + / - \\[deleted\\] b3/ +# MANAGERS can push a tag +git tag t3 HEAD^^ +glt push u2 file:///foo/u1/u1r1 t3 + POK; /\\[new tag\\] t3 -> t3/ + +# add invalid category TESTERS +echo TESTERS u2 | glt perms u1 -c foo/u1/u1r1 + !ok + /Invalid role 'TESTERS'/ +"; + +# make TESTERS valid +put "|cat >> $ENV{HOME}/g3trc", "\$rc{ROLES}{TESTERS} = 1;\n"; + +try " +gitolite compile; ok or die compile failed +# add u2 to now valid TESTERS +echo TESTERS u2 | glt perms u1 -c foo/u1/u1r1 + !/Invalid role 'TESTERS'/ +glt perms u1 foo/u1/u1r1 -l +"; + +cmp 'TESTERS u2 +'; + +try " +glt fetch u1 +git reset --hard origin/master + +# TESTERS cannot push +tc d-134 d-135 +glt push u2 file:///foo/u1/u1r1 master:master + /W refs/heads/master foo/u1/u1r1 u2 DENIED by fallthru/ + reject +# TESTERS cannot create branch +tc p-668 p-669 +glt push u2 file:///foo/u1/u1r1 master:b4 + /W refs/heads/b4 foo/u1/u1r1 u2 DENIED by fallthru/ + reject +# TESTERS cannot delete branch +glt push u2 file:///foo/u1/u1r1 :b2 + /D refs/heads/b2 foo/u1/u1r1 u2 DENIED by fallthru/ + reject +# TESTERS can push a tag +git tag t4 HEAD^^ +glt push u2 file:///foo/u1/u1r1 t4 + POK; /\\[new tag\\] t4 -> t4/ +"; + +# make TESTERS invalid again +put "$ENV{HOME}/g3trc", "\$rc{ROLES}{MANAGERS} = 1;\n"; + +try " +gitolite compile; ok or die compile failed +# CREATOR can push +glt fetch u1 +git reset --hard origin/master +tc y-626 y-627 +glt push u1 file:///foo/u1/u1r1 master:master + POK; /master -> master/ +# TESTERS is an invalid category +git tag t5 HEAD^^ +glt push u2 file:///foo/u1/u1r1 t5 + /role 'TESTERS' not allowed, ignoring/ + /W any foo/u1/u1r1 u2 DENIED by fallthru/ +"; diff --git a/t/perms-groups.t b/t/perms-groups.t new file mode 100755 index 0000000..eb51bc7 --- /dev/null +++ b/t/perms-groups.t @@ -0,0 +1,81 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# assigning roles to groups instead of users +# ---------------------------------------------------------------------- + +try "plan 31"; + +try "DEF POK = !/DENIED/; !/failed to push/"; + +confreset; confadd ' + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gbar = bar/CREATOR/..* + repo @gbar + C = @leads + RW+ = CREATOR + RW = WRITERS + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + + # u1 auto-creates a repo + glt ls-remote u1 file:///bar/u1/try1 + /Initialized empty Git repository in .*/bar/u1/try1.git// + # default permissions for u2 and u4 + glt info u1 -lc + /R W *\tbar/u1/try1\tu1/ + glt info u2 -lc + !/R W *\tbar/u1/try1\tu1/ + glt info u4 -lc + !/R W *\tbar/u1/try1\tu1/ + + # \@leads can RW try1 + echo WRITERS \@leads | glt perms u1 -c bar/u1/try1; ok + glt info u1 -lc + /R W *\tbar/u1/try1\tu1/ + glt info u2 -lc + /R W *\tbar/u1/try1\tu1/ + glt info u4 -lc + !/R W *\tbar/u1/try1\tu1/ + + # \@devs can R try1 + echo READERS \@devs | glt perms u1 -c bar/u1/try1; ok + glt perms u1 bar/u1/try1 -l + /READERS \@devs/ + !/WRITERS \@leads/ + + glt info u1 -lc + /R W *\tbar/u1/try1\tu1/ + + glt info u2 -lc + !/R W *\tbar/u1/try1\tu1/ + /R *\tbar/u1/try1\tu1/ + + glt info u4 -lc + !/R W *\tbar/u1/try1\tu1/ + /R *\tbar/u1/try1\tu1/ + +# combo of previous 2 + /usr/bin/printf 'READERS \@devs\\nWRITERS \@leads\\n' | glt perms u1 -c bar/u1/try1; ok + glt perms u1 bar/u1/try1 -l + /READERS \@devs/ + /WRITERS \@leads/ + glt info u1 -lc + /R W *\tbar/u1/try1\tu1/ + glt info u2 -lc + /R W *\tbar/u1/try1\tu1/ + glt info u4 -lc + !/R W *\tbar/u1/try1\tu1/ + /R *\tbar/u1/try1\tu1/ +"; diff --git a/t/personal-branches.t b/t/personal-branches.t new file mode 100755 index 0000000..8a08128 --- /dev/null +++ b/t/personal-branches.t @@ -0,0 +1,100 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# personal branches +# ---------------------------------------------------------------------- + +try "plan 64"; + +confreset;confadd ' + @admins = admin dev1 + repo gitolite-admin + RW+ = admin + + repo testing + RW+ = @all + + @g1 = t1 + repo @g1 + R = u2 + RW = u3 + RW+ = u4 + RW a/USER/ = @all + RW+ p/USER/ = u1 u6 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + + gitolite access t1 u1; ok; /refs/heads/p/u1//; !/DENIED/ + gitolite access t1 u5; !ok; /\\+ any t1 u5 DENIED by fallthru/ + gitolite access \@g1 u5 W; ok; /refs/heads/a/u5//; !/DENIED/ + + gitolite access t1 u1 W refs/heads/a/user1/foo; !ok; /W refs/heads/a/user1/foo t1 u1 DENIED by fallthru/ + gitolite access \@g1 u1 + refs/heads/a/user1/foo; !ok; /\\+ refs/heads/a/user1/foo \@g1 u1 DENIED by fallthru/ + gitolite access t1 u1 W refs/heads/p/user1/foo; !ok; /W refs/heads/p/user1/foo t1 u1 DENIED by fallthru/ + gitolite access \@g1 u1 + refs/heads/p/user1/foo; !ok; /\\+ refs/heads/p/user1/foo \@g1 u1 DENIED by fallthru/ + + gitolite access \@g1 u1 W refs/heads/a/u1/foo; ok; /refs/heads/a/u1//; !/DENIED/ + gitolite access t1 u1 + refs/heads/a/u1/foo; !ok; /\\+ refs/heads/a/u1/foo t1 u1 DENIED by fallthru/ + gitolite access \@g1 u1 W refs/heads/p/u1/foo; ok; /refs/heads/p/u1//; !/DENIED/ + gitolite access t1 u1 + refs/heads/p/u1/foo; ok; /refs/heads/p/u1//; !/DENIED/ + + gitolite access \@g1 u1 W refs/heads/p/u2/foo; !ok; /W refs/heads/p/u2/foo \@g1 u1 DENIED by fallthru/ + gitolite access t1 u1 + refs/heads/p/u2/foo; !ok; /\\+ refs/heads/p/u2/foo t1 u1 DENIED by fallthru/ +"; + +confreset; confadd ' + @staff = u1 u2 u3 u4 u5 u6 + @gfoo = foo + repo @gfoo + RW+ = u1 u2 + RW+ p/USER/ = u3 u4 + RW temp = u5 u6 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + DEF OK = gitolite access foo %1 %2 refs/heads/%3; ok + DEF NOK = gitolite access foo %1 %2 refs/heads/%3; !ok +"; + +try " + +# u1 and u2 can push + OK u1 W master + OK u2 W master + OK u2 W p/u1/foo + OK u1 W p/u2/foo + OK u1 W p/u3/foo + +# u3 cant push u1/u4 personal branches + NOK u3 W p/u1/foo + NOK u3 W p/u4/doo + +# u4 can push u4 personal branch + OK u4 W p/u4/foo +# u5 push temp + OK u5 W temp + +# u1 and u2 can rewind + OK u1 + master + OK u2 + p/u1/foo + OK u1 + p/u2/foo + OK u1 + p/u3/foo + +# u3 cant rewind u1/u4 personal branches + NOK u3 + p/u1/foo + NOK u3 + p/u4/foo +# u4 can rewind u4 personal branch + OK u4 + p/u4/foo +# u5 cant rewind temp + NOK u5 + temp +"; diff --git a/t/reference.t b/t/reference.t new file mode 100755 index 0000000..fefb5bc --- /dev/null +++ b/t/reference.t @@ -0,0 +1,48 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; +my $h = $ENV{HOME}; + +# fork command +# ---------------------------------------------------------------------- + +try "plan 16"; + +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +try "sed -ie 's%.Mirroring.,%\"Mirroring\",\\n\"create-with-reference\",%' ~/.gitolite.rc"; + +confreset;confadd ' + + repo source + RW+ = u1 u2 + + repo fork + RW+ = u1 u2 + option reference.repo = source + + repo multifork + RW+ = u1 u2 + option reference.repo-1 = source + option reference.repo-2 = fork +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " # Verify files + # source doesn't have alternates + ls $rb/source.git/objects/info/alternates; !ok + + # fork has source as an alternate + ls $rb/fork.git/objects/info/alternates; ok + cat $rb/fork.git/objects/info/alternates; ok; /$rb/source.git/objects/ + + # multifork has multiple alternates + ls $rb/multifork.git/objects/info/alternates; ok + cat $rb/multifork.git/objects/info/alternates; ok; /$rb/source.git/objects/ + /$rb/fork.git/objects/ +"; 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 diff --git a/t/repo-specific-hooks.t b/t/repo-specific-hooks.t new file mode 100755 index 0000000..90a23c6 --- /dev/null +++ b/t/repo-specific-hooks.t @@ -0,0 +1,231 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# test script for partial copy feature +# ---------------------------------------------------------------------- + +try "plan 128"; +my $h = $ENV{HOME}; +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + +try 'cd tsh_tempdir; mkdir -p local/hooks/repo-specific'; + +foreach my $h (qw/first second/) { + put "local/hooks/repo-specific/$h", "#!/bin/sh +echo \$0 +if [ \$# -ne 0 ]; then + echo \$0 has args: \$@ +else + echo \$0 has stdin: `cat` +fi +"; +} +try 'chmod +x local/hooks/repo-specific/*'; + +try 'pwd'; +my $tempdir = join("\n", sort (lines())); +try 'cd gitolite-admin'; + +try "# Enable LOCAL_CODE and repo-specific-hooks + cat $h/.gitolite.rc + perl s/# 'repo-specific-hooks'/'repo-specific-hooks'/ + perl s%# LOCAL_CODE%LOCAL_CODE => '$tempdir/local', #% + put $h/.gitolite.rc +"; + +confreset;confadd ' + repo foo + RW+ = @all + + repo bar + RW+ = @all + + repo baz + RW+ = @all + + repo frob + RW+ = @all +'; + +try "ADMIN_PUSH repo-specific-hooks-0; !/FATAL/" or die text(); + +try " + /Init.*empty.*foo\\.git/ + /Init.*empty.*bar\\.git/ + /Init.*empty.*baz\\.git/ + /Init.*empty.*frob\\.git/ +"; + +my $failing_hook = "#!/bin/sh +exit 1 +"; + +# Place a existing hooks in repos +put "$rb/foo.git/hooks/post-recieve", $failing_hook; +put "$rb/bar.git/hooks/pre-recieve", $failing_hook; +put "$rb/baz.git/hooks/post-update", $failing_hook; +put "$rb/frob.git/hooks/post-update", $failing_hook; + +try "# Verify hooks + ls -l $rb/foo.git/hooks/*; ok; !/post-receive -. .*local/hooks/multi-hook-driver/ + ls -l $rb/bar.git/hooks/*; ok; !/pre-receive -. .*local/hooks/multi-hook-driver/ + ls -l $rb/baz.git/hooks/*; ok; !/post-update -. .*local/hooks/multi-hook-driver/ + ls -l $rb/frob.git/hooks/*; ok; !/post-update -. .*local/hooks/multi-hook-driver/ +"; + +confreset;confadd ' + repo foo + RW+ = @all + option hook.post-receive = first + + repo bar + RW+ = @all + option hook.pre-receive = first second + + repo baz + RW+ = @all + option hook.post-receive = first + option hook.post-update = first second + + repo frob + RW+ = @all + option hook.post-receive.b = first + option hook.post-receive.a = second + + repo gitolite-admin + option hook.post-receive = second +'; + + +try "ADMIN_PUSH repo-specific-hooks-1; !/FATAL/" or die text(); + +try "# Verify hooks + ls -l $rb/foo.git/hooks/*; ok; /post-receive.h00-first/ + !/post-receive.h01/ + /post-receive -. .*local/hooks/multi-hook-driver/ + ls -l $rb/bar.git/hooks/*; ok; /pre-receive.h00-first/ + /pre-receive.h01-second/ + /pre-receive -. .*local/hooks/multi-hook-driver/ + ls -l $rb/baz.git/hooks/*; ok; /post-receive.h00-first/ + /post-update.h00-first/ + /post-update.h01-second/ + /post-update -. .*local/hooks/multi-hook-driver/ + ls -l $rb/frob.git/hooks/*; ok; /post-receive.h00-second/ + /post-receive.h01-first/ + /post-receive -. .*local/hooks/multi-hook-driver/ + ls -l $rb/gitolite-admin.git/hooks/* + ok; /post-receive.h/ + /post-receive -. .*local/hooks/multi-hook-driver/ + !/post-update -. .*local/hooks/multi-hook-driver/ +"; + +try " + cd .. + + # Single hook still works + [ -d foo ]; !ok; + CLONE admin foo; ok; /empty/; /cloned/ + cd foo + tc a1; ok; /ee47f8b/ + PUSH admin master; ok; /new.*master -. master/ + /hooks/post-receive.h00-first/ + !/post-receive.*has args:/ + /post-receive.h00-first has stdin: 0000000000000000000000000000000000000000 ee47f8b6be2160ad1a3f69c97a0cb3d488e6657e refs/heads/master/ + + cd .. + + # Multiple hooks fired + [ -d bar ]; !ok; + CLONE admin bar; ok; /empty/; /cloned/ + cd bar + tc a2; ok; /cfc8561/ + PUSH admin master; ok; /new.*master -. master/ + /hooks/pre-receive.h00-first/ + !/hooks/pre-recieve.*has args:/ + /hooks/pre-receive.h00-first has stdin: 0000000000000000000000000000000000000000 cfc8561c7827a8b94df6c5dad156383d4cb210f5 refs/heads/master/ + /hooks/pre-receive.h01-second/ + !/hooks/pre-receive.h01.*has args:/ + /hooks/pre-receive.h01-second has stdin: 0000000000000000000000000000000000000000 cfc8561c7827a8b94df6c5dad156383d4cb210f5 refs/heads/master/ + + cd .. + + # Post-update has stdin instead of arguments + [ -d baz ]; !ok; + CLONE admin baz; ok; /empty/; /cloned/ + cd baz + tc a3; ok; /2863617/ + PUSH admin master; ok; /new.*master -. master/ + /hooks/post-receive.h00-first/ + !/hooks/post-receive.h00.*has args:/ + /hooks/post-receive.h00-first has stdin: 0000000000000000000000000000000000000000 28636171ae703f42fb17c312c6b6a078ed07a2cd refs/heads/master/ + /hooks/post-update.h00-first/ + /hooks/post-update.h00-first has args: refs/heads/master/ + !/hooks/post-update.h00.*has stdin:/ + /hooks/post-update.h01-second/ + /hooks/post-update.h01-second has args: refs/heads/master/ + !/hooks/post-update.h01.*has stdin:/ +"; + +# Verify hooks are removed properly + +confadd ' + repo foo + RW+ = @all + option hook.post-receive = "" + + repo bar + RW+ = @all + option hook.pre-receive = second + + repo baz + RW+ = @all + option hook.post-receive = "" + option hook.post-update = second +'; + +try "ADMIN_PUSH repo-specific-hooks-02; !/FATAL/" or die text(); + +try " + ls $rb/foo.git/hooks/*; ok; !/post-receive.h0/ + ls $rb/bar.git/hooks/*; ok; !/pre-receive.*first/ + /pre-receive.h00-second/ + ls $rb/baz.git/hooks/*; ok; !/post-receive.h0/ + !/post-update.*first/ + /post-update.h00-second/ +"; + +try " + cd .. + + # Foo has no hooks + cd foo + tc b1; ok; /7ef69de/ + PUSH admin master; ok; /master -. master/ + !/hooks/post-receive/ + + cd .. + + # Bar only has the second hook + cd bar + tc b2; ok; /cc7808f/ + PUSH admin master; ok; /master -. master/ + /hooks/pre-receive.h00-second/ + !/hooks/pre-receive.*has args:/ + /hooks/pre-receive.h00-second has stdin: cfc8561c7827a8b94df6c5dad156383d4cb210f5 cc7808f77c7c7d705f82dc54dc3152146175768f refs/heads/master/ + + cd .. + + # Baz has no post-receive and keeps the second hook for post-update + cd baz + tc b3; ok; /8d20101/ + PUSH admin master; ok; /master -. master/ + !/hooks/post-receive.*/ + /hooks/post-update.h00-second/ + /hooks/post-update.h00-second has args: refs/heads/master/ + !/hooks/post-update.*has stdin/ +"; @@ -0,0 +1,33 @@ +#!/usr/bin/perl +use strict; +use warnings; + +BEGIN { + unlink "$ENV{HOME}/.ssh/authorized_keys"; +} + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +use Cwd; +my $workdir = getcwd(); + +confreset;confadd ' +repo foo/..* + C = u1 u2 u3 + RW+ = CREATOR + RW = WRITERS + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + mkdir -p keydir + cp \$HOME/.ssh/u*.pub keydir + cp \$HOME/.ssh/admin.pub keydir + git add keydir + git commit -m 6k + glt push admin origin +"; diff --git a/t/rule-seq.t b/t/rule-seq.t new file mode 100755 index 0000000..0d97558 --- /dev/null +++ b/t/rule-seq.t @@ -0,0 +1,87 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# rule sequence +# ---------------------------------------------------------------------- + +# this is the specific example in commit 32056e0 of g2 + +try "plan 27"; + +try "DEF POK = !/DENIED/; !/failed to push/"; + +confreset; confadd ' + @private-owners = u1 u2 + @experienced-private-owners = u3 u4 + + repo CREATOR/.* + C = @private-owners @experienced-private-owners + RWD = CREATOR + RW = WRITERS + R = READERS + - = @private-owners + RW+D = CREATOR +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + glt clone u1 file:///u1/r1 + /Initialized empty Git repository in .*/u1/r1.git// + cd r1 + tc h-395 + glt push u1 origin master + git checkout -b br1 + tc m-367 + tc i-747 + + # u1 create branch + glt push u1 origin br1 + /\\* \\[new branch\\] br1 -> br1/ + POK; /br1 -> br1/ + + # u1 rewind branch + git reset --hard HEAD^ + tc e-633 + glt push u1 origin +br1 + /\\+ refs/heads/br1 u1/r1 u1 DENIED by refs// + /error: hook declined to update refs/heads/br1/ + reject + + # u1 delete branch + glt push u1 origin :br1 + /\\[deleted\\] br1/ + + cd .. + rm -rf r1 + glt clone u3 file:///u3/r1 + /Initialized empty Git repository in .*/u3/r1.git// + cd r1 + tc p-274 + glt push u3 origin master + git checkout -b br1 + tc s-613 + tc k-988 + + # u3 create branch + glt push u3 origin br1 + /\\* \\[new branch\\] br1 -> br1/ + POK; /br1 -> br1/ + + # u3 rewind branch + git reset --hard HEAD^ + tc n-919 + glt push u3 origin +br1 + /To file:///u3/r1/ + /\\+ .......\\.\\.\\........ br1 -> br1 \\(forced update\\)/ + + # u3 delete branch + glt push u3 origin :br1 + /\\[deleted\\] br1/ +"; diff --git a/t/sequence.t b/t/sequence.t new file mode 100755 index 0000000..8d66d03 --- /dev/null +++ b/t/sequence.t @@ -0,0 +1,116 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# uhh, seems to be another rule sequence test +# ---------------------------------------------------------------------- + +try "plan 48"; + +confreset;confadd ' + @staff = u1 u2 u3 + @gfoo = foo/CREATOR/..* + repo @gfoo + C = u1 + RW+ = CREATOR + RW = WRITERS + - = @staff +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + glt clone u1 file:///foo/u1/bar; ok + /Initialized empty Git repository in .*/foo/u1/bar.git// + + cd bar + tc p-906 + glt push u1 origin master + /To file:///foo/u1/bar/ + /\\[new branch\\] master -> master/ + echo WRITERS u2 | glt perms u1 -c foo/u1/bar + glt perms u1 foo/u1/bar -l + /WRITERS u2/ + # expand + glt info u2 + /R W *\tfoo/u1/bar/ + /R W *\ttesting/ + + # push + cd .. + glt clone u2 file:///foo/u1/bar u2bar + /Cloning into 'u2bar'.../ + cd u2bar + tc p-222 + glt push u2 + /master -> master/ + !/DENIED/ + !/failed to push/ +"; + +confreset;confadd ' + @staff = u1 u2 u3 + @gfoo = foo/CREATOR/..* + repo @gfoo + C = u1 + RW+ = CREATOR + - = @staff + RW = WRITERS + R = READERS +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + cd .. + rm -rf bar u2bar + glt clone u1 file:///foo/u1/bar; ok + /Initialized empty Git repository in .*/foo/u1/bar.git// + + cd bar + tc p-906 + glt push u1 origin master + /To file:///foo/u1/bar/ + /\\[new branch\\] master -> master/ + echo WRITERS u2 | glt perms u1 -c foo/u1/bar + glt perms u1 foo/u1/bar -l + /WRITERS u2/ + # expand + glt info u2 + !/R W *\tfoo/u1/baz/ + /R W *\tfoo/u1/bar/ + /R W *\ttesting/ + + # push + cd .. + glt clone u2 file:///foo/u1/bar u2bar + /Cloning into 'u2bar'.../ + cd u2bar + tc p-222 + glt push u2 + !ok + reject + /W refs/heads/master foo/u1/bar u2 DENIED by refs/\\.\\*/ + + # auto-create using perms fail + echo READERS u5 | glt perms u4 -c foo/u4/baz + !/Initialized empty Git repository in .*/foo/u4/baz.git/ + /FATAL: repo does not exist, or you are not authorised/ + + # auto-create using perms + echo READERS u2 | glt perms u1 -c foo/u1/baz + /Initialized empty Git repository in .*/foo/u1/baz.git/ + + glt perms u1 foo/u1/baz -l + /READERS u2/ + # expand + glt info u2 + /R *\tfoo/u1/baz/ + /R W *\tfoo/u1/bar/ + /R W *\ttesting/ +"; diff --git a/t/smart-http b/t/smart-http new file mode 100755 index 0000000..3ac910b --- /dev/null +++ b/t/smart-http @@ -0,0 +1,90 @@ +#!/bin/bash + +die() { echo "$@"; exit 1; } + +# git clone `url u1 r1` +url() { + echo http://$1:$1@localhost/git/$2.git +} + +# `cmd sitaram info` +cmd() { + c="curl http://$1:$1@localhost/git" + shift + c="$c/$1" + shift + + if [ -n "$1" ] + then + c="$c?$1" + shift + fi + while [ -n "$1" ] + do + c="$c+$1" + shift + done + + echo $c +} + +export tmp=$(mktemp -d); +trap "rm -rf $tmp" 0; +cd $tmp + +tsh "plan 28" + +tsh " + ## ls-remote admin admin + git ls-remote `url admin gitolite-admin` + ok + /HEAD/ + /refs.heads.master/ + ## clone + git clone `url admin gitolite-admin` + ok + /Cloning into/ + ls -al gitolite-admin/conf + /gitolite.conf/ +" || die "step 1" + +cd gitolite-admin +echo repo t2 >> conf/gitolite.conf +echo 'RW+ = u1 u2' >> conf/gitolite.conf + +tsh " + ## add, commit, push + git add conf/gitolite.conf + ok + !/./ + git commit -m t2 + ok + /1 file.*changed/ + git push + ok + /Initialized.*gitolite-home.repositories.t2.git/ + /To http:..localhost.git.gitolite-admin.git/ + /master -. master/ + ## various ls-remotes + git ls-remote `url u1 gitolite-admin` + !ok + /FATAL: R any gitolite-admin u1 DENIED by fallthru/ + git ls-remote `url u1 t2` + ok + !/./ + git ls-remote `url u2 t2` + ok + !/./ + git ls-remote `url u3 t2` + !ok + /FATAL: R any t2 u3 DENIED by fallthru/ + ## push to u1:t2 + git push `url u1 t2` master:master + ok + /To http:..localhost.git.t2.git/ + /master -. master/ + git ls-remote `url u2 t2` + ok + /HEAD/ + /refs.heads.master/ +" || die "step 2" diff --git a/t/smart-http.root-setup b/t/smart-http.root-setup new file mode 100755 index 0000000..f22dcb5 --- /dev/null +++ b/t/smart-http.root-setup @@ -0,0 +1,105 @@ +#!/bin/bash + +# ---------------------------------------------------------------------- +# please do not even LOOK at this file without reading doc/http.mkd +# ---------------------------------------------------------------------- + +die() { echo "$@"; exit 1; } + +# scare the sh*t out of people who run it blindly +[ -f /tmp/gitolite-smart-http-test-OK ] || { + # scary message + echo '+ rm -rf /' + # lots of disk activity + find / >/dev/null 2>/dev/null + # and it he's still clueless, God bless! + echo 'root file system erased successfully. Goodbye and God bless!' + exit 1 +} + +# ---------------------------------------------------------------------- +# are we *BSD or Linux? +uname_s=`uname -s` # could be Linux or FreeBSD or some other BSD +if [ "$uname_s" = "Linux" ] +then + bsd=: +else + lnx=: +fi + +# ---------------------------------------------------------------------- +# main + +[ $EUID = 0 ] || die "you must run this as root" + +# delete any existing apache conf for gitolite +$lnx rm /etc/httpd/conf.d/gitolite.conf +$bsd rm /usr/local/etc/apache24/Includes/gitolite.conf + +# build your "home within a home" +$lnx cd ~apache +$bsd rm -rf /tmp/usr.share.httpd +$bsd mkdir -p /tmp/usr.share.httpd +$bsd chown www:www /tmp/usr.share.httpd +$bsd cd /tmp/usr.share.httpd + +rm -rf gitolite-home +mkdir gitolite-home +export GITOLITE_HTTP_HOME=$PWD/gitolite-home + +# get the gitolite sources +cd gitolite-home +git clone /tmp/gitolite.git gitolite-source +# NOTE: I use a bare repo in /tmp for convenience; you'd use +# 'https://github.com/sitaramc/gitolite' + +# make the bin directory, and add it to PATH +cd gitolite-source +mkdir $GITOLITE_HTTP_HOME/bin +./install -ln $GITOLITE_HTTP_HOME/bin +export PATH=$PATH:$GITOLITE_HTTP_HOME/bin + +# come back to base, then run setup. Notice that you have to point HOME to +# the right place, even if it is just for this command +cd $GITOLITE_HTTP_HOME +HOME=$GITOLITE_HTTP_HOME gitolite setup -a admin + +# insert some essential lines at the beginning of the rc file +echo '$ENV{PATH} .= ":$ENV{GITOLITE_HTTP_HOME}/bin";' >> 1 +echo >> 1 +cat .gitolite.rc >> 1 +\mv 1 .gitolite.rc + +# fix up ownership +$lnx chown -R apache:apache $GITOLITE_HTTP_HOME +$bsd chown -R www:www $GITOLITE_HTTP_HOME + +# create the apache config. Note the trailing slashes on the 2 ScriptAlias +# lines. (The second one is optional for most sites). NOTE: you also need to +# give the AuthUserFile a better name/location than what I have below. +cat <<EOF1 > 1 +SetEnv GIT_PROJECT_ROOT $GITOLITE_HTTP_HOME/repositories +ScriptAlias /git/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ +ScriptAlias /gitmob/ $GITOLITE_HTTP_HOME/gitolite-source/src/gitolite-shell/ +SetEnv GITOLITE_HTTP_HOME $GITOLITE_HTTP_HOME +SetEnv GIT_HTTP_EXPORT_ALL + +<Location /git> + AuthType Basic + AuthName "Private Git Access" + Require valid-user + AuthUserFile $GITOLITE_HTTP_HOME/gitolite-http-authuserfile +</Location> +EOF1 +$lnx mv 1 /etc/httpd/conf.d/gitolite.conf +$bsd mv 1 /usr/local/etc/apache24/Includes/gitolite.conf + +# NOTE: this is for testing only +htpasswd -bc $GITOLITE_HTTP_HOME/gitolite-http-authuserfile admin admin +map "htpasswd -b $GITOLITE_HTTP_HOME/gitolite-http-authuserfile % %" u{1..6} +$lnx chown apache:apache $GITOLITE_HTTP_HOME/gitolite-http-authuserfile +$bsd chown www:www $GITOLITE_HTTP_HOME/gitolite-http-authuserfile + +# restart httpd to make it pick up all the new stuff +$lnx service httpd restart +$bsd /usr/local/etc/rc.d/apache24 restart diff --git a/t/ssh-authkeys.t b/t/ssh-authkeys.t new file mode 100755 index 0000000..46b9413 --- /dev/null +++ b/t/ssh-authkeys.t @@ -0,0 +1,77 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# testing the (separate) authkeys handler +# ---------------------------------------------------------------------- + +$ENV{GL_BINDIR} = "$ENV{PWD}/src"; + +my $ak = "$ENV{HOME}/.ssh/authorized_keys"; +mkdir("$ENV{HOME}/.ssh", 0700) if not -d "$ENV{HOME}/.ssh"; +my $kd = `gitolite query-rc -n GL_ADMIN_BASE` . "/keydir"; + +try "plan 49"; + +my $pgm = "gitolite ../triggers/post-compile/ssh-authkeys"; + +try " + # prep + rm -rf $ak; ok + + $pgm; ok + mkdir $kd; ok + cd $kd; ok + $pgm; ok; /authorized_keys missing/ + /creating/ + wc < $ak; ok; /2 *6 *32/ + # some gl keys + ssh-keygen -N '' -q -f alice -C alice + ssh-keygen -N '' -q -f bob -C bob + ssh-keygen -N '' -q -f carol -C carol + ssh-keygen -N '' -q -f dave -C dave + ssh-keygen -N '' -q -f eve -C eve + rm alice bob carol dave eve + ls -a; ok; /alice.pub/; /bob.pub/; /carol.pub/; /dave.pub/; /eve.pub/ + $pgm; ok; + wc < $ak; ok; /^ *7 .*/; + grep gitolite $ak; ok; /start/ + /end/ + + # some normal keys + mv alice.pub $ak; ok + cat carol.pub >> $ak; ok + $pgm; ok; /carol.pub duplicates.*non-gitolite key/ + wc < $ak; ok; /^ *8 .*/; + + # moving normal keys up + mv dave.pub dave + $pgm; ok + cat dave >> $ak; ok + grep -n dave $ak; ok; /8:ssh-rsa/ + mv dave dave.pub + $pgm; ok; /carol.pub duplicates.*non-gitolite key/ + /dave.pub duplicates.*non-gitolite key/ + grep -n dave $ak; ok; /3:ssh-rsa/ + + # a bad key + ls -al > bad.pub + $pgm; !ok; /fingerprinting failed for \\'keydir/bad.pub\\'/ + wc < $ak; ok; /^ *9 .*/; + # a good key doesn't get added + ssh-keygen -N '' -q -f good + $pgm; !ok; /fingerprinting failed for \\'keydir/bad.pub\\'/ + wc < $ak; ok; /^ *9 .*/; + # till the bad key is removed + rm bad.pub + $pgm; ok; + wc < $ak; ok; /^ *10 .*/; + + # duplicate gl key + cp bob.pub robert.pub + $pgm; ok; /robert.pub duplicates.*bob.pub/ +"; diff --git a/t/ssh-basic.t b/t/ssh-basic.t new file mode 100755 index 0000000..ebed2d2 --- /dev/null +++ b/t/ssh-basic.t @@ -0,0 +1,57 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Common; +use Gitolite::Test; + +# basic tests using ssh +# ---------------------------------------------------------------------- + +my $bd = `gitolite query-rc -n GL_BINDIR`; +my $h = $ENV{HOME}; +my $ab = `gitolite query-rc -n GL_ADMIN_BASE`; +umask 0077; + +try " + plan 26 + + # reset stuff + rm -f $h/.ssh/authorized_keys; ok or die 1 + + cp $bd/../t/keys/u[1-6]* $h/.ssh; ok or die 2 + cp $bd/../t/keys/admin* $h/.ssh; ok or die 3 + cp $bd/../t/keys/config $h/.ssh; ok or die 4 + cat $h/.ssh/config + perl s/%USER/$ENV{USER}/ + put $h/.ssh/config + + mkdir $ab/keydir; ok or die 5 + cp $bd/../t/keys/*.pub $ab/keydir; ok or die 6 +"; + +system("gitolite ../triggers/post-compile/ssh-authkeys"); + +# basic tests +# ---------------------------------------------------------------------- + +confreset; confadd ' + @g1 = u1 + @g2 = u2 + repo foo + RW = @g1 u3 + R = @g2 u4 +'; + +try "ADMIN_PUSH set3; !/FATAL/" or die text(); + +try " + ssh u1 info; ok; /R W\tfoo/ + ssh u2 info; ok; /R \tfoo/ + ssh u3 info; ok; /R W\tfoo/ + ssh u4 info; ok; /R \tfoo/ + ssh u5 info; ok; !/foo/ + ssh u6 info; ok; !/foo/ +" diff --git a/t/templates.t b/t/templates.t new file mode 100755 index 0000000..a705167 --- /dev/null +++ b/t/templates.t @@ -0,0 +1,1322 @@ +#!/usr/bin/perl +use strict; +use warnings; +use 5.10.0; +use Data::Dumper; + +# this is hardcoded; change it if needed +use lib "$ENV{PWD}/src/lib"; + +use Gitolite::Test; + +BEGIN { + $ENV{G3T_RC} = "$ENV{HOME}/g3trc"; + put "$ENV{G3T_RC}", "\$rc{ROLES} = { + FORCERS => 1, + MASTERS => 1, + READERS => 1, + ROOT => 1, + TEAM => 1, + WRITERS => 1 + }"; +} + +use Gitolite::Rc; +use Gitolite::Common; +use Gitolite::Conf::Load; + +# permissions using role names +# ---------------------------------------------------------------------- + +try "plan 1163"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +# basic push admin repo +confreset; confadd ' +# order is important for these next few repo group definitions, because an +# individual repo may pick and choose any combination of them, and they should +# apply sensibly. In this example, "BASE" is pretty much required; the others +# are optional. + +# if you want someone to have "ultimate" power over all refs in the repo, +# add them to the ROOT role. +repo @BASE + RW+CD = ROOT + +# add this to the repo group list to allow personal branches +repo @PERSONAL + RW+CD dev/USER/ = TEAM + - dev/ = TEAM + RW+CD refs/tags/dev/USER/ = TEAM + - refs/tags/dev/ = TEAM + +# add this to the repo group list to control tagging for release versions +repo @RELEASES + RWC refs/tags/v[0-9] = RELEASERS + - refs/tags/v[0-9] = @all + +# (the basic set of access rules continues) +repo @BASE + # Note that "FORCERS" here, even though they have RW+CD, + # 1. cannot touch other users personal branches or tags if you added + # PER_BR to the repo group list, and + # 2. create a release tag unless they are also in RELEASE_TAGGERS if + # you added TAGS to the repo group list + RW+CD = FORCERS + RWC master = MASTERS + - master = @all + RWC = RELEASERS MASTERS WRITERS + # Note you can define "@all" to have the READERS role, and then this will + # effectively be public (albeit authenticated public) readable. + R = READERS + +=begin template-data + +repo base = BASE + FORCERS = u1 + MASTERS = u2 + WRITERS = u3 + READERS = u4 + +repo baseroot = BASE + ROOT = admin + FORCERS = u1 + MASTERS = u2 + WRITERS = u3 + READERS = u4 + +repo basepers = BASE PERSONAL + FORCERS = u1 + MASTERS = u2 + WRITERS = u3 + READERS = u4 u5 + TEAM = u1 u2 u3 u5 u6 + +repo baserel = BASE RELEASES + FORCERS = u1 + MASTERS = u2 + WRITERS = u3 + READERS = u4 u5 + TEAM = u1 u2 u3 u5 u6 + +repo baseall = BASE PERSONAL RELEASES + ROOT = admin + FORCERS = u1 + MASTERS = u2 + WRITERS = u3 + READERS = u4 u5 + TEAM = u1 u2 u3 u5 u6 + +=end +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +# now we step outside tsh, into pure perl + +sub _access { + push @_, 'any' if @_ < 4; + my $ref = pop; + $ref =~ s(^)(refs/heads/) if $ref ne 'any' and $ref !~ m(^(refs|VREF)/); + push @_, $ref; + + return access(@_); +} + +sub ok { + say STDOUT (_access(@_) !~ /DENIED/ ? "ok" : "not ok"); +} +sub nok { + say STDOUT (_access(@_) =~ /DENIED/ ? "ok" : "not ok"); +} + +nok qw( base admin R ); +nok qw( base admin W master ); +nok qw( base admin W notmaster ); +nok qw( base admin W refs/tags/boo ); +nok qw( base admin W refs/tags/v1 ); +nok qw( base admin W dev/admin/foo ); +nok qw( base admin W refs/tags/dev/admin/foo ); +nok qw( base admin W dev/alice/foo ); +nok qw( base admin W refs/tags/dev/alice/foo ); +nok qw( base admin + master ); +nok qw( base admin + notmaster ); +nok qw( base admin + refs/tags/boo ); +nok qw( base admin + refs/tags/v1 ); +nok qw( base admin + dev/admin/foo ); +nok qw( base admin + refs/tags/dev/admin/foo ); +nok qw( base admin + dev/alice/foo ); +nok qw( base admin + refs/tags/dev/alice/foo ); +nok qw( base admin C master ); +nok qw( base admin C notmaster ); +nok qw( base admin C refs/tags/boo ); +nok qw( base admin C refs/tags/v1 ); +nok qw( base admin C dev/admin/foo ); +nok qw( base admin C refs/tags/dev/admin/foo ); +nok qw( base admin C dev/alice/foo ); +nok qw( base admin C refs/tags/dev/alice/foo ); +nok qw( base admin D master ); +nok qw( base admin D notmaster ); +nok qw( base admin D refs/tags/boo ); +nok qw( base admin D refs/tags/v1 ); +nok qw( base admin D dev/admin/foo ); +nok qw( base admin D refs/tags/dev/admin/foo ); +nok qw( base admin D dev/alice/foo ); +nok qw( base admin D refs/tags/dev/alice/foo ); + +ok qw( base u1 R ); +ok qw( base u1 W master ); +ok qw( base u1 W notmaster ); +ok qw( base u1 W refs/tags/boo ); +ok qw( base u1 W refs/tags/v1 ); +ok qw( base u1 W dev/u1/foo ); +ok qw( base u1 W refs/tags/dev/u1/foo ); +ok qw( base u1 W dev/alice/foo ); +ok qw( base u1 W refs/tags/dev/alice/foo ); +ok qw( base u1 + master ); +ok qw( base u1 + notmaster ); +ok qw( base u1 + refs/tags/boo ); +ok qw( base u1 + refs/tags/v1 ); +ok qw( base u1 + dev/u1/foo ); +ok qw( base u1 + refs/tags/dev/u1/foo ); +ok qw( base u1 + dev/alice/foo ); +ok qw( base u1 + refs/tags/dev/alice/foo ); +ok qw( base u1 C master ); +ok qw( base u1 C notmaster ); +ok qw( base u1 C refs/tags/boo ); +ok qw( base u1 C refs/tags/v1 ); +ok qw( base u1 C dev/u1/foo ); +ok qw( base u1 C refs/tags/dev/u1/foo ); +ok qw( base u1 C dev/alice/foo ); +ok qw( base u1 C refs/tags/dev/alice/foo ); +ok qw( base u1 D master ); +ok qw( base u1 D notmaster ); +ok qw( base u1 D refs/tags/boo ); +ok qw( base u1 D refs/tags/v1 ); +ok qw( base u1 D dev/u1/foo ); +ok qw( base u1 D refs/tags/dev/u1/foo ); +ok qw( base u1 D dev/alice/foo ); +ok qw( base u1 D refs/tags/dev/alice/foo ); + +ok qw( base u2 R ); +ok qw( base u2 W master ); +ok qw( base u2 W notmaster ); +ok qw( base u2 W refs/tags/boo ); +ok qw( base u2 W refs/tags/v1 ); +ok qw( base u2 W dev/u2/foo ); +ok qw( base u2 W refs/tags/dev/u2/foo ); +ok qw( base u2 W dev/alice/foo ); +ok qw( base u2 W refs/tags/dev/alice/foo ); +nok qw( base u2 + master ); +nok qw( base u2 + notmaster ); +nok qw( base u2 + refs/tags/boo ); +nok qw( base u2 + refs/tags/v1 ); +nok qw( base u2 + dev/u2/foo ); +nok qw( base u2 + refs/tags/dev/u2/foo ); +nok qw( base u2 + dev/alice/foo ); +nok qw( base u2 + refs/tags/dev/alice/foo ); +ok qw( base u2 C master ); +ok qw( base u2 C notmaster ); +ok qw( base u2 C refs/tags/boo ); +ok qw( base u2 C refs/tags/v1 ); +ok qw( base u2 C dev/u2/foo ); +ok qw( base u2 C refs/tags/dev/u2/foo ); +ok qw( base u2 C dev/alice/foo ); +ok qw( base u2 C refs/tags/dev/alice/foo ); +nok qw( base u2 D master ); +nok qw( base u2 D notmaster ); +nok qw( base u2 D refs/tags/boo ); +nok qw( base u2 D refs/tags/v1 ); +nok qw( base u2 D dev/u2/foo ); +nok qw( base u2 D refs/tags/dev/u2/foo ); +nok qw( base u2 D dev/alice/foo ); +nok qw( base u2 D refs/tags/dev/alice/foo ); + +ok qw( base u3 R ); +nok qw( base u3 W master ); +ok qw( base u3 W notmaster ); +ok qw( base u3 W refs/tags/boo ); +ok qw( base u3 W refs/tags/v1 ); +ok qw( base u3 W dev/u3/foo ); +ok qw( base u3 W refs/tags/dev/u3/foo ); +ok qw( base u3 W dev/alice/foo ); +ok qw( base u3 W refs/tags/dev/alice/foo ); +nok qw( base u3 + master ); +nok qw( base u3 + notmaster ); +nok qw( base u3 + refs/tags/boo ); +nok qw( base u3 + refs/tags/v1 ); +nok qw( base u3 + dev/u3/foo ); +nok qw( base u3 + refs/tags/dev/u3/foo ); +nok qw( base u3 + dev/alice/foo ); +nok qw( base u3 + refs/tags/dev/alice/foo ); +nok qw( base u3 C master ); +ok qw( base u3 C notmaster ); +ok qw( base u3 C refs/tags/boo ); +ok qw( base u3 C refs/tags/v1 ); +ok qw( base u3 C dev/u3/foo ); +ok qw( base u3 C refs/tags/dev/u3/foo ); +ok qw( base u3 C dev/alice/foo ); +ok qw( base u3 C refs/tags/dev/alice/foo ); +nok qw( base u3 D master ); +nok qw( base u3 D notmaster ); +nok qw( base u3 D refs/tags/boo ); +nok qw( base u3 D refs/tags/v1 ); +nok qw( base u3 D dev/u3/foo ); +nok qw( base u3 D refs/tags/dev/u3/foo ); +nok qw( base u3 D dev/alice/foo ); +nok qw( base u3 D refs/tags/dev/alice/foo ); + +ok qw( base u4 R ); +nok qw( base u4 W master ); +nok qw( base u4 W notmaster ); +nok qw( base u4 W refs/tags/boo ); +nok qw( base u4 W refs/tags/v1 ); +nok qw( base u4 W dev/u4/foo ); +nok qw( base u4 W refs/tags/dev/u4/foo ); +nok qw( base u4 W dev/alice/foo ); +nok qw( base u4 W refs/tags/dev/alice/foo ); +nok qw( base u4 + master ); +nok qw( base u4 + notmaster ); +nok qw( base u4 + refs/tags/boo ); +nok qw( base u4 + refs/tags/v1 ); +nok qw( base u4 + dev/u4/foo ); +nok qw( base u4 + refs/tags/dev/u4/foo ); +nok qw( base u4 + dev/alice/foo ); +nok qw( base u4 + refs/tags/dev/alice/foo ); +nok qw( base u4 C master ); +nok qw( base u4 C notmaster ); +nok qw( base u4 C refs/tags/boo ); +nok qw( base u4 C refs/tags/v1 ); +nok qw( base u4 C dev/u4/foo ); +nok qw( base u4 C refs/tags/dev/u4/foo ); +nok qw( base u4 C dev/alice/foo ); +nok qw( base u4 C refs/tags/dev/alice/foo ); +nok qw( base u4 D master ); +nok qw( base u4 D notmaster ); +nok qw( base u4 D refs/tags/boo ); +nok qw( base u4 D refs/tags/v1 ); +nok qw( base u4 D dev/u4/foo ); +nok qw( base u4 D refs/tags/dev/u4/foo ); +nok qw( base u4 D dev/alice/foo ); +nok qw( base u4 D refs/tags/dev/alice/foo ); + +nok qw( base u5 R ); +nok qw( base u5 W master ); +nok qw( base u5 W notmaster ); +nok qw( base u5 W refs/tags/boo ); +nok qw( base u5 W refs/tags/v1 ); +nok qw( base u5 W dev/u5/foo ); +nok qw( base u5 W refs/tags/dev/u5/foo ); +nok qw( base u5 W dev/alice/foo ); +nok qw( base u5 W refs/tags/dev/alice/foo ); +nok qw( base u5 + master ); +nok qw( base u5 + notmaster ); +nok qw( base u5 + refs/tags/boo ); +nok qw( base u5 + refs/tags/v1 ); +nok qw( base u5 + dev/u5/foo ); +nok qw( base u5 + refs/tags/dev/u5/foo ); +nok qw( base u5 + dev/alice/foo ); +nok qw( base u5 + refs/tags/dev/alice/foo ); +nok qw( base u5 C master ); +nok qw( base u5 C notmaster ); +nok qw( base u5 C refs/tags/boo ); +nok qw( base u5 C refs/tags/v1 ); +nok qw( base u5 C dev/u5/foo ); +nok qw( base u5 C refs/tags/dev/u5/foo ); +nok qw( base u5 C dev/alice/foo ); +nok qw( base u5 C refs/tags/dev/alice/foo ); +nok qw( base u5 D master ); +nok qw( base u5 D notmaster ); +nok qw( base u5 D refs/tags/boo ); +nok qw( base u5 D refs/tags/v1 ); +nok qw( base u5 D dev/u5/foo ); +nok qw( base u5 D refs/tags/dev/u5/foo ); +nok qw( base u5 D dev/alice/foo ); +nok qw( base u5 D refs/tags/dev/alice/foo ); + +nok qw( base u6 R ); +nok qw( base u6 W master ); +nok qw( base u6 W notmaster ); +nok qw( base u6 W refs/tags/boo ); +nok qw( base u6 W refs/tags/v1 ); +nok qw( base u6 W dev/u6/foo ); +nok qw( base u6 W refs/tags/dev/u6/foo ); +nok qw( base u6 W dev/alice/foo ); +nok qw( base u6 W refs/tags/dev/alice/foo ); +nok qw( base u6 + master ); +nok qw( base u6 + notmaster ); +nok qw( base u6 + refs/tags/boo ); +nok qw( base u6 + refs/tags/v1 ); +nok qw( base u6 + dev/u6/foo ); +nok qw( base u6 + refs/tags/dev/u6/foo ); +nok qw( base u6 + dev/alice/foo ); +nok qw( base u6 + refs/tags/dev/alice/foo ); +nok qw( base u6 C master ); +nok qw( base u6 C notmaster ); +nok qw( base u6 C refs/tags/boo ); +nok qw( base u6 C refs/tags/v1 ); +nok qw( base u6 C dev/u6/foo ); +nok qw( base u6 C refs/tags/dev/u6/foo ); +nok qw( base u6 C dev/alice/foo ); +nok qw( base u6 C refs/tags/dev/alice/foo ); +nok qw( base u6 D master ); +nok qw( base u6 D notmaster ); +nok qw( base u6 D refs/tags/boo ); +nok qw( base u6 D refs/tags/v1 ); +nok qw( base u6 D dev/u6/foo ); +nok qw( base u6 D refs/tags/dev/u6/foo ); +nok qw( base u6 D dev/alice/foo ); +nok qw( base u6 D refs/tags/dev/alice/foo ); + +ok qw( baseroot admin R ); +ok qw( baseroot admin W master ); +ok qw( baseroot admin W notmaster ); +ok qw( baseroot admin W refs/tags/boo ); +ok qw( baseroot admin W refs/tags/v1 ); +ok qw( baseroot admin W dev/admin/foo ); +ok qw( baseroot admin W refs/tags/dev/admin/foo ); +ok qw( baseroot admin W dev/alice/foo ); +ok qw( baseroot admin W refs/tags/dev/alice/foo ); +ok qw( baseroot admin + master ); +ok qw( baseroot admin + notmaster ); +ok qw( baseroot admin + refs/tags/boo ); +ok qw( baseroot admin + refs/tags/v1 ); +ok qw( baseroot admin + dev/admin/foo ); +ok qw( baseroot admin + refs/tags/dev/admin/foo ); +ok qw( baseroot admin + dev/alice/foo ); +ok qw( baseroot admin + refs/tags/dev/alice/foo ); +ok qw( baseroot admin C master ); +ok qw( baseroot admin C notmaster ); +ok qw( baseroot admin C refs/tags/boo ); +ok qw( baseroot admin C refs/tags/v1 ); +ok qw( baseroot admin C dev/admin/foo ); +ok qw( baseroot admin C refs/tags/dev/admin/foo ); +ok qw( baseroot admin C dev/alice/foo ); +ok qw( baseroot admin C refs/tags/dev/alice/foo ); +ok qw( baseroot admin D master ); +ok qw( baseroot admin D notmaster ); +ok qw( baseroot admin D refs/tags/boo ); +ok qw( baseroot admin D refs/tags/v1 ); +ok qw( baseroot admin D dev/admin/foo ); +ok qw( baseroot admin D refs/tags/dev/admin/foo ); +ok qw( baseroot admin D dev/alice/foo ); +ok qw( baseroot admin D refs/tags/dev/alice/foo ); + +ok qw( baseroot u1 R ); +ok qw( baseroot u1 W master ); +ok qw( baseroot u1 W notmaster ); +ok qw( baseroot u1 W refs/tags/boo ); +ok qw( baseroot u1 W refs/tags/v1 ); +ok qw( baseroot u1 W dev/u1/foo ); +ok qw( baseroot u1 W refs/tags/dev/u1/foo ); +ok qw( baseroot u1 W dev/alice/foo ); +ok qw( baseroot u1 W refs/tags/dev/alice/foo ); +ok qw( baseroot u1 + master ); +ok qw( baseroot u1 + notmaster ); +ok qw( baseroot u1 + refs/tags/boo ); +ok qw( baseroot u1 + refs/tags/v1 ); +ok qw( baseroot u1 + dev/u1/foo ); +ok qw( baseroot u1 + refs/tags/dev/u1/foo ); +ok qw( baseroot u1 + dev/alice/foo ); +ok qw( baseroot u1 + refs/tags/dev/alice/foo ); +ok qw( baseroot u1 C master ); +ok qw( baseroot u1 C notmaster ); +ok qw( baseroot u1 C refs/tags/boo ); +ok qw( baseroot u1 C refs/tags/v1 ); +ok qw( baseroot u1 C dev/u1/foo ); +ok qw( baseroot u1 C refs/tags/dev/u1/foo ); +ok qw( baseroot u1 C dev/alice/foo ); +ok qw( baseroot u1 C refs/tags/dev/alice/foo ); +ok qw( baseroot u1 D master ); +ok qw( baseroot u1 D notmaster ); +ok qw( baseroot u1 D refs/tags/boo ); +ok qw( baseroot u1 D refs/tags/v1 ); +ok qw( baseroot u1 D dev/u1/foo ); +ok qw( baseroot u1 D refs/tags/dev/u1/foo ); +ok qw( baseroot u1 D dev/alice/foo ); +ok qw( baseroot u1 D refs/tags/dev/alice/foo ); + +ok qw( baseroot u2 R ); +ok qw( baseroot u2 W master ); +ok qw( baseroot u2 W notmaster ); +ok qw( baseroot u2 W refs/tags/boo ); +ok qw( baseroot u2 W refs/tags/v1 ); +ok qw( baseroot u2 W dev/u2/foo ); +ok qw( baseroot u2 W refs/tags/dev/u2/foo ); +ok qw( baseroot u2 W dev/alice/foo ); +ok qw( baseroot u2 W refs/tags/dev/alice/foo ); +nok qw( baseroot u2 + master ); +nok qw( baseroot u2 + notmaster ); +nok qw( baseroot u2 + refs/tags/boo ); +nok qw( baseroot u2 + refs/tags/v1 ); +nok qw( baseroot u2 + dev/u2/foo ); +nok qw( baseroot u2 + refs/tags/dev/u2/foo ); +nok qw( baseroot u2 + dev/alice/foo ); +nok qw( baseroot u2 + refs/tags/dev/alice/foo ); +ok qw( baseroot u2 C master ); +ok qw( baseroot u2 C notmaster ); +ok qw( baseroot u2 C refs/tags/boo ); +ok qw( baseroot u2 C refs/tags/v1 ); +ok qw( baseroot u2 C dev/u2/foo ); +ok qw( baseroot u2 C refs/tags/dev/u2/foo ); +ok qw( baseroot u2 C dev/alice/foo ); +ok qw( baseroot u2 C refs/tags/dev/alice/foo ); +nok qw( baseroot u2 D master ); +nok qw( baseroot u2 D notmaster ); +nok qw( baseroot u2 D refs/tags/boo ); +nok qw( baseroot u2 D refs/tags/v1 ); +nok qw( baseroot u2 D dev/u2/foo ); +nok qw( baseroot u2 D refs/tags/dev/u2/foo ); +nok qw( baseroot u2 D dev/alice/foo ); +nok qw( baseroot u2 D refs/tags/dev/alice/foo ); + +ok qw( baseroot u3 R ); +nok qw( baseroot u3 W master ); +ok qw( baseroot u3 W notmaster ); +ok qw( baseroot u3 W refs/tags/boo ); +ok qw( baseroot u3 W refs/tags/v1 ); +ok qw( baseroot u3 W dev/u3/foo ); +ok qw( baseroot u3 W refs/tags/dev/u3/foo ); +ok qw( baseroot u3 W dev/alice/foo ); +ok qw( baseroot u3 W refs/tags/dev/alice/foo ); +nok qw( baseroot u3 + master ); +nok qw( baseroot u3 + notmaster ); +nok qw( baseroot u3 + refs/tags/boo ); +nok qw( baseroot u3 + refs/tags/v1 ); +nok qw( baseroot u3 + dev/u3/foo ); +nok qw( baseroot u3 + refs/tags/dev/u3/foo ); +nok qw( baseroot u3 + dev/alice/foo ); +nok qw( baseroot u3 + refs/tags/dev/alice/foo ); +nok qw( baseroot u3 C master ); +ok qw( baseroot u3 C notmaster ); +ok qw( baseroot u3 C refs/tags/boo ); +ok qw( baseroot u3 C refs/tags/v1 ); +ok qw( baseroot u3 C dev/u3/foo ); +ok qw( baseroot u3 C refs/tags/dev/u3/foo ); +ok qw( baseroot u3 C dev/alice/foo ); +ok qw( baseroot u3 C refs/tags/dev/alice/foo ); +nok qw( baseroot u3 D master ); +nok qw( baseroot u3 D notmaster ); +nok qw( baseroot u3 D refs/tags/boo ); +nok qw( baseroot u3 D refs/tags/v1 ); +nok qw( baseroot u3 D dev/u3/foo ); +nok qw( baseroot u3 D refs/tags/dev/u3/foo ); +nok qw( baseroot u3 D dev/alice/foo ); +nok qw( baseroot u3 D refs/tags/dev/alice/foo ); + +ok qw( baseroot u4 R ); +nok qw( baseroot u4 W master ); +nok qw( baseroot u4 W notmaster ); +nok qw( baseroot u4 W refs/tags/boo ); +nok qw( baseroot u4 W refs/tags/v1 ); +nok qw( baseroot u4 W dev/u4/foo ); +nok qw( baseroot u4 W refs/tags/dev/u4/foo ); +nok qw( baseroot u4 W dev/alice/foo ); +nok qw( baseroot u4 W refs/tags/dev/alice/foo ); +nok qw( baseroot u4 + master ); +nok qw( baseroot u4 + notmaster ); +nok qw( baseroot u4 + refs/tags/boo ); +nok qw( baseroot u4 + refs/tags/v1 ); +nok qw( baseroot u4 + dev/u4/foo ); +nok qw( baseroot u4 + refs/tags/dev/u4/foo ); +nok qw( baseroot u4 + dev/alice/foo ); +nok qw( baseroot u4 + refs/tags/dev/alice/foo ); +nok qw( baseroot u4 C master ); +nok qw( baseroot u4 C notmaster ); +nok qw( baseroot u4 C refs/tags/boo ); +nok qw( baseroot u4 C refs/tags/v1 ); +nok qw( baseroot u4 C dev/u4/foo ); +nok qw( baseroot u4 C refs/tags/dev/u4/foo ); +nok qw( baseroot u4 C dev/alice/foo ); +nok qw( baseroot u4 C refs/tags/dev/alice/foo ); +nok qw( baseroot u4 D master ); +nok qw( baseroot u4 D notmaster ); +nok qw( baseroot u4 D refs/tags/boo ); +nok qw( baseroot u4 D refs/tags/v1 ); +nok qw( baseroot u4 D dev/u4/foo ); +nok qw( baseroot u4 D refs/tags/dev/u4/foo ); +nok qw( baseroot u4 D dev/alice/foo ); +nok qw( baseroot u4 D refs/tags/dev/alice/foo ); + +nok qw( baseroot u5 R ); +nok qw( baseroot u5 W master ); +nok qw( baseroot u5 W notmaster ); +nok qw( baseroot u5 W refs/tags/boo ); +nok qw( baseroot u5 W refs/tags/v1 ); +nok qw( baseroot u5 W dev/u5/foo ); +nok qw( baseroot u5 W refs/tags/dev/u5/foo ); +nok qw( baseroot u5 W dev/alice/foo ); +nok qw( baseroot u5 W refs/tags/dev/alice/foo ); +nok qw( baseroot u5 + master ); +nok qw( baseroot u5 + notmaster ); +nok qw( baseroot u5 + refs/tags/boo ); +nok qw( baseroot u5 + refs/tags/v1 ); +nok qw( baseroot u5 + dev/u5/foo ); +nok qw( baseroot u5 + refs/tags/dev/u5/foo ); +nok qw( baseroot u5 + dev/alice/foo ); +nok qw( baseroot u5 + refs/tags/dev/alice/foo ); +nok qw( baseroot u5 C master ); +nok qw( baseroot u5 C notmaster ); +nok qw( baseroot u5 C refs/tags/boo ); +nok qw( baseroot u5 C refs/tags/v1 ); +nok qw( baseroot u5 C dev/u5/foo ); +nok qw( baseroot u5 C refs/tags/dev/u5/foo ); +nok qw( baseroot u5 C dev/alice/foo ); +nok qw( baseroot u5 C refs/tags/dev/alice/foo ); +nok qw( baseroot u5 D master ); +nok qw( baseroot u5 D notmaster ); +nok qw( baseroot u5 D refs/tags/boo ); +nok qw( baseroot u5 D refs/tags/v1 ); +nok qw( baseroot u5 D dev/u5/foo ); +nok qw( baseroot u5 D refs/tags/dev/u5/foo ); +nok qw( baseroot u5 D dev/alice/foo ); +nok qw( baseroot u5 D refs/tags/dev/alice/foo ); + +nok qw( baseroot u6 R ); +nok qw( baseroot u6 W master ); +nok qw( baseroot u6 W notmaster ); +nok qw( baseroot u6 W refs/tags/boo ); +nok qw( baseroot u6 W refs/tags/v1 ); +nok qw( baseroot u6 W dev/u6/foo ); +nok qw( baseroot u6 W refs/tags/dev/u6/foo ); +nok qw( baseroot u6 W dev/alice/foo ); +nok qw( baseroot u6 W refs/tags/dev/alice/foo ); +nok qw( baseroot u6 + master ); +nok qw( baseroot u6 + notmaster ); +nok qw( baseroot u6 + refs/tags/boo ); +nok qw( baseroot u6 + refs/tags/v1 ); +nok qw( baseroot u6 + dev/u6/foo ); +nok qw( baseroot u6 + refs/tags/dev/u6/foo ); +nok qw( baseroot u6 + dev/alice/foo ); +nok qw( baseroot u6 + refs/tags/dev/alice/foo ); +nok qw( baseroot u6 C master ); +nok qw( baseroot u6 C notmaster ); +nok qw( baseroot u6 C refs/tags/boo ); +nok qw( baseroot u6 C refs/tags/v1 ); +nok qw( baseroot u6 C dev/u6/foo ); +nok qw( baseroot u6 C refs/tags/dev/u6/foo ); +nok qw( baseroot u6 C dev/alice/foo ); +nok qw( baseroot u6 C refs/tags/dev/alice/foo ); +nok qw( baseroot u6 D master ); +nok qw( baseroot u6 D notmaster ); +nok qw( baseroot u6 D refs/tags/boo ); +nok qw( baseroot u6 D refs/tags/v1 ); +nok qw( baseroot u6 D dev/u6/foo ); +nok qw( baseroot u6 D refs/tags/dev/u6/foo ); +nok qw( baseroot u6 D dev/alice/foo ); +nok qw( baseroot u6 D refs/tags/dev/alice/foo ); + +nok qw( basepers admin R ); +nok qw( basepers admin W master ); +nok qw( basepers admin W notmaster ); +nok qw( basepers admin W refs/tags/boo ); +nok qw( basepers admin W refs/tags/v1 ); +nok qw( basepers admin W dev/admin/foo ); +nok qw( basepers admin W refs/tags/dev/admin/foo ); +nok qw( basepers admin W dev/alice/foo ); +nok qw( basepers admin W refs/tags/dev/alice/foo ); +nok qw( basepers admin + master ); +nok qw( basepers admin + notmaster ); +nok qw( basepers admin + refs/tags/boo ); +nok qw( basepers admin + refs/tags/v1 ); +nok qw( basepers admin + dev/admin/foo ); +nok qw( basepers admin + refs/tags/dev/admin/foo ); +nok qw( basepers admin + dev/alice/foo ); +nok qw( basepers admin + refs/tags/dev/alice/foo ); +nok qw( basepers admin C master ); +nok qw( basepers admin C notmaster ); +nok qw( basepers admin C refs/tags/boo ); +nok qw( basepers admin C refs/tags/v1 ); +nok qw( basepers admin C dev/admin/foo ); +nok qw( basepers admin C refs/tags/dev/admin/foo ); +nok qw( basepers admin C dev/alice/foo ); +nok qw( basepers admin C refs/tags/dev/alice/foo ); +nok qw( basepers admin D master ); +nok qw( basepers admin D notmaster ); +nok qw( basepers admin D refs/tags/boo ); +nok qw( basepers admin D refs/tags/v1 ); +nok qw( basepers admin D dev/admin/foo ); +nok qw( basepers admin D refs/tags/dev/admin/foo ); +nok qw( basepers admin D dev/alice/foo ); +nok qw( basepers admin D refs/tags/dev/alice/foo ); + +ok qw( basepers u1 R ); +ok qw( basepers u1 W master ); +ok qw( basepers u1 W notmaster ); +ok qw( basepers u1 W refs/tags/boo ); +ok qw( basepers u1 W refs/tags/v1 ); +ok qw( basepers u1 W dev/u1/foo ); +ok qw( basepers u1 W refs/tags/dev/u1/foo ); +nok qw( basepers u1 W dev/alice/foo ); +nok qw( basepers u1 W refs/tags/dev/alice/foo ); +ok qw( basepers u1 + master ); +ok qw( basepers u1 + notmaster ); +ok qw( basepers u1 + refs/tags/boo ); +ok qw( basepers u1 + refs/tags/v1 ); +ok qw( basepers u1 + dev/u1/foo ); +ok qw( basepers u1 + refs/tags/dev/u1/foo ); +nok qw( basepers u1 + dev/alice/foo ); +nok qw( basepers u1 + refs/tags/dev/alice/foo ); +ok qw( basepers u1 C master ); +ok qw( basepers u1 C notmaster ); +ok qw( basepers u1 C refs/tags/boo ); +ok qw( basepers u1 C refs/tags/v1 ); +ok qw( basepers u1 C dev/u1/foo ); +ok qw( basepers u1 C refs/tags/dev/u1/foo ); +nok qw( basepers u1 C dev/alice/foo ); +nok qw( basepers u1 C refs/tags/dev/alice/foo ); +ok qw( basepers u1 D master ); +ok qw( basepers u1 D notmaster ); +ok qw( basepers u1 D refs/tags/boo ); +ok qw( basepers u1 D refs/tags/v1 ); +ok qw( basepers u1 D dev/u1/foo ); +ok qw( basepers u1 D refs/tags/dev/u1/foo ); +nok qw( basepers u1 D dev/alice/foo ); +nok qw( basepers u1 D refs/tags/dev/alice/foo ); + +ok qw( basepers u2 R ); +ok qw( basepers u2 W master ); +ok qw( basepers u2 W notmaster ); +ok qw( basepers u2 W refs/tags/boo ); +ok qw( basepers u2 W refs/tags/v1 ); +ok qw( basepers u2 W dev/u2/foo ); +ok qw( basepers u2 W refs/tags/dev/u2/foo ); +nok qw( basepers u2 W dev/alice/foo ); +nok qw( basepers u2 W refs/tags/dev/alice/foo ); +nok qw( basepers u2 + master ); +nok qw( basepers u2 + notmaster ); +nok qw( basepers u2 + refs/tags/boo ); +nok qw( basepers u2 + refs/tags/v1 ); +ok qw( basepers u2 + dev/u2/foo ); +ok qw( basepers u2 + refs/tags/dev/u2/foo ); +nok qw( basepers u2 + dev/alice/foo ); +nok qw( basepers u2 + refs/tags/dev/alice/foo ); +ok qw( basepers u2 C master ); +ok qw( basepers u2 C notmaster ); +ok qw( basepers u2 C refs/tags/boo ); +ok qw( basepers u2 C refs/tags/v1 ); +ok qw( basepers u2 C dev/u2/foo ); +ok qw( basepers u2 C refs/tags/dev/u2/foo ); +nok qw( basepers u2 C dev/alice/foo ); +nok qw( basepers u2 C refs/tags/dev/alice/foo ); +nok qw( basepers u2 D master ); +nok qw( basepers u2 D notmaster ); +nok qw( basepers u2 D refs/tags/boo ); +nok qw( basepers u2 D refs/tags/v1 ); +ok qw( basepers u2 D dev/u2/foo ); +ok qw( basepers u2 D refs/tags/dev/u2/foo ); +nok qw( basepers u2 D dev/alice/foo ); +nok qw( basepers u2 D refs/tags/dev/alice/foo ); + +ok qw( basepers u3 R ); +nok qw( basepers u3 W master ); +ok qw( basepers u3 W notmaster ); +ok qw( basepers u3 W refs/tags/boo ); +ok qw( basepers u3 W refs/tags/v1 ); +ok qw( basepers u3 W dev/u3/foo ); +ok qw( basepers u3 W refs/tags/dev/u3/foo ); +nok qw( basepers u3 W dev/alice/foo ); +nok qw( basepers u3 W refs/tags/dev/alice/foo ); +nok qw( basepers u3 + master ); +nok qw( basepers u3 + notmaster ); +nok qw( basepers u3 + refs/tags/boo ); +nok qw( basepers u3 + refs/tags/v1 ); +ok qw( basepers u3 + dev/u3/foo ); +ok qw( basepers u3 + refs/tags/dev/u3/foo ); +nok qw( basepers u3 + dev/alice/foo ); +nok qw( basepers u3 + refs/tags/dev/alice/foo ); +nok qw( basepers u3 C master ); +ok qw( basepers u3 C notmaster ); +ok qw( basepers u3 C refs/tags/boo ); +ok qw( basepers u3 C refs/tags/v1 ); +ok qw( basepers u3 C dev/u3/foo ); +ok qw( basepers u3 C refs/tags/dev/u3/foo ); +nok qw( basepers u3 C dev/alice/foo ); +nok qw( basepers u3 C refs/tags/dev/alice/foo ); +nok qw( basepers u3 D master ); +nok qw( basepers u3 D notmaster ); +nok qw( basepers u3 D refs/tags/boo ); +nok qw( basepers u3 D refs/tags/v1 ); +ok qw( basepers u3 D dev/u3/foo ); +ok qw( basepers u3 D refs/tags/dev/u3/foo ); +nok qw( basepers u3 D dev/alice/foo ); +nok qw( basepers u3 D refs/tags/dev/alice/foo ); + +ok qw( basepers u4 R ); +nok qw( basepers u4 W master ); +nok qw( basepers u4 W notmaster ); +nok qw( basepers u4 W refs/tags/boo ); +nok qw( basepers u4 W refs/tags/v1 ); +nok qw( basepers u4 W dev/u4/foo ); +nok qw( basepers u4 W refs/tags/dev/u4/foo ); +nok qw( basepers u4 W dev/alice/foo ); +nok qw( basepers u4 W refs/tags/dev/alice/foo ); +nok qw( basepers u4 + master ); +nok qw( basepers u4 + notmaster ); +nok qw( basepers u4 + refs/tags/boo ); +nok qw( basepers u4 + refs/tags/v1 ); +nok qw( basepers u4 + dev/u4/foo ); +nok qw( basepers u4 + refs/tags/dev/u4/foo ); +nok qw( basepers u4 + dev/alice/foo ); +nok qw( basepers u4 + refs/tags/dev/alice/foo ); +nok qw( basepers u4 C master ); +nok qw( basepers u4 C notmaster ); +nok qw( basepers u4 C refs/tags/boo ); +nok qw( basepers u4 C refs/tags/v1 ); +nok qw( basepers u4 C dev/u4/foo ); +nok qw( basepers u4 C refs/tags/dev/u4/foo ); +nok qw( basepers u4 C dev/alice/foo ); +nok qw( basepers u4 C refs/tags/dev/alice/foo ); +nok qw( basepers u4 D master ); +nok qw( basepers u4 D notmaster ); +nok qw( basepers u4 D refs/tags/boo ); +nok qw( basepers u4 D refs/tags/v1 ); +nok qw( basepers u4 D dev/u4/foo ); +nok qw( basepers u4 D refs/tags/dev/u4/foo ); +nok qw( basepers u4 D dev/alice/foo ); +nok qw( basepers u4 D refs/tags/dev/alice/foo ); + +ok qw( basepers u5 R ); +nok qw( basepers u5 W master ); +nok qw( basepers u5 W notmaster ); +nok qw( basepers u5 W refs/tags/boo ); +nok qw( basepers u5 W refs/tags/v1 ); +ok qw( basepers u5 W dev/u5/foo ); +ok qw( basepers u5 W refs/tags/dev/u5/foo ); +nok qw( basepers u5 W dev/alice/foo ); +nok qw( basepers u5 W refs/tags/dev/alice/foo ); +nok qw( basepers u5 + master ); +nok qw( basepers u5 + notmaster ); +nok qw( basepers u5 + refs/tags/boo ); +nok qw( basepers u5 + refs/tags/v1 ); +ok qw( basepers u5 + dev/u5/foo ); +ok qw( basepers u5 + refs/tags/dev/u5/foo ); +nok qw( basepers u5 + dev/alice/foo ); +nok qw( basepers u5 + refs/tags/dev/alice/foo ); +nok qw( basepers u5 C master ); +nok qw( basepers u5 C notmaster ); +nok qw( basepers u5 C refs/tags/boo ); +nok qw( basepers u5 C refs/tags/v1 ); +ok qw( basepers u5 C dev/u5/foo ); +ok qw( basepers u5 C refs/tags/dev/u5/foo ); +nok qw( basepers u5 C dev/alice/foo ); +nok qw( basepers u5 C refs/tags/dev/alice/foo ); +nok qw( basepers u5 D master ); +nok qw( basepers u5 D notmaster ); +nok qw( basepers u5 D refs/tags/boo ); +nok qw( basepers u5 D refs/tags/v1 ); +ok qw( basepers u5 D dev/u5/foo ); +ok qw( basepers u5 D refs/tags/dev/u5/foo ); +nok qw( basepers u5 D dev/alice/foo ); +nok qw( basepers u5 D refs/tags/dev/alice/foo ); + +ok qw( basepers u6 R ); +nok qw( basepers u6 W master ); +nok qw( basepers u6 W notmaster ); +nok qw( basepers u6 W refs/tags/boo ); +nok qw( basepers u6 W refs/tags/v1 ); +ok qw( basepers u6 W dev/u6/foo ); +ok qw( basepers u6 W refs/tags/dev/u6/foo ); +nok qw( basepers u6 W dev/alice/foo ); +nok qw( basepers u6 W refs/tags/dev/alice/foo ); +nok qw( basepers u6 + master ); +nok qw( basepers u6 + notmaster ); +nok qw( basepers u6 + refs/tags/boo ); +nok qw( basepers u6 + refs/tags/v1 ); +ok qw( basepers u6 + dev/u6/foo ); +ok qw( basepers u6 + refs/tags/dev/u6/foo ); +nok qw( basepers u6 + dev/alice/foo ); +nok qw( basepers u6 + refs/tags/dev/alice/foo ); +nok qw( basepers u6 C master ); +nok qw( basepers u6 C notmaster ); +nok qw( basepers u6 C refs/tags/boo ); +nok qw( basepers u6 C refs/tags/v1 ); +ok qw( basepers u6 C dev/u6/foo ); +ok qw( basepers u6 C refs/tags/dev/u6/foo ); +nok qw( basepers u6 C dev/alice/foo ); +nok qw( basepers u6 C refs/tags/dev/alice/foo ); +nok qw( basepers u6 D master ); +nok qw( basepers u6 D notmaster ); +nok qw( basepers u6 D refs/tags/boo ); +nok qw( basepers u6 D refs/tags/v1 ); +ok qw( basepers u6 D dev/u6/foo ); +ok qw( basepers u6 D refs/tags/dev/u6/foo ); +nok qw( basepers u6 D dev/alice/foo ); +nok qw( basepers u6 D refs/tags/dev/alice/foo ); + +nok qw( baserel admin R ); +nok qw( baserel admin W master ); +nok qw( baserel admin W notmaster ); +nok qw( baserel admin W refs/tags/boo ); +nok qw( baserel admin W refs/tags/v1 ); +nok qw( baserel admin W dev/admin/foo ); +nok qw( baserel admin W refs/tags/dev/admin/foo ); +nok qw( baserel admin W dev/alice/foo ); +nok qw( baserel admin W refs/tags/dev/alice/foo ); +nok qw( baserel admin + master ); +nok qw( baserel admin + notmaster ); +nok qw( baserel admin + refs/tags/boo ); +nok qw( baserel admin + refs/tags/v1 ); +nok qw( baserel admin + dev/admin/foo ); +nok qw( baserel admin + refs/tags/dev/admin/foo ); +nok qw( baserel admin + dev/alice/foo ); +nok qw( baserel admin + refs/tags/dev/alice/foo ); +nok qw( baserel admin C master ); +nok qw( baserel admin C notmaster ); +nok qw( baserel admin C refs/tags/boo ); +nok qw( baserel admin C refs/tags/v1 ); +nok qw( baserel admin C dev/admin/foo ); +nok qw( baserel admin C refs/tags/dev/admin/foo ); +nok qw( baserel admin C dev/alice/foo ); +nok qw( baserel admin C refs/tags/dev/alice/foo ); +nok qw( baserel admin D master ); +nok qw( baserel admin D notmaster ); +nok qw( baserel admin D refs/tags/boo ); +nok qw( baserel admin D refs/tags/v1 ); +nok qw( baserel admin D dev/admin/foo ); +nok qw( baserel admin D refs/tags/dev/admin/foo ); +nok qw( baserel admin D dev/alice/foo ); +nok qw( baserel admin D refs/tags/dev/alice/foo ); + +ok qw( baserel u1 R ); +ok qw( baserel u1 W master ); +ok qw( baserel u1 W notmaster ); +ok qw( baserel u1 W refs/tags/boo ); +nok qw( baserel u1 W refs/tags/v1 ); +ok qw( baserel u1 W dev/u1/foo ); +ok qw( baserel u1 W refs/tags/dev/u1/foo ); +ok qw( baserel u1 W dev/alice/foo ); +ok qw( baserel u1 W refs/tags/dev/alice/foo ); +ok qw( baserel u1 + master ); +ok qw( baserel u1 + notmaster ); +ok qw( baserel u1 + refs/tags/boo ); +nok qw( baserel u1 + refs/tags/v1 ); +ok qw( baserel u1 + dev/u1/foo ); +ok qw( baserel u1 + refs/tags/dev/u1/foo ); +ok qw( baserel u1 + dev/alice/foo ); +ok qw( baserel u1 + refs/tags/dev/alice/foo ); +ok qw( baserel u1 C master ); +ok qw( baserel u1 C notmaster ); +ok qw( baserel u1 C refs/tags/boo ); +nok qw( baserel u1 C refs/tags/v1 ); +ok qw( baserel u1 C dev/u1/foo ); +ok qw( baserel u1 C refs/tags/dev/u1/foo ); +ok qw( baserel u1 C dev/alice/foo ); +ok qw( baserel u1 C refs/tags/dev/alice/foo ); +ok qw( baserel u1 D master ); +ok qw( baserel u1 D notmaster ); +ok qw( baserel u1 D refs/tags/boo ); +nok qw( baserel u1 D refs/tags/v1 ); +ok qw( baserel u1 D dev/u1/foo ); +ok qw( baserel u1 D refs/tags/dev/u1/foo ); +ok qw( baserel u1 D dev/alice/foo ); +ok qw( baserel u1 D refs/tags/dev/alice/foo ); + +ok qw( baserel u2 R ); +ok qw( baserel u2 W master ); +ok qw( baserel u2 W notmaster ); +ok qw( baserel u2 W refs/tags/boo ); +nok qw( baserel u2 W refs/tags/v1 ); +ok qw( baserel u2 W dev/u2/foo ); +ok qw( baserel u2 W refs/tags/dev/u2/foo ); +ok qw( baserel u2 W dev/alice/foo ); +ok qw( baserel u2 W refs/tags/dev/alice/foo ); +nok qw( baserel u2 + master ); +nok qw( baserel u2 + notmaster ); +nok qw( baserel u2 + refs/tags/boo ); +nok qw( baserel u2 + refs/tags/v1 ); +nok qw( baserel u2 + dev/u2/foo ); +nok qw( baserel u2 + refs/tags/dev/u2/foo ); +nok qw( baserel u2 + dev/alice/foo ); +nok qw( baserel u2 + refs/tags/dev/alice/foo ); +ok qw( baserel u2 C master ); +ok qw( baserel u2 C notmaster ); +ok qw( baserel u2 C refs/tags/boo ); +nok qw( baserel u2 C refs/tags/v1 ); +ok qw( baserel u2 C dev/u2/foo ); +ok qw( baserel u2 C refs/tags/dev/u2/foo ); +ok qw( baserel u2 C dev/alice/foo ); +ok qw( baserel u2 C refs/tags/dev/alice/foo ); +nok qw( baserel u2 D master ); +nok qw( baserel u2 D notmaster ); +nok qw( baserel u2 D refs/tags/boo ); +nok qw( baserel u2 D refs/tags/v1 ); +nok qw( baserel u2 D dev/u2/foo ); +nok qw( baserel u2 D refs/tags/dev/u2/foo ); +nok qw( baserel u2 D dev/alice/foo ); +nok qw( baserel u2 D refs/tags/dev/alice/foo ); + +ok qw( baserel u3 R ); +nok qw( baserel u3 W master ); +ok qw( baserel u3 W notmaster ); +ok qw( baserel u3 W refs/tags/boo ); +nok qw( baserel u3 W refs/tags/v1 ); +ok qw( baserel u3 W dev/u3/foo ); +ok qw( baserel u3 W refs/tags/dev/u3/foo ); +ok qw( baserel u3 W dev/alice/foo ); +ok qw( baserel u3 W refs/tags/dev/alice/foo ); +nok qw( baserel u3 + master ); +nok qw( baserel u3 + notmaster ); +nok qw( baserel u3 + refs/tags/boo ); +nok qw( baserel u3 + refs/tags/v1 ); +nok qw( baserel u3 + dev/u3/foo ); +nok qw( baserel u3 + refs/tags/dev/u3/foo ); +nok qw( baserel u3 + dev/alice/foo ); +nok qw( baserel u3 + refs/tags/dev/alice/foo ); +nok qw( baserel u3 C master ); +ok qw( baserel u3 C notmaster ); +ok qw( baserel u3 C refs/tags/boo ); +nok qw( baserel u3 C refs/tags/v1 ); +ok qw( baserel u3 C dev/u3/foo ); +ok qw( baserel u3 C refs/tags/dev/u3/foo ); +ok qw( baserel u3 C dev/alice/foo ); +ok qw( baserel u3 C refs/tags/dev/alice/foo ); +nok qw( baserel u3 D master ); +nok qw( baserel u3 D notmaster ); +nok qw( baserel u3 D refs/tags/boo ); +nok qw( baserel u3 D refs/tags/v1 ); +nok qw( baserel u3 D dev/u3/foo ); +nok qw( baserel u3 D refs/tags/dev/u3/foo ); +nok qw( baserel u3 D dev/alice/foo ); +nok qw( baserel u3 D refs/tags/dev/alice/foo ); + +ok qw( baserel u4 R ); +nok qw( baserel u4 W master ); +nok qw( baserel u4 W notmaster ); +nok qw( baserel u4 W refs/tags/boo ); +nok qw( baserel u4 W refs/tags/v1 ); +nok qw( baserel u4 W dev/u4/foo ); +nok qw( baserel u4 W refs/tags/dev/u4/foo ); +nok qw( baserel u4 W dev/alice/foo ); +nok qw( baserel u4 W refs/tags/dev/alice/foo ); +nok qw( baserel u4 + master ); +nok qw( baserel u4 + notmaster ); +nok qw( baserel u4 + refs/tags/boo ); +nok qw( baserel u4 + refs/tags/v1 ); +nok qw( baserel u4 + dev/u4/foo ); +nok qw( baserel u4 + refs/tags/dev/u4/foo ); +nok qw( baserel u4 + dev/alice/foo ); +nok qw( baserel u4 + refs/tags/dev/alice/foo ); +nok qw( baserel u4 C master ); +nok qw( baserel u4 C notmaster ); +nok qw( baserel u4 C refs/tags/boo ); +nok qw( baserel u4 C refs/tags/v1 ); +nok qw( baserel u4 C dev/u4/foo ); +nok qw( baserel u4 C refs/tags/dev/u4/foo ); +nok qw( baserel u4 C dev/alice/foo ); +nok qw( baserel u4 C refs/tags/dev/alice/foo ); +nok qw( baserel u4 D master ); +nok qw( baserel u4 D notmaster ); +nok qw( baserel u4 D refs/tags/boo ); +nok qw( baserel u4 D refs/tags/v1 ); +nok qw( baserel u4 D dev/u4/foo ); +nok qw( baserel u4 D refs/tags/dev/u4/foo ); +nok qw( baserel u4 D dev/alice/foo ); +nok qw( baserel u4 D refs/tags/dev/alice/foo ); + +ok qw( baserel u5 R ); +nok qw( baserel u5 W master ); +nok qw( baserel u5 W notmaster ); +nok qw( baserel u5 W refs/tags/boo ); +nok qw( baserel u5 W refs/tags/v1 ); +nok qw( baserel u5 W dev/u5/foo ); +nok qw( baserel u5 W refs/tags/dev/u5/foo ); +nok qw( baserel u5 W dev/alice/foo ); +nok qw( baserel u5 W refs/tags/dev/alice/foo ); +nok qw( baserel u5 + master ); +nok qw( baserel u5 + notmaster ); +nok qw( baserel u5 + refs/tags/boo ); +nok qw( baserel u5 + refs/tags/v1 ); +nok qw( baserel u5 + dev/u5/foo ); +nok qw( baserel u5 + refs/tags/dev/u5/foo ); +nok qw( baserel u5 + dev/alice/foo ); +nok qw( baserel u5 + refs/tags/dev/alice/foo ); +nok qw( baserel u5 C master ); +nok qw( baserel u5 C notmaster ); +nok qw( baserel u5 C refs/tags/boo ); +nok qw( baserel u5 C refs/tags/v1 ); +nok qw( baserel u5 C dev/u5/foo ); +nok qw( baserel u5 C refs/tags/dev/u5/foo ); +nok qw( baserel u5 C dev/alice/foo ); +nok qw( baserel u5 C refs/tags/dev/alice/foo ); +nok qw( baserel u5 D master ); +nok qw( baserel u5 D notmaster ); +nok qw( baserel u5 D refs/tags/boo ); +nok qw( baserel u5 D refs/tags/v1 ); +nok qw( baserel u5 D dev/u5/foo ); +nok qw( baserel u5 D refs/tags/dev/u5/foo ); +nok qw( baserel u5 D dev/alice/foo ); +nok qw( baserel u5 D refs/tags/dev/alice/foo ); + +nok qw( baserel u6 R ); +nok qw( baserel u6 W master ); +nok qw( baserel u6 W notmaster ); +nok qw( baserel u6 W refs/tags/boo ); +nok qw( baserel u6 W refs/tags/v1 ); +nok qw( baserel u6 W dev/u6/foo ); +nok qw( baserel u6 W refs/tags/dev/u6/foo ); +nok qw( baserel u6 W dev/alice/foo ); +nok qw( baserel u6 W refs/tags/dev/alice/foo ); +nok qw( baserel u6 + master ); +nok qw( baserel u6 + notmaster ); +nok qw( baserel u6 + refs/tags/boo ); +nok qw( baserel u6 + refs/tags/v1 ); +nok qw( baserel u6 + dev/u6/foo ); +nok qw( baserel u6 + refs/tags/dev/u6/foo ); +nok qw( baserel u6 + dev/alice/foo ); +nok qw( baserel u6 + refs/tags/dev/alice/foo ); +nok qw( baserel u6 C master ); +nok qw( baserel u6 C notmaster ); +nok qw( baserel u6 C refs/tags/boo ); +nok qw( baserel u6 C refs/tags/v1 ); +nok qw( baserel u6 C dev/u6/foo ); +nok qw( baserel u6 C refs/tags/dev/u6/foo ); +nok qw( baserel u6 C dev/alice/foo ); +nok qw( baserel u6 C refs/tags/dev/alice/foo ); +nok qw( baserel u6 D master ); +nok qw( baserel u6 D notmaster ); +nok qw( baserel u6 D refs/tags/boo ); +nok qw( baserel u6 D refs/tags/v1 ); +nok qw( baserel u6 D dev/u6/foo ); +nok qw( baserel u6 D refs/tags/dev/u6/foo ); +nok qw( baserel u6 D dev/alice/foo ); +nok qw( baserel u6 D refs/tags/dev/alice/foo ); + +ok qw( baseall admin R ); +ok qw( baseall admin W master ); +ok qw( baseall admin W notmaster ); +ok qw( baseall admin W refs/tags/boo ); +ok qw( baseall admin W refs/tags/v1 ); +ok qw( baseall admin W dev/admin/foo ); +ok qw( baseall admin W refs/tags/dev/admin/foo ); +ok qw( baseall admin W dev/alice/foo ); +ok qw( baseall admin W refs/tags/dev/alice/foo ); +ok qw( baseall admin + master ); +ok qw( baseall admin + notmaster ); +ok qw( baseall admin + refs/tags/boo ); +ok qw( baseall admin + refs/tags/v1 ); +ok qw( baseall admin + dev/admin/foo ); +ok qw( baseall admin + refs/tags/dev/admin/foo ); +ok qw( baseall admin + dev/alice/foo ); +ok qw( baseall admin + refs/tags/dev/alice/foo ); +ok qw( baseall admin C master ); +ok qw( baseall admin C notmaster ); +ok qw( baseall admin C refs/tags/boo ); +ok qw( baseall admin C refs/tags/v1 ); +ok qw( baseall admin C dev/admin/foo ); +ok qw( baseall admin C refs/tags/dev/admin/foo ); +ok qw( baseall admin C dev/alice/foo ); +ok qw( baseall admin C refs/tags/dev/alice/foo ); +ok qw( baseall admin D master ); +ok qw( baseall admin D notmaster ); +ok qw( baseall admin D refs/tags/boo ); +ok qw( baseall admin D refs/tags/v1 ); +ok qw( baseall admin D dev/admin/foo ); +ok qw( baseall admin D refs/tags/dev/admin/foo ); +ok qw( baseall admin D dev/alice/foo ); +ok qw( baseall admin D refs/tags/dev/alice/foo ); + +ok qw( baseall u1 R ); +ok qw( baseall u1 W master ); +ok qw( baseall u1 W notmaster ); +ok qw( baseall u1 W refs/tags/boo ); +nok qw( baseall u1 W refs/tags/v1 ); +ok qw( baseall u1 W dev/u1/foo ); +ok qw( baseall u1 W refs/tags/dev/u1/foo ); +nok qw( baseall u1 W dev/alice/foo ); +nok qw( baseall u1 W refs/tags/dev/alice/foo ); +ok qw( baseall u1 + master ); +ok qw( baseall u1 + notmaster ); +ok qw( baseall u1 + refs/tags/boo ); +nok qw( baseall u1 + refs/tags/v1 ); +ok qw( baseall u1 + dev/u1/foo ); +ok qw( baseall u1 + refs/tags/dev/u1/foo ); +nok qw( baseall u1 + dev/alice/foo ); +nok qw( baseall u1 + refs/tags/dev/alice/foo ); +ok qw( baseall u1 C master ); +ok qw( baseall u1 C notmaster ); +ok qw( baseall u1 C refs/tags/boo ); +nok qw( baseall u1 C refs/tags/v1 ); +ok qw( baseall u1 C dev/u1/foo ); +ok qw( baseall u1 C refs/tags/dev/u1/foo ); +nok qw( baseall u1 C dev/alice/foo ); +nok qw( baseall u1 C refs/tags/dev/alice/foo ); +ok qw( baseall u1 D master ); +ok qw( baseall u1 D notmaster ); +ok qw( baseall u1 D refs/tags/boo ); +nok qw( baseall u1 D refs/tags/v1 ); +ok qw( baseall u1 D dev/u1/foo ); +ok qw( baseall u1 D refs/tags/dev/u1/foo ); +nok qw( baseall u1 D dev/alice/foo ); +nok qw( baseall u1 D refs/tags/dev/alice/foo ); + +ok qw( baseall u2 R ); +ok qw( baseall u2 W master ); +ok qw( baseall u2 W notmaster ); +ok qw( baseall u2 W refs/tags/boo ); +nok qw( baseall u2 W refs/tags/v1 ); +ok qw( baseall u2 W dev/u2/foo ); +ok qw( baseall u2 W refs/tags/dev/u2/foo ); +nok qw( baseall u2 W dev/alice/foo ); +nok qw( baseall u2 W refs/tags/dev/alice/foo ); +nok qw( baseall u2 + master ); +nok qw( baseall u2 + notmaster ); +nok qw( baseall u2 + refs/tags/boo ); +nok qw( baseall u2 + refs/tags/v1 ); +ok qw( baseall u2 + dev/u2/foo ); +ok qw( baseall u2 + refs/tags/dev/u2/foo ); +nok qw( baseall u2 + dev/alice/foo ); +nok qw( baseall u2 + refs/tags/dev/alice/foo ); +ok qw( baseall u2 C master ); +ok qw( baseall u2 C notmaster ); +ok qw( baseall u2 C refs/tags/boo ); +nok qw( baseall u2 C refs/tags/v1 ); +ok qw( baseall u2 C dev/u2/foo ); +ok qw( baseall u2 C refs/tags/dev/u2/foo ); +nok qw( baseall u2 C dev/alice/foo ); +nok qw( baseall u2 C refs/tags/dev/alice/foo ); +nok qw( baseall u2 D master ); +nok qw( baseall u2 D notmaster ); +nok qw( baseall u2 D refs/tags/boo ); +nok qw( baseall u2 D refs/tags/v1 ); +ok qw( baseall u2 D dev/u2/foo ); +ok qw( baseall u2 D refs/tags/dev/u2/foo ); +nok qw( baseall u2 D dev/alice/foo ); +nok qw( baseall u2 D refs/tags/dev/alice/foo ); + +ok qw( baseall u3 R ); +nok qw( baseall u3 W master ); +ok qw( baseall u3 W notmaster ); +ok qw( baseall u3 W refs/tags/boo ); +nok qw( baseall u3 W refs/tags/v1 ); +ok qw( baseall u3 W dev/u3/foo ); +ok qw( baseall u3 W refs/tags/dev/u3/foo ); +nok qw( baseall u3 W dev/alice/foo ); +nok qw( baseall u3 W refs/tags/dev/alice/foo ); +nok qw( baseall u3 + master ); +nok qw( baseall u3 + notmaster ); +nok qw( baseall u3 + refs/tags/boo ); +nok qw( baseall u3 + refs/tags/v1 ); +ok qw( baseall u3 + dev/u3/foo ); +ok qw( baseall u3 + refs/tags/dev/u3/foo ); +nok qw( baseall u3 + dev/alice/foo ); +nok qw( baseall u3 + refs/tags/dev/alice/foo ); +nok qw( baseall u3 C master ); +ok qw( baseall u3 C notmaster ); +ok qw( baseall u3 C refs/tags/boo ); +nok qw( baseall u3 C refs/tags/v1 ); +ok qw( baseall u3 C dev/u3/foo ); +ok qw( baseall u3 C refs/tags/dev/u3/foo ); +nok qw( baseall u3 C dev/alice/foo ); +nok qw( baseall u3 C refs/tags/dev/alice/foo ); +nok qw( baseall u3 D master ); +nok qw( baseall u3 D notmaster ); +nok qw( baseall u3 D refs/tags/boo ); +nok qw( baseall u3 D refs/tags/v1 ); +ok qw( baseall u3 D dev/u3/foo ); +ok qw( baseall u3 D refs/tags/dev/u3/foo ); +nok qw( baseall u3 D dev/alice/foo ); +nok qw( baseall u3 D refs/tags/dev/alice/foo ); + +ok qw( baseall u4 R ); +nok qw( baseall u4 W master ); +nok qw( baseall u4 W notmaster ); +nok qw( baseall u4 W refs/tags/boo ); +nok qw( baseall u4 W refs/tags/v1 ); +nok qw( baseall u4 W dev/u4/foo ); +nok qw( baseall u4 W refs/tags/dev/u4/foo ); +nok qw( baseall u4 W dev/alice/foo ); +nok qw( baseall u4 W refs/tags/dev/alice/foo ); +nok qw( baseall u4 + master ); +nok qw( baseall u4 + notmaster ); +nok qw( baseall u4 + refs/tags/boo ); +nok qw( baseall u4 + refs/tags/v1 ); +nok qw( baseall u4 + dev/u4/foo ); +nok qw( baseall u4 + refs/tags/dev/u4/foo ); +nok qw( baseall u4 + dev/alice/foo ); +nok qw( baseall u4 + refs/tags/dev/alice/foo ); +nok qw( baseall u4 C master ); +nok qw( baseall u4 C notmaster ); +nok qw( baseall u4 C refs/tags/boo ); +nok qw( baseall u4 C refs/tags/v1 ); +nok qw( baseall u4 C dev/u4/foo ); +nok qw( baseall u4 C refs/tags/dev/u4/foo ); +nok qw( baseall u4 C dev/alice/foo ); +nok qw( baseall u4 C refs/tags/dev/alice/foo ); +nok qw( baseall u4 D master ); +nok qw( baseall u4 D notmaster ); +nok qw( baseall u4 D refs/tags/boo ); +nok qw( baseall u4 D refs/tags/v1 ); +nok qw( baseall u4 D dev/u4/foo ); +nok qw( baseall u4 D refs/tags/dev/u4/foo ); +nok qw( baseall u4 D dev/alice/foo ); +nok qw( baseall u4 D refs/tags/dev/alice/foo ); + +ok qw( baseall u5 R ); +nok qw( baseall u5 W master ); +nok qw( baseall u5 W notmaster ); +nok qw( baseall u5 W refs/tags/boo ); +nok qw( baseall u5 W refs/tags/v1 ); +ok qw( baseall u5 W dev/u5/foo ); +ok qw( baseall u5 W refs/tags/dev/u5/foo ); +nok qw( baseall u5 W dev/alice/foo ); +nok qw( baseall u5 W refs/tags/dev/alice/foo ); +nok qw( baseall u5 + master ); +nok qw( baseall u5 + notmaster ); +nok qw( baseall u5 + refs/tags/boo ); +nok qw( baseall u5 + refs/tags/v1 ); +ok qw( baseall u5 + dev/u5/foo ); +ok qw( baseall u5 + refs/tags/dev/u5/foo ); +nok qw( baseall u5 + dev/alice/foo ); +nok qw( baseall u5 + refs/tags/dev/alice/foo ); +nok qw( baseall u5 C master ); +nok qw( baseall u5 C notmaster ); +nok qw( baseall u5 C refs/tags/boo ); +nok qw( baseall u5 C refs/tags/v1 ); +ok qw( baseall u5 C dev/u5/foo ); +ok qw( baseall u5 C refs/tags/dev/u5/foo ); +nok qw( baseall u5 C dev/alice/foo ); +nok qw( baseall u5 C refs/tags/dev/alice/foo ); +nok qw( baseall u5 D master ); +nok qw( baseall u5 D notmaster ); +nok qw( baseall u5 D refs/tags/boo ); +nok qw( baseall u5 D refs/tags/v1 ); +ok qw( baseall u5 D dev/u5/foo ); +ok qw( baseall u5 D refs/tags/dev/u5/foo ); +nok qw( baseall u5 D dev/alice/foo ); +nok qw( baseall u5 D refs/tags/dev/alice/foo ); + +ok qw( baseall u6 R ); +nok qw( baseall u6 W master ); +nok qw( baseall u6 W notmaster ); +nok qw( baseall u6 W refs/tags/boo ); +nok qw( baseall u6 W refs/tags/v1 ); +ok qw( baseall u6 W dev/u6/foo ); +ok qw( baseall u6 W refs/tags/dev/u6/foo ); +nok qw( baseall u6 W dev/alice/foo ); +nok qw( baseall u6 W refs/tags/dev/alice/foo ); +nok qw( baseall u6 + master ); +nok qw( baseall u6 + notmaster ); +nok qw( baseall u6 + refs/tags/boo ); +nok qw( baseall u6 + refs/tags/v1 ); +ok qw( baseall u6 + dev/u6/foo ); +ok qw( baseall u6 + refs/tags/dev/u6/foo ); +nok qw( baseall u6 + dev/alice/foo ); +nok qw( baseall u6 + refs/tags/dev/alice/foo ); +nok qw( baseall u6 C master ); +nok qw( baseall u6 C notmaster ); +nok qw( baseall u6 C refs/tags/boo ); +nok qw( baseall u6 C refs/tags/v1 ); +ok qw( baseall u6 C dev/u6/foo ); +ok qw( baseall u6 C refs/tags/dev/u6/foo ); +nok qw( baseall u6 C dev/alice/foo ); +nok qw( baseall u6 C refs/tags/dev/alice/foo ); +nok qw( baseall u6 D master ); +nok qw( baseall u6 D notmaster ); +nok qw( baseall u6 D refs/tags/boo ); +nok qw( baseall u6 D refs/tags/v1 ); +ok qw( baseall u6 D dev/u6/foo ); +ok qw( baseall u6 D refs/tags/dev/u6/foo ); +nok qw( baseall u6 D dev/alice/foo ); +nok qw( baseall u6 D refs/tags/dev/alice/foo ); + diff --git a/t/vrefs-1.t b/t/vrefs-1.t new file mode 100755 index 0000000..eea4b24 --- /dev/null +++ b/t/vrefs-1.t @@ -0,0 +1,138 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# VREFs - part 1 +# ---------------------------------------------------------------------- + +try "plan 88"; + +put "conf/gitolite.conf", " + repo gitolite-admin + RW+ = admin + + \@gfoo = foo + \@lead = u1 + \@dev2 = u2 + \@dev4 = u4 + \@devs = \@dev2 \@dev4 u6 + repo \@gfoo + RW+ = \@lead \@devs + # intentional mis-spelling + - VREF/MISCOUNT/2 = \@dev2 + - VREF/MISCOUNT/4 = \@dev4 + - VREF/MISCOUNT/3/NEWFILES = u6 + - VREF/MISCOUNT/6 = u6 +"; + +try " + ADMIN_PUSH vr1a + cd .. + [ -d foo ]; !ok + CLONE u1 foo; ok; /Cloning into/ + /You appear to have cloned an empty/ + cd foo; ok + [ -d .git ]; ok + + # VREF not called for u1 + tc a1 a2 a3 a4 a5; ok; /aaf9e8e/ + PUSH u1 master; ok; /new branch.*master -. master/ + !/helper program missing/ + !/hook declined/ + !/remote rejected/ + # VREF is called for u2 + tc b1; ok; /1f440d3/ + PUSH u2; !ok; /helper program missing/ + /hook declined/ + /remote rejected/ +"; + +put "../gitolite-admin/conf/gitolite.conf", " + repo gitolite-admin + RW+ = admin + + \@gfoo = foo + \@lead = u1 + \@dev2 = u2 + \@dev4 = u4 + \@devs = \@dev2 \@dev4 u6 + repo \@gfoo + RW+ = \@lead \@devs + - VREF/COUNT/2 = \@dev2 + - VREF/COUNT/4 = \@dev4 + - VREF/COUNT/3/NEWFILES = u6 + - VREF/COUNT/6 = u6 +"; + +try " + ADMIN_PUSH vr1b + cd ../foo; ok + + # u2 1 file + PUSH u2; ok; /aaf9e8e..1f440d3.*master -. master/ + + # u2 2 files + tc b2 b3; ok; /c3397f7/ + PUSH u2; ok; /1f440d3..c3397f7.*master -. master/ + + # u2 3 files + tc c1 c2 c3; ok; /be242d7/ + PUSH u2; !ok; /W VREF/COUNT/2 foo u2 DENIED by VREF/COUNT/2/ + /too many changed files in this push/ + /hook declined/ + /remote rejected/ + + # u4 3 files + PUSH u4; ok; /c3397f7..be242d7.*master -. master/ + + # u4 4 files + tc d1 d2 d3 d4; ok; /88d80e2/ + PUSH u4; ok; /be242d7..88d80e2.*master -. master/ + + # u4 5 files + tc d5 d6 d7 d8 d9; ok; /e9c60b0/ + PUSH u4; !ok; /W VREF/COUNT/4 foo u4 DENIED by VREF/COUNT/4/ + /too many changed files in this push/ + /hook declined/ + /remote rejected/ + + # u1 all files + PUSH u1; ok; /88d80e2..e9c60b0.*master -. master/ + + # u6 6 old files + test-tick + tc d1 d2 d3 d4 d5 d6 + ok; /2773f0a/ + PUSH u6; ok; /e9c60b0..2773f0a.*master -. master/ + tag six + + # u6 updates 7 old files + test-tick; test-tick + tc d1 d2 d3 d4 d5 d6 d7 + ok; /d3fb574/ + PUSH u6; !ok; /W VREF/COUNT/6 foo u6 DENIED by VREF/COUNT/6/ + /too many changed files in this push/ + /hook declined/ + /remote rejected/ + reset-h six; ok; /HEAD is now at 2773f0a/ + + # u6 4 new 2 old files + test-tick; test-tick + tc d1 d2 n1 n2 n3 n4 + ok; /9e90848/ + PUSH u6; !ok; /W VREF/COUNT/3/NEWFILES foo u6 DENIED by VREF/COUNT/3/NEWFILES/ + /too many new files in this push/ + /hook declined/ + /remote rejected/ + reset-h six; ok; /HEAD is now at 2773f0a/ + + # u6 3 new 3 old files + test-tick; test-tick + tc d1 d2 d3 n1 n2 n3 + ok; /e47ff5d/ + PUSH u6; ok; /2773f0a..e47ff5d.*master -. master/ +"; diff --git a/t/vrefs-2.t b/t/vrefs-2.t new file mode 100755 index 0000000..40db308 --- /dev/null +++ b/t/vrefs-2.t @@ -0,0 +1,109 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# VREFs - part 2 +# ---------------------------------------------------------------------- + +try "plan 72"; + +put "../gitolite-admin/conf/gitolite.conf", " + \@gfoo = foo + \@lead = u1 + \@senior_devs = u2 u3 + \@junior_devs = u4 u5 u6 + repo \@gfoo + + RW+ = \@all + + RW+ VREF/COUNT/2/NO_SIGNOFF = \@lead + - VREF/COUNT/2/NO_SIGNOFF = \@all + + - VREF/COUNT/10/NEWFILES = \@junior_devs + + - VREF/FILETYPE/AUTOGENERATED = \@all +"; + +try " + ADMIN_PUSH vr2a + cd .. + # setup + [ -d foo ]; !ok + CLONE u1 foo; ok; /Cloning into/ + /You appear to have cloned an empty/ + cd foo; ok + [ -d .git ]; ok + + # u1 push 15 new files + tc a b c d e f g h i j k l m n o + ok; /d8c0392/ + PUSH u1 master; ok; /new branch.*master -. master/ + + # u2 push 2 new 10 old without signoff + tc a b c d e f g h i j u2a u2b + ok; /6787ac9/ + PUSH u2; ok; /d8c0392..6787ac9.*master -. master/ + + # u2 fail to push 3 new files without signoff + tc u2c u2d u2e; ok; /a74562b/ + PUSH u2; !ok; /W VREF/COUNT/2/NO_SIGNOFF foo u2 DENIED by VREF/COUNT/2/NO_SIGNOFF/ + /top commit message should include the text .3 new files signed-off by: tester.example.com./ + /hook declined/ + /remote rejected/ + # u2 push 15 new files with signoff + tc u2f u2g u2h u2i u2j u2k u2l u2m u2n u2o u2p u2q + ok; /8dd31aa/ + git commit --allow-empty -m '15 new files signed-off by: tester\@example.com' + ok; /.master 6126489. 15 new files signed-off by: tester.example.com/ + PUSH u2; ok; /6787ac9..6126489.*master -. master/ + + # u4 push 2 new 10 old files without signoff + tc u4a u4b a b c d e f g h i j + ok; /76c5593/ + PUSH u4; ok; /6126489..76c5593.*master -. master/ + + # u4 fail push 3 new files withoug signoff + tc u4c u4d u4e; ok; /2a84398/ + PUSH u4; !ok; /W VREF/COUNT/2/NO_SIGNOFF foo u4 DENIED by VREF/COUNT/2/NO_SIGNOFF/ + /top commit message should include the text .3 new files signed-off by: tester.example.com./ + /hook declined/ + /remote rejected/ + + # u4 push 10 new 5 old with signoff + tc u4f u4g u4h u4i u4j u4k u4l a b c d e + ok; /09b646a/ + git commit --allow-empty -m '10 new files signed-off by: tester\@example.com' + ok; /.master 47f84b0. 10 new files signed-off by: tester.example.com/ + PUSH u4; ok; /76c5593..47f84b0.*master -. master/ + + # u4 fail push 11 new files even with signoff + tc u4ab u4ac u4ad u4ae u4af u4ag u4ah u4ai u4aj u4ak u4al + ok; /90e7344/ + git commit --allow-empty -m '11 new files signed-off by: tester\@example.com' + ok; /.master 1f36537. 11 new files signed-off by: tester.example.com/ + PUSH u4; !ok; /W VREF/COUNT/10/NEWFILES foo u4 DENIED by VREF/COUNT/10/NEWFILES/ + /too many new files in this push/ + /hook declined/ + /remote rejected/ + + # test AUTOGENERATED vref + glt fetch u1 origin; ok; + reset-h origin/master; ok; + tc not-really.java; ok; /0f88b2e/ + PUSH u4; ok; /47f84b0..0f88b2e.*master -. master/ +"; + +put "|cat >> not-really.java", " + Generated by the protocol buffer compiler. DO NOT EDIT +"; + +try " + commit -am pbc; ok; /b2df6ef/ + PUSH u4; !ok; /W VREF/FILETYPE/AUTOGENERATED foo u4 DENIED by VREF/FILETYPE/AUTOGENERATED/ + /hook declined/ + /remote rejected/ +"; diff --git a/t/wild-1.t b/t/wild-1.t new file mode 100755 index 0000000..7a8f766 --- /dev/null +++ b/t/wild-1.t @@ -0,0 +1,126 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# wild repos - part 1 +# ---------------------------------------------------------------------- + +try "plan 66"; + +confreset;confadd ' + @prof = u1 + @TAs = u2 u3 + @students = u4 u5 u6 + + @gfoo = foo/CREATOR/a[0-9][0-9] + repo @gfoo + C = @all + RW+ = CREATOR + RW = WRITERS @TAs + R = READERS @prof +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " +# reasonably complex setup; we'll do everything from one repo though +cd .. + +# u1 create success +glt clone u1 file:///foo/u1/a01; ok; /Initialized empty Git repository in .*/foo/u1/a01.git// + +# u2 create success +glt clone u2 file:///foo/u2/a02; ok; /Initialized empty Git repository in .*/foo/u2/a02.git// + +# u4 tries to create u2 repo +glt clone u4 file:///foo/u2/a12; !ok; /R any foo/u2/a12 u4 DENIED by fallthru/ + +# line anchored regexes +glt clone u4 file:///foo/u4/a1234; !ok; /R any foo/u4/a1234 u4 DENIED by fallthru/ + +# u4 tries to create his own repo +glt clone u4 file:///foo/u4/a12; ok; /Initialized empty Git repository in .*/foo/u4/a12.git// + /warning: You appear to have cloned an empty repository./ + +# u4 push success +cd a12 +tc p-728 p-729 p-730 p-731; ok +glt push u4 origin master; ok; /To file:///foo/u4/a12/ + /\\* \\[new branch\\] master -> master/ + +# u1 clone success +cd .. +glt clone u1 file:///foo/u4/a12 u1a12; ok; /Cloning into 'u1a12'.../ + +# u1 push fail +cd u1a12 +tc m-778 m-779; ok; +glt push u1 origin; !ok; /W any foo/u4/a12 u1 DENIED by fallthru/ + +# u2 clone success +cd .. +glt clone u2 file:///foo/u4/a12 u2a12; ok; /Cloning into 'u2a12'.../ + +# u2 push success +cd u2a12 +tc s-708 s-709; ok; +glt push u2 origin; ok; /To file:///foo/u4/a12/ + /master -> master/ + +# u2 rewind fail +glt push u2 -f origin master^:master; !ok; /\\+ refs/heads/master foo/u4/a12 u2 DENIED by fallthru/ + reject + +# u4 pull to sync up +cd ../a12 +glt pull u4; ok; /Fast-forward/ + /From file:///foo/u4/a12/ + /master -> origin/master/ + +# u4 rewind success +git reset --hard HEAD^; ok +glt push u4 -f; ok; /To file:///foo/u4/a12/ + /\\+ .* master -> master \\(forced update\\)/ + +# u5 clone fail +cd .. +glt clone u5 file:///foo/u4/a12 u5a12; !ok; /R any foo/u4/a12 u5 DENIED by fallthru/ + +glt perms u4 foo/u4/a12 + READERS u5 +glt perms u4 foo/u4/a12 + WRITERS u6 + +glt perms u4 foo/u4/a12 -l +"; + +cmp 'READERS u5 +WRITERS u6 +'; + +try " +# u5 clone success +glt clone u5 file:///foo/u4/a12 u5a12; ok; /Cloning into 'u5a12'.../ + +# u5 push fail +cd u5a12 +tc y-743 y-744; ok +glt push u5; !ok; /W any foo/u4/a12 u5 DENIED by fallthru/ + +# u6 clone success +cd .. +glt clone u6 file:///foo/u4/a12 u6a12; ok; /Cloning into 'u6a12'.../ + +# u6 push success +cd u6a12 +tc k-68 k-69; ok +glt push u6 file:///foo/u4/a12; ok; /To file:///foo/u4/a12/ + /master -> master/ + +# u6 rewind fail +glt push u6 -f file:///foo/u4/a12 master^:master + !ok; /\\+ refs/heads/master foo/u4/a12 u6 DENIED by fallthru/ + reject +"; diff --git a/t/wild-2.t b/t/wild-2.t new file mode 100755 index 0000000..cbba4f8 --- /dev/null +++ b/t/wild-2.t @@ -0,0 +1,128 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# wild repos - part 2 +# ---------------------------------------------------------------------- + +try "plan 65"; + +confreset;confadd ' + @prof = u1 + @TAs = u2 u3 + @students = u4 u5 u6 + + @gfoo = foo/CREATOR/a[0-9][0-9] + repo @gfoo + C = @students + RW+ = CREATOR + RW = WRITERS @TAs + R = READERS @prof +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " +cd .. + +# u1 create fail +glt clone u1 file:///foo/u1/a01; !ok; /R any foo/u1/a01 u1 DENIED by fallthru/ + +# u2 create fail +glt clone u2 file:///foo/u2/a02; !ok; /R any foo/u2/a02 u2 DENIED by fallthru/ + +# u4 tries to create u2 repo +glt clone u4 file:///foo/u2/a12; !ok; /R any foo/u2/a12 u4 DENIED by fallthru/ + +# line anchored regexes +glt clone u4 file:///foo/u4/a1234; !ok; /R any foo/u4/a1234 u4 DENIED by fallthru/ + +# u4 tries to create his own repo +glt clone u4 file:///foo/u4/a12; ok; /Initialized empty Git repository in .*/foo/u4/a12.git// + /warning: You appear to have cloned an empty repository./ + +# u4 push success +cd a12 +tc n-770 n-771 n-772 n-773; ok +glt push u4 origin master; ok; /To file:///foo/u4/a12/ + /\\* \\[new branch\\] master -> master/ + +# u1 clone success +cd .. +glt clone u1 file:///foo/u4/a12 u1a12; ok; /Cloning into 'u1a12'.../ + +# u1 push fail +cd u1a12 +tc c-442 c-443; ok +glt push u1; !ok; /W any foo/u4/a12 u1 DENIED by fallthru/ + +# u2 clone success +cd .. +glt clone u2 file:///foo/u4/a12 u2a12; ok; /Cloning into 'u2a12'.../ + +# u2 push success +cd u2a12 +tc e-393 e-394; ok; +glt push u2; ok; /To file:///foo/u4/a12/ + /master -> master/ + +# u2 rewind fail +glt push u2 -f origin master^:master; !ok; /\\+ refs/heads/master foo/u4/a12 u2 DENIED by fallthru/ + reject + +# u4 pull to sync up +cd ../a12 +glt pull u4; ok; /Fast-forward/ + /From file:///foo/u4/a12/ + /master -> origin/master/ + +# u4 rewind success +git reset --hard HEAD^; ok +glt push u4 -f; ok; /To file:///foo/u4/a12/ + /\\+ .* master -> master \\(forced update\\)/ + +# u5 clone fail +cd .. +glt clone u5 file:///foo/u4/a12 u5a12; !ok; /R any foo/u4/a12 u5 DENIED by fallthru/ + +# setperm +glt perms u4 foo/u4/a12 + READERS u5 +glt perms u4 foo/u4/a12 + WRITERS u6 + +# getperms +glt perms u4 foo/u4/a12 -l +"; + +cmp 'READERS u5 +WRITERS u6 +'; + +try " +# u5 clone success +glt clone u5 file:///foo/u4/a12 u5a12; ok; /Cloning into 'u5a12'.../ + +# u5 push fail +cd u5a12 +tc g-809 g-810; ok +glt push u5; !ok; /W any foo/u4/a12 u5 DENIED by fallthru/ + +# u6 clone success +cd .. +glt clone u6 file:///foo/u4/a12 u6a12; ok; /Cloning into 'u6a12'.../ + +# u6 push success +cd u6a12 +tc f-912 f-913 +glt push u6 file:///foo/u4/a12; ok; /To file:///foo/u4/a12/ + /master -> master/ + +# u6 rewind fail +glt push u6 -f file:///foo/u4/a12 master^:master + !ok; /\\+ refs/heads/master foo/u4/a12 u6 DENIED by fallthru/ + reject + +"; diff --git a/t/writable.t b/t/writable.t new file mode 100755 index 0000000..a649323 --- /dev/null +++ b/t/writable.t @@ -0,0 +1,124 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; +use Cwd; +my $workdir = getcwd(); + +# 'gitolite writable' command +# ---------------------------------------------------------------------- + +my $sf = ".gitolite.down"; + +try "plan 66"; +try "DEF POK = !/DENIED/; !/failed to push/"; + +# delete the down file +unlink "$ENV{HOME}/$sf"; + +# add foo, bar/..* repos to the config and push +confreset;confadd ' + repo foo + RW = u1 + R = u2 + + repo bar/..* + C = u2 u4 u6 + RW = CREATOR u3 +'; + +try "ADMIN_PUSH set1; !/FATAL/" or die text(); + +try " + # clone and push to foo + CLONE u1 foo; ok + cd foo; ok + tc f1; ok + PUSH u1 master; ok; /new branch/ + + # auto-clone and push to bar/u2 + cd .. + CLONE u2 bar/u2; ok; /appear to have cloned an empty/ + /Initialized empty/ + cd u2; + tc f2 + PUSH u2 master; ok; + + # disable site with some message + gitolite writable \@all off testing site-wide disable; ok + + # try push foo and see fail + message + cd ../foo; ok + tc f3; ok + PUSH u1; !ok; /testing site-wide disable/ + # try push bar/u2 and ... + cd ../u2; ok + tc f4; ok + PUSH u2; !ok; /testing site-wide disable/ + + # try auto-create push bar/u4 and this works!! + cd .. + CLONE u4 bar/u4; ok; /appear to have cloned an empty/ + /Initialized empty/ + !/testing site-wide disable/ + cd u4; ok + + # enable site + gitolite writable \@all on; ok + + # try same 3 again + + # try push foo and see fail + message + cd ../foo; ok + tc g3; ok + PUSH u1; ok; /master -> master/ + # try push bar/u2 and ... + cd ../u2; ok + tc g4; ok + PUSH u2; ok; /master -> master/ + + # try auto-create push bar/u4 and this works!! + cd .. + CLONE u6 bar/u6; ok; /appear to have cloned an empty/ + /Initialized empty/ + !/testing site-wide disable/ + cd u6; ok + + # disable just foo + gitolite writable foo off foo down + + # try push foo and see the message + cd ../foo; ok + tc g3; ok + PUSH u1; !ok; /foo down/ + !/testing site-wide disable/ + # push bar/u2 ok + cd ../u2 + tc g4 + PUSH u2; ok; /master -> master/ + + # enable foo, disable bar/u2 + gitolite writable foo on + gitolite writable bar/u2 off the bar is closed + + # try both + cd ../foo; ok + tc h3; ok + PUSH u1; ok; /master -> master/ + # push bar/u2 ok + cd ../u2 + tc h4 + PUSH u2; !ok; /the bar is closed/ + + ssh u3 writable bar/u2 on; !ok; /you are not authorized/ + ssh u3 writable \@all on; !ok; /you are not authorized/ + + ssh u2 writable bar/u2 on; ok + ssh u2 writable \@all on; !ok; /you are not authorized/ + + ssh admin writable \@all on; + ok +"; diff --git a/t/z-end.t b/t/z-end.t new file mode 100755 index 0000000..6c98fe4 --- /dev/null +++ b/t/z-end.t @@ -0,0 +1,14 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +try "plan 1; cd $ENV{PWD}; git status -s -uno; !/./ or die" or die "dirty tree"; +try "git log -1 --format='%h %ai %s'"; +put "|cat >> prove.log", text(); + + + |