diff --git a/conf/example.gitolite.rc b/conf/example.gitolite.rc index 0c23364..9e3b39d 100644 --- a/conf/example.gitolite.rc +++ b/conf/example.gitolite.rc @@ -28,6 +28,7 @@ $GL_CONF_COMPILED="$GL_ADMINDIR/conf/gitolite.conf-compiled.pm"; $GL_WILDREPOS = 0; $PROJECTS_LIST = $ENV{HOME} . "/projects.list"; # $WEB_INTERFACE = "gitweb"; +# $GITWEB_URI_ESCAPE = 0; $REPO_UMASK = 0077; # ------------------------------------------------------------------------------ diff --git a/doc/gitolite.rc.mkd b/doc/gitolite.rc.mkd index de6b96f..36a8479 100644 --- a/doc/gitolite.rc.mkd +++ b/doc/gitolite.rc.mkd @@ -46,6 +46,12 @@ things happen if you change them. `$projects_list` (please see gitweb docs for more on this). Set this to the same value as that one. + * `$GITWEB_URI_ESCAPE`, boolean, default undef + + Apparently gitweb expects project names to be URI-escaped (but seems to + work fine even if you don't). If you need strict compatibility with + gitweb, add/uncomment this variable and set it to 1. + * `$REPO_UMASK`, octal, default `0077` The default UMASK that gitolite uses makes all the repos and their diff --git a/src/gitolite.pm b/src/gitolite.pm index 0f520f1..9bca279 100644 --- a/src/gitolite.pm +++ b/src/gitolite.pm @@ -48,6 +48,8 @@ use Data::Dumper; $Data::Dumper::Deepcopy = 1; $|++; +use CGI::Util qw(escape); + # ---------------------------------------------------------------------------- # find the rc file, then pull the libraries # ---------------------------------------------------------------------------- @@ -123,20 +125,23 @@ sub slurp { } sub add_del_line { - my ($line, $file, $flag) = @_; + my ($line, $file, $op, $escape) = @_; + # $op is true for add operation, false for delete + # $escape is true if the lines needs to be URI escaped my $contents; + $line = escape($line) if $escape; local $/ = undef; my $fh = wrap_open("<", $file); $contents = <$fh>; $contents =~ s/\s+$/\n/; - if ($flag and $contents !~ /^\Q$line\E$/m) { + if ($op and $contents !~ /^\Q$line\E$/m) { # add line if it doesn't exist $contents .= "$line\n"; wrap_print($file, $contents); } - if (not $flag and $contents =~ /^\Q$line\E$/m) { + if (not $op and $contents =~ /^\Q$line\E$/m) { $contents =~ s/^\Q$line\E(\n|$)//m; wrap_print($file, $contents); } @@ -477,12 +482,13 @@ sub setup_daemon_access # ---------------------------------------------------------------------------- sub setup_web_access { + # input is a hashref; keys are project names if ($WEB_INTERFACE eq 'gitweb') { my $projlist = shift; my $projlist_fh = wrap_open( ">", "$PROJECTS_LIST.$$"); for my $proj (sort keys %{ $projlist }) { - print $projlist_fh "$proj\n"; + print $projlist_fh "" . ( $GITWEB_URI_ESCAPE ? escape($proj) : $proj ) . "\n"; } close $projlist_fh; rename "$PROJECTS_LIST.$$", $PROJECTS_LIST; @@ -493,10 +499,13 @@ sub setup_web_access { } sub add_del_web_access { + # input is a repo name. Code could simply use `can_read($repo, 'gitweb')` + # to determine whether to add or delete the repo from web access. + # However, "desc" also factors into this so we have think about this. if ($WEB_INTERFACE eq 'gitweb') { my $repo = shift; - add_del_line ("$repo.git", $PROJECTS_LIST, setup_gitweb_access($repo, '', '')); + add_del_line ("$repo.git", $PROJECTS_LIST, setup_gitweb_access($repo, '', '') || 0, $GITWEB_URI_ESCAPE || 0); } else { warn "sorry, unknown web interface $WEB_INTERFACE\n"; diff --git a/src/gitolite_rc.pm b/src/gitolite_rc.pm index 71f6d0b..9f65a7d 100644 --- a/src/gitolite_rc.pm +++ b/src/gitolite_rc.pm @@ -21,8 +21,9 @@ use Exporter 'import'; $GL_NO_CREATE_REPOS $GL_NO_DAEMON_NO_GITWEB $GL_NO_SETUP_AUTHKEYS $GL_PACKAGE_CONF $GL_PACKAGE_HOOKS $GL_PERFLOGT $GL_SITE_INFO $GL_SLAVE_MODE $GL_WILDREPOS $GL_WILDREPOS_DEFPERMS - $GL_WILDREPOS_PERM_CATS $HTPASSWD_FILE $PROJECTS_LIST $WEB_INTERFACE $REPO_BASE - $REPO_UMASK $RSYNC_BASE $SVNSERVE $UPDATE_CHAINS_TO $AUTH_OPTIONS + $GL_WILDREPOS_PERM_CATS $HTPASSWD_FILE $PROJECTS_LIST $WEB_INTERFACE + $GITWEB_URI_ESCAPE $REPO_BASE $REPO_UMASK $RSYNC_BASE $SVNSERVE + $UPDATE_CHAINS_TO $AUTH_OPTIONS $GL_HOSTNAME $GL_HTTP_ANON_USER diff --git a/t/t58-daemon-gitweb-wild b/t/t58-daemon-gitweb-wild index d0bee20..b5ed6ed 100644 --- a/t/t58-daemon-gitweb-wild +++ b/t/t58-daemon-gitweb-wild @@ -158,3 +158,173 @@ do name "INTERNAL" done done + +for bc in 0 1 +do + for ais in 0 1 + do + cd $TESTDIR + $TESTDIR/rollback || die "rollback failed" + editrc GL_WILDREPOS 1 + editrc GL_BIG_CONFIG $bc + echo "\$GL_ALL_INCLUDES_SPECIAL = $ais;" | addrc + echo "\$GITWEB_URI_ESCAPE = 1;" | addrc + + # ---------- + + name "INTERNAL" + echo " + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gbar = bar/CREATOR/..* + repo @gbar + C = @leads + RW+ = @leads + RW = @devs + " | ugc + expect_push_ok "master -> master" + runlocal git ls-remote u1:bar/u1/try1 + runremote ls -al $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + notexpect "bar/u1/try1.git" + + name "add daemon access" + echo " + R = daemon + " | ugc + runremote ls -al $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + + name "add one more repo" + runlocal git ls-remote u1:bar/u1/try2 + runremote ls -al $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + notexpect "bar/u1/try1.git" + notexpect "bar/u1/try2.git" + + name "add descriptions for try1 and try3 and compile" + echo " + bar/u1/try1 = \"this is bar/u1/try1\" + bar/u1/try3 = \"this is bar/u1/try3\" + " | ugc + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 20 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 32 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + notexpect "bar/u1/try1.git" + expect "bar%2Fu1%2Ftry1.git" + notexpect "bar/u1/try2.git" + notexpect "bar/u1/try3.git" + notexpect "bar%2Fu1%2Ftry2.git" + notexpect "bar%2Fu1%2Ftry3.git" + runremote cat $TEST_BASE/bar/u1/try1.git/description + expect "this is bar/u1/try1" + + name "add try3 project" + runlocal git ls-remote u1:bar/u1/try3 + runremote ls -al $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 20 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 32 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + notexpect "bar/u1/try1.git" + expect "bar%2Fu1%2Ftry1.git" + notexpect "bar/u1/try2.git" + notexpect "bar/u1/try3.git" + notexpect "bar%2Fu1%2Ftry2.git" + notexpect "bar%2Fu1%2Ftry3.git" + runremote cat $TEST_BASE/bar/u1/try1.git/description + expect "this is bar/u1/try1" + runremote cat $TEST_BASE/bar/u1/try3.git/description + expect "Unnamed repository; edit this file 'description' to name the repository." + + name "now compile and recheck try3 stuff" + echo " + " | ugc + runremote ls -al $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 40 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 52 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + notexpect "bar/u1/try1.git" + expect "bar%2Fu1%2Ftry1.git" + notexpect "bar/u1/try2.git" + notexpect "bar%2Fu1%2Ftry2.git" + notexpect "bar/u1/try3.git" + expect "bar%2Fu1%2Ftry3.git" + runremote cat $TEST_BASE/bar/u1/try1.git/description + expect "this is bar/u1/try1" + runremote cat $TEST_BASE/bar/u1/try3.git/description + expect "this is bar/u1/try3" + + name "add owner for try2 and compile" + echo " + bar/u1/try2 \"owner2\" = \"this is bar/u1/try1\" + " | ugc + runremote cat $TEST_BASE/bar/u1/try2.git/config + expect "\[gitweb\]" + expect "owner = owner2" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 72 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry2.git" + + name "add gitweb access to all" + echo " + repo @gbar + R = gitweb + " | ugc + expect_push_ok "master -> master" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 72 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + expect "bar%2Fu1%2Ftry1.git" + expect "bar%2Fu1%2Ftry2.git" + expect "bar%2Fu1%2Ftry3.git" + + name "add try4 project" + runlocal git ls-remote u1:bar/u1/try4 + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 80 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 92 .* projects.list" + runremote cat projects.list + [ "$ais" = "0" ] && notexpect "testing.git" + [ "$ais" = "1" ] && expect "testing.git" + expect "bar%2Fu1%2Ftry1.git" + expect "bar%2Fu1%2Ftry2.git" + expect "bar%2Fu1%2Ftry3.git" + expect "bar%2Fu1%2Ftry4.git" + runremote cat $TEST_BASE/bar/u1/try4.git/description + expect "Unnamed repository; edit this file 'description' to name the repository." + + name "INTERNAL" + done +done diff --git a/t/t60-daemon-gitweb-via-setperms b/t/t60-daemon-gitweb-via-setperms index b08718c..c1bea6b 100644 --- a/t/t60-daemon-gitweb-via-setperms +++ b/t/t60-daemon-gitweb-via-setperms @@ -168,3 +168,176 @@ do done done + +for bc in 0 1 +do + for ais in 0 1 + do + cd $TESTDIR + $TESTDIR/rollback || die "rollback failed" + editrc GL_WILDREPOS 1 + editrc GL_BIG_CONFIG $bc + echo "\$GL_ALL_INCLUDES_SPECIAL = $ais;" | addrc + echo "\$GITWEB_URI_ESCAPE = 1;" | addrc + + name "INTERNAL" + echo " + @leads = u1 u2 + @devs = u1 u2 u3 u4 + + @gbar = bar/CREATOR/..* + repo @gbar + C = @leads + RW+ = @leads + RW = WRITERS @devs + R = READERS + " | ugc + name "nothing set yet" + expect_push_ok "master -> master" + + runlocal git ls-remote u1:bar/u1/try1 + runremote ls -al $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + runremote cat projects.list + notexpect "bar/u1/try1.git" + + runlocal git ls-remote u1:bar/u1/try2 + runremote ls -al $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + runremote cat projects.list + notexpect "bar/u1/try2.git" + + name "add daemon access to try1" + echo R daemon | runlocal ssh u1 setperms bar/u1/try1 + expect "READERS daemon" + + runremote ls -al $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try1.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 0 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 12 .* projects.list" + runremote cat projects.list + notexpect "bar/u1/try1.git" + + name "add gitweb access to try2" + echo R gitweb | runlocal ssh u1 setperms bar/u1/try2 + expect "READERS gitweb" + + runremote ls -al $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try2.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 20 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 32 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry2.git" + + echo "\$GL_WILDREPOS_DEFPERMS = 'R daemon';" | addrc + + name "add default daemon access" + runlocal git ls-remote u1:bar/u1/try3 + runremote ls -al $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try3.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 20 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 32 .* projects.list" + runremote cat projects.list + notexpect "bar%2Fu1%2Ftry3.git" + + name "add default gitweb access" + echo "\$GL_WILDREPOS_DEFPERMS = 'R gitweb';" | addrc + + runlocal git ls-remote u1:bar/u1/try4 + runremote ls -al $TEST_BASE/bar/u1/try4.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try4.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 40 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 52 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry4.git" + + name "add default both access" + echo "\$GL_WILDREPOS_DEFPERMS = 'R daemon gitweb';" | addrc + + runlocal git ls-remote u1:bar/u1/try5 + runremote ls -al $TEST_BASE/bar/u1/try5.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try5.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 72 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry5.git" + + name "add default both access with @all also" + echo "\$GL_WILDREPOS_DEFPERMS = 'R @all daemon gitweb';" | addrc + + runlocal git ls-remote u1:bar/u1/try6 + runremote ls -al $TEST_BASE/bar/u1/try6.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try6.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 80 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 92 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry6.git" + + name "remove all from u6" + < /dev/null runlocal ssh u1 setperms bar/u1/try6 + + runlocal git ls-remote u1:bar/u1/try6 + runremote ls -al $TEST_BASE/bar/u1/try6.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try6.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 72 .* projects.list" + runremote cat projects.list + notexpect "bar%2Fu1%2Ftry6.git" + + name "set default access to @all only" + echo "\$GL_WILDREPOS_DEFPERMS = 'R @all';" | addrc + + runlocal git ls-remote u1:bar/u1/try7 + runremote ls -al $TEST_BASE/bar/u1/try7.git/git-daemon-export-ok + [ "$ais" = "0" ] && expect "ls: cannot access $TEST_BASE/bar/u1/try7.git/git-daemon-export-ok: No such file or directory" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try7.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 92 .* projects.list" + runremote cat projects.list + notexpect "bar/u1/try7.git" + notexpect "bar/u1/try7.git" + [ "$ais" = "0" ] && notexpect "bar%2Fu1%2Ftry7.git" + [ "$ais" = "1" ] && expect "bar%2Fu1%2Ftry7.git" + + name "set default access to daemon only" + echo "\$GL_WILDREPOS_DEFPERMS = 'R daemon';" | addrc + + runlocal git ls-remote u1:bar/u1/try8 + runremote ls -al $TEST_BASE/bar/u1/try8.git/git-daemon-export-ok + expect "gitolite-test gitolite-test .* $TEST_BASE/bar/u1/try8.git/git-daemon-export-ok" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 60 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 92 .* projects.list" + runremote cat projects.list + notexpect "bar%2Fu1%2Ftry8.git" + + name "set default access to gitweb only" + echo "\$GL_WILDREPOS_DEFPERMS = 'R gitweb';" | addrc + + runlocal git ls-remote u1:bar/u1/try9 + runremote ls -al $TEST_BASE/bar/u1/try9.git/git-daemon-export-ok + expect "ls: cannot access $TEST_BASE/bar/u1/try9.git/git-daemon-export-ok: No such file or directory" + runremote ls -al projects.list + [ "$ais" = "0" ] && expect "gitolite-test gitolite-test 80 .* projects.list" + [ "$ais" = "1" ] && expect "gitolite-test gitolite-test 112 .* projects.list" + runremote cat projects.list + expect "bar%2Fu1%2Ftry9.git" + + name "INTERNAL" + + done +done