From aaccb367ec48ad193413a67fd52565aba320fc00 Mon Sep 17 00:00:00 2001 From: Thomas Hager Date: Wed, 18 Apr 2012 09:09:24 +0200 Subject: [PATCH 001/158] changes to support Solaris default shell Solaris default bourne shell does not recognize $(), and does not allow exporting a variable and assigning a value to it in one step. --- src/triggers/post-compile/update-git-daemon-access-list | 5 +++-- src/triggers/post-compile/update-gitweb-access-list | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/triggers/post-compile/update-git-daemon-access-list b/src/triggers/post-compile/update-git-daemon-access-list index feb4a37..4585f44 100755 --- a/src/triggers/post-compile/update-git-daemon-access-list +++ b/src/triggers/post-compile/update-git-daemon-access-list @@ -2,8 +2,9 @@ # this is probably the *fastest* git-daemon update possible. -export EO=git-daemon-export-ok -export RB=$(gitolite query-rc GL_REPO_BASE) +EO=git-daemon-export-ok +RB=`gitolite query-rc GL_REPO_BASE` +export EO RB gitolite list-phy-repos | gitolite access % daemon R any | perl -lane ' diff --git a/src/triggers/post-compile/update-gitweb-access-list b/src/triggers/post-compile/update-gitweb-access-list index d7f5a95..f97061f 100755 --- a/src/triggers/post-compile/update-gitweb-access-list +++ b/src/triggers/post-compile/update-gitweb-access-list @@ -4,7 +4,7 @@ # whatever you want and contribute it back, as long as it is upward # compatible. -plf=$(gitolite query-rc GITWEB_PROJECTS_LIST) +plf=`gitolite query-rc GITWEB_PROJECTS_LIST` [ -z "$plf" ] && plf=$HOME/projects.list ( From 3a7b547759aac7f808b11ffa5a71e1076936c471 Mon Sep 17 00:00:00 2001 From: Thomas Hager Date: Wed, 18 Apr 2012 08:35:21 +0200 Subject: [PATCH 002/158] replaced /bin/echo with printf, Solaris echo doesn't recognize -n gitolite setup fails to check admin pubkey, because $text always contains 2 or more lines after tsh_try() (the key and -n). [committer adds: I wasn't sure if 'printf' would work on cygwin, so I chose what looked like a safer option, but apparently it wasn't safe enough and fell afoul of Solaris. Anyway I managed to check (using a small test program) with someone who runs gitolite on cygwin, and it works. If you're wondering why I didn't just use echo followed by chomp(), that would of course have been the easy way out but I wanted to see how you'd do it without a post-processing option. It became a frustrating challenge of sorts because it seems such a trivial thing! ] --- src/lib/Gitolite/Common.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Common.pm b/src/lib/Gitolite/Common.pm index 947819a..638b122 100644 --- a/src/lib/Gitolite/Common.pm +++ b/src/lib/Gitolite/Common.pm @@ -277,7 +277,7 @@ sub logger_plus_stderr { sub tsh_try { my $cmd = shift; die "try: expects only one argument" if @_; - $text = `( $cmd ) 2>&1; /bin/echo -n RC=\$?`; + $text = `( $cmd ) 2>&1; printf RC=\$?`; if ( $text =~ s/RC=(\d+)$// ) { $rc = $1; trace( 3, $text ); From cf3dd885fcfc7ed63d83b7e4eaa1b9d517ed29fd Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 19 Apr 2012 06:33:36 +0530 Subject: [PATCH 003/158] (some docfixes) --- README.mkd | 23 +++++++++++++++-------- doc/dev-status.mkd | 2 +- doc/index.mkd | 2 +- doc/install.mkd | 20 +++++++++++++------- doc/mkdoc | 3 +++ 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/README.mkd b/README.mkd index e41f513..6400dc4 100644 --- a/README.mkd +++ b/README.mkd @@ -12,20 +12,27 @@ If you're reading this on the main gitolite page on github, several branch, and is now the actively maintained and supported software. Do NOT try to merge this with your old "master" branch! + The [main page][h-mp] leads to several useful starting points. The [table + of contents][h-mt] is a much more meaningfully ordered/structured list of + links (instead of putting them in alphabetical order of the filename, like + in g2!) + + If you are an existing (g2) user and wish to migrate, you MUST read + [this](http://sitaramc.github.com/gitolite/install.html#migr). + 2. Versions v2.x are on branch "g2". It will be supported for security issues and serious bugs in core functionality, but not for anything less - critical. Versions v1.x are completely unsupported now. - -If you're an existing (v1.x, v2.x) gitolite user please spend some time with -the documentation for the new version before upgrading. The [main page][h-mp] -leads to several useful starting points. The [table of contents][h-mt] is a -much more meaningfully ordered/structured list of links (instead of putting -them in alphabetical order of the filename, like in g2!) + critical. Versions v1.x are completely unsupported now. (Documentation + links for this version are [here][o1] and [here][o2]). [h-mp]: http://sitaramc.github.com/gitolite/ [h-mt]: http://sitaramc.github.com/gitolite/master-toc.html +[o1]: http://sitaramc.github.com/gitolite/g2/ +[o2]: http://sitaramc.github.com/gitolite/g2/master-toc.html ---- License information for code and documentation is at the end of doc/index.mkd -(or you can read it online [here][license]). +(or you can read it online +[here](http://sitaramc.github.com/gitolite/index.html#license)). + diff --git a/doc/dev-status.mkd b/doc/dev-status.mkd index c9af92a..03ef93f 100644 --- a/doc/dev-status.mkd +++ b/doc/dev-status.mkd @@ -2,7 +2,6 @@ Not yet done (will be tackled in this order unless someone asks): - * svnserve (someone is testing it) * mechanism for ADCs using unchecked arguments -- this is not just a matter of writing it; I have to think about *how* it will be done. (AFAIK the only tool affected is git-annexe; if there are more let me know) @@ -33,3 +32,4 @@ Done: * distro packaging instructions * migration advice for common cases * smart http + * svnserve diff --git a/doc/index.mkd b/doc/index.mkd index b153b50..9552975 100644 --- a/doc/index.mkd +++ b/doc/index.mkd @@ -13,7 +13,7 @@ For users of gitolite v2.x (call it "g2" for convenience), * [Why][g3why] I rewrote gitolite. * Development [status][dev-status]. - * Specific migration [issues and steps][g2migr]. + * Information on [migrating][migr] from g2 to g3. diff --git a/doc/install.mkd b/doc/install.mkd index 14f68ea..e3e925f 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -4,6 +4,12 @@ settings that MUST be dealt with **before** running `gitolite setup`; please start [here][migr]. RTFM is *mandatory* for migrations. +---- + +[[TOC]] + +---- + ## notes and naming conventions Gitolite uses a single "real" (i.e., unix) user to provide secure access to @@ -138,8 +144,8 @@ Here are the requirements for gitolite: ## #migr migrating -If you're migrating from gitosis, [this][gsmigr] is what -you want to start with. +This section is about migrating from older gitolite to +"g3". If you're migrating from gitosis, see [here][gsmigr]. First things first: g2 will be supported for a good long time for critical bugs, although enhancements and new features won't happen. @@ -147,7 +153,7 @@ bugs, although enhancements and new features won't happen. If you're an existing (gitolite v1.x or v2.x) user, and wish to migrate , here are the steps: -### pre-migration +### pre-migration checks 1. Check the [dev-status][] page to make sure all the features you want have been implemented in g3. @@ -157,13 +163,13 @@ are the steps: you were to a default install of the old gitolite, the less time a migration will take.) -### migration +### the actual migration **Note**: nothing in any of the gitolite install/setup/etc will ever touch the *data* in any repository except the gitolite-admin repo. The only thing it will normally touch in normal repos is the `update` hook. -1. Carefully wipe out the old gitolite +1. **On the server**, carefully wipe out the old gitolite: * The **code** @@ -203,8 +209,8 @@ will normally touch in normal repos is the `update` hook. followed by [setup][]. 4. Make sure your gitolite-admin clone has the correct pubkey for the - administrator in its `keydir` directory, then `git push -f` to the server - to overwrite the "default" admin repo created by the install. + administrator in its `keydir` directory, then run [`gitolite push + -f`][bypass] to overwrite the "default" admin repo created by the install. 5. Handle any errors, look for migration issues, etc., as described in the links at the top of this page. diff --git a/doc/mkdoc b/doc/mkdoc index 2f44d6c..bce1013 100755 --- a/doc/mkdoc +++ b/doc/mkdoc @@ -113,3 +113,6 @@ __DATA__ | license

+

+This is for gitolite "g3"; for older (v2.x) documentation click here +

From c3ec518cefba685ed36f6da40e17beb4fb9d0aee Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 09:34:06 +0530 Subject: [PATCH 004/158] fork command, and some core changes to make it work... - access command allows checking ^C - ^C check will fail when the repo exists --- doc/non-core.mkd | 1 + src/commands/access | 2 +- src/commands/fork | 62 ++++++++++++++++++++++++++++++ src/lib/Gitolite/Conf/Load.pm | 8 +++- src/lib/Gitolite/Rc.pm | 1 + t/fork.t | 71 +++++++++++++++++++++++++++++++++++ t/glt | 1 + 7 files changed, 144 insertions(+), 2 deletions(-) create mode 100755 src/commands/fork create mode 100755 t/fork.t diff --git a/doc/non-core.mkd b/doc/non-core.mkd index 207036a..eb0e7aa 100644 --- a/doc/non-core.mkd +++ b/doc/non-core.mkd @@ -18,6 +18,7 @@ bug to me if they don't. Here's a list of remote commands that are shipped: * 'desc' -- get/set the 'description' file for a repo + * 'fork' -- fork a repo * 'info' -- already documented [here][info] * 'mirror' -- documented [here][sync] * 'perms' -- get/set the gl-perms file; see [perms][] for more diff --git a/src/commands/access b/src/commands/access index db3ece0..cdefacb 100755 --- a/src/commands/access +++ b/src/commands/access @@ -42,7 +42,7 @@ if ( $ARGV[0] eq '-q' ) { $quiet = 1; shift @ARGV; } my ( $repo, $user, $aa, $ref ) = @ARGV; $aa ||= '+'; $ref ||= 'any'; -_die "invalid perm" if not( $aa and $aa =~ /^(R|W|\+|C|D|M)$/ ); +_die "invalid perm" if not( $aa and $aa =~ /^(R|W|\+|C|D|M|\^C)$/ ); _die "invalid ref name" if not( $ref and $ref =~ $REPONAME_PATT ); my $ret = ''; diff --git a/src/commands/fork b/src/commands/fork new file mode 100755 index 0000000..fb49d92 --- /dev/null +++ b/src/commands/fork @@ -0,0 +1,62 @@ +#!/bin/sh + +# Usage: ssh git@host fork +# +# Forks repo1 to repo2. You must have read permissions on repo1, and create +# ("C") permissions for repo2, which of course must not exist. +# +# A fork is functionally the same as cloning repo1 to a client and pushing it +# to a new repo2. It's just a little more efficient, not just in network +# traffic but because it uses git clone's "-l" option to share the object +# store also, so it is likely to be almost instantaneous, regardless of how +# big the repo actually is. +# +# The only caveat is that the repo you cloned *from* must not later become +# unavailable in any way. If you cannot be sure of this, take the scenic +# route (clone repo1, push to repo2). + +die() { echo "$@" >&2; exit 1; } +usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } +[ -z "$1" ] && usage +[ "$1" = "-h" ] && usage +[ -z "$GL_USER" ] && die GL_USER not set + +# ---------------------------------------------------------------------- +from=$1; shift +to=$1; shift +[ -z "$to" ] && usage + +gitolite access -q "$from" $GL_USER R any || die "'$from' does not exist or you are not allowed to read it" +gitolite access -q "$to" $GL_USER ^C any || die "'$to' already exists or you are not allowed to create it" + +# ---------------------------------------------------------------------- +# IMPORTANT NOTE: checking whether someone can create a repo is done as above. +# However, make sure that the env var GL_USER is set, and that too to the same +# value as arg-2 of the access command), otherwise it won't work. + +# Ideally, you'll leave such code to me. There's a reason ^C is not listed in +# the help message for 'gitolite access'. +# ---------------------------------------------------------------------- + +# clone $from to $to +git clone --bare -l $GL_REPO_BASE/$from.git $GL_REPO_BASE/$to.git +[ $? -ne 0 ] && exit 1 + +echo "$from forked to $to" >&2 + +# fix up creator, default role permissions (gl-perms), and hooks +cd $GL_REPO_BASE/$to.git +echo $GL_USER > gl-creator + +if gitolite query-rc -q DEFAULT_ROLE_PERMS +then + gitolite query-rc DEFAULT_ROLE_PERMS > gl-perms +fi + +ln -sf `gitolite query-rc GL_ADMIN_BASE`/hooks/common/* hooks + +# record where you came from +echo "$from" > gl-forked-from + +# trigger post_create +gitolite trigger POST_CREATE diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 3417d34..6878a70 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -80,6 +80,11 @@ sub access { $iret =~ s/\^C/$aa/; return $iret if $iret =~ /DENIED/; } + # similarly, ^C must be denied if the repo exists + if ( $aa eq '^C' and not repo_missing($repo) ) { + trace( 2, "DENIED by existence" ); + return "$aa $ref $repo $user DENIED by existence"; + } my @rules = rules( $repo, $user ); trace( 2, scalar(@rules) . " rules found" ); @@ -367,7 +372,8 @@ sub generic_name { # get the creator name. For not-yet-born repos this is $ENV{GL_USER}, # which should be set in all cases that we care about, viz., where we are # checking ^C permissions before new_wild_repo(), and the info command. - # In particular, 'gitolite access' can't be used to check ^C perms. + # In particular, 'gitolite access' can't be used to check ^C perms on wild + # repos that contain "CREATOR" if GL_USER is not set. $creator = creator($base); $base2 = $base; diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 6386651..924fe3f 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -288,6 +288,7 @@ __DATA__ { 'help' => 1, 'desc' => 1, + # 'fork' => 1, 'info' => 1, # 'mirror' => 1, 'perms' => 1, diff --git a/t/fork.t b/t/fork.t new file mode 100755 index 0000000..afa88ef --- /dev/null +++ b/t/fork.t @@ -0,0 +1,71 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# this is hardcoded; change it if needed +use lib "src/lib"; +use Gitolite::Test; + +# fork command +# ---------------------------------------------------------------------- + +try "plan 30"; + +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\$rc{DEFAULT_ROLE_PERMS} = 'READERS \@all';\n"; + +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 + +try "cd $rb; find . -name gl-perms | sort | xargs md5sum"; cmp +'59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1a2.git/gl-perms +59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1e.git/gl-perms +'; + +try "cd $rb; find . -name gl-creator | sort | xargs md5sum"; cmp +'346955ff2eadbf76e19373f07dd370a9 ./foo/u1/u1a2.git/gl-creator +e4774cdda0793f86414e8b9140bb6db4 ./foo/u1/u1a.git/gl-creator +346955ff2eadbf76e19373f07dd370a9 ./foo/u1/u1e.git/gl-creator +'; diff --git a/t/glt b/t/glt index b335cc0..1bf31e8 100755 --- a/t/glt +++ b/t/glt @@ -13,6 +13,7 @@ my %extcmds = ( help => 1, info => 1, desc => 1, + fork => 1, perms => 1, writable => 1, ); From 1ad0a761f791663204e94a58c74329d58b59e5fb Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 19:03:07 +0530 Subject: [PATCH 005/158] install should fail more gracefully if the '-ln' directory does not exist thanks to EugeneKay for catching this --- install | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/install b/install index 1cf7853..ca6a864 100755 --- a/install +++ b/install @@ -20,14 +20,21 @@ Usage (from gitolite clone directory): ./install to run gitolite using an absolute or relative path, for example 'src/gitolite' or '/full/path/to/this/dir/src/gitolite' + ./install -ln [] to symlink just the gitolite executable to some that is in - $PATH. defauls to $HOME/bin if not specified. + $PATH. defaults to $HOME/bin if not specified. is + assumed to exist; gitolite will not create it. + + Please provide a full path, not a relative path. + ./install -to to copy the entire 'src' directory to . If is not in $PATH, use the full path to run gitolite commands. -Simplest use, if you have $HOME/bin in $PATH, is: + Please provide a full path, not a relative path. + +Simplest use, if $HOME/bin exists and is in $PATH, is: git clone -b g3 git://github.com/sitaramc/gitolite gitolite/install -ln @@ -46,6 +53,12 @@ GetOptions( ); usage() if $to and $ln or $help; $ln = "$ENV{HOME}/bin" if defined($ln) and not $ln; +for my $d ($ln, $to) { + if ($d and not -d $d) { + print STDERR "FATAL: '$d' does not exist.\n"; + usage(); + } +} chdir($ENV{GL_BINDIR}); my $version = `git describe --tags --long --dirty=-dt`; From 6b65e7853fe373169f9e9ff54688f0f53d416ec6 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 19:49:56 +0530 Subject: [PATCH 006/158] (minor) add quotes to make repo name stand out in error message --- src/lib/Gitolite/Conf/Load.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 6878a70..8f1ebfe 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -209,7 +209,7 @@ sub load_1 { } if ( -f "gl-conf" ) { - _warn "split conf not set, gl-conf present for $repo" if not $split_conf{$repo}; + _warn "split conf not set, gl-conf present for '$repo'" if not $split_conf{$repo}; my $cc = "gl-conf"; _die "parse $cc failed: " . ( $! or $@ ) unless do $cc; @@ -218,7 +218,7 @@ sub load_1 { $repos{$repo} = $one_repo{$repo}; $configs{$repo} = $one_config{$repo} if $one_config{$repo}; } else { - _die "split conf set, gl-conf not present for $repo" if $split_conf{$repo}; + _die "split conf set, gl-conf not present for '$repo'" if $split_conf{$repo}; } } From 895b3614ed9211dcee8b76fd07a594f7a9c50a31 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 21:44:06 +0530 Subject: [PATCH 007/158] (minor) add a bit more detail on usage text for 'info' --- src/commands/info | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/info b/src/commands/info index 4eca761..f3217ee 100755 --- a/src/commands/info +++ b/src/commands/info @@ -12,7 +12,8 @@ use Gitolite::Conf::Load; =for args Usage: gitolite info [-lc] [] -List all repos/repo groups you can access. +List all existing repos you can access, as well as repo name patterns you can +create repos from (if any). '-lc' lists creators as an additional field at the end. From 198dcfd4c8100b4993c75cd2d8b6c57e86cf0aaa Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 21:25:54 +0530 Subject: [PATCH 008/158] POST_CREATE efficiency... (please read below if you care) The POST_CREATE trigger is called when * a user creates a new "wild" repo, * a user uses the "perms" command, and * a user uses the "fork" command. The trigger calls 3 programs (see rc file): post-compile/update-git-configs post-compile/update-gitweb-access-list post-compile/update-git-daemon-access-list (They are also called by the POST_COMPILE trigger, by the way.) However, the 3 programs shown are a bit wasteful -- they run through *all* the repos when really only *one* repo has been affected. This patch * passes the repo name to the 3 programs (duh!) * adds the optimisation to the first of the 3 programs listed above (the one dealing with 'git config'). For the other two programs (gitweb and git-daemon), you have 3 choices: * if you don't have too many repos, ignore the problem. * take out the 2nd and 3rd lines from the POST_CREATE list in the rc file, so they don't run. Then run 'gitolite trigger POST_COMPILE' from cron at regular intervals. (Note that is POST_COMPILE not POST_CREATE!) However, this means that gitweb and daemon permissions won't be current immediately after someone adds a new repo or sets perms etc.; they get updated only on the next cron run. * patch the programs to add this optimisation (and send me the patches). The optimisation would check if arg-1 ($1 in shell, $ARGV[0] in perl) is 'POST_CREATE', and if it is, take the *next* argument as a repo name that may have changed. --- src/commands/fork | 2 +- src/commands/perms | 4 ++-- src/triggers/post-compile/update-git-configs | 21 ++++++++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/commands/fork b/src/commands/fork index fb49d92..fe27035 100755 --- a/src/commands/fork +++ b/src/commands/fork @@ -59,4 +59,4 @@ ln -sf `gitolite query-rc GL_ADMIN_BASE`/hooks/common/* hooks echo "$from" > gl-forked-from # trigger post_create -gitolite trigger POST_CREATE +gitolite trigger POST_CREATE $to $GL_USER diff --git a/src/commands/perms b/src/commands/perms index dce271c..7be3a28 100755 --- a/src/commands/perms +++ b/src/commands/perms @@ -34,8 +34,9 @@ if ( $ARGV[0] eq '-l' ) { getperms(@ARGV); # doesn't return } +my $repo = shift; setperms(@ARGV); -_system( "gitolite", "trigger", "POST_CREATE" ); +_system( "gitolite", "trigger", "POST_CREATE", $repo, $ENV{GL_USER} ); # ---------------------------------------------------------------------- @@ -50,7 +51,6 @@ sub getperms { } sub setperms { - my $repo = shift; _die "sorry you are not authorised" if repo_missing($repo) or creator($repo) ne $ENV{GL_USER}; my $pf = "$rc{GL_REPO_BASE}/$repo.git/gl-perms"; diff --git a/src/triggers/post-compile/update-git-configs b/src/triggers/post-compile/update-git-configs index 446b28a..7f3fb83 100755 --- a/src/triggers/post-compile/update-git-configs +++ b/src/triggers/post-compile/update-git-configs @@ -13,13 +13,30 @@ use Gitolite::Conf::Load; use strict; use warnings; -# ---------------------------------------------------------------------- - my $RB = $rc{GL_REPO_BASE}; _chdir($RB); + +# ---------------------------------------------------------------------- +# if called from POST_CREATE, we have only a single repo to worry about +if (@ARGV and $ARGV[0] eq 'POST_CREATE') { + my $repo = $ARGV[1]; + fixup_config($repo); + + exit 0; +} + +# ---------------------------------------------------------------------- +# else it's all repos (i.e., called from POST_COMPILE) + my $lpr = list_phy_repos(); for my $pr (@$lpr) { + fixup_config($pr); +} + +sub fixup_config { + my $pr = shift; + my $gc = git_config( $pr, '.' ); while ( my ( $key, $value ) = each( %{$gc} ) ) { next if $key =~ /^gitolite-options\./; From d74f596e231fe349961466dc2f00bfc931f88312 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 23 Apr 2012 06:22:03 +0530 Subject: [PATCH 009/158] make can_write() in Easy.pm more flexible --- src/lib/Gitolite/Easy.pm | 10 +++++++--- t/easy.t | 12 +++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/lib/Gitolite/Easy.pm b/src/lib/Gitolite/Easy.pm index 280a924..9231d00 100644 --- a/src/lib/Gitolite/Easy.pm +++ b/src/lib/Gitolite/Easy.pm @@ -112,14 +112,18 @@ sub can_read { } # can_write() -# return true if $ENV{GL_USER} is set and can write to the given repo +# return true if $ENV{GL_USER} is set and can write to the given repo. +# Optional second argument can be '+' to check that instead of 'W'. Optional +# third argument can be a full ref name instead of 'any'. # shell equivalent # if gitolite access -q $REPONAME $GL_USER W; then ... sub can_write { valid_user(); - my $r = shift; - return not( access( $r, $user, 'W', 'any' ) =~ /DENIED/ ); + my ($r, $aa, $ref) = @_; + $aa ||= 'W'; + $ref ||= 'any'; + return not( access( $r, $user, $aa, $ref ) =~ /DENIED/ ); } # config() diff --git a/t/easy.t b/t/easy.t index c626602..dcd6c1a 100755 --- a/t/easy.t +++ b/t/easy.t @@ -18,7 +18,7 @@ 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 90"; +try "plan 98"; try " cat $ENV{HOME}/.gitolite.rc @@ -117,6 +117,11 @@ $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")); @@ -132,6 +137,11 @@ $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/"); From 5d366b5c0e3406478183247a235dc60910b8cf83 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 19 Apr 2012 20:05:47 +0530 Subject: [PATCH 010/158] new VREF: MAX_NEWBIN_SIZE (manual spot testing only) --- src/VREF/MAX_NEWBIN_SIZE | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100755 src/VREF/MAX_NEWBIN_SIZE diff --git a/src/VREF/MAX_NEWBIN_SIZE b/src/VREF/MAX_NEWBIN_SIZE new file mode 100755 index 0000000..84a9efa --- /dev/null +++ b/src/VREF/MAX_NEWBIN_SIZE @@ -0,0 +1,40 @@ +#!/usr/bin/perl +use strict; +use warnings; + +# gitolite VREF to check max size of new binary files + +# see gitolite docs for what the first 7 arguments mean + +# inputs: +# arg-8 is a number +# outputs (STDOUT) +# arg-7 if any new binary files exist that are greater in size than arg-8 +# *and* there is no "signed-off by" line for such a file in the top commit +# message. +# +# Otherwise nothing +# exit status: +# always 0 + +die "not meant to be run manually" unless $ARGV[7]; + +my ( $newsha, $oldtree, $newtree, $refex, $max ) = @ARGV[ 2, 3, 4, 6, 7 ]; + +# / (.*) +\| Bin 0 -> (\d+) bytes/ + +chomp( my $author_email = `git log --format=%ae -1 $newsha` ); +my $msg = `git cat-file -p $newsha`; +$msg =~ s/\t/ /g; # makes our regexes simpler + +for my $newbin (`git diff --stat=999,999 $oldtree $newtree | grep Bin.0.-`) { + next unless $newbin =~ /^ (.*) +\| +Bin 0 -> (\d+) bytes/; + my ( $f, $s ) = ( $1, $2 ); + next if $s <= $max; + + next if $msg =~ /^ *$f +signed-off by: *$author_email *$/mi; + + print "$refex $f is larger than $max"; +} + +exit 0 From 9e1cb5936c984a28b7363c0491ea4cd81de93604 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 22 Apr 2012 09:33:57 +0530 Subject: [PATCH 011/158] (some docfixes) --- doc/g2migr.mkd | 10 ++++++++++ doc/install.mkd | 5 ++++- doc/non-core.mkd | 2 +- doc/progit.mkd | 1 + doc/qi.mkd | 4 ++-- doc/rc.mkd | 17 +++++++++++++++++ doc/sskm.mkd | 10 +++++----- 7 files changed, 40 insertions(+), 9 deletions(-) diff --git a/doc/g2migr.mkd b/doc/g2migr.mkd index aba2961..46079a8 100644 --- a/doc/g2migr.mkd +++ b/doc/g2migr.mkd @@ -116,6 +116,16 @@ Some of them have links where there is more detail than I want to put here. (ancillary, non-core, or minor functionality lost) + * Built-in command `expand` -- **dropped**. The 'info' command shows you + both normal and wild repos now. The output format is also much simpler. + + * Built-in commands 'getperms', 'setperms' -- **merged** into external + command 'perms'. Run `ssh git@host perms -h` for details. + + Similarly, 'getdesc' and 'setdesc' have been merged into 'desc'. + + * Several 'ADC's -- see the [dev-status][] page for more on this. + * [gl-time][g2i-gl-time]: the CpuTime module replaces gl-time. * `BIG_INFO_CAP` -- **dropped**. If you think you must have this, try it diff --git a/doc/install.mkd b/doc/install.mkd index e3e925f..65697ab 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -99,10 +99,13 @@ you can run the 'install' command in 3 different ways: # option 2 gitolite/install -ln - # defaults to $HOME/bin, or use a specific directory: + # defaults to $HOME/bin (which is assumed to exist) + # ** or ** + # or use a specific directory (please supply full path): gitolite/install -ln /usr/local/bin # option 3 + # (again, please supply a full path) gitolite/install -to /usr/local/gitolite/bin Creating a symlink doesn't need a separate program but 'install' also runs diff --git a/doc/non-core.mkd b/doc/non-core.mkd index eb0e7aa..e6f9eab 100644 --- a/doc/non-core.mkd +++ b/doc/non-core.mkd @@ -22,7 +22,7 @@ Here's a list of remote commands that are shipped: * 'info' -- already documented [here][info] * 'mirror' -- documented [here][sync] * 'perms' -- get/set the gl-perms file; see [perms][] for more - * 'sskm' -- self-service key management + * 'sskm' -- self-service key management, see [sskm][] for more * 'writable' -- disabling pushes to take backups etc * 'D' -- deleting user-created repos diff --git a/doc/progit.mkd b/doc/progit.mkd index 1e7856d..fe4e304 100644 --- a/doc/progit.mkd +++ b/doc/progit.mkd @@ -20,6 +20,7 @@ To begin, create a user called `git` on your server and login to this user. Cop git clone git://github.com/sitaramc/gitolite gitolite/install -ln + # assumes $HOME/bin exists and is in your $PATH gitolite setup -pk $HOME/YourName.pub # for example, I would run 'gitolite setup -pk $HOME/sitaram.pub' diff --git a/doc/qi.mkd b/doc/qi.mkd index 563071b..2ac9470 100644 --- a/doc/qi.mkd +++ b/doc/qi.mkd @@ -23,8 +23,8 @@ On your workstation: * This is a fresh install, not a migration from the old gitolite (v1.x, v2.x). - * On the server, your `$PATH` contains `$HOME/bin`. If you don't like that, - there are [other install methods][install]. + * On the server, `$HOME/bin` exists and is in your `$PATH`. If you don't + like that, there are [other install methods][install]. * "your-name.pub" is your public key from your workstation. * Also, this key does not already have shell access to this gitolite diff --git a/doc/rc.mkd b/doc/rc.mkd index 04c88f1..2c84d88 100644 --- a/doc/rc.mkd +++ b/doc/rc.mkd @@ -80,3 +80,20 @@ information. with regular expressions) is to allow anything and everything: `$GIT_CONFIG_KEYS = '.*';` + * `DEFAULT_ROLE_PERMS`, string, default undef + + This sets default wildcard permissions for newly created wildcard repos. + + If set, this value will be used as the default role permissions for new + wildcard repositories. The user can change this value with the perms + command as desired after repository creation; it is only a default. + + Please be aware this is potentially a multi-line variable. In most + setups, it will be left undefined. Some installations may benefit from + setting it to `READERS @all`. + + If you want multiple roles to be assigned by default, here is how. Note + double quotes this time, due to the embedded newline, which in turn + require the '@' to be escaped: + + DEFAULT_ROLE_PERMS => "READERS \@all\nWRITERS \@senior_devs", diff --git a/doc/sskm.mkd b/doc/sskm.mkd index e9ce302..4ac908d 100644 --- a/doc/sskm.mkd +++ b/doc/sskm.mkd @@ -221,12 +221,12 @@ Listing the keys shows that that new key is now marked active again: ## important notes for the admin -These are the things that can break if you allows your users to use this command: +These are the things that can break if you allow your users to use this +command: - * If you, as the gitolite admin, are in the habit of force-pushing changes - to the admin repo instead of doing a `git pull` (or, even better, a `git - pull --rebase`) then you had better not enable this command. Your users - will eventually come after you with pitchforks ;-) + * "sskm" clones, changes, and pushes back the gitolite-admin repo. This + means, even if you're the only administrator, you should never 'git push + -f', in case you end up overwriting something sskm did. * There is no way to distinguish `foo/alice.pub` from `bar/alice.pub` using this command. You can distinguish `foo/alice.pub` from From e0ed14172bca04614dd6edf8c15aced2a92b0827 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 24 Apr 2012 14:09:17 +0530 Subject: [PATCH 012/158] add migration example, plus some other little mig doc fixes --- doc/g2migr-example.mkd | 269 +++++++++++++++++++++++++++++++++++++++++ doc/g2migr.mkd | 2 +- doc/install.mkd | 16 ++- 3 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 doc/g2migr-example.mkd diff --git a/doc/g2migr-example.mkd b/doc/g2migr-example.mkd new file mode 100644 index 0000000..18c2ba8 --- /dev/null +++ b/doc/g2migr-example.mkd @@ -0,0 +1,269 @@ +# migration example + +This shows what a typical migration would look like, using a test setup. + +[[TOC]] + +## existing setup + +The existing gitolite is the latest in the "g2" (v2.x) branch. + +First, the rc file has the following lines different from the default: + + -$GL_WILDREPOS = 0; + +$GL_WILDREPOS = 1; + + -$GL_GITCONFIG_KEYS = ""; + +$GL_GITCONFIG_KEYS = ".*"; + +Next, the conf/gitolite.conf file in `~/.gitolite`: + + repo gitolite-admin + RW+ = tester u1 + + repo testing + RW+ = @all + + repo foo + RW+ = u1 u2 + RW+ NAME/ = u1 + RW+ NAME/u2 = u2 + + repo bar + RW = u2 + + repo baz/..* + C = u3 u4 + RW+ = CREATOR + config foo.bar = baz + +(Note that this conf file has NAME/ rules, which **have changed** +significantly in g3; see [here][g2i-name] for details). + +These are the repos already existing + + $ find repositories -name "*.git" | sort + repositories/bar.git + repositories/baz/u3.git + repositories/baz/u4.git + repositories/baz/uthree.git + repositories/foo.git + repositories/gitolite-admin.git + repositories/testing.git + +The config entries exist for all the baz/ repos: + + $ grep -2 foo `find repositories -name "config" ` + repositories/baz/uthree.git/config-[gitweb] + repositories/baz/uthree.git/config- owner = u3 + repositories/baz/uthree.git/config:[foo] + repositories/baz/uthree.git/config- bar = baz + -- + repositories/baz/u4.git/config-[gitweb] + repositories/baz/u4.git/config- owner = u4 + repositories/baz/u4.git/config:[foo] + repositories/baz/u4.git/config- bar = baz + -- + repositories/baz/u3.git/config-[gitweb] + repositories/baz/u3.git/config- owner = u3 + repositories/baz/u3.git/config:[foo] + repositories/baz/u3.git/config- bar = baz + +## preparing for the migration + +### getting g3 + +Fortunately this is easy here; I just happened to have the repo already +fetched so I just had to switch branches. You may have to 'git clone ...' +from github. + + $ cd gitolite + $ git checkout master + Branch master set up to track remote branch master from origin. + Switched to a new branch 'master' + +### run check-g2-compat + +This is a quick and dirty program to catch some of the big issues. + + $ cd + $ gitolite/check-g2-compat + INFO This program only checks for uses that make the new g3 completely unusable + or that might end up giving *more* access to someone if migrated as-is. + It does NOT attempt to catch all the differences described in the docs. + + INFO 'see docs' usually means doc/g2migr.mkd + (online at http://sitaramc.github.com/gitolite/g3/g2migr.html) + + checking rc file... + NOTE GL_ADMINDIR is in the right place; assuming you did not mess with + GL_CONF, GL_LOGT, GL_KEYDIR, and GL_CONF_COMPILED + + checking conf file(s)... + SEVERE NAME rules; see docs + + checking repos... + WARNING found 3 gl-creater files; see docs + + ...all done... + +## the actual migration + +Here's the actual migration, step by step + +### step 1 + + $ ls -a bin + . gl-admin-push gl-install gl-setup-authkeys gl-VREF-DUPKEYS + .. gl-auth-command gl-mirror-push gl-system-install gl-VREF-EMAIL_CHECK + gitolite_env.pm gl-compile-conf gl-mirror-shell gl-time gl-VREF-FILETYPE + gitolite.pm gl-conf-convert gl-query-rc gl-tool gl-VREF-MERGE_CHECK + gitolite_rc.pm gl-dryrun gl-setup gl-VREF-COUNT sshkeys-lint + $ rm -rf bin;mkdir bin + + $ grep GL_PACKAGE .gitolite.rc + $GL_PACKAGE_CONF = "/home/g3/share/gitolite/conf"; + $GL_PACKAGE_HOOKS = "/home/g3/share/gitolite/hooks"; + $ rm -rf share + + $GL_PACKAGE_HOOKS = "/home/g3/share/gitolite/hooks"; + $ rm -rf share + + $ mv .gitolite.rc old.grc + +(still on step 1, this is substep 3) notice we are cloning **on the server**, +using a **full path** to the repo. + + $ git clone repositories/gitolite-admin.git old.ga + Cloning into 'old.ga'... + done. + $ rm -rf repositories/gitolite-admin.git/ + +Since I'm not interested in preserving the logs and don't have any custom +hooks: + + $ rm -rf .gitolite + +### step 2 + +I have no variables that *must* be preset, since the report by +`check-g2-compat` is clear. + +### step 3 + +Here we install the new gitolite. Remember we already got the new software +(in order to run 'check-g2-compat'). + +Just check that bin is empty, then run 'install -ln' from the gitolite source +tree: + + $ ls -al bin + total 8 + drwxrwxr-x 2 g3 g3 4096 Apr 24 10:57 . + drwx------ 8 g3 g3 4096 Apr 24 10:59 .. + $ gitolite/install -ln + $ ls -al bin + total 8 + drwxrwxr-x 2 g3 g3 4096 Apr 24 11:01 . + drwx------ 8 g3 g3 4096 Apr 24 10:59 .. + lrwxrwxrwx 1 g3 g3 30 Apr 24 11:01 gitolite -> /home/g3/gitolite/src/gitolite + +OK that went well. Now setup gitolite. You don't need a key here; just use a +random name: + + $ gitolite setup -a admin + Initialized empty Git repository in /home/g3/repositories/gitolite-admin.git/ + +### step 4 + +Now go to your old clone, and push it: + + $ cd old.ga + $ gitolite push -f + ...usual git progress output deleted... + remote: FATAL: git config foo.bar not allowed + remote: check GIT_CONFIG_KEYS in the rc file + To /home/g3/repositories/gitolite-admin.git + + 7eb8163...1474770 master -> master (forced update) + +Aaha! I forgot to set `CONFIG_KEYS` (new name for `GL_GIT_CONFIG_KEYS`) in +the new rc file so fix that: + + $ vim ~/.gitolite.rc + (edit and set it to `.*` for now) + +and push again: + + $ gitolite push -f + Everything up-to-date + +Damn. We have to make a dummy commit to allow the push to do something. + +But wait! We forgot fix the [NAME/][g2i-name] rules, so may as well fix +those, add, and push: + + $ vim conf/gitolite.conf + # change all NAME/ to VREF/NAME/ + # append a '- VREF/NAME/ = @all' at the end + # save + git add conf + + $ git commit -m name-rules + ... some output for add... + + $ gitolite push -f + Counting objects: 1, done. + Writing objects: 100% (1/1), 181 bytes, done. + Total 1 (delta 0), reused 0 (delta 0) + Unpacking objects: 100% (1/1), done. + To /home/g3/repositories/gitolite-admin.git + 1474770..4c2b41d master -> master + +### step 5 + +The only thing left is to fix up the gl-creater files: + + $ cd $HOME/repositories + $ find . -type d -name "*.git" -prune | while read r + > do + > mv $r/gl-creater $r/gl-creator + > done 2>/dev/null + +And we're done! + +## checking things out + +Let's see what repos u3 has: + + ssh u3 info + hello u3, this is g3@sita-lt running gitolite3 v3.0-11-g090b0f5 on git 1.7.7.6 + + C baz/..* + R W baz/u3 + R W baz/uthree + R W gitolite-admin + R W testing + +That's a combination of 'info' and 'expand', by the way. There is no expand +command any more. + +How about adding a new repo and checking if the config entries made it? + + $ git ls-remote u4:baz/ufour + Initialized empty Git repository in /home/g3/repositories/baz/ufour.git/ + $ grep -A1 foo `find repositories -name "config" ` + repositories/baz/u3.git/config:[foo] + repositories/baz/u3.git/config- bar = baz + -- + repositories/baz/u4.git/config:[foo] + repositories/baz/u4.git/config- bar = baz + -- + repositories/baz/ufour.git/config:[foo] + repositories/baz/ufour.git/config- bar = baz + -- + repositories/baz/uthree.git/config:[foo] + repositories/baz/uthree.git/config- bar = baz + +And there it is, in the second block of lines... + +And now we're really done. diff --git a/doc/g2migr.mkd b/doc/g2migr.mkd index 46079a8..e7f2864 100644 --- a/doc/g2migr.mkd +++ b/doc/g2migr.mkd @@ -145,7 +145,7 @@ Some of them have links where there is more detail than I want to put here. business touching these anyway; if you did, move them into the expected default locations before attempting to run `gitolite setup` - * `GL_GITCONFIG_KEYS` -- is now `GITCONFIG_KEYS`. + * `GL_GITCONFIG_KEYS` -- is now `GIT_CONFIG_KEYS`. * `GL_LOGT` -- now has a fixed value; email me if this is a problem. diff --git a/doc/install.mkd b/doc/install.mkd index 65697ab..ad681ec 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -166,13 +166,21 @@ are the steps: you were to a default install of the old gitolite, the less time a migration will take.) + This includes at least running `check-g2-compat` to see what are the big + issues you might need to address during the migration. + ### the actual migration +(Note: You may also like the [example migration][g2migr-example] page). + **Note**: nothing in any of the gitolite install/setup/etc will ever touch the *data* in any repository except the gitolite-admin repo. The only thing it will normally touch in normal repos is the `update` hook. -1. **On the server**, carefully wipe out the old gitolite: +**Note: all migration happens on the server; you do not need your +workstation**. + +1. Carefully wipe out the old gitolite: * The **code** @@ -209,7 +217,11 @@ will normally touch in normal repos is the `update` hook. your new rc file. 3. Install gitolite g3; see [quick install and setup][qi] or [install][] - followed by [setup][]. + followed by [setup][]. However, the 'setup' step need not supply a + private key. You can run it as `gitolite setup -a admin`. + + NOTE: ignore any 'split conf not set, gl-conf present...' errors at this + time. You may see none, some, or many. It does not matter right now. 4. Make sure your gitolite-admin clone has the correct pubkey for the administrator in its `keydir` directory, then run [`gitolite push From a952f2d6272ce02ea06f65523c54acd9d10acb8f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 26 Apr 2012 16:04:46 +0530 Subject: [PATCH 013/158] add COPYING file (from http://www.gnu.org/licenses/gpl-2.0.txt) thanks to Jon Ciesla for catching this omission... --- COPYING | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 COPYING diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..7d5393a --- /dev/null +++ b/COPYING @@ -0,0 +1,278 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. From eabcf83deedd6524c57fd5468d9354c27aa7369c Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 26 Apr 2012 16:33:26 +0530 Subject: [PATCH 014/158] (minor) add titles to rendered HTML docs --- doc/mkdoc | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/doc/mkdoc b/doc/mkdoc index bce1013..72470d3 100755 --- a/doc/mkdoc +++ b/doc/mkdoc @@ -38,9 +38,10 @@ sub main { chomp(@ARGV = `find . -name "*.mkd" | cut -c3-`) if not @ARGV; @ARGV = grep { /./ } @ARGV; my @save = @ARGV; - my $css = join("", ); + my $css_block = join("", ); my %ct; # chapter tocs + my %title; my $mf = ''; my $fh; @@ -49,6 +50,7 @@ sub main { my $b = $1; if (/^(#+) (?:#(\S+) )?(.*)/) { + $title{$b} ||= $3; if ( length($1) == 1 ) { $ct{$b} .= "\n"; $ct{$b} .= " * [$3][$b]\n"; @@ -80,6 +82,9 @@ sub main { $mkd =~ /^(?:.*\/)?([^\/]+)\.mkd$/; my $b = $1; + my $css = $css_block; + $css =~ s/%TITLE/$title{$b} || $b/e; + open($fh, ">", "../html/$b.html") and print $fh $css and close $fh; @@ -95,7 +100,9 @@ sub main { __DATA__ - + +

master TOC From 7d6b04605d5caad2475005592c6eece6f9e18d70 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 28 Apr 2012 04:54:05 +0530 Subject: [PATCH 015/158] fix test suite's dependency on time zone I had not remembered that the 'tc' subcommand in tsh adds *text* that contains the current time, so commit SHAs were changing. Thanks to milki for catching this, and in fact being the only person who ever appears to have attempted to run the test suite at all! --- src/lib/Gitolite/Test/Tsh.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Test/Tsh.pm b/src/lib/Gitolite/Test/Tsh.pm index 581a844..2097acd 100644 --- a/src/lib/Gitolite/Test/Tsh.pm +++ b/src/lib/Gitolite/Test/Tsh.pm @@ -583,7 +583,7 @@ sub dummy_commits { test_tick(); next; } - my $ts = ( $tick ? localtime($tick) : localtime() ); + my $ts = ( $tick ? gmtime($tick+19800) : gmtime() ); _sh("echo $f at $ts >> $f && git add $f && git commit -m '$f at $ts'"); } } From e919a0b7ca6a519c4aba35cdca2e3bda340299e3 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 28 Apr 2012 12:02:15 +0530 Subject: [PATCH 016/158] solaris doesn't like 'hostname -s'... (luckily, unlike linux, it doesn't spew a usage message to STDOUT!) --- src/commands/info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/info b/src/commands/info index f3217ee..0b789bd 100755 --- a/src/commands/info +++ b/src/commands/info @@ -49,7 +49,7 @@ sub args { } sub print_version { - chomp( my $hn = `hostname -s` ); + chomp( my $hn = `hostname -s 2>/dev/null || hostname` ); my $gv = substr( `git --version`, 12 ); $ENV{GL_USER} or _die "GL_USER not set"; print "hello $ENV{GL_USER}, this is $ENV{USER}\@$hn running gitolite3 " . version() . " on git $gv\n"; From 48ed4deb8fa87f5aec22f7f9d9fc7df950d9c325 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 28 Apr 2012 12:03:32 +0530 Subject: [PATCH 017/158] BSD compat changes thanks to milki for all the efforts! Details: - partial-copy fell afoul of BSD not having $RANDOM - test suite: fix bad GNU sort with good perl sort - test suite: fix md5sum dependency (which BSD doesn't have or can't easily have or requires extra options or whatever...), by doing it in perl. (Requires Digest::MD5, which is probably available anyway, but since this is only for the test suite, meh!) --- doc/non-core.mkd | 3 ++ src/VREF/partial-copy | 6 ++-- src/lib/Gitolite/Test.pm | 12 ++++++++ src/lib/Gitolite/Test/Tsh.pm | 4 +-- t/0-me-first.t | 2 +- t/fork.t | 9 +++--- t/git-config.t | 56 +++++++++++++++++++----------------- t/partial-copy.t | 6 ++-- 8 files changed, 58 insertions(+), 40 deletions(-) diff --git a/doc/non-core.mkd b/doc/non-core.mkd index e6f9eab..b893e0a 100644 --- a/doc/non-core.mkd +++ b/doc/non-core.mkd @@ -121,6 +121,9 @@ Here's how: - VREF/partial-copy = @all config gitolite.partialCopyOf = foo + **IMPORTANT**: if you're using other VREFs, please make sure this one is + placed at the end, after all the others. + And that should be it. **Please test it and let me know if it doesn't work!** WARNINGS: diff --git a/src/VREF/partial-copy b/src/VREF/partial-copy index efb73bf..19111de 100755 --- a/src/VREF/partial-copy +++ b/src/VREF/partial-copy @@ -20,13 +20,13 @@ exec >&2 main=`git config --file $GL_REPO_BASE/$repo.git/config --get gitolite.partialCopyOf`; [ -z "$main" ] && exit 0 -rand=$RANDOM +rand=$$ export GL_BYPASS_ACCESS_CHECKS=1 -git push -f $GL_REPO_BASE/$main.git $new:refs/heads/br-$rand || die "FATAL: failed to send $new" +git push -f $GL_REPO_BASE/$main.git $new:refs/partial/br-$rand || die "FATAL: failed to send $new" cd $GL_REPO_BASE/$main.git -git update-ref -d refs/heads/br-$rand +git update-ref -d refs/partial/br-$rand git update-ref $ref $new $old || die "FATAL: update-ref for $ref failed" exit 0 diff --git a/src/lib/Gitolite/Test.pm b/src/lib/Gitolite/Test.pm index 07838f0..48a2330 100644 --- a/src/lib/Gitolite/Test.pm +++ b/src/lib/Gitolite/Test.pm @@ -8,15 +8,18 @@ package Gitolite::Test; try put text + lines dump confreset confadd cmp + md5sum ); #>>> use Exporter 'import'; use File::Path qw(mkpath); use Carp qw(carp cluck croak confess); +use Digest::MD5 qw(md5_hex); use Gitolite::Common; @@ -25,6 +28,7 @@ BEGIN { *{'try'} = \&Tsh::try; *{'put'} = \&Tsh::put; *{'text'} = \&Tsh::text; + *{'lines'} = \&Tsh::lines; *{'cmp'} = \&Tsh::cmp; } @@ -100,4 +104,12 @@ sub confadd { put "|cat >> conf/$file", $string; } +sub md5sum { + my $out = ''; + for my $file (@_) { + $out .= md5_hex(slurp($file)) . " $file\n"; + } + return $out; +} + 1; diff --git a/src/lib/Gitolite/Test/Tsh.pm b/src/lib/Gitolite/Test/Tsh.pm index 2097acd..2b7dcee 100644 --- a/src/lib/Gitolite/Test/Tsh.pm +++ b/src/lib/Gitolite/Test/Tsh.pm @@ -473,9 +473,9 @@ sub fail { } sub cmp { - # compare input string with text() - my $text = text(); + # compare input string with second input string or text() my $in = shift; + my $text = ( @_ ? +shift : text() ); if ( $text eq $in ) { ok(); diff --git a/t/0-me-first.t b/t/0-me-first.t index a11dfd0..dc8916b 100755 --- a/t/0-me-first.t +++ b/t/0-me-first.t @@ -32,7 +32,7 @@ try " glt clone u1 file://aa u1aa; ok; /Cloning into 'u1aa'.../ /warning: You appear to have cloned an empty repository/ ls -ald --time-style=long-iso u1aa; - ok; /drwxr-xr-x 3 $ENV{USER} $ENV{USER} 4096 201.-..-.. ..:.. u1aa/ + ok; /drwxr-xr-x 3 $ENV{USER} $ENV{USER} \\d+ 201.-..-.. ..:.. u1aa/ # basic clone deny glt clone u4 file://aa u4aa; !ok; /R any aa u4 DENIED by fallthru/ diff --git a/t/fork.t b/t/fork.t index afa88ef..38cb200 100755 --- a/t/fork.t +++ b/t/fork.t @@ -59,13 +59,14 @@ try " # now check the various files that should have been produced -try "cd $rb; find . -name gl-perms | sort | xargs md5sum"; cmp +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 | sort | xargs md5sum"; cmp -'346955ff2eadbf76e19373f07dd370a9 ./foo/u1/u1a2.git/gl-creator -e4774cdda0793f86414e8b9140bb6db4 ./foo/u1/u1a.git/gl-creator +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 index 437e1cc..18f2e78 100755 --- a/t/git-config.t +++ b/t/git-config.t @@ -15,6 +15,8 @@ try "pwd"; my $od = text(); chomp($od); +my $t; # temp + # try an invalid config key confreset;confadd ' @@ -62,13 +64,15 @@ 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 | sort + egrep foo\\|bar *.git/config "; -cmp 'bar.git/config: bare = true -bar.git/config: bar = one +$t = join("\n", sort (lines())); + +cmp $t, 'bar.git/config: bar = one +bar.git/config: bare = true bar.git/config:[foo] -foo.git/config: bare = true foo.git/config: bar = f1 +foo.git/config: bare = true foo.git/config:[foo] frob.git/config: bar = dft frob.git/config: bare = true @@ -76,8 +80,7 @@ frob.git/config:[foo] gitolite-admin.git/config: bare = true testing.git/config: bar = dft testing.git/config: bare = true -testing.git/config:[foo] -'; +testing.git/config:[foo]'; try "cd $od; ok"; @@ -97,23 +100,23 @@ try "ADMIN_PUSH set1; !/FATAL/" or die text(); try " cd $rb; ok - egrep foo\\|bar *.git/config | sort + egrep foo\\|bar *.git/config "; +$t = join("\n", sort (lines())); -cmp 'bar.git/config: bare = true -bar.git/config: bar = one +cmp $t, 'bar.git/config: bar = one +bar.git/config: bare = true bar.git/config:[foo] -foo.git/config: bare = true foo.git/config: bar = f1 +foo.git/config: bare = true foo.git/config:[foo] -frob.git/config: bare = true 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] -'; +testing.git/config:[foo]'; try "cd $od; ok"; @@ -129,22 +132,22 @@ try "ADMIN_PUSH set1; !/FATAL/" or die text(); try " cd $rb; ok - egrep foo\\|bar *.git/config | sort + egrep foo\\|bar *.git/config "; +$t = join("\n", sort (lines())); -cmp 'bar.git/config: bare = true +cmp $t, 'bar.git/config: bare = true bar.git/config:[foo] -foo.git/config: bare = true foo.git/config: bar = f1 +foo.git/config: bare = true foo.git/config:[foo] -frob.git/config: bare = true 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] -'; +testing.git/config:[foo]'; try "cd $od; ok"; @@ -170,21 +173,20 @@ try " try " cd $rb; ok - egrep foo\\|bar *.git/config | sort - find . -name config | xargs egrep foo\\|bar | sort + find . -name config | xargs egrep foo\\|bar "; +$t = join("\n", sort (lines())); -cmp './bar/u2/one.git/config: bare = true -./bar/u2/one.git/config: bar = one +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: bare = true ./foo.git/config: bar = f1 +./foo.git/config: bare = true ./foo.git/config:[foo] -./frob.git/config: bare = true ./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] -'; +./testing.git/config:[foo]'; diff --git a/t/partial-copy.t b/t/partial-copy.t index 6b8dfdc..5bff843 100755 --- a/t/partial-copy.t +++ b/t/partial-copy.t @@ -90,20 +90,20 @@ try " tc u4n1 u4n2 PUSH u4 next; ok /To .*/foo.git/ - /new branch\\] ca3787119b7e8b9914bc22c939cefc443bc308da -> br-\\d+/ + /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 -> br-\\d+/ + /\\[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 -> br-\\d+/ + /new branch\\] 228353950557ed1eb13679c1fce4d2b4718a2060 -> refs/partial/br-\\d+/ /file:///foo-pc/ /new branch.* HEAD -> dev/u4/u4master/ From 88b4c86c385f6abfea7b2aae35136538881dcf88 Mon Sep 17 00:00:00 2001 From: Thomas Hager Date: Fri, 20 Apr 2012 15:28:05 +0200 Subject: [PATCH 018/158] Added instructions to make repositories available via http and ssh This patch adds instructions for configuring Gitolite and Apache 2.x to make repositories available to both ssh and http clients. [minor fixups by committer] --- doc/http.mkd | 94 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/doc/http.mkd b/doc/http.mkd index 1c935db..bfc7544 100644 --- a/doc/http.mkd +++ b/doc/http.mkd @@ -13,10 +13,6 @@ that is the same or even relevant -- that is from 2006 and is quite different * I have tested this only on stock Fedora 16; YDMV. - * As before, I have not tried making repos available to both ssh *and* http - mode clients but it ought to work. If you managed it, I'd appreciate a - doc patch describing how you did it. - ## assumptions: * Apache 2.x and git installed. @@ -38,6 +34,96 @@ that delete files etc.), change values per your system, and only then run it. git-http-backend") is no longer optional. Make sure you set it to some place outside apache's `DOCUMENT_ROOT`. +## Making repositories available to both ssh and http mode clients + +This section has been contributed by Thomas Hager (duke at sigsegv dot at). + +Assumptions: + + * Apache 2.x with CGI and Suexec support installed. + * Git and Gitolite installed with user "git" and group "git", and pubkey SSH + access configured and working. + * Git plumbing installed to /usr/libexec/git-core + * Gitolite base located at /opt/git + * Apache `DOCUMENT_ROOT` set to /var/www + * Apache runs with user www and group www + +Please adjust the instructions below to reflect your setup (users and paths). + +Edit your .gitolite.rc and add + + $ENV{GIT_HTTP_BACKEND} = "/usr/libexec/git-core/git-http-backend"; + $ENV{PATH} .= ":/opt/git/bin"; + +at the very top (as described in `t/smart-http.root-setup`). + +Next, check which document root your Apache's suexec accepts: + + # suexec -V + -D AP_DOC_ROOT="/var/www" + -D AP_GID_MIN=100 + -D AP_HTTPD_USER="www" + -D AP_LOG_EXEC="/var/log/apache/suexec.log" + -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" + -D AP_UID_MIN=100 + -D AP_USERDIR_SUFFIX="public_html" + +We're interested in `AP_DOC_ROOT`, which is set to `/var/www` in our case. + +Create a `bin` and a `git` directory in `AP_DOC_ROOT`: + + install -d -m 0755 -o git -g git /var/www/bin + install -d -m 0755 -o www -g www /var/www/git + +`/var/www/git` is just a dummy directory used as Apache's document root (see below). + +Next, create a shell script inside `/var/www/bin` named `gitolite-suexec-wrapper.sh`, +with mode **0700** and owned by user and group **git**. Add the following content: + + #!/bin/bash + # + # Suexec wrapper for gitolite-shell + # + + export GIT_PROJECT_ROOT="/opt/git/repositories" + export GITOLITE_HTTP_HOME="/opt/git" + + exec ${GITOLITE_HTTP_HOME}/gitolite-source/src/gitolite-shell + +Edit your Apache's config to add http pull/push support, preferably in +a dedicated `VirtualHost` section: + + + ServerName git.example.com + ServerAlias git + ServerAdmin you@example.com + + DocumentRoot /var/www/git + + Options None + AllowOverride none + Order allow,deny + Allow from all + + + SuexecUserGroup git git + ScriptAlias /git/ /var/www/bin/gitolite-suexec-wrapper.sh/ + ScriptAlias /gitmob/ /var/www/bin/gitolite-suexec-wrapper.sh/ + + + AuthType Basic + AuthName "Git Access" + Require valid-user + AuthUserFile /etc/apache/git.passwd + + + +This Apache config is just an example, you probably should adapt the authentication +section and use https instead of http! + +Finally, add an `R = daemon` access rule to all repositories you want to +make available via http. + ## usage ### client side From 88c8d774d099cc9f64dcc95919395d4876760dc4 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 29 Apr 2012 05:55:37 +0530 Subject: [PATCH 019/158] v3.01 --- doc/CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index cb3626b..10c045c 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -1,3 +1,6 @@ +2012-04-29 v3.01 mostly BSD and Solaris compat + also fork command added + 2012-04-18 v3.0 first release to "master" This is a compete rewrite of gitolite; please see documentation before upgrading. From 850882c1a6d95446e38ff8ceaa7d2513e44b57f5 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 30 Apr 2012 05:35:26 +0530 Subject: [PATCH 020/158] allow VREF code to print to STDOUT... Using a g2-style "chained update hook" as a VREF doesn't *quite* work: - all STDOUT from the hook is lost - worse, all lines get parsed as a ref followed by a message, and if the ref doesn't look like a ref it dies So now we do all this only if the message starts with 'VREF/'. Any other output is just printed out as is. --- doc/vref.mkd | 31 ++++++++++++++++++------------- src/lib/Gitolite/Hooks/Update.pm | 6 ++++++ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/doc/vref.mkd b/doc/vref.mkd index a5bfb27..ac6599b 100644 --- a/doc/vref.mkd +++ b/doc/vref.mkd @@ -71,9 +71,9 @@ Briefly, a refex starting with `VREF/FOO` triggers a call to a program called `FOO` in `$GL_BINDIR/VREF`. That program is expected to print zero or more lines to its STDOUT; each line -is taken by gitolite as a new "ref" to be matched against all the refexes for -this user in the config. Including the refex that caused the vref call, of -course. +that starts with `VREF/` is taken by gitolite as a new "ref" to be matched +against all the refexes for this user in the config. Including the refex that +caused the vref call, of course. Normally, you send back the refex itself, if the test determines that the rule should be matched, otherwise nothing. So, in our example, we print @@ -102,16 +102,21 @@ exit. The program is passed **nine arguments** in this case (see next section for details). - * The script can print anything it wants to STDOUT; the first word in each - such line will be treated as a virtual ref to be matched against all the - rules, while the rest, if any, is a message to be added to the standard - "...DENIED..." message that gitolite prints if that refex matches. + * The script can print anything it wants to STDOUT. Lines not starting with + `VREF/` are printed as is (so your VREF can do mostly-normal printing to + STDOUT). + + For lines starting with `VREF/`, the first word in each such line will be + treated as a virtual ref to be matched against all the rules, while the + rest, if any, is a message to be added to the standard "...DENIED..." + message that gitolite prints if that refex matches. Usually it only makes sense to either - * Print nothing -- if you don't want the rule that triggered it to match - (ie., whatever condition being tested was not violated; like if the - count of changed files did not exceed 9, in our earlier example). + * Print nothing that starts with `VREF/` -- if you don't want the rule + that triggered it to match (ie., whatever condition being tested was + not violated; like if the count of changed files did not exceed 9, in + our earlier example). * Print the refex itself (plus an optional message), so that it matches the line which invoked it. @@ -151,9 +156,9 @@ to write vref scripts in any language. See script examples in source. ## what (else) can the vref code pass back -Actually, the vref code can pass anything back; each line in its output will -be matched against all the rules as usual (with the exception that fallthru is -not failure). +Actually, the vref code can pass anything back; each line in its output that +starts with `VREF/` will be matched against all the rules as usual (with the +exception that fallthru is not failure). For example, you could have a ruleset like this: diff --git a/src/lib/Gitolite/Hooks/Update.pm b/src/lib/Gitolite/Hooks/Update.pm index 3bcb8cf..ed4a03f 100644 --- a/src/lib/Gitolite/Hooks/Update.pm +++ b/src/lib/Gitolite/Hooks/Update.pm @@ -66,6 +66,12 @@ sub check_vrefs { open( my $fh, "-|", $pgm, @_, $vref, @args ) or _die "$vref: can't spawn helper program: $!"; while (<$fh>) { + # print non-vref lines and skip processing (for example, + # normal STDOUT by a normal update hook) + unless (m(^VREF/)) { + print; + next; + } my ( $ref, $deny_message ) = split( ' ', $_, 2 ); check_vref( $aa, $ref, $deny_message ); } From c1455288496d1e80dcffc2cf10557293bd451e6d Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 1 May 2012 12:05:17 +0530 Subject: [PATCH 021/158] (minor typo fix) --- src/lib/Gitolite/Setup.pm | 2 +- src/lib/Gitolite/Test.pm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Setup.pm b/src/lib/Gitolite/Setup.pm index effdb96..0a677a8 100644 --- a/src/lib/Gitolite/Setup.pm +++ b/src/lib/Gitolite/Setup.pm @@ -137,7 +137,7 @@ sub setup_gladmin { tsh_try("git config --get user.email") or tsh_run( "git config user.email $ENV{USER}\@" . `hostname` ); tsh_try("git config --get user.name") or tsh_run( "git config user.name '$ENV{USER} on '" . `hostname` ); tsh_try("git diff --cached --quiet") - or tsh_try("git commit -am 'gl-setup $argv'") + or tsh_try("git commit -am 'gitolite setup $argv'") or _die "setup failed to commit to the admin repo"; delete $ENV{GIT_WORK_TREE}; } diff --git a/src/lib/Gitolite/Test.pm b/src/lib/Gitolite/Test.pm index 48a2330..e6e5a36 100644 --- a/src/lib/Gitolite/Test.pm +++ b/src/lib/Gitolite/Test.pm @@ -47,7 +47,7 @@ try " DEF ADMIN_PUSH = AP_2 %1; glt push admin origin; ok; gsh; /master -> master/ DEF CS_1 = pwd; //tmp/tsh_tempdir.*gitolite-admin/; git remote -v; ok; /file://gitolite-admin/ - DEF CHECK_SETUP = CS_1; git log; ok; /6b18ec2ab0f765122ec133959b36c57f77d4565c/ + DEF CHECK_SETUP = CS_1; git log; ok; /fa7564c1b903ea3dce49314753f25b34b9e0cea0/ DEF CLONE = glt clone %1 file:///%2 DEF PUSH = glt push %1 origin From 49d132a969cb1148e289af6bb5633d193263fd19 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 1 May 2012 13:12:10 +0530 Subject: [PATCH 022/158] minor fix to info command output under httpd... when running under httpd, $ENV{USER} is not set, so we use a (hopefully informative) default to print. Thanks to Thomas Hager (duke at sigsegv dot at) for catching this. --- src/commands/info | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/info b/src/commands/info index 0b789bd..c4f5d6c 100755 --- a/src/commands/info +++ b/src/commands/info @@ -52,7 +52,7 @@ sub print_version { chomp( my $hn = `hostname -s 2>/dev/null || hostname` ); my $gv = substr( `git --version`, 12 ); $ENV{GL_USER} or _die "GL_USER not set"; - print "hello $ENV{GL_USER}, this is $ENV{USER}\@$hn running gitolite3 " . version() . " on git $gv\n"; + print "hello $ENV{GL_USER}, this is " . ($ENV{USER} || "httpd") . "\@$hn running gitolite3 " . version() . " on git $gv\n"; } sub print_patterns { From 47a0c4454082abef5489df0a9f1742f3f6a5275c Mon Sep 17 00:00:00 2001 From: Andreas Stenius Date: Wed, 2 May 2012 18:03:05 +0200 Subject: [PATCH 023/158] migrated htpasswd command from g2. (with some fixups by committer) --- src/commands/htpasswd | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100755 src/commands/htpasswd diff --git a/src/commands/htpasswd b/src/commands/htpasswd new file mode 100755 index 0000000..3571cf1 --- /dev/null +++ b/src/commands/htpasswd @@ -0,0 +1,44 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Rc; +use Gitolite::Common; + +=for usage +Usage: ssh git@host htpasswd + +Sets your htpasswd, assuming your admin has enabled it. + +(Admins: You need to add HTPASSWD_FILE to the rc file, pointing to an +existing, writable, but possibly an initially empty, file, as well as adding +an entry for 'htpasswd' to the COMMANDS hash). +=cut + +# usage and sanity checks +usage() if @ARGV and $ARGV[0] eq '-h'; +$ENV{GL_USER} or _die "GL_USER not set"; +my $htpasswd_file = $rc{HTPASSWD_FILE} || ''; +die "htpasswd not enabled\n" unless $htpasswd_file; +die "$htpasswd_file doesn't exist or is not writable\n" unless -w $htpasswd_file; + +# prompt +$|++; +print <; +$password =~ s/[\n\r]*$//; +die "empty passwords are not allowed\n" unless $password; +my $res = system("htpasswd", "-mb", $htpasswd_file, $ENV{GL_USER}, $password); +die "htpasswd command seems to have failed with return code: $res.\n" if $res; From d8df4a93440ef10c28fed8eb92822538ab3d85aa Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 4 May 2012 16:33:04 +0530 Subject: [PATCH 024/158] git-config bugfix + backward compat breakage in usage of 'config' (1) the backward compat breakage: you can't create empty-valued config keys anymore. That is, you can't do the eqvt of the following shell command using gitolite git config foo.bar "" (2) fixed a bug where this: repo foo config foo.bar = when queried using gitolite git-config -r foo . would return even the empty valued ones, which -- remember! -- are not supposed to exist anymore. Fixing this bug allows situations like this to not show the admin repo in gitweb: repo [a-z].* config gitweb.owner = P-h B repo gitolite-admin config gitweb.owner = ---- background... Somewhere in g3 (well actually in 057506b), we lost the ability to distinguish config foo.bar = "" from config foo.bar = I decided that conflating them is more intuitive for most people, because a survey [1] revealed that no one seemed to want the equivalent of the following shell command: ---- [1] ...of a (small prime greater than 1) number of people on #git --- doc/git-config.mkd | 6 +++--- src/lib/Gitolite/Conf/Load.pm | 11 ++++++++++- src/triggers/post-compile/update-git-configs | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/doc/git-config.mkd b/doc/git-config.mkd index e1c1c00..94487e1 100644 --- a/doc/git-config.mkd +++ b/doc/git-config.mkd @@ -23,9 +23,9 @@ For example: config foo.bar = "" config foo.baz = -This does either a plain "git config section.key value" (for the first 3 -examples above) or "git config --unset-all section.key" (for the last -example). Other forms of the `git config` command (`--add`, the +This does either a plain "git config section.key value" (for the first 2 +examples above) or "git config --unset-all section.key" (for the last 2 +examples). Other forms of the `git config` command (`--add`, the `value_regex`, etc) are not supported. > ---- diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 8f1ebfe..9f4ddb0 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -114,7 +114,7 @@ sub access { } sub git_config { - my ( $repo, $key ) = @_; + my ( $repo, $key, $empty_values_OK ) = @_; $key ||= '.'; return {} if repo_missing($repo); @@ -149,6 +149,15 @@ sub git_config { # and the final map does this: # 'foo.bar'=>'repo' , 'foodbar'=>'repoD' + # now some of these will have an empty key; we need to delete them unless + # we're told empty values are OK + unless ($empty_values_OK) { + my($k, $v); + while (($k, $v) = each %ret) { + delete $ret{$k} if not $v; + } + } + trace( 3, map { ( "$_" => "-> $ret{$_}" ) } ( sort keys %ret ) ); return \%ret; } diff --git a/src/triggers/post-compile/update-git-configs b/src/triggers/post-compile/update-git-configs index 7f3fb83..bd7ff13 100755 --- a/src/triggers/post-compile/update-git-configs +++ b/src/triggers/post-compile/update-git-configs @@ -37,7 +37,7 @@ for my $pr (@$lpr) { sub fixup_config { my $pr = shift; - my $gc = git_config( $pr, '.' ); + my $gc = git_config( $pr, '.', 1 ); while ( my ( $key, $value ) = each( %{$gc} ) ) { next if $key =~ /^gitolite-options\./; if ( $value ne "" ) { From 6d057fb84c2e0e85dd353061b73e9e8de15d3953 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 4 May 2012 17:52:43 +0530 Subject: [PATCH 025/158] allow info to print description also --- src/commands/info | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/commands/info b/src/commands/info index c4f5d6c..daf3ad2 100755 --- a/src/commands/info +++ b/src/commands/info @@ -10,12 +10,13 @@ use Gitolite::Common; use Gitolite::Conf::Load; =for args -Usage: gitolite info [-lc] [] +Usage: gitolite info [-lc] [-ld] [] List all existing repos you can access, as well as repo name patterns you can create repos from (if any). '-lc' lists creators as an additional field at the end. + '-ld' lists description as an additional field at the end. The optional pattern is an unanchored regex that will limit the repos searched, in both cases. It might speed up things a little if you have more @@ -23,7 +24,7 @@ than a few thousand repos. =cut # these two are globals -my ( $lc, $patt ) = args(); +my ( $lc, $ld, $patt ) = args(); print_version(); @@ -34,18 +35,19 @@ print "\n$rc{SITE_INFO}\n" if $rc{SITE_INFO}; # ---------------------------------------------------------------------- sub args { - my ( $lc, $patt ) = ( '', '' ); + my ( $lc, $ld, $patt ) = ( '', '', '' ); my $help = ''; GetOptions( 'lc' => \$lc, + 'ld' => \$ld, 'h' => \$help, ) or usage(); usage() if @ARGV > 1 or $help; $patt = shift @ARGV || '.'; - return ( $lc, $patt ); + return ( $lc, $ld, $patt ); } sub print_version { @@ -61,8 +63,8 @@ sub print_patterns { # find repo patterns only, call them with ^C flag included @$repos = grep { !/$REPONAME_PATT/ } @{ lister_dispatch('list-repos')->() }; @aa = qw(R W ^C); - listem( $repos, '', @aa ); - # but squelch the 'lc' flag for these + listem( $repos, '', '', @aa ); + # but squelch the 'lc' and 'ld' flags for these } sub print_phy_repos { @@ -72,16 +74,19 @@ sub print_phy_repos { _chdir( $rc{GL_REPO_BASE} ); $repos = list_phy_repos(1); @aa = qw(R W); - listem( $repos, $lc, @aa ); + listem( $repos, $lc, $ld, @aa ); } sub listem { - my ( $repos, $lc, @aa ) = @_; + my ( $repos, $lc, $ld, @aa ) = @_; my $creator = ''; + my $desc = ''; for my $repo (@$repos) { next unless $repo =~ /$patt/; my $perm = ''; $creator = creator($repo) if $lc; + $desc = slurp("$ENV{GL_REPO_BASE}/$repo.git/description") if $ld; + chomp($desc); for my $aa (@aa) { my $ret = access( $repo, $ENV{GL_USER}, $aa, 'any' ); @@ -91,6 +96,7 @@ sub listem { next unless $perm =~ /\S/; print "$perm\t$repo"; print "\t$creator" if $lc; + print "\t$desc" if $ld; print "\n"; } } From 196706c1457d9ad242bd2a9ef833f21f1dd6b607 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 5 May 2012 07:11:59 +0530 Subject: [PATCH 026/158] bugfix: smart http mode wasn't running pre_ and post_ git triggers (while we're about it, we also steal Michael Brown's idea (patch #2 in [1] and get rid of GIT_HTTP_BACKEND). [1]: http://groups.google.com/group/gitolite/msg/adfae758dd28f2a8 --- doc/http.mkd | 1 - src/gitolite-shell | 10 ++++++---- t/smart-http.root-setup | 1 - 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/http.mkd b/doc/http.mkd index bfc7544..3b9809e 100644 --- a/doc/http.mkd +++ b/doc/http.mkd @@ -52,7 +52,6 @@ Please adjust the instructions below to reflect your setup (users and paths). Edit your .gitolite.rc and add - $ENV{GIT_HTTP_BACKEND} = "/usr/libexec/git-core/git-http-backend"; $ENV{PATH} .= ":/opt/git/bin"; at the very top (as described in `t/smart-http.root-setup`). diff --git a/src/gitolite-shell b/src/gitolite-shell index 07e2cd5..af03a36 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -121,11 +121,13 @@ sub main { gl_log( "pre_git", $repo, $user, $aa, 'any', "-> $ret" ); } - exec $ENV{GIT_HTTP_BACKEND} if $ENV{REQUEST_URI}; - trigger( 'PRE_GIT', $repo, $user, $aa, 'any', $verb ); - my $repodir = "'$rc{GL_REPO_BASE}/$repo.git'"; - _system( "git", "shell", "-c", "$verb $repodir" ); + if ($ENV{REQUEST_URI}) { + _system( "git", "http-backend" ); + } else { + my $repodir = "'$rc{GL_REPO_BASE}/$repo.git'"; + _system( "git", "shell", "-c", "$verb $repodir" ); + } trigger( 'POST_GIT', $repo, $user, $aa, 'any', $verb ); } diff --git a/t/smart-http.root-setup b/t/smart-http.root-setup index ed3d413..dd42ad9 100755 --- a/t/smart-http.root-setup +++ b/t/smart-http.root-setup @@ -46,7 +46,6 @@ 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{GIT_HTTP_BACKEND} = "/usr/libexec/git-core/git-http-backend";' > 1 echo '$ENV{PATH} .= ":$ENV{GITOLITE_HTTP_HOME}/bin";' >> 1 echo >> 1 cat .gitolite.rc >> 1 From e76be7ff110db02ffe78bede9b2001c5aab7cbc6 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 6 May 2012 18:53:52 +0530 Subject: [PATCH 027/158] move repo/user validity check deeper (but change repo check to allow repoPATT instead of just repoNAME) This is because there are/will be some situations where access() is called without those two checks being done (i.e., it is not only from src/commands/access that it is called). --- src/commands/access | 2 -- src/lib/Gitolite/Conf/Load.pm | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/access b/src/commands/access index cdefacb..636dc61 100755 --- a/src/commands/access +++ b/src/commands/access @@ -49,8 +49,6 @@ my $ret = ''; if ( $repo ne '%' and $user ne '%' ) { # single repo, single user; no STDIN - _die "invalid repo name" if not( $repo and $repo =~ $REPONAME_PATT ); - _die "invalid user name" if not( $user and $user =~ $USERNAME_PATT ); $ret = access( $repo, $user, $aa, $ref ); if ( $ret =~ /DENIED/ ) { diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 9f4ddb0..7599727 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -67,6 +67,8 @@ my $last_repo = ''; sub access { my ( $repo, $user, $aa, $ref ) = @_; + _die "invalid repo '$repo'" if not( $repo and $repo =~ $REPOPATT_PATT ); + _die "invalid user '$user'" if not( $user and $user =~ $USERNAME_PATT ); my $deny_rules = option( $repo, 'deny-rules' ); load($repo); From 699bafa096d21e85c281950e98e60d64104637f9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 6 May 2012 19:01:53 +0530 Subject: [PATCH 028/158] (minor fixup to t/info.t) --- t/info.t | 3 --- 1 file changed, 3 deletions(-) diff --git a/t/info.t b/t/info.t index deaacb8..22b5b94 100755 --- a/t/info.t +++ b/t/info.t @@ -93,16 +93,13 @@ try " try " glt ls-remote u1 file:///foo/one; ok glt info u1 -lc; ok; GS u1 - put /C\tfoo/\\.\\.\\*/ !/C\tfoo.*u1/ /R W *\tfoo/one\tu1/ glt info u2 -lc; ok; GS u2 - put !/C\tfoo/ !/R W *\tfoo/one/ glt info u3 -lc; ok; GS u3 - put !/C\tfoo/ /R W *\tfoo/one\tu1/ "; From fa2893be7c45ac17bac6da570f3270f0e0210103 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 6 May 2012 19:15:28 +0530 Subject: [PATCH 029/158] the dupkeys function was already in ssh-authkeys... ...so there's no need for the VREF. Ironically, while I was arguing with Eli that I wouldn't do it and why, the code was *already* there, and had been for over a month! (It must have been there for much longer for me to have forgotten!) TODO: convert from using fingerprint compute to actual key strings when the complaints about speed start appearing. My own personal speed up loop [1] I guess :) [1]: http://thedailywtf.com/Articles/Classic-WTF-The-Speedup-Loop.aspx --- doc/vref.mkd | 8 +------- src/VREF/DUPKEYS | 45 --------------------------------------------- 2 files changed, 1 insertion(+), 52 deletions(-) delete mode 100755 src/VREF/DUPKEYS diff --git a/doc/vref.mkd b/doc/vref.mkd index ac6599b..5d86c03 100644 --- a/doc/vref.mkd +++ b/doc/vref.mkd @@ -16,12 +16,6 @@ Here's an example to start you off. Now dev2 and dev3 cannot push changes that affect more than 9 files at a time, nor those that have more than 3 new files. -Another example is detecting duplicate pubkeys in a push to the admin repo: - - repo gitolite-admin - # ... normal rules ... - - VREF/DUPKEYS = @all - ---- ## rule matching recap @@ -63,7 +57,7 @@ the VREF only in "deny" rules. This in turn means any existing update hook can be used as a VREF *as-is*, as long as it (a) prints nothing on success and (b) dies on failure. See the -email-check and dupkeys examples later. +email-check example later. ## how it works -- overview diff --git a/src/VREF/DUPKEYS b/src/VREF/DUPKEYS deleted file mode 100755 index 7e479fa..0000000 --- a/src/VREF/DUPKEYS +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# gitolite VREF to detect duplicate public keys - -# see gitolite doc/vref.mkd for what the arguments are -sha=$3 - -# git sets this; and we don't want it at this point... -unset GIT_DIR - -# paranoia -set -e - -# setup the temp area -export TMPDIR=$GL_REPO_BASE_ABS -export tmp=$(mktemp -d -t gl-internal-temp-repo.XXXXXXXXXX); -trap "rm -rf $tmp" EXIT; - -git archive $sha keydir | tar -C $tmp -xf - - # DO NOT try, say, 'GIT_WORK_TREE=$tmp git checkout $sha'. It'll screw up - # both the 'index' and 'HEAD' of the repo.git. Screwing up the index is - # BAD because now it goes out of sync with $GL_ADMINDIR. Think of a push - # that had a deleted pubkey but failed a hooklet for some reason. A - # subsequent push that fixes the error will now result in a $GL_ADMINDIR - # that still *has* that deleted pubkey!! - - # And this is equally applicable to cases where you're using a - # post-receive or similar hook to live update a web site or something, - # which is a pretty common usage, I am given to understand. - -cd $tmp - -for f in `find keydir -name "*.pub"` -do - ssh-keygen -l -f "$f" -done | perl -ane ' - die "FATAL: $F[2] is a duplicate of $seen{$F[1]}\n" if $seen{$F[1]}; - $seen{$F[1]} = $F[2]; -' - -# as you can see, a vref can also 'die' if it wishes to, and it'll take the -# whole update with it if it does. No messing around with sending back a -# vref, having it run through the matches, and printing the DENIED message, -# etc. However, if your push is running from a script, and that script is -# looking for the word "DENIED" or something, then this won't work... From e511943a45cdfc77b02896e2a43e8cf3bc3f49ac Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 10 May 2012 10:37:11 +0530 Subject: [PATCH 030/158] just for kicks, a VREF that allows voting on changes to a branch (manually smoke tested; no test script) I've been meaning to do this for a while, since someone told me that is one of gerrit's features they like. Of course, gitolite can't/won't do the whole "code review" thing (nor the workflow enforcement that follows). But voting is simple -- literally 2-3 lines of code in a VREF. (The rest is inline documentation). --- src/VREF/VOTES | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100755 src/VREF/VOTES diff --git a/src/VREF/VOTES b/src/VREF/VOTES new file mode 100755 index 0000000..bb6bf22 --- /dev/null +++ b/src/VREF/VOTES @@ -0,0 +1,80 @@ +#!/bin/bash + +# gitolite VREF to count votes before allowing pushes to certain branches. + +# This approximates gerrit's voting (but it is SHA based; I believe Gerrit is +# more "changeset" based). Here's how it works: + +# - A normal developer "bob" proposes changes to master by pushing a commit to +# "pers/bob/master", then informs the voting members by email. + +# - Some or all of the voting members fetch and examine the commit. If they +# approve, they "vote" for the commit like so. For example, say voting +# member "alice" fetched bob's proposed commit into "bob-master" on her +# clone, then tested or reviewed it. She would approve it by running: +# git push origin bob-master:votes/alice/master + +# - Once enough votes have been tallied (hopefully there is normal team +# communication that says "hey I approved your commit", or it can be checked +# by 'git ls-remote origin' anyway), Bob, or any developer, can push the +# same commit (same SHA) to master and the push will succeed. + +# - Finally, a "trusted" developer can push a commit to master without +# worrying about the voting restriction at all. + +# The config for this example would look like this: + +# repo foo +# # allow personal branches (to submit proposed changes) +# RW+ pers/USER/ = @devs +# - pers/ = @all +# +# # allow only voters to vote +# RW+ votes/USER/ = @voters +# - votes/ = @all +# +# # normal access rules go here; should allow *someone* to push master +# RW+ = @devs +# +# # 2 votes required to push master, but trusted devs don't have this restriction +# RW+ VREF/VOTES/2/master = @trusted-devs +# - VREF/VOTES/2/master = @devs + +# Note: "2 votes required to push master" means at least 2 refs matching +# "votes/*/master" have the same SHA as the one currently being pushed. + +# ---------------------------------------------------------------------- + +# see gitolite docs for what the first 7 arguments mean + +# inputs: +# arg-8 is a number; see below +# arg-9 is a simple branch name (i.e., "master", etc). Currently this code +# does NOT do vote counting for branch names with more than one component +# (like foo/bar). +# outputs (STDOUT) +# nothing +# exit status: +# always 0 + +die() { echo "$@" >&2; exit 1; } +[ -z "$8" ] && die "not meant to be run manually" + +ref=$1 +newsha=$3 +refex=$7 +votes_needed=$8 +branch=$9 + +# nothing to do if the branch being pushed is not "master" (using our example) +[ "$ref" = "refs/heads/$branch" ] || exit 0 + +# find how many votes have come in +votes=`git for-each-ref refs/heads/votes/*/$branch | grep -c $newsha` + +# send back a vref if we don't have the minimum votes needed. For trusted +# developers this will invoke the RW+ rule and pass anyway, but for others it +# will invoke the "-" rule and fail. +[ $votes -ge $votes_needed ] || echo $refex "require at least $votes_needed votes to push $branch" + +exit 0 From 17a680e0f67b129f98464e0434aa2ff1790af65b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 26 Apr 2012 06:38:04 +0530 Subject: [PATCH 031/158] (collected docfixes) --- doc/admin.mkd | 18 +++++++++++----- doc/clone.mkd | 19 +++++++++++++++++ doc/extras/ssh.mkd | 5 +++++ doc/install.mkd | 11 ++++++++++ doc/master-toc.mkd | 15 +++++++------ doc/qi.mkd | 52 +++++++++++++++++++++++----------------------- doc/setup.mkd | 11 +++++++--- doc/vref.mkd | 15 ++++++++----- 8 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 doc/clone.mkd diff --git a/doc/admin.mkd b/doc/admin.mkd index df3bdf2..47c3aeb 100644 --- a/doc/admin.mkd +++ b/doc/admin.mkd @@ -2,7 +2,8 @@ ## #server server-side administration -The following activities require command line access to the server: +The following activities require command line access to the server. They are +usually one-time or rarely done activities. * Changing anything in the [rc][] file. * Installing custom [hooks][], whether to all repos or just some repos. @@ -10,12 +11,19 @@ The following activities require command line access to the server: Please read the [WARNINGS][] page first. -## #conf access control (the gitolite.conf file) +## #adminrepo access control via the gitolite-admin repo + +Most day-to-day administration of a gitolite site happens like this: + + * [clone][] the gitolite-admin repo to your workstation + * make appropriate changes + * add, commit, and push + +### #conf the conf/gitolite.conf file Most of gitolite's power is in the conf/gitolite.conf file, which specifies -detailed access control for repos. - -### #confex example of a conf file +detailed access control for repos. Everything except [adding users][users] +happens from this file. Here is an example of a simple conf/gitolite.conf file. diff --git a/doc/clone.mkd b/doc/clone.mkd new file mode 100644 index 0000000..f51c2d0 --- /dev/null +++ b/doc/clone.mkd @@ -0,0 +1,19 @@ +# cloning the admin repo + +This is the third step in using gitolite, after [install][] and [setup][]. + +To clone the admin repo, go to the workstation where the public key used in +'setup' came from, and run this: + + git clone git@host:gitolite-admin + +NOTE that (1) you must not include the `repositories/` part (gitolite handles +that internally), and (2) you may include the ".git" at the end but it is +optional. + +If this step succeeds, you can add [users][], [repos][], or anything else +described [here][adminrepo]. + +If this step fails, be sure to look at the [ssh][] documentation before asking +for help. (A very basic first step is to run `ssh git@host info`; +[this][info] page tells you what to expect). diff --git a/doc/extras/ssh.mkd b/doc/extras/ssh.mkd index 1d7272f..fb51655 100644 --- a/doc/extras/ssh.mkd +++ b/doc/extras/ssh.mkd @@ -1,5 +1,10 @@ # ssh +If you're installing gitolite, you're a "system admin", like it or not. If +you're using the default ssh mode (i.e., not [http][] mode), ssh is a +necessary skill. Please take the time to learn at least enough to get +passwordless access working. + There are two documents you need to read, in order: * [Gitolite and ssh][glssh] explains how gitolite uses openssh features to diff --git a/doc/install.mkd b/doc/install.mkd index ad681ec..fb0348c 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -6,6 +6,11 @@ start [here][migr]. RTFM is *mandatory* for migrations. ---- +This is the first step in using gitolite, and happens on the server. It is +followed by [setup][], then [clone][]. + +---- + [[TOC]] ---- @@ -20,6 +25,9 @@ The real user used is called the **hosting user**. Typically this user is RPMs and DEBs create a user called *gitolite* for this, so adjust instructions and examples accordingly. +**Unless otherwise stated, everything in this page is to be done by logging in +as this "hosting user"**. + Notes: * Any unix user can be a hosting user. @@ -72,6 +80,9 @@ side. ## the actual install +**Note**: This section describes installing an ssh-based setup. For smart +http setup click [here][http]. + Gitolite has only one server side "command" now, much like git itself. This command is `gitolite`. You don't need to place it anywhere special; worst case you run it with the full path. diff --git a/doc/master-toc.mkd b/doc/master-toc.mkd index 39904ba..d244d2b 100644 --- a/doc/master-toc.mkd +++ b/doc/master-toc.mkd @@ -14,7 +14,7 @@ * [lost][lost-key] admin key/access * [bypass][]ing gitolite * [clean][]ing out a botched install - * [common][ce] errors (TBD) + * [common][ce] errors * [uncommon][ue] errors * things that are [not gitolite problems][ngp] @@ -43,16 +43,18 @@ ## [setup][] +## [clone][] + + ## gitolite [admin][]istration - * [server][]-side + * ([server-side][server]) settings, hooks, etc. * ([link][WARNINGS]: important cautions on server side activity) * changing settings in the [rc][] file * installing custom [hooks][] * ([link][existing]: moving existing repos into gitolite) - * [access control][conf] (the gitolite.conf file) - * [example][confex] of a conf file - * basic [syntax][] + * ([client-side][adminrepo]) access control via the gitolite-admin repo + * basic [syntax][] of the [conf][] file * include files * ([link][sugar]: syntactic sugar) * [groups][] (of users and repos) @@ -93,6 +95,7 @@ * [disabling pushes][writable] to take backups * [personal][pers] branches + * ([link][votes]: voting on commits) * [delegating][deleg] access control responsibilities * ([link][NAME]: the NAME VREF) * the [subconf][] command @@ -159,4 +162,4 @@ * log file format, LOG_EXTRA * hub * mob branches - * password access \ No newline at end of file + * password access diff --git a/doc/qi.mkd b/doc/qi.mkd index 2ac9470..90a83c2 100644 --- a/doc/qi.mkd +++ b/doc/qi.mkd @@ -1,25 +1,9 @@ # quick install, setup, and clone -(Please do not ignore the "assumptions" list below). - -On the server: - - # get the software - git clone git://github.com/sitaramc/gitolite - - # install it - gitolite/install -ln - - # setup the initial repos with your key - gitolite setup -pk your-name.pub - -On your workstation: - - # clone the admin repo so you can start adding stuff - git clone git@host:gitolite-admin.git - ## ASSUMPTIONS + * This is an ssh-based setup. For smart http setup click [here][http]. + * This is a fresh install, not a migration from the old gitolite (v1.x, v2.x). @@ -34,15 +18,31 @@ On your workstation: * If it does, please see [common errors][ce] and fix things before continuing, or read the more complete [setup][] page. -## Notes +## instructions -Note that the clone path is NOT "repositories/gitolite-admin.git". If you -clone with a path that includes "repositories/", the clone should fail. If -the clone *does* succeed, a subsequent push should fail :-) See -[this][ybpfail] for some details. If that doesn't make enough sense read all -of [ssh][]. +On the server, as the hosting user (e.g., 'git'): + + # get the software + git clone git://github.com/sitaramc/gitolite + + # install it + gitolite/install -ln + + # setup the initial repos with your key + gitolite setup -pk your-name.pub + +On your workstation: + + # clone the admin repo so you can start adding stuff + git clone git@host:gitolite-admin.git + # Note 1: clone path must not include "repositories/" + # Note 2: it may include the ".git" at the end but it is optional ## next steps -Next steps are usually adding [users][] and [repos][] and learning about -[access control][conf]. +If this step succeeds, you can add [users][], [repos][], or anything else +described [here][adminrepo]. + +If this step fails, be sure to look at the [ssh][] documentation before asking +for help. (A very basic first step is to run `ssh git@host info`; +[this][info] page tells you what to expect). diff --git a/doc/setup.mkd b/doc/setup.mkd index 17a238a..ef866c2 100644 --- a/doc/setup.mkd +++ b/doc/setup.mkd @@ -1,11 +1,16 @@ # setting up gitolite +This is the second step in using gitolite, after [install][]. This also +happens on the server, (The next step is [clone][]). + +---- + Installing the software gets you ready to use it, but the first "use" of it is always the "setup" command. -The first time you run it, you need to have a public key file ready. If the -main gitolite admin's username is "alice", this file should be named -"alice.pub". Then run +The first time you run it, you need to have a public key file (usually from +the admin's workstation) ready. If the main gitolite admin's username is +"alice", this file should be named "alice.pub". Then run gitolite setup -pk alice.pub diff --git a/doc/vref.mkd b/doc/vref.mkd index 5d86c03..6f7bd2f 100644 --- a/doc/vref.mkd +++ b/doc/vref.mkd @@ -6,6 +6,10 @@ who stop reading halfway! ---- +[[TOC]] + +---- + Here's an example to start you off. repo r1 @@ -262,12 +266,13 @@ copied to `src/VREF/EMAIL-CHECK` and it works, because VREFs get the same first 3 arguments and those are all that it cares about. (Note: you have to change one subroutine in that script if you want to use it) -### catching duplicate pubkeys +### #votes voting on commits -This checks keydir/ for duplicate keys and aborts the push if it finds any. -You should use this only on the gitolite-admin repo. - -We covered this as a teaser example at the start. +Although gitolite can't/won't do the whole "code review + workflow +enforcement" thing that Gerrit Code Review does, a basic implementation of +voting on a commit is surprisingly easy. See src/VREF/VOTES for details (and +note that the actual *code* is just 2-3 lines; the rest is inline +documentation). ## other ideas -- code welcome! From bc3eb3421171a432aa62d784709d0b0e319de183 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 14 May 2012 14:32:13 +0530 Subject: [PATCH 032/158] simulate POST_CREATE for newly created "normal" repos See "background" in new program src/triggers/new-normal-repos --- src/triggers/new-normal-repos | 55 +++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100755 src/triggers/new-normal-repos diff --git a/src/triggers/new-normal-repos b/src/triggers/new-normal-repos new file mode 100755 index 0000000..7e66509 --- /dev/null +++ b/src/triggers/new-normal-repos @@ -0,0 +1,55 @@ +#!/bin/sh + +# run some command on every new repo created via the conf file +# ---------------------------------------------------------------------- + +# BACKGROUND +# The POST_CREATE trigger (see doc/triggers.mkd) only works for repos that a +# user creates (see doc/wild.mkd). It does NOT work for repos created +# normally using the conf file. The POST_COMPILE trigger sequence should +# normally be used to trigger anything to happen after a compile. +# +# I have not seen a sane use case for a POST_CREATE trigger when a new repo +# is created via the conf file. (I do not consider "all new repos should +# have a default set of branches" to be a sane requirement). However, on +# the off-chance that something turns up at some future time, here's how you +# can do this without touching the core gitolite code. + +# INSTRUCTIONS FOR USE +# - (optional) rename this to whatever you want +# - change the 'post_create_normal' function below to do whatever you want it +# to do, or make it call some other command to do it +# - make the script executable +# - add 'new-normal-repos' (or whatever you renamed it to) to the PRE_GIT and +# the POST_COMPILE trigger lists in the rc file + +post_create_normal() { + echo "post_create_normal called with repo '$1'" >&2 +} + +# tempfile prefix; if you really care, change this also, otherwise leave it alone +tfp=$HOME/.tmp.$GL_USER.list-repos + +# ---------------------------------------------------------------------- + +if [ "$1" = "PRE_GIT" ] +then + # unless someone is pushing to the admin repo, we don't care + [ "$2" = "gitolite-admin" ] || exit 0 + [ "$4" = "W" ] || exit 0 + + # save the list of repos + gitolite list-repos > $tfp.1 +elif [ "$1" = "POST_COMPILE" ] +then + # get the new list of repos and compare with the one PRE_GIT created + gitolite list-repos > $tfp.2 + for repo in `grep -x -f $tfp.1 -v $tfp.2` + do + + post_create_normal "$repo" + done +else + # if you edited your rc file correctly, this line should never be reached + echo "ignoring call to" `basename $0` "with arg1 = '$1'" >&2 +fi From 07169c37ec9abfa7ebd31d745564586bf64fc019 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 9 May 2012 05:56:40 +0530 Subject: [PATCH 033/158] allow aliasing a repo to another name all documentation is inside Alias.pm. --- src/lib/Gitolite/Triggers/Alias.pm | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 src/lib/Gitolite/Triggers/Alias.pm diff --git a/src/lib/Gitolite/Triggers/Alias.pm b/src/lib/Gitolite/Triggers/Alias.pm new file mode 100755 index 0000000..a00b385 --- /dev/null +++ b/src/lib/Gitolite/Triggers/Alias.pm @@ -0,0 +1,81 @@ +package Gitolite::Triggers::Alias; + +use Gitolite::Rc; +use Gitolite::Common; +use Gitolite::Conf::Load; + +use strict; +use warnings; + +# aliasing a repo to another +# ---------------------------------------------------------------------- + +=for usage + +Why: + + We had an existing repo "foo" that lots of people use. We wanted to + rename it to "foo/code", so that related repos "foo/upstream" and + "foo/docs" (both containing stuff we did not want to put in "foo") could + also be made and then the whole thing would be structured nicely. + + At the same time we did not want to *force* all the users to change the + name. At least git operations should still work with the old name, + although it is OK for "info" and other "commands" to display/require the + proper name (i.e., the new name). + +How: + + * add a new variable REPO_ALIASES to the rc file, with entries like: + + REPO_ALIASES => + { + 'foo' => 'foo/code', + } + + * add the following line to the INPUT section in the rc file: + + 'Alias::input', + +Notes: + + * only git operations (clone/fetch/push) are alias aware. Nothing else in + gitolite, such as all the gitolite commands etc., are alias-aware and will + always use/require the proper repo name. + + * http mode has not been tested and will not be. If someone has the time to + test it and make it work please let me know. + + * funnily enough, this even works with mirroring! That is, a master can + push a repo "foo" to a slave per its configuration, while the slave thinks + it is getting repo "bar" from the master per its configuration. + + Just make sure to put the Alias::input line *before* the Mirroring::input + line in the rc file on the slave. + + However, it will probably not work with redirected pushes unless you setup + the opposite alias ("bar" -> "foo") on master. +=cut + +sub input { + my $git_commands = "git-upload-pack|git-receive-pack|git-upload-archive"; + my $user = $ARGV[0] || '@all'; # user name is undocumented for now + + if ( $ENV{SSH_ORIGINAL_COMMAND} =~ /(?:$git_commands) '(\S+)'$/ ) { + my $repo = $1; + ( my $norm = $repo ) =~ s/\.git$//; # normalised repo name + + my $target; + + return unless $target = $rc{REPO_ALIASES}{$norm}; + $target = $target->{$user} if ref($target) eq 'HASH'; + return unless $target; + + _warn "'$norm' is an alias for '$target'"; + + $ENV{SSH_ORIGINAL_COMMAND} =~ s/'$repo'/'$target'/; + } + +} + +1; From 864469050696fbff1581607a9203288f09247c31 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 18 May 2012 12:48:51 +0530 Subject: [PATCH 034/158] (ssh) make it easier to make give some users a full shell --- doc/extras/sts.mkd | 21 +++++++------ .../post-compile/ssh-authkeys-shell-users | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) create mode 100755 src/triggers/post-compile/ssh-authkeys-shell-users diff --git a/doc/extras/sts.mkd b/doc/extras/sts.mkd index 9252d58..843f679 100644 --- a/doc/extras/sts.mkd +++ b/doc/extras/sts.mkd @@ -151,20 +151,23 @@ Done? OK, now the general outline for ssh troubleshooting is this: Thanks to an idea from Jesse Keating, a single key can allow both gitolite access *and* shell access. -This is done by manually prefixing the username with "-s" as an extra argument -in the "command=" part of `~/.ssh/authorized_keys`. For example +To do this: - command="/home/g3/gitolite/src/gitolite-shell u1",no-port-[...etc...] + * add the list of users who will have shell access -- one username per line, + no extra whitespace -- to a plain text file of your choice. -should be edited to be + * put the name of this file in a new rc variable `SHELL_USERS_LIST`. For + example it could be - command="/home/g3/gitolite/src/gitolite-shell -s u1",no-port-[...etc...] + SHELL_USERS_LIST => "$ENV{HOME}/.gitolite.shell-users", -and moved out of the gitolite area of the authkeys file. + * add the line `'Shell::input',` to the `INPUT` list in the rc file. -It should be easy to make src/triggers/post-compile/ssh-authkeys read a list -of shell capable users from some file on the server and put in the "-s" for -those users. Patches welcome. + * add the line `'post-compile/ssh-authkeys-shell-users',` to the + `POST_COMPILE` list, *after* the `'post-compile/ssh-authkeys',` line. + +Then run `gitolite compile; gitolite trigger POST_COMPILE` or push a dummy +change to the admin repo. #### simulating ssh-copy-id diff --git a/src/triggers/post-compile/ssh-authkeys-shell-users b/src/triggers/post-compile/ssh-authkeys-shell-users new file mode 100755 index 0000000..91ed857 --- /dev/null +++ b/src/triggers/post-compile/ssh-authkeys-shell-users @@ -0,0 +1,31 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use File::Temp qw(tempfile); + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Rc; +use Gitolite::Common; + +$|++; + +my $akfile = "$ENV{HOME}/.ssh/authorized_keys"; +my $sufile = $rc{SHELL_USERS_LIST} or exit 0; +-r $sufile or _die "'$sufile' not readable"; + +# ---------------------------------------------------------------------- + +my $aktext = slurp($akfile); + +for my $su ( shell_users() ) { + $aktext =~ s(/gitolite-shell $su",(.*?),no-pty )(/gitolite-shell -s $su",$1 ); +} + +_print( $akfile, $aktext ); + +sub shell_users { + my @ret = grep { not /^#/ } slurp($sufile); + chomp(@ret); + return @ret; +} From 27c0190b7616779798d46e34841a3e6b2bd6066c Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 20 May 2012 06:20:21 +0530 Subject: [PATCH 035/158] packaging instructions make analogy with git for better explanation --- doc/install.mkd | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/doc/install.mkd b/doc/install.mkd index fb0348c..25e7cbe 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -131,26 +131,44 @@ Creating a symlink doesn't need a separate program but 'install' also runs arguments as before). * Run `gitolite setup`. -## packaging gitolite +## #package packaging gitolite -Here are the requirements for gitolite: +Gitolite has broad similarities to git in terms of packaging requirements. - * The programs `gitolite` and `gitolite-shell`, and the directories - `commands`, `lib`, `syntactic-sugar`, `triggers`, and `VREF` must all be - in the same directory. + * Git has 150 executables to marshal and put somewhere. Gitolite has the + directories `commands`, `lib`, `syntactic-sugar`, `triggers`, and `VREF`. It doesn't matter what this directory is. As an example, Fedora keeps git's 150 executables in /usr/libexec/git-core, so /usr/libexec/gitolite may be a good choice; it's upto you. - The rest of this section will assume you chose /usr/libexec/gitolite as - the location. Adjust as needed. + *The rest of this section will assume you chose /usr/libexec/gitolite as + the location, and that this location contains the 5 directories named + above*. - * The program `/usr/libexec/gitolite/gitolite` must then be *symlinked* to - some directory in the PATH. Do not *copy* it; it must be a symlink. + * Git has the `GIT_EXEC_PATH` env var to point to this directory. Gitolite + has `GL_BINDIR`. However, in git, the "make" process embeds a suitable + default into the binary, making the env var optional. - * The `Gitolite` subdirectory in `/usr/libexec/gitolite/lib` can stay there, - **OR**, if your distro policies don't allow that, can be put in any +With that said, here's one way to package gitolite: + + * Put the two executables (gitolite and gitolite-shell) somewhere in PATH. + Then change the 2 assignments to `$ENV{GL_BINDIR}`, one in 'gitolite', one + in 'gitolite-shell', to "/usr/libexec/gitolite". + + This is equivalent to "make" embedding the exec-path into the executable. + + **OR** + + Put the two executables `gitolite` and `gitolite-shell` also into + /usr/libexec/gitolite (i.e., as siblings to the 5 directories mentioned + above). Then *symlink* `/usr/libexec/gitolite/gitolite` to some directory + in the PATH. Do not *copy* it; it must be a symlink. + + Gitolite will find the exec-path by following the symlink. + + * The `Gitolite` subdirectory in `/usr/libexec/gitolite/lib` can stay right + there, **OR**, if your distro policies don't allow that, can be put in any directory in perl's `@INC` path (such as `/usr/share/perl5/vendor_perl`). * Finally, a file called `/usr/libexec/gitolite/VERSION` must contain a From 72b6a54e0a67e4a2cde6da59ff051a9bfaa7c791 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 20 May 2012 10:07:29 +0530 Subject: [PATCH 036/158] test packaging instructions and make required changes --- doc/install.mkd | 9 +++++---- src/lib/Gitolite/Hooks/PostUpdate.pm | 4 ++-- src/lib/Gitolite/Setup.pm | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/install.mkd b/doc/install.mkd index 25e7cbe..519ab52 100644 --- a/doc/install.mkd +++ b/doc/install.mkd @@ -152,15 +152,16 @@ Gitolite has broad similarities to git in terms of packaging requirements. With that said, here's one way to package gitolite: - * Put the two executables (gitolite and gitolite-shell) somewhere in PATH. - Then change the 2 assignments to `$ENV{GL_BINDIR}`, one in 'gitolite', one - in 'gitolite-shell', to "/usr/libexec/gitolite". + * Put the executable `gitolite` somewhere in PATH. Put the executable + `gitolite-shell` in /usr/libexec/gitolite (along with those 5 directories). + Change the 2 assignments to `$ENV{GL_BINDIR}`, one in 'gitolite', one in + 'gitolite-shell', to "/usr/libexec/gitolite" from `$FindBin::RealBin`. This is equivalent to "make" embedding the exec-path into the executable. **OR** - Put the two executables `gitolite` and `gitolite-shell` also into + Put both executables `gitolite` and `gitolite-shell` also into /usr/libexec/gitolite (i.e., as siblings to the 5 directories mentioned above). Then *symlink* `/usr/libexec/gitolite/gitolite` to some directory in the PATH. Do not *copy* it; it must be a symlink. diff --git a/src/lib/Gitolite/Hooks/PostUpdate.pm b/src/lib/Gitolite/Hooks/PostUpdate.pm index 70e23f8..9013ee9 100644 --- a/src/lib/Gitolite/Hooks/PostUpdate.pm +++ b/src/lib/Gitolite/Hooks/PostUpdate.pm @@ -29,8 +29,8 @@ sub post_update { local $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE}; tsh_try("git checkout -f --quiet master"); } - _system("$ENV{GL_BINDIR}/gitolite compile"); - _system("$ENV{GL_BINDIR}/gitolite trigger POST_COMPILE"); + _system("gitolite compile"); + _system("gitolite trigger POST_COMPILE"); exit 0; } diff --git a/src/lib/Gitolite/Setup.pm b/src/lib/Gitolite/Setup.pm index 0a677a8..1077c0e 100644 --- a/src/lib/Gitolite/Setup.pm +++ b/src/lib/Gitolite/Setup.pm @@ -46,8 +46,8 @@ sub setup { setup_glrc(); setup_gladmin( $admin, $pubkey, $argv ); - _system("$ENV{GL_BINDIR}/gitolite compile"); - _system("$ENV{GL_BINDIR}/gitolite trigger POST_COMPILE"); + _system("gitolite compile"); + _system("gitolite trigger POST_COMPILE"); hook_repos(); # all of them, just to be sure } From 8aba6ec2be3d2263e2bbd8d3620e62c8f8022048 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 20 May 2012 16:41:21 +0530 Subject: [PATCH 037/158] v3.02 --- doc/CHANGELOG | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 10c045c..8271e04 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -1,3 +1,19 @@ +2012-05-20 v3.02 packaging instructions fixed up and smoke tested + + make it easier to give some users a full shell + + allow aliasing a repo to another name + + simulate POST_CREATE for new normal (non-wild) repos + + (just for kicks) a VREF that allows for voting on changes + to a branch + + bug fix: smart http was not running PRE_ and POST_GIT + triggers + + htpasswd migrated + 2012-04-29 v3.01 mostly BSD and Solaris compat also fork command added From 3a59f5aff0f68b4836bde537d169dc3552e381b4 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 21 May 2012 13:23:20 +0530 Subject: [PATCH 038/158] line up regexes for easier review --- src/lib/Gitolite/Rc.pm | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 924fe3f..55cda82 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -43,12 +43,15 @@ $rc{LOG_TEMPLATE} = "$ENV{HOME}/.gitolite/logs/gitolite-%y-%m.log"; # variables that should probably never be changed but someone will want to, I'll bet... # ---------------------------------------------------------------------- -$REMOTE_COMMAND_PATT = qr(^[- 0-9a-zA-Z\@\%_=+:,./]*$); -$REF_OR_FILENAME_PATT = qr(^[0-9a-zA-Z][0-9a-zA-Z._\@/+ :,-]*$); -$REPONAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@/+-]*$); -$REPOPATT_PATT = qr(^\@?[0-9a-zA-Z[][\\^.$|()[\]*+?{}0-9a-zA-Z._\@/,-]*$); -$USERNAME_PATT = qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$); +#<<< +$REMOTE_COMMAND_PATT = qr(^[-0-9a-zA-Z._\@/+ :,\%=]*$); +$REF_OR_FILENAME_PATT = qr(^[0-9a-zA-Z][-0-9a-zA-Z._\@/+ :,]*$); +$REPONAME_PATT = qr(^\@?[0-9a-zA-Z][-0-9a-zA-Z._\@/+]*$); +$REPOPATT_PATT = qr(^\@?[[0-9a-zA-Z][-0-9a-zA-Z._\@/+\\^$|()[\]*?{},]*$); +$USERNAME_PATT = qr(^\@?[0-9a-zA-Z][-0-9a-zA-Z._\@+]*$); + $UNSAFE_PATT = qr([`~#\$\&()|;<>]); +#>>> # ---------------------------------------------------------------------- From 20d2120ea5578a9f72bf85c42f2969eb32940a64 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 21 May 2012 15:20:04 +0530 Subject: [PATCH 039/158] move input command check so it works for non-ssh modes also --- src/gitolite-shell | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gitolite-shell b/src/gitolite-shell index af03a36..c4463ad 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -31,6 +31,12 @@ if ( exists $ENV{G3T_USER} ) { _die "who the *heck* are you?"; } +# sanity... +my $soc = $ENV{SSH_ORIGINAL_COMMAND}; +$soc =~ s/[\n\r]+/<>/g; +_die "I don't like newlines in the command: '$soc'\n" if $ENV{SSH_ORIGINAL_COMMAND} ne $soc; + +# the INPUT trigger massages @ARGV and $ENV{SSH_ORIGINAL_COMMAND} as needed trigger('INPUT'); main($id); @@ -75,9 +81,6 @@ sub in_ssh { gl_log( 'ssh', "ARGV=" . join( ",", @ARGV ), "SOC=" . ( $ENV{SSH_ORIGINAL_COMMAND} || '' ), "FROM=$ip" ); $ENV{SSH_ORIGINAL_COMMAND} ||= ''; - my $soc = $ENV{SSH_ORIGINAL_COMMAND}; - $soc =~ s/[\n\r]+/<>/g; - _die "I don't like newlines in the command: $soc\n" if $ENV{SSH_ORIGINAL_COMMAND} ne $soc; return $ip; } From d04e79d291c832c14cbcc94e5e813d9b3ed8c1af Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 21 May 2012 15:22:19 +0530 Subject: [PATCH 040/158] (minor) single quotes around variables in error messages (plus a couple of other minor fixups) --- src/gitolite | 2 +- src/gitolite-shell | 2 +- src/lib/Gitolite/Conf.pm | 2 +- src/lib/Gitolite/Conf/Explode.pm | 4 ++-- src/lib/Gitolite/Conf/Load.pm | 8 ++++---- src/lib/Gitolite/Conf/Store.pm | 2 +- src/lib/Gitolite/Hooks/Update.pm | 4 ++-- src/lib/Gitolite/Rc.pm | 6 +++--- src/lib/Gitolite/Setup.pm | 10 +++++----- src/triggers/post-compile/ssh-authkeys | 10 +++++----- t/fork.t | 2 +- t/git-config.t | 2 +- t/include-subconf.t | 2 +- t/invalid-refnames-filenames.t | 6 +++--- t/ssh-authkeys.t | 4 ++-- 15 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/gitolite b/src/gitolite index 911eee9..aeca6af 100755 --- a/src/gitolite +++ b/src/gitolite @@ -103,7 +103,7 @@ sub args { sub run_command { my $pgm = shift; my $fullpath = "$ENV{GL_BINDIR}/commands/$pgm"; - _die "$pgm not found or not executable" if not -x $fullpath; + _die "'$pgm' not found or not executable" if not -x $fullpath; _system( $fullpath, @_ ); exit 0; } diff --git a/src/gitolite-shell b/src/gitolite-shell index c4463ad..a40611b 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -161,7 +161,7 @@ sub parse_soc { exit 0; } - _die "unknown git/gitolite command: $soc"; + _die "unknown git/gitolite command: '$soc'"; } sub sanity { diff --git a/src/lib/Gitolite/Conf.pm b/src/lib/Gitolite/Conf.pm index a5bda56..8d8c82f 100644 --- a/src/lib/Gitolite/Conf.pm +++ b/src/lib/Gitolite/Conf.pm @@ -62,7 +62,7 @@ sub parse { my @validkeys = split( ' ', ( $rc{GIT_CONFIG_KEYS} || '' ) ); push @validkeys, "gitolite-options\\..*"; my @matched = grep { $key =~ /^$_$/ } @validkeys; - _die "git config $key not allowed\ncheck GIT_CONFIG_KEYS in the rc file" if ( @matched < 1 ); + _die "git config '$key' not allowed\ncheck GIT_CONFIG_KEYS in the rc file" if ( @matched < 1 ); _die "bad value '$value'" if $value =~ $UNSAFE_PATT; add_config( 1, $key, $value ); } elsif ( $line =~ /^subconf (\S+)$/ ) { diff --git a/src/lib/Gitolite/Conf/Explode.pm b/src/lib/Gitolite/Conf/Explode.pm index f72878b..03f2cb2 100644 --- a/src/lib/Gitolite/Conf/Explode.pm +++ b/src/lib/Gitolite/Conf/Explode.pm @@ -52,7 +52,7 @@ sub incsub { my $is_subconf = ( +shift eq 'subconf' ); my ( $new_subconf, $include_glob, $current_subconf, $out ) = @_; - _die "subconf $current_subconf attempting to run 'subconf'\n" if $is_subconf and $current_subconf ne 'master'; + _die "subconf '$current_subconf' attempting to run 'subconf'\n" if $is_subconf and $current_subconf ne 'master'; _die "invalid include/subconf file/glob '$include_glob'" unless $include_glob =~ /^"(.+)"$/ @@ -63,7 +63,7 @@ sub incsub { for my $file ( glob($include_glob) ) { _warn("included file not found: '$file'"), next unless -f $file; - _die "invalid include/subconf filename $file" unless $file =~ m(([^/]+).conf$); + _die "invalid include/subconf filename '$file'" unless $file =~ m(([^/]+).conf$); my $basename = $1; next if already_included($file); diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 7599727..3537c4f 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -73,7 +73,7 @@ sub access { load($repo); # sanity check the only piece the user can control - _die "invalid characters in ref or filename: $ref\n" unless $ref =~ $REF_OR_FILENAME_PATT; + _die "invalid characters in ref or filename: '$ref'\n" unless $ref =~ $REF_OR_FILENAME_PATT; # when a real repo doesn't exist, ^C is a pre-requisite for any other # check to give valid results. @@ -193,11 +193,11 @@ sub load_common { my $cc = "conf/gitolite.conf-compiled.pm"; - _die "parse $cc failed: " . ( $! or $@ ) unless do $cc; + _die "parse '$cc' failed: " . ( $! or $@ ) unless do $cc; if ( data_version_mismatch() ) { _system("gitolite setup"); - _die "parse $cc failed: " . ( $! or $@ ) unless do $cc; + _die "parse '$cc' failed: " . ( $! or $@ ) unless do $cc; _die "data version update failed; this is serious" if data_version_mismatch(); } } @@ -223,7 +223,7 @@ sub load_1 { _warn "split conf not set, gl-conf present for '$repo'" if not $split_conf{$repo}; my $cc = "gl-conf"; - _die "parse $cc failed: " . ( $! or $@ ) unless do $cc; + _die "parse '$cc' failed: " . ( $! or $@ ) unless do $cc; $last_repo = $repo; $repos{$repo} = $one_repo{$repo}; diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index ef5b0fd..4eb3c67 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -137,7 +137,7 @@ sub expand_list { for my $item (@list) { if ( $item =~ /^@/ and $item ne '@all' ) # nested group { - _die "undefined group $item" unless $groups{$item}; + _die "undefined group '$item'" unless $groups{$item}; # add those names to the list push @new_list, sort keys %{ $groups{$item} }; } else { diff --git a/src/lib/Gitolite/Hooks/Update.pm b/src/lib/Gitolite/Hooks/Update.pm index ed4a03f..6d3844d 100644 --- a/src/lib/Gitolite/Hooks/Update.pm +++ b/src/lib/Gitolite/Hooks/Update.pm @@ -62,9 +62,9 @@ sub check_vrefs { } else { my ( $dummy, $pgm, @args ) = split '/', $vref; $pgm = "$ENV{GL_BINDIR}/VREF/$pgm"; - -x $pgm or _die "$vref: helper program missing or unexecutable"; + -x $pgm or _die "'$vref': helper program missing or unexecutable"; - open( my $fh, "-|", $pgm, @_, $vref, @args ) or _die "$vref: can't spawn helper program: $!"; + open( my $fh, "-|", $pgm, @_, $vref, @args ) or _die "'$vref': can't spawn helper program: $!"; while (<$fh>) { # print non-vref lines and skip processing (for example, # normal STDOUT by a normal update hook) diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 55cda82..3bcac33 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -63,7 +63,7 @@ my $rc = glrc('filename'); do $rc if -r $rc; if ( defined($GL_ADMINDIR) ) { say2 ""; - say2 "FATAL: $rc seems to be for older gitolite; please see doc/g2migr.mkd\n" . "(online at http://sitaramc.github.com/gitolite/g3/g2migr.html)"; + say2 "FATAL: '$rc' seems to be for older gitolite; please see doc/g2migr.mkd\n" . "(online at http://sitaramc.github.com/gitolite/g2migr.html)"; exit 1; } @@ -132,7 +132,7 @@ sub glrc { } elsif ( $cmd eq 'current-data-version' ) { return $current_data_version; } else { - _die "unknown argument to glrc: $cmd"; + _die "unknown argument to glrc: '$cmd'"; } } @@ -178,7 +178,7 @@ sub trigger { if ( exists $rc{$rc_section} ) { if ( ref( $rc{$rc_section} ) ne 'ARRAY' ) { - _die "$rc_section section in rc file is not a perl list"; + _die "'$rc_section' section in rc file is not a perl list"; } else { for my $s ( @{ $rc{$rc_section} } ) { my ( $pgm, @args ) = split ' ', $s; diff --git a/src/lib/Gitolite/Setup.pm b/src/lib/Gitolite/Setup.pm index 1077c0e..3fca752 100644 --- a/src/lib/Gitolite/Setup.pm +++ b/src/lib/Gitolite/Setup.pm @@ -69,11 +69,11 @@ sub args { usage() if $help or ( $pubkey and $admin ); if ($pubkey) { - $pubkey =~ /\.pub$/ or _die "$pubkey name does not end in .pub"; - $pubkey =~ /\@/ and _die "$pubkey name contains '\@'"; - tsh_try("cat $pubkey") or _die "$pubkey not a readable file"; - tsh_lines() == 1 or _die "$pubkey must have exactly one line"; - tsh_try("ssh-keygen -l -f $pubkey") or _die "$pubkey does not seem to be a valid ssh pubkey file"; + $pubkey =~ /\.pub$/ or _die "'$pubkey' name does not end in .pub"; + $pubkey =~ /\@/ and _die "'$pubkey' name contains '\@'"; + tsh_try("cat $pubkey") or _die "'$pubkey' not a readable file"; + tsh_lines() == 1 or _die "'$pubkey' must have exactly one line"; + tsh_try("ssh-keygen -l -f $pubkey") or _die "'$pubkey' does not seem to be a valid ssh pubkey file"; $admin = $pubkey; $admin =~ s(.*/)(); diff --git a/src/triggers/post-compile/ssh-authkeys b/src/triggers/post-compile/ssh-authkeys index 450144c..7afd3af 100755 --- a/src/triggers/post-compile/ssh-authkeys +++ b/src/triggers/post-compile/ssh-authkeys @@ -53,16 +53,16 @@ if (@gl_keys) { my $out = join( "\n", @non_gl, "# gitolite start", @gl_keys, "# gitolite end" ) . "\n"; my $ak = slurp($akfile); - _die "$akfile changed between start and end of this program!" if $ak ne $old_ak; + _die "'$akfile' changed between start and end of this program!" if $ak ne $old_ak; _print( $akfile, $out ); } # ---------------------------------------------------------------------- sub sanity { - _die "$glshell not found; this should NOT happen..." if not -f $glshell; - _die "$glshell found but not readable; this should NOT happen..." if not -r $glshell; - _die "$glshell found but not executable; this should NOT happen..." if not -x $glshell; + _die "'$glshell' not found; this should NOT happen..." if not -f $glshell; + _die "'$glshell' found but not readable; this should NOT happen..." if not -r $glshell; + _die "'$glshell' found but not executable; this should NOT happen..." if not -x $glshell; _warn "$akdir missing; creating a new one" if not -d $akdir; _warn "$akfile missing; creating a new one" if not -f $akfile; @@ -103,7 +103,7 @@ sub fp_file { my $f = shift; my $fp = `ssh-keygen -l -f '$f'`; chomp($fp); - _die "fingerprinting failed for $f" unless $fp =~ /([0-9a-f][0-9a-f](:[0-9a-f][0-9a-f])+)/; + _die "fingerprinting failed for '$f'" unless $fp =~ /([0-9a-f][0-9a-f](:[0-9a-f][0-9a-f])+)/; $fp = $1; return $fp; } diff --git a/t/fork.t b/t/fork.t index 38cb200..d595847 100755 --- a/t/fork.t +++ b/t/fork.t @@ -29,7 +29,7 @@ try " 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/ + glt fork u1 foo/u1/u1a foo/u1/u1a2; !ok; /FATAL: unknown git/gitolite command: \\'fork/ "; # allow fork as a valid command diff --git a/t/git-config.t b/t/git-config.t index 18f2e78..86a3a7b 100755 --- a/t/git-config.t +++ b/t/git-config.t @@ -26,7 +26,7 @@ confreset;confadd ' try "ADMIN_PUSH set1; /FATAL/" or die text(); try " - /git config foo.bar not allowed/ + /git config \\'foo.bar\\' not allowed/ /check GIT_CONFIG_KEYS in the rc file/ "; diff --git a/t/include-subconf.t b/t/include-subconf.t index 6bdff81..813cb93 100755 --- a/t/include-subconf.t +++ b/t/include-subconf.t @@ -78,7 +78,7 @@ confadd 'g2.conf', ' '; try " - ADMIN_PUSH set3; ok; /FATAL: subconf g2 attempting to run 'subconf'/ + ADMIN_PUSH set3; ok; /FATAL: subconf \\'g2\\' attempting to run 'subconf'/ "; # ---------------------------------------------------------------------- diff --git a/t/invalid-refnames-filenames.t b/t/invalid-refnames-filenames.t index d3a3065..bf4fabe 100755 --- a/t/invalid-refnames-filenames.t +++ b/t/invalid-refnames-filenames.t @@ -50,7 +50,7 @@ glt push u1 origin 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/ + /invalid characters in ref or filename: \\'refs/heads/dd=ee/ reject "; @@ -84,7 +84,7 @@ glt push u1 origin HEAD tc aa=bb glt push u1 origin HEAD /To file:///aa/ - /invalid characters in ref or filename: VREF/NAME/aa=bb/ + /invalid characters in ref or filename: \\'VREF/NAME/aa=bb/ reject # push to branch dd,ee ok @@ -96,6 +96,6 @@ glt push u1 origin 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/ + /invalid characters in ref or filename: \\'refs/heads/dd=ee/ reject "; diff --git a/t/ssh-authkeys.t b/t/ssh-authkeys.t index 9a897ca..a9b1457 100755 --- a/t/ssh-authkeys.t +++ b/t/ssh-authkeys.t @@ -60,11 +60,11 @@ try " # a bad key ls -al > bad.pub - $pgm; !ok; /fingerprinting failed for keydir/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/ + $pgm; !ok; /fingerprinting failed for \\'keydir/bad.pub\\'/ wc < $ak; ok; /^ *9 .*/; # till the bad key is removed rm bad.pub From b12a9672724d6d3893c50419e353309f645b8d36 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 21 May 2012 20:41:11 +0530 Subject: [PATCH 041/158] update g2 compat and migr info thanks to karihre on #gitolite for catching the first of the corrections (GL_GET_MEMBERSHIPS_PGM) and so reminding me... --- check-g2-compat | 7 +++---- doc/dev-status.mkd | 3 ++- doc/g2incompat.mkd | 2 +- doc/g2migr-example.mkd | 2 +- doc/g2migr.mkd | 3 +-- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/check-g2-compat b/check-g2-compat index 58c6b2f..11fe7a7 100755 --- a/check-g2-compat +++ b/check-g2-compat @@ -39,7 +39,7 @@ sub intro { msg( '' => "It does NOT attempt to catch all the differences described in the docs." ); msg( '', '' ); msg( INFO => "'see docs' usually means doc/g2migr.mkd" ); - msg( '', => "(online at http://sitaramc.github.com/gitolite/g3/g2migr.html)" ); + msg( '', => "(online at http://sitaramc.github.com/gitolite/g2migr.html)" ); msg( '', '' ); } @@ -54,14 +54,13 @@ sub rc_basic { sub rest_of_rc { msg( SEVERE => "GIT_PATH found; see docs" ) if $GIT_PATH; msg( SEVERE => "GL_ALL_INCLUDES_SPECIAL found; see docs" ) if $GL_ALL_INCLUDES_SPECIAL; - msg( SEVERE => "GL_GET_MEMBERSHIPS_PGM not yet implemented" ) if $GL_GET_MEMBERSHIPS_PGM; msg( SEVERE => "GL_NO_CREATE_REPOS not yet implemented" ) if $GL_NO_CREATE_REPOS; - msg( SEVERE => 'htpasswd, rsync, and svnserve not yet implemented' ) if $HTPASSWD_FILE or $RSYNC_BASE or $SVNSERVE; + msg( SEVERE => "rsync not yet implemented" ) if $RSYNC_BASE; msg( WARNING => "ADMIN_POST_UPDATE_CHAINS_TO found; see docs" ) if $ADMIN_POST_UPDATE_CHAINS_TO; msg( WARNING => "GL_NO_DAEMON_NO_GITWEB found; see docs" ) if $GL_NO_DAEMON_NO_GITWEB; msg( WARNING => "GL_NO_SETUP_AUTHKEYS found; see docs" ) if $GL_NO_SETUP_AUTHKEYS; msg( WARNING => "UPDATE_CHAINS_TO found; see docs" ) if $UPDATE_CHAINS_TO; - msg( WARNING => "GL_ADC_PATH found; many ADCs not yet implemented" ) if $GL_ADC_PATH; + msg( WARNING => "GL_ADC_PATH found; see docs" ) if $GL_ADC_PATH; msg( WARNING => "non-default GL_WILDREPOS_PERM_CATS found" ) if $GL_WILDREPOS_PERM_CATS ne 'READERS WRITERS'; } diff --git a/doc/dev-status.mkd b/doc/dev-status.mkd index 03ef93f..6d40949 100644 --- a/doc/dev-status.mkd +++ b/doc/dev-status.mkd @@ -10,7 +10,7 @@ Help needed: * I'd like distro packagers to play with it and help with migration advice for distro-upgrades - * rsync, htpasswd + * rsync * git-annexe support (but this has a pre-requisite in the previous list) Won't be done unless someone asks (saw no evidence that anyone used them in g2 @@ -33,3 +33,4 @@ Done: * migration advice for common cases * smart http * svnserve + * htpasswd diff --git a/doc/g2incompat.mkd b/doc/g2incompat.mkd index 02a3d85..ca54ebc 100644 --- a/doc/g2incompat.mkd +++ b/doc/g2incompat.mkd @@ -92,7 +92,7 @@ There are several changes with regard to mirroring: option mirror.nightly = merry pippin but they will not be processed by gitolite. Your cron jobs should use - `gitolite git-config` to query this variable, grab the list of repos, and + `gitolite git-config` to query this variable, grab the list of peers, and run `gitolite mirror` on each of them. * The external command to resync mirrors is 'mirror', run just like any diff --git a/doc/g2migr-example.mkd b/doc/g2migr-example.mkd index 18c2ba8..28ec8b2 100644 --- a/doc/g2migr-example.mkd +++ b/doc/g2migr-example.mkd @@ -93,7 +93,7 @@ This is a quick and dirty program to catch some of the big issues. It does NOT attempt to catch all the differences described in the docs. INFO 'see docs' usually means doc/g2migr.mkd - (online at http://sitaramc.github.com/gitolite/g3/g2migr.html) + (online at http://sitaramc.github.com/gitolite/g2migr.html) checking rc file... NOTE GL_ADMINDIR is in the right place; assuming you did not mess with diff --git a/doc/g2migr.mkd b/doc/g2migr.mkd index e7f2864..916aab2 100644 --- a/doc/g2migr.mkd +++ b/doc/g2migr.mkd @@ -161,8 +161,7 @@ Some of them have links where there is more detail than I want to put here. * `GL_WILDREPOS_PERM_CATS` -- is now the ROLES hash in the rc file. - * `HTPASSWD_FILE`, `RSYNC_BASE`, `SVNSERVE` -- need work. Email me if you - are using any of these. + * `RSYNC_BASE` -- needs work. Email me if you are using this. * `NICE_VALUE` -- **dropped**. Uncomment the 'renice 10' line in the rc file. You can also change the 10 to something else if you wish. From b6ce11a19f00a06e363229c1c7c3955edc9df954 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 21 May 2012 22:00:38 +0530 Subject: [PATCH 042/158] (minor) permissions fixup -- sugar scripts do not need +x --- src/lib/Gitolite/Conf/Sugar.pm | 4 ++-- src/syntactic-sugar/continuation-lines | 0 src/syntactic-sugar/keysubdirs-as-groups | 0 3 files changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 src/syntactic-sugar/continuation-lines mode change 100755 => 100644 src/syntactic-sugar/keysubdirs-as-groups diff --git a/src/lib/Gitolite/Conf/Sugar.pm b/src/lib/Gitolite/Conf/Sugar.pm index 1e9cd9f..06422b7 100644 --- a/src/lib/Gitolite/Conf/Sugar.pm +++ b/src/lib/Gitolite/Conf/Sugar.pm @@ -4,7 +4,7 @@ package SugarBox; sub run_sugar_script { my ( $ss, $lref ) = @_; - do $ss if -x $ss; + do $ss if -r $ss; $lref = sugar_script($lref); return $lref; } @@ -54,7 +54,7 @@ sub sugar { # aliasing, which would happen if you touched $s itself my $sfp = "$ENV{GL_BINDIR}/syntactic-sugar/$s"; - _warn("skipped sugar script '$s'"), next if not -x $sfp; + _warn("skipped sugar script '$s'"), next if not -r $sfp; $lines = SugarBox::run_sugar_script( $sfp, $lines ); $lines = [ grep /\S/, map { cleanup_conf_line($_) } @$lines ]; } diff --git a/src/syntactic-sugar/continuation-lines b/src/syntactic-sugar/continuation-lines old mode 100755 new mode 100644 diff --git a/src/syntactic-sugar/keysubdirs-as-groups b/src/syntactic-sugar/keysubdirs-as-groups old mode 100755 new mode 100644 From 55d64752ae90439ab619292d1f2a8083ad828936 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 22 May 2012 11:45:05 +0530 Subject: [PATCH 043/158] fix repo alias to work when reponame has leading "/" as in git@host:repo.git works but ssh://git@host/repo.git doesn't --- src/lib/Gitolite/Triggers/Alias.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Triggers/Alias.pm b/src/lib/Gitolite/Triggers/Alias.pm index a00b385..acff44b 100755 --- a/src/lib/Gitolite/Triggers/Alias.pm +++ b/src/lib/Gitolite/Triggers/Alias.pm @@ -61,7 +61,7 @@ sub input { my $git_commands = "git-upload-pack|git-receive-pack|git-upload-archive"; my $user = $ARGV[0] || '@all'; # user name is undocumented for now - if ( $ENV{SSH_ORIGINAL_COMMAND} =~ /(?:$git_commands) '(\S+)'$/ ) { + if ( $ENV{SSH_ORIGINAL_COMMAND} =~ /(?:$git_commands) '\/?(\S+)'$/ ) { my $repo = $1; ( my $norm = $repo ) =~ s/\.git$//; # normalised repo name @@ -73,7 +73,7 @@ sub input { _warn "'$norm' is an alias for '$target'"; - $ENV{SSH_ORIGINAL_COMMAND} =~ s/'$repo'/'$target'/; + $ENV{SSH_ORIGINAL_COMMAND} =~ s/'\/?$repo'/'$target'/; } } From 290756152921d1dba754feebfb06485a4dc4c9c9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 22 May 2012 13:15:54 +0530 Subject: [PATCH 044/158] (minor) solaris doesn't like "shift" when there are no arguments remaining --- src/commands/D | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/D b/src/commands/D index 11bff3c..2d96964 100755 --- a/src/commands/D +++ b/src/commands/D @@ -45,11 +45,12 @@ die() { echo "$@" >&2; exit 1; } usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } [ -z "$1" ] && usage [ "$1" = "-h" ] && usage +[ "$1" != "list-trash" ] && [ -z "$2" ] && usage [ -z "$GL_USER" ] && die GL_USER not set # ---------------------------------------------------------------------- -cmd=$1; shift -repo=$1; shift # may not be present for 'list-trash' command +cmd=$1 +repo=$2 # ---------------------------------------------------------------------- RB=`gitolite query-rc GL_REPO_BASE`; cd $RB TRASH_CAN=`gitolite query-rc TRASH_CAN`; tcan=Trash; TRASH_CAN=${TRASH_CAN:-$tcan} From dd083085cf8714b96746bb881cfb3a400f4f5ed8 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 22 May 2012 22:32:11 +0530 Subject: [PATCH 045/158] (fix bugly) info -ld should handle missing description files more gracefully bugly = bug that makes the output ugly :) --- src/commands/info | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/commands/info b/src/commands/info index daf3ad2..d5ff810 100755 --- a/src/commands/info +++ b/src/commands/info @@ -80,13 +80,17 @@ sub print_phy_repos { sub listem { my ( $repos, $lc, $ld, @aa ) = @_; my $creator = ''; - my $desc = ''; for my $repo (@$repos) { next unless $repo =~ /$patt/; my $perm = ''; $creator = creator($repo) if $lc; - $desc = slurp("$ENV{GL_REPO_BASE}/$repo.git/description") if $ld; - chomp($desc); + + my $desc = ''; + for my $d ("$ENV{GL_REPO_BASE}/$repo.git/description") { + next unless $ld and -r $d; + $desc = slurp($d); + chomp($desc); + } for my $aa (@aa) { my $ret = access( $repo, $ENV{GL_USER}, $aa, 'any' ); From 5298a79cb503c9034de5e2dbc88ed0c9b72a566f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 23 May 2012 03:17:58 +0530 Subject: [PATCH 046/158] MAJOR BUGFIX: disallow "hooks" directory in admin repo Although this is not a "hole" that allows a normal user to bypass controls, I still consider this a hole in the sense that I want to separate "admin push" rights from "shell access on server" rights. (I realise that most people don't make this distinction, but I do, and for me and most sites I consult for it is important). Thanks to drue on #gitolite who pointed it out excitedly, and apologies for killing what he thought of as a feature! --- src/lib/Gitolite/Hooks/PostUpdate.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Hooks/PostUpdate.pm b/src/lib/Gitolite/Hooks/PostUpdate.pm index 9013ee9..3605de0 100644 --- a/src/lib/Gitolite/Hooks/PostUpdate.pm +++ b/src/lib/Gitolite/Hooks/PostUpdate.pm @@ -23,7 +23,7 @@ sub post_update { # this is the *real* post_update hook for gitolite tsh_try("git ls-tree --name-only master"); - _die "no files/dirs called 'hooks' or 'logs' are allowed" if tsh_text() =~ /^(hooks|logs)$/; + _die "no files/dirs called 'hooks' or 'logs' are allowed" if tsh_text() =~ /^(hooks|logs)$/m; { local $ENV{GIT_WORK_TREE} = $rc{GL_ADMIN_BASE}; From 75387fd6cb16449c4587f804445b3196c28731b5 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 23 May 2012 03:48:40 +0530 Subject: [PATCH 047/158] v3.03 --- doc/CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 8271e04..2767b31 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -1,3 +1,5 @@ +2012-05-23 v3.03 fix major bug that allowed an admin to get a shell + 2012-05-20 v3.02 packaging instructions fixed up and smoke tested make it easier to give some users a full shell From 62a66662bebb02d8c491379a2b55d02bc089605a Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 22 May 2012 18:03:07 -0400 Subject: [PATCH 048/158] Properly migrate [gitosis] section --- convert-gitosis-conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/convert-gitosis-conf b/convert-gitosis-conf index 999f8f7..9b92f68 100755 --- a/convert-gitosis-conf +++ b/convert-gitosis-conf @@ -47,6 +47,9 @@ while (<>) $groupname = ''; $reponame = $1; $reponame =~ s/\.git$//; + } elsif (/^\[gitosis\]$/) { + $groupname = ''; + $reponame = '@all'; } elsif (/^gitweb\s*=\s*yes/i) { push @{$repos{$reponame}{R}}, 'gitweb'; } elsif (/^daemon\s*=\s*yes/i) { From 04367af3e86b518170bb96513c15ba590097e8fe Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 25 May 2012 11:17:25 +0530 Subject: [PATCH 049/158] Revert "simulate POST_CREATE for newly created "normal" repos" This reverts commit bc3eb3421171a432aa62d784709d0b0e319de183. --- src/triggers/new-normal-repos | 55 ----------------------------------- 1 file changed, 55 deletions(-) delete mode 100755 src/triggers/new-normal-repos diff --git a/src/triggers/new-normal-repos b/src/triggers/new-normal-repos deleted file mode 100755 index 7e66509..0000000 --- a/src/triggers/new-normal-repos +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh - -# run some command on every new repo created via the conf file -# ---------------------------------------------------------------------- - -# BACKGROUND -# The POST_CREATE trigger (see doc/triggers.mkd) only works for repos that a -# user creates (see doc/wild.mkd). It does NOT work for repos created -# normally using the conf file. The POST_COMPILE trigger sequence should -# normally be used to trigger anything to happen after a compile. -# -# I have not seen a sane use case for a POST_CREATE trigger when a new repo -# is created via the conf file. (I do not consider "all new repos should -# have a default set of branches" to be a sane requirement). However, on -# the off-chance that something turns up at some future time, here's how you -# can do this without touching the core gitolite code. - -# INSTRUCTIONS FOR USE -# - (optional) rename this to whatever you want -# - change the 'post_create_normal' function below to do whatever you want it -# to do, or make it call some other command to do it -# - make the script executable -# - add 'new-normal-repos' (or whatever you renamed it to) to the PRE_GIT and -# the POST_COMPILE trigger lists in the rc file - -post_create_normal() { - echo "post_create_normal called with repo '$1'" >&2 -} - -# tempfile prefix; if you really care, change this also, otherwise leave it alone -tfp=$HOME/.tmp.$GL_USER.list-repos - -# ---------------------------------------------------------------------- - -if [ "$1" = "PRE_GIT" ] -then - # unless someone is pushing to the admin repo, we don't care - [ "$2" = "gitolite-admin" ] || exit 0 - [ "$4" = "W" ] || exit 0 - - # save the list of repos - gitolite list-repos > $tfp.1 -elif [ "$1" = "POST_COMPILE" ] -then - # get the new list of repos and compare with the one PRE_GIT created - gitolite list-repos > $tfp.2 - for repo in `grep -x -f $tfp.1 -v $tfp.2` - do - - post_create_normal "$repo" - done -else - # if you edited your rc file correctly, this line should never be reached - echo "ignoring call to" `basename $0` "with arg1 = '$1'" >&2 -fi From 0f3a09ce60e157c552d165f874102139feee678f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 25 May 2012 12:26:52 +0530 Subject: [PATCH 050/158] PRE_ and POST_CREATE should work for normal repos also --- doc/triggers.mkd | 14 +++++++++----- src/lib/Gitolite/Conf.pm | 4 ++++ src/lib/Gitolite/Conf/Store.pm | 6 +++++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/doc/triggers.mkd b/doc/triggers.mkd index 5ae8609..660ccd7 100644 --- a/doc/triggers.mkd +++ b/doc/triggers.mkd @@ -61,7 +61,7 @@ Triggers receive the following arguments: Here are the **rest of** the arguments for each trigger, plus a brief description of when the trigger runs: - * `ACCESS_1` runs after the first access check. Arguments: + * `ACCESS_1` runs after the first access check. Extra arguments: * repo * user * 'R' or 'W' @@ -71,7 +71,7 @@ description of when the trigger runs: result contains the refex that caused the access to succeed. * `ACCESS_2` runs after the second access check, in the update hook. - Arguments: + Extra arguments: * repo * user * any of W, +, C, D, WM, +M, CM, DM @@ -79,7 +79,7 @@ description of when the trigger runs: * result (see above) * `PRE_GIT` and `POST_GIT` run just before and after the git command. - Arguments: + Extra arguments: * repo * user * 'R' or 'W' @@ -88,12 +88,16 @@ description of when the trigger runs: 'git-upload-archive') being invoked. * `PRE_CREATE` and `POST_CREATE` run just before and after a new "[wild][]" - repo is created by user action. Arguments: + repo is created by user action. Extra arguments: * repo * user + They are also run when a *normal* repo is created (say by adding a "repo + foo" line to the conf file). This case has only one extra argument: + * repo + * `POST_COMPILE` runs after an admin push has successfully "compiled" the config file. By default, the next thing is to update the ssh authkeys file, then all the 'git-config's, gitweb access, and daemon access. - No arguments. + No extra arguments. diff --git a/src/lib/Gitolite/Conf.pm b/src/lib/Gitolite/Conf.pm index 8d8c82f..e7ca028 100644 --- a/src/lib/Gitolite/Conf.pm +++ b/src/lib/Gitolite/Conf.pm @@ -34,6 +34,10 @@ sub compile { # place to put the individual gl-conf files new_repos(); store(); + + for my $repo ( @{ $rc{NEW_REPOS_CREATED} } ) { + trigger( 'POST_CREATE', $repo ); + } } sub parse { diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 4eb3c67..f4f4cf2 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -164,7 +164,11 @@ sub new_repos { # use gl-conf as a sentinel hook_1($repo) if -d "$repo.git" and not -f "$repo.git/gl-conf"; - new_repo($repo) if not -d "$repo.git"; + if (not -d "$repo.git") { + push @{ $rc{NEW_REPOS_CREATED} }, $repo; + trigger( 'PRE_CREATE', $repo ); + new_repo($repo); + } } } From 37e97d29fe81c9e641712bc128761c35dcc24eb8 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 25 May 2012 12:28:14 +0530 Subject: [PATCH 051/158] the 3 shipped post-create programs should exit when called on a normal repo creation --- src/triggers/post-compile/update-git-configs | 7 +++++++ src/triggers/post-compile/update-git-daemon-access-list | 7 +++++++ src/triggers/post-compile/update-gitweb-access-list | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/src/triggers/post-compile/update-git-configs b/src/triggers/post-compile/update-git-configs index bd7ff13..7069f6c 100755 --- a/src/triggers/post-compile/update-git-configs +++ b/src/triggers/post-compile/update-git-configs @@ -16,6 +16,13 @@ use warnings; my $RB = $rc{GL_REPO_BASE}; _chdir($RB); +# ---------------------------------------------------------------------- +# skip if arg-0 is POST_CREATE and no arg-2 (user name) exists; this means +# it's been triggered by a *normal* (not "wild") repo creation, which in turn +# means a POST_COMPILE should be following so there's no need to waste time +# running this once for each new repo +exit 0 if @ARGV and $ARGV[0] eq 'POST_CREATE' and not $ARGV[2]; + # ---------------------------------------------------------------------- # if called from POST_CREATE, we have only a single repo to worry about if (@ARGV and $ARGV[0] eq 'POST_CREATE') { diff --git a/src/triggers/post-compile/update-git-daemon-access-list b/src/triggers/post-compile/update-git-daemon-access-list index 4585f44..cc865f1 100755 --- a/src/triggers/post-compile/update-git-daemon-access-list +++ b/src/triggers/post-compile/update-git-daemon-access-list @@ -2,6 +2,13 @@ # this is probably the *fastest* git-daemon update possible. +# ---------------------------------------------------------------------- +# skip if arg-1 is POST_CREATE and no arg-3 (user name) exists; this means +# it's been triggered by a *normal* (not "wild") repo creation, which in turn +# means a POST_COMPILE should be following so there's no need to waste time +# running this once for each new repo +[ "$1" = "POST_CREATE" ] && [ -z "$3" ] && exit 0; + EO=git-daemon-export-ok RB=`gitolite query-rc GL_REPO_BASE` export EO RB diff --git a/src/triggers/post-compile/update-gitweb-access-list b/src/triggers/post-compile/update-gitweb-access-list index f97061f..b7faee2 100755 --- a/src/triggers/post-compile/update-gitweb-access-list +++ b/src/triggers/post-compile/update-gitweb-access-list @@ -4,6 +4,13 @@ # whatever you want and contribute it back, as long as it is upward # compatible. +# ---------------------------------------------------------------------- +# skip if arg-1 is POST_CREATE and no arg-3 (user name) exists; this means +# it's been triggered by a *normal* (not "wild") repo creation, which in turn +# means a POST_COMPILE should be following so there's no need to waste time +# running this once for each new repo +[ "$1" = "POST_CREATE" ] && [ -z "$3" ] && exit 0; + plf=`gitolite query-rc GITWEB_PROJECTS_LIST` [ -z "$plf" ] && plf=$HOME/projects.list From e1d9aee98be8bffcf56d36d2d981e305c3e29a3c Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 25 May 2012 12:38:11 +0530 Subject: [PATCH 052/158] delete the 'description' file for new repos --- src/triggers/post-compile/update-gitweb-access-list | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/triggers/post-compile/update-gitweb-access-list b/src/triggers/post-compile/update-gitweb-access-list index b7faee2..d986fb3 100755 --- a/src/triggers/post-compile/update-gitweb-access-list +++ b/src/triggers/post-compile/update-gitweb-access-list @@ -4,6 +4,11 @@ # whatever you want and contribute it back, as long as it is upward # compatible. +# ---------------------------------------------------------------------- +# delete the 'description' file that 'git init' created if this is run from +# the post-create trigger +[ "$1" = "POST_CREATE" ] && rm -f $GL_REPO_BASE/$2.git/description 2>/dev/null + # ---------------------------------------------------------------------- # skip if arg-1 is POST_CREATE and no arg-3 (user name) exists; this means # it's been triggered by a *normal* (not "wild") repo creation, which in turn From 17841e8208248f26701e10a5bac4c4b483285104 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 25 May 2012 06:07:10 +0530 Subject: [PATCH 053/158] gitolite setup learns --hooks-only option --- src/lib/Gitolite/Setup.pm | 53 +++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/src/lib/Gitolite/Setup.pm b/src/lib/Gitolite/Setup.pm index 3fca752..72d3452 100644 --- a/src/lib/Gitolite/Setup.pm +++ b/src/lib/Gitolite/Setup.pm @@ -6,21 +6,30 @@ package Gitolite::Setup; =for args Usage: gitolite setup [

s around - # "paragraphs" that are wrapped in non-block-level tags, such as anchors, - # phrase emphasis, and spans. The list of tags we're looking for is - # hard-coded: - my $block_tags_a = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del/; - my $block_tags_b = qr/p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math/; - - # First, look for nested blocks, e.g.: - #

- # - # The outermost tags must start at the left margin for this to match, and - # the inner nested divs must be indented. - # We need to do this before the next, more liberal match, because the next - # match will start at the first `
` and stop at the first `
`. - $text =~ s{ - ( # save in $1 - ^ # start of line (with /m) - <($block_tags_a) # start tag = $2 - \b # word break - (.*\n)*? # any number of lines, minimally matching - # the matching end tag - [ \t]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egmx; - - - # - # Now match more liberally, simply from `\n` to `\n` - # - $text =~ s{ - ( # save in $1 - ^ # start of line (with /m) - <($block_tags_b) # start tag = $2 - \b # word break - (.*\n)*? # any number of lines, minimally matching - .* # the matching end tag - [ \t]* # trailing spaces/tabs - (?=\n+|\Z) # followed by a newline or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egmx; - # Special case just for
. It was easier to make a special case than - # to make the other regex more complicated. - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - <(hr) # start tag = $2 - \b # word break - ([^<>])*? # - /?> # the matching end tag/ - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - # Special case for standalone HTML comments: - $text =~ s{ - (?: - (?<=\n\n) # Starting after a blank line - | # or - \A\n? # the beginning of the doc - ) - ( # save in $1 - [ ]{0,$less_than_tab} - (?s: - - ) - [ \t]* - (?=\n{2,}|\Z) # followed by a blank line or end of document - ) - }{ - my $key = md5_hex($1); - $g_html_blocks{$key} = $1; - "\n\n" . $key . "\n\n"; - }egx; - - - return $text; -} - - -sub _RunBlockGamut { -# -# These are all the transformations that form block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _DoHeaders($text); - - # Do Horizontal Rules: - $text =~ s{^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$}{\n tags around block-level tags. - $text = _HashHTMLBlocks($text); - - $text = _FormParagraphs($text); - - return $text; -} - - -sub _RunSpanGamut { -# -# These are all the transformations that occur *within* block-level -# tags like paragraphs, headers, and list items. -# - my $text = shift; - - $text = _DoCodeSpans($text); - - $text = _EscapeSpecialChars($text); - - # Process anchor and image tags. Images must come first, - # because ![foo][f] looks like an anchor. - $text = _DoImages($text); - $text = _DoAnchors($text); - - # Make links out of things like `` - # Must come after _DoAnchors(), because you can use < and > - # delimiters in inline links like [this](). - $text = _DoAutoLinks($text); - - $text = _EncodeAmpsAndAngles($text); - - $text = _DoItalicsAndBold($text); - - # Do hard breaks: - $text =~ s/ {2,}\n/ or tags. -# my $tags_to_skip = qr!<(/?)(?:pre|code|kbd|script|math)[\s>]!; - - foreach my $cur_token (@$tokens) { - if ($cur_token->[0] eq "tag") { - # Within tags, encode * and _ so they don't conflict - # with their use in Markdown for italics and strong. - # We're replacing each such character with its - # corresponding MD5 checksum value; this is likely - # overkill, but it should prevent us from colliding - # with the escape values by accident. - $cur_token->[1] =~ s! \* !$g_escape_table{'*'}!gx; - $cur_token->[1] =~ s! _ !$g_escape_table{'_'}!gx; - $text .= $cur_token->[1]; - } else { - my $t = $cur_token->[1]; - $t = _EncodeBackslashEscapes($t); - $text .= $t; - } - } - return $text; -} - - -sub _DoAnchors { -# -# Turn Markdown link shortcuts into XHTML
tags. -# - my $text = shift; - - # - # First, handle reference-style links: [link text] [id] - # - $text =~ s{ - ( # wrap whole match in $1 - \[ - ($g_nested_brackets) # link text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $link_text; # for shortcut links like [this][]. - } - - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "? # href = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # Title = $6 - \5 # matching quote - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $link_text = $2; - my $url = $3; - my $title = $6; - - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = " tags. -# - my $text = shift; - - # - # First, handle reference-style labeled images: ![alt text][id] - # - $text =~ s{ - ( # wrap whole match in $1 - !\[ - (.*?) # alt text = $2 - \] - - [ ]? # one optional space - (?:\n[ ]*)? # one optional newline followed by spaces - - \[ - (.*?) # id = $3 - \] - - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $link_id = lc $3; - - if ($link_id eq "") { - $link_id = lc $alt_text; # for shortcut links like ![this][]. - } - - $alt_text =~ s/"/"/g; - if (defined $g_urls{$link_id}) { - my $url = $g_urls{$link_id}; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";? # src url = $3 - [ \t]* - ( # $4 - (['"]) # quote char = $5 - (.*?) # title = $6 - \5 # matching quote - [ \t]* - )? # title is optional - \) - ) - }{ - my $result; - my $whole_match = $1; - my $alt_text = $2; - my $url = $3; - my $title = ''; - if (defined($6)) { - $title = $6; - } - - $alt_text =~ s/"/"/g; - $title =~ s/"/"/g; - $url =~ s! \* !$g_escape_table{'*'}!gx; # We've got to encode these to avoid - $url =~ s! _ !$g_escape_table{'_'}!gx; # conflicting with italics/bold. - $result = "\"$alt_text\"";" . _RunSpanGamut($1) . "\n\n"; - }egmx; - - $text =~ s{ ^(.+)[ \t]*\n-+[ \t]*\n+ }{ - "

" . _RunSpanGamut($1) . "

\n\n"; - }egmx; - - - # atx-style headers: - # # Header 1 - # ## Header 2 - # ## Header 2 with closing hashes ## - # ... - # ###### Header 6 - # - $text =~ s{ - ^(\#{1,6}) # $1 = string of #'s - [ \t]* - (.+?) # $2 = Header text - [ \t]* - \#* # optional closing #'s (not counted) - \n+ - }{ - my $h_level = length($1); - "" . _RunSpanGamut($2) . "\n\n"; - }egmx; - - return $text; -} - - -sub _DoLists { -# -# Form HTML ordered (numbered) and unordered (bulleted) lists. -# - my $text = shift; - my $less_than_tab = $g_tab_width - 1; - - # Re-usable patterns to match list item bullets and number markers: - my $marker_ul = qr/[*+-]/; - my $marker_ol = qr/\d+[.]/; - my $marker_any = qr/(?:$marker_ul|$marker_ol)/; - - # Re-usable pattern to match any entirel ul or ol list: - my $whole_list = qr{ - ( # $1 = whole list - ( # $2 - [ ]{0,$less_than_tab} - (${marker_any}) # $3 = first list item marker - [ \t]+ - ) - (?s:.+?) - ( # $4 - \z - | - \n{2,} - (?=\S) - (?! # Negative lookahead for another list item marker - [ \t]* - ${marker_any}[ \t]+ - ) - ) - ) - }mx; - - # We use a different prefix before nested lists than top-level lists. - # See extended comment in _ProcessListItems(). - # - # Note: There's a bit of duplication here. My original implementation - # created a scalar regex pattern as the conditional result of the test on - # $g_list_level, and then only ran the $text =~ s{...}{...}egmx - # substitution once, using the scalar as the pattern. This worked, - # everywhere except when running under MT on my hosting account at Pair - # Networks. There, this caused all rebuilds to be killed by the reaper (or - # perhaps they crashed, but that seems incredibly unlikely given that the - # same script on the same server ran fine *except* under MT. I've spent - # more time trying to figure out why this is happening than I'd like to - # admit. My only guess, backed up by the fact that this workaround works, - # is that Perl optimizes the substition when it can figure out that the - # pattern will never change, and when this optimization isn't on, we run - # afoul of the reaper. Thus, the slightly redundant code to that uses two - # static s/// patterns rather than one conditional pattern. - - if ($g_list_level) { - $text =~ s{ - ^ - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}(?! {8,})/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - $result = "<$list_type>\n" . $result . "\n"; - $result; - }egmx; - } - else { - $text =~ s{ - (?:(?<=\n\n)|\A\n?) - $whole_list - }{ - my $list = $1; - my $list_type = ($3 =~ m/$marker_ul/) ? "ul" : "ol"; - # Turn double returns into triple returns, so that we can make a - # paragraph for the last item in a list, if necessary: - $list =~ s/\n{2,}(?! {8,})/\n\n\n/g; - my $result = _ProcessListItems($list, $marker_any); - $result = "<$list_type>\n" . $result . "\n"; - $result; - }egmx; - } - - - return $text; -} - - -sub _ProcessListItems { -# -# Process the contents of a single ordered or unordered list, splitting it -# into individual list items. -# - - my $list_str = shift; - my $marker_any = shift; - - - # The $g_list_level global keeps track of when we're inside a list. - # Each time we enter a list, we increment it; when we leave a list, - # we decrement. If it's zero, we're not in a list anymore. - # - # We do this because when we're not inside a list, we want to treat - # something like this: - # - # I recommend upgrading to version - # 8. Oops, now this line is treated - # as a sub-list. - # - # As a single paragraph, despite the fact that the second line starts - # with a digit-period-space sequence. - # - # Whereas when we're inside a list (or sub-list), that line will be - # treated as the start of a sub-list. What a kludge, huh? This is - # an aspect of Markdown's syntax that's hard to parse perfectly - # without resorting to mind-reading. Perhaps the solution is to - # change the syntax rules such that sub-lists must start with a - # starting cardinal number; e.g. "1." or "a.". - - $g_list_level++; - - # trim trailing blank lines: - $list_str =~ s/\n{2,}\z/\n/; - - - $list_str =~ s{ - (\n)? # leading line = $1 - (^[ \t]*) # leading whitespace = $2 - ($marker_any) [ \t]+ # list marker = $3 - ((?s:.+?) # list item text = $4 - (\n{1,2})) - (?= \n* (\z | \2 ($marker_any) [ \t]+)) - }{ - my $item = $4; - my $leading_line = $1; - my $leading_space = $2; - - if ($leading_line or ($item =~ m/\n{2,}/)) { - $item = _RunBlockGamut(_Outdent($item)); - } - else { - # Recursion for sub-lists: - $item = _DoLists(_Outdent($item)); - chomp $item; - $item = _RunSpanGamut($item); - } - - "
  • " . $item . "
  • \n"; - }egmx; - - $g_list_level--; - return $list_str; -} - - - -sub _DoCodeBlocks { -# -# Process Markdown `
    ` blocks.
    -#	
    -
    -	my $text = shift;
    -
    -	$text =~ s{
    -			(?:\n\n|\A)
    -			(	            # $1 = the code block -- one or more lines, starting with a space/tab
    -			  (?:
    -			    (?:[ ]{$g_tab_width} | \t)  # Lines must start with a tab or a tab-width of spaces
    -			    .*\n+
    -			  )+
    -			)
    -			((?=^[ ]{0,$g_tab_width}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    -		}{
    -			my $codeblock = $1;
    -			my $result; # return value
    -
    -			$codeblock = _EncodeCode(_Outdent($codeblock));
    -			$codeblock = _Detab($codeblock);
    -			$codeblock =~ s/\A\n+//; # trim leading newlines
    -			$codeblock =~ s/\s+\z//; # trim trailing whitespace
    -
    -			$result = "\n\n
    " . $codeblock . "\n
    \n\n"; - - $result; - }egmx; - - return $text; -} - - -sub _DoCodeSpans { -# -# * Backtick quotes are used for spans. -# -# * You can use multiple backticks as the delimiters if you want to -# include literal backticks in the code span. So, this input: -# -# Just type ``foo `bar` baz`` at the prompt. -# -# Will translate to: -# -#

    Just type foo `bar` baz at the prompt.

    -# -# There's no arbitrary limit to the number of backticks you -# can use as delimters. If you need three consecutive backticks -# in your code, use four for delimiters, etc. -# -# * You can use spaces to get literal backticks at the edges: -# -# ... type `` `bar` `` ... -# -# Turns to: -# -# ... type `bar` ... -# - - my $text = shift; - - $text =~ s@ - (`+) # $1 = Opening run of ` - (.+?) # $2 = The code block - (?$c
    "; - @egsx; - - return $text; -} - - -sub _EncodeCode { -# -# Encode/escape certain characters inside Markdown code runs. -# The point is that in code, these characters are literals, -# and lose their special Markdown meanings. -# - local $_ = shift; - - # Encode all ampersands; HTML entities are not - # entities within a Markdown code span. - s/&/&/g; - - # Encode $'s, but only if we're running under Blosxom. - # (Blosxom interpolates Perl variables in article bodies.) - { - no warnings 'once'; - if (defined($blosxom::version)) { - s/\$/$/g; - } - } - - - # Do the angle bracket song and dance: - s! < !<!gx; - s! > !>!gx; - - # Now, escape characters that are magic in Markdown: - s! \* !$g_escape_table{'*'}!gx; - s! _ !$g_escape_table{'_'}!gx; - s! { !$g_escape_table{'{'}!gx; - s! } !$g_escape_table{'}'}!gx; - s! \[ !$g_escape_table{'['}!gx; - s! \] !$g_escape_table{']'}!gx; - s! \\ !$g_escape_table{'\\'}!gx; - - return $_; -} - - -sub _DoItalicsAndBold { - my $text = shift; - - # must go first: - $text =~ s{ (\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1 } - {$2}gsx; - - $text =~ s{ (\*|_) (?=\S) (.+?) (?<=\S) \1 } - {$2}gsx; - - return $text; -} - - -sub _DoBlockQuotes { - my $text = shift; - - $text =~ s{ - ( # Wrap whole match in $1 - ( - ^[ \t]*>[ \t]? # '>' at the start of a line - .+\n # rest of the first line - (.+\n)* # subsequent consecutive lines - \n* # blanks - )+ - ) - }{ - my $bq = $1; - $bq =~ s/^[ \t]*>[ \t]?//gm; # trim one level of quoting - $bq =~ s/^[ \t]+$//mg; # trim whitespace-only lines - $bq = _RunBlockGamut($bq); # recurse - - $bq =~ s/^/ /g; - # These leading spaces screw with
     content, so we need to fix that:
    -			$bq =~ s{
    -					(\s*
    .+?
    ) - }{ - my $pre = $1; - $pre =~ s/^ //mg; - $pre; - }egsx; - - "
    \n$bq\n
    \n\n"; - }egmx; - - - return $text; -} - - -sub _FormParagraphs { -# -# Params: -# $text - string to process with html

    tags -# - my $text = shift; - - # Strip leading and trailing lines: - $text =~ s/\A\n+//; - $text =~ s/\n+\z//; - - my @grafs = split(/\n{2,}/, $text); - - # - # Wrap

    tags. - # - foreach (@grafs) { - unless (defined( $g_html_blocks{$_} )) { - $_ = _RunSpanGamut($_); - s/^([ \t]*)/

    /; - $_ .= "

    "; - } - } - - # - # Unhashify HTML blocks - # - foreach (@grafs) { - if (defined( $g_html_blocks{$_} )) { - $_ = $g_html_blocks{$_}; - } - } - - return join "\n\n", @grafs; -} - - -sub _EncodeAmpsAndAngles { -# Smart processing for ampersands and angle brackets that need to be encoded. - - my $text = shift; - - # Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: - # http://bumppo.net/projects/amputator/ - $text =~ s/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/&/g; - - # Encode naked <'s - $text =~ s{<(?![a-z/?\$!])}{<}gi; - - return $text; -} - - -sub _EncodeBackslashEscapes { -# -# Parameter: String. -# Returns: The string, with after processing the following backslash -# escape sequences. -# - local $_ = shift; - - s! \\\\ !$g_escape_table{'\\'}!gx; # Must process escaped backslashes first. - s! \\` !$g_escape_table{'`'}!gx; - s! \\\* !$g_escape_table{'*'}!gx; - s! \\_ !$g_escape_table{'_'}!gx; - s! \\\{ !$g_escape_table{'{'}!gx; - s! \\\} !$g_escape_table{'}'}!gx; - s! \\\[ !$g_escape_table{'['}!gx; - s! \\\] !$g_escape_table{']'}!gx; - s! \\\( !$g_escape_table{'('}!gx; - s! \\\) !$g_escape_table{')'}!gx; - s! \\> !$g_escape_table{'>'}!gx; - s! \\\# !$g_escape_table{'#'}!gx; - s! \\\+ !$g_escape_table{'+'}!gx; - s! \\\- !$g_escape_table{'-'}!gx; - s! \\\. !$g_escape_table{'.'}!gx; - s{ \\! }{$g_escape_table{'!'}}gx; - - return $_; -} - - -sub _DoAutoLinks { - my $text = shift; - - $text =~ s{<((https?|ftp):[^'">\s]+)>}{
    $1}gi; - - # Email addresses: - $text =~ s{ - < - (?:mailto:)? - ( - [-.\w]+ - \@ - [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+ - ) - > - }{ - _EncodeEmailAddress( _UnescapeSpecialChars($1) ); - }egix; - - return $text; -} - - -sub _EncodeEmailAddress { -# -# Input: an email address, e.g. "foo@example.com" -# -# Output: the email address as a mailto link, with each character -# of the address encoded as either a decimal or hex entity, in -# the hopes of foiling most address harvesting spam bots. E.g.: -# -# foo -# @example.com -# -# Based on a filter by Matthew Wickline, posted to the BBEdit-Talk -# mailing list: -# - - my $addr = shift; - - srand; - my @encode = ( - sub { '&#' . ord(shift) . ';' }, - sub { '&#x' . sprintf( "%X", ord(shift) ) . ';' }, - sub { shift }, - ); - - $addr = "mailto:" . $addr; - - $addr =~ s{(.)}{ - my $char = $1; - if ( $char eq '@' ) { - # this *must* be encoded. I insist. - $char = $encode[int rand 1]->($char); - } elsif ( $char ne ':' ) { - # leave ':' alone (to spot mailto: later) - my $r = rand; - # roughly 10% raw, 45% hex, 45% dec - $char = ( - $r > .9 ? $encode[2]->($char) : - $r < .45 ? $encode[1]->($char) : - $encode[0]->($char) - ); - } - $char; - }gex; - - $addr = qq{$addr}; - $addr =~ s{">.+?:}{">}; # strip the mailto: from the visible part - - return $addr; -} - - -sub _UnescapeSpecialChars { -# -# Swap back in all the special characters we've hidden. -# - my $text = shift; - - while( my($char, $hash) = each(%g_escape_table) ) { - $text =~ s/$hash/$char/g; - } - return $text; -} - - -sub _TokenizeHTML { -# -# Parameter: String containing HTML markup. -# Returns: Reference to an array of the tokens comprising the input -# string. Each token is either a tag (possibly with nested, -# tags contained therein, such as , or a -# run of text between tags. Each element of the array is a -# two-element array; the first is either 'tag' or 'text'; -# the second is the actual value. -# -# -# Derived from the _tokenize() subroutine from Brad Choate's MTRegex plugin. -# -# - - my $str = shift; - my $pos = 0; - my $len = length $str; - my @tokens; - - my $depth = 6; - my $nested_tags = join('|', ('(?:<[a-z/!$](?:[^<>]') x $depth) . (')*>)' x $depth); - my $match = qr/(?s: ) | # comment - (?s: <\? .*? \?> ) | # processing instruction - $nested_tags/ix; # nested tags - - while ($str =~ m/($match)/g) { - my $whole_tag = $1; - my $sec_start = pos $str; - my $tag_start = $sec_start - length $whole_tag; - if ($pos < $tag_start) { - push @tokens, ['text', substr($str, $pos, $tag_start - $pos)]; - } - push @tokens, ['tag', $whole_tag]; - $pos = pos $str; - } - push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len; - \@tokens; -} - - -sub _Outdent { -# -# Remove one level of line-leading tabs or spaces -# - my $text = shift; - - $text =~ s/^(\t|[ ]{1,$g_tab_width})//gm; - return $text; -} - - -sub _Detab { -# -# Cribbed from a post by Bart Lateur: -# -# - my $text = shift; - - $text =~ s{(.*?)\t}{$1.(' ' x ($g_tab_width - length($1) % $g_tab_width))}ge; - return $text; -} - - -1; - -__END__ - - -=pod - -=head1 NAME - -B - - -=head1 SYNOPSIS - -B [ B<--html4tags> ] [ B<--version> ] [ B<-shortversion> ] - [ I ... ] - - -=head1 DESCRIPTION - -Markdown is a text-to-HTML filter; it translates an easy-to-read / -easy-to-write structured text format into HTML. Markdown's text format -is most similar to that of plain text email, and supports features such -as headers, *emphasis*, code blocks, blockquotes, and links. - -Markdown's syntax is designed not as a generic markup language, but -specifically to serve as a front-end to (X)HTML. You can use span-level -HTML tags anywhere in a Markdown document, and you can use block level -HTML tags (like
    and as well). - -For more information about Markdown's syntax, see: - - http://daringfireball.net/projects/markdown/ - - -=head1 OPTIONS - -Use "--" to end switch parsing. For example, to open a file named "-z", use: - - Markdown.pl -- -z - -=over 4 - - -=item B<--html4tags> - -Use HTML 4 style for empty element tags, e.g.: - -
    - -instead of Markdown's default XHTML style tags, e.g.: - -
    - - -=item B<-v>, B<--version> - -Display Markdown's version number and copyright information. - - -=item B<-s>, B<--shortversion> - -Display the short-form version number. - - -=back - - - -=head1 BUGS - -To file bug reports or feature requests (other than topics listed in the -Caveats section above) please send email to: - - support@daringfireball.net - -Please include with your report: (1) the example input; (2) the output -you expected; (3) the output Markdown actually produced. - - -=head1 VERSION HISTORY - -See the readme file for detailed release notes for this version. - -1.0.1 - 14 Dec 2004 - -1.0 - 28 Aug 2004 - - -=head1 AUTHOR - - John Gruber - http://daringfireball.net - - PHP port and other contributions by Michel Fortin - http://michelf.com - - -=head1 COPYRIGHT AND LICENSE - -Copyright (c) 2003-2004 John Gruber - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -* Neither the name "Markdown" nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -This software is provided by the copyright holders and contributors "as -is" and any express or implied warranties, including, but not limited -to, the implied warranties of merchantability and fitness for a -particular purpose are disclaimed. In no event shall the copyright owner -or contributors be liable for any direct, indirect, incidental, special, -exemplary, or consequential damages (including, but not limited to, -procurement of substitute goods or services; loss of use, data, or -profits; or business interruption) however caused and on any theory of -liability, whether in contract, strict liability, or tort (including -negligence or otherwise) arising in any way out of the use of this -software, even if advised of the possibility of such damage. - -=cut diff --git a/doc/WARNINGS.mkd b/doc/WARNINGS.mkd deleted file mode 100644 index dc364de..0000000 --- a/doc/WARNINGS.mkd +++ /dev/null @@ -1,72 +0,0 @@ -# WARNINGS - -Gitolite does NOT like it if you fiddle with files, directories, permissions, -etc., on the server except as directed in the documentation. Gitolite also -expects all the directories and files it manages/uses to be owned by the -hosting user and not have strange permissions and ownerships. - -Very few people have fallen foul of this, but the ones who *did* became very -obnoxious about it, hence this warning. - -Gitolite depends on several system-installed packages: openssh, git, perl, sh -being the main ones. They should all be configured sensibly and with most of -the normal defaults. (For example, if your sshd config says the authorized -keys file should be placed in some directory other than the default, expect -trouble). - ----- - -For the entertainment of the sensible majority, and as a way of thanking all -of you, here are some examples of requests (demands in some cases) I have -received over the last couple of years. - - * deleting environment variables copied from client session - - demand: add code to delete certain environment variables at startup - because "the openssh servers in the linux distribution that [he] use[s], - are configured to copy `GIT_*` variables to the remote session". - - This is wrong on so many levels it's almost plonk-able! - - * using `cp` instead of `ln` - - Guy has an NTFS file system mounted on Linux. So... no symlinks (an NTFS - file system on Windows works fine because msysgit/cygwin manage to - *simulate* them. NTFS mounted on Linux won't do that!) - - He wanted all the symlink stuff to be replaced by copies. - - No. Way. - - * non-bare repos on the server - - Some guy gave me a complicated spiel about git-svn not liking bare repos - or whatever. I tuned off at the first mention of those 3 letters so I - don't really know what the actual problem was. - - But it doesn't matter. Even if someone (Ralf H) had not chipped in with a - workable solution, I still would not do it. A server repo should be bare. - Period. - - * incomplete ownership of `GL_REPO_BASE` - - This guy had a repo-base directory where not all of the files were owned - by the git user. As a result, some of the hooks did not get created. He - claimed my code should detect OS-permissions issues while it's doing its - stuff. - - No. I refuse to have the code constantly look over its shoulder making - sure fundamental assumptions are being met. - - * empty template directory - - (See man git-init for what a template directory is). - - The same guy with the environment variables had an empty template - directory because he "does not like to have sample hooks in every - repository". So naturally, the hooks directory does not get created when - you run a `git init`. He expects gitolite to compensate for it. - - Granted, it's only a 1-line change. But again, this falls under - "constantly looking over your shoulder to double check fundamental - assumptions". Where does it end? diff --git a/doc/admin.mkd b/doc/admin.mkd deleted file mode 100644 index 47c3aeb..0000000 --- a/doc/admin.mkd +++ /dev/null @@ -1,50 +0,0 @@ -# gitolite administration - -## #server server-side administration - -The following activities require command line access to the server. They are -usually one-time or rarely done activities. - - * Changing anything in the [rc][] file. - * Installing custom [hooks][], whether to all repos or just some repos. - * Moving [existing][] repos into gitolite control. - -Please read the [WARNINGS][] page first. - -## #adminrepo access control via the gitolite-admin repo - -Most day-to-day administration of a gitolite site happens like this: - - * [clone][] the gitolite-admin repo to your workstation - * make appropriate changes - * add, commit, and push - -### #conf the conf/gitolite.conf file - -Most of gitolite's power is in the conf/gitolite.conf file, which specifies -detailed access control for repos. Everything except [adding users][users] -happens from this file. - -Here is an example of a simple conf/gitolite.conf file. - - @staff = dilbert alice # line 1 - @projects = foo bar # line 2 - - repo @projects baz # line 3 - RW+ = @staff # line 4 - - master = ashok # line 5 - RW = ashok # line 6 - R = wally # line 7 - - config hooks.emailprefix = '[%GL_REPO] ' # line 8 - -Use the following links to learn more: - - * The basic [syntax][] -- comments, whitespace, include files, etc. - * Defining [groups][], as in lines 1 and 2. - * Adding and removing [users][]. - * Adding and removing [repos][], as in line 3. - * Defining access [rules][], as in lines 4, 5, 6, and 7. - * Gitolite [options][]. - * [Git config][git-config] keys and values, as in line 8. - * ["Wild"][wild] repos -- ad hoc, user-created, repos. diff --git a/doc/clone.mkd b/doc/clone.mkd deleted file mode 100644 index f51c2d0..0000000 --- a/doc/clone.mkd +++ /dev/null @@ -1,19 +0,0 @@ -# cloning the admin repo - -This is the third step in using gitolite, after [install][] and [setup][]. - -To clone the admin repo, go to the workstation where the public key used in -'setup' came from, and run this: - - git clone git@host:gitolite-admin - -NOTE that (1) you must not include the `repositories/` part (gitolite handles -that internally), and (2) you may include the ".git" at the end but it is -optional. - -If this step succeeds, you can add [users][], [repos][], or anything else -described [here][adminrepo]. - -If this step fails, be sure to look at the [ssh][] documentation before asking -for help. (A very basic first step is to run `ssh git@host info`; -[this][info] page tells you what to expect). diff --git a/doc/cust.mkd b/doc/cust.mkd deleted file mode 100644 index 8c7607b..0000000 --- a/doc/cust.mkd +++ /dev/null @@ -1,154 +0,0 @@ -# customising gitolite - -Much of gitolite (g3)'s functionality comes from programs and scripts that are -not considered "core". This keeps the core simpler, and allows you to enhance -gitolite for your own purposes without too much fuss. (As an extreme example, -even mirroring is not in core now!) - -This document will tell you about the types of non-core programs, and -how/where to install your own. (Actually *writing* the code is described in -the [developer notes][dev-notes] page). - ----- - -[[TOC]] - ----- - -## introduction - -There are 5 basic types of non-core programs. - - * *Commands* can be run from the shell command line. Among those, the ones - listed in the COMMANDS hash of the rc file can also be run remotely. - * *Hooks* are standard git hooks. - * *Sugar scripts* change the conf language for your convenience. The word - sugar comes from "syntactic sugar". - * *Triggers* are to gitolite what hooks are to git. I just chose a - different name to avoid confusion and constant disambiguation in the docs. - * **VREFs** are extensions to the access control check part of gitolite. - -[Here][non-core] is a list of non-core programs shipped with gitolite, with -some description of each. - -## locations - -### default/primary location of non-core programs - -Regardless of how you installed gitolite, `gitolite query-rc GL_BINDIR` will -tell you where the programs reside. Within that directory, the locations of -non-core programs are: - - * `commands` for commands. - * `syntactic-sugar` for sugar scripts. - * `triggers` and `lib/Gitolite/Triggers` for triggers ([this][triggers] will - explain the difference). - * `VREF` for [VREFs][vref]. - -### #localcode alternate location -- the `LOCAL_CODE` rc variable - -If you want to add new non-core programs to your installation, or override the -shipped non-core programs with your own versions, it's easy enough to simply -copy your programs to the appropriate directory above, but then they'd get -wiped out on the next upgrade. - -A simple, "git-ish", method is to maintain a "local" branch in your clone of -the gitolite source repo and make your changes there. Maintain them using -rebase or merge when you 'git pull' gitolite itself, then use the rebased or -merged "local" as the source for your gitolite upgrades. Works very nicely, -and uses nothing but your git knowledge. - -Sadly, it doesn't work for people installing from RPMs/DEBs; their "primary -location" has already been setup, so any site-local customisations have to be -done elsewhere. - -This is where `LOCAL_CODE` comes in. If you define the `LOCAL_CODE` rc -variable, then its value (**please use a FULL path**) describes a location -where you can have any or all of these subdirectories: - - * `commands` - * `hooks/common` - * `syntactic-sugar` - * `triggers` and `lib/Gitolite/Triggers` - * `VREF` - -You might have noticed there's a new `hooks/common` directory here so you can -add hooks also using this mechanism. Unlike the rest of the directories, -adding new hooks to `hooks/common` requires that you follow up with `gitolite -setup`, or at least `gitolite setup --hooks-only`. - -### #pushcode managing custom code via the gitolite-admin repo - -The location given in `LOCAL_CODE` could be anywhere on disk. - -However, if you point it to someplace inside `$GL_ADMIN_BASE` (i.e., -`$HOME/.gitolite`), then you can version those programs using the -gitolite-admin repo. - -I suggest using a directory called "local-code" within the gitolite-admin repo -that contains as much of the above directory structure you need. If you do -that, then this is what you'd have in the rc file: - - LOCAL_CODE => "$ENV{HOME}/.gitolite/local-code", - -When you do this, gitolite takes care of everything automatically, including -running `gitolite setup --hooks-only` when you change any hooks and push. -**However, if you do this, anyone who can push changes to the admin repo will -effectively be able to run any arbitrary command on the server.** - -## types of non-core programs - -### #commands gitolite "commands" - -Gitolite comes with several commands that users can run. Remote users run -commands by saying: - - ssh git@host command-name [args...] - -while on the server you can run - - gitolite command [args...] - -Very few commands are designed to be run both ways, but it can be done, by -checking for the presence of env var `GL_USER`. - -You can get a **list of available commands** by using the `help` command. -Naturally, a remote user will see a much smaller list than the server user. - -You allow a command to be run from remote clients by adding its name to (or -uncommenting it if it's already added but commented out) the COMMANDS hash in -the [rc][] file. - -### #hooks hooks and gitolite - -You can install any hooks except these: - - * (all repos) gitolite reserves the `update` hook. See the "update hook" - section in [dev-notes][] if you want additional update hook functionality. - - * (gitolite-admin repo only) gitolite reserves the `post-update` hook. - -How/where to install them is described in detail in the "locations" section -above, especially [this][localcode] and [this][pushcode]. The summary is that -you put them in the "hooks/common" sub-directory within the directory whose -name is given in the `LOCAL_CODE` rc variable. - -### #sugar syntactic sugar - -Sugar scripts help you change the perceived syntax of the conf language. The -base syntax of the language is very simple, so sugar scripts take something -*else* and convert it into that. - -That way, the admin sees additional features (like allowing continuation -lines), while the parser in the core gitolite engine does not change. - -If you want to write your own sugar scripts, please read the "your own sugar" -section in [dev-notes][] first then email me. - -### triggers - -Triggers have their own [document][triggers]. - -### VREFs - -VREFs also have their own [document][vref]. diff --git a/doc/deleg.mkd b/doc/deleg.mkd deleted file mode 100644 index f693432..0000000 --- a/doc/deleg.mkd +++ /dev/null @@ -1,118 +0,0 @@ -# delegating access control responsibilities - -Delegation allows you to divide up a large conf file into smaller groups of -repos (called **subconf**s) and hand over responsibility to manage them to -**sub-admin**s. Gitolite can prevent one sub-admin from being able to set -access rules for any other sub-admin's repos. - -Delegation is achieved by combining two gitolite features: [subconf][] and the -[NAME VREF][NAME]. - -To understand delegation, read both those links then come back to this -example. - -## example - - @webbrowsers = firefox lynx browsers/..* - @webservers = apache nginx servers/..* - @malwares = conficker storm ms/..* - # side note: if anyone objects, we claim ms stands for "metasploit" ;-) - - # the admin repo access was probably like this to start with: - repo gitolite-admin - RW+ = sitaram - # now add these lines to the config for the admin repo - RW = alice bob mallory - RW VREF/NAME/conf/subs/webbrowsers = alice - RW VREF/NAME/conf/subs/webservers = bob - RW VREF/NAME/conf/subs/malwares = mallory - - VREF/NAME/ = alice bob mallory - -Finally, you tell gitolite to pull in these files using the "subconf" command - - subconf "subs/*.conf" - -And that's it. - -## #subconf the subconf command - -Subconf is exactly like the include command in syntax: - - subconf "foo.conf" - -but while reading the included file (as well as anything included from it), -gitolite sets the "subconf name" to "foo". - -A "subconf" imposes some restrictions on what repos can be managed. - -For example, while the subconf name is "foo", as in the above example, -gitolite will only process "repo" lines for: - - * A repo called "foo". - * A group called "@foo", as long as the group is defined in the main conf - file (i.e., *outside* "foo.conf"). - * A member of a group called "@foo" (again, defined outside). - * A repo that matches a member of a group called "@foo" if that member is a - regular expression pattern. - -Here's an example. If the main conf file contains - - @foo = aa bb cc/..* - -then the subconf can only accept repo statements that refer to 'foo', '@foo', -'aa', 'bb', or any repo whose name starts with 'cc/'. - -**Note**: the subconf name "master" is special; it is the default subconf in -effect for the main conf file and has no restrictions. - -### how the "subconf name" is derived - -For subconf lines that look just like include statements, i.e., - - subconf "foo/bar.conf" - subconf "frob/*.conf" - # assume frob has files aa.conf, bb.conf - -the subconf name as each file is being processed is the base name of the file. -This means it would be "bar" for the first line, "aa" when processing -"frob/aa.conf", and "bb" when processing "frob/bb.conf". - -A variation of subconf exists that can explicitly state the subconf name: - - subconf foo "frob/*.conf" - -In this variation, regardless of what file in "frob/" is being read, the -subconf name in effect is "foo". - -## security notes - -### group names - -You can use "@group"s defined in the main config file but do not attempt to -redefine or extend them in your own subconf file. If you must extend a group -(say `@foo`) defined in the main config file, do this: - - @myfoo = @foo - # now do whatever you want with @myfoo - -Group names you define in your subconf will not clash even if the exact same -name is used in another subconf file, so you need not worry about that. - -### delegating pubkeys - -Short answer: not gonna happen. - -The delegation feature is meant only for access control rules, not pubkeys. -Adding/removing pubkeys is a much more significant event than changing branch -level permissions for people already on staff, and only the main admin should -be allowed to do it. - -Gitolite's "userids" all live in the same namespace. This is unlikely to -change, so please don't ask -- it gets real complicated to do otherwise. -Allowing sub-admins to add users means username collisions, which also means -security problems (admin-A creates a pubkey for Admin-B, thus gaining access -to all of Admin-B's stuff). - -If you feel the need to delegate even that, please just go the whole hog and -give them separate gitolite instances (i.e., running under different gitolite -hosting users)! diff --git a/doc/dev-notes.mkd b/doc/dev-notes.mkd deleted file mode 100644 index a493ee7..0000000 --- a/doc/dev-notes.mkd +++ /dev/null @@ -1,165 +0,0 @@ -# notes for developers - -[[TOC]] - ----- - -Gitolite has a huge bunch of existing features that gradually need to moved -over. Plus you may want to write your own programs to interact with it. - -**This document is about *writing* hooks, commands, triggers, VREFS, and sugar -scripts. *Installing* them, including "where and how", is described -[here][localcode]**. - -## environment variables and other inputs - -In general, the following environment variables should always be available: - - GL_BINDIR - GL_REPO_BASE - GL_ADMIN_BASE - -Commands invoked by a remote client will also have `GL_USER` set. Hooks will -have `GL_REPO` also set. - -Finally, note that triggers get a lot of relevant information from gitolite as -arguments; see [here][triggers] for details. - -## APIs - -### the shell API - -The following commands exist to help you write shell scripts that interact -easily with gitolite. Each of them responds to `-h` so please run that for -more info. - - * `gitolite access` to check access rights given repo, user, type of access - (R, W, ...) and refname (optional). Example use: src/commands/desc. - - * `gitolite creator` to get/check the creator of a repo. Example use: - src/commands/desc. - - * `gitolite git-config` to check gitolite options or git config variables - directly from gitolite's "compiled" output, (i.e., without looking at the - actual `repo.git/config` file or using the `git config` command). Example - use: src/triggers/post-compile/update-gitweb-access-list. - - * `gitolite query-rc` to check the value of an RC variable. Example use: - src/commands/desc. - -In addition, you can also look at the comments in src/lib/Gitolite/Easy.pm -(the perl API module) for ideas. - -### the perl API - -...is implemented by Gitolite::Easy; the comments in src/lib/Gitolite/Easy.pm -serve as documentation. - -Note that some of the perl functions called by Easy.pm will change the current -directory to something else, without saving and restoring the directory. -Patches (to Easy.pm *only*) welcome. - -## writing your own... - -### ...commands - -Commands are standalone programs, in any language you like. They simply -receive the arguments you append. In addition, the env var `GL_USER` is -available if it is being run remotely. src/commands/desc is the best example -at present. - -### ...hooks - -#### anything but the update hook - -If you want to add any hook other than the update hook, 'man githooks' is all -you need. - -#### update hook - -If you want to add additional `update` hook functionality, do this: - - * Write and test your update hook separately from gitolite. - - * Now add the code as a VREF (see [here][localcode] for details). Let's say - you called it "foo". - - * To call your new update hook to all accesses for all repos, add this to - the end of your conf file: - - repo @all - - VREF/foo = @all - -As you probably guessed, you can make your additional update hooks more -selective, applying them only to some repos / users / combinations. - -Note: a normal update hook expects 3 arguments (ref, old SHA, new SHA). A -VREF will get those three, followed by at least 4 more. Your VREF should just -ignore the extra args. - -### ...trigger programs - -Trigger programs run at specific points in gitolite's execution, with specific -arguments being passed to them. See the [triggers][] page for details. - -You can write programs that are both manually runnable as well as callable by -trigger events, especially if they don't *need* any arguments. - -### ..."sugar" - -Syntactic sugar helpers are NOT complete, standalone, programs. They must -include a perl sub called `sugar_script` that takes in a listref, and returns -a listref. The listrefs point to a list that contains the entire conf file -(with all [include][] processing already done). You create a new list with -contents modified as you like and return a ref to it. - -There are a couple of examples in src/syntactic-sugar. - -## appendix 1: notes on the INPUT trigger - -Note: some of this won't make sense if you haven't read about [triggers][]. - -The INPUT trigger sequence is designed to set or change environment variables -or the argument list. (Side note: this means INPUT triggers have to be -written as perl modules; they cannot be standalone scripts). This is a very -powerful idea so an extended description may be useful. - -Sshd invokes gitolite-shell with the SSH\_ORIGINAL\_COMMAND env var containing -the git/gitolite command and one argument: the gitolite username. - - * see [this][glssh] for details on the latter - * the *first* thing gitolite does in smart http mode is to use the - REMOTE\_USER and the CGI variables that apache provides to *construct* - a fake argument list and a fake SSH\_ORIGINAL\_COMMAND env var, so the - rest of the code can stay the same - -The INPUT trigger is then run. The purpose of the input trigger is to ensure -that the first argument *is* the gitolite username, and that the -SSH\_ORIGINAL\_COMMAND env var contains the actual command to execute. It can -also be used to set up any other environment variables that you may decide you -need. - -Wait... didn't we say that's what gitolite-shell gets anyway, just now? - -Well, we lied a bit there; it's not always true! - -For example, if [this][giving-shell] feature is used, the first argument *may* -be "-s", with the username in the *second* argument. Shell.pm deals with -that. (Order matters. If you use this feature, put the -`'Shell::input',` line ahead of the others, since it is the only one prepared -to deal with username not being the first argument). - -If you look at CpuTime.pm, you'll see that it's `input()` function doesn't set -or change anything, but does set a package variable to record the start time. -Later, when the same module's `post_git()` function is invoked, it uses this -variable to determine elapsed time. - -*(This is a very nice and simple example of how you can implement features by -latching onto multiple events and sharing data to do something)*. - -You can even change the reponame the user sees, behind his back. Alias.pm -handles that. - -Finally, as an exercise for the reader, consider how you would create a brand -new env var that contains the *comment* field of the ssh pubkey that was used -to gain access, using the information [here][kfn]. diff --git a/doc/dev-status.mkd b/doc/dev-status.mkd deleted file mode 100644 index 6d40949..0000000 --- a/doc/dev-status.mkd +++ /dev/null @@ -1,36 +0,0 @@ -## #dev-status g3 development status - -Not yet done (will be tackled in this order unless someone asks): - - * mechanism for ADCs using unchecked arguments -- this is not just a matter - of writing it; I have to think about *how* it will be done. (AFAIK the - only tool affected is git-annexe; if there are more let me know) - -Help needed: - - * I'd like distro packagers to play with it and help with migration advice - for distro-upgrades - * rsync - * git-annexe support (but this has a pre-requisite in the previous list) - -Won't be done unless someone asks (saw no evidence that anyone used them in g2 -anyway!): - - * mob branches - * password access - * some of the more arcane rc variables! - * specific ADCs -- there are too many for me to bother without applying - Pareto somewhere, so I choose to not do any and wait for people to ask :-) - -Done: - - * core code - * test suite - * mirroring - * documentation - * migration documentation - * distro packaging instructions - * migration advice for common cases - * smart http - * svnserve - * htpasswd diff --git a/doc/emergencies.mkd b/doc/emergencies.mkd deleted file mode 100644 index 1d0e616..0000000 --- a/doc/emergencies.mkd +++ /dev/null @@ -1,192 +0,0 @@ -# help for emergencies - ----- - -"Don't Panic!" - ----- - -## #lost-key lost admin key/access - -If you lost your gitolite **admin** key or access, here's what you do. We'll -assume your username is 'alice'. - - * Make yourself a new keypair and copy the public key to the server as - 'alice.pub'. - - * Log on to the server, and run `gitolite setup -pk alice.pub`. - -That's it; the new alice.pub file replaces whatever existed in the repo -before. - -## #bypass bypassing gitolite - -You may have lost access because of a conf file error, in which case the above -trick won't help. What you want is to make changes to the repo (or perhaps -just rewind) and push that. Here's how to do that: - - * Log on to the server. - - * Clone the admin repo using the full path: `git clone - $HOME/repositories/gitolite-admin.git temp`. - - * Make whatever changes you want -- add/replace a key, 'git revert' or 'git - reset --hard' to an older commit, etc. Anything you need to fix the - problem, really. - - * Run `gitolite push` (or possibly `gitolite push -f`). Note that's - 'gitolite push', not 'git push'. - - -**NOTE**: gitolite does **no access checking** when you do this! - - -## #clean cleaning out a botched install - -If you've read the [files involved in gitolite][files] page, you probably know -the answer, but here's a list of files you should blow away. - - * **Gitolite sources** -- can be found by running `which gitolite`. If it's - a symlink, go to its target directory. - - * **Gitolite admin directory** -- `$HOME/.gitolite`. Save the 'logs' - directory if you want to preserve them for any reason. - - * **The rc file** -- `$HOME/.gitolite.rc`. If you made any changes to it - you can save it as some other name instead of deleting it. - - * **The gitolite-admin repo** -- `$HOME/repositories/gitolite-admin.git`. - You can clone it somewhere to save it before blowing it away if you wish. - - * **Git repositories** -- `$HOME/repositories`. The install process will - not touch any existing repos except 'gitolite-admin.git', so you do not - have to blow away (or move) your work repos to fix a botched install. - - Only when you update the conf to include those repos and push the changes - will those repos be touched. And even then all that happens is that the - update hook, if any, is replaced with gitolite's own hook. - - * **Ssh stuff** -- exercise caution when doing this, but in general it - should be safe to delete all lines between the "gitolite start" and - "gitolite end" markers in `$HOME/.ssh/authorized_keys`. - - Gitolite does not touch any other files in the ssh directory. - -## #ce common errors - - * `WARNING: keydir/.pub duplicates a non-gitolite key, sshd will ignore it` - - You used a key that is already set to give you shell access. You cannot - use the same key to get shell access as well as access gitolite repos. - - Solution: use a different keypair for gitolite. There's a slightly longer - discussion in the [setup][] page. Also see [why bypassing causes a - problem][ybpfail] and both the documents in [ssh][] for background. - - * `Empty compile time value given to use lib at hooks/update line 6` - - (followed by `Can't locate Gitolite/Hooks/Update.pm in @INC` a couple of - lines later). - - You're bypassing gitolite. You cloned the repo using the full path (i.e., - including the `repositories/` prefix), either directly on the server, or - via ssh but with a key that gives you **shell** access. - - Solution: same as for the previous bullet. - - NOTE: If you really *must* do it, and this is a one-time thing, you can - try `gitolite push` instead of `git push`. **BUT**... this defeats all - gitolite access control, so if you're going to do this often, maybe you - don't need gitolite! - -## #ue uncommon errors - - * `WARNING: split conf not set, gl-conf present for ` - - (Case 1) you copied a bare repo ("repo.git") from another g3 site (or g2 - with `GL_BIG_CONFIG` on). Then you pushed a change to "gitolite.conf" or - ran certain server-side commands without adding the repo to the conf. - - Conversely, you removed "repo" from "gitolite.conf" but did not remove the - actual "repo.git" on disk. - - (Case 2) This can also happen if you changed something like this - - repo foo - ...... - - to this - - @grp = foo - repo @grp - ...... - - Also, even running `gitolite setup` will not fix this. - - The root cause is an internal consistency check that I do not wish to - disable or subvert. It is there for a reason, and I would prefer a - warning that a human can investigate. - - If you're sure the reasons are one of the two above, you can either add - the repo to the conf file in case 1, or manually remove the gl-conf file - from the repo.git directory in case 2. - - Either way, run `gitolite setup` afterwards to make sure things are in - good shape. - - If you think neither of those is the cause, email me. - -## #ngp things that are not gitolite problems - -There are several things that appear to be gitolite problems but are not. I -cannot help with most of these (although the good folks on irc or the mailing -list -- see [contact][] -- might be able to; they certainly appear to have a -lot more patience than I do, bless 'em!) - - * **Client side software** - - * putty/plink - * jgit/Eclipse - * Mac OS client **or** server - * putty/plink - * windows as a server - * ...probably some more I forgot; will update this list as I remember... - * did I mention putty/plink? - - * **Ssh** - - The *superstar* of the "not a gitolite problem" category is actually ssh. - - Surprised? It is so common that it has [its own document][auth] to tell - you why it is *not* a gitolite problem, while [another one][ssh] tries to - help you anyway! - - Everything I know is in that latter link. Please email me about ssh ONLY - if you find something wrong or missing in those documents. - - * **Git** - - I wish I had a dollar for each time someone did a *first push* on a new - repo, got an error because there were "no refs in common (etc.)", and - asked me why gitolite was not allowing the push. - - Gitolite is designed to look like just another bare repo server to a - client (except requiring public keys -- no passwords allowed). It is - *completely transparent* when there is no authorisation failure (i.e., - when the access is allowed, the remote client has no way of knowing - gitolite was even installed!) - - Even "on disk", apart from reserving the `update` hook for itself, - gitolite does nothing to your bare repos unless you tell it to (for - example, adding 'gitweb.owner' and such to the config file). - - BEFORE you think gitolite is the problem, try the same thing with a normal - bare repo. In most cases you can play with it just by doing something - like this: - - mkdir /tmp/throwaway - cd /tmp/throwaway - git clone --mirror bare.git - git clone bare.git worktree - cd worktree - <...try stuff> diff --git a/doc/external.mkd b/doc/external.mkd deleted file mode 100644 index 45d19a7..0000000 --- a/doc/external.mkd +++ /dev/null @@ -1,71 +0,0 @@ -# interfacing with external tools - -> ---- - -> **Note**: The old gitolite (v1.x, v2.x) used to tie itself into knots -> dealing with gitweb and daemon. One of the goals of g3 was to get out of -> that game, which your author does not play anyway. This means statements -> like "...special user called 'gitweb'..." really apply to the [non-core][] -> programs that gitolite ships with, not to "core" gitolite, and any or all -> of this functionality can be disabled by commenting out certain lines in -> the [rc][] file. - -> ---- - -> Also, **note** that gitolite does **not** install or configure -> gitweb/git-daemon -- that is a one-time setup you must do separately. - -> ---- - -## gitweb - -The following repos are deemed to be readable by gitweb: - - * any repos readable by the special user `gitweb` - * any repos containing one or more of the following types of lines: - - config gitweb.owner = owner name - config gitweb.description = some description - config gitweb.category = some category - - Side note: the following shorter forms are available as [syntactic - sugar][sugar] for the above longer forms: - - owner = owner name - desc = some description - category = some category - -The list of gitweb-readable repos is written to a file whose name is given by -the [rc][] file variable `GITWEB_PROJECTS_LIST`. The default value of this -variable, if it is not specified or empty, is `$HOME/projects.list`. - -In addition, each of the config variables described above is written to the -repo to which it pertains, so that gitweb can use them. - -### #umask changing the UMASK - -Gitweb typically runs under a different userid, and the default permissions -that gitolite sets make them unreadable. - -See the section on the `UMASK` variable in the documentation for the [rc -file][rc]. - -## git-daemon - -Any repo readable by the special user `daemon` is deemed to be readable by -git-daemon. For each of these repos, an empty file called -`git-daemon-export-ok` is created in the repository (i.e., the `repo.git` -directory inside `$HOME/repositories`). - -## tips - -Setting descriptions en-masse usually does not make sense, but you can -certainly do things like - - repo @all - R = gitweb daemon - -assuming you have other means of setting 'gitweb.description' and -'gitweb.owner'. - -Also see [this][deny-rules] for a twist on that. diff --git a/doc/extras/auth.mkd b/doc/extras/auth.mkd deleted file mode 100644 index 1b88a6a..0000000 --- a/doc/extras/auth.mkd +++ /dev/null @@ -1,106 +0,0 @@ -# authentication versus authorisation - -This document will explain why an "ssh issue" is almost never a "gitolite -issue", and, indirectly, why I dont get too excited about the former. - -Note: for actual ssh troubleshooting see [this][sts]. - -Here is a fundamental point: **Gitolite does not do -authentication. It only does authorisation**. - -So first, let's loosely define these words: - -> **Authentication** is the process of verifying that you are who you claim -> to be. An authentication system will establish that I am the user -> "sitaram" on my work system. The one behind gmail will similarly -> establish that I am "sitaramc". And so on... - -> **Authorisation** is the process of asking what you want to do and -> deciding if you're allowed to do it or not. - -Now, if you managed to read about [gitolite and ssh][glssh], you -know that gitolite is meant to be invoked as: - - /full/path/to/gitolite-shell some-authenticated-gitolite-username - -(where the "gitolite username" is a "virtual" username; it does not have to -be, and usually *isn't*, an actual *unix* username). - -As you can see, authentication happens before gitolite is called. - -## but... but... you have all that ssh stuff in gitolite! - -No I don't. Not in "core" gitolite from g3 onwards :-) - -The default setup does use ssh keys, but it's only helping you **setup** -ssh-based authentication **as a convenience to you**. But in fact it is a -*completely* separate program that you can disable (in the rc file) or replace -with something else of your choice. - -For example, in both [smart http][http] and ldap-backed sshd, gitolite has no -role to play in creating users, setting up their passwords/keys, etc. - -## so you're basically saying you won't support "X" - -(where "X" is some ssh related behaviour change or feature) - -Well, if it's not a security issue I won't. But since it's no longer part of -"core" gitolite, I can be much more relaxed about taking patches, or even -alternative implementations. - -While we're on the subject, locking someone out is *not* a security issue. -Even if you [lost the admin key][lost-key], the docs tell you how to recover -from such errors. You do need some password based method to get a shell -command line on the server, of course. - -## #otherauth how to use other authentication systems with gitolite - -The bottom line in terms of how to invoke gitolite has been described above, -and as long as you manage to do that gitolite won't even know how the -authentication was done. Which in turn means you can use whatever -authentication scheme you want. - -It also expects the `SSH_ORIGINAL_COMMAND` environment variable to contain the -full command (typically starting with git-receive-pack or git-upload-pack) -that the client sent. Also, when using [smart http][http], things are somewhat -different: gitolite uses certain environment variables that it expects httpd -to have set up. Even the user name comes from the `REMOTE_USER` environment -variable instead of as a command line argument in this case. - -However, it has to be an authentication system that is compatible with sshd or -httpd in some form. Why? Because the git *client* accessing the server only -knows those 2 protocols to "speak git". (Well, the `git://` protocol is -unauthenticated, and `file://` doesn't really apply to this discussion, so -we're ignoring those). - -For example, let's say you have an LDAP-based authentication system somewhere. -It is possible to make apache use that to authenticate users, so when a user -accesses a git url using `http://sitaram:password@git.example.com/repo`, it is -LDAP that does the actual authentication. [I wouldn't know how to do it but I -know it is possible. Patches to this doc explaining how are welcome!] - -There are also ssh daemons that use LDAP to store the authorised keys (instead -of putting them all in `~/.ssh/authorized_keys`). The clients will still need -to generate keypairs and send them to the admin, but they can be more -centrally stored and perhaps used by other programs or tools simultaneously, -which can be useful. - -## #ldap getting user group info from LDAP - -Gitolite's [groups][] are pretty convenient, but some organisations already -have similar (or sufficient) information in their LDAP store. - -Gitolite can tap into that information, with a little help. Write a program -which, given a username, queries your LDAP store and returns a space-separated -list of groups that the user is a member of. Then put the full path to this -program in an [rc][] variable called `GROUPLIST_PGM`, like so: - - GROUPLIST_PGM => '/home/git/bin/ldap-query-groups', - -Now you can use those groupnames in access rules in gitolite, just as if you -had declared their memberships in the conf file. - -Caution: your program must do its own logging if you want the audit trail of -"why/how did this user get access to this repo at this time?" to resolve -properly. Gitolite does not do any logging of the results of the queries -because for people who don't need it that would be a huge waste. diff --git a/doc/extras/glssh.mkd b/doc/extras/glssh.mkd deleted file mode 100644 index f25bc13..0000000 --- a/doc/extras/glssh.mkd +++ /dev/null @@ -1,149 +0,0 @@ -# #glssh how gitolite uses ssh - -[[TOC]] - ----- - -Although other forms of authentications exist (see the document on -[authentication versus authorisation][auth]), ssh is the one that most git -users use. - -***Therefore, gitolite is (usually) heavily dependent on ssh***. - -Most people didn't realise this, and even if they did they don't know ssh -well enough to help themselves. If you don't understand how ssh public key -authentication works, or how the `~/.ssh/authorized_keys` file can be used to -restrict users, etc., you will have endless amounts of trouble getting -gitolite to work, because you'll be attacking the wrong problem. - -So please please please understand this before tearing your hair out and -blaming ***git/gitolite*** for whatever is going wrong with your setup :-) - -## ssh basics - -Let's start with some basics, focusing *only* on the pieces relevant to -`gitolite`. If this is not detailed enough, please use google and learn more -from somewhere, or maybe buy the OReilly ssh book. - - * You can login to an ssh server by typing a password, but ssh can also use - ***public-private keys*** (also called "key pairs") for authentication. - `gitolite` *requires* you to use this mechanism for your users -- they - cannot log in using passwords. Hopefully by the time you finish reading - this document you will understand why :-) - - The way you set this up is you generate a key pair on your workstation, - and give the server the public key. (I need not add that the "private" - key must be, well, kept *private*!) - - * **Generating a key pair on your workstation** is done by running the - command `ssh-keygen -t rsa`. This produces two files in `~/.ssh`. One is - `id_rsa`; this is the **private** key -- ***never*** let it out of your - machine. The other is `id_rsa.pub`, which is the corresponding public - key. This public key is usually just one long line of text. - - * On Windows machines with msysgit installed, you should do this from - within a "git bash" window. The command will report the full path where - the files have been written; make a note of this, and use those files in - any of the description that follows. - - * **Adding your public key to the server**'s `~/.ssh/authorized_keys` - file is how ssh uses pubkeys to authenticate users. Let's say - sita@work.station is trying to log in as git@serv.er. What you have to do - is take the `~/.ssh/id_rsa.pub` file for user sita on work.station and - append its contents (remember it's only one line) to - `~/.ssh/authorized_keys` for user git on serv.er. - - The `authorized_keys` file can have multiple public keys (from many - different people) added to it so any of them can log in to git@serv.er. - - In the normal case (not gitolite, but your normal everyday shell access), - there's a command that does this, `ssh-copy-id`, which also fixes up - permissions etc., as needed, since sshd is a little picky about allowing - pubkey access if permissions on the server are loose. Or you can do it - manually, as long as you know what you're doing and you're careful not to - erase or overwrite the existing contents of `~/.ssh/authorized_keys` on - the server! - - But in the gitolite case, it's different; we'll get to that in a minute. - - * **Troubleshooting pubkey authentication failures**: if you are unable to - get ssh access to the server after doing all this, you'll have to look - in `/var/log/secure` or `/var/log/auth.log` or some such file on the - server to see what specific error `sshd` is complaining about. - - * **Restricting users to specific commands** is very important for gitolite. - If you read `man sshd` and look for `authorized_keys file format`, you'll - see a lot of options you can add to the public key line, which restrict - the incoming user in various ways. In particular, note the `command=` - option, which means "regardless of what the incoming user is asking to do, - forcibly run this command instead". - - Also note that when there are many public keys (i.e., lines) in the - `authorized_keys` file, each line can have a *different* set of options - and `command=` values. - - Without this `command=` option, the ssh daemon will simply give you a - shell, which is not what we want for our gitolite keys (although we may - well have other keys which we use to get a shell). - - **This is the backbone of what makes gitolite work; please make sure you - understand this**. - -## how does gitolite use all this ssh magic? - -These are two different questions you ought to be having by now: - - * How does it distinguish between me and someone else, since we're all - logging in as the same remote user "git". - * How does it restrict what I can do within a repository. - -### restricting shell access/distinguishing one user from another - -The answer to the first question is the `command=` we talked about before. If -you look in the `authorized_keys` file, you'll see entries like this (I chopped -off the ends of course; they're pretty long lines): - - command="[path]/gitolite-shell sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t... - command="[path]/gitolite-shell usertwo",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArXtCT... - -First, it finds out which of the public keys in this file match the incoming -login. That's crypto stuff, and I won't go into it. Once the match has been -found, it will run the command given on that line; e.g., if I logged in, it -would run `[path]/gitolite-shell sitaram`. So the first thing to note is -that such users do not get "shell access", which is good! - -Before running the command, however, sshd sets up an environment variable -called `SSH_ORIGINAL_COMMAND` which contains the actual git command that your -workstation sent out. This is the command that *would have run* if you did -not have the `command=` part in the authorised keys file. - -When `gitolite-shell` gets control, it looks at the first argument -("sitaram", "usertwo", etc) to determine who you are. It then looks at the -`SSH_ORIGINAL_COMMAND` variable to find out which repository you want to -access, and whether you're reading or writing. - -Now that it has a user, repository, and access requested (read/write), gitolite looks -at its config file, and either allows or rejects the request. - -But this cannot differentiate between different branches within a repo; that -has to be done separately. - -### restricting branch level actions - -[If you look inside the git source tree, there's a file among the "howto"s in -there called `update-hook-example.txt`, which was the inspiration for this -part of gitolite.] - -Git allows you to specify many "hooks", which get control as various events -happen -- see `git help hooks` for details. One of those hooks is the -`update` hook, which, if it is present, is invoked just before a branch or a -tag is about to be updated. The hook is passed the name of the branch or tag, -the old SHA1 value, and the new SHA1 value, as arguments. Hooks that are -called *before* an action happens are allowed to prevent that action from -happening by returning an error code. - -When gitolite is told to create a new repository (by the admin), it installs -a special update hook. This hook takes all the information presented, looks -at the config file, and decides to allow or reject the update. - -And that's basically it. diff --git a/doc/extras/putty.mkd b/doc/extras/putty.mkd deleted file mode 100644 index 5a4ff56..0000000 --- a/doc/extras/putty.mkd +++ /dev/null @@ -1,203 +0,0 @@ -# putty and msysgit - -This document is intended for those who wish to use Putty/Plink with msysgit. - -If you need more help with putty or component programs I suggest looking at [the official putty documentation](http://the.earth.li/~sgtatham/putty/latest/htmldoc/). - -**If you are not already using Putty for SSH it is recommended you do _NOT_ use it with msysgit.** - -**Please note that this only covers the client side of things, and does not involve server side components to troubleshooting. For that, please see the [ssh-troubleshooting document][sts].** - - - -## msysgit setup - -Provided you have putty sessions msysgit should give you the option of specifying a location to plink. If it did not then you will need to add an environment variable named "GIT\_SSH" to point at plink.exe, wherever you have that sitting. - -How to do that on your version of windows will likely vary, and is not covered here. For purposes of example, on a 64 bit Windows Vista machine the GIT\_SSH value could be: - - C:\Program Files (x86)\PuTTY\plink.exe - -Note the lack of quotes. - -Testing that msysgit is properly configured can be done from the git bash shell. Simply type (case sensitive, include the quotes): - - "$GIT_SSH" -V - -You should get a response similar to this: - - plink: Release 0.60 - -If instead you get a "command not found" type error you likely have a typo in your environment variable. - - - -## Going back to OpenSSH - -If you wish to go back to OpenSSH all you need to do is delete the GIT\_SSH environment variable. This will vary by your version of windows and thus is not covered here. - - - -## Putty keys - -If you do not already have putty private key files (.ppk) you will need to make at least one. You can either make a new one or convert an existing key to putty private key format. - -Either way, you will want to use puttygen. Note that you can go the other way if you want to stop using putty but keep the key by exporting the key to OpenSSH format. - - - -### Creating a new key - -To make it simple, I suggest SSH-2 RSA and a bit size of at least 1024. Larger keys will take longer to generate and will take longer to authenticate you on most systems. Making the key is as simple at hitting "Generate". - -It is recommended to give the key a meaningful comment. - - - -### Importing an existing key - -If you already have an OpenSSH or ssh.com key you can import it using the "Import" option on the "Conversions" menu. - -If the key does not have a meaningful comment I would suggest adding one at this point. - - - -### Loading an existing key - -If you need to load an existing key to edit or view it you can do so from the File menu. - - - -### Public key - -To get your public key for use with gitolite, load (or generate, or import) your key into puttygen. There is a box labeled "Public key for pasting into OpenSSH `authorized_keys` file" there. Copy the text into your preferred text editor and save. - - - -### Putty ageant - -Though not required in all cases you may wish to use the putty ageant, pageant, to load your key(s). This will allow for your key(s) to be passphrase protected but not have to enter the passphrase when you go to use them, provided you have already loaded the key into the ageant. - - - -## Sessionless or raw hostname usage - -When using plink without a putty session you pretty much have to load your keys with putty ageant, if only so that plink can find them. - - - -## Putty sessions - -In addition to hostnames msysgit can, when using putty, use putty sessions. This works in a manner similar to definitions in OpenSSH's `ssh_config` file. All settings in the session that apply to plink usage will be loaded, including the key file to use and even the username to connect to. Thus, instead of: - - ssh://user@host.example.ext:port/repo - -You can use: - - ssh://session_name/repo - - - -## Host key authentication - -Whether you are using hostnames or sessions you still run into one potential problem. Plink currently wants to validate the server's SSH host key before allowing you to connect, and when git calls plink there is no way to tell it yes. Thus, you may get something like this: - - The server's host key is not cached in the registry. You - have no guarantee that the server is the computer you - think it is. - The server's rsa2 key fingerprint is: - ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 - Connection abandoned. - fatal: The remote end hung up unexpectedly - -Or, in the case of the host key changing, something like this: - - WARNING - POTENTIAL SECURITY BREACH! - The server's host key does not match the one PuTTY has - cached in the registry. This means that either the - server administrator has changed the host key, or you - have actually connected to another computer pretending - to be the server. - The new rsa2 key fingerprint is: - ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 - Connection abandoned. - fatal: The remote end hung up unexpectedly - -The solution is to call plink directly, or start putty and connect with it first. To use plink, open the Git Bash shell and enter: - - "$GIT_SSH" hostname_or_session_name - -When you do you will see something like this: - - The server's host key is not cached in the registry. You - have no guarantee that the server is the computer you - think it is. - The server's rsa2 key fingerprint is: - ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 - If you trust this host, enter "y" to add the key to - PuTTY's cache and carry on connecting. - If you want to carry on connecting just once, without - adding the key to the cache, enter "n". - If you do not trust this host, press Return to abandon the - connection. - Store key in cache? (y/n) - -Or, in the case of a changed key, a response like this: - - WARNING - POTENTIAL SECURITY BREACH! - The server's host key does not match the one PuTTY has - cached in the registry. This means that either the - server administrator has changed the host key, or you - have actually connected to another computer pretending - to be the server. - The new rsa2 key fingerprint is: - ssh-rsa 2048 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 - If you were expecting this change and trust the new key, - enter "y" to update PuTTY's cache and continue connecting. - If you want to carry on connecting but without updating - the cache, enter "n". - If you want to abandon the connection completely, press - Return to cancel. Pressing Return is the ONLY guaranteed - safe choice. - Update cached key? (y/n, Return cancels connection) - -In either case hit y and the key will be stored. - - - -## Debugging multiple putty ageant keys - -In the event you are using putty ageant with multiple keys loaded you may see the wrong key being used. In general, pageant keys are tried in the order they were loaded into the ageant. If you have descriptive comment on each of your keys you can try connecting with plink in verbose mode to see what keys are being tried. Simply open the Git bash shell and run: - - "$GIT_SSH" -v user@hostname - -Or, if using sessions with a pre-entered username: - - "$GIT_SSH" -v session_name - -In either case, you should look for lines like: - - Trying Pageant key #0 - Authenticating with public key "My Key" from agent - -The first says which (numerical) key the ageant is trying. The second tells you the key comment for the authenticating key. To my knowledge the second line should only show up once, for the valid key. - - - -## Setperms and other commands - -When using wildcard repos the setperms command is very important, and other commands can come in handy as well. See their documentation for how to use them, but where they use: - - ssh user@host command etc etc - -You will want to use: - - "$GIT_SSH" user@host command etc etc - -Otherwise everything should be identical. - - - -## About this document - -This document was written by Thomas Berezansky (tsbere (at) mvlc (dot) org) in the hopes that it would be useful to those using putty on windows and wishing to use git/gitolite with their putty keys and sessions. diff --git a/doc/extras/regex.mkd b/doc/extras/regex.mkd deleted file mode 100644 index c334c2c..0000000 --- a/doc/extras/regex.mkd +++ /dev/null @@ -1,34 +0,0 @@ -# extremely brief regex overview - -Regexes are powerful. Gitolite uses that power as much as it can. If you -can't handle that power, hire someone who can and become a manager. - -That said, here's a very quick overview of the highlights. - -`^` and `$` are called "anchors". They anchor the match to the beginning and -end of the string respectively. - - ^foo matches any string starting with 'foo' - foo$ matches any string ending with 'foo' - ^foo$ matches exact string 'foo'. - -To be precise, the last one is "any string starting and ending with *the same* -'foo'". "foofoo" does not match. - -`[0-9]` is an example of a character class; it matches any single digit. -`[a-z]` matches any lower case alpha, and `[0-9a-f]` is the range of hex -characters. You should now guess what `[a-zA-Z0-9_]` does. - -`.` (the period) is special -- it matches any character. If you want to match -an actual period, you need to say `\.`. - -`*`, `?`, and `+` are quantifiers. They apply to the previous token. `a*` -means "zero or more 'a' characters". Similarly `a+` means "one or more", and -`a?` means "zero or one". - -As a result, `.*` means "any number (including zero) of any character". - -The previous token need not be a single character; you can use parens to make -it longer. `(foo)+` matches one or more "foo", (like "foo", "foofoo", -"foofoofoo", etc.) - diff --git a/doc/extras/ssh.mkd b/doc/extras/ssh.mkd deleted file mode 100644 index fb51655..0000000 --- a/doc/extras/ssh.mkd +++ /dev/null @@ -1,16 +0,0 @@ -# ssh - -If you're installing gitolite, you're a "system admin", like it or not. If -you're using the default ssh mode (i.e., not [http][] mode), ssh is a -necessary skill. Please take the time to learn at least enough to get -passwordless access working. - -There are two documents you need to read, in order: - - * [Gitolite and ssh][glssh] explains how gitolite uses openssh features to - create any number of virtual users over just one actual (unix) user, and - distinguish between them by their public keys. - - * [Ssh troubleshooting][sts] is a rather long document that, as far as I - know, covers almost every known ssh related issue. If you find something - missing, send me an email with details so I can update it. diff --git a/doc/extras/sts.mkd b/doc/extras/sts.mkd deleted file mode 100644 index 1c68f42..0000000 --- a/doc/extras/sts.mkd +++ /dev/null @@ -1,472 +0,0 @@ -# #sts ssh troubleshooting and tips - -**This document must be read in full the first time. If you start from some -nice looking section in the middle it may not help you unless you're already -an expert at ssh**. - -This document should help you troubleshoot ssh-related problems in installing -and accessing gitolite. It also has a section of random ssh-related tips and -tricks that gitolite can do. - ----- - -[[TOC]] - ----- - -## IMPORTANT -- READ THIS FIRST - -### caveats - - * Before reading this document, it is **mandatory** to read and **completely - understand** [this][ssh], which is a very detailed look at how gitolite - uses ssh's features on the server side. Don't assume you know all that; - if you did, you wouldn't be needing *this* document either! - - * This document, and others linked from this, together comprise all the help - I can give you in terms of the ssh aspect of using gitolite. If you're - installing gitolite, you're a "system admin", like it or not. Ssh is - therefore a necessary skill. Please take the time to learn at least - enough to get passwordless access working. - - * Please note that authentication is not really gitolite's job at all. I'd - rather spend time on actual gitolite features, code, and documentation - than authentication (i.e., ssh, in the common case). - - Surprised? [This][auth] might help explain better. - -### naming conventions used - - * Your workstation is the **client**. Your userid on the client does not - matter, and it has no relation to your gitolite username. - - * The server is called **server** and the "hosting user" is **git**. If - this is an RPM/DEB install, the hosting user is probably called - "gitolite", however we will use "git" in this document. - -### taking stock -- relevant files and directories - - * The client has a `~/.ssh` containing a few keypairs. It may also have a - `config` file. - - * The client also has a clone of the "gitolite-admin" repo, which contains a - bunch of `*.pub` files in `keydir`. We assume this clone is in `$HOME`; - if it is not, adjust instructions accordingly when needed. - - * The git user on the server has a `~/.ssh/authorized_keys` file that the - ssh daemon uses to authenticate incoming users. We often call this file - **authkeys** to save typing, and it always means the one on the server - (we're not interested in this file on the client side). - - * The server also has a `~/.gitolite/keydir` which contains a bunch of - `*.pub` files. - -### normal gitolite key handling - -Here's how normal gitolite key handling works: - - * (On client) pub key changes like adding new ones, deleting old ones, etc., - are done in the `keydir` directory in the gitolite-admin repo clone. Then - the admin `git add`s and `git commit`s those changes, then `git push`es - them to the server. - - * (On server) a successful push from the client makes git invoke the - post-update hook in the gitolite-admin repo. This hook is installed by - gitolite, and it does a bunch of things which are quite transparent to - the admin, but we'll describe briefly here: - - * The pubkey files from this push are checked-out into - `~/.gitolite/keydir` (and similarly the config files into - `~/.gitolite/conf`). - - * The "compile" script then runs, which uses these files to populate - `~/.ssh/authorized_keys` on the server. - - The authkeys file may have other, (non-gitolite) keys also. Those - lines are preserved. Gitolite only touches lines that are found - between gitolite's "marker" lines (`# gitolite start` and `# gitolite - end`). - -## common ssh problems - -Since I'm pretty sure at least some of you didn't bother to read the -"IMPORTANT: PLEASE READ FIRST" section above, let me take a minute to point -you there again. Especially the first bullet. - -Done? OK, read on... - -The following problem(s) indicate that pubkey access is not working at all, so -you should start with [appendix 1][stsapp1]. If that doesn't fix the problem, continue -with the other appendices in sequence. - - * Running any git clone/fetch/ls-remote or just `ssh git@server info` asks - you for a password. - -The following problem(s) indicate that your pubkey is bypassing gitolite and -going straight to a shell. You should start with [appendix 2][sshkeys-lint] -and continue with the rest in sequence. [Appendix 5][ybpfail] has some -background info. - - * Running `ssh git@server info` gets you the output of the GNU 'info' - command instead of gitolite's version and access info. - - * Running `git clone git@server:repositories/reponame` (note presence of - `repositories/` in URL) works. - - [A proper gitolite key will only let you `git clone git@server:reponame` - (note absence of `repositories/`)] - - * You are able to clone repositories but are unable to push changes back - (the error complains about the `GL_BINDIR` environment variable not being - set, and the `hooks/update` failing in some way). - - [If you run `git remote -v` you will find that your clone URL included the - `repositories/` described above!] - - * Conversely, using the correct syntax, `git clone git@server:reponame` - (note absence of `repositories/` in the URL), gets you `fatal: 'reponame' - does not appear to be a git repository`, and yet you are sure 'reponame' - exists, you haven't mis-spelled it, etc. - -## step by step - -Since I'm pretty sure at least some of you didn't bother to read the -"IMPORTANT: PLEASE READ FIRST" section above, let me take a minute to point -you there again. Especially the first bullet. - -Done? OK, now the general outline for ssh troubleshooting is this: - - * Make sure the server's overall setup even *allows* pubkey based login. - I.e., check that git fetch/clone/ls-remote commands or a plain `ssh - git@server info` do NOT ask for a password. If you do get asked for a - password, see [appendix 1][stsapp1]. - - * Match client-side pubkeys (`~/.ssh/*.pub`) with the server's authkeys - file. To do this, run `sshkeys-lint`, which tells you in detail what key - has what access. See [appendix 2][sshkeys-lint]. - - * At this point, we know that we have the right key, and that if sshd - receives that key, things will work. But we're not done yet. We still - need to make sure that this specific key is being offered/sent by the - client, instead of the default key. See [appendix 3][stsapp3] and - [appendix 4][ssh-ha]. - -## random tips, tricks, and notes - -### #giving-shell giving shell access to gitolite users - -Thanks to an idea from Jesse Keating, a single key can allow both gitolite -access *and* shell access. - -To do this: - - * add the list of users who will have shell access -- one username per line, - no extra whitespace -- to a plain text file of your choice. - - * put the name of this file in a new rc variable `SHELL_USERS_LIST`. For - example it could be - - SHELL_USERS_LIST => "$ENV{HOME}/.gitolite.shell-users", - - * add the line `'Shell::input',` to the `INPUT` list in the rc file. This - must be the first item on the list (possibly preceded by CpuTime, if - you're using that). - - * add the line `'post-compile/ssh-authkeys-shell-users',` to the - `POST_COMPILE` list, *after* the `'post-compile/ssh-authkeys',` line. - -Then run `gitolite compile; gitolite trigger POST_COMPILE` or push a dummy -change to the admin repo. - -### #kfn distinguishing one key from another - -Since a user can have [more than one key][multi-key], it is sometimes useful -to distinguish one key from another. Sshd does not tell you even the -fingerprint of the key that finally matched, so normally all you have is the -`GL_USER` env var. - -However, if you replace - - 'post-compile/ssh-authkeys', - -in the `POST_COMPILE` trigger list in the rc file with - - 'post-compile/ssh-authkeys --key-file-name', - -then an extra argument is added after the username in the "command" variable -of the authkeys file. That is, instead of this: - - command="/home/g3/gitolite/src/gitolite-shell u3",no-port-forwarding,... - -you get this: - - command="/home/g3/gitolite/src/gitolite-shell u3 keydir/u3.pub",no-port-forwarding,... - -You can then write an INPUT trigger to do whatever you need with the file -name, which is in `$ARGV[1]` (the second argument). The actual file is -available at `$ENV{GL_ADMIN_BASE}/$ARGV[1]` if you need its contents. - -### simulating ssh-copy-id - -don't have `ssh-copy-id`? This is broadly what that command does, if you want -to replicate it manually. The input is your pubkey, typically -`~/.ssh/id_rsa.pub` from your client/workstation. - - * It copies it to the server as some file. - - * It appends that file to `~/.ssh/authorized_keys` on the server - (creating it if it doesn't already exist). - - * It then makes sure that all these files/directories have go-w perms - set (assuming user is "git"): - - /home/git/.ssh/authorized_keys - /home/git/.ssh - /home/git - -[Actually, `sshd` requires that even directories *above* `~` (`/`, `/home`, -typically) also must be `go-w`, but that needs root. And typically -they're already set that way anyway. (Or if they're not, you've got -bigger problems than gitolite install not working!)] - -### problems with using non-openssh public keys - -Gitolite accepts public keys only in openssh format. Trying to use an "ssh2" -key (used by proprietary SSH software) will not be a happy experience. -src/triggers/post-compile/ssh-authkeys can be made to detect non-openssh -formats and automatically convert them; patches welcome! - -The actual conversion command, if you want to just do it manually for now and -be done with it, is: - - ssh-keygen -i -f /tmp/ssh2/YourName.pub > /tmp/openssh/YourName.pub - -then use the resulting pubkey as you normally would in gitolite. - -### windows issues - -On windows, I have only used msysgit, and the openssh that comes with it. -Over time, I have grown to distrust putty/plink due to the number of people -who seem to have trouble when those beasts are involved (I myself have never -used them for any kind of git access). If you have unusual ssh problems that -just don't seem to have any explanation, try removing all traces of -putty/plink, including environment variables, etc., and then try again. - -Thankfully, someone contributed [this][putty]. - -## #stsapp1 appendix 1: ssh daemon asks for a password - -> **NOTE**: This section should be useful to anyone trying to get -> password-less access working. It is not necessarily specific to gitolite, -> so keep that in mind if the wording feels a little more general than you -> were expecting. - -You have generated a keypair on your workstation (`ssh-keygen`) and copied the -public part of it (`~/.ssh/id_rsa.pub`, by default) to the server. - -On the server you have appended this file to `~/.ssh/authorized_keys`. Or you -ran something, like the `gitolite setup` step during a gitolite install, which -should have done that for you. - -You now expect to log in without having to type in a password, but when you -try, you are being asked for a password. - -This is a quick checklist: - - * Make sure you're being asked for a password and not a pass*phrase*. Do - not confuse or mistake a prompt saying `Enter passphrase for key - '/home/sitaram/.ssh/id_rsa':` for a password prompt from the remote - server! - - When you create an ssh keypair using `ssh-keygen`, you have the option of - protecting it with a passphrase. When you subsequently use that keypair - to access a remote host, your *local* ssh client needs to unlock the - corresponding private key, and ssh will probably ask for the passphrase - you set when you created the keypair. - - You have two choices to avoid this prompt every time you try to use the - private key. The first is to create keypairs *without* a passphrase (just - hit enter when prompted for one). **Be sure to add a passphrase later, - once everything is working, using `ssh-keygen -p`**. - - The second is to use `ssh-agent` (or `keychain`, which in turn uses - `ssh-agent`) or something like that to manage your keys. Other than - discussing one more potential trouble-spot with ssh-agent (see below), - further discussion of ssh-agent/keychain is out of scope of this document. - - * Ssh is very sensitive to permissions. An extremely conservative setup is - given below, but be sure to do this on **both the client and the server**: - - cd $HOME - chmod go-rwx . - chmod -R go-rwx .ssh - - * Actually, every component of the path to `~/.ssh/authorized_keys` all the - way upto the root directory must be at least `chmod go-w`. So be sure to - check `/` and `/home` also. - - * While you're doing this, make sure the owner and group info for each of - these components are correct. `ls -ald ~ ~/.ssh ~/.ssh/authorized_keys` - will tell you what they are. - - * You may also want to check `/etc/ssh/sshd_config` to see if the "git" user - is allowed to login at all. For example, if that file contains an - `AllowUsers` config entry, then only users mentioned in that line are - allowed to log in! - - * While you're in there, check that file does NOT have a setting for - `AuthorizedKeysFile`. See `man sshd_config` for details. This setting is - a show stopper for gitolite to use ssh. - - * Some OSs/distributions require that the "git" user should have a password - and/or not be a locked account. You may want to check that as well. - - * If your server is running SELinux, and you install gitolite to - `/var/gitolite` or another location unsupported by default SELinux - policies, then SELinux will prevent sshd from reading - `.ssh/authorized_keys`. Consider installing gitolite to - `/var/lib/gitolite`, which is a supported location by default SELinux - policies. - - * If all that fails, log onto the server as root, `cd /var/log`, and look - for a file called `auth.log` or `secure` or some such name. Look inside - this file for messages matching the approximate time of your last attempt - to login, to see if they tell you what is the problem. - -## #sshkeys-lint appendix 2: which key is which -- running sshkeys-lint - -The sshkeys-lint program can be run on the server or the client. Run it with -'-h' to get a help message. - -On the server you can run `gitolite sshkeys-lint` and it will tell you, for -each key in the admin directory's keydir, what access is available. This is -especially good at finding duplicate keys and such. - -To run it on the client you have to copy the file src/commands/sshkeys-lint -from some gitolite clone, then follow these steps: - - * Get a copy of `~/.ssh/authorized_keys` from the server and put it in - `/tmp/foo` or something. - - * cd to `~/.ssh`. - - * Run `/path/to/sshkeys-lint *.pub < /tmp/foo`. - -Note that it is not trying to log in or anything -- it's just comparing -fingerprints as computed by `ssh-keygen -l`. - -If the pubkey file you're interested in appears to have the correct access to -the server, you're done with this step. - -Otherwise you have to rename some keypairs and try again to get the effect you -need. Be careful: - - * Do not just rename the ".pub" file; you will have to rename the - corresponding private key also (the one with the same basename but without - an extension). - - * If you're running ssh-agent, you may have to delete (using `ssh-add -D`) - and re-add identities for it to pick up the renamed ones correctly. - -### typical cause(s) - -The admin often has passwordless shell access to `git@server` already, and -then used that same key to get access to gitolite (i.e., copied that same -pubkey as YourName.pub and ran `gitolite setup` on it). - -As a result, the same key appears twice in the authkeys file now, and since -the ssh server will always use the first match, the second occurrence (which -invokes gitolite) is ignored. - -To fix this, you have to use a different keypair for gitolite access. The -best way to do this is to create a new keypair, copy the pubkey to the server -as YourName.pub, then run `gitolite setup -pk YourName.pub` on the server. -Remember to adjust your agent identities using ssh-add -D and ssh-add if -you're using ssh-agent, otherwise these new keys may not work. - -## #stsapp3 appendix 3: ssh client may not be offering the right key - - * Make sure the right private key is being offered. Run ssh in very - verbose mode and look for the word "Offering", like so: - - ssh -vvv user@host pwd 2> >(grep -i offer) - - If some keys *are* being offered, but not the key that was supposed to be - used, you may be using ssh-agent (next bullet). You may also need to - create some host aliases in `~/.ssh/config` ([appendix 4][ssh-ha]). - - * (ssh-agent issues) If `ssh-add -l` responds with either "The agent has no - identities." or "Could not open a connection to your authentication - agent.", then you can skip this bullet. - - However, if `ssh-add -l` lists *any* keys at all, then something weird - happens. Due to a quirk in ssh-agent, ssh will now *only* use one of - those keys, *even if you explicitly ask* for some other key to be used. - - In that case, add the key you want using `ssh-add ~/.ssh/YourName` and try - the access again. - -## #ssh-ha appendix 4: ssh host aliases - -(or "making git use the right options for ssh") - -The ssh command has several options for non-default items to be specified. -Two common examples are `-p` for the port number if it is not 22, and `-i` for -the public key file if you do not want to use just `~/.ssh/id_rsa` or such. - -Git has two ssh-based URL syntaxes, but neither allows specifying a -non-default public key file. And a port number is only allowed in one of -them. (See `man git-clone` for details). Finally, hosts often have to be -referred with IP addresses (such is life), or the name is very long, or hard -to remember. - -Using a "host" para in `~/.ssh/config` lets you nicely encapsulate all this -within ssh and give it a short, easy-to-remember, name. Example: - - host gitolite - user git - hostname a.long.server.name.or.annoying.IP.address - port 22 - identityfile ~/.ssh/id_rsa - -Now you can simply use the one word `gitolite` (which is the host alias we -defined here) and ssh will infer all those details defined under it -- just -say `ssh gitolite` and `git clone gitolite:reponame` and things will work. - -(By the way, the 'port' and 'identityfile' lines are needed only if you have -non-default values, although I put them in anyway just to be complete). - -If you have *more than one* pubkey with access to the *same* server, you -**must** use this method to make git pick up the right key. There is no other -way to do this, as far as I know. - -[tut]: http://sites.google.com/site/senawario/home/gitolite-tutorial - -## #ybpfail appendix 5: why bypassing gitolite causes a problem - -When you bypass gitolite, you end up running your normal shell instead of the -special gitolite entry point script `gitolite-shell`. - -This means commands (like 'info') are interpreted by the shell instead of -gitolite. - -It also means git operations look for repos in `$HOME`. - -However, gitolite places all your repos in a subdirectory pointed to by -`$REPO_BASE` in the rc file (default: `repositories`), and internally prefixes -this before calling the actual git command you invoked. Thus, the pathname of -the repo that you use on the client is almost never the correct pathname on -the server. (This is by design. Don't argue...) - -This means that, you get 2 kinds of errors if you bypass gitolite - - * When you use `git@server:reponame` with a key that bypasses gitolite - (i.e., gets you a shell), this prefixing does not happen, and so the repo - is not found. Neither a clone/fetch nor a push will work. - - * Conversely, consider `git@server:repositories/reponame.git`. The clone - operation will work -- you're using the full Unix path, (assuming default - `$REPO_BASE` setting), and so the shell finds the repo where you said it - would be. However, when you push, gitolite's **update hook** kicks in, - and fails to run because some of the environment variables it is expecting - are not present. diff --git a/doc/files.mkd b/doc/files.mkd deleted file mode 100644 index 1cb7b2d..0000000 --- a/doc/files.mkd +++ /dev/null @@ -1,86 +0,0 @@ -# files involved in gitolite - -## install - -Let's say you start from a totally clean slate: - - $ pwd - /home/gl-test - - $ ls -a - . .. .bash_logout .bash_profile .bashrc - -You run `git clone git://github.com/sitaramc/gitolite`. - -Now you have - - $ ls -aF - ./ ../ .bash_logout .bash_profile .bashrc gitolite/ - - $ ls -aF gitolite - ./ ../ check-g2-compat* doc/ dot.pl .git/ install* src/ t/ - -If we were an existing user, we'd run the migration checker 'check-g2-compat' -(see [here][g2migr]). For now we're only interested in "gitolite/src", so: - - $ ls -aF gitolite/src - ./ ../ commands/ gitolite* Gitolite/ gitolite-shell* syntactic-sugar/ triggers/ VREF/ - -We check our PATH to make sure `$HOME/bin` is in it: - - $ echo $PATH - /usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/gl-test/.local/bin:/home/gl-test/bin - -Since it is, we run `mkdir bin; gitolite/install -ln`, and get: - - $ mkdir bin - $ gitolite/install -ln - - $ ls -aF - ./ ../ .bash_logout .bash_profile .bashrc bin/ gitolite/ - - $ ls -aF bin - ./ ../ gitolite@ - - $ file bin/gitolite - bin/gitolite: symbolic link to `/home/gl-test/gitolite/src/gitolite' - -That's the install done. At the end of it, we have just *one* symlink in -`$HOME/bin`; everything else is in a different directory. - -## setup - -Now you copy your pubkey (typically `id_rsa.pub`) from your workstation to the -server, then run `gitolite setup -pk "yourname.pub"`. Which gives you this: - - $ ls -aF - ./ .bash_logout .bashrc gitolite/ .gitolite.rc repositories/ .ssh/ - ../ .bash_profile bin/ .gitolite/ projects.list sitaram.pub - - $ ls -aF bin - ./ ../ gitolite@ - - $ ls -aF .gitolite - ./ ../ conf/ hooks/ keydir/ logs/ - - $ ls -aF repositories - ./ ../ gitolite-admin.git/ testing.git/ - - $ ls -aF .ssh - ./ ../ authorized_keys* - -And that's the setup done. At the end of this step, you have - - * `~/bin/gitolite` -- a symlink to `~/gitolite/src/gitolite`. The target of - this symlink tells gitolite where the rest of the code is. - * `~/gitolite/src` -- the rest of the code. - * `~/.gitolite` -- the gitolite "admin" directory. The only thing you - should directly touch here are the [log][] files and [hooks][]. (I.e., do - NOT change the conf or keydir contents here; see adding [users][] and - [repos][] for how to do that. - * `~/.gitolite.rc` -- the [rc][] file. - * `~/repositories` -- which contains all the repositories that gitolite will - be managing. - * `~/.ssh` -- which contains (at least) the `authorized_keys` file that - provides access to users. You can look inside that file and correlate it - with what the [ssh][] docs tell you, if you wish. diff --git a/doc/g2incompat.mkd b/doc/g2incompat.mkd deleted file mode 100644 index ca54ebc..0000000 --- a/doc/g2incompat.mkd +++ /dev/null @@ -1,103 +0,0 @@ -# #g2incompat incompatibility with g2 - -This page expands on some incompatibilities that were only briefly mentioned -in the [migration][g2migr] page. - -## #g2i-name NAME rules - -1. NAME/ rules must be changed to VREF/NAME/ - -2. Fallthru on all VREFs is "success" now, so any NAME/ rules you have - **MUST** change the ruleset in some way to maintain the same restrictions. - The simplest is to add the following line to the end of each repo's rule - list: - - - VREF/NAME/ = @all - -## #g2i-subconf subconf command in admin repo - -(This is also affected by the previous issue, 'NAME rules'; please read that -as well). - -If you're using delegation in your admin conf setup, please add the following -lines to the end of the gitolite-admin rules in your conf/gitolite.conf file: - - repo gitolite-admin - - VREF/NAME/ = @all - - subconf "fragments/*.conf" - -The first part compensates for fallthru now being a success when processing -[VREF][vref] rules (NAME rules are just one specific VREF). Although, -**ideally**, you should change your ruleset so that you no longer require that -line. As the [vref documentation][vref] says: - -> **Virtual refs are best used as additional "deny" rules**, performing -> extra checks that core gitolite cannot. - -The second part explicitly says when and where to include the subconf files. -(Before subconf was invented, this used to happen implicitly at the end of the -main conf file, and was hardcoded to that specific glob.) - -## #g2i-gl-time gl-time for performance measurement - -If you've been using gl-time for performance measurement, there's a much -better system available now. - -gl-time used to only log elapsed time. The new 'CpuTime' trigger module -shipped with gitolite, if enabled in the rc file, can also report CPU times -using perl's 'times()' function. See comments within that file and in the -default rc file that contain the word "cpu", for more details. - -Further, you can copy that module with a different name, add your own -functionality, and invoke *that* from the rc file instead. - -## #g2i-mirroring changes in mirroring setup - -There are several changes with regard to mirroring: - - * There is no 'post-receive' hook to be installed. Mirroring is handled by - g3's [triggers][] mechanism. Gitolite triggers are enabled by adding (or - uncommenting, in this case) appropriate lines in the rc file. - - * The `GL_HOSTNAME` variable is now `HOSTNAME`. (Note that the rc file - syntax itself has changed quite a bit; to be accurate, HOSTNAME is not a - variable but a hash key with an associated value). - - * The `GL_GITCONFIG_KEYS` variable is now `GIT_CONFIG_KEYS`, **but** you no - longer need to set it to anything for mirroring to work. - - * The `gl-tool` program does not exist anymore. Adding keys for peer - servers is done just like adding user keys, except that the pubkey file - name must start with `server-`. For example, to add a peer host called - frodo, you will acquire its pubkey and add it as `server-frodo.pub`. - - * The config variables are quite different now. The main ones now look like - this: - - option mirror.master = sam - option mirror.slaves = frodo gollum - - The redirectOK looks like this: - - option mirror.redirectOK = frodo - - The special value "true" to say that all slaves are trusted is now "all": - - option mirror.redirectOK = all - - * There are no more mirroring "keys", (lists of servers named in config keys - like 'gitolite.mirror.nightly', etc). You can certainly add lines like - - option mirror.nightly = merry pippin - - but they will not be processed by gitolite. Your cron jobs should use - `gitolite git-config` to query this variable, grab the list of peers, and - run `gitolite mirror` on each of them. - - * The external command to resync mirrors is 'mirror', run just like any - other [command][commands]. In particular, you can run `gitolite mirror - -h` to get help. It cannot be run from a slave to ask a master to push - (unlike in the old system) but what's more convenient is that any user who - has any access to the master can run it remotely (if you allow it) to - invoke a push. diff --git a/doc/g2migr-example.mkd b/doc/g2migr-example.mkd deleted file mode 100644 index 28ec8b2..0000000 --- a/doc/g2migr-example.mkd +++ /dev/null @@ -1,269 +0,0 @@ -# migration example - -This shows what a typical migration would look like, using a test setup. - -[[TOC]] - -## existing setup - -The existing gitolite is the latest in the "g2" (v2.x) branch. - -First, the rc file has the following lines different from the default: - - -$GL_WILDREPOS = 0; - +$GL_WILDREPOS = 1; - - -$GL_GITCONFIG_KEYS = ""; - +$GL_GITCONFIG_KEYS = ".*"; - -Next, the conf/gitolite.conf file in `~/.gitolite`: - - repo gitolite-admin - RW+ = tester u1 - - repo testing - RW+ = @all - - repo foo - RW+ = u1 u2 - RW+ NAME/ = u1 - RW+ NAME/u2 = u2 - - repo bar - RW = u2 - - repo baz/..* - C = u3 u4 - RW+ = CREATOR - config foo.bar = baz - -(Note that this conf file has NAME/ rules, which **have changed** -significantly in g3; see [here][g2i-name] for details). - -These are the repos already existing - - $ find repositories -name "*.git" | sort - repositories/bar.git - repositories/baz/u3.git - repositories/baz/u4.git - repositories/baz/uthree.git - repositories/foo.git - repositories/gitolite-admin.git - repositories/testing.git - -The config entries exist for all the baz/ repos: - - $ grep -2 foo `find repositories -name "config" ` - repositories/baz/uthree.git/config-[gitweb] - repositories/baz/uthree.git/config- owner = u3 - repositories/baz/uthree.git/config:[foo] - repositories/baz/uthree.git/config- bar = baz - -- - repositories/baz/u4.git/config-[gitweb] - repositories/baz/u4.git/config- owner = u4 - repositories/baz/u4.git/config:[foo] - repositories/baz/u4.git/config- bar = baz - -- - repositories/baz/u3.git/config-[gitweb] - repositories/baz/u3.git/config- owner = u3 - repositories/baz/u3.git/config:[foo] - repositories/baz/u3.git/config- bar = baz - -## preparing for the migration - -### getting g3 - -Fortunately this is easy here; I just happened to have the repo already -fetched so I just had to switch branches. You may have to 'git clone ...' -from github. - - $ cd gitolite - $ git checkout master - Branch master set up to track remote branch master from origin. - Switched to a new branch 'master' - -### run check-g2-compat - -This is a quick and dirty program to catch some of the big issues. - - $ cd - $ gitolite/check-g2-compat - INFO This program only checks for uses that make the new g3 completely unusable - or that might end up giving *more* access to someone if migrated as-is. - It does NOT attempt to catch all the differences described in the docs. - - INFO 'see docs' usually means doc/g2migr.mkd - (online at http://sitaramc.github.com/gitolite/g2migr.html) - - checking rc file... - NOTE GL_ADMINDIR is in the right place; assuming you did not mess with - GL_CONF, GL_LOGT, GL_KEYDIR, and GL_CONF_COMPILED - - checking conf file(s)... - SEVERE NAME rules; see docs - - checking repos... - WARNING found 3 gl-creater files; see docs - - ...all done... - -## the actual migration - -Here's the actual migration, step by step - -### step 1 - - $ ls -a bin - . gl-admin-push gl-install gl-setup-authkeys gl-VREF-DUPKEYS - .. gl-auth-command gl-mirror-push gl-system-install gl-VREF-EMAIL_CHECK - gitolite_env.pm gl-compile-conf gl-mirror-shell gl-time gl-VREF-FILETYPE - gitolite.pm gl-conf-convert gl-query-rc gl-tool gl-VREF-MERGE_CHECK - gitolite_rc.pm gl-dryrun gl-setup gl-VREF-COUNT sshkeys-lint - $ rm -rf bin;mkdir bin - - $ grep GL_PACKAGE .gitolite.rc - $GL_PACKAGE_CONF = "/home/g3/share/gitolite/conf"; - $GL_PACKAGE_HOOKS = "/home/g3/share/gitolite/hooks"; - $ rm -rf share - - $GL_PACKAGE_HOOKS = "/home/g3/share/gitolite/hooks"; - $ rm -rf share - - $ mv .gitolite.rc old.grc - -(still on step 1, this is substep 3) notice we are cloning **on the server**, -using a **full path** to the repo. - - $ git clone repositories/gitolite-admin.git old.ga - Cloning into 'old.ga'... - done. - $ rm -rf repositories/gitolite-admin.git/ - -Since I'm not interested in preserving the logs and don't have any custom -hooks: - - $ rm -rf .gitolite - -### step 2 - -I have no variables that *must* be preset, since the report by -`check-g2-compat` is clear. - -### step 3 - -Here we install the new gitolite. Remember we already got the new software -(in order to run 'check-g2-compat'). - -Just check that bin is empty, then run 'install -ln' from the gitolite source -tree: - - $ ls -al bin - total 8 - drwxrwxr-x 2 g3 g3 4096 Apr 24 10:57 . - drwx------ 8 g3 g3 4096 Apr 24 10:59 .. - $ gitolite/install -ln - $ ls -al bin - total 8 - drwxrwxr-x 2 g3 g3 4096 Apr 24 11:01 . - drwx------ 8 g3 g3 4096 Apr 24 10:59 .. - lrwxrwxrwx 1 g3 g3 30 Apr 24 11:01 gitolite -> /home/g3/gitolite/src/gitolite - -OK that went well. Now setup gitolite. You don't need a key here; just use a -random name: - - $ gitolite setup -a admin - Initialized empty Git repository in /home/g3/repositories/gitolite-admin.git/ - -### step 4 - -Now go to your old clone, and push it: - - $ cd old.ga - $ gitolite push -f - ...usual git progress output deleted... - remote: FATAL: git config foo.bar not allowed - remote: check GIT_CONFIG_KEYS in the rc file - To /home/g3/repositories/gitolite-admin.git - + 7eb8163...1474770 master -> master (forced update) - -Aaha! I forgot to set `CONFIG_KEYS` (new name for `GL_GIT_CONFIG_KEYS`) in -the new rc file so fix that: - - $ vim ~/.gitolite.rc - (edit and set it to `.*` for now) - -and push again: - - $ gitolite push -f - Everything up-to-date - -Damn. We have to make a dummy commit to allow the push to do something. - -But wait! We forgot fix the [NAME/][g2i-name] rules, so may as well fix -those, add, and push: - - $ vim conf/gitolite.conf - # change all NAME/ to VREF/NAME/ - # append a '- VREF/NAME/ = @all' at the end - # save - git add conf - - $ git commit -m name-rules - ... some output for add... - - $ gitolite push -f - Counting objects: 1, done. - Writing objects: 100% (1/1), 181 bytes, done. - Total 1 (delta 0), reused 0 (delta 0) - Unpacking objects: 100% (1/1), done. - To /home/g3/repositories/gitolite-admin.git - 1474770..4c2b41d master -> master - -### step 5 - -The only thing left is to fix up the gl-creater files: - - $ cd $HOME/repositories - $ find . -type d -name "*.git" -prune | while read r - > do - > mv $r/gl-creater $r/gl-creator - > done 2>/dev/null - -And we're done! - -## checking things out - -Let's see what repos u3 has: - - ssh u3 info - hello u3, this is g3@sita-lt running gitolite3 v3.0-11-g090b0f5 on git 1.7.7.6 - - C baz/..* - R W baz/u3 - R W baz/uthree - R W gitolite-admin - R W testing - -That's a combination of 'info' and 'expand', by the way. There is no expand -command any more. - -How about adding a new repo and checking if the config entries made it? - - $ git ls-remote u4:baz/ufour - Initialized empty Git repository in /home/g3/repositories/baz/ufour.git/ - $ grep -A1 foo `find repositories -name "config" ` - repositories/baz/u3.git/config:[foo] - repositories/baz/u3.git/config- bar = baz - -- - repositories/baz/u4.git/config:[foo] - repositories/baz/u4.git/config- bar = baz - -- - repositories/baz/ufour.git/config:[foo] - repositories/baz/ufour.git/config- bar = baz - -- - repositories/baz/uthree.git/config:[foo] - repositories/baz/uthree.git/config- bar = baz - -And there it is, in the second block of lines... - -And now we're really done. diff --git a/doc/g2migr.mkd b/doc/g2migr.mkd deleted file mode 100644 index 2783cf8..0000000 --- a/doc/g2migr.mkd +++ /dev/null @@ -1,279 +0,0 @@ -# #g2migr migrating from g2 - - **This document is a *MUST* read if you are currently using -g2 and want to move to g3.** - ----- - -[[TOC]] - ----- - -First things first: g2 will be supported for a good long time for critical -bugs, although enhancements and new features won't happen. - -Migration should be straightforward, but it is not automatic. The biggest -differences are in the rc file, mirroring, "NAME/" rules, and delegation. - -> ---- - -> **Presetting the rc file** - -> Some rc settings in the older gitolite are such that you cannot directly -> run `gitolite setup` when you're ready to migrate. **Doing that will -> clobber something important**. See [presetting the rc file][rc-preset] -> for details. - -> ---- - -The `check-g2-compat` program attempts to identify any *big* issues you will -be facing; run that first. See [later][cg2c] in this page for what its -messages mean. If it does not report any issues, your migrate will probably -go quickly. I still suggest you go through the links below in case that -program missed something. - -## incompatible features - -Here's a list of incompatible features and what you need to do to migrate. -Some of them have links where there is more detail than I want to put here. - -### high impact - -(serious loss of functionality and/or access control compromised) - - * [`NAME/`][g2i-name] rules: thes need to change to `VREF/NAME/`, and you - need to add a deny rule at the end because fallthru is "success" for all - [VREFs][vref] now, including the "NAME" VREF. - - * [subconf][g2i-subconf]: if you're using [delegation][deleg], there is no - implicit "subconf" at the end; you'll have to add it in. - - * There are several important differences in mirroring. You can start from - scratch by reading the new [mirroring][mirroring] doc or - [migrate][g2i-mirroring] (carefully!). - - * `ADMIN_POST_UPDATE_CHAINS_TO` -- **dropped**. Add your script to the - `POST_COMPILE` trigger chain. Your script won't be getting the arguments - that *git* sends to the post-update hook, but for the admin repo the only - argument that even comes in (or is significant) is "refs/heads/master" - anyway. - - * `GL_ALL_INCLUDES_SPECIAL` -- **dropped**, **requires presetting**. - - @all always includes gitweb and daemon now. Use [deny-rules][] if you - want to say `R = @all` but not have the repo(s) be visible to gitweb or - daemon. - - * `GL_NO_CREATE_REPOS` -- **dropped**. If you think you need this, email - me. I know one group who does need this so I will be putting it in - eventually but not right away. It's almost certain to be renamed anyway. - - * `GL_NO_DAEMON_NO_GITWEB` **dropped**, **requires presetting**. Default - will clobber your projects.list file and git-daemon-export-ok files. - - Comment out the appropriate lines in the rc file, in the `POST_COMPILE` - *and* the `POST_CREATE` trigger sections. As a bonus, gitweb and daemon - can now be separately disabled, instead of both being tied to the same - setting. - - * `GL_NO_SETUP_AUTHKEYS` **dropped**, **requires presetting**. Default will - clobber your authkeys file. - - Comment out all the line(s) that call ssh-authkeys in the rc file. - - * `UPDATE_CHAINS_TO` **dropped**, **requires presetting**. Default will - fail to run this extra check when users push. - - Use a [vref][] instead. You can directly use any existing chained-to - script as a VREF; they'll work. Don't forget to add a rule that - references the new VREF! - - * `GIT_PATH` **dropped**, **requires presetting**. - - If you need its functionality, add these lines to the end of the rc file: - - $ENV{PATH}="...whatever you want..."; - 1; - -### medium impact - -(important functionality lost, but access control not compromised) - - * `GL_ADMINDIR` -- **dropped**, is now at a fixed location: `~/.gitolite`. - If you want it somewhere else go ahead and move it, then place a symlink - from the assumed location to the real one. - - * `GL_GET_MEMBERSHIPS_PGM` -- is now `GROUPLIST_PGM`, see - [here][ldap]. - - * `GL_WILDREPOS_DEFPERMS` -- is now `DEFAULT_ROLE_PERMS`. - - * `REPO_BASE` -- **dropped**, is now at a fixed location: `~/repositories`. - If you want it somewhere else go ahead and move it, then place a symlink - from the assumed location to the real one. - -### low impact - -(ancillary, non-core, or minor functionality lost) - - * Built-in command `expand` -- **dropped**. The 'info' command shows you - both normal and wild repos now. The output format is also much simpler. - - * Built-in commands 'getperms', 'setperms' -- **merged** into external - command 'perms'. Run `ssh git@host perms -h` for details. - - Similarly, 'getdesc' and 'setdesc' have been merged into 'desc'. - - * Several 'ADC's -- see the [dev-status][] page for more on this. - - * [gl-time][g2i-gl-time]: the CpuTime module replaces gl-time. - - * `BIG_INFO_CAP` -- **dropped**. If you think you must have this, try it - without and see if there's a difference. If you *know* you need this, - convince me. - - * `GL_ADC_PATH` -- **dropped**. It is obsolete; use [commands][] or add - [your own][dev-notes]. - - * `GL_ALL_READ_ALL` -- **dropped**. If you think you must have this, try it - without and see if there's a difference. If you *know* you need this, - convince me. - - * `GL_BIG_CONFIG` -- **dropped**. This feature is default now. - - * `GL_CONF`, `GL_CONF_COMPILED`, and `GL_KEYDIR` -- **dropped**. You had no - business touching these anyway; if you did, move them into the expected - default locations before attempting to run `gitolite setup` - - * `GL_GITCONFIG_KEYS` -- is now `GIT_CONFIG_KEYS`. - - * `GL_LOGT` -- now has a fixed value; email me if this is a problem. - - * `GL_PACKAGE_CONF` and `GL_PACKAGE_HOOKS` -- **dropped**. They are not - needed anymore, but check if you had any custom hooks set in the latter - location and copy them across. - - * `GL_PERFLOGT` -- **dropped**. See [gl-time][g2i-gl-time]. - - * `GL_SITE_INFO` -- is now `SITE_INFO`. - - * `GL_WILDREPOS` -- **dropped**. This feature is default now. - - * `GL_WILDREPOS_PERM_CATS` -- is now the ROLES hash in the rc file. - - * `RSYNC_BASE` -- needs work. Email me if you are using this. - - * `NICE_VALUE` -- **dropped**. Uncomment the 'renice 10' line in the rc - file. You can also change the 10 to something else if you wish. - - * `PROJECTS_LIST` -- is now `GITWEB_PROJECTS_LIST`. More importantly, it is - only used by update-gitweb-access-list in src/commands/post-compile. This - variable now has nothing to do with gitolite core, and the rc is just - helping to store settings for external programs like that one. - - * `REPO_UMASK` -- is now `UMASK`. - - * `WEB_INTERFACE` and `GITWEB_URI_ESCAPE` -- **dropped**. Patches to the - update program to directly do those things are welcome. Personally, I - think people who use spaces and other funky characters in dir/file names - should be shot but no one listens to me anyway. - -## #cg2c using the "check-g2-compat" program - -This program checks a few things only, not everything. In particular, it -looks for settings and status that might: - - * make g3 unusable for lots of users - * make g3 give *more* access than g2 under some conditions - -It does NOT look for or warn about anything else; you're expected to read (and -act upon, if needed) the rest of the migration guide links given a few paras -above to cover everything else. - -Here's an explanation of those messages that the check-g2-compat program may -put that contain the words "see docs": - - * `GL_ADMINDIR in the wrong place -- aborting` - - It expects to find `GL_ADMINDIR` and `REPO_BASE` pointing to the right - places. It aborts if these conditions are not met and does not scan - further since that sort of guesswork is not good. If you are in that - position, make a symlink from the real location to the expected location, - change the RC accordingly, and re-try. - - * `REPO_BASE in the wrong place -- aborting` - - same as above - - * `NAME rules` - - **This is a significant difference and affects access badly (gives access - that would otherwise not be given)**. Please see the [list of non-RC - incompatibilities][g2incompat]. - - * `subconf command in admin repo` - - This is not so bad security wise but it might *reduce* access by not - processing files you intended to. Again, see the same link as in the - previous bullet. - - * `mirroring used` - - There have been quite a few changes to mirroring. You can start from - scratch by reading the new [mirroring][mirroring] doc or - [migrate][g2i-mirroring] (carefully!). - - * `found N gl-creater files` - - These need to be renamed to `gl-creator` (the correct spelling at last, - hooray!). Suggested command sequence: - - cd $HOME/repositories - find . -type d -name "*.git" -prune | while read r - do - mv $r/gl-creater $r/gl-creator - done 2>/dev/null - - Once you do this, the g2 will not work completely unless you change them - back. - - * `found N gl-perms files with R or RW` - - Setting perms of R and RW will no longer work; you have to say READERS and - WRITERS now. Suggested command: - - find `gitolite query-rc GL_REPO_BASE` -name gl-perms | - xargs perl -pi -e 's/\bR\b/READERS/;s/\bRW\b/WRITERS/' - -## #rc-preset presetting the rc file - -Some rc settings in the older gitolite are such that you cannot directly run -`gitolite setup` when you're ready to migrate. **Doing that will clobber -something important**. You have to create a default rc file, edit it -appropriately, and *then* run `gitolite setup`. - -The most serious example of this is `GL_NO_SETUP_AUTHKEYS`, which tells the -(old) gitolite that you want to manage `~/.ssh/authorized_keys` yourself and -it should not fiddle with it. - -If you don't preset the rc (in this case, by commenting out the 'ssh-authkeys' -line) **before** running `gitolite setup`, **your `~/.ssh/authorized_keys` -file will get clobbered**. - -The actual rc settings that require presetting are listed in the "high -impact" section above. This section tells you how to do the presetting. - - * save your old (g2) rc file somewhere, just in case - - * run - - gitolite print-default-rc > $HOME/.gitolite.rc - - * edit the file - - ${EDITOR:-vim} $HOME/.gitolite.rc - - make appropriate changes as described elsewhere in this migration guide, - and save it. - - * *then* you can run [gitolite setup][setup]. diff --git a/doc/g3why.mkd b/doc/g3why.mkd deleted file mode 100644 index ae6cad0..0000000 --- a/doc/g3why.mkd +++ /dev/null @@ -1,97 +0,0 @@ -# why a completely new version? - -Gitolite started life as 400 lines of perl written on a weekend because I was -quickly losing control of my projects at work, exacerbated by git newbies -doing all the wrong things. I really needed it! - -That little 400 line thing is now a huge bunch of programs that do all sorts -of things (I mean, rsync access control in a git related program? WTF!), -because it kinda just *grew* while I wasn't looking. - -So, briefly, here are the advantages of g3: - - * compile versus everything else - - g2's "compile" script was doing way, way too much. For example, dealing - with gitweb and git-daemon was a good chunk of code in g2. In contrast, - here's how g3 generates gitweb's projects.list file: - - ( - gitolite list-phy-repos | gitolite access % gitweb R any | grep -v DENIED - gitolite list-phy-repos | gitolite git-config -r % gitweb\\. - ) | - cut -f1 | sort -u | sed -e 's/$/.git/' > $plf - - * core versus non-core - - That's just the tip of the iceberg. The commands above run from a script - that is itself outside gitolite, and can be enabled and disabled from the - rc file. There are six different "events" within gitolite that can - trigger external programs, with specific arguments passed to them, much - like git's own hooks. The example you saw is called from the - "POST_COMPILE" trigger. - - And as you can see, these programs be in any language. - - * get/set perms/desc, and ADCs - - I've always wanted to kick setperms out of core and make it an ADC. - Sadly, it couldn't be done because when you update your repo's permissions - using setperms, that can affect gitweb/daemon access, which -- you guessed - right -- feeds back into the main code in complex ways. It *had* to be an - "inside job". - - But now, the new 'perms' program is quite external to gitolite. And how - does it fix up gitweb/daemon permissions after it is done updating the - "gl-perms" file? - - system("gitolite", "trigger", "POST_CREATE"); - - * syntax versus semantics - - I got tired of people asking things like "why can't I have - backslash-escaped continuation lines?" I designed it differently because - I don't like them but perhaps it's reasonable for some people. - - Someone else wanted to use subdirectories of 'keydir' as group names. Why - not? - - G3 comes with a stackable set of "syntactic sugar" helpers. And you can - write your own, though they do have to be in perl (because they're not - standalone programs). - - Once the code is written and placed in the right place, all a site has to - do to enable it is to uncomment some lines in the rc file: - - # these will run in sequence during the conf file parse - SYNTACTIC_SUGAR => - [ - # 'continuation-lines', - # 'keysubdirs-as-groups', - - - * roll your own - - Having a decent shell API helps enormously. You saw an example above but - how about if your boss asks you "I need a list of everyone who *currently* - has read access to the 'foo' repo"? - - Sure you could look in conf/gitolite.conf, all its include files (if you - have any), and if the repo is user-created, then in its gl-perms. - - Or you could do something like this: - - gitolite list-users | gitolite access foo % R any | cut -f1 - - * over-engineered - - g2 was, to some extent, over-engineered. One of the best examples is the - documentation on hook-propagation in g2, which required even a *picture* - to make clear (always a bad sign). In g3, the [hooks][] section is 4 - sentences. - -Anyway you get the idea. - -The point is not that you can do all these cool tricks. The point is they are -possible because of the redesign. There is no way on God's green earth I -could have done this with the old code. diff --git a/doc/git-config.mkd b/doc/git-config.mkd deleted file mode 100644 index 94487e1..0000000 --- a/doc/git-config.mkd +++ /dev/null @@ -1,66 +0,0 @@ -# "git-config" keys and values - -Here's all you want to know about setting repo-specific git-config values. - -(Original version thanks to teemu dot matilainen at iki dot fi) - -> ---- - -> **Note**: this won't work unless the rc file has the right settings; -> please see `$GIT_CONFIG_KEYS` in the [rc file doc][rc]. - -> ---- - -The syntax is simple: - - config sectionname.keyname = [optional value_string] - -For example: - - repo gitolite - config hooks.mailinglist = gitolite-commits@example.tld - config hooks.emailprefix = "[gitolite] " - config foo.bar = "" - config foo.baz = - -This does either a plain "git config section.key value" (for the first 2 -examples above) or "git config --unset-all section.key" (for the last 2 -examples). Other forms of the `git config` command (`--add`, the -`value_regex`, etc) are not supported. - -> ---- - -> **WARNING**: simply deleting the config line from the `conf/gitolite.conf` -> file will *not* delete the variable from `repo.git/config`. The syntax in -> the last example is the *only* way to make gitolite execute a -> `--unset-all` operation on the given key. - -> ---- - -You can also use the special value `%GL_REPO` in the string to save typing: - - repo foo bar baz - config hooks.mailinglist = %GL_REPO-commits@example.tld - config hooks.emailprefix = "[%GL_REPO] " - -You can repeat the 'config' line as many times as you like, and the last -occurrence will be the one in effect. This allows you to override settings -just for one project, as in this example: - - repo @all - config hooks.mailinglist = %GL_REPO-commits@example.tld - config hooks.emailprefix = "[%GL_REPO] " - - repo customer-project - # different mailing list - config hooks.mailinglist = announce@customer.tld - -The "delete config variable" syntax can also be used, if you wish: - - repo secret # no emails for this one please - config hooks.mailinglist = - config hooks.emailprefix = - -As you can see, the general idea is to place the most generic ones (`repo -@all`, or repo patterns like `repo foo.*`) first, and place more specific ones -later to override the generic settings. diff --git a/doc/groups.mkd b/doc/groups.mkd deleted file mode 100644 index 970ea1d..0000000 --- a/doc/groups.mkd +++ /dev/null @@ -1,30 +0,0 @@ -# group definitions - -You can group repos or users for convenience. The syntax is the same for both -and does not distinguish; until you *use* the group name it could really be -either. - -Here's an example: - - @developers = dilbert alice wally - -Group definitions accumulate; this is the same as the above: - - @developers = dilbert - @developers = alice - @developers = wally - -You can use one group in another group definition; the values will be expanded -right there (meaning later additions will not appear in the second group). - - @developers = dilbert alice - @interns = ashok - @staff = @interns @developers - @developers = wally - - # wally is NOT part of @staff - -## special group `@all` - -`@all` is a special group name that is often convenient to use if you really -mean "all repos" or "all users". diff --git a/doc/gsmigr.mkd b/doc/gsmigr.mkd deleted file mode 100644 index 0f54bbb..0000000 --- a/doc/gsmigr.mkd +++ /dev/null @@ -1,125 +0,0 @@ -# migrating from gitosis to gitolite - -[2012-04-09] Modified for gitolite g3. These instructions have not really -been tested with g3, but are expected to work. - -Migrating from gitosis to gitolite is fairly easy, because the basic design is -the same. - -There's only one thing that might trip up people: the userid. Gitosis uses -`gitosis`. Gitolite can use any userid you want; most of the documentation -uses `git`, while DEB/RPM packages use `gitolite`. - -Here are the steps on the server: - - * (as 'gitosis' on the server) **Rename** `~/.ssh/authorized_keys` to - something else so that no one can accidentally push while you're doing - this. - - * (as 'gitosis' on the server) For added safety, **delete** the post-update - hook that gitosis-admin installed - - rm ~/repositories/gitosis-admin.git/hooks/post-update - - or at least rename it to `.sample` like all the other hooks hanging - around, or edit it and comment out the line that calls `gitosis-run-hook - post-update`. - - * (as 'gitosis' on the server) If you already use the `update` hook for some - reason, you'll have to make that a [VREF][vref]. This is because gitolite - uses the update hook for checking write access. - - * (as 'root' on the server) copy all of `~/repositories` to the gitolite - hosting user's home directory. Something like - - cp -a /home/gitosis/repositories /home/git - chown -R git.git /home/git/repositories - - * (as 'root' and/or 'git' on the server) Follow instructions to install - gitolite; see the [install document][install]. - - This will give you a gitolite config that has the required entries for the - "gitolite-admin" repo. - -Now, log off the server and get back to the client. All subsequent -instructions are to be read as "on gitolite admin's workstation". - - * **Clone** the new gitolite-admin repo to your workstation. (You already - have a clone of the gitosis-admin repo so now you have both). - - * **Convert** your gitosis config file and append it to your gitolite config - file. Substitute the path for your gitosis-admin clone in `$GSAC` below, - and similarly the path for your gito**lite**-admin clone in `$GLAC`. (The - convert-gitosis-conf program is a standalone program that you can bring - over from any gitolite clone; you don't have to install all of gitolite on - your workstation to use this): - - ./convert-gitosis-conf < $GSAC/gitosis.conf >> $GLAC/conf/gitolite.conf - - **Be sure to check the file to make sure it converted correctly** -- due - it's "I only need it once" nature, this program has not received too much - attention from anyone! - - * Remove the entry for the 'gitosis-admin' repo. You do not need it here - and it may cause confusion. - - * **Copy** the keys from gitosis's keydir (same meanings for GSAC and GLAC) - - cp $GSAC/keydir/* $GLAC/keydir - - If your gitosis-admin key was `you@machine.pub`, and you supplied the same - one to gitolite's gl-setup program as `you.pub` when you installed - gitolite, then you should remove `you@machine.pub` from the new keydir - now. Otherwise you will have 2 pubkey files (`you.pub` and - `you@machine.pub`) which are identical, which is *not* a good idea. - - Similarly, you should replace all occurrences of `you@machine.pub` with - `you` in the `conf/gitolite.conf` file. - - * **IMPORTANT**: if you have any users with names like `user@foo`, where the - part after the `@` does *not* have a `.` in it (i.e., does not look like - an email address), you need to change them, because gitolite uses that - syntax for [enabling multi keys][multi-key]. - - You have two choices in how to fix this. You can change the gitolite - config so that all mention of `user@foo` is changed to just `user`. - - Or you can change each occurrence of `user@foo` to, say, `user_foo` *and* - change the pubkey filename in keydir/ also the same way (`user_foo.pub`). - - Just to repeat, you do NOT need to do this if the username was like - `user@foo.bar`, i.e., the part after the `@` had a `.` in it, because then - it looks like an email address. - - * **IMPORTANT: expand any multi-key files you may have**. Gitosis is happy - to accept files containing more than one public key (one per line) and - assign all the keys to the same user. Gitolite does not allow that; see - [here][multi-key]'s for how gitolite handles multi-keys. - - So if you had any multi-keys in gitosis, they need to be carefully split - into individual keys. - - You can split the keys manually, or use the following code (just - copy-paste it into your xterm after "cd"-ing to your gitolite-admin repo - clone): - - wc -l keydir/*.pub | grep -v total | grep -v -w 1 | while read a b - do - i=1 - cat $b|while read l - do - echo "$l" > ${b%.pub}@$i.pub - (( i++ )) - done - mv $b $b.done - done - - This will split each multi-key file (say "sitaram.pub") into individual - files called "sitaram@1.pub", "sitaram@2.pub", etc., and rename the - original to "sitaram.pub.done" so gitolite won't pick it up. - - At this point you can rename the split parts more appropriately, like - "sitaram@laptop.pub" and "sitaram@desktop.pub" or whatever. *Please check - the files to make sure this worked properly* - - * Check all your changes to your gitolite-admin clone, commit, and push. diff --git a/doc/http.mkd b/doc/http.mkd deleted file mode 100644 index 3b9809e..0000000 --- a/doc/http.mkd +++ /dev/null @@ -1,157 +0,0 @@ -# how to setup gitolite to use smart http mode - -**Note**: "smart http" refers to the feature that came with git 1.6.6, late -2009 or so. The base documentation for this is `man git-http-backend`. Do -**NOT** read `Documentation/howto/setup-git-server-over-http.txt` and think -that is the same or even relevant -- that is from 2006 and is quite different -(and arguably obsolete). - -## WARNINGS and important notes - - * Please read [authentication versus authorisation][auth] first, and make - sure you understand what is gitolite's responsibility and what isn't. - - * I have tested this only on stock Fedora 16; YDMV. - -## assumptions: - - * Apache 2.x and git installed. - * Httpd runs under the "apache" userid; adjust instructions below if not. - * Similarly for "/var/www" and other file names/locations. - -## instructions - -The detailed instructions I used to have in g2 have now been replaced by a -script called `t/smart-http.root-setup`. **Do NOT run this script as is -- it -is actually meant for my testing setup and deletes stuff**. However, it does -provide an excellent (and working!) narration of what you need to do to -install gitolite in smart http mode. - -Make a copy of the script, go through it carefully, (possibly removing lines -that delete files etc.), change values per your system, and only then run it. - -Note that the `GIT_PROJECT_ROOT` variable (see "man -git-http-backend") is no longer optional. Make sure you set it to some place -outside apache's `DOCUMENT_ROOT`. - -## Making repositories available to both ssh and http mode clients - -This section has been contributed by Thomas Hager (duke at sigsegv dot at). - -Assumptions: - - * Apache 2.x with CGI and Suexec support installed. - * Git and Gitolite installed with user "git" and group "git", and pubkey SSH - access configured and working. - * Git plumbing installed to /usr/libexec/git-core - * Gitolite base located at /opt/git - * Apache `DOCUMENT_ROOT` set to /var/www - * Apache runs with user www and group www - -Please adjust the instructions below to reflect your setup (users and paths). - -Edit your .gitolite.rc and add - - $ENV{PATH} .= ":/opt/git/bin"; - -at the very top (as described in `t/smart-http.root-setup`). - -Next, check which document root your Apache's suexec accepts: - - # suexec -V - -D AP_DOC_ROOT="/var/www" - -D AP_GID_MIN=100 - -D AP_HTTPD_USER="www" - -D AP_LOG_EXEC="/var/log/apache/suexec.log" - -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" - -D AP_UID_MIN=100 - -D AP_USERDIR_SUFFIX="public_html" - -We're interested in `AP_DOC_ROOT`, which is set to `/var/www` in our case. - -Create a `bin` and a `git` directory in `AP_DOC_ROOT`: - - install -d -m 0755 -o git -g git /var/www/bin - install -d -m 0755 -o www -g www /var/www/git - -`/var/www/git` is just a dummy directory used as Apache's document root (see below). - -Next, create a shell script inside `/var/www/bin` named `gitolite-suexec-wrapper.sh`, -with mode **0700** and owned by user and group **git**. Add the following content: - - #!/bin/bash - # - # Suexec wrapper for gitolite-shell - # - - export GIT_PROJECT_ROOT="/opt/git/repositories" - export GITOLITE_HTTP_HOME="/opt/git" - - exec ${GITOLITE_HTTP_HOME}/gitolite-source/src/gitolite-shell - -Edit your Apache's config to add http pull/push support, preferably in -a dedicated `VirtualHost` section: - - - ServerName git.example.com - ServerAlias git - ServerAdmin you@example.com - - DocumentRoot /var/www/git - - Options None - AllowOverride none - Order allow,deny - Allow from all - - - SuexecUserGroup git git - ScriptAlias /git/ /var/www/bin/gitolite-suexec-wrapper.sh/ - ScriptAlias /gitmob/ /var/www/bin/gitolite-suexec-wrapper.sh/ - - - AuthType Basic - AuthName "Git Access" - Require valid-user - AuthUserFile /etc/apache/git.passwd - - - -This Apache config is just an example, you probably should adapt the authentication -section and use https instead of http! - -Finally, add an `R = daemon` access rule to all repositories you want to -make available via http. - -## usage - -### client side - -Git URLs look like `http://user:password@server/git/reponame.git`. - -The custom commands, like "info", "expand" should be handled as follows. The -command name will come just after the `/git/`, followed by a `?`, followed by -the arguments, with `+` representing a space. Here are some examples: - - # ssh git@server info - curl http://user:password@server/git/info - # ssh git@server info repopatt - curl http://user:password@server/git/info?repopatt - # ssh git@server info repopatt user1 user2 - curl http://user:password@server/git/info?repopatt+user1+user2 - -With a few nice shell aliases, you won't even notice the horrible convolutions -here ;-) See t/smart-http for a couple of useful ones. - -### server side - -The 'gitolite' command (for example, 'gitolite compile', 'gitolite query-rc', -and so on) *can* be run on the server, but it's not straightforward. Assuming -you installed exactly as given in this document, you should - - * get a shell by using, say, `su -s /bin/bash - apache` - * run `export HOME=$HOME/gitolite-home` - * run `export PATH=$PATH:$HOME/bin` - -and *then* you can run `gitolite ` - diff --git a/doc/index.mkd b/doc/index.mkd deleted file mode 100644 index 9552975..0000000 --- a/doc/index.mkd +++ /dev/null @@ -1,66 +0,0 @@ -# Hosting git repositories - -Gitolite allows you to setup git hosting on a central server, with -fine-grained access control and many more powerful features. - -Here's more on [what][] it is and [why][] you might need it. - - - -## #g2 (for older gitolite (v1.x and v2.x) users) - -For users of gitolite v2.x (call it "g2" for convenience), - - * [Why][g3why] I rewrote gitolite. - * Development [status][dev-status]. - * Information on [migrating][migr] from g2 to g3. - - - -## #ql quick links - - * [Trying][trying] out gitolite. - * Minimum [requirements][req]. - * Here's how to do a [quick install, setup, and clone][qi]. - * Don't know ssh well enough? [Learn][ssh]. It's **IMPORTANT**. - * Add [users][] and [repos][]. - * Learn about fine-grained access control with the [conf][] file. - * Explain gitolite to your [users][user]. - -The rest of the documentation is in the "master index" link at the top of each -page on this website. This is the first place you should search when looking -for specific information. - -## #what What is gitolite? - -Gitolite is an access control layer on top of git. Here are the features that -most people see: - - * Use a single unix user ("real" user) on the server. - * Provide access to many gitolite users: - * they are not "real" users, - * they do not get shell access. - * Control access to many git repositories: - * read access controlled at the repo level, - * write access controlled at the branch/tag/file/directory level, - including who can rewind, create, and delete branches/tags. - * Can be installed without root access, assuming git and perl are already - installed. - * Authentication is most commonly done using sshd, but you can also use - [http][] if you prefer (this may require root access). - -## #contact contact - - * author: sitaramc@gmail.com, sitaram@atc.tcs.com - * mailing list: gitolite@googlegroups.com - * list subscribe address : gitolite+subscribe@googlegroups.com - * IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 - time zone). - -## #license license - -The gitolite *code* is released under GPL v2. See COPYING for details. - -The gitolite documentation is provided under a [Creative Commons -Attribution-NonCommercial-ShareAlike 3.0 Unported -License](http://creativecommons.org/licenses/by-nc-sa/3.0/). diff --git a/doc/install.mkd b/doc/install.mkd deleted file mode 100644 index 519ab52..0000000 --- a/doc/install.mkd +++ /dev/null @@ -1,265 +0,0 @@ -# installing gitolite - -**NOTE**: if you're migrating from g2, there are some -settings that MUST be dealt with **before** running `gitolite setup`; please -start [here][migr]. RTFM is *mandatory* for migrations. - ----- - -This is the first step in using gitolite, and happens on the server. It is -followed by [setup][], then [clone][]. - ----- - -[[TOC]] - ----- - -## notes and naming conventions - -Gitolite uses a single "real" (i.e., unix) user to provide secure access to -git repos to any number of "virtual" users, without giving them a shell. - -The real user used is called the **hosting user**. Typically this user is -*git*, and that is what we will use throughout the documentation. However -RPMs and DEBs create a user called *gitolite* for this, so adjust instructions -and examples accordingly. - -**Unless otherwise stated, everything in this page is to be done by logging in -as this "hosting user"**. - -Notes: - - * Any unix user can be a hosting user. - * Which also means you can have several hosting users on the same machine. - * The URLs used will be of the form `git@host:reponame` (or its longer - equivalent starting with `ssh://`). The `.git` at the end is optional. I - recommend you leave it out, so your reponames are consistent with what the - conf file uses. - -## #req requirements - -### your skills - - * If you're installing gitolite, you're a "system admin", like it or not. - Ssh is therefore a necessary skill. Please take the time to learn at - least enough to get passwordless access working. - - * You also need to be somewhat familiar with git itself. You cannot - administer a whole bunch of git repositories if you don't know the basics - of git. - - * Some familiarity with Unix and shells is probably required. - - * Regular expressions are a big part of gitolite in many places but - familiarity is not necessary to do *basic* access control. - -### server - - * Any Unix system with a posix compatible "sh". - * Git version 1.6.6 or later. - * Perl 5.8.8 or later. - * Openssh (almost any version). Optional if you're using [smart - http][http]. - * A dedicated Unix userid to be the hosting user, usually "git" but it can - be any user, even your own normal one. (If you're using an RPM/DEB the - install probably created one called "gitolite"). - -Also see the [WARNINGS][] page for more on what gitolite expects on the server -side. - -### client - - * Openssh client. - * Git 1.6.6 or later. Almost any git client will work, as long as it knows - how to use ssh keys and send the right one along. - -## getting the software - - git clone git://github.com/sitaramc/gitolite - -## the actual install - -**Note**: This section describes installing an ssh-based setup. For smart -http setup click [here][http]. - -Gitolite has only one server side "command" now, much like git itself. This -command is `gitolite`. You don't need to place it anywhere special; worst -case you run it with the full path. - -"Installation" consists of the following options: - -1. Keep the sources anywhere and use the full path to run the `gitolite` - command. -2. Keep the sources anywhere and symlink *just* the `gitolite` program to - some directory on your `$PATH`. -3. Copy the sources somewhere and use that path to run the `gitolite` - command. - -Option 2 is the best for general use. - -There is a program called 'install' that helps you do these easily. Assuming -your cloned the repo like this: - - git clone git://github.com/sitaramc/gitolite - -you can run the 'install' command in 3 different ways: - - # option 1 - gitolite/install - - # option 2 - gitolite/install -ln - # defaults to $HOME/bin (which is assumed to exist) - # ** or ** - # or use a specific directory (please supply full path): - gitolite/install -ln /usr/local/bin - - # option 3 - # (again, please supply a full path) - gitolite/install -to /usr/local/gitolite/bin - -Creating a symlink doesn't need a separate program but 'install' also runs -`git describe` to create a VERSION file, which, trust me, is important! - -**Next step**: run [**setup**][setup]. - -## upgrading - - * Update your clone of the gitolite source. - * Repeat the install command you used earlier (make sure you use the same - arguments as before). - * Run `gitolite setup`. - -## #package packaging gitolite - -Gitolite has broad similarities to git in terms of packaging requirements. - - * Git has 150 executables to marshal and put somewhere. Gitolite has the - directories `commands`, `lib`, `syntactic-sugar`, `triggers`, and `VREF`. - - It doesn't matter what this directory is. As an example, Fedora keeps - git's 150 executables in /usr/libexec/git-core, so /usr/libexec/gitolite - may be a good choice; it's upto you. - - *The rest of this section will assume you chose /usr/libexec/gitolite as - the location, and that this location contains the 5 directories named - above*. - - * Git has the `GIT_EXEC_PATH` env var to point to this directory. Gitolite - has `GL_BINDIR`. However, in git, the "make" process embeds a suitable - default into the binary, making the env var optional. - -With that said, here's one way to package gitolite: - - * Put the executable `gitolite` somewhere in PATH. Put the executable - `gitolite-shell` in /usr/libexec/gitolite (along with those 5 directories). - - Change the 2 assignments to `$ENV{GL_BINDIR}`, one in 'gitolite', one in - 'gitolite-shell', to "/usr/libexec/gitolite" from `$FindBin::RealBin`. - This is equivalent to "make" embedding the exec-path into the executable. - - **OR** - - Put both executables `gitolite` and `gitolite-shell` also into - /usr/libexec/gitolite (i.e., as siblings to the 5 directories mentioned - above). Then *symlink* `/usr/libexec/gitolite/gitolite` to some directory - in the PATH. Do not *copy* it; it must be a symlink. - - Gitolite will find the exec-path by following the symlink. - - * The `Gitolite` subdirectory in `/usr/libexec/gitolite/lib` can stay right - there, **OR**, if your distro policies don't allow that, can be put in any - directory in perl's `@INC` path (such as `/usr/share/perl5/vendor_perl`). - - * Finally, a file called `/usr/libexec/gitolite/VERSION` must contain a - suitable version string. - -## #migr migrating - -This section is about migrating from older gitolite to -"g3". If you're migrating from gitosis, see [here][gsmigr]. - -First things first: g2 will be supported for a good long time for critical -bugs, although enhancements and new features won't happen. - -If you're an existing (gitolite v1.x or v2.x) user, and wish to migrate , here -are the steps: - -### pre-migration checks - -1. Check the [dev-status][] page to make sure all the features you want have - been implemented in g3. - -2. Read the [g2 migration][g2migr] page to see what changes affect you and - your users, and how much time it might take you to migrate. (The closer - you were to a default install of the old gitolite, the less time a - migration will take.) - - This includes at least running `check-g2-compat` to see what are the big - issues you might need to address during the migration. - -### the actual migration - -(Note: You may also like the [example migration][g2migr-example] page). - -**Note**: nothing in any of the gitolite install/setup/etc will ever touch the -*data* in any repository except the gitolite-admin repo. The only thing it -will normally touch in normal repos is the `update` hook. - -**Note: all migration happens on the server; you do not need your -workstation**. - -1. Carefully wipe out the old gitolite: - - * The **code** - - * Delete or move away all the old gitolite scripts. Check the path - to the gl-auth-command in `~/.ssh/authorized_keys` if you forgot - where you put them. - - * Delete or move away the two directories named in the two variables - `GL_PACKAGE_CONF` and `GL_PACKAGE_HOOKS` in `~/.gitolite.rc`. - - * The **rc file** - - * Rename `~/.gitolite.rc` to something else. - - * The **admin repo** - - * clone `~/repositories/gitolite-admin.git` to someplace safe - * then delete `~/repositories/gitolite-admin.git` - - (Make sure you do not delete any other repos!) - - * The **admin directory**. - - * If you need to preserve logs, move the ~/.gitolite/logs` directory - somewhere else. - - * If you added any custom hooks and wish to preserve them, move the - ~/.gitolite/hooks` directory somewhere else. - - * Delete `~/.gitolite`. - -2. Read about [presetting][rc-preset] the rc file; if you're using any - variables listed as requiring preset, follow those instructions to create - your new rc file. - -3. Install gitolite g3; see [quick install and setup][qi] or [install][] - followed by [setup][]. However, the 'setup' step need not supply a - private key. You can run it as `gitolite setup -a admin`. - - NOTE: ignore any 'split conf not set, gl-conf present...' errors at this - time. You may see none, some, or many. It does not matter right now. - -4. Make sure your gitolite-admin clone has the correct pubkey for the - administrator in its `keydir` directory, then run [`gitolite push - -f`][bypass] to overwrite the "default" admin repo created by the install. - -5. Handle any errors, look for migration issues, etc., as described in the - links at the top of this page. - - This also includes building up your new `~/.gitolite.rc` file. - -You're done. diff --git a/doc/ips.mkd b/doc/ips.mkd deleted file mode 100644 index dcbff02..0000000 --- a/doc/ips.mkd +++ /dev/null @@ -1,104 +0,0 @@ -## idiot-proof setup for gitolite - -WARNING 1: this document uses my new, Linus-inspired, motto: people who get -offended, *should* be offended. - -WARNING 2: contains more words in ALL CAPS than all my other documents put -together. - -WARNING 3: this document will work for any Linux on which git has already been -installed. BSDs, or legacy systems like Solaris, also should work but I can't -guarantee it or test it. - ----- - -Some people seem to get terribly, **terribly** confused by ssh. If you've -read through all the [documentation on ssh][ssh] that came with gitolite, yet -you *still* cannot get things to work, you have two choices: - -1. exchange your "developer" badge for a "manager" badge and then hire - someone to do this. - -2. start over with the instructions below. They include some DRASTIC - measures, requirements, and restrictions, almost NONE of which are - normally necessary, but it's either that or a suit and tie from tomorrow - so play along. - -**IMPORTANT**: Do NOT ask for help on these instructions unless you have kept -a detailed log of every command you typed, and the complete response you got. -I do not ask for this information to help you -- that's only a front. I -*know* these instructions work (at least on any Linux that already has git -installed), so the real reason is to find where you mistyped something and -mock you for that, - -### Assumptions - - * your name is Ron. Substitute accordingly in the instructions below. - - * you have a workstation. - - * you have a server called `server`. - - * you have root access on this server. - -### Tasks - -1. Create a new userid on the server, say `git`. This will be the **hosting - user**. ("hosting user" means when you're done installing, your users - will use URLs like `git@server:reponame` or `ssh://git@server/reponame`). - - **Make sure this is a NEW userid**. - - If the name you want already exists, then: - - * log in as root - * if you have any data on that user's HOME directory save it somewhere - else - * delete the userid - * obliterate the home directory of the user (since on most systems - merely deleting the user does not remove the home directory). - * re-create the userid again - -2. If you don't already have one, make yourself an ssh keypair **on your - workstation**. - - Do NOT, in a fit of inspiration and energy, add this public key to the - authorised keys file on the newly created hosting user! - - Your ONLY access to the new (`git`) userid should be by logging onto the - server as root, then running `su - git`. - -3. Now copy the pubkey from your workstation (`~/.ssh/id_rsa.pub`) to the - server as `/tmp/ron.pub`. (Your name is Ron, remember?) - -4. Log on to the server as root. - -5. Switch to the `git` user: - - su - git - -6. Clone the gitolite source code - - git clone git://github.com/sitaramc/gitolite - -7. Install it - - cd $HOME - mkdir -p bin - gitolite/install -to $HOME/bin - -8. Set it up - - cd $HOME - $HOME/bin/gitolite setup -pk /tmp/ron.pub - -9. Now go to your workstation and type in - - git ls-remote git@server:gitolite-admin - - This should return something like - - 9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4 HEAD - 9dd8aab60bac5e54ccf887a87b4f3d35c96b05e4 refs/heads/master - - (do I have to mention that your SHAs will be different?) diff --git a/doc/locking.mkd b/doc/locking.mkd deleted file mode 100644 index 2799003..0000000 --- a/doc/locking.mkd +++ /dev/null @@ -1,160 +0,0 @@ -# locking binary files - -Locking is useful to make sure that binary files (office docs, images, ...) -don't get into a merge state. (If you think it's not a big -deal, you have never manually merged independent changes to an ODT or -something!) - -When git is used in a truly distributed fashion, locking is impossible. -However, in most corporate setups, there is a single central server acting as -the canonical source of truth and collaboration point for all developers. In -this situation it should be possible to at least prevent commits from being -pushed that contains changes to files locked by someone else. - -The two "lock" programs (one a command that a user uses, and one a VREF that -the admin adds to a repo's access rules) together attempt to achieve this. - -Of course, locking by itself is not quite enough. You may still get into -merge situations if you make changes in branches. For best results you should -actually keep all the binary files in their own branch, separate from the ones -containing source code. - ----- - -[[TOC]] - -## problem description - -Our users are alice, bob, and carol. Our repo is foo. It has some "odt" -files in the "doc/" directory. We want to make sure these odt files never get -into a "merge" situation. - -## admin/setup - -First, someone with shell access to the server must add 'lock' to the -"COMMANDS" list in the rc file. - -Next, the gitolite.conf file should have something like this: - - repo foo - <...other rules...> - - VREF/lock = @all - -However, see below for the difference between "RW" and "RW+" from the point of -view of this feature and adjust permissions accordingly. - -## user view - -Here's a summary: - - * Any user with "W" permissions to any branch in the repo can "lock" any - file. Once locked, no other user can push changes to that file, *in any - branch*, until it is unlocked. - * Any user with "+" permissions to any branch in the repo can "break" a lock - held by someone else if needed. - -For best results, everyone on the team should: - - * Switch to the branch containing the binary files when wanting to make a - change. - * Run 'git pull' or eqvt, then lock the binary file(s) before editing them. - * Finish the editing task as quickly as possible, then commit, push, and - unlock the file(s) so others are not needlessly blocked. - * Understand that breaking a lock require additional, (out of band) - communication. It is upto the team's policies what that entails. - -## detailed example - -Alice declares her intent to work on "d1.odt": - - $ git pull - $ ssh git@host lock -l foo doc/d1.odt - -Similarly Bob starts on "d2.odt" - - $ git pull - $ ssh git@host lock -l foo doc/d2.odt - -Carol makes some changes to d2.odt (**without attempting to lock the file or -checking to see if it is already locked**) and pushes: - - $ ooffice doc/d2.odt - $ git add doc/d2.odt - $ git commit -m 'added footnotes to d2 in klingon' - $ git push - <...normal push progress output...> - remote: FATAL: W VREF/lock testing carol DENIED by VREF/lock - remote: 'doc/d2.odt' locked by 'bob' - remote: error: hook declined to update refs/heads/master - To u2:testing - ! [remote rejected] master -> master (hook declined) - error: failed to push some refs to 'carol:foo' - -Carol backs out her changes, but saves them away for a "manual merge" later. - - git reset HEAD^ - git stash save 'klingon changes to d2.odt saved for possible manual merge later' - -Note that this still represents wasted work in some sense, because Carol would -have to somehow re-apply the same changes to the new version of d2.odt after -pulling it down. **This is because she did not lock the file before making -changes on her local repo. Educating users in doing this is important if this -scheme is to help you.** - -She now decides to work on "d1.odt". However, she has learned her lesson and -decides to follow the protocol described above: - - $ git pull - $ ssh git@host lock -l foo doc/d1.odt - FATAL: 'doc/d1.odt' locked by 'alice' since Sun May 27 17:59:59 2012 - -Oh damn; can't work on that either. - -Carol now decides to see what else there may be. Instead of checking each -file to see if she can lock it, she starts with a list of what is already -locked: - - $ ssh git@host lock -ls foo - - # locks held: - - alice doc/d1.odt (Sun May 27 17:59:59 2012) - bob doc/d2.odt (Sun May 27 18:00:06 2012) - - # locks broken: - -Aha, looks like only d1 and d2 are locked. She picks d3.odt to work on. This -time, she starts by locking it: - - $ ssh git@host lock -l foo doc/d3.odt - $ ooffice doc/d3.odt - <...etc...> - -Meanwhile, in a parallel universe where d3.odt doesn't exist, and Alice has -gone on vacation while keeping d1.odt locked, Carol breaks the lock. Carol -can do this because she has RW+ permissions for the repository itself. - -However, protocol in this team requires that she get email approval from the -team lead before doing this and that Alice be in CC in those emails, so she -does that first, and *then* she breaks the lock: - - $ git pull - $ ssh git@host lock --break foo doc/d1.odt - -She then locks d1.odt for herself: - - $ ssh git@host lock -l foo doc/d1.odt - -When Alice comes back, she can tell who broke her lock and when: - - $ ssh git@host lock -ls foo - - # locks held: - - carol doc/d1.odt (Sun May 27 18:17:29 2012) - bob doc/d2.odt (Sun May 27 18:00:06 2012) - - # locks broken: - - carol doc/d1.odt (Sun May 27 18:17:03 2012) (locked by alice at Sun May 27 17:59:59 2012) - diff --git a/doc/master-toc.mkd b/doc/master-toc.mkd deleted file mode 100644 index 77cd40f..0000000 --- a/doc/master-toc.mkd +++ /dev/null @@ -1,170 +0,0 @@ -# gitolite documentation - -## [Introduction][index] - - * (for [older][g2] gitolite (v1 or v2) users) - * [quick links][ql] - * [what][] is gitolite - * [why][] might you need it - * [contact][] info, mailing list, IRC channel - * [license][] info - -## help for [emergencies][] - - * [lost][lost-key] admin key/access - * [bypass][]ing gitolite - * [clean][]ing out a botched install - * [common][ce] errors - * [uncommon][ue] errors - * things that are [not gitolite problems][ngp] - -## [WARNINGS][] - - -## [testing][] gitolite - * [trying][] out gitolite - - -## [quick][qi] install, setup, and clone - - -## [install][] - - * notes and naming conventions - * requirements - * your skills - * server - * client - * getting the software - * the actual install - * upgrading - * packaging gitolite - * [migr][]ating - -## [setup][] - - -## [clone][] - - -## gitolite [admin][]istration - - * ([server-side][server]) settings, hooks, etc. - * ([link][WARNINGS]: important cautions on server side activity) - * changing settings in the [rc][] file - * installing custom [hooks][] - * ([link][existing]: moving existing repos into gitolite) - * ([client-side][adminrepo]) access control via the gitolite-admin repo - * basic [syntax][] of the [conf][] file - * include files - * ([link][sugar]: syntactic sugar) - * [groups][] (of users and repos) - * special: '@all' - * (link: storing user group info in LDAP) - * adding and removing [users][] - * multiple keys per user - * adding and removing [repos][] - * renaming repos - * defining access [rules][] - * what does a rule look like? - * when are the rules checked? - * how are the rules matched? - * summary of [permissions][permsum] - * additional topics - * [rule accumulation][rule-accum] - * applying [deny rules][deny-rules] during the pre-git check - * ([link][refex]: refexes) - * ([link][write-types]: different types of write operations) - * ([link][vref]: virtual refs) - * gitolite [options][] - * "[git config][git-config]" keys and values - * ["wild"][wild] repos (user created repos) - * quick introduction - * (admin) declaring wild repos in the conf file - * (user) [creating][create] a specific repo - * repo patterns - * roles - * adding other roles - * [IMPORTANT WARNING ABOUT THIS FEATURE][rolenamewarn] - * listing wild repos - * deleting wild repos - -## what your [user][]s need to know - - -## [special][] features/setups - - * putting 'repositories' and '.gitolite' [somewhere else][elsewhere] - * [disabling pushes][writable] to take backups - * [personal][pers] branches - * ([link][votes]: voting on commits) - * [delegating][deleg] access control responsibilities - * ([link][NAME]: the NAME VREF) - * the [subconf][] command - * ([link][partial-copy]: faking selective READ control) - * using pubkeys obtained [from elsewhere][keysonly] - * ([link][pushcode]: updating code via the admin repo) - -## interfacing with [external][] tools - - * gitweb - * changing the [UMASK][umask] - * git-daemon - -## [mirroring][] - - -## [rare][]/one-time activities - - * moving [existing][] repos into gitolite - * [moving][] servers - -## [customisation][cust] - - * where do you put custom code? - * types of non-core programs - * [commands][] - * [hooks][] - * syntactic [sugar][] - * ([link][triggers]: triggers) - * ([link][vref]: VREFs) - * ([link][non-core]: non-core programs shipped with gitolite) - * [developer notes][dev-notes] -- writing custom code - * environment variables and other inputs - * APIs - * the shell API - * the perl API - * writing your own... - * hooks - * commands - * trigger programs - * sugar - -## [non-core][] programs shipped with gitolite - - * commands - * syntactic sugar - * triggers - * ([link][vref]: VREFs) - * special cases - * [partial-copy][]: selective read control for branches - -## background info - - * [files and directories][files] involved in install+setup - * [auth][]entication versus authorisation - * interfacing with [other authentication][otherauth] systems - * getting user group info from [LDAP][ldap] - * [ssh][] - * [regular expressions][regex] - -## contributed software, tools, and documentation - - * TBD - -## TBD - - * log file format, LOG_EXTRA - * hub - * mob branches - * password access diff --git a/doc/mirroring.mkd b/doc/mirroring.mkd deleted file mode 100644 index 7b07882..0000000 --- a/doc/mirroring.mkd +++ /dev/null @@ -1,235 +0,0 @@ -# mirroring using gitolite - -**WARNING** existing gitolite mirroring users please note: -**there are [significant changes][g2i-mirroring]** in syntax and usage -compared to g2. If you're not the kind who reads documentation before doing -serious system admin things, well... good luck! - ----- - -[[TOC]] - ----- - -Mirroring is simple: you have one "master" server and one or more "slave" -servers. The slaves get updates only from the master; to the rest of the -world they are at best read-only. - -Gitolite extends this simple notion in the following ways: - - * Different masters and sets of slaves for different repos - - This lets you do things like: - - * Use the server closest to *most* of its developers as the master for - that repo. - * Not mirror a repo at all to some servers. - * Have repos that are purely local to a server (not mirrored at all). - * Negotiate mirroring with servers that are not even under your control. - * Push to a slave on demand or via cron (helps deal with bandwidth or - connectivity constraints). - - * Pushes to a slave can be transparently forwarded to the real master. - - Your developers need not worry about where a repo's master is -- they just - write to their local mirror for *all* repos, even if their local mirror is - only a slave for some. - -## caveats - - * Mirroring will never *create* a repo on a slave; it has to exist and be - prepared to receive updates from the master. - - However, there is limited support for auto-creating wild card repos and - sending 'perms' info across, with the following caveats at present. (Some - of this text won't make sense unless you know what those features are). - - * *WARNING: it does NOT make sense to mirror wild repos in setups where - the authentication data is not the same (i.e., where "alice" on the - master and "alice" on a slave maybe totally different people)*. - - * This has only been minimally tested. For example, complex setups or - asymmetric configs on master and slave, etc. have NOT been tested. - - * Permission changes will only propagate on the next 'git push'. Of - course, if you know the name of the slave server, you can run - - ssh git@host mirror push slave-server-name repo-name - - * Using 'perms' on a slave is allowed but will neither propagate nor - persist. They will be overwritten by whatever perms the master has - (even if it is an empty set) on the next 'git push'. - - * As with lots of extra features in gitolite, smart http support is not - on my radar. Don't ask. - - Please test it out and let me know if something surprising happens. Be - aware that I have been known to claim bugs are features if I don't have - time to fix them immediately :-) - - * Mirroring is only for git repos. Ancillary files like gl-creator and - gl-perms in the repo directory are not mirrored; you must do that - separately. Files in the admin directory (like log files) are also not - mirrored. - - * If you ever do a [bypass push][bypass], mirroring will not work. - Mirroring checks also will not work -- for example, you can push to a - slave, which is not usually a good idea. So don't bypass gitolite if the - repo is mirrored! - -## setting up mirroring - -This is in two parts: the initial setup and the rc file, followed by the conf -file settings and syntax. - -### the initial setup and the rc file - -On **each** server: - - * Install gitolite normally. Make clones of the server's 'gitolite-admin' - repo on your workstation so you can admin them all from one place. - - * Give the server a short, simple, "hostname" and set the HOSTNAME in the - rc file to this name, for example 'mars'. - - * Run ssh-keygen if needed and get an ssh key pair for the server. Copy the - public key to a common area and name it after the host, but with 'server-' - prefixed. For example, the pubkey for server 'mars' must be stored as - 'server-mars.pub'. - - * Copy all keys to all the admin repo clones on your workstation and and add - them as usual. This is an `O(N^2)` operation ;-) - - You may have guessed that the prefix 'server-' is special, and - distinguishes a human user from a mirroring peer. - - * Create "host" aliases to refer to all other machines. See [here][ssh-ha] - for what/how. - - The host alias for a host (in all other machines' `~/.ssh/config` files) - MUST be the same as the `HOSTNAME` in the referred host's - `~/.gitolite.rc`. Gitolite mirroring **requires** this consistency in - naming; things will NOT work otherwise. - - Normally you should be able to build one common file and append it to all - the servers' `~/.ssh/config` files. - - * The following **MUST** work for **each pair** of servers that must talk to - each other: - - # on server mars - ssh phobos info - # the response MUST start with "hello, server-mars..." - - Note the exact syntax used; variations like "ssh git@phobos.example.com - info" are NOT sufficient. That is why you need the ssh host aliases. - - Check this command from *everywhere to everywhere else*, and make sure you - get expected results. **Do NOT proceed otherwise.** - - * Setup the gitolite.conf file on all the servers. If the slaves are to be - exact copies of the master, you need to do the complete configuration only - on the master; the slaves can have just this: - - repo gitolite-admin - RW+ = - - option mirror.master = mars - option mirror.slaves = phobos - - because on the first push to the master it will update all the slaves - anyway. - - * When that is all done and tested, **enable mirroring** by going through - the rc file and uncommenting all the lines mentioning `Mirroring`. - -### conf file settings and syntax - -Mirroring is defined by the following [options][]. You can have different -settings for different repos, and of course some repos may not have any mirror -options at all -- they are then purely local. - - repo foo - ...access rules... - - option mirror.master = mars - option mirror.slaves = phobos deimos - option mirror.redirectOK = all - -The first line is easy, since a repo can have only one master. - -The second is a space separated list of hosts that are all slaves. You can -have several slave lists, as long as the config key starts with -'mirror.slaves' and is unique. For example. - - option mirror.slaves-1 = phobos deimos - option mirror.slaves-2 = io europa - option mirror.slaves-3 = ganymede callisto - -Do not repeat a key; then only the last line for that key will be effective. - -## redirected pushes - -**Please read carefully; there are security implications if you enable this -for mirrors NOT under your control**. - -Normally, a master, (and *only* a master), pushes to a slave, and the slaves -are "read-only" to the users. Gitolite allows a *slave* to receive pushes -from a user and transparently redirect them to the *master*. - -This simplifies things for users in complex setups, letting them use their -local mirror for both fetch and push access to all repos. - -Just remember that if you do this, **authentication** happens on the slave, -but **authorisation** is on the master. The master is trusting the slave to -authenticate the user correctly, *and* use the same authentication data (i.e., -user alice on the slave should be guaranteed to be the same as user alice on -the master). - -The syntax for enabling this is one of these: - - option mirror.redirectOK = all - option mirror.redirectOK = phobos deimos - -The first syntax trusts all valid slaves to redirect user pushes, while the -second one trusts only some slaves. - -Note that you cannot redirect gitolite commands (like perms, etc). - -## #sync manually synchronising a slave repo - -You can use the `gitolite mirror push` command on a master to manually -synchronise any of its slaves. Try it with `-h` to get usage info. - -Tip: if you want to do this to all the slaves, try this: - - for s in `gitolite git-config -r reponame mirror.slave | cut -f3` - do - gitolite mirror push $s reponame - done - -This command can also be run remotely; run `ssh git@host mirror -h` for -details. - -## #HOSTNAME appendix A: HOSTNAME substitution - -Wherever gitolite sees the word `%HOSTNAME`, it will replace it with the -HOSTNAME supplied in the rc file, if one was supplied. This lets you maintain -configurations for all servers in one repo, yet havethem act differently on -different servers, by saying something like: - - subconf "%HOSTNAME/*.conf" - -You can use it in other places also, for example: - - RW+ VREF/NAME/subs/%HOSTNAME/ = @%HOSTNAME-admins - -(you still have to define @mars-admins, @phobos-admins, etc., but the actual -VREF is now one line instead of one for each server!) - -## appendix B: efficiency versus paranoia - -If you're paranoid enough to use mirrors, you should be paranoid enough to -set this on each server, despite the possible CPU overhead: - - git config --global receive.fsckObjects true diff --git a/doc/mkdoc b/doc/mkdoc deleted file mode 100755 index 72470d3..0000000 --- a/doc/mkdoc +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/perl - -# cd /doc; ./mkdoc # --> creates ../html/*.html - -my $MKD = "./Markdown.pl"; - -use 5.10.0; -use strict; -use warnings; -use lib '../src/lib/Gitolite/Test'; -use Tsh; - -$ENV{TSH_ERREXIT} = 1; - -try " - mkdir ../html; ok - git status -s -uno; !/./ - git log --oneline -1 -" or die 1; - -my $head = (lines())[0]; - -main(); - -try " - git checkout gh-pages; ok - git reset --hard github/gh-pages; ok - cd ..; ok - git rm *.html; ok - mv html/*.html .; ok - git add *.html; ok - git commit -m '$head'; ok - git checkout master; ok - rmdir html; ok -" or die 2; - -sub main { - chomp(@ARGV = `find . -name "*.mkd" | cut -c3-`) if not @ARGV; - @ARGV = grep { /./ } @ARGV; - my @save = @ARGV; - my $css_block = join("", ); - - my %ct; # chapter tocs - my %title; - my $mf = ''; - my $fh; - - while (<>) { - $ARGV =~ /^(?:.*\/)?([^\/]+)\.mkd$/; - my $b = $1; - - if (/^(#+) (?:#(\S+) )?(.*)/) { - $title{$b} ||= $3; - if ( length($1) == 1 ) { - $ct{$b} .= "\n"; - $ct{$b} .= " * [$3][$b]\n"; - $mf .= "[$b]: $b.html\n"; - } else { - $ct{$b} .= " " x ( 4 * ( length($1) - 1 ) ); - $ct{$b} .= " * "; - $ct{$b} .= ( - $2 - ? "[$3][$2]" - : "$3" - ); - $ct{$b} .= "\n"; - $mf .= "[$2]: $b.html" . ($2 ne $b ? "#$2" : "") . "\n" if $2; - } - } - } - - # open($fh, ">", "master-toc.mk2") - # and print $fh $mt - # and close $fh; - - # after this, do this for every mkd (including the master-toc.mkd) - - # cat $css_block > $base.html - # cat $base.mkd $mf | $MKD >> $base.html - - for my $mkd (@save) { - $mkd =~ /^(?:.*\/)?([^\/]+)\.mkd$/; - my $b = $1; - - my $css = $css_block; - $css =~ s/%TITLE/$title{$b} || $b/e; - - open($fh, ">", "../html/$b.html") - and print $fh $css - and close $fh; - - my $mkt = `cat $mkd`; - $mkt =~ s/^(#+) #(\S+) /$1 <\/a> /mg; - $mkt =~ s/^\[\[TOC\]\]/$ct{$b}/mg; - open($fh, "|-", "$MKD >> ../html/$b.html") - and print $fh $mkt, "\n\n", $mf - and close $fh; - } -} - -__DATA__ - - - %TITLE - - - -

    - master TOC -| - main page -| - license -

    -

    -This is for gitolite "g3"; for older (v2.x) documentation click here -

    diff --git a/doc/non-core.mkd b/doc/non-core.mkd deleted file mode 100644 index dc0e188..0000000 --- a/doc/non-core.mkd +++ /dev/null @@ -1,131 +0,0 @@ -# non-core programs shipped with gitolite - ----- - -[[TOC]] - ----- - -## commands - -A list of these commands can be obtained by running `gitolite help` on the -server. A different (and probably much smaller) list can be obtained by a -remote user running `ssh git@host help`. - -All the commands that ship with gitolite will respond to `-h`; please report a -bug to me if they don't. - -A particularly interesting command is the 'sudo' command, which allows an -admin to run any remote command as some other user (though not the other way -round!) - -Here's a list of some commands where additional information is available -elsewhere: - - * 'info' -- documented [here][info] - * 'mirror' -- documented [here][sync] - * 'perms' -- get/set the gl-perms file; see [perms][] for more - * 'sskm' -- self-service key management, see [sskm][] for more - -## syntactic sugar - -The following "sugar" programs are available: - - * Continuation-lines -- allow the use of C-style backslash escaped - continuation lines in the conf file. I don't like it but some people do, - and now I can support them without bulking up the "core" conf parser! - - * Keysubdirs-as-groups -- someone wanted the sub-directory name (of - "keydir/") in which the pubkey was placed to be a group to which the user - automatically belonged. A very unusual requirement, and one which would - *never* have seen the light of day in g2, but in g3 it's easy, and doesn't - affect anyone else! - - (Note: the last component of the directory path is used if there are more - than one level between "keydir/" and the actual file). - -## triggers - -Most triggers need to be enabled by adding or uncommenting an appropriate line -in the [rc][] file. There are enough examples in there for the syntax to not -need explanation. - -Some features need to be enabled in more than one trigger. Mirroring is -probably the best example -- it needs to hook into the `INPUT`, `PRE_GIT`, and -the `POST_GIT` triggers to work. - -In general, the source code for each trigger will tell you what it is doing -and which trigger list you should add it to. Please note that there are two -types of [triggers][]; the perl triggers usually have subroutine names that -reflect what trigger sections they should go into. (Using mirroring as an -example again, the Mirroring.pm perl module has sub's named 'input', -'pre\_git', and 'post\_git'). - -Please report a bug to me if you could not find the information you wanted on -any specific trigger. - -Here's a list of some triggers where additional information is available -elsewhere: - - * Shell -- see "giving shell access to gitolite users" in [this][sts] page. - * Mirroring -- see [doc/mirroring.mkd][mirroring] - * partial-copy -- this has its own section later in this page. - -## VREFs - -VREFs have their [own page][vref]. - -## special cases - -### #partial-copy partial-copy: selective read control for branches - -Git (and therefore gitolite) cannot do selective read control -- allowing -someone to read branch A but not branch B. It's the entire repo or nothing. - - [Side note: Gerrit Code Review can do that, but that is -because they have their own git stack (and their own sshd, and so on) all in -one big Java program. Gerrit is *really* useful if you want code review to be -part of the access control decision] - -Gitolite can now help you do this. Note that this is only for branches; you -can't do this for files and directories. - -Here's how: - -1. enable 'partial-copy' in the `PRE_GIT` section in the rc file. - -2. for each repo "foo" which has secret branches that a certain set of - developers (we'll use a group called `@temp-emp` as an example) are not - supposed to see, do this: - - repo foo - # rules should allow @temp-emp NO ACCESS - - repo foo-partialcopy-1 - - secret-branch = @temp-emp - - # other rules; see notes below - - - VREF/partial-copy = @all - config gitolite.partialCopyOf = foo - - **IMPORTANT NOTES**: - - * if you're using other VREFs, **make sure** this one is placed at the - end, after all the others. - - * remember that any change allowed to be made to the partial-copy repo - will propagate to the main repo so make sure you use other rules to - restrict pushes to other branches and tags as needed. - -And that should be it. **Please test it and let me know if it doesn't work!** - -WARNINGS: - - * If you change the config to disallow something that used to be allowed, - you should delete the partial repo on the server and then run `gitolite - compile; gitolite trigger POST_COMPILE` to let it build again. - - * Not tested with smart http; probably won't work. - - * Also not tested with mirroring, or with wild card repos. diff --git a/doc/options.mkd b/doc/options.mkd deleted file mode 100644 index 22d12af..0000000 --- a/doc/options.mkd +++ /dev/null @@ -1,20 +0,0 @@ -# gitolite options - -Some gitolite features are enabled, or gitolite's behaviour changed, by -setting "options". - -Options are set by repo. The syntax is very simple: - - option foo.bar = baz - -Of course this is useless if some other part of gitolite, or some external -command, is not querying for the option key 'foo.bar'! - -Options are therefore documented in the section/page they belong in, not here. -Here are the currently recognised options: - - * [deny-rules][] -- ask gitolite to honor deny rules during the pre-git - check also. - - * [mirroring][] related options -- tell gitolite who is the master server, - and who are the slaves, for each repo. diff --git a/doc/progit.mkd b/doc/progit.mkd deleted file mode 100644 index 5e293c1..0000000 --- a/doc/progit.mkd +++ /dev/null @@ -1,163 +0,0 @@ -# (expanded version of the gitolite chapter in the progit book) - -## Gitolite ## - -[Update 2012-04-10]: This page has been completely rewritten for gitolite version 3, informally called "g3". G3 is a *total* rewrite of gitolite to push a lot more features away from "core", give the core a bunch of extension mechanisms, and finally have much better shell and perl APIs to bring all this together. - -Git has become very popular in corporate environments, which tend to have some additional requirements in terms of access control. Gitolite was originally created to help with those requirements, but it turns out that it's equally useful in the open source world: the Fedora Project controls access to their package management repositories (over 10,000 of them!) using gitolite, and this is probably the largest gitolite installation anywhere too. KDE, and kernel.org, are other very high-profile users of gitolite. - -Gitolite allows you to specify permissions not just by repository, but also by branch or tag names within each repository. That is, you can specify that certain people (or groups of people) can only push certain "refs" (branches or tags) but not others. - -### Installing ### - -Installing Gitolite is very easy, even if you don't read the extensive documentation that comes with it. You need an account on a Unix server of some kind. You do not need root access, assuming git, perl, and an openssh compatible ssh server are already installed. In the examples below, we will use the `git` account on a host called `gitserver`. - -Gitolite is somewhat unusual as far as "server" software goes -- access is via ssh, and so every userid on the server is a potential "gitolite host". Gitolite is at present best installed manually, as the "g3" version does not yet have RPM/DEB support from distros. We will describe the simplest install method in this article; for the other methods please see the documentation. - -To begin, create a user called `git` on your server and login to this user. Copy your ssh pubkey (a file called `~/.ssh/id_rsa.pub` if you did a plain `ssh-keygen` with all the defaults) from your workstation, renaming it to `YourName.pub`. Then run these commands: - - git clone git://github.com/sitaramc/gitolite - gitolite/install -ln - # assumes $HOME/bin exists and is in your $PATH - gitolite setup -pk $HOME/YourName.pub - # for example, I would run 'gitolite setup -pk $HOME/sitaram.pub' - -Finally, back on your workstation, run `git clone git@server:gitolite-admin`. - -And you're done! Gitolite has now been installed on the server, and you now have a brand new repository called `gitolite-admin` in your workstation. You administer your gitolite setup by making changes to this repository and pushing. See adding [users][] and [repos][] to start with. - -### Customising the Install ### - -While the default, quick, install works for most people, there are some ways to customise the install if you need to. Some changes can be made simply by editing the [rc file][rc], but if that is not sufficient, there's documentation on [customising gitolite][cust] by using non-core programs. - -### Config File and Access Control Rules ### - -Once the install is done, you switch to the `gitolite-admin` repository (placed in your HOME directory) and poke around to see what you got: - - $ cd ~/gitolite-admin/ - $ ls - conf/ keydir/ - $ find conf keydir -type f - conf/gitolite.conf - keydir/sitaram.pub - $ cat conf/gitolite.conf - - repo gitolite-admin - RW+ = sitaram - - repo testing - RW+ = @all - -Notice that "sitaram" (the name of the pubkey in the gl-setup command you used earlier) has read-write permissions on the `gitolite-admin` repository as well as a public key file of the same name. - -The config file syntax for gitolite is [well documented][conf], so we'll only mention some highlights here. - -You can group users or repos for convenience. The group names are just like macros; when defining them, it doesn't even matter whether they are projects or users; that distinction is only made when you *use* the "macro". - - @oss_repos = linux perl rakudo git gitolite - @secret_repos = fenestra pear - - @admins = scott # Adams, not Chacon, sorry :) - @interns = ashok # get the spelling right, Scott! - @engineers = sitaram dilbert wally alice - @staff = @admins @engineers @interns - -You can control permissions at the "ref" level. In the following example, interns can only push the "int" branch. Engineers can push any branch whose name starts with "eng-", and tags that start with "rc" followed by a digit. And the admins can do anything (including rewind) to any ref. - - repo @oss_repos - RW int$ = @interns - RW eng- = @engineers - RW refs/tags/rc[0-9] = @engineers - RW+ = @admins - -The expression after the `RW` or `RW+` is a regular expression (regex) that the refname (ref) being pushed is matched against. So we call it a "refex"! Of course, a refex can be far more powerful than shown here, so don't overdo it if you're not comfortable with perl regexes. - -Also, as you probably guessed, Gitolite prefixes `refs/heads/` as a syntactic convenience if the refex does not begin with `refs/`. - -An important feature of the config file's syntax is that all the rules for a repository need not be in one place. You can keep all the common stuff together, like the rules for all `oss_repos` shown above, then add specific rules for specific cases later on, like so: - - repo gitolite - RW+ = sitaram - -That rule will just get added to the ruleset for the `gitolite` repository. - -At this point you might be wondering how the access control rules are actually applied, so let's go over that briefly. - -There are two levels of access control in gitolite. The first is at the repository level; if you have read (or write) access to *any* ref in the repository, then you have read (or write) access to the repository. - -The second level, applicable only to "write" access, is by branch or tag within a repository. The username, the access being attempted (`W` or `+`), and the refname being updated are known. The access rules are checked in order of appearance in the config file, looking for a match for this combination (but remember that the refname is regex-matched, not merely string-matched). If a match is found, the push succeeds. A fallthrough results in access being denied. - -### Advanced Access Control with "deny" rules ### - -So far, we've only seen permissions to be one or `R`, `RW`, or `RW+`. However, gitolite allows another permission: `-`, standing for "deny". This gives you a lot more power, at the expense of some complexity, because now fallthrough is not the *only* way for access to be denied, so the *order of the rules now matters*! - -Let us say, in the situation above, we want engineers to be able to rewind any branch *except* master and integ. Here's how to do that: - - RW master integ = @engineers - - master integ = @engineers - RW+ = @engineers - -Again, you simply follow the rules top down until you hit a match for your access mode, or a deny. Non-rewind push to master or integ is allowed by the first rule. A rewind push to those refs does not match the first rule, drops down to the second, and is therefore denied. Any push (rewind or non-rewind) to refs other than master or integ won't match the first two rules anyway, and the third rule allows it. - -You can also use deny rules to hide specific repos from people (or gitweb, or git-daemon, etc.), when you have otherwise allowed them access to *all* repos. For example, a server containing open source repos may nevertheless wish to hide the special 'gitolite-admin' repo from gitweb, even though all the other repos can be made visible: - - repo gitolite-admin - - = gitweb daemon - [... other access rules ...] - option deny-rules = 1 - # remember this is for gitolite "g3"; the older gitolite had a - # different syntax - - repo @all - R = gitweb daemon - -[This][deny-rules] page has more details. - -### Restricting pushes by files changed ### - -In addition to restricting what branches a user can push changes to, you can also restrict what files they are allowed to touch. For example, perhaps the Makefile (or some other program) is really not supposed to be changed by just anyone, because a lot of things depend on it or would break if the changes are not done *just right*. You can tell gitolite: - - repo foo - RW = @junior_devs @senior_devs - - - VREF/NAME/Makefile = @junior_devs - -User who are migrating from the older gitolite should note that there is a significant change in behaviour with regard to this feature; please see the [migration guide][migr] for details. - -### Personal Branches ### - -Gitolite also has a feature called "personal branches" (or rather, "personal branch namespace") that can be very useful in a corporate environment. - -A lot of code exchange in the git world happens by "please pull" requests. In a corporate environment, however, unauthenticated access is a no-no, and a developer workstation cannot do authentication, so you have to push to the central server and ask someone to pull from there. - -This would normally cause the same branch name clutter as in a centralised VCS, plus setting up permissions for this becomes a chore for the admin. - -Gitolite lets you define a "personal" or "scratch" namespace prefix for each developer (for example, `refs/personal//*`); the details are [here][pers]. - -### "Wildcard" repositories ### - -Gitolite allows you to specify repositories with wildcards (actually perl regexes), like, for example `assignments/s[0-9][0-9]/a[0-9][0-9]`, to pick a random example. It allows you to assign a new permission mode ("C") which allows users to create repositories based on such wild cards, automatically assigns ownership to the specific user who created it, allows him/her to hand out R and RW permissions to other users to collaborate, etc. This feature is documented [here][wild]. - -### Other Features ### - -We'll round off this discussion with a sampling of other features, all of which, and many more, are described in great detail in the documentation. - -**Logging**: Gitolite logs all successful accesses. If you were somewhat relaxed about giving people rewind permissions (`RW+`) and some kid blew away "master", the log file is a life saver, in terms of easily and quickly finding the SHA that got hosed. - -**Access rights reporting**: Another convenient feature is what happens when you try and just ssh to the server. Gitolite shows you what repos you have access to, and what that access may be. Here's an example: - - hello sitaram, this is git@git running gitolite3 v0.02-15-g1db50f4 on git 1.7.4.4 - - R anu-wsd - R entrans - R W git-notes - R W gitolite - R W gitolite-admin - R indic_web_input - R shreelipi_converter - -**Delegation**: For really large installations, you can delegate responsibility for groups of repositories to various people and have them manage those pieces independently. This reduces the load on the main admin, and makes him less of a bottleneck. See [here][deleg] for more on this. - -**Mirroring**: Gitolite can help you maintain multiple [mirrors][mirroring], and switch between them easily if the primary server goes down. - -[progit]: http://sitaramc.github.com/gitolite/progit.html diff --git a/doc/qi.mkd b/doc/qi.mkd deleted file mode 100644 index 90a83c2..0000000 --- a/doc/qi.mkd +++ /dev/null @@ -1,48 +0,0 @@ -# quick install, setup, and clone - -## ASSUMPTIONS - - * This is an ssh-based setup. For smart http setup click [here][http]. - - * This is a fresh install, not a migration from the old gitolite (v1.x, - v2.x). - - * On the server, `$HOME/bin` exists and is in your `$PATH`. If you don't - like that, there are [other install methods][install]. - - * "your-name.pub" is your public key from your workstation. - * Also, this key does not already have shell access to this gitolite - hosting user. - - * The setup command does not generate any warnings. - * If it does, please see [common errors][ce] and fix things before - continuing, or read the more complete [setup][] page. - -## instructions - -On the server, as the hosting user (e.g., 'git'): - - # get the software - git clone git://github.com/sitaramc/gitolite - - # install it - gitolite/install -ln - - # setup the initial repos with your key - gitolite setup -pk your-name.pub - -On your workstation: - - # clone the admin repo so you can start adding stuff - git clone git@host:gitolite-admin.git - # Note 1: clone path must not include "repositories/" - # Note 2: it may include the ".git" at the end but it is optional - -## next steps - -If this step succeeds, you can add [users][], [repos][], or anything else -described [here][adminrepo]. - -If this step fails, be sure to look at the [ssh][] documentation before asking -for help. (A very basic first step is to run `ssh git@host info`; -[this][info] page tells you what to expect). diff --git a/doc/rare.mkd b/doc/rare.mkd deleted file mode 100644 index bcb1c6a..0000000 --- a/doc/rare.mkd +++ /dev/null @@ -1,52 +0,0 @@ -# rare or one-time activities - -## #existing moving existing repos into gitolite - -On the server: - - * Move the repos to `$HOME/repositories`. - - * Make sure that: - - * They are all *bare* repos. - * All the repo names end in ".git". - * All the files and directories are owned and writable by the gitolite - hosting user (especially true if you copied them as root). - - * Run `gitolite setup`. **If you forget this step, you can also forget - about write access control!** - -Back on your workstation: - - * [Add them][repos] to conf/gitolite.conf in your clone of the admin repo, - then commit and push the change. - - If the repos are already covered by some [wild][] pattern, this is - optional. - -## #moving moving servers - -This is adapted from the "migrating" section of the [install][] page; if -you're actually *migrating* from g2 please go there! - -Nothing in any of the gitolite install/setup/etc will ever touch the *data* in -any repository except the gitolite-admin repo. The only thing it will -normally touch is the `update` hook. So one fool-proof way of "moving" -servers is this (untested but should work; feedback appreciated): - -1. Install gitolite on the new server, using the same key for the admin as - for the old server. - -2. Copy the [rc][] file from the old server, overwriting this one. - -3. [Disable][writable] the old server so people won't push to it. - -4. Copy all the repos over from the old server, including gitolite-admin. - Make sure the files end up with the right ownership and permissions; if - not, chown/chmod them. - -5. Run `gitolite setup`. - -6. On a clone of the old gitolite-admin, add a new remote (or change an - existing one) to point to the new server. Then `git push -f` to this - remote. diff --git a/doc/rc.mkd b/doc/rc.mkd deleted file mode 100644 index 98ad1d7..0000000 --- a/doc/rc.mkd +++ /dev/null @@ -1,104 +0,0 @@ -# the "rc" file (`$HOME/.gitolite.rc`) - -**NOTE**: if you're migrating from g2, there are some settings that MUST be -dealt with **before** running `gitolite setup`; please read the [g2 -migration][g2migr] page and linked pages, and especially the one on -[presetting the rc file][rc-preset]. - ----- - -The rc file for g3 is *quite* different from that of g2. - -As before, it is designed to be the only thing unique to your site for most -setups. What is new is that it is easy to extend it when new needs come up, -without having to touch core gitolite. - -The rc file is perl code, 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! - -Please look at the `~/.gitolite.rc` file that gets installed when you setup -gitolite. As you can see there are 3 types of variables in it: - - * simple variables (like `UMASK`) - * lists (like `POST_COMPILE`, `POST_CREATE`) - * hashes (like `ROLES`, `COMMANDS`) - -While some of the variables are documented in this file, many of them are not. -Their purposes are to be found in each of their individual documentation files -around; start with [customising gitolite][cust]. If a setting is used by an -external command then running that command with '-h' may give you additional -information. - -## specific variables - - * `$UMASK`, octal, default `0077` - - The default UMASK that gitolite uses makes all the repos and their - contents have `rwx------` permissions. People who want to run gitweb - realise that this will not do. - - The correct way to deal with this is to give this variable a value like - `0027` (note the syntax: the leading 0 is required), and then make the - user running the webserver (apache, www-data, whatever) a member of the - 'git' group. - - If you've already installed gitolite then existing files will have to be - fixed up manually (for a umask or 0027, that would be `chmod -R g+rX`). - This is because umask only affects permissions on newly created files, not - existing ones. - - * `$GIT_CONFIG_KEYS`, string, default empty - - This setting allows the repo admin to define acceptable gitconfig keys. - - Gitolite allows you to set git config values using the "config" keyword; - see [here][git-config] for details and syntax. - - However, if you are in an installation where the repo admin does not (and - should not) have shell access to the server, then allowing him to set - arbitrary repo config options *may* be a security risk -- some config - settings allow executing arbitrary commands! - - You have 3 choices. By default `$GIT_CONFIG_KEYS` is left empty, which - completely disables this feature (meaning you cannot set git configs via - the repo config). - - The second choice is to give it a space separated list of settings you - consider safe. (These are actually treated as a set of [regular - expression][regex] patterns, and any one of them must match). - - For example: - - $GIT_CONFIG_KEYS = 'core\.logAllRefUpdates core\..*compression'; - - Each pattern should match the *whole* key (in other words, there - is an implicit `^` at the start of each pattern, and a `$` at the - end). - - The third choice (which you may have guessed already if you're familiar - with regular expressions) is to allow anything and everything: - `$GIT_CONFIG_KEYS = '.*';` - - * `DEFAULT_ROLE_PERMS`, string, default undef - - This sets default wildcard permissions for newly created wildcard repos. - - If set, this value will be used as the default role permissions for new - wildcard repositories. The user can change this value with the perms - command as desired after repository creation; it is only a default. - - Please be aware this is potentially a multi-line variable. In most - setups, it will be left undefined. Some installations may benefit from - setting it to `READERS @all`. - - If you want multiple roles to be assigned by default, here is how. Note - double quotes this time, due to the embedded newline, which in turn - require the '@' to be escaped: - - DEFAULT_ROLE_PERMS => "READERS \@all\nWRITERS \@senior_devs", - - * `LOCAL_CODE`, string - - This is described in more detail [here][localcode]. Please be aware - **this must be a FULL path**, not a relative path. diff --git a/doc/refex.mkd b/doc/refex.mkd deleted file mode 100644 index c5359c2..0000000 --- a/doc/refex.mkd +++ /dev/null @@ -1,34 +0,0 @@ -## #refex matching a ref and a refex - -A refex is a word I made up to mean "a regex that matches a ref". If you know -[regular expressions][regex] you're halfway there. - -In addition: - - * If no refex is supplied, it defaults to `refs/.*`, for example in a rule - like this: - - RW = alice - - * A refex not starting with `refs/` is assumed to start with `refs/heads/`. - This means normal branches can be conveniently written like this: - - RW master = alice - # becomes 'refs/heads/master' internally - - while tags will need to be fully qualified - - RW refs/tags/v[0-9] = bob - - * A refex is implicitly anchored at the start, but not at the end. In - regular expression lingo, a `^` is assumed at the start (but no `$` at the - end is assumed). So a refex of `master` will match all these: - - refs/heads/master - refs/heads/master1 - refs/heads/master2 - refs/heads/master/full - - If you want to restrict the match to just the one specific ref, use - - RW master$ = alice diff --git a/doc/repos.mkd b/doc/repos.mkd deleted file mode 100644 index fc73d36..0000000 --- a/doc/repos.mkd +++ /dev/null @@ -1,56 +0,0 @@ -# adding and removing repos - -**NOTE**: this page describes how to add new repos. To bring already existing -repos into gitolite control, click [here][existing]. - -> ---- - -> *WARNING: Do NOT add new repos or users manually on the server. Gitolite -> users, repos, and access rules are maintained by making changes to a -> special repo called 'gitolite-admin' and pushing those changes to the -> server.* - -> ---- - -Just as for [users][], all operations are in a clone of the gitolite-admin -repo. - -To **add** a new repo, edit `conf/gitolite.conf` and add it, along with at -least one user with some permissions. Or add it to an existing repo line: - - repo gitolite tsh gitpod - RW+ = sitaram - RW dev = alice bob - R = @all - -The "repo" line can have any number of repo names or repo group names in it. -However, it can only be one line; this will not work - - repo foo - repo bar # WRONG; 'foo' is now forgotten - RW = alice - -If you have too many, use a group name: - - @myrepos = foo - @myrepos = bar - - repo @myrepos - RW = alice - -Finally, you add, commit, and push this change. Gitolite will create a bare, -empty, repo on the server that is ready to be cloned. - -**Removing** a repo is not so straightforward. You certainly must remove the -appropriate lines from the `conf/gitolite.conf` file, but gitolite will not -automatically delete the repo from the server. You have to log on to the -server and do the dirty deed yourself :-) - -It is best to make the change in the conf file, push it, and *then* go to the -server and do what you need to. - -**Renaming** a repo is also not automatic. Here's what you do (and the order -is important): - - * Go to the server and rename the repo at the Unix command line. - * Change the name in the conf/gitolite.conf file and add/commit/push. diff --git a/doc/rules.mkd b/doc/rules.mkd deleted file mode 100644 index 39cabe9..0000000 --- a/doc/rules.mkd +++ /dev/null @@ -1,151 +0,0 @@ -## #rules access rules - -This is arguably the most complex part of day-to-day gitolite. There are -several interconnected ideas that make this hard to lay out easily if you're -totally new to this, so read carefully. - -We will use this as a running example: - - @staff = dilbert alice wally bob - - repo foo - RW+ = dilbert # line 1 - RW+ dev = alice # line 2 - - = wally # line 3 - RW temp/ = @staff # line 4 - R = ashok # line 5 - -### what does a rule look like? - -A rule line has the structure - - = - -The most common permissions used are: - - * R, for read only - * RW, for push existing ref or create new ref - * RW+, for "push -f" or ref deletion allowed (i.e., destroy - information) - * `-` (the minus sign), to **deny** access. - -There are also other, less commonly used, [types of permissions][write-types]. - -A refex is an expression that matches the ref (i.e., branch or tag) being -pushed. See [this][refex] for more info. - -### when are the rules checked? - -There are 2 places where access rules are checked. - -The "pre-git" check is before git is invoked. Gitolite knows the repo name, -user name, and attempted access (R or W), but no ref name. - -The "update" check is only for write operations, and it is just before git -updates a ref. This time gitolite knows the refname also. - -### how are the rules matched? - -For the **pre-git check**, any permission that contains "R" matches a read -operation, and any permission that contains "W" matches a write operation. -This is because we simply don't know enough to make finer distinctions at this -point. - -In addition, *gitolite ignores deny rules during the pre-git check*. (You can [change this][deny-rules] if you wish, though it's -rarely needed). This means line 3 is ignored, and so Wally in our -example will pass the pre-git check. - -For the **update check**, git gives us all the information we need. Then: - - * All the rules for a repo are [accumulated][rule-accum]. - - * The rules pertaining to this repo *and* this user (or to a group to which - they belong, respectively) are kept; the rest are ignored. - - * These rules are examined *in the sequence they appeared in the conf file*. - For each rule: - - * If the ref does not match the [refex][], the rule is skipped. - * If it's a deny rule (the permissions field is a `-`), access is - **rejected** and the matching stops. - * If the permission field matches the specific [type of - write][write-types] operation, access is **allowed** and the matching - stops. - - * If no rule ends with a decision, ("fallthru"), access is **rejected**. - -Now you need to understand how [refex][] matching happens and how the -permissions match the various [types of write operations][write-types]. - -Using these, you can see, in our example, that: - - * Everyone, even wally, can read the repo. - * Dilbert can push, rewind, or delete any ref. - * Alice can push, rewind, or delete any ref whose name starts with 'dev'; - see [refex][] for details. - * Alice can also push (but not rewind or delete) any ref whose name starts - with 'temp/'. This applies to bob also. - * If it weren't for line 3, the previous statement would apply to wally - also. - -Interestingly, wally can get past the pre-git check because gitolite ignores -deny rules for pre-git, but having got past it, he can't actually do anything. -That's by design, and as I said if you don't like it you can ask gitolite to -[deny at pre-git][deny-rules]. - -### #permsum summary of permissions - -The full set of permissions, in regex syntax: `-|R|RW+?C?D?M?`. This expands -to one of `-`, `R`, `RW`, `RW+`, `RWC`, `RW+C`, `RWD`, `RW+D`, `RWCD`, or -`RW+CD`, all but the first two optionally followed by an `M`. And by now you -know what they all mean. - -## additional topics - -### #rule-accum rule accumulation - -Gitolite was meant to collect rules from multiple places and apply them all. -For example, this: - - repo foo - RW = u1 - - @gr1 = foo bar - - repo @gr1 - RW = u2 - R = u3 - - repo @all - R = gitweb - -is effectively the same as this, for repo foo: - - repo foo - RW = u1 - RW = u2 - R = u3 - R = gitweb - -This extends to patterns also, but I'll leave an example for later. - -### #deny-rules applying deny rules during the pre-git check - -The access rules section above describes the problem in one scenario. Here's -another. Let's say you have this at the end of your gitolite.conf file: - - repo @all - R = gitweb daemon - -but you don't want the gitolite-admin repo showing up on gitweb. How do you -do that? Here's how: - - repo gitolite-admin - - = gitweb daemon - option deny-rules = 1 - - repo @all - R = gitweb daemon - -Note that the order matters; the `-` rule must come *before* the `R` rule. diff --git a/doc/setup.mkd b/doc/setup.mkd deleted file mode 100644 index ef866c2..0000000 --- a/doc/setup.mkd +++ /dev/null @@ -1,48 +0,0 @@ -# setting up gitolite - -This is the second step in using gitolite, after [install][]. This also -happens on the server, (The next step is [clone][]). - ----- - -Installing the software gets you ready to use it, but the first "use" of it is -always the "setup" command. - -The first time you run it, you need to have a public key file (usually from -the admin's workstation) ready. If the main gitolite admin's username is -"alice", this file should be named "alice.pub". Then run - - gitolite setup -pk alice.pub - -If that command completes without any warnings, you should be done. If it had -a warning, you probably supplied a key which already has shell access to the -server. That won't work. - -> ---- - -> Normally, gitolite is hosted on a user that no one accesses directly -- -> you log on to the server using some other userid, and then `su - git`. In -> this scenario, there *is* no key being used for shell access, so there is -> no conflict. - -> An alternative method is to use two different keys, and a [host -> alias][ssh-ha] to distinguish the two. - -> [common errors][ce] has some links to background information on this -> issue. - -> ---- - -The 'setup' command has other uses, so you will be running it at other times -after the install as well: - - * To setup the update hook when you move [existing][] repos to gitolite. - This also applies if someone has been fiddling with the hooks on some - repos and you want to put them all right quickly. - - * To replace a [lost admin key][lost-key]. - - * To setup gitolite for http mode (run 'gitolite setup -h' for more info). - -When in doubt, run 'gitolite setup' anyway; it doesn't do any harm, though it -may take a minute or so if you have more than a few thousand repos! diff --git a/doc/special.mkd b/doc/special.mkd deleted file mode 100644 index 4ff6d75..0000000 --- a/doc/special.mkd +++ /dev/null @@ -1,102 +0,0 @@ -# special features and setups - ----- - -[[TOC]] - ----- - -## #elsewhere putting 'repositories' and '.gitolite' somewhere else - -Gitolite insists that the "repositories" and ".gitolite" directories be in -`$HOME`. If you want them somewhere else: - - * do the install as normal, - * *then* move those directories to wherever you want and replace them with - symlinks pointing to the new location. - -## #writable disabling pushes to take backups - -The `writable` command allows you to disable pushes to all repos or just the -named repo, in order to do file-system level things to the repo directory that -require it not to change, like using normal backup software. - -Run `gitolite writable -h` for more info. - -## #pers "personal" branches - -"personal" branches are great for environments where developers need to share -work but can't directly pull from each other (usually due to either a -networking or authentication related reason, both common in corporate setups). - -Personal branches exist **in a namespace** of their own. The syntax is - - RW+ personal/USER/ = @userlist - -where the "personal" can be anything you like (but cannot be empty), and the -"/USER/" part is **necessary (including both slashes)**. - -A user "alice" (if she's in the userlist) can then push any branches inside -`personal/alice/`. Which means she can push `personal/alice/foo` and -`personal/alice/bar`, but NOT `personal/alice`. - -(Background: at runtime the "USER" component will be replaced by the name of -the invoking user. Access is determined by the right hand side, as usual). - -Compared to using arbitrary branch names on the same server, this: - - * Reduces namespace pollution by corralling all these ad hoc branches into - the "personal/" namespace. - * Reduces branch name collision by giving each developer her own - sub-hierarchy within that. - * Removes the need to think about access control, because a user can push - only to his own sub-hierarchy. - -## delegating access control responsibilities - -See [this][deleg]. - -## #keysonly using pubkeys obtained from elsewhere - -If you're not managing keys via the gitolite-admin repo, but getting them from -somewhere else, you'll want to periodically "update" the keys. - -To do that, first edit your rc file and add something like this: - - SSH_AUTHKEYS => - [ - 'post-compile/ssh-authkeys', - ], - -Then write a script that - - * gets all the keys and dumps them into `$HOME/.gitolite/keydir` (or into a - subdirectory of it). - - * runs `gitolite trigger SSH_AUTHKEYS`. - -Run this from cron or however you want. - -## #gh giving users their own repos - -(Please see [this][wild] for background on the ideas in this section). - -It's very easy to give users their own set of repos to create, with the -username at the top level. The simplest setup is: - - repo CREATOR/..* - C = @all - RW+ = CREATOR - RW = WRITERS - R = READERS - -Now users can create any repo under their own name simply by cloning it or -pushing to it, then use the [perms][] command to add other users to their -WRITERS and READERS lists. - -Of course you can get much more creative if you add a few more roles (see -"roles" in [this][wild] page). - -(I prefer using some prefix, say "u", as in `repo -u/CREATOR/..*`. This helps to keep user-created repos separate, and avoid -name clashes in some far-fetched scenarios). diff --git a/doc/sskm.mkd b/doc/sskm.mkd deleted file mode 100644 index 4ac908d..0000000 --- a/doc/sskm.mkd +++ /dev/null @@ -1,242 +0,0 @@ -# changing keys -- self service key management - -[Note on g3 version: this has been manually spot-tested; there is no test suite. Changes from g2 version are minimal so it should all work fine but please report errors!] - -Follow this guide to add keys to or remove keys from your account. Note that you cannot use this method to add your *first* key to the account; you must still email your initial key to your admin. - -The key management is done using a command called `sskm`. This command must be enabled for remote use by the admin (see [here][commands] for more on this). - ----- - -[[TOC]] - ----- - -## Important! - -There are a few things that you should know before using the key management system. Please do not ignore this section! - -### Key fingerprints - -Keys are identified in some of these subcommands by their fingerprints. To see the fingerprint for a public key on your computer, use the following syntax: - - ssh-keygen -l -f - -You'll get output like: - - jeff@baklava ~ $ ssh-keygen -l -f .ssh/jeffskey.pub - 2048 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 .ssh/jeffskey.pub (RSA) - -### Active keys - -Any keys that you can use to interact with the system are active keys. (Inactive keys are keys that are, for instance, scheduled to be added or removed.) Keys are identified with their `keyid`; see the section below on listing keys. - -If you have no current active keys, you will be locked out of the system (in which case email your admin for help). Therefore, be sure that you are never removing your only active key! - -### Selecting which key to use - -Although you can identify yourself to the Gitolite system with any of your active keys on the server, at times it is necessary to specifically pick which key you are identifying with. To pick the key to use, pass the `-i` flag into `ssh`: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git info - hello jeff, the gitolite version here is v2.0.1-11-g1cd3414 - the gitolite config gives you the following access: - @C R W [a-zA-Z0-9][a-zA-Z0-9_\-\.]+[a-zA-Z0-9] - .... - -*N.B.*: If you have any keys loaded into `ssh-agent` (i.e., `ssh-add -l` shows -at least one key), then this may not work properly. `ssh` has a bug which -makes it ignore `-i` values when that key has not been loaded into the agent. -One solution is to add the key you want to use (e.g., `ssh-add -.ssh/jeffskey`). The other is to remove *all* the keys from the agent or -disable the agent, using one of these commands: - -* Terminate `ssh-agent` or use `ssh-add -D` flag to remove identities from it -* If using `keychain`, run `keychain --clear` to remove identities -* Unset the `SSH_AUTH_SOCK` and `SSH_AGENT_PID` variables in the current shell - -### Public vs. private keys - -In this guide, all keys are using their full suffix. In other words, if you see a `.pub` at the end of a key, it's the public key; if you don't, it's the private key. For instance, when using the `-i` flag with `ssh`, you are specifying private keys to use. When you are submitting a key for addition to the system, you are using the public key. - -## Listing your existing keys - -To see a list of your existing keys, use the `list` argument to `sskm`: - - jeff@baklava ~ $ ssh git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - -Notice the `@` sign in each key's name? That sign and the text after that up until the `.pub` is the `keyid`. This is what you will use when identifying keys to the system. Above, for instance, one of my keys has the `keyid` of `@key3`. - -A keyid may be *empty*; in fact to start with you may only have a single -`jeff.pub` key, depending on how your admin added your initial key. You can -use any keyid you wish when adding keys (like `@home`, `@laptop`, ...); the -only rules are that it must start with the `@` character and after that -contain only digits, letters, or underscores. - -## Adding or Replacing a key - -### Step 1: Adding the Key - -Adding and replacing a key is the same process. What matters is the `keyid`. When adding a new key, use a new `keyid`; when replacing a key, pass in the `keyid` of the key you want to replace, as found by using the `list` subcommand. Pretty simple! - -To add a key, pipe in the text of your new key using `cat` to the `add` subcommand. In the example below, I explicitly select which existing, active pubkey to identify with for the command (using the `-i` parameter to ssh) for clarity: - - jeff@baklava ~ $ cat .ssh/newkey.pub | ssh -i .ssh/jeffskey git@git sskm add @key4 - hello jeff, you are currently using a normal ("active") key - please supply the new key on STDIN. (I recommend you - don't try to do this interactively, but use a pipe) - -If you now run the `list` command you'll see that it's scheduled for addition: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - == keys marked for addition/replacement == - 1: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a : jeff@key4.pub - -### Step 2: Confirming the addition - -Gitolite uses Git internally to store the keys. Just like with Git, where you commit locally before `push`-ing up to the server, you need to confirm the key addition (see the next section if you made a mistake). We use the `confirm-add` subcommand to do this, *but*: to verify that you truly have ownership of the corresponding private key, you *must* use the key you are adding itself to do the confirmation! (Inconvenient like most security, but very necessary from a security perspective.) This is where using the `-i` flag of `ssh` comes in handy: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm confirm-add @key4 - hello jeff, you are currently using a key in the 'marked for add' state - -Listing keys again shows that all four keys are now active: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - 4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a : jeff@key4.pub - -### Optional: Undoing a mistaken add (before confirmation) - -Another advantage of Gitolite using Git internally is that that if we mistakenly add the wrong key, we can undo it before it's confirmed by passing in the `keyid` we want to remove into the `undo-add` subcommand: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git sskm undo-add @key4 - hello jeff, you are currently using a normal ("active") key - -Listing the keys shows that that new key has been removed: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - -## Removing a key - -### Step 1: Mark the key for deletion - -Deleting a key works very similarly to adding a key, with `del` substituted for `add`. - -Let's say that I have my four keys from the example above: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - 4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a : jeff@key4.pub - -I would like to remove the key that on my box is called `newkey` and in the Gitolite system is known as `@key4`. - -I simply pass in the identifier to the `del` subcommand of `sskm`: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm del @key4 - hello jeff, you are currently using a normal ("active") key - -Listing the keys now shows that it is marked for deletion: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm list - hello jeff, you are currently using a key in the 'marked for del' state - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - == keys marked for deletion == - 1: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a : jeff@key4.pub - -### Step 2: Confirming the deletion - -Just like with Git, where you commit locally before `push`-ing up to the server, you need to confirm the key addition (see the next section if you made a mistake). We use the `confirm-del` subcommand to do this, *but*: unlike the `confirm-add` subcommand, you *must* use a *different* key than the key you are deleting to do the confirmation! This prevents you from accidentally locking yourself out of the system by removing all active keys: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git sskm confirm-del @key4 - hello jeff, you are currently using a normal ("active") key - -Listing keys again shows that the fourth key has been removed: - - jeff@baklava ~ $ ssh -i .ssh/jeffskey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - -### Optional: Undoing a mistaken delete (before confirmation) - -Another advantage of Gitolite using Git internally is that that if we mistakenly delete the wrong key, we can undo it before it's confirmed by passing in the `keyid` we want to keep into the `undo-del` subcommand. Note that this operation *must* be performed using the private key that corresponds to the key you are trying to keep! (Security reasons, similar to the reason that you must confirm an addition this way; it prevents anyone from undoing a deletion, and therefore keeping in the system, a key that they cannot prove (by having the corresponding private key) should stay in the system): - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm undo-del @key4 - hello jeff, you are currently using a key in the 'marked for del' state - - You're undeleting a key that is currently marked for deletion. - Hit ENTER to undelete this key - Hit Ctrl-C to cancel the undelete - Please see documentation for caveats on the undelete process as well as how to - actually delete it. - -(Go ahead and hit ENTER there; the caveats are really only on the administrative side of things.) - -Listing the keys shows that that new key is now marked active again: - - jeff@baklava ~ $ ssh -i .ssh/newkey git@git sskm list - hello jeff, you are currently using a normal ("active") key - you have the following keys: - == active keys == - 1: 72:ef:a3:e0:f5:06:f8:aa:6f:a2:88:9d:50:86:25:4e : jeff@key1.pub - 2: 61:38:a7:9f:ba:cb:99:81:4f:49:2c:8b:c8:63:8e:33 : jeff@key2.pub - 3: 2d:78:d4:2c:b1:6d:9a:dc:d9:0d:94:3c:d8:c2:65:44 : jeff@key3.pub - 4: ff:92:a2:20:6d:42:6b:cf:20:e8:a2:4a:3b:b0:32:3a : jeff@key4.pub - ----- - -## important notes for the admin - -These are the things that can break if you allow your users to use this -command: - - * "sskm" clones, changes, and pushes back the gitolite-admin repo. This - means, even if you're the only administrator, you should never 'git push - -f', in case you end up overwriting something sskm did. - - * There is no way to distinguish `foo/alice.pub` from `bar/alice.pub` using - this command. You can distinguish `foo/alice.pub` from - `bar/alice@home.pub`, but that's not because of the foo and bar, it's - because the two files have different keyids. - - In other words, sskm only works with the older style, not with the - "subdirectory" style of [multi-key][] management. - - * Keys placed in specific folders (for whatever reasons), will probably not - stay in those folders if this command is used. Even a key delete, followed - by undoing the delete, will cause the key to effectively move to the root - of the key store (i.e., the `keydir` directory in the gitolite-admin repo). diff --git a/doc/syntax.mkd b/doc/syntax.mkd deleted file mode 100644 index 5d3b6b5..0000000 --- a/doc/syntax.mkd +++ /dev/null @@ -1,46 +0,0 @@ -# #syntax basic syntax - -In general, everything is **space separated**; there are no commas, -semicolons, etc., in the syntax. - -**Comments** are in the usual shell-ish style. - -**User names** and **repo names** are as simple as possible; they must start -with an alphanumeric, but after that they can also contain `.`, `_`, or `-`. - -Usernames can optionally be followed by an `@` and a domainname containing at -least one `.` (this allows you to use an email address as someone's username). -Reponames can contain `/` characters (this allows you to put your repos in a -tree-structure for convenience) - -There are no continuation lines by default. You do not need them; the section -on "groups" will tell you how you can break up large lists of names in a group -definition into multiple lines. - -If you *must* have them, you can optionally enable them; -see the syntactic [sugar][] section. - -## #include include files - -Gitolite allows you to break up the configuration into multiple files and -include them in the main file for convenience. - - include "foo.conf" - -will include the contents of the file "foo.conf". - -Details: - - * You can also use a glob (`include "*.conf"`), or put your include files - into subdirectories of "conf" (`include "foo/bar.conf"`), or both - (`include "repos/*.conf"`). - - * Included files are always searched from the gitolite-admin repo's "conf/" - directory, unless you supplied an absolute path. (Note: in the interests - of cloning the admin-repo sanely you should avoid absolute paths!) - - * If you ended up recursing, files that have been already processed once are - skipped, with a warning. - -Advanced users: `subconf`, a command that is very closely -related to `include`, is documented [here][subconf]. diff --git a/doc/testing.mkd b/doc/testing.mkd deleted file mode 100644 index bf3eb4d..0000000 --- a/doc/testing.mkd +++ /dev/null @@ -1,50 +0,0 @@ -# testing gitolite - -Here's how to *run* the tests. - -**WARNING: they will clobber lots of things in your `$HOME`, -so be sure to use a throwaway userid**. - - git clone git://github.com/sitaramc/gitolite - cd gitolite - prove - -Make sure: - - * `$HOME/bin` is in `$PATH` - * sshd allows incoming ssh to this userid, at least from localhost - -Gitolite's test suite is mostly written using [tsh][] -- the "testing shell". -Take a look at some of the scripts and you will see what it looks like. It -has a few quirks and nuances; if you really care, email me. - -[tsh]: http://github.com/sitaramc/tsh - -The tests also use a somewhat convoluted system of environment variables in -order to run *entirely* as a local user, without going through ssh at all. -This lets a complete test suite run in about a fifth or less of the time it -would otherwise take. - -If you think that defeats the purpose of the testing, you haven't read -[this][auth] yet. - -## #trying trying out gitolite - -It's easy to take gitolite for a trial run, in ssh mode, and play with all of -its features (except mirroring). - -Create a **throw-away userid**, log in to it, then do what the "testing -gitolite" section above says, except instead of running `prove`, you run -`prove t/ssh*`. - -When this is done, you get a gitolite installation with 7 gitolite users -("admin", and "u1" through "u6"). - -Don't forget that the client and the server are all on the same user on the -same machine; we're *simulating* 7 gitolite users using ssh keys! (How? -Maybe `~/.ssh/config` will give you a hint). - -URLs look like `user:repo`, so for example you can clone the admin repo by -`git clone admin:gitolite-admin`. Remote commands look like `ssh u1 info`. - -So start by cloning the admin repo, and try out whatever you want! diff --git a/doc/triggers.mkd b/doc/triggers.mkd deleted file mode 100644 index 9ecdbc9..0000000 --- a/doc/triggers.mkd +++ /dev/null @@ -1,161 +0,0 @@ -# gitolite triggers - -[[TOC]] - -## intro and sample rc excerpt - -Gitolite fires off external commands at 7 different times. The [rc][] file -specifies what commands to run at each trigger point, but for illustration, -here's an excerpt: - - %RC = ( - - <...several lines later...> - - # comment out or uncomment as needed - # these will run in sequence after post-update - POST_COMPILE => - [ - 'post-compile/ssh-authkeys', - 'post-compile/update-git-configs', - 'post-compile/update-gitweb-access-list', - 'post-compile/update-git-daemon-access-list', - ], - - # comment out or uncomment as needed - # these will run in sequence after a new wild repo is created - POST_CREATE => - [ - 'post-compile/update-git-configs', - 'post-compile/update-gitweb-access-list', - 'post-compile/update-git-daemon-access-list', - ], - -(As you can see, post-create runs 3 programs that also run from post-compile. -This is perfectly fine, by the way) - -## types of trigger programs - -There are two types of trigger programs. Standalone scripts are placed in -src/triggers or its subdirectories. They are invoked by being added to a -trigger list (using the path after "src/triggers/", as you can see). Such -scripts are quick and easy to write in any language of your choice. - -Triggers written as perl modules are placed in src/lib/Gitolite/Triggers. -They are invoked by being listed with the package+function name, although even -here the 'Gitolite::Triggers' part is skipped. Perl modules have to follow -some conventions (see some of the shipped modules to ideas) but the advantage -is that they can set environment variables and change the argument list of the -gitolite-shell program that invokes them. - -If this does not make sense, please examine a default install of gitolite, -paying attention to: - - * the path names in various trigger lists in the rc file - * corresponding path names in the src/ directory in gitolite source - * and for perl modules, the package names and function names within. - -## manually firing triggers - -...from the server command line is easy. For example: - - gitolite trigger POST_COMPILE - -However if the triggered code depends on arguments (see next section) this -won't work. (The `POST_COMPILE` trigger programs all just happen to not -require any arguments, so it works). - -## common arguments - -Triggers receive the following arguments: - -1. any arguments mentioned in the rc file (for an example, see the renice - command in the PRE_GIT trigger sequence), - -2. the name of the trigger as a string (example, `"POST_COMPILE"`), so you - can call the same program from multiple triggers and it can know where it - was called from, - -3. followed by zero or more arguments specific to the trigger, as given in - the next section. - -## trigger-specific arguments and other details - -Here are the **rest of** the arguments for each trigger, plus a brief -description of when the trigger runs: - - * `INPUT` runs before pretty much anything else. INPUT trigger scripts - *must* be in perl, since they manipulate the arguments to and the - environment of the 'gitolite-shell' program itself. Most commonly they - will read/change `@ARGV`, and/or `$ENV{SSH_ORIGINAL_COMMAND}`. - - There are certain conventions to adhere to; please see some of the shipped - samples or ask me if you need help writing your own. - - * `ACCESS_1` runs after the first access check. Extra arguments: - * repo - * user - * 'R' or 'W' - * 'any' - * result (see notes below) - - 'result' is the return value of the access() function. If it contains the - uppercase word "DENIED", the access was rejected. Otherwise it is the - refex that caused the access to succeed. - - *Please note that if access is rejected, gitolite-shell will die as soon - as it returns from the trigger*. - - * `ACCESS_2` runs after the second access check, which is invoked by the - update hook to check the ref. Extra arguments: - * repo - * user - * any of W, +, C, D, WM, +M, CM, DM - * the ref being updated (e.g., 'refs/heads/master') - * result - * old SHA - * new SHA - - `ACCESS_2` also runs on each [VREF][vref] that gets checked. In this case - the "ref" argument will start with "VREF/", and the last two arguments - won't be passed. - - 'result' is similar to `ACCESS_1`, except that it is the *update hook* - which dies as soon as access is rejected for the ref or any of the VREFs. - Control then returns to git, and then to gitolite-shell, so the `POST_GIT` - trigger *will* run. - - * `PRE_GIT` and `POST_GIT` run just before and after the git command. - Extra arguments: - * repo - * user - * 'R' or 'W' - * 'any' - * the git command ('git-receive-pack', 'git-upload-pack', or - 'git-upload-archive') being invoked. - - * `PRE_CREATE` and `POST_CREATE` run just before and after a new "[wild][]" - repo is created by user action. Extra arguments: - * repo - * user - * invoking operation - * 'R' for fetch/clone/ls-remote, 'W' for push - * can also be anything set by the external command running the - trigger (e.g., see the perms and fork commands). - - They are also run when a *normal* repo is created (say by adding a "repo - foo" line to the conf file). This case has only one extra argument: - * repo - - * `POST_COMPILE` runs after an admin push has successfully "compiled" the - config file. By default, the next thing is to update the ssh authkeys - file, then all the 'git-config's, gitweb access, and daemon access. - - No extra arguments. - -## tips - -If you have code that latches onto more than one trigger, collecting data -(such as for logging), then the outputs may be intermixed. You can record the -value of the environment variable `GL_TID` to tie together related entries. - diff --git a/doc/user.mkd b/doc/user.mkd deleted file mode 100644 index a0a767e..0000000 --- a/doc/user.mkd +++ /dev/null @@ -1,97 +0,0 @@ -# what users (not admins) need to know about gitolite - -...written for the one guy in the world no one will think of as "just a normal -user" ;-) - ----- - -[[TOC]] - ----- - -## accessing gitolite - -The most common setup is based on ssh, where your admin asks you to send him -your public key, and uses that to setup your access. - -Your actual access is either a git command (like `git clone -git@server:reponame`, and we won't be discussing these any more in this -document), or an ssh command (like `ssh git@server info`). - -Note that you do *not* get a shell on the server -- the whole point of -gitolite is to prevent that! - -## #info the info command - -The only command that is *always* available to every user is the `info` -command (run `ssh git@host info -h` for help), which tells you what version of -gitolite and git are on the server, and what repositories you have access to. -The list of repos is very useful if you have doubts about the spelling of some -new repo that you know was setup. - -## digression: two kinds of repos - -Gitolite has two kinds of repos. Normal repos are specified by their full -names in the config file. "Wildcard" repos are specified by a regex in the -config file. Try the [`info` command][info] and see if it shows any lines -that look like regex patterns, (with a "C" permission). - -If you see any, it means you are allowed to create brand new repos whose names -fit that pattern. When you create such a repo, your "ownership" of it (as far -as gitolite is concerned) is automatically recorded by gitolite. - -## other commands - -### #perms set/get additional permissions for repos you created - -The gitolite config may have several permissions lines for your repo, like so: - - repo pub/CREATOR/..* - RW+ = CREATOR - RW = user1 user2 - R = user3 - -If that's all it had, you really can't do much. Any changes to access must be -done by the administrator. (Note that "CREATOR" is a reserved word that gets -expanded to your userid in some way, so the admin can literally add just the -first two lines, and *every* authenticated user now has his own personal repo -namespace, starting with `pub//`). - -To give some flexibility to users, the admin could add rules like this: - - RW = WRITERS - R = READERS - -(he could also add other roles but then he needs to read the documentation). - -Once he does this, you can then use the `perms` command (run `ssh git@host -perms -h` for help) to set permissions for other users by specifying which -users are in the list of "READERS", and which in "WRITERS". - -If you think of READERS and WRITERS as "roles", it will help. You can't -change what access a role has, but you *can* say which users have that role. - -**Note**: there isn't a way for you to see the actual rule set unless you're -given read access to the special 'gitolite-admin' repo. Sorry. The idea is -that your admin will tell you what "roles" he added into rules for your repos, -and what permissions those roles have. - -### #desc adding a description to repos you created - -The `desc` command is extremely simple. Run `ssh git@host desc -h` for help. - -## "site-local" commands - -The main purpose of gitolite is to prevent you from getting a shell. But -there are commands that you often need to run on the server (i.e., cannot be -done by pushing something to a repo). - -To enable this, gitolite allows the admin to setup scripts in a special -directory that users can then run. Gitolite comes with a set of working -scripts that your admin may install, or may use as a starting point for his -own, if he chooses. - -Think of these commands as equivalent to those in `COMMAND_DIR` in `man -git-shell`. - -You can get a list of available commands by running `ssh git@host help`. diff --git a/doc/users.mkd b/doc/users.mkd deleted file mode 100644 index 6211278..0000000 --- a/doc/users.mkd +++ /dev/null @@ -1,67 +0,0 @@ -# adding and removing users - -Strictly speaking, gitolite doesn't know where users come from. If that -surprises you, read [this][auth]. However, gitolite does help with ssh-based -authentication, so here's some info on adding and removing users. - -> ---- - -> *WARNING: Do NOT add new repos or users manually on the server. Gitolite -> users, repos, and access rules are maintained by making changes to a -> special repo called 'gitolite-admin' and pushing those changes to the -> server.* - -> ---- - -All operations are in a clone of the gitolite-admin repo. - -To **add** a user, say Alice, obtain her public key (typically -`$HOME/.ssh/id_rsa.pub` on her workstation), copy it to `keydir` with the user -name as the basename (e.g., 'alice.pub' for user alice), then `git add -keydir/alice.pub`. (All keys files must have names ending in ".pub", and must -be in openssh's default format). - -To **remove** a user, `git rm keydir/alice.pub`. - -In both cases, you must commit and push. On receiving the push, gitolite will -carry out the changes specified. - -The user name is simply the base name of the public key file name. So -'alice.pub', 'foo/alice.pub' and 'bar/alice.pub', all resolve to user "alice". - -## #multi-key multiple keys per user - -The simplest and most understandable is to put their keys in different -subdirectories, (alice.pub, home/alice.pub, laptop/alice.pub, etc). - -### old style multi-keys - -There is another way that involves creating key files like `alice@home.pub` -and `alice@laptop.pub`, but there is a complication because gitolite also -allows *full email addresses* as user names. (I.e., `sitaramc@gmail.com.pub` -denotes the user called `sitaramc@gmail.com`). - -This older method of enabling multi-keys was developed to deal with that. It -will continue to work and be supported in *code*, simply because I prefer it. -But I will not accept questions or doc patches for it, because it seems it is -too difficult to understand for a lot of people. This table of sample pubkey -filenames and the corresponding derived usernames is all you get: - - * plain username, no multikey - - sitaramc.pub sitaramc - - * plain username, with multikeys - - sitaramc@laptop.pub sitaramc - sitaramc@desktop.pub sitaramc - - * email address as username, no multikey - - sitaramc@gmail.com.pub sitaramc@gmail.com - - * email address as username, with multikeys - - sitaramc@gmail.com@laptop.pub sitaramc@gmail.com - sitaramc@gmail.com@desktop.pub sitaramc@gmail.com - diff --git a/doc/vref.mkd b/doc/vref.mkd deleted file mode 100644 index 0f7c382..0000000 --- a/doc/vref.mkd +++ /dev/null @@ -1,308 +0,0 @@ -# virtual refs - -**IMPORTANT**: fallthru is success in VREFs, unlike the normal refs. That -won't make sense until you read further, but I had to put it up here for folks -who stop reading halfway! - ----- - -[[TOC]] - ----- - -Here's an example to start you off. - - repo r1 - RW+ = lead_dev dev2 dev3 - - VREF/COUNT/9 = dev2 dev3 - - VREF/COUNT/3/NEWFILES = dev2 dev3 - -Now dev2 and dev3 cannot push changes that affect more than 9 files at a time, -nor those that have more than 3 new files. - ----- - -## rule matching recap - -You won't get any joy out of this if you don't understand at least -[refex][]es and how [rules][] are processed. - -But VREFs have one **very important difference** from normal rules. With -VREFs, a **fallthru results in success**. You'll see why this is more -convenient as you read on. - ----- - -## what is a virtual ref - -A ref like `refs/heads/master` is the main property of a push that gitolite -uses to make its yes/no decision. I call this a "real" ref. - -Any *other* property of the push that you want to use to help in the decision -is therefore a *virtual* ref. This could be a property that git knows about, -like in the example above, or comes from outside git like, say, the current -time; see examples section later for some ideas. - -## #vref-fallthru fallthru is success here - -Notice that you didn't need to add an `RW+ VREF/...` rule for user `lead_dev` -in our example. This section explains why. - -**Virtual refs are best used as additional "deny" rules**, performing extra -checks that core gitolite cannot. - -Making fallthru be a "fail" forces you to add rules for all users, instead of -just the ones who should have those extra checks. Worse, since every virtual -ref involves calling an external program, many of these calls may be wasted. - -There's another advantage to doing it this way: a VREF can choose to simply -die if things look bad, and it will have the same effect, assuming you used -the VREF only in "deny" rules. - -This in turn means any existing update hook can be used as a VREF *as-is*, as -long as it (a) prints nothing on success and (b) dies on failure. See the -email-check example later. - -## how it works -- overview - -Briefly, a refex starting with `VREF/FOO` triggers a call to a program called -`FOO` in `$GL_BINDIR/VREF`. - -That program is expected to print zero or more lines to its STDOUT; each line -that starts with `VREF/` is taken by gitolite as a new "ref" to be matched -against all the refexes for this user in the config. Including the refex that -caused the vref call, of course. - -Normally, you send back the refex itself, if the test determines that the rule -should be matched, otherwise nothing. So, in our example, we print -`VREF/COUNT/9` if the count was indeed greater than 9. Otherwise we just -exit. - -## how it works -- details - - * The VREF code is only called if there are any VREF rules for the user, - which means when the lead developer pushes, the VREF is not called at all. - - Side note: this is enormously more efficient than adding additional - `update` hooks, which will get executed whether they are needed or not, - for every repo and every user! - - * When dev2 or dev3 push, gitolite first checks the real ref - (`ref/heads/master` or whatever). After this it looks at VREF rules, and - calls an external program for every one it finds. Specifically, in a line - like - - - VREF/COUNT/3/NEWFILES = user - - COUNT is the vref name, so the program called is - `$GL_BINDIR/VREF/COUNT`. - - The program is passed **nine arguments** in this case (see next section - for details). - - * The script can print anything it wants to STDOUT. Lines not starting with - `VREF/` are printed as is (so your VREF can do mostly-normal printing to - STDOUT). - - For lines starting with `VREF/`, the first word in each such line will be - treated as a virtual ref to be matched against all the rules, while the - rest, if any, is a message to be added to the standard "...DENIED..." - message that gitolite prints if that refex matches. - - Usually it only makes sense to either - - * Print nothing that starts with `VREF/` -- if you don't want the rule - that triggered it to match (ie., whatever condition being tested was - not violated; like if the count of changed files did not exceed 9, in - our earlier example). - * Print the refex itself (plus an optional message), so that it matches - the line which invoked it. - -### #vref-args arguments passed to the vref code - - * Arguments **1, 2, 3**: the 'ref', 'oldsha', and 'newsha' that git passed - to the update hook (see 'man githooks'). - - This, combined with the fact that non-zero exits are detected, mean that - you can simply use an existing update.secondary as a new VREF as-is, no - changes needed. - - * Arguments **4 and 5**: the 'oldtree' and 'newtree' SHAs. These are the - same as the oldsha and newsha values, except if one of them is all-0. - (indicating a ref creation or deletion). In that case the corresponding - 'tree' SHA is set (by gitolite, as a courtesy) to the special SHA - `4b825dc642cb6eb9a060e54bf8d69288fbee4904`, which is the hash of an empty - tree. - - (None of these shenanigans would have been needed if `git diff $oldsha - $newsha` would not error out when passed an all-0 SHA.) - - * Argument **6**: the attempted access flag. Typically `W` or `+`, but - could also be `C`, `D`, or any of these 4 followed by `M`. If you have to - ask what they mean, you haven't read enough gitolite documentation to be - able to make virtual refs work. - - * Argument **7**: is the entire refex; in our example - `VREF/COUNT/3/NEWFILES`. - - * Arguments **8 onward**: are the split out (by `/`) portions of the refex, - excluding the first two components. In our example they would be `3` - followed by `NEWFILES`. - -Yes, argument 7 is redundant if you have 8 and 9. It's meant to make it easy -to write vref scripts in any language. See script examples in source. - -## what (else) can the vref code pass back - -Actually, the vref code can pass anything back; each line in its output that -starts with `VREF/` will be matched against all the rules as usual (with the -exception that fallthru is not failure). - -For example, you could have a ruleset like this: - - repo r1 - # ... normal rules ... - - - VREF/TIME/WEEKEND = @interns - - VREF/TIME/WEEKNIGHT = @interns - - VREF/TIME/HOLIDAY = @interns - -and you could write the TIME vref code to passback any or all -of the times that match. Then if an intern tried to access the system, each -rule would trigger a call to gl-bindir/VREF/TIME. - -The script should send back any of the applicable times (even more than one, -or none at all, as the case may be). So even if it was invoked using the -first rule, it might pass back (to gitolite) a virtual ref saying -'VREF/TIME/HOLIDAY', which would promptly cause the request to be denied. - -## VREFs shipped with gitolite - -### #NAME restricting pushes by dir/file name - -The "NAME" VREF allows you to restrict pushes by the names of dirs and files -changed. (Side note: the NAME VREF is the only one directly implemented -within the update hook, so you won't find it in the VREF directory). - -Here's an example. Say you don't want junior developers pushing changes to -the Makefile, because it's quite complex: - - repo foo - RW+ = @senior_devs - RW = @junior_devs - - - VREF/NAME/Makefile = @junior_devs - -When a senior dev pushes, the VREF is not invoked at all. But when a junior -dev pushes, the VREF is invoked, and it returns a list of files changed **as -refs**, looking like this: - - VREF/NAME/file-1 - VREF/NAME/dir-2/file-3 - ...etc... - -Each of these refs is matched against the access rules. If one of them -happens to be the Makefile, then the ref returned (VREF/NAME/Makefile) will -match the deny rule and kill the push. - -Another way to use this is when you know what is allowed instead of what is -not allowed. Let's say the QA person is only allowed to touch a file called -CHANGELOG and any files in a directory called ReleaseNotes: - - repo foo - RW+ = @senior_devs - RW = @junior_devs - RW+ = QA-guy - - RW+ VREF/NAME/CHANGELOG = QA-guy - RW+ VREF/NAME/ReleaseNotes/ = QA-guy - - VREF/NAME/ = QA-guy - -### number of new files - -The COUNT VREF is used like this: - - - VREF/COUNT/9 = @junior-developers - -In response, if anyone in the user list pushes a commit series that -changes more than 9 files, a vref of "VREF/COUNT/9" is returned. Gitolite -uses that as a "ref" to match against all the rules, hits the same rule -that invoked it, and denies the request. - -If the user did not push more than 9 files, the VREF code returns nothing, -and nothing happens. - -COUNT can take one more argument: - - - VREF/COUNT/9/NEWFILES = @junior-developers - -This is the same as before, but have to be more than 9 *new* files not -just changed files. - -### advanced filetype detection - -Note: this is more for illustration than use; it's rather specific to one of -the projects I manage but the idea is the important thing. - -Sometimes a file has a standard extension (that cannot be 'gitignore'd), but -it is actually automatically generated. Here's one way to catch it: - - - VREF/FILETYPE/AUTOGENERATED = @all - -You can look at `src/VREF/FILETYPE` to see how it handles the -'AUTOGENERATED' option. You could also have a more generic option, like -perhaps BINARY, and handle that in the FILETYPE vref too. - -### checking author email - -Some people want to ensure that "you can only push your own commits". - -If you force it on everyone, this is a very silly idea (see "Philosophical -Notes" section of `src/VREF/EMAIL-CHECK`). - -But there may be value in enforcing it just for the junior developers. - -The neat thing is that the existing `contrib/update.email-check` was just -copied to `src/VREF/EMAIL-CHECK` and it works, because VREFs get -the same first 3 arguments and those are all that it cares about. (Note: you -have to change one subroutine in that script if you want to use it) - -### #votes voting on commits - -Although gitolite can't/won't do the whole "code review + workflow -enforcement" thing that Gerrit Code Review does, a basic implementation of -voting on a commit is surprisingly easy. See src/VREF/VOTES for details (and -note that the actual *code* is just 2-3 lines; the rest is inline -documentation). - -## other ideas -- code welcome! - -### "no non-merge first-parents" - -Shruggar on #gitolite wanted this. Possible code to implement it would be -something like this (untested) - - [ -z "$(git rev-list --first-parent --no-merges $2..$3)" ] - -This can be implemented using `src/VREF/MERGE-CHECK` as a model. That script -does what the 'M' qualifier does in access rules (see last part of -[this][write-types]), although the syntax to be used in conf/gitolite will be -quite different. - -### other ideas for VREFs - -Here are some more ideas: - - * Number of commits (`git rev-list --count $old $new`). - * Number of binary files in commit (currently I only know to count - occurrences of ` Bin ` in the output of `git diff --stat`. - * Number of *new* binary files (count ` Bin 0 ->` in `git diff --stat` - output). - * Time of day/day of week (see example snippet somewhere above). - * IP address. - * Phase of the moon. - -Note that pretty much anything that involves `$oldsha..$newsha` will have to -deal with the issue that when you push a new tag or branch, the "old" part -is all 0's, and unless you consider `--all` existing branches and tags it -becomes meaningless in terms of "number of new files" etc. diff --git a/doc/why.mkd b/doc/why.mkd deleted file mode 100644 index f88f7c1..0000000 --- a/doc/why.mkd +++ /dev/null @@ -1,97 +0,0 @@ -# why might you need gitolite - -[[TOC]] - ----- - -## basic use case - -Gitolite is useful in any server that is going to host multiple git -repositories, each with many developers, where "anyone can do anything to any -repo" is not a good idea. Here're two examples to illustrate. - -Example 1, 3 repos, 3 developers with different levels of access to each repo: - - repo foo - RW+ = alice - R = bob - - repo bar - RW+ = bob - R = alice - - repo baz - RW+ = carol - R = alice bob - -Example 2, one repo, but different levels of access to different branches and -tags for different developers: - - repo foo - RW+ master = alice - RW+ dev/ = bob - RW refs/heads/tags/v[0-9] = ashok - -## #alt alternatives - -### unix permissions and ACLs - -If you're a masochist, you could probably do example 1 with Unix permissions -and facls. But you can't do example 2 -- git is not designed to allow that! - -Here are some other disadvantages of the Unix ACL method: - - * Every user needs a userid and password on the server. - * Changing access rights involves complex `usermod -G ...` mumblings - (I.e., the "pain" mentioned above is not a one-time pain!) - * *Viewing* the current set of permissions requires running multiple - commands to list directories and their permissions/ownerships, users and - their group memberships, and then correlating all these manually. - * Auditing historical permissions or permission changes is impossible. - -### #gcr Gerrit Code Review - -The best real alternative to gitolite is Gerrit Code Review. If code review -is an essential part of your workflow, you should use Gerrit. - -Here're some high level differences between gitolite and Gerrit: - -**Size**: 3000+ lines of perl versus of 56,000+ lines of Java - -**Architecture**: Gitolite sits on top of "standard" git and openssh, which -are assumed to already be installed. Gerrit includes its own git stack (jgit) -and sshd (Apache Mina). In Java tradition, they all come bundled together. - -(Corollary: As far as I know jgit does not support the same hooks that 'man -githooks' talks about). - -Gitolite uses a plain text config file; gerrit uses a database. - -**User view**: Gitolite is invisible to users except when access is denied. I -think Gerrit is much more visible to devs. - -On a related note, gitolite does not do anything special with signed or -annotated tags, nor does it check author/committer identity. However, it is -trivial to add your own code to do either (or if someone contributes it, to -just "enable" what ships with gitolite in a disabled state). - -### gitorious - -Anecdotally, gitorious is very hard to install. Comparison with gitolite may -be useless because I believe it doesn't have branch/tag level access control. -However, I can't confirm or deny this because I can't find any documentation -on the website. - -In addition, the main website hides the source code very well, so you already -have a challenge! [The only link I could find was tucked away at the bottom -of the About page, in the License section]. - -### gitlab - -Gitlab is built on top of gitolite, but I don't know more than that as yet. -Patches welcome. - -### others - -Please send in patches to this doc if you know of other open source git -hosting solutions that do access control. diff --git a/doc/wild.mkd b/doc/wild.mkd deleted file mode 100644 index 4670cc4..0000000 --- a/doc/wild.mkd +++ /dev/null @@ -1,157 +0,0 @@ -# "wild" repos (user created repos) - -## quick introduction - -The wildrepos feature allows you to specify access control rules using regular -expression patterns, so you can have many actual repos being served by a -single set of rules in the config file. The regex pattern can also include -the word `CREATOR` in it, allowing you to parametrise the name of the user -creating the repo. - -See the section on "repo patterns" later for additional information on what -counts as a "wild" repo pattern and how it is matched. - -## (admin) declaring wild repos in the conf file - -Here's an example: - - @prof = u1 - @TAs = u2 u3 - @students = u4 u5 u6 - - repo assignments/CREATOR/a[0-9][0-9] - C = @students - RW+ = CREATOR - RW = WRITERS @TAs - R = READERS @prof - -Note the "C" permission. This is a standalone "C", which gives the named -users the right to *create a repo*. This is not to be -confused with the "RWC" or its variants described elsewhere, which are about -*branches*, not *repos*. - -## #create (user) creating a specific repo - -For now, ignore the special usernames READERS and WRITERS, and just create a -new repo, as user "u4" (a student): - - $ git clone git@server:assignments/u4/a12 - Initialized empty Git repository in /home/sitaram/a12/.git/ - Initialized empty Git repository in /home/git/repositories/assignments/u4/a12.git/ - warning: You appear to have cloned an empty repository. - -Notice the *two* empty repo inits, and the order in which they occur ;-) - -## a slightly different example - -Here's how the same example would look if you did not want the CREATOR's name -to be part of the actual repo name. - - repo assignments/a[0-9][0-9] - C = @students - RW+ = CREATOR - RW = WRITERS @TAs - R = READERS @prof - -We haven't changed anything except the repo name pattern. This means that the -first student that creates, say, `assignments/a12` becomes the owner. -Mistakes (such as claiming a12 instead of a13) need to be rectified by an -admin logging on to the back end, though it's not too difficult. - -You could also repace the C line like this: - - C = @TAs - -and have a TA create the repos in advance. - -## repo patterns - -### pattern versus normal repo - -Due to projects like `gtk+`, the `+` character is now considered a valid -character for an *ordinary* repo. Therefore, a pattern like `foo/.+` does not -look like a regex to gitolite. Use `foo/..*` if you want that. - -Also, `..*` by itself is not considered a valid repo pattern. Try -`[a-zA-Z0-9].*`. - -### line-anchored regexes - -A regex like - - repo assignments/S[0-9]+/A[0-9]+ - -would match `assignments/S02/A37`. It will not match `assignments/S02/ABC`, -or `assignments/S02/a37`, obviously. - -But you may be surprised to find that it does not match even -`assignments/S02/A37/B99`. This is because internally, gitolite -*line-anchors* the given regex; so that regex actually becomes -`^assignments/S[0-9]+/A[0-9]+$` -- notice the line beginning and ending -metacharacters. - -> ---- - -> *Side-note: contrast with refexes* - -> Just for interest, note that this is in contrast to the refexes for the -> normal "branch" permissions, as described in `doc/gitolite.conf.mkd` and -> elsewhere. These "refexes" are only anchored at the start; a pattern like -> `refs/heads/master` actually can match `refs/heads/master01/bar` as well, -> even if no one will actually push such a branch! You can anchor both -> sides if you really care, by using `master$` instead of `master`, but that -> is *not* the default for refexes. - -> ---- - -## roles - -The tokens READERS and WRITERS are called "role" names. The access rules in -the conf file decide what permissions these roles have, but they don't say -what users are in each of these roles. - -That needs to be done by the creator of the repo, using the `perms` command. -You can run `ssh git@host perms -h` for detailed help, but in brief, that -command lets you give and take away roles to users. [This][perms] has some -more detail. - -## adding other roles - -If you want to have more than just the 2 default roles, say something like: - - repo foo/..* - C = u1 - RW refs/tags/ = TESTERS - - refs/tags/ = @all - RW+ = WRITERS - RW = INTERNS - R = READERS - RW+D = MANAGERS - -You can add the new names to the ROLES hash in the [rc][] file. Be sure to -run the 2 commands mentioned there after you have added the roles. -file. The rc file documentation (`doc/gitolite.rc.mkd`) explains how. - -#### #rolenamewarn **IMPORTANT WARNING ABOUT THIS FEATURE** - -Please make sure that none of the role names conflict with any of the user -names or group names in the system. For example, if you have a user called -"foo" or a group called "@foo", make sure you do not include "foo" as a valid -role in the ROLES hash. - -You can keep things sane by using UPPERCASE names for roles, while keeping all -your user and group names lowercase; then you don't have to worry about this -problem. - -## listing wild repos - -In order to see what repositories were created from a wildcard, use the 'info' -command. Try `ssh git@host info -h` to get help on the info command. - -## deleting a wild repo - -Run the whimsically named "D" command -- try `ssh git@host D -h` for more info -on how to delete a wild repo. (Yes the command is "D"; it's meant to be a -counterpart to the "C" permission that allowed you to create the repo in the -first place). Of course this only works if your admin has enabled the command -(gitolite ships with the command disabled for remote use). diff --git a/doc/write-types.mkd b/doc/write-types.mkd deleted file mode 100644 index 79d8f67..0000000 --- a/doc/write-types.mkd +++ /dev/null @@ -1,31 +0,0 @@ -## #write-types different types of write operations - -Git supplies enough information to the update hook to be able to distinguish -several types of writes. - -The most common are: - - * `RW` -- create a ref or fast-forward push a ref. No rewinds or deletes. - * `RW+` -- create, fast-forward push, rewind push, or delete a ref. - -Sometimes you want to allow people to push, but not *create* a ref. Or -rewind, but not *delete* a ref. The `C` and `D` qualifiers help here. - - * When a rule specifies `RWC` or `RW+C`, then *rules that do NOT have the C - qualifier will no longer permit **creating** a ref*. - - Please do not confuse this with the standalone `C` - permission that allows someone to [create][] a **repo** - - * When a rule specifies `RWD` or `RW+D`, then *rules that do NOT have the D - qualifier will no longer permit **deleting** a ref*. - -Note: These two can be combined, so you can have `RWCD` and `RW+CD` as well. - -One very rare need is to reject merge commits (a commit series that is not a -straight line of commits). The `M` qualifier helps here: - - * When a rule has `M` appended to the permissions, *rules that do NOT have - it will reject a commit sequence that contains a merge commit* (i.e., they - only accept a straight line series of commits). - From af437c3a7b9034c8bfda30d99daf3a8160ff904d Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 27 Jun 2012 07:10:09 +0530 Subject: [PATCH 092/158] v3.04 --- CHANGELOG | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 2767b31..f743d19 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,25 @@ +2012-06-27 v3.04 documentation graduated and moved out of parents house :) + + new trigger for 'repo specific umask' + + new 'list-dangling-repos' command + + new LOCAL_CODE rc var; allow admin specified programs to + override system-installed ones + + new 'upstream' trigger-cum-command to maintain local + copies of external repos + + new 'sudo' command + + minor backward compat breakage in 'gitolite query-rc' + + 'perms' command can now create repo if needed + + migrated 'symbolic-ref' command + + 'gitolite setup --hooks-only' + 2012-05-23 v3.03 fix major bug that allowed an admin to get a shell 2012-05-20 v3.02 packaging instructions fixed up and smoke tested From db2cf23379bf0d14cc2e1d0edd5289d38f7f5a90 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 29 Jun 2012 22:19:06 +0530 Subject: [PATCH 093/158] logical expressions on refexes :-) --- src/VREF/refex-expr | 73 +++++++++++++++++++++++ src/lib/Gitolite/Triggers/RefexExpr.pm | 80 ++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100755 src/VREF/refex-expr create mode 100644 src/lib/Gitolite/Triggers/RefexExpr.pm diff --git a/src/VREF/refex-expr b/src/VREF/refex-expr new file mode 100755 index 0000000..3ff4bf4 --- /dev/null +++ b/src/VREF/refex-expr @@ -0,0 +1,73 @@ +#!/usr/bin/perl +use strict; +use warnings; + +my $rule = $ARGV[7]; +my $res = $ENV{"GL_REFEX_EXPR_" . $rule} || 0; +print "$ARGV[6] ($res)\n" if $res; + +exit 0; + +__END__ + +Documentation for the refex-expression evaluation feature + +First, make sure you have both the VREF and the trigger scripts +(src/VREF/refex-expr and src/lib/Gitolite/Triggers/RefexExpr.pm) + +Next, add this to the ACCESS_2 list in the rc file: + + 'RefexExpr::access_2', + +For the rest, we'll use this example: + + * user u1 can push foo to some other branch, and anything else to the master + branch, but not foo to the master branch + + * user u2 is allowed to push either 'doc/' or 'src/' but not both + +Here's the conf file extract: + + repo testing + RW+ master = u1 # line 1 + RW+ = @all # line 2 + + RW+ VREF/NAME/foo = u1 + RW+ VREF/NAME/doc/ = u2 + RW+ VREF/NAME/src/ = u2 + + # set up 2 refex expressions, named e1, e2 + option refex-expr.e1 = master and VREF/NAME/foo + option refex-expr.e2 = VREF/NAME/doc/ and VREF/NAME/src/ + + # now deny users if the corresponding expression is true + - VREF/refex-expr/e1 = u1 + - VREF/refex-expr/e2 = u2 + +Here are some IMPORTANT notes: + + * You MUST place VREF/refex-expr rules at the end. (Only 'partial-copy', if + you use it, must come later). + + * You MUST explicitly permit the refexes used in your refex expressions. If + you have more generic rules, the specific ones must come first. + + For example, without line 1, the refex recorded for user u1 will come from + line 2, (so it will be 'refs/.*'), and 'master' in the refex expressions + will never have a true value. + + * (corollary) make sure you use the exact same refex in the expression as + you did on the original rule line. E.g., a missing slash at the end will + mess things up. + + * You can use any logical expression using refexes as operands and using + these operators: + + and not xor or + + Parens are not allowed. + + If a refex has passed, it will have a 'true' value, else it will be false. + + The result of the evaluation, after these substitutions, will be the + result of the refex-expr VREF. diff --git a/src/lib/Gitolite/Triggers/RefexExpr.pm b/src/lib/Gitolite/Triggers/RefexExpr.pm new file mode 100644 index 0000000..687cb9e --- /dev/null +++ b/src/lib/Gitolite/Triggers/RefexExpr.pm @@ -0,0 +1,80 @@ +package Gitolite::Triggers::RefexExpr; +use strict; +use warnings; + +# track refexes passed and evaluate expressions on them +# ---------------------------------------------------------------------- +# see instructions for use at the bottom of src/VREF/refex-expr + +use Gitolite::Easy; + +my %passed; +my %rules; +my $init_done = 0; + +sub access_2 { + # get out quick for repos that don't have any rules + return if $init_done and not %rules; + + # but we don't really know that the first time, heh! + if (not $init_done) { + my $repo = $_[1]; + init($repo); + return unless %rules; + } + + my $refex = $_[5]; + return if $refex =~ /DENIED/; + + $passed{$refex}++; + + # evaluate the rules each time; it's not very expensive + for my $k (sort keys %rules) { + $ENV{"GL_REFEX_EXPR_" . $k} = eval_rule($rules{$k}); + } +} + +sub eval_rule { + my $rule = shift; + + my $e; + $e = join " ", map { convert($_) } split ' ', $rule; + + my $ret = eval $e; + _die "eval '$e' -> '$@'" if $@; + Gitolite::Common::trace(1, "RefexExpr", "'$rule' -> '$e' -> '$ret'"); + + return "'$rule' -> '$e'" if $ret; +} + +my %constant; +%constant = map { $_ => $_ } qw(1 not and or xor + - ==); +$constant{'-lt'} = '<'; +$constant{'-gt'} = '>'; +$constant{'-eq'} = '=='; +$constant{'-le'} = '<='; +$constant{'-ge'} = '>='; +$constant{'-ne'} = '!='; + +sub convert { + my $i = shift; + return $i if $i =~ /^-?\d+$/; + return $constant{$i} || $passed{$i} || $passed{"refs/heads/$i"} || 0; +} + +# called only once +sub init { + $init_done = 1; + my $repo = shift; + + # find all the rule expressions + my %t = config($repo, "^gitolite-options\\.refex-expr\\."); + my ($k, $v); + # get rid of the cruft and store just the rule name as the key + while ( ($k, $v) = each %t) { + $k =~ s/^gitolite-options\.refex-expr\.//; + $rules{$k} = $v; + } +} + +1; From f545bc08f6e932fd15ca231696903237a736d878 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 1 Jul 2012 16:00:25 +0530 Subject: [PATCH 094/158] minor fixups --- check-g2-compat | 5 +++-- src/lib/Gitolite/Rc.pm | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/check-g2-compat b/check-g2-compat index 11fe7a7..72c32fa 100755 --- a/check-g2-compat +++ b/check-g2-compat @@ -38,8 +38,9 @@ sub intro { msg( '' => "or that might end up giving *more* access to someone if migrated as-is." ); msg( '' => "It does NOT attempt to catch all the differences described in the docs." ); msg( '', '' ); - msg( INFO => "'see docs' usually means doc/g2migr.mkd" ); - msg( '', => "(online at http://sitaramc.github.com/gitolite/g2migr.html)" ); + msg( INFO => "'see docs' usually means the pre-migration checklist in" ); + msg( '', => "'g2migr.html'; to get there, start from the main migration" ); + msg( '', => "page at http://sitaramc.github.com/gitolite/install.html#migr" ); msg( '', '' ); } diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 23ed421..876760a 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -326,6 +326,8 @@ __DATA__ # word, not a full domain name. See documentation if in doubt # HOSTNAME => 'darkstar', 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 From f35db87efc115a8e79ca7776fcc0c5898275b52c Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 10 Jul 2012 20:59:36 +0530 Subject: [PATCH 095/158] (minor) new mailing list --- README.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.txt b/README.txt index 61e4423..09e6dd2 100644 --- a/README.txt +++ b/README.txt @@ -343,8 +343,12 @@ CONTACT Author: sitaramc@gmail.com, sitaram@atc.tcs.com - Mailing list: gitolite@googlegroups.com - List subscribe address : gitolite+subscribe@googlegroups.com + Mailing lists: + gitolite@googlegroups.com -- general discussion + gitolite-announce@googlegroups.com -- announcements and notices only + List subscribe addresses: + gitolite+subscribe@googlegroups.com + gitolite-announce+subscribe@googlegroups.com IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 time zone). From fd0778e6d61876ed5ef83dfc07f0d795d6d767bd Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 10 Jul 2012 21:04:52 +0530 Subject: [PATCH 096/158] (minor) don't keep adding the same thing to $PATH --- src/lib/Gitolite/Rc.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 876760a..346e049 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -91,7 +91,7 @@ do $ENV{G3T_RC} if exists $ENV{G3T_RC} and -r $ENV{G3T_RC}; unshift @INC, "$rc{LOCAL_CODE}/lib" if $rc{LOCAL_CODE}; -$ENV{PATH} = "$ENV{GL_BINDIR}:$ENV{PATH}"; +$ENV{PATH} = "$ENV{GL_BINDIR}:$ENV{PATH}" unless $ENV{PATH} =~ /^$ENV{GL_BINDIR}:/; { $rc{GL_TID} = $ENV{GL_TID} ||= $$; From d3279e4ad03b928b5ee832447b46fa6851f2682e Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Wed, 11 Jul 2012 21:29:05 -0400 Subject: [PATCH 097/158] Fix a typo --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 09e6dd2..b5d0a18 100644 --- a/README.txt +++ b/README.txt @@ -184,7 +184,7 @@ ACCESS RULES * a permission of RW matches only a fast-forward push or create * a permission of RW+ matches any type of push - * a permission or '-' matches any type of push + * a permission of '-' matches any type of push Note 2: refex matching: (refex = optional regex to match the ref being pushed) From 8ad1eee2201c5337e1da3b79bc844dbb2817b7e1 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 17 Jul 2012 16:51:41 +0530 Subject: [PATCH 098/158] migrated 'who-pushed' command (manual smoke test only) --- src/commands/who-pushed | 57 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100755 src/commands/who-pushed diff --git a/src/commands/who-pushed b/src/commands/who-pushed new file mode 100755 index 0000000..5de7b9d --- /dev/null +++ b/src/commands/who-pushed @@ -0,0 +1,57 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Easy; + +=for usage +Usage: ssh git@host who-pushed + +Determine who pushed the given commit. The first few hex digits of the SHA +should suffice. + +Each line of the output contains the following fields: timestamp, a +transaction ID, username, refname, and the old and new SHAs for the ref. + +We assume the logfile names have been left as default, or if changed, in such +a way that they come up oldest first when sorted. + +The program searches ALL the log files, in reverse sorted order (i.e., newest +first). This means it could take a long time if your log directory is large +and contains lots of old log files. Patches to limit the search to an +optional date range are welcome. + +Note on the "transaction ID" field: if looking at the log file doesn't help +you figure out what its purpose is, please just ignore it. +=cut + +usage() if not @ARGV or @ARGV < 2 or $ARGV[0] eq '-h'; +usage() if $ARGV[1] !~ /^[0-9a-f]+$/i; + +my $repo = shift; +my $sha = shift; $sha =~ tr/A-F/a-f/; + +$ENV{GL_USER} and ( can_read($repo) or die "no read permissions on '$repo'" ); + +# ---------------------------------------------------------------------- + +my $repodir = "$ENV{GL_REPO_BASE}/$repo.git"; +chdir $repodir or die "repo '$repo' missing"; +(my $logdir = $ENV{GL_LOGFILE}) =~ s(/[^/]+$)(); + +for my $logfile ( reverse glob("$logdir/*") ) { + @ARGV = ($logfile); + for my $line ( reverse grep { m(\tupdate\t($repo|$repodir)\t) } <> ) { + chomp($line); + my @fields = split /\t/, $line; + my ($ts, $pid, $who, $ref, $d_old, $new) = @fields[ 0, 1, 4, 6, 7, 8]; + + # d_old is what you display + my $old = $d_old; + $old = "" if $d_old eq ("0" x 40); + $old = "$old.." if $old; + + system("git rev-list $old$new 2>/dev/null | grep ^$sha >/dev/null && echo '$ts $pid $who $ref $d_old $new'"); + } +} From f4eb6dcb5326418366fadc8db1bf60bb46ebabe8 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 18 Jul 2012 15:34:28 +0530 Subject: [PATCH 099/158] 'rsync' command to create and send bundles (manual smoke test only) run 'ssh git@host rsync -h' for usage, as usual --- src/commands/rsync | 149 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100755 src/commands/rsync diff --git a/src/commands/rsync b/src/commands/rsync new file mode 100755 index 0000000..87fb046 --- /dev/null +++ b/src/commands/rsync @@ -0,0 +1,149 @@ +#!/usr/bin/perl +use strict; +use warnings; + +use lib $ENV{GL_LIBDIR}; +use Gitolite::Easy; + +=for admins + +BUNDLE SUPPORT + + (1) For each repo in gitolite.conf for which you want bundle support (or + '@all', if you wish), add the following line: + + option bundle = 1 + + Or you can say: + + option bundle.ttl = + + A bundle file that is more than seconds old (default value + 86400, i.e., 1 day) is recreated on the next bundle request. Increase + this if your repo is not terribly active. + + Note: a bundle file is also deleted and recreated if it contains a ref + that was then either deleted or rewound in the repo. This is checked + on every invocation. + + (2) Add 'rsync' to the COMMANDS list in the rc file + + +GENERIC RSYNC SUPPORT + + TBD + +=cut + +=for usage +rsync helper for gitolite + +BUNDLE SUPPORT + + Admins: see src/commands/rsync for setup instructions + + Users: + rsync -P git@host:repo.bundle . + # downloads a file called ".bundle"; repeat as + # needed till the whole thing is downloaded + git clone repo.bundle repo + cd repo + git remote set-url origin git@host:repo + git fetch origin # and maybe git pull, etc. to freshen the clone + +GENERIC RSYNC SUPPORT + + TBD + +=cut + +usage() if not @ARGV or $ARGV[0] eq '-h'; + +# rsync driver program. Several things can be done later, but for now it +# drives just the 'bundle' transfer. + +if ( $ENV{SSH_ORIGINAL_COMMAND} =~ /^rsync --server --sender (-[-\w=.]+ )+\. (\S+)\.bundle$/ ) { + + my $repo = $2; + $repo =~ s/\.git$//; + + # all errors have the same message to avoid leaking info + can_read($repo) or _die "you are not authorised"; + my %config = config( $repo, "gitolite-options.bundle" ) or _die "you are not authorised"; + + my $ttl = $config{'gitolite-options.bundle.ttl'} || 86400; # in seconds (default 1 day) + + my $bundle = bundle_create( $repo, $ttl ); + + $ENV{SSH_ORIGINAL_COMMAND} =~ s( \S+\.bundle)( $bundle); + trace( 1, "rsync bundle", $ENV{SSH_ORIGINAL_COMMAND} ); + Gitolite::Common::_system( split ' ', $ENV{SSH_ORIGINAL_COMMAND} ); + exit 0; +} + +_warn "invalid rsync command '$ENV{SSH_ORIGINAL_COMMAND}'"; +usage(); + +# ---------------------------------------------------------------------- +# helpers +# ---------------------------------------------------------------------- + +sub bundle_create { + my ( $repo, $ttl ) = @_; + my $bundle = "$repo.bundle"; + $bundle =~ s(.*/)(); + my $recreate = 0; + + my ( %b, %r ); + if ( -f $bundle ) { + %b = map { chomp; reverse split; } `git ls-remote --heads --tags $bundle`; + %r = map { chomp; reverse split; } `git ls-remote --heads --tags .`; + + for my $ref ( sort keys %b ) { + + my $mtime = ( stat $bundle )[9]; + if ( time() - $mtime > $ttl ) { + trace( 1, "bundle too old" ); + $recreate++; + last; + } + + if ( not $r{$ref} ) { + trace( 1, "ref '$ref' deleted in repo" ); + $recreate++; + last; + } + + if ( $r{$ref} eq $b{$ref} ) { + # same on both sides; ignore + delete $r{$ref}; + delete $b{$ref}; + next; + } + + `git rev-list --count --left-right $b{$ref}...$r{$ref}` =~ /^(\d+)\s+(\d+)$/ or _die "git too old"; + if ($1) { + trace( 1, "ref '$ref' rewound in repo" ); + $recreate++; + last; + } + + } + + } else { + trace( 1, "no bundle found" ); + $recreate++; + } + + return $bundle if not $recreate; + + trace( 1, "creating bundle for '$repo'" ); + -f $bundle and ( unlink $bundle or die "a horrible death" ); + system("git bundle create $bundle --branches --tags >&2"); + + return $bundle; +} + +sub trace { + Gitolite::Common::trace(@_); +} From 57bea39a1e65d29ce43ee8d0c1fbcb9ff19c0a9b Mon Sep 17 00:00:00 2001 From: Patrick Westerhoff Date: Thu, 21 Jun 2012 23:52:22 +0200 Subject: [PATCH 100/158] Add special %GL_CREATOR variable for git-config Add a special variable `%GL_CREATOR` to the the git-config trigger that is replaced by the name of the repository creator (if any). This can be useful to set up the default owner configuration for wild repositories. Example: repo assignments/CREATOR/a[0-9][0-9] C = @students RW+ = CREATOR config gitweb.owner = %GL_CREATOR ---- committer added an if condition to the s/// line. --- src/triggers/post-compile/update-git-configs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/triggers/post-compile/update-git-configs b/src/triggers/post-compile/update-git-configs index 7069f6c..23458d2 100755 --- a/src/triggers/post-compile/update-git-configs +++ b/src/triggers/post-compile/update-git-configs @@ -43,12 +43,14 @@ for my $pr (@$lpr) { sub fixup_config { my $pr = shift; + my $creator = creator($pr); my $gc = git_config( $pr, '.', 1 ); while ( my ( $key, $value ) = each( %{$gc} ) ) { next if $key =~ /^gitolite-options\./; if ( $value ne "" ) { $value =~ s/%GL_REPO/$pr/g; + $value =~ s/%GL_CREATOR/$creator/g if $creator; system( "git", "config", "--file", "$RB/$pr.git/config", $key, $value ); } else { system( "git", "config", "--file", "$RB/$pr.git/config", "--unset-all", $key ); From b2a3509e63a834f8bff3f45de74fcd58baf2c6a5 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 27 Jul 2012 21:19:07 +0530 Subject: [PATCH 101/158] point people to mailing list for general questions --- README.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.txt b/README.txt index b5d0a18..e38b11a 100644 --- a/README.txt +++ b/README.txt @@ -341,14 +341,19 @@ GITWEB CONTACT ------- + NOTE: Unless you have very good reasons, please use the mailing list below + instead of mailing me personally. If you have to mail me, use the gmail + address instead of my work address. + Author: sitaramc@gmail.com, sitaram@atc.tcs.com - Mailing lists: - gitolite@googlegroups.com -- general discussion - gitolite-announce@googlegroups.com -- announcements and notices only - List subscribe addresses: - gitolite+subscribe@googlegroups.com - gitolite-announce+subscribe@googlegroups.com + Mailing list for questions and general discussion: + gitolite@googlegroups.com + subscribe address: gitolite+subscribe@googlegroups.com + + Mailing list for announcements and notices: + gitolite-announce@googlegroups.com + subscribe address: gitolite-announce+subscribe@googlegroups.com IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 time zone). From 31166e1e1c3113012d022f4029e60f721e273074 Mon Sep 17 00:00:00 2001 From: Nate Jones Date: Fri, 3 Aug 2012 13:46:43 -0700 Subject: [PATCH 102/158] find symlinked commands when generating help list --- src/commands/help | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/help b/src/commands/help index d7fae78..2165d5f 100755 --- a/src/commands/help +++ b/src/commands/help @@ -37,5 +37,5 @@ sub list_x { my $d = shift; return unless $d; _chdir "$d/commands"; - return map { $_ => $d } grep { -x $_ } map { chomp; s(^./)(); $_ } `find . -type f|sort`; + return map { $_ => $d } grep { -x $_ } map { chomp; s(^./)(); $_ } `find . -type f -o -type l|sort`; } From ba67f6f9ca2a9152b3687348d71feedcc58f3ce6 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 9 Aug 2012 18:02:00 +0200 Subject: [PATCH 103/158] Bailout tests unless envvar $GITOLITE_TEST is 'y' [committer made some changes to t/README] --- src/lib/Gitolite/Test.pm | 6 ++++++ t/README | 13 +++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/lib/Gitolite/Test.pm b/src/lib/Gitolite/Test.pm index e6e5a36..f42c463 100644 --- a/src/lib/Gitolite/Test.pm +++ b/src/lib/Gitolite/Test.pm @@ -37,6 +37,12 @@ use warnings; # ---------------------------------------------------------------------- +# make sure the user is ready for it +if (not $ENV{GITOLITE_TEST} or $ENV{GITOLITE_TEST} ne 'y') { + print "Bail out! See t/README for information on how to run the tests.\n"; + exit 255; +} + # required preamble for all tests try " DEF gsh = /TRACE: gsh.SOC=/ diff --git a/t/README b/t/README index c863b41..6a98e27 100644 --- a/t/README +++ b/t/README @@ -1,8 +1,13 @@ + +============================================ WARNING: THE TEST SUITE DELETES STUFF FIRST! +============================================ -Testing gitolite3 is now one command after the clone: +Please run the tests ONLY on a userid where it's ok to LOSE DATA. - prove +On such a userid, clone gitolite then run this command in the clone: -But because it starts by cleaning the slate, it's best to do it on a spare -userid that you are ok to lose data on. + GITOLITE_TEST=y prove + +http://sitaramc.github.com/gitolite/testing.html has more details. It will +also help you try out gitolite if you want to go beyond just the test suite. From 740963582301665bcf9ece47a4fb438beed35589 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 17 Aug 2012 10:04:32 +0530 Subject: [PATCH 104/158] (minor) add a 'dd' function to quickly dump stuff to STDERR --- src/lib/Gitolite/Common.pm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/Gitolite/Common.pm b/src/lib/Gitolite/Common.pm index 03008b3..b5c4b47 100644 --- a/src/lib/Gitolite/Common.pm +++ b/src/lib/Gitolite/Common.pm @@ -12,6 +12,8 @@ package Gitolite::Common; usage tsh_run gen_lfn gl_log + + dd ); #>>> use Exporter 'import'; @@ -63,6 +65,11 @@ sub dbg { } } +sub dd { + local $ENV{D} = 1; + dbg(@_); +} + sub _warn { gl_log( 'warn', @_ ); if ( $ENV{D} and $ENV{D} >= 3 ) { From cc9727c42bea266c19fca503f75b5b835382c676 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 17 Aug 2012 22:26:03 +0530 Subject: [PATCH 105/158] minor bug in include file handing... gitolite does indeed try to not load itself twice, but I forgot that by that time the pwd is ~/.gitolite/conf not ~/.gitolite so it always ended up reading itself twice in case of a wildcard include. --- src/lib/Gitolite/Conf/Explode.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Conf/Explode.pm b/src/lib/Gitolite/Conf/Explode.pm index 03f2cb2..ec78973 100644 --- a/src/lib/Gitolite/Conf/Explode.pm +++ b/src/lib/Gitolite/Conf/Explode.pm @@ -27,7 +27,7 @@ sub explode { my ( $file, $subconf, $out ) = @_; # seed the 'seen' list if it's empty - $included{ device_inode("conf/gitolite.conf") }++ unless %included; + $included{ device_inode("gitolite.conf") }++ unless %included; my $fh = _open( "<", $file ); while (<$fh>) { From ed4862ff968d9f33a1d423904d3419c072c598ea Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 27 Aug 2012 12:18:38 +0530 Subject: [PATCH 106/158] minor changes to README --- README.txt | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/README.txt b/README.txt index e38b11a..e170df9 100644 --- a/README.txt +++ b/README.txt @@ -6,18 +6,26 @@ file will not suffice; you *must* check the online docs (see below for URL). ------------------------------------------------------------------------ -DOCUMENTATION FOR GITOLITE -========================== +This file contains BASIC DOCUMENTATION ONLY. -This file contains basic documentation for a fresh, ssh-based, installation of -gitolite and basic usage of its most important features. + * It is suitable for a fresh, ssh-based, installation of gitolite and basic + usage of its most important features. -If you need more details on any of the topics covered here, or help with some -troubleshooting, or just wish to read about the advanced features not covered -here, please check the gitolite online documentation at: + * It is NOT meant to be exhaustive or detailed. + +The COMPLETE DOCUMENTATION is at: http://sitaramc.github.com/gitolite/master-toc.html +Please go there for what/why/how, concepts, background, troubleshooting, more +details on what is covered here, or advanced features not covered here. + +------------------------------------------------------------------------ + + +BASIC DOCUMENTATION FOR GITOLITE +================================ + This file contains the following sections: INSTALLATION AND SETUP From aec8c718908b77e9b3d745f927689b391c9e833f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 30 Aug 2012 18:40:24 +0530 Subject: [PATCH 107/158] 'help' command barfage fix should not barf if LOCAL_CODE is defined but it doesn't contain a "commands" subdirectory. --- src/commands/help | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/help b/src/commands/help index 2165d5f..23fa6ae 100755 --- a/src/commands/help +++ b/src/commands/help @@ -36,6 +36,7 @@ exit 0; sub list_x { my $d = shift; return unless $d; + return unless -d "$d/commands"; _chdir "$d/commands"; return map { $_ => $d } grep { -x $_ } map { chomp; s(^./)(); $_ } `find . -type f -o -type l|sort`; } From e59c3ba9f98abe27c6c34dbe6c31c87f54fabaef Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 19 Sep 2012 17:47:12 +0530 Subject: [PATCH 108/158] (minor docfix) add info on using Easy.pm from elsewhere --- src/lib/Gitolite/Easy.pm | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/lib/Gitolite/Easy.pm b/src/lib/Gitolite/Easy.pm index 9231d00..9e0ae0b 100644 --- a/src/lib/Gitolite/Easy.pm +++ b/src/lib/Gitolite/Easy.pm @@ -5,6 +5,25 @@ package Gitolite::Easy; # most/all functions in this module test $ENV{GL_USER}'s rights and # permissions so it needs to be set. +# "use"-ing this module +# ---------------------------------------------------------------------- +# Using this module from within a gitolite trigger or command is easy; you +# just need 'use lib $ENV{GL_LIBDIR};' before the 'use Gitolite::Easy;'. +# +# Using it from something completely outside gitolite requires a bit more +# work. First, run 'gitolite query-rc -a' to find the correct values for +# GL_BINDIR and GL_LIBDIR in your installation. Then use this code in your +# external program, using the paths you just found: +# +# BEGIN { +# $ENV{GL_BINDIR} = "/full/path/to/gitolite/src"; +# $ENV{GL_LIBDIR} = "/full/path/to/gitolite/src/lib"; +# } +# use lib $ENV{GL_LIBDIR}; +# use Gitolite::Easy; + +# API documentation +# ---------------------------------------------------------------------- # documentation for each function is at the top of the function. # Documentation is NOT in pod format; just read the source with a nice syntax # coloring text editor and you'll be happy enough. (I do not like POD; please From 724c741335acbcd6eb438ae5fad0bd1de56c9e3a Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 20 Sep 2012 06:21:44 +0530 Subject: [PATCH 109/158] prevent barfage when presetting the rc file --- src/lib/Gitolite/Rc.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 346e049..5d3b861 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -61,7 +61,7 @@ $UNSAFE_PATT = qr([`~#\$\&()|;<>]); my $current_data_version = "3.0"; my $rc = glrc('filename'); -if (-r $rc) { +if (-r $rc and -s $rc) { do $rc or die $@; } if ( defined($GL_ADMINDIR) ) { From 9606e35528d0f83ae8f64f4fffd785f1e443f715 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 19 Sep 2012 06:24:07 +0530 Subject: [PATCH 110/158] help cgit folks out a bit :) --- .../post-compile/update-description-file | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 src/triggers/post-compile/update-description-file diff --git a/src/triggers/post-compile/update-description-file b/src/triggers/post-compile/update-description-file new file mode 100755 index 0000000..7d00298 --- /dev/null +++ b/src/triggers/post-compile/update-description-file @@ -0,0 +1,17 @@ +#!/bin/bash + +# For normal (not "wild") repos, gitolite v3 sets 'gitweb.description' instead +# of putting the text in the "description" file. This is easier because it +# just goes with the flow of setting config variables; nothing special needs +# to be done for the description. + +# But this only works for gitweb, not for cgit. Cgit users must therefore add +# this line to the POST_COMPILE list in the rc file: +# 'post-compile/update-description-file', + +cd $GL_REPO_BASE +gitolite list-phy-repos | gitolite git-config % gitweb.description | + while read a b c + do + echo "$c" > $GL_REPO_BASE/$a.git/description + done From 3fe8ecf974de37e1e4202bdc924740013e10b32f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 25 Sep 2012 19:05:12 +0530 Subject: [PATCH 111/158] (minor) avoid spurious 'repo missing' messages for repo patterns --- src/lib/Gitolite/Conf/Load.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 70ec14a..b6991f8 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -211,7 +211,7 @@ sub load_1 { trace( 3, $repo ); if ( repo_missing($repo) ) { - trace( 1, "repo '$repo' missing" ); + trace( 1, "repo '$repo' missing" ) if $repo =~ $REPONAME_PATT; return; } _chdir("$rc{GL_REPO_BASE}/$repo.git"); From 6328ec2cbe55929b53c729bbf32b35908759f7e9 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 25 Sep 2012 05:07:05 +0530 Subject: [PATCH 112/158] dont auto-vivify empty entries in %repos... before this, trying to access a wild repo would create an empty hash in %repos. This is pretty harmless, but at some later point, memberships() would try to use that in a pattern, attempting to match the real repo being access-checked. Which is still fine if your repo doesn't look like "libstdc++" AND you're using some recent perl. However, for perl 5.8.8, and if the repo has a ++ in it, perl barfs. Here's a test program to check your perl: #!/usr/bin/perl $base="foo/u1/libstdc++"; $i="foo/u1/libstdc++"; if ( $base =~ /^$i$/ ) { print 1; } else { print 2; } On 5.14.2 I get "2". On 5.8.8 I get: Nested quantifiers in regex; marked by <-- HERE in m/^foo/u1/libstdc++ <-- HERE $/ at ./aa.pl line 6. --- src/lib/Gitolite/Conf/Load.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index b6991f8..dcc559c 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -255,7 +255,7 @@ sub load_1 { for my $r (@repos) { for my $u (@users) { - push @rules, @{ $repos{$r}{$u} } if exists $repos{$r}{$u}; + push @rules, @{ $repos{$r}{$u} } if exists $repos{$r} and exists $repos{$r}{$u}; } } From 2dbaa4d12ec66a9328ba30c1bdcbf2634b97ec1b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 26 Sep 2012 14:58:56 +0530 Subject: [PATCH 113/158] (minor) move a small chunk of code out of a loop --- src/lib/Gitolite/Conf/Store.pm | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index c77cac3..4d1c642 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -63,12 +63,20 @@ sub add_to_group { } sub set_repolist { - @repolist = @_; + @repolist = (); # ...sanity checks - for (@repolist) { + for (@_) { + if ( check_subconf_repo_disallowed( $subconf, $_ ) ) { + (my $repo = $_) =~ s/^\@$subconf\./locally modified \@/; + $ignored{$subconf}{$repo} = 1; + next; + } + _warn "explicit '.git' extension ignored for $_.git" if s/\.git$//; _die "bad reponame '$_'" if $_ !~ $REPOPATT_PATT; + + push @repolist, $_; } } @@ -103,13 +111,6 @@ sub add_rule { $nextseq++; for my $repo (@repolist) { - if ( check_subconf_repo_disallowed( $subconf, $repo ) ) { - my $repo = $repo; - $repo =~ s/^\@$subconf\./locally modified \@/; - $ignored{$subconf}{$repo} = 1; - next; - } - push @{ $repos{$repo}{$user} }, [ $nextseq, $perm, $ref ]; } } From 0d371ac957840ba8152d5fd11357cd850ffbd76c Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 4 Oct 2012 22:01:57 +0530 Subject: [PATCH 114/158] call GROUPLIST_PGM before determining user_roles()... thanks to Stephane Chazelas [1] [1]: https://groups.google.com/d/topic/gitolite/gy_ZkrxGSjg --- src/lib/Gitolite/Conf/Load.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index dcc559c..4abfa90 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -308,6 +308,8 @@ sub memberships { } } + push @ret, @{ ext_grouplist($base) } if $type eq 'user' and $rc{GROUPLIST_PGM}; + if ( $type eq 'user' and $repo and not repo_missing($repo) ) { # find the roles this user has when accessing this repo and add those # in as groupnames he is a member of. You need the already existing @@ -315,8 +317,6 @@ sub memberships { push @ret, user_roles( $base, $repo, @ret ); } - push @ret, @{ ext_grouplist($base) } if $type eq 'user' and $rc{GROUPLIST_PGM}; - @ret = @{ sort_u( \@ret ) }; trace( 3, sort @ret ); return @ret; From f636ce3ba3e340569b26d1e47b9d9b62dd8a3bf2 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 5 Oct 2012 07:19:59 +0530 Subject: [PATCH 115/158] (security) fix bug in pattern to detect path traversal while we're about it, add the same check to some of the internal routines, so that commands can also be protected. finally, just to make sure we don't lose it again in some other fashion, add a few tests for path traversal... --- src/gitolite-shell | 2 +- src/lib/Gitolite/Conf/Load.pm | 15 ++++++++++++++- t/0-me-first.t | 19 ++++++++++++++++++- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/gitolite-shell b/src/gitolite-shell index 5d48cc9..4bbae48 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -168,7 +168,7 @@ sub sanity { my $repo = shift; _die "'$repo' contains bad characters" if $repo !~ $REPONAME_PATT; _die "'$repo' ends with a '/'" if $repo =~ m(/$); - _die "'$repo' contains '..'" if $repo =~ m(\.\.$); + _die "'$repo' contains '..'" if $repo =~ m(\.\.); } # ---------------------------------------------------------------------- diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 4abfa90..0f76908 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -67,8 +67,9 @@ my $last_repo = ''; sub access { my ( $repo, $user, $aa, $ref ) = @_; - _die "invalid repo '$repo'" if not( $repo and $repo =~ $REPOPATT_PATT ); _die "invalid user '$user'" if not( $user and $user =~ $USERNAME_PATT ); + sanity($repo); + my $deny_rules = option( $repo, 'deny-rules' ); load($repo); @@ -175,8 +176,18 @@ sub option { return $ret->{$option}; } +sub sanity { + my $repo = shift; + + _die "invalid repo '$repo'" if not( $repo and $repo =~ $REPOPATT_PATT ); + _die "'$repo' ends with a '/'" if $repo =~ m(/$); + _die "'$repo' contains '..'" if $repo =~ $REPONAME_PATT and $repo =~ m(\.\.); +} + sub repo_missing { my $repo = shift; + sanity($repo); + return not -d "$rc{GL_REPO_BASE}/$repo.git"; } @@ -400,6 +411,8 @@ sub generic_name { sub creator { my $repo = shift; + sanity($repo); + return ( $ENV{GL_USER} || '' ) if repo_missing($repo); my $f = "$rc{GL_REPO_BASE}/$repo.git/gl-creator"; my $creator = ''; diff --git a/t/0-me-first.t b/t/0-me-first.t index dc8916b..22102ef 100755 --- a/t/0-me-first.t +++ b/t/0-me-first.t @@ -6,10 +6,12 @@ use warnings; use lib "src/lib"; use Gitolite::Test; +my $rb = `gitolite query-rc -n GL_REPO_BASE`; + # initial smoke tests # ---------------------------------------------------------------------- -try "plan 65"; +try "plan 73"; # basic push admin repo confreset;confadd ' @@ -75,4 +77,19 @@ try " 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: 'cc/bar/baz/\\.\\./frob' contains '\\.\\.'/ + + "; From 51ab768e2a121eac48fa82bb41ef121f44082e64 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 5 Oct 2012 14:42:25 +0530 Subject: [PATCH 116/158] v3.1 --- CHANGELOG | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index f743d19..5ec6cd9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,13 @@ +2012-10-05 v3.1 (security) fix path traversal on wild repos + + new %GL_CREATOR variable for git-config lines + + rsync command to create and send bundles automagically + + migrated 'who-pushed' + + logical expressions on refexes!!! + 2012-06-27 v3.04 documentation graduated and moved out of parents house :) new trigger for 'repo specific umask' From 896ada58c052243d59ca3221d5bfd66473959c01 Mon Sep 17 00:00:00 2001 From: "Eugene E. Kashpureff Jr" Date: Wed, 10 Oct 2012 07:59:52 +0000 Subject: [PATCH 117/158] Fix spurious error in triggers/upstream The initial fetch of a new repo which has 'upstream' read-only mirroring configured will cause a spurious error concerning FETCH_HEAD not yet existing. This silences the error. --- src/triggers/upstream | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/triggers/upstream b/src/triggers/upstream index b66ae87..7834778 100755 --- a/src/triggers/upstream +++ b/src/triggers/upstream @@ -11,7 +11,7 @@ cd $GL_REPO_BASE/$repo.git || exit 1 [ "$1" != "fetch" ] && { nice=$(gitolite git-config $repo gitolite-options.upstream.nice) - [ -n "$nice" ] && find FETCH_HEAD -mmin -$nice | grep . >/dev/null && exit 0 + [ -n "$nice" ] && find FETCH_HEAD -mmin -$nice 2>/dev/null | grep . >/dev/null && exit 0 } git fetch -q "$url" '+refs/*:refs/*' From 3eefc06551149882d7676cfb606542256e9e4392 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 10 Oct 2012 13:43:17 +0530 Subject: [PATCH 118/158] (minor) clarify that D only works on wild repos --- src/commands/D | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/D b/src/commands/D index 2d96964..a255073 100755 --- a/src/commands/D +++ b/src/commands/D @@ -18,7 +18,8 @@ # Usage: ssh git@host D # # The whimsically named "D" command deletes repos ("D" is a counterpart to the -# "C" permission which lets you create repos!) +# "C" permission which lets you create repos. Which also means that, just +# like "C", it only works for wild repos). # # There are two kinds of deletions: 'rm' removes a repo completely, while # 'trash' moves it to a trashcan which can be recovered later (upto a time From 4eb8cd4ad17f961b35c2be4381c30dfde582bc84 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 27 Oct 2012 07:07:30 +0530 Subject: [PATCH 119/158] (minor) bash -> sh changes in some non-core code /bin/bash is muscle memory for me, although it appears that not too much of the actual code is bash-specific, so it's reasonably easy to fix. --- src/VREF/COUNT | 5 ++--- src/VREF/FILETYPE | 3 +-- src/VREF/VOTES | 2 +- src/triggers/post-compile/update-description-file | 2 +- src/triggers/upstream | 2 +- 5 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/VREF/COUNT b/src/VREF/COUNT index 6b5cacf..f4c3eae 100755 --- a/src/VREF/COUNT +++ b/src/VREF/COUNT @@ -1,5 +1,4 @@ -#!/bin/bash -# TODO: convert to perl! +#!/bin/sh # gitolite VREF to count number of changed/new files in a push @@ -34,7 +33,7 @@ nf= # $oldsha when you update an old feature branch from master and then push it count=`git log --name-only $nf --format=%n $newtree --not --all | grep . | sort -u | perl -ne '}{print "$."'` -[[ $count -gt $max ]] && { +[ $count -gt $max ] && { # count has been exceeded. If $9 was NO_SIGNOFF there's still a chance # for redemption -- if the top commit has a proper signed-off by line [ "$9" = "NO_SIGNOFF" ] && { diff --git a/src/VREF/FILETYPE b/src/VREF/FILETYPE index 2115a5c..3f1d5f9 100755 --- a/src/VREF/FILETYPE +++ b/src/VREF/FILETYPE @@ -1,5 +1,4 @@ -#!/bin/bash -# TODO: convert to perl! +#!/bin/sh # gitolite VREF to find autogenerated files diff --git a/src/VREF/VOTES b/src/VREF/VOTES index bb6bf22..8dc3563 100755 --- a/src/VREF/VOTES +++ b/src/VREF/VOTES @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # gitolite VREF to count votes before allowing pushes to certain branches. diff --git a/src/triggers/post-compile/update-description-file b/src/triggers/post-compile/update-description-file index 7d00298..f8c2bd6 100755 --- a/src/triggers/post-compile/update-description-file +++ b/src/triggers/post-compile/update-description-file @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # For normal (not "wild") repos, gitolite v3 sets 'gitweb.description' instead # of putting the text in the "description" file. This is easier because it diff --git a/src/triggers/upstream b/src/triggers/upstream index 7834778..7c4981d 100755 --- a/src/triggers/upstream +++ b/src/triggers/upstream @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh # manage local, gitolite-controlled, copies of read-only upstream repos. From a802071a5e8880d47ced5b32231a28d3eb62a74f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 27 Oct 2012 13:20:55 +0530 Subject: [PATCH 120/158] (test suite) stop using 'ls' to test for presence/absence of files/directories another of those "duh! what was I thinking" moments, this specific one being "why test that files/directories are created with the right user and group IDs? Shouldn't that be out of your control, as well as totally unnecessary on a sane system?" --- t/0-me-first.t | 7 +++---- t/basic.t | 4 ++-- t/merge-check.t | 6 +++--- t/vrefs-1.t | 6 +++--- t/vrefs-2.t | 6 +++--- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/t/0-me-first.t b/t/0-me-first.t index 22102ef..47784ae 100755 --- a/t/0-me-first.t +++ b/t/0-me-first.t @@ -11,7 +11,7 @@ my $rb = `gitolite query-rc -n GL_REPO_BASE`; # initial smoke tests # ---------------------------------------------------------------------- -try "plan 73"; +try "plan 71"; # basic push admin repo confreset;confadd ' @@ -33,12 +33,11 @@ try " cd .. glt clone u1 file://aa u1aa; ok; /Cloning into 'u1aa'.../ /warning: You appear to have cloned an empty repository/ - ls -ald --time-style=long-iso u1aa; - ok; /drwxr-xr-x 3 $ENV{USER} $ENV{USER} \\d+ 201.-..-.. ..:.. u1aa/ + [ -d u1aa ]; ok # basic clone deny glt clone u4 file://aa u4aa; !ok; /R any aa u4 DENIED by fallthru/ - ls -ald u4aa; !ok; /ls: cannot access u4aa: No such file or directory/ + [ -d u4aa ]; !ok # basic push cd u1aa; ok diff --git a/t/basic.t b/t/basic.t index 3e8c3aa..4626f96 100755 --- a/t/basic.t +++ b/t/basic.t @@ -10,7 +10,7 @@ use Gitolite::Test; # ---------------------------------------------------------------------- try " - plan 218 + plan 217 CHECK_SETUP # subtest 1 @@ -77,7 +77,7 @@ try " /fatal: The remote end hung up unexpectedly/ CLONE u2 t1; ok; gsh /warning: You appear to have cloned an empty repository./ - ls -al t1; ok; /$ENV{USER}.*$ENV{USER}.*\.git/ + [ -d t1/.git ]; ok cd t1; ok; # push diff --git a/t/merge-check.t b/t/merge-check.t index 443a848..fdea318 100755 --- a/t/merge-check.t +++ b/t/merge-check.t @@ -9,7 +9,7 @@ use Gitolite::Test; # merge check -- the M flag # ---------------------------------------------------------------------- -try "plan 57"; +try "plan 55"; confreset;confadd ' repo foo @@ -25,7 +25,7 @@ try "ADMIN_PUSH set1; !/FATAL/" or die text(); try " cd .. - ls -al foo; !ok; /cannot access foo: No such file or directory/ + [ -d foo ]; !ok glt clone u1 file:///foo ok; /Cloning into/ /You appear to have cloned an empty/ @@ -33,7 +33,7 @@ try " try " cd foo; ok - ls -Al; ok; /\.git/ + [ -d .git ]; ok test-commit aa; ok; /1 file changed, 1 insertion/ tag start; ok glt push u1 origin master diff --git a/t/vrefs-1.t b/t/vrefs-1.t index bd5086b..eea4b24 100755 --- a/t/vrefs-1.t +++ b/t/vrefs-1.t @@ -9,7 +9,7 @@ use Gitolite::Test; # VREFs - part 1 # ---------------------------------------------------------------------- -try "plan 90"; +try "plan 88"; put "conf/gitolite.conf", " repo gitolite-admin @@ -32,11 +32,11 @@ put "conf/gitolite.conf", " try " ADMIN_PUSH vr1a cd .. - ls -al foo; !ok; /cannot access foo: No such file or directory/ + [ -d foo ]; !ok CLONE u1 foo; ok; /Cloning into/ /You appear to have cloned an empty/ cd foo; ok - ls -Al; ok; /\.git/ + [ -d .git ]; ok # VREF not called for u1 tc a1 a2 a3 a4 a5; ok; /aaf9e8e/ diff --git a/t/vrefs-2.t b/t/vrefs-2.t index 6c53341..40db308 100755 --- a/t/vrefs-2.t +++ b/t/vrefs-2.t @@ -9,7 +9,7 @@ use Gitolite::Test; # VREFs - part 2 # ---------------------------------------------------------------------- -try "plan 74"; +try "plan 72"; put "../gitolite-admin/conf/gitolite.conf", " \@gfoo = foo @@ -32,11 +32,11 @@ try " ADMIN_PUSH vr2a cd .. # setup - ls -al foo; !ok; /cannot access foo: No such file or directory/ + [ -d foo ]; !ok CLONE u1 foo; ok; /Cloning into/ /You appear to have cloned an empty/ cd foo; ok - ls -Al; ok; /\.git/ + [ -d .git ]; ok # u1 push 15 new files tc a b c d e f g h i j k l m n o From 2aa129bc7075254e24b5ced06a2bb11c137c0ba6 Mon Sep 17 00:00:00 2001 From: Andrew Page Date: Mon, 29 Oct 2012 17:15:52 -0600 Subject: [PATCH 121/158] fix for keysubdirs-as-groups sugar script to support "old style multi-keys" for users --- src/syntactic-sugar/keysubdirs-as-groups | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/syntactic-sugar/keysubdirs-as-groups b/src/syntactic-sugar/keysubdirs-as-groups index 69a69b1..0a3a9ae 100644 --- a/src/syntactic-sugar/keysubdirs-as-groups +++ b/src/syntactic-sugar/keysubdirs-as-groups @@ -20,7 +20,7 @@ sub groupnames { my @out = (); my %members = (); for my $pk (`find ../keydir/ -name "*.pub"`) { - next unless $pk =~ m(.*/([^/]+)/([^/]+)\.pub$); + next unless $pk =~ m(.*/([^/]+)/([^/]+?)(?:@[^./]+)?\.pub$); next if $1 eq 'keydir'; $members{$1} .= " $2"; } From 70ad045e08a663537b5652bc86ea779421cda62a Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 3 Oct 2012 19:14:47 +0530 Subject: [PATCH 122/158] (minor fixups to some non-code parts) --- README.txt | 18 +++++++----------- src/lib/Gitolite/Rc.pm | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/README.txt b/README.txt index e170df9..468062e 100644 --- a/README.txt +++ b/README.txt @@ -40,7 +40,7 @@ This file contains the following sections: GIT-DAEMON GITWEB - CONTACT + CONTACT AND SUPPORT LICENSE ------------------------------------------------------------------------ @@ -346,26 +346,22 @@ GITWEB ------------------------------------------------------------------------ -CONTACT -------- +CONTACT AND SUPPORT +------------------- - NOTE: Unless you have very good reasons, please use the mailing list below - instead of mailing me personally. If you have to mail me, use the gmail - address instead of my work address. - - Author: sitaramc@gmail.com, sitaram@atc.tcs.com - - Mailing list for questions and general discussion: + Mailing list for support and general discussion: gitolite@googlegroups.com subscribe address: gitolite+subscribe@googlegroups.com Mailing list for announcements and notices: - gitolite-announce@googlegroups.com subscribe address: gitolite-announce+subscribe@googlegroups.com IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 time zone). + Author: sitaramc@gmail.com, but please DO NOT use this for general support + questions. Subscribe to the list and ask there instead. + LICENSE ------- diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 5d3b861..58fc4db 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -425,7 +425,7 @@ __DATA__ ], # comment out or uncomment as needed - # these will run in sequence after a new wild repo is created + # these will run in sequence after a new repo is created POST_CREATE => [ 'post-compile/update-git-configs', From be61cd2d66da5729a7506e852262171ce1ea6ead Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 6 Nov 2012 06:19:13 +0530 Subject: [PATCH 123/158] make sure gl-perms exists, even if it is empty... I expect this to help if we optimise the rule generation by caching. --- src/commands/fork | 1 + src/lib/Gitolite/Conf/Store.pm | 2 +- t/fork.t | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/commands/fork b/src/commands/fork index 6cd6eea..1d68d64 100755 --- a/src/commands/fork +++ b/src/commands/fork @@ -48,6 +48,7 @@ echo "$from forked to $to" >&2 cd $GL_REPO_BASE/$to.git echo $GL_USER > gl-creator +touch gl-perms if gitolite query-rc -q DEFAULT_ROLE_PERMS then gitolite query-rc DEFAULT_ROLE_PERMS > gl-perms diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 4d1c642..8e2e6c8 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -191,7 +191,7 @@ sub new_wild_repo { trigger( 'PRE_CREATE', $repo, $user, $aa ); new_repo($repo); _print( "$repo.git/gl-creator", $user ); - _print( "$repo.git/gl-perms", "$rc{DEFAULT_ROLE_PERMS}\n" ) if $rc{DEFAULT_ROLE_PERMS}; + _print( "$repo.git/gl-perms", ( $rc{DEFAULT_ROLE_PERMS} ? "$rc{DEFAULT_ROLE_PERMS}\n" : "" ) ); trigger( 'POST_CREATE', $repo, $user, $aa ); _chdir( $rc{GL_ADMIN_BASE} ); diff --git a/t/fork.t b/t/fork.t index d595847..99d4a41 100755 --- a/t/fork.t +++ b/t/fork.t @@ -61,7 +61,8 @@ try " my $t; try "cd $rb; find . -name gl-perms"; $t = md5sum(sort (lines())); cmp $t, -'59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1a2.git/gl-perms +'d41d8cd98f00b204e9800998ecf8427e ./foo/u1/u1a.git/gl-perms +59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1a2.git/gl-perms 59b3a74b4d33c7631f08e75e7b60c7ce ./foo/u1/u1e.git/gl-perms '; From a509b208e340f11bb62a113dbdf089942b229db5 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 30 Oct 2012 12:09:16 +0530 Subject: [PATCH 124/158] move %GL_REPO and %GL_CREATOR substitution into core see usage example at the end of src/triggers/upstream --- src/lib/Gitolite/Conf/Load.pm | 8 ++++++ src/triggers/post-compile/update-git-configs | 2 -- src/triggers/upstream | 26 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 0f76908..27f3c95 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -164,6 +164,14 @@ sub git_config { } } + my($k, $v); + my $creator = creator($repo); + while (($k, $v) = each %ret) { + $v =~ s/%GL_REPO/$repo/g; + $v =~ s/%GL_CREATOR/$creator/g if $creator; + $ret{$k} = $v; + } + trace( 3, map { ( "$_" => "-> $ret{$_}" ) } ( sort keys %ret ) ); return \%ret; } diff --git a/src/triggers/post-compile/update-git-configs b/src/triggers/post-compile/update-git-configs index 23458d2..64b8ed9 100755 --- a/src/triggers/post-compile/update-git-configs +++ b/src/triggers/post-compile/update-git-configs @@ -49,8 +49,6 @@ sub fixup_config { while ( my ( $key, $value ) = each( %{$gc} ) ) { next if $key =~ /^gitolite-options\./; if ( $value ne "" ) { - $value =~ s/%GL_REPO/$pr/g; - $value =~ s/%GL_CREATOR/$creator/g if $creator; system( "git", "config", "--file", "$RB/$pr.git/config", $key, $value ); } else { system( "git", "config", "--file", "$RB/$pr.git/config", "--unset-all", $key ); diff --git a/src/triggers/upstream b/src/triggers/upstream index 7c4981d..c8e8c6d 100755 --- a/src/triggers/upstream +++ b/src/triggers/upstream @@ -44,3 +44,29 @@ git fetch -q "$url" '+refs/*:refs/*' # * if the upstream URL changes, just change the conf and push admin repo # * the 'nice' setting is in minutes and is optional; it is the minimum # elapsed time between 2 upstream fetches. + +# USAGE EXAMPLE: +# +# Let's say you want to keep a read-only local mirror of all your github repos +# on your local gitolite installation. Assuming your github usernames are the +# same as your local usernames, and you have updated GIT_CONFIG_KEYS in the rc +# file to allow 'config' lines, you can do this: +# +# repo github/CREATOR/..* +# C = @all +# R = @all +# option upstream.url = git://github.com/%GL_REPO.git +# option upstream.nice = 120 +# config url.git://github.com/.insteadOf = git://github.com/github/ +# +# Now you can make local, read-only, clones of all your github repos with +# +# git ls-remote gitolite:github/sitaramc/gitolite +# git ls-remote gitolite:github/sitaramc/hap +# (etc) +# +# and if milki were also a user on this gitolite instance, then +# +# git ls-remote gitolite:github/milki/xclip +# git ls-remote gitolite:github/milki/ircblogger +# (etc) From 8a9564f171e99d0546d93d5610129893197c796f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 8 Nov 2012 19:12:20 +0530 Subject: [PATCH 125/158] some minor rearrangements of code... why? now that would be telling! --- src/lib/Gitolite/Conf/Load.pm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 27f3c95..c696388 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -70,8 +70,12 @@ sub access { _die "invalid user '$user'" if not( $user and $user =~ $USERNAME_PATT ); sanity($repo); - my $deny_rules = option( $repo, 'deny-rules' ); + my @rules; + my $deny_rules; + load($repo); + @rules = rules( $repo, $user ); + $deny_rules = option( $repo, 'deny-rules' ); # sanity check the only piece the user can control _die "invalid characters in ref or filename: '$ref'\n" unless $ref =~ $REF_OR_FILENAME_PATT; @@ -89,7 +93,6 @@ sub access { return "$aa $ref $repo $user DENIED by existence"; } - my @rules = rules( $repo, $user ); trace( 2, scalar(@rules) . " rules found" ); for my $r (@rules) { my $perm = $r->[1]; @@ -304,9 +307,11 @@ sub load_1 { sub memberships { trace( 3, @_ ); my ( $type, $base, $repo ) = @_; + $repo ||= ''; + my @ret; my $base2 = ''; - my @ret = ( $base, '@all' ); + @ret = ( $base, '@all' ); if ( $type eq 'repo' ) { # first, if a repo, say, pub/sitaram/project, has a gl-creator file From d491b5384f572d5a4bedb12aac430dc770ea475f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 9 Nov 2012 17:54:04 +0530 Subject: [PATCH 126/158] (minor) add quick and dirty timer code to Common.pm --- src/lib/Gitolite/Common.pm | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/lib/Gitolite/Common.pm b/src/lib/Gitolite/Common.pm index b5c4b47..c93e6ef 100644 --- a/src/lib/Gitolite/Common.pm +++ b/src/lib/Gitolite/Common.pm @@ -14,6 +14,8 @@ package Gitolite::Common; gl_log dd + t_start + t_lap ); #>>> use Exporter 'import'; @@ -70,6 +72,21 @@ sub dd { dbg(@_); } +{ + use Time::HiRes; + my %start_times; + + sub t_start { + my $name = shift || 'default'; + $start_times{$name} = [ Time::HiRes::gettimeofday() ]; + } + + sub t_lap { + my $name = shift || 'default'; + return Time::HiRes::tv_interval( $start_times{$name} ); + } +} + sub _warn { gl_log( 'warn', @_ ); if ( $ENV{D} and $ENV{D} >= 3 ) { From c03d107bac810e663357e7d703a43f30ca0d376e Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 10 Nov 2012 14:09:26 +0530 Subject: [PATCH 127/158] help run some trigger programs in the background --- src/triggers/bg | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 src/triggers/bg diff --git a/src/triggers/bg b/src/triggers/bg new file mode 100755 index 0000000..3c66500 --- /dev/null +++ b/src/triggers/bg @@ -0,0 +1,17 @@ +#!/bin/bash + +# quick and dirty program to background any of the triggers programs that are +# taking too long. To use, just replace a line like +# 'post-compile/update-gitweb-access-list', +# with +# 'bg post-compile/update-gitweb-access-list', + +# We dump output to a file in the log directory but please keep in mind this +# is not a "log" so much as a redirection of the entire output. + +echo `date` $GL_TID "$0: $@" >> $GL_LOGFILE.bg + +path=${0%/*} +script=$path/$1; shift + +( ( $script "$@" < /dev/null >> $GL_LOGFILE.bg 2>&1 & ) ) From 16f2d9b879516e6268fe8f12f930318f6916a42c Mon Sep 17 00:00:00 2001 From: gitolite tester Date: Tue, 13 Nov 2012 06:51:14 +0530 Subject: [PATCH 128/158] gl-conf must be created even if the repo para has only config lines (i.e., no access rules but only config lines) --- src/lib/Gitolite/Conf/Store.pm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 8e2e6c8..252bf14 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -258,15 +258,18 @@ sub store_1 { # warning: writes and *deletes* it from %repos and %configs my ($repo) = shift; trace( 3, $repo ); - return unless $repos{$repo} and -d "$repo.git"; + return unless ( $repos{$repo} or $configs{$repo} ) and -d "$repo.git"; my ( %one_repo, %one_config ); open( my $compiled_fh, ">", "$repo.git/gl-conf" ) or return; - $one_repo{$repo} = $repos{$repo}; - delete $repos{$repo}; - my $dumped_data = Data::Dumper->Dump( [ \%one_repo ], [qw(*one_repo)] ); + my $dumped_data = ''; + if ($repos{$repo}) { + $one_repo{$repo} = $repos{$repo}; + delete $repos{$repo}; + $dumped_data = Data::Dumper->Dump( [ \%one_repo ], [qw(*one_repo)] ); + } if ( $configs{$repo} ) { $one_config{$repo} = $configs{$repo}; From 57760d7e1bbff68629e2489f84fdeb0ffe83ef7d Mon Sep 17 00:00:00 2001 From: gitolite tester Date: Mon, 12 Nov 2012 11:25:23 +0530 Subject: [PATCH 129/158] refex-expr: die when admin forgets to add the required line to the rc --- src/VREF/refex-expr | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/VREF/refex-expr b/src/VREF/refex-expr index 3ff4bf4..d0a51b7 100755 --- a/src/VREF/refex-expr +++ b/src/VREF/refex-expr @@ -3,6 +3,8 @@ use strict; use warnings; my $rule = $ARGV[7]; +die "\n\nFATAL: GL_REFEX_EXPR_ doesn't exist\n(your admin probably forgot the rc file change needed for this to work)\n\n" + unless exists $ENV{"GL_REFEX_EXPR_" . $rule}; my $res = $ENV{"GL_REFEX_EXPR_" . $rule} || 0; print "$ARGV[6] ($res)\n" if $res; From 1f96180df0bd6c2b4be6b4f9a06c1051da61974f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 13 Nov 2012 08:45:45 +0530 Subject: [PATCH 130/158] allow multi-line pubkeys; see code for doc --- src/triggers/post-compile/ssh-authkeys-split | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 src/triggers/post-compile/ssh-authkeys-split diff --git a/src/triggers/post-compile/ssh-authkeys-split b/src/triggers/post-compile/ssh-authkeys-split new file mode 100755 index 0000000..b6b0e15 --- /dev/null +++ b/src/triggers/post-compile/ssh-authkeys-split @@ -0,0 +1,59 @@ +#!/bin/bash + +# split multi-key files into separate keys like ssh-authkeys likes + +# WHY +# --- +# +# Yeah I wonder that too, when it's so much more maintainable to keep the damn +# keys as sitaram@home.pub and sitaram@work.pub or such. But there's no +# accounting for tastes, and some old fogies apparently want to put all of a +# user's keys into a single ".pub" file. + +# WARNINGS AND CAVEATS +# -------------------- +# +# - assumes no "@" sign in basenames of any multi-key files (single line file +# may still have them) +# - assumes you don't have a subdir in keydir called "__split_keys__" +# - God help you if you try to throw in a putty key in there. + +# SUPPORT +# ------- +# +# NONE. Mainly because I **know** someone will throw in a putty key. I just +# know it. + +# USAGE +# ----- +# +# add it to the POST_COMPILE trigger list in the rc file, but *before* the +# ssh-authkeys program entry. + +cd $GL_ADMIN_BASE/keydir + +rm -rf __split_keys__ +mkdir __split_keys__ +export SKD=$PWD/__split_keys__ + +find . -type f -name "*.pub" | while read k +do + # do we need to split? + lines=`wc -l < $k` + [ "$lines" = "1" ] && continue + + # is it sane to split? + base=`basename $k .pub` + echo $base | grep '@' >/dev/null && continue + + # ok do it + seq=1 + while read line + do + echo "$line" > $SKD/$base@$seq.pub + (( seq++ )) + done < $k + + # now delete the original file + rm $k +done From d3d93961a082c286d3f205d310c78079ebc3256f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 14 Nov 2012 15:12:30 +0530 Subject: [PATCH 131/158] Uggh; horrible inner loop screwing up all performance :-( This might actually make the redis version unnecessary for most people! And if it does, well shame on me for not instrumenting things at a more granular level before going all "oh we need a cache!" [In my defense, I blame redis for being such a sweet little tool that I felt compelled to use it somehow!] ---- t/sequence failed because the test itself was in error; fixed. --- src/lib/Gitolite/Conf/Load.pm | 7 +++++-- src/lib/Gitolite/Conf/Store.pm | 12 ++++++++++++ src/lib/Gitolite/Rc.pm | 2 +- t/sequence.t | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index c696388..9a09793 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -32,6 +32,7 @@ our $data_version = ''; our %repos; our %one_repo; our %groups; +our %patterns; our %configs; our %one_config; our %split_conf; @@ -326,8 +327,10 @@ sub memberships { } } - for my $i ( keys %groups ) { - if ( $base eq $i or $base =~ /^$i$/ or $base2 and ( $base2 eq $i or $base2 =~ /^$i$/ ) ) { + push @ret, @{ $groups{$base} } if exists $groups{$base}; + push @ret, @{ $groups{$base2} } if $base2 and exists $groups{$base2}; + for my $i ( keys %{ $patterns{groups} } ) { + if ( $base =~ /^$i$/ or $base2 and ( $base2 =~ /^$i$/ ) ) { push @ret, @{ $groups{$i} }; } } diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 252bf14..2a38a72 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -288,6 +288,8 @@ sub store_common { my $cc = "conf/gitolite.conf-compiled.pm"; my $compiled_fh = _open( ">", "$cc.new" ); + my %patterns = (); + my $data_version = glrc('current-data-version'); trace( 3, "data_version = $data_version" ); print $compiled_fh Data::Dumper->Dump( [$data_version], [qw(*data_version)] ); @@ -301,7 +303,17 @@ sub store_common { my %groups = %{ inside_out( \%groups ) }; $dumped_data = Data::Dumper->Dump( [ \%groups ], [qw(*groups)] ); print $compiled_fh $dumped_data; + + # save patterns in %groups for faster handling of multiple repos, such + # as happens in the various POST_COMPILE scripts + for my $k (keys %groups) { + $patterns{groups}{$k} = 1 unless $k =~ $REPONAME_PATT; + } } + + $dumped_data = Data::Dumper->Dump( [ \%patterns ], [qw(*patterns)] ) if %patterns; + print $compiled_fh $dumped_data; + print $compiled_fh Data::Dumper->Dump( [ \%split_conf ], [qw(*split_conf)] ) if %split_conf; close $compiled_fh or _die "close compiled-conf failed: $!\n"; diff --git a/src/lib/Gitolite/Rc.pm b/src/lib/Gitolite/Rc.pm index 58fc4db..9c2ae5b 100644 --- a/src/lib/Gitolite/Rc.pm +++ b/src/lib/Gitolite/Rc.pm @@ -58,7 +58,7 @@ $UNSAFE_PATT = qr([`~#\$\&()|;<>]); # find the rc file and 'do' it # ---------------------------------------------------------------------- -my $current_data_version = "3.0"; +my $current_data_version = "3.2"; my $rc = glrc('filename'); if (-r $rc and -s $rc) { diff --git a/t/sequence.t b/t/sequence.t index acccb0b..e98690b 100755 --- a/t/sequence.t +++ b/t/sequence.t @@ -55,7 +55,7 @@ try " confreset;confadd ' @staff = u1 u2 u3 - @gfoo = foo/CREATOR/.+ + @gfoo = foo/CREATOR/..* repo @gfoo C = u1 RW+ = CREATOR From 5f9789ed8ee519a5987e8fede7f3e65001f4f9c0 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 14 Nov 2012 15:36:04 +0530 Subject: [PATCH 132/158] v3.2 --- CHANGELOG | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5ec6cd9..91faaa5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,18 @@ +2012-11-14 v3.2 major efficiency boost for large setups + + optional support for multi-line pubkeys; see + src/triggers/post-compile/ssh-authkeys-split + + bug fix for not creating gl-conf when repo para has only + config lines and no access rules + + new 'bg' trigger command to put long jobs started from a + trigger into background + + %GL_REPO and %GL_CREATOR now work for 'option's also + + test suite now much more BSD friendly + 2012-10-05 v3.1 (security) fix path traversal on wild repos new %GL_CREATOR variable for git-config lines From a26532d6358cc8a617b36149600a2bf8d8717e8d Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 19 Nov 2012 07:48:21 +0530 Subject: [PATCH 133/158] allow simple macros in conf file --- src/syntactic-sugar/macros | 74 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/syntactic-sugar/macros diff --git a/src/syntactic-sugar/macros b/src/syntactic-sugar/macros new file mode 100644 index 0000000..1202dae --- /dev/null +++ b/src/syntactic-sugar/macros @@ -0,0 +1,74 @@ +# vim: syn=perl: + +# "sugar script" (syntactic sugar helper) for gitolite3 + +# simple line-wise macro processor +# ---------------------------------------------------------------------- +# see documentation at the end of this script + +my %macro; +sub sugar_script { + my $lines = shift; + my @out = (); + + my $l = join("\n", @$lines); + while ($l =~ s/^macro (\w+) (.*?)\nend//ms) { + $macro{$1} = $2; + } + + $l =~ s/^((\w+) .*)/$macro{$2} ? expand($1) : $1/gem; + + $lines = [split "\n", $l]; + return $lines; +} + +sub expand { + my $l = shift; + my ($word, @arg) = split ' ', $l; + my $v = $macro{$word}; + $v =~ s/%(\d+)/$arg[$1-1] or die "macro '$word' needs $1 arguments at '$l'\n"/gem; + return $v; +} + +__END__ + +Documentation is mostly by example. + +Setup: + + * the line + 'macros', + should be added to the SYNTACTIC_SUGAR list in ~/.gitolite.rc + +Notes on macro definition: + + * the keywords 'macro' and 'end' should start on a new line + * the first word after 'macro' is the name of the macro, and the rest, until + the 'end', is the body + +Notes on macro use: + + * the macro name should be the first word on a line + * the rest of the line is used as arguments to the macro + +Example: + + if your conf contains: + + macro foo repo aa-%1 + RW = u1 %2 + R = u2 + end + + foo 1 alice + foo 2 bob + + this will effectively turn into + + repo aa-1 + RW = u1 alice + R = u2 + + repo aa-2 + RW = u1 bob + R = u2 From 2018267a4527429dce41a542a806cdb76225b86f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Tue, 20 Nov 2012 06:32:53 +0530 Subject: [PATCH 134/158] (minor) fixes to lint program, mainly usage message --- src/commands/sshkeys-lint | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/commands/sshkeys-lint b/src/commands/sshkeys-lint index 2ff8e66..a981a13 100755 --- a/src/commands/sshkeys-lint +++ b/src/commands/sshkeys-lint @@ -73,7 +73,7 @@ for my $pkf (@pubkeyfiles) { my $fp = fprint($pkf); next unless $fp; msg 1, "$pkfsn appears to be a COPY of $pkf_by_fp{$fp}\n" if $pkf_by_fp{$fp}; - $pkf_by_fp{$fp} ||= $pkf; + $pkf_by_fp{$fp} ||= $pkfsn; my $fpu = ( $seen_fprints{$fp}{user} || 'no access' ); msg 0, "$pkfsn maps to $fpu\n"; } @@ -170,17 +170,20 @@ sub fprint { sub usage { print < Date: Wed, 21 Nov 2012 20:58:07 +0530 Subject: [PATCH 135/158] 'gitolite mirror' needs to set exit code on push failure --- src/commands/mirror | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/commands/mirror b/src/commands/mirror index 16c14dd..d091979 100755 --- a/src/commands/mirror +++ b/src/commands/mirror @@ -53,10 +53,11 @@ if ( $cmd eq 'push' ) { my $errors = 0; for (`git push --mirror $host:$repo 2>&1`) { + $errors = 1 if $?; print STDERR "$_" if -t STDERR or exists $ENV{GL_USER}; chomp; if (/FATAL/) { - $errors++; + $errors = 1; gl_log( 'mirror', $_ ); } else { trace( 1, "mirror: $_" ); From 7cec71b0eff40544882e56b6fbe080ce1b268e15 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 22 Nov 2012 15:59:13 +0530 Subject: [PATCH 136/158] minor fixups to some non-core programs (following a bit of a doc shakeup) --- src/lib/Gitolite/Triggers/Alias.pm | 0 src/lib/Gitolite/Triggers/CpuTime.pm | 3 +-- src/lib/Gitolite/Triggers/RepoUmask.pm | 2 ++ src/lib/Gitolite/Triggers/Shell.pm | 3 +++ 4 files changed, 6 insertions(+), 2 deletions(-) mode change 100755 => 100644 src/lib/Gitolite/Triggers/Alias.pm mode change 100755 => 100644 src/lib/Gitolite/Triggers/CpuTime.pm diff --git a/src/lib/Gitolite/Triggers/Alias.pm b/src/lib/Gitolite/Triggers/Alias.pm old mode 100755 new mode 100644 diff --git a/src/lib/Gitolite/Triggers/CpuTime.pm b/src/lib/Gitolite/Triggers/CpuTime.pm old mode 100755 new mode 100644 index 552bf40..74b4217 --- a/src/lib/Gitolite/Triggers/CpuTime.pm +++ b/src/lib/Gitolite/Triggers/CpuTime.pm @@ -10,6 +10,7 @@ use warnings; # cpu and elapsed times for gitolite+git operations # ---------------------------------------------------------------------- +# uncomment the appropriate lines in the rc file to enable this # Ideally, you will (a) write your own code with a different filename so later # gitolite upgrades won't overwrite your copy, (b) add appropriate variables @@ -18,8 +19,6 @@ use warnings; # ---------------------------------------------------------------------- my $start_time; -# this trigger is not yet documented; it gets called at the start and does not -# receive any arguments. sub input { _warn "something wrong with the invocation of CpuTime::input" if $ENV{GL_TID} ne $$; $start_time = [ Time::HiRes::gettimeofday() ]; diff --git a/src/lib/Gitolite/Triggers/RepoUmask.pm b/src/lib/Gitolite/Triggers/RepoUmask.pm index b0a9ad1..ea675e2 100644 --- a/src/lib/Gitolite/Triggers/RepoUmask.pm +++ b/src/lib/Gitolite/Triggers/RepoUmask.pm @@ -9,6 +9,8 @@ use warnings; # setting a repo specific umask # ---------------------------------------------------------------------- +# this is for people who are too paranoid to trust e.g., gitweb's repo +# exclusion logic, but not paranoid enough to put it on a different server =for usage diff --git a/src/lib/Gitolite/Triggers/Shell.pm b/src/lib/Gitolite/Triggers/Shell.pm index 0e6f0a1..b6e24c3 100644 --- a/src/lib/Gitolite/Triggers/Shell.pm +++ b/src/lib/Gitolite/Triggers/Shell.pm @@ -3,6 +3,9 @@ package Gitolite::Triggers::Shell; # usage notes: this module must be loaded first in the INPUT trigger list. Or # at least before Mirroring::input anyway. +# documentation is in the ssh troubleshooting and tips document, under the +# section "giving shell access to gitolite users" + use Gitolite::Rc; use Gitolite::Common; From 96be9503ef1a59dcb42fbb958e4c1d7e229c7c5e Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski Date: Thu, 22 Nov 2012 11:57:18 +0100 Subject: [PATCH 137/158] sudo command: CLI fix: 2 non-empty args required --- src/commands/sudo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/sudo b/src/commands/sudo index ac2bb54..eeb0083 100755 --- a/src/commands/sudo +++ b/src/commands/sudo @@ -7,7 +7,7 @@ die() { echo "$@" >&2; exit 1; } usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } -[ -z "$1" ] && usage +[ -z "$2" ] && usage [ "$1" = "-h" ] && usage [ -z "$GL_USER" ] && die GL_USER not set From 96cc2eaf41aa9c313e56cfb3ddf25899cfa08f53 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 22 Nov 2012 19:53:15 +0530 Subject: [PATCH 138/158] new features relating to creating wild repos: - new 'create' command for explicit creation - new 'AutoCreate' trigger to prevent auto-creation on read operations or both read and write operations - a few related fixups to the perms command --- src/commands/create | 15 +++++++++++++++ src/commands/perms | 20 +++++++++++--------- src/lib/Gitolite/Triggers/AutoCreate.pm | 24 ++++++++++++++++++++++++ t/sequence.t | 2 +- 4 files changed, 51 insertions(+), 10 deletions(-) create mode 100755 src/commands/create create mode 100644 src/lib/Gitolite/Triggers/AutoCreate.pm diff --git a/src/commands/create b/src/commands/create new file mode 100755 index 0000000..adac0e3 --- /dev/null +++ b/src/commands/create @@ -0,0 +1,15 @@ +#!/bin/bash + +# Usage: ssh git@host create +# +# Create wild repo. + +die() { echo "$@" >&2; exit 1; } +usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } +[ -z "$1" ] && usage +[ -z "$2" ] || usage +[ "$1" = "-h" ] && usage +[ -z "$GL_USER" ] && die GL_USER not set + +# ---------------------------------------------------------------------- +exec $GL_BINDIR/commands/perms -c "$@" < /dev/null diff --git a/src/commands/perms b/src/commands/perms index 46c4e97..6b61596 100755 --- a/src/commands/perms +++ b/src/commands/perms @@ -46,18 +46,20 @@ if ( $ARGV[0] eq '-l' ) { # auto-create the repo if -c passed and repo doesn't exist if ( $ARGV[0] eq '-c' ) { shift; - my $repo = $ARGV[0]; + my $repo = $ARGV[0] or usage(); _die "invalid repo '$repo'" unless $repo =~ $REPONAME_PATT; - if (not -d "$rc{GL_REPO_BASE}/$repo.git") { - my $ret = access( $repo, $ENV{GL_USER}, '^C', 'any' ); - _die $ret if $ret =~ /DENIED/; + my $d = "$rc{GL_REPO_BASE}/$repo.git"; + my $errmsg = "repo already exists or you are not authorised to create it"; + # use the same message in both places to prevent leaking repo existence info + _die $errmsg if -d $d; + my $ret = access( $repo, $ENV{GL_USER}, '^C', 'any' ); + _die $errmsg if $ret =~ /DENIED/; - require Gitolite::Conf::Store; - Gitolite::Conf::Store->import; - new_wild_repo( $repo, $ENV{GL_USER}, 'perms-c' ); - gl_log( 'create', $repo, $ENV{GL_USER}, 'perms-c' ); - } + require Gitolite::Conf::Store; + Gitolite::Conf::Store->import; + new_wild_repo( $repo, $ENV{GL_USER}, 'perms-c' ); + gl_log( 'create', $repo, $ENV{GL_USER}, 'perms-c' ); } my $repo = shift; diff --git a/src/lib/Gitolite/Triggers/AutoCreate.pm b/src/lib/Gitolite/Triggers/AutoCreate.pm new file mode 100644 index 0000000..8fe46d7 --- /dev/null +++ b/src/lib/Gitolite/Triggers/AutoCreate.pm @@ -0,0 +1,24 @@ +package Gitolite::Triggers::AutoCreate; + +use strict; +use warnings; + +# perl trigger set for stuff to do with auto-creating repos +# ---------------------------------------------------------------------- + +# to deny auto-create on read access, add 'AutoCreate::deny_R' to the +# PRE_CREATE trigger list +sub deny_R { + die "autocreate denied\n" if $_[3] and $_[3] eq 'R'; + return; +} + +# to deny auto-create on read *and* write access, add 'AutoCreate::deny_RW' to +# the PRE_CREATE trigger list. This means you can only create repos using the +# 'create' command, (which needs to be enabled in the COMMANDS list). +sub deny_RW { + die "autocreate denied\n" if $_[3] and ( $_[3] eq 'R' or $_[3] eq 'W' ); + return; +} + +1; diff --git a/t/sequence.t b/t/sequence.t index e98690b..a42b6b6 100755 --- a/t/sequence.t +++ b/t/sequence.t @@ -100,7 +100,7 @@ try " # 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: .C any foo/u4/baz u4 DENIED by fallthru/ + /FATAL: repo already exists or you are not authorised to create it/ # auto-create using perms echo READERS u2 | glt perms u1 -c foo/u1/baz From d2214b06b5f48af10dd2321e5e5b4bb926e43bfa Mon Sep 17 00:00:00 2001 From: Stephen Palmer Date: Thu, 15 Nov 2012 17:35:47 +0000 Subject: [PATCH 139/158] Fixed bug in lock script the unlock command was not checking the correct hash key to match the user name --- src/commands/lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/lock b/src/commands/lock index f95af6c..a9e9073 100755 --- a/src/commands/lock +++ b/src/commands/lock @@ -71,7 +71,7 @@ sub f_unlock { my ( $repo, $file ) = @_; my %locks = get_locks(); - _die "'$file' not locked by '$ENV{GL_USER}'" if ( $locks{$file} || '' ) ne $ENV{GL_USER}; + _die "'$file' not locked by '$ENV{GL_USER}'" if ( $locks{$file}{USER} || '' ) ne $ENV{GL_USER}; delete $locks{$file}; put_locks(%locks); } From 72e36f32aa5c46c33e9205f47a54672fba672586 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 28 Nov 2012 05:49:48 +0530 Subject: [PATCH 140/158] oops; hashes were getting printed twice in certain cases... harmless but wasteful --- src/lib/Gitolite/Conf/Store.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 2a38a72..9090999 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -311,8 +311,7 @@ sub store_common { } } - $dumped_data = Data::Dumper->Dump( [ \%patterns ], [qw(*patterns)] ) if %patterns; - print $compiled_fh $dumped_data; + print $compiled_fh Data::Dumper->Dump( [ \%patterns ], [qw(*patterns)] ) if %patterns; print $compiled_fh Data::Dumper->Dump( [ \%split_conf ], [qw(*split_conf)] ) if %split_conf; From b6d6260dbb8f7881f9d1a312fc26aa0e3f7d69de Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 28 Nov 2012 06:22:55 +0530 Subject: [PATCH 141/158] prevent empty %groups being created in compiled conf this would happen if @all was used but no actual groups were defined, and would in turn cause a parse error on the compiled conf because it now ends with a 'false'. thanks to Jelle Raaijmakers --- src/lib/Gitolite/Conf/Store.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Conf/Store.pm b/src/lib/Gitolite/Conf/Store.pm index 9090999..1d6d8e2 100644 --- a/src/lib/Gitolite/Conf/Store.pm +++ b/src/lib/Gitolite/Conf/Store.pm @@ -156,7 +156,7 @@ sub new_repos { # normal repos my @repos = grep { $_ =~ $REPONAME_PATT and not /^@/ } sort keys %repos; # add in members of repo groups - map { push @repos, keys %{ $groups{$_} } } grep { /^@/ } keys %repos; + map { push @repos, keys %{ $groups{$_} } } grep { /^@/ and $_ ne '@all' } keys %repos; for my $repo ( @{ sort_u( \@repos ) } ) { next unless $repo =~ $REPONAME_PATT; # skip repo patterns From 2741fadc9d2538eeafa12cc8b91f2e19b9b05b1a Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 22 Nov 2012 20:22:35 +0530 Subject: [PATCH 142/158] a few minor changes * minor typos * perltidy on Tsh * a minor optimisation to "do" in gl-conf * remove inapplicable caveat in fork command --- README.txt | 2 +- src/commands/fork | 4 ---- src/lib/Gitolite/Conf/Load.pm | 2 +- src/lib/Gitolite/Test/Tsh.pm | 11 ++++++++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/README.txt b/README.txt index 468062e..08fed1c 100644 --- a/README.txt +++ b/README.txt @@ -219,7 +219,7 @@ ACCESS RULES GROUPS ------ - Gitolite allows you to groups users or repos for convenience. Here's an + Gitolite allows you to group users or repos for convenience. Here's an example that creates two groups of users: @staff = alice bob carol diff --git a/src/commands/fork b/src/commands/fork index 1d68d64..b381662 100755 --- a/src/commands/fork +++ b/src/commands/fork @@ -10,10 +10,6 @@ # traffic but because it uses git clone's "-l" option to share the object # store also, so it is likely to be almost instantaneous, regardless of how # big the repo actually is. -# -# The only caveat is that the repo you cloned *from* must not later become -# unavailable in any way. If you cannot be sure of this, take the scenic -# route (clone repo1, push to repo2). die() { echo "$@" >&2; exit 1; } usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 9a09793..00a6b8a 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -248,7 +248,7 @@ sub load_1 { if ( -f "gl-conf" ) { _warn "split conf not set, gl-conf present for '$repo'" if not $split_conf{$repo}; - my $cc = "gl-conf"; + my $cc = "./gl-conf"; _die "parse '$cc' failed: " . ( $! or $@ ) unless do $cc; $last_repo = $repo; diff --git a/src/lib/Gitolite/Test/Tsh.pm b/src/lib/Gitolite/Test/Tsh.pm index 2b7dcee..b3c43e0 100644 --- a/src/lib/Gitolite/Test/Tsh.pm +++ b/src/lib/Gitolite/Test/Tsh.pm @@ -261,7 +261,12 @@ sub rc_lines { $cmd = shift @cmds; # is the current command a "testing" command? - my $testing_cmd = ( $cmd =~ m(^ok(?:\s+or\s+(.*))?$) or $cmd =~ m(^!ok(?:\s+or\s+(.*))?$) or $cmd =~ m(^/(.*?)/(?:\s+or\s+(.*))?$) or $cmd =~ m(^!/(.*?)/(?:\s+or\s+(.*))?$) ); + my $testing_cmd = ( + $cmd =~ m(^ok(?:\s+or\s+(.*))?$) + or $cmd =~ m(^!ok(?:\s+or\s+(.*))?$) + or $cmd =~ m(^/(.*?)/(?:\s+or\s+(.*))?$) + or $cmd =~ m(^!/(.*?)/(?:\s+or\s+(.*))?$) + ); # warn if the previous command failed but rc is not being checked if ( $rc and not $testing_cmd ) { @@ -474,7 +479,7 @@ sub fail { sub cmp { # compare input string with second input string or text() - my $in = shift; + my $in = shift; my $text = ( @_ ? +shift : text() ); if ( $text eq $in ) { @@ -583,7 +588,7 @@ sub dummy_commits { test_tick(); next; } - my $ts = ( $tick ? gmtime($tick+19800) : gmtime() ); + my $ts = ( $tick ? gmtime( $tick + 19800 ) : gmtime() ); _sh("echo $f at $ts >> $f && git add $f && git commit -m '$f at $ts'"); } } From f1c69a3ec0bea287103232d2b2298c7ed51f336f Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 5 Dec 2012 05:54:38 +0530 Subject: [PATCH 143/158] bugfix: don't delete description file when running perms thanks to drue on #gitolite for catching it --- src/triggers/post-compile/update-gitweb-access-list | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/triggers/post-compile/update-gitweb-access-list b/src/triggers/post-compile/update-gitweb-access-list index d986fb3..11e1aa6 100755 --- a/src/triggers/post-compile/update-gitweb-access-list +++ b/src/triggers/post-compile/update-gitweb-access-list @@ -6,8 +6,10 @@ # ---------------------------------------------------------------------- # delete the 'description' file that 'git init' created if this is run from -# the post-create trigger -[ "$1" = "POST_CREATE" ] && rm -f $GL_REPO_BASE/$2.git/description 2>/dev/null +# the post-create trigger. However, note that POST_CREATE is also called from +# perms (since POST_CREATE doubles as eqvt of POST_COMPILE to propagate ad hoc +# permissions changes for wild repos) and then you should not delete it. +[ "$1" = "POST_CREATE" ] && [ "$4" != "perms" ] && rm -f $GL_REPO_BASE/$2.git/description 2>/dev/null # ---------------------------------------------------------------------- # skip if arg-1 is POST_CREATE and no arg-3 (user name) exists; this means From fc7ddfc818498cf8c97fe1f12e61fb8209061427 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 7 Dec 2012 17:30:56 +0530 Subject: [PATCH 144/158] (minor) lint had syntax errors thanks to xcat on #gitolite for catching it (shows you how often it gets used I guess!) --- src/commands/sshkeys-lint | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/sshkeys-lint b/src/commands/sshkeys-lint index a981a13..5626a27 100755 --- a/src/commands/sshkeys-lint +++ b/src/commands/sshkeys-lint @@ -177,9 +177,9 @@ Look for potential problems in ssh keys. sshkeys-lint expects: - the contents of an authorized_keys file via STDIN, otherwise it uses - $HOME/.ssh/authorized_keys + \$HOME/.ssh/authorized_keys - one or more pubkey filenames as arguments, otherwise it uses all the keys - found (recursively) in $HOME/.gitolite/keydir + found (recursively) in \$HOME/.gitolite/keydir The '-q' option will print only warnings instead of all mappings. From f89408adb12a853f02e6f03787242e3d6cebd13c Mon Sep 17 00:00:00 2001 From: Sven Strickroth Date: Sun, 9 Dec 2012 03:31:45 +0100 Subject: [PATCH 145/158] Set Content-Type to text/plain for gitolite commands over http Explicitly set "Content-Type: text/plain" for gitolite commands when issued over http, so that it is possible to see the output with normal browsers. (At least) Apache httpd might set the Content-Type to something different and triggers a download instead of showing the text directly. Signed-off-by: Sven Strickroth --- src/gitolite-shell | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gitolite-shell b/src/gitolite-shell index 4bbae48..a3ec321 100755 --- a/src/gitolite-shell +++ b/src/gitolite-shell @@ -234,5 +234,6 @@ sub http_print_headers { print "Expires: Fri, 01 Jan 1980 00:00:00 GMT\r\n"; print "Pragma: no-cache\r\n"; print "Cache-Control: no-cache, max-age=0, must-revalidate\r\n"; + print "Content-Type: text/plain\r\n"; print "\r\n"; } From 3103d68a75473383d791e8c8d7ce446168ac4c7d Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 13 Dec 2012 19:30:12 +0530 Subject: [PATCH 146/158] new trigger: update-gitweb-daemon-from-options another way to update gitweb and daemon access lists --- .../update-gitweb-daemon-from-options | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100755 src/triggers/post-compile/update-gitweb-daemon-from-options diff --git a/src/triggers/post-compile/update-gitweb-daemon-from-options b/src/triggers/post-compile/update-gitweb-daemon-from-options new file mode 100755 index 0000000..a3627c9 --- /dev/null +++ b/src/triggers/post-compile/update-gitweb-daemon-from-options @@ -0,0 +1,57 @@ +#!/bin/sh + +# Update git-daemon and gitweb access using 'option' lines instead of special +# usernames. + +# To use: + +# * enable this combined updater in the rc file by removing the other two +# update-*-access-list entries and inserting this one instead. (This would +# be in the POST_CREATE and POST_COMPILE lists). + +# * the add option lines in the conf file, like this: +# +# repo foo @bar +# option daemon = 1 +# option gitweb = 1 + +# Note: don't forget that gitweb can also be enabled by actual config +# variables (gitweb.owner, gitweb.description, gitweb.category) + +# This is useful for people who don't like '@all' to be literally *all* users, +# including gitweb and daemon, and can't/won't use deny-rules properly. + +# ---------------------------------------------------------------------- +# skip if arg-1 is POST_CREATE and no arg-3 (user name) exists; this means +# it's been triggered by a *normal* (not "wild") repo creation, which in turn +# means a POST_COMPILE should be following so there's no need to waste time +# running this once for each new repo +[ "$1" = "POST_CREATE" ] && [ -z "$3" ] && exit 0; + +# first do the gitweb stuff + +plf=`gitolite query-rc GITWEB_PROJECTS_LIST` +[ -z "$plf" ] && plf=$HOME/projects.list + +( + gitolite list-phy-repos | gitolite git-config % gitolite-options.gitweb + gitolite list-phy-repos | gitolite git-config -r % gitweb\\. +) | + cut -f1 | sort -u | sed -e 's/$/.git/' > $plf + +# now deal with git-daemon + +EO=git-daemon-export-ok +RB=`gitolite query-rc GL_REPO_BASE` +export EO RB + +export tmp=$(mktemp -d) +trap "rm -rf $tmp" 0 + +gitolite list-phy-repos | sort | tee $tmp/all | gitolite git-config % gitolite-options.daemon | cut -f1 > $tmp/daemon + +comm -23 $tmp/all $tmp/daemon | perl -lne 'unlink "$ENV{RB}/$_.git/$ENV{EO}"' +cat $tmp/daemon | while read repo +do + > $RB/$repo.git/$EO +done From 8e3ee2f9c11bcce2bdc85fd31453f4b5ab6a022b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Thu, 13 Dec 2012 20:15:17 +0530 Subject: [PATCH 147/158] (minor) macro buglets - allow parameter-less macros - allow macro body to start on next line --- src/syntactic-sugar/macros | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/syntactic-sugar/macros b/src/syntactic-sugar/macros index 1202dae..2dbb5fd 100644 --- a/src/syntactic-sugar/macros +++ b/src/syntactic-sugar/macros @@ -12,11 +12,11 @@ sub sugar_script { my @out = (); my $l = join("\n", @$lines); - while ($l =~ s/^macro (\w+) (.*?)\nend//ms) { + while ($l =~ s/^macro (\w+)\b(.*?)\nend//ms) { $macro{$1} = $2; } - $l =~ s/^((\w+) .*)/$macro{$2} ? expand($1) : $1/gem; + $l =~ s/^((\w+)\b.*)/$macro{$2} ? expand($1) : $1/gem; $lines = [split "\n", $l]; return $lines; From 20484845786fedc48ea3b78f0b9375a346485d94 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 14 Dec 2012 07:28:58 +0530 Subject: [PATCH 148/158] add more detail to error message this error normally happens due to some permission issue on the log file, but we weren't printing the actual cause, so it was confusing --- src/lib/Gitolite/Common.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Common.pm b/src/lib/Gitolite/Common.pm index c93e6ef..f7171ff 100644 --- a/src/lib/Gitolite/Common.pm +++ b/src/lib/Gitolite/Common.pm @@ -277,7 +277,7 @@ sub gl_log { my $fh; logger_plus_stderr( "errors found before logging could be setup", "$msg" ) if not $ENV{GL_LOGFILE}; open my $lfh, ">>", $ENV{GL_LOGFILE} - or logger_plus_stderr( "errors found before logfile could be created", "$msg" ); + or logger_plus_stderr( "errors found but logfile could not be created", "$ENV{GL_LOGFILE}: $!", "$msg" ); print $lfh "$ts\t$tid\t$msg\n"; close $lfh; } From 4f4658274dd84595d23b2d0fd16eba6927239a34 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 14 Dec 2012 07:29:20 +0530 Subject: [PATCH 149/158] CREATOR need only be a "word" in wild repo patterns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this was a v2 compat breakage, caught by Dominik Schäfer (schaedpq at gmail) --- src/lib/Gitolite/Conf/Load.pm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 00a6b8a..2611630 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -418,8 +418,7 @@ sub generic_name { $creator = creator($base); $base2 = $base; - $base2 =~ s(/$creator/)(/CREATOR/) if $creator; - $base2 =~ s(^$creator/)(CREATOR/) if $creator; + $base2 =~ s(\b$creator\b)(CREATOR) if $creator; $base2 = '' if $base2 eq $base; # if there was no change return $base2; From 3513f4a153a2ec9c5216ef11c84668107c4e409e Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 19 Dec 2012 06:09:03 +0530 Subject: [PATCH 150/158] fix bug in list-dangling-repos Still, I would advise caution if you use this as a basis for deleting repos from the file system. A bug in this program could cause you to lose important data! --- src/commands/list-dangling-repos | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/commands/list-dangling-repos b/src/commands/list-dangling-repos index 6889ed9..ea36bab 100755 --- a/src/commands/list-dangling-repos +++ b/src/commands/list-dangling-repos @@ -12,6 +12,9 @@ List all existing repos that no one can access remotely any more. They could be normal repos that were taken out of "repo" statements in the conf file, or wildcard repos whose matching "wild" pattern was taken out or changed so it no longer matches. + +I would advise caution if you use this as a basis for deleting repos from the +file system. A bug in this program could cause you to lose important data! =cut usage() if @ARGV and $ARGV[0] eq '-h'; @@ -21,6 +24,9 @@ usage() if @ARGV and $ARGV[0] eq '-h'; # is to cull %phy_repos of all keys that have a matching key in %repos, where # "matching" means "string equal" or "regex match". my %repos = map { chomp; $_ => 1 } `gitolite list-repos`; +for my $r ( grep /^@/, keys %repos ) { + map { chomp; $repos{$_} = 1; } `gitolite list-members $r`; +} my %phy_repos = map { chomp; $_ => 1 } `gitolite list-phy-repos`; # Remove exact matches. But for repo names like "gtk+", you could have From b9bbb78278c12d9468d8c50b61ca27e6d6fa0c5b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Wed, 19 Dec 2012 07:17:09 +0530 Subject: [PATCH 151/158] D: allow rm and unlock to be disabled --- src/commands/D | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/commands/D b/src/commands/D index a255073..1a8c2b5 100755 --- a/src/commands/D +++ b/src/commands/D @@ -12,6 +12,9 @@ # - run a cron job to delete old repos based on age (the TRASH_SUFFIX has a # timestamp); your choice how/how often you do that + +# - you can completely disable the 'rm' command by setting an rc variable +# called D_DISABLE_RM to "1". # ---------------------------------------------------------------------- # ---------------------------------------------------------------------- @@ -67,6 +70,8 @@ owner_or_die() { if [ "$cmd" = "rm" ] then + gitolite query-rc -q D_DISABLE_RM && die "sorry, 'unlock' and 'rm' are disabled" + owner_or_die [ -f $repo.git/gl-rm-ok ] || die "'$repo' is locked!" rm -rf $repo.git @@ -82,6 +87,8 @@ then elif [ "$cmd" = "unlock" ] then + gitolite query-rc -q D_DISABLE_RM && die "sorry, 'unlock' and 'rm' are disabled" + owner_or_die touch $repo.git/gl-rm-ok echo "'$repo' is now unlocked" From b3036948821003b4b0d4aad6927630deb6fdf266 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 29 Dec 2012 13:14:36 +0530 Subject: [PATCH 152/158] minor bugly... please remember we make up words here, like refex was a word we created to mean "a regex that matches a ref". A "bugly", then, is a bug that's merely ugly (and not a real problem!) --- src/lib/Gitolite/Conf/Load.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 2611630..441c644 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -386,6 +386,8 @@ sub user_roles { for (@roles) { # READERS u3 u4 @g1 s/^\s+//; s/ +$//; s/=/ /; s/\s+/ /g; s/^\@//; + next if /^#/; + next unless /\S/; my ( $role, @members ) = split; # role = READERS, members = u3, u4, @g1 if ( $role ne 'CREATOR' and not $rc{ROLES}{$role} ) { From 84424e48b9a89fc9a3784dc4cd640c7420618318 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 29 Dec 2012 11:38:13 +0530 Subject: [PATCH 153/158] bug fix: perms propagation to slaves... Sometime after v3.2, I fixed what looked like an information disclosure issue, where a user could determine if an arbitrary repo existed or not, even if he had no rights to see the repo. This was: 96cc2ea "new features relating to creating wild repos:" Unfortunately, this appears to have broken gl-perms propagation to slaves, because now running "perm -c" on an existing repo dies! If you run git diff 96cc2ea^ -- src/commands/perms you'll see how simple the fix *should* have been :-( --- src/commands/perms | 24 ++++++++++++------------ t/sequence.t | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/commands/perms b/src/commands/perms index 6b61596..ffb4bd9 100755 --- a/src/commands/perms +++ b/src/commands/perms @@ -43,23 +43,23 @@ if ( $ARGV[0] eq '-l' ) { getperms(@ARGV); # doesn't return } +my $generic_error = "repo does not exist, or you are not authorised"; + # auto-create the repo if -c passed and repo doesn't exist if ( $ARGV[0] eq '-c' ) { shift; my $repo = $ARGV[0] or usage(); _die "invalid repo '$repo'" unless $repo =~ $REPONAME_PATT; - my $d = "$rc{GL_REPO_BASE}/$repo.git"; - my $errmsg = "repo already exists or you are not authorised to create it"; - # use the same message in both places to prevent leaking repo existence info - _die $errmsg if -d $d; - my $ret = access( $repo, $ENV{GL_USER}, '^C', 'any' ); - _die $errmsg if $ret =~ /DENIED/; + if (not -d "$rc{GL_REPO_BASE}/$repo.git") { + my $ret = access( $repo, $ENV{GL_USER}, '^C', 'any' ); + _die $generic_error if $ret =~ /DENIED/; - require Gitolite::Conf::Store; - Gitolite::Conf::Store->import; - new_wild_repo( $repo, $ENV{GL_USER}, 'perms-c' ); - gl_log( 'create', $repo, $ENV{GL_USER}, 'perms-c' ); + require Gitolite::Conf::Store; + Gitolite::Conf::Store->import; + new_wild_repo( $repo, $ENV{GL_USER}, 'perms-c' ); + gl_log( 'create', $repo, $ENV{GL_USER}, 'perms-c' ); + } } my $repo = shift; @@ -70,7 +70,7 @@ _system( "gitolite", "trigger", "POST_CREATE", $repo, $ENV{GL_USER}, 'perms' ); sub getperms { my $repo = shift; - _die "sorry you are not authorised" if repo_missing($repo) or creator($repo) ne $ENV{GL_USER}; + _die $generic_error if repo_missing($repo) or creator($repo) ne $ENV{GL_USER}; my $pf = "$rc{GL_REPO_BASE}/$repo.git/gl-perms"; print slurp($pf) if -f $pf; @@ -79,7 +79,7 @@ sub getperms { } sub setperms { - _die "sorry you are not authorised" if repo_missing($repo) or creator($repo) ne $ENV{GL_USER}; + _die $generic_error if repo_missing($repo) or creator($repo) ne $ENV{GL_USER}; my $pf = "$rc{GL_REPO_BASE}/$repo.git/gl-perms"; if ( not @_ ) { diff --git a/t/sequence.t b/t/sequence.t index a42b6b6..87f3731 100755 --- a/t/sequence.t +++ b/t/sequence.t @@ -100,7 +100,7 @@ try " # 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 already exists or you are not authorised to create it/ + /FATAL: repo does not exist, or you are not authorised/ # auto-create using perms echo READERS u2 | glt perms u1 -c foo/u1/baz From ea3d04ea0a7283f641ef59390f64bf9b133291e6 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 29 Dec 2012 07:31:27 +0530 Subject: [PATCH 154/158] perms batch mode confuses; print something to help What happens is that running ssh git@host perms reponame appears to hang, since it is waiting for STDIN. I added a message to help, since we don't want users losing files accidentally! (The other alternative is to add a specific option for batch mode, but this is backward incompatible for people who have scripts that may be doing this). thanks to Caleb Cushing for catching this ---- The "make sure Ctrl-C gets caught" thing needs some explanation. Without it, a user could inadvertently lose his gl-perms file if he ran the command in batch mode. You'd think that the Ctrl-C would hit the for (<>) { line and bail, but it manages to reach the _print( $pf, @a ); line somehow. Even trapping SIG INT does not help. I suspect it is to do with how signals are propagated by ssh across a "no-pty" session, but am not sure. --- src/commands/mirror | 2 +- src/commands/perms | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/commands/mirror b/src/commands/mirror index d091979..d72f9ae 100755 --- a/src/commands/mirror +++ b/src/commands/mirror @@ -48,7 +48,7 @@ if ( $cmd eq 'push' ) { if (-f "gl-creator") { # try to propagate the wild repo, including creator name and gl-perms my $creator = `cat gl-creator`; chomp($creator); - trace(1, `cat gl-perms 2>/dev/null | ssh $host CREATOR=$creator perms -c \\'$repo\\'`); + trace(1, `cat gl-perms 2>/dev/null | ssh $host CREATOR=$creator perms -c \\'$repo\\' 2>/dev/null`); } my $errors = 0; diff --git a/src/commands/perms b/src/commands/perms index ffb4bd9..88244a9 100755 --- a/src/commands/perms +++ b/src/commands/perms @@ -84,12 +84,15 @@ sub setperms { if ( not @_ ) { # legacy mode; pipe data in + print STDERR "'batch' mode started, waiting for input (run with '-h' for details).\n"; + print STDERR "Please hit Ctrl-C if you did not intend to do this.\n"; @ARGV = (); my @a; for (<>) { _die "Invalid role '$1'; check the rc file" if /(\S+)/ and not $rc{ROLES}{$1}; push @a, $_; } + print STDERR "\n"; # make sure Ctrl-C gets caught _print( $pf, @a ); return; } From 1fefb1c0d9acd1b7ebd74208c82cf15c7452e34b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sat, 29 Dec 2012 13:58:12 +0530 Subject: [PATCH 155/158] v3.3 --- CHANGELOG | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 91faaa5..b7d4330 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,18 @@ +2012-12-29 v3.3 bug fix: gl-perms propagation to slaves broke sometime + after v3.2 (so if you're only picking up tagged releases + you're OK) + + the "D" command now allows rm/unlock to be totally + disabled + + new trigger: update-gitweb-daemon-from-options; another + way to update gitweb and daemon access lists + + new 'create' command for explicit wild repo creation, and + new AutoCreate trigger to control auto-creation + + allow simple macros in conf file + 2012-11-14 v3.2 major efficiency boost for large setups optional support for multi-line pubkeys; see From 5aef1adc7b47e8c9145d912c76ad15737a5fd34b Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 31 Dec 2012 05:48:18 +0530 Subject: [PATCH 156/158] list-dangling-repos: are we there yet? First I forgot @groups that may contain repos and patterns, then I forgot patterns where the CREATOR token is used (this is the fix here). --- src/commands/list-dangling-repos | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/list-dangling-repos b/src/commands/list-dangling-repos index ea36bab..6d86937 100755 --- a/src/commands/list-dangling-repos +++ b/src/commands/list-dangling-repos @@ -4,6 +4,7 @@ use warnings; use lib $ENV{GL_LIBDIR}; use Gitolite::Common; +use Gitolite::Conf::Load; =for usage Usage: gitolite list-dangling-repos @@ -40,8 +41,9 @@ for my $pr (keys %phy_repos) { # Remove regex matches. for my $pr (keys %phy_repos) { my $matched = 0; + my $pr2 = Gitolite::Conf::Load::generic_name($pr); for my $r (keys %repos) { - if ($pr =~ /^$r$/) { + if ($pr =~ /^$r$/ or $pr2 =~ /^$r$/) { $matched = 1; next; } From 089f0f9d9ed37d44ad2d8d0eb574e1496b113579 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Mon, 31 Dec 2012 06:23:00 +0530 Subject: [PATCH 157/158] on removing a repo... Not following through on instructions to remove a repo, per [1], is not sufficient. Even if you did just the first step, the repo should no longer be accessible. See [2] for discussion. As a bonus, we get rid of one pesky warning that always confused people. (In hindsight -- this confusion itself should have been a warning that something is wrong and needed fixing!) [1]: http://sitaramc.github.com/gitolite/repos.html [2]: http://groups.google.com/group/gitolite/browse_thread/thread/a3d4c3e917056abb --- src/lib/Gitolite/Conf/Load.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Gitolite/Conf/Load.pm b/src/lib/Gitolite/Conf/Load.pm index 441c644..6c133e2 100644 --- a/src/lib/Gitolite/Conf/Load.pm +++ b/src/lib/Gitolite/Conf/Load.pm @@ -246,7 +246,7 @@ sub load_1 { } if ( -f "gl-conf" ) { - _warn "split conf not set, gl-conf present for '$repo'" if not $split_conf{$repo}; + return if not $split_conf{$repo}; my $cc = "./gl-conf"; _die "parse '$cc' failed: " . ( $! or $@ ) unless do $cc; From a6f6886e84248b2fb07a6199dde4d51c349d0c81 Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Wed, 2 Jan 2013 14:55:04 +0100 Subject: [PATCH 158/158] README.txt -> README.md + clean up --- README.md | 359 +++++++++++++++++++++++++++++++++++++++++++++++++++ README.txt | 373 ----------------------------------------------------- 2 files changed, 359 insertions(+), 373 deletions(-) create mode 100644 README.md delete mode 100644 README.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..e650fa6 --- /dev/null +++ b/README.md @@ -0,0 +1,359 @@ +Github-users: click the 'wiki' link before sending me anything via github. + +Existing users: this is gitolite v3.x. If you are upgrading from v2.x this +file will not suffice; you *must* check the online docs (see below for URL). + +------------------------------------------------------------------------ + + +This file contains BASIC DOCUMENTATION ONLY. + +* It is suitable for a fresh, ssh-based, installation of gitolite and basic + usage of its most important features. +* It is NOT meant to be exhaustive or detailed. + +The COMPLETE DOCUMENTATION is at: + + http://sitaramc.github.com/gitolite/master-toc.html + +Please go there for what/why/how, concepts, background, troubleshooting, more +details on what is covered here, or advanced features not covered here. + +------------------------------------------------------------------------ + + +BASIC DOCUMENTATION FOR GITOLITE +================================ + +This file contains the following sections: + +* INSTALLATION AND SETUP +* ADDING USERS AND REPOS +* HELP FOR YOUR USERS +* BASIC SYNTAX +* ACCESS RULES +* GROUPS +* COMMANDS +* THE 'rc' FILE +* GIT-CONFIG +* GIT-DAEMON +* GITWEB +* CONTACT AND SUPPORT +* LICENSE + +------------------------------------------------------------------------ + + +INSTALLATION AND SETUP +---------------------- + +Server requirements: + +* any unix system +* sh +* git 1.6.6+ +* perl 5.8.8+ +* openssh 5.0+ +* a dedicated userid to host the repos (in this document, we assume it + is 'git'), with shell access ONLY by 'su - git' from some other userid + on the same server. + +Steps to install: + +* login as 'git' as described above +* make sure ~/.ssh/authorized_keys is empty or non-existent +* make sure your ssh public key from your workstation is available at $HOME/YourName.pub +* run the following commands: + + git clone git://github.com/sitaramc/gitolite + mkdir -p $HOME/bin + gitolite/install -to $HOME/bin + gitolite setup -pk YourName.pub + + If the last command doesn't run perhaps 'bin' in not in your 'PATH'. + You can either add it, or just run: + + $HOME/bin/gitolite setup -pk YourName.pub + + +ADDING USERS AND REPOS +---------------------- + +Do NOT add new repos or users manually on the server. Gitolite users, +repos, and access rules are maintained by making changes to a special repo +called 'gitolite-admin' and pushing those changes to the server. + +---- + +To administer your gitolite installation, start by doing this on your +workstation (if you have not already done so): + + git clone git@host:gitolite-admin + +**NOTE**: if you are asked for a password, something has gone wrong. + +Now if you 'cd gitolite-admin', you will see two subdirectories in it: +'conf' and 'keydir'. + +To add new users alice, bob, and carol, obtain their public keys and add +them to 'keydir' as alice.pub, bob.pub, and carol.pub respectively. + +To add a new repo 'foo' and give different levels of access to these +users, edit the file 'conf/gitolite.conf' and add lines like this: + + repo foo + RW+ = alice + RW = bob + R = carol + +See the 'ACCESS RULES' section later for more details. + +Once you have made these changes, do something like this: + + git add conf + git add keydir + git commit -m 'added foo, gave access to alice, bob, carol' + git push + +When the push completes, gitolite will add the new users to +~/.ssh/authorized_keys on the server, as well as create a new, empty, repo +called 'foo'. + + +HELP FOR YOUR USERS +------------------- + +Once a user has sent you their public key and you have added them as +specified above and given them access, you have to tell them what URL to +access their repos at. This is usually 'git clone git@host:reponame'; see +man git-clone for other forms. + +**NOTE**: again, if they are asked for a password, something is wrong. + +If they need to know what repos they have access to, they just have to run +'ssh git@host info'; see 'COMMANDS' section later for more on this. + + +BASIC SYNTAX +------------ + +The basic syntax of the conf file is very simple. + +* Everything is space separated; there are no commas, semicolons, etc., + in the syntax. +* Comments are in the usual perl/shell style. +* User and repo names are as simple as possible; they must start with an + alphanumeric, but after that they can also contain '.', '_', or '-'. + + Usernames can optionally be followed by an '@' and a domainname + containing at least one '.'; this allows you to use an email address + as someone's username. + + Reponames can contain '/' characters; this allows you to put your + repos in a tree-structure for convenience. +* There are no continuation lines. + + +ACCESS RULES +------------ + +This section is mostly 'by example'. + +Gitolite's access rules are very powerful. The simplest use was already +shown above. Here is a slightly more detailed example: + + repo foo + RW+ = alice + - master = bob + - refs/tags/v[0-9] = bob + RW = bob + RW refs/tags/v[0-9] = carol + R = dave + +For clones and fetches, as long as the user is listed with an R, RW +or RW+ in at least one rule, he is allowed to read the repo. + +For pushes, rules are processed in sequence until a rule is found +where the user, the permission (see note 1), and the refex (note 2) +*all* match. At that point, if the permission on the matched rule +was '-', the push is denied, otherwise it is allowed. If no rule +matches, the push is denied. + +Note 1: permission matching: + +* a permission of RW matches only a fast-forward push or create +* a permission of RW+ matches any type of push +* a permission of '-' matches any type of push + +Note 2: refex matching: +(refex = optional regex to match the ref being pushed) + +* an empty refex is treated as 'refs/.*' +* a refex that does not start with 'refs/' is prefixed with 'refs/heads/' +* finally, a '^' is prefixed +* the ref being pushed is matched against this resulting refex + +With all that background, here's what the example rules say: + +* alice can do anything to any branch or tag -- create, push, delete, rewind/overwrite etc. +* bob can create or fast-forward push any branch whose name does + not start with 'master' and create any tag whose name does not + start with 'v'+digit. +* carol can create tags whose names start with 'v'+digit. +* dave can clone/fetch. + + +GROUPS +------ + +Gitolite allows you to group users or repos for convenience. Here's an +example that creates two groups of users: + + @staff = alice bob carol + @interns = ashok + + repo secret + RW = @staff + + repo foss + RW+ = @staff + RW = @interns + +Group lists accumulate. The following two lines have the same effect as +the earlier definition of @staff above: + + @staff = alice bob + @staff = carol + +You can also use group names in other group names: + + @all-devs = @staff @interns + +Finally, @all is a special group name that is often convenient to use if +you really mean 'all repos' or 'all users'. + + +COMMANDS +-------- + +Users can run certain commands remotely, using ssh. For example: + + ssh git@host help + +prints a list of available commands. + +The most commonly used command is 'info'. All commands respond to a +single argument of '-h' with suitable information. + +If you have shell on the server, you have a lot more commands available to +you; try running 'gitolite help'. + + +THE 'rc' FILE +-------------- + +Some of the instructions below may require you to edit the rc file +(~/.gitolite.rc on the server). + +The rc file is perl code, 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. + + +GIT-CONFIG +---------- + +Gitolite lets you set git-config values for individual repos without +having to log on to the server and run 'git config' commands: + + repo foo + config hooks.mailinglist = foo-commits@example.tld + config hooks.emailprefix = '[foo] ' + config foo.bar = '' + config foo.baz = + +**WARNING** + +The last syntax shown above is the *only* way to *delete* a config +variable once you have added it. Merely removing it from the conf +file will *not* delete it from the repo.git/config file. + +**SECURITY NOTE** + +Some git-config keys allow arbitrary code to be run on the server. + +If all of your gitolite admins already have shell access to the server +account hosting it, you can edit the rc file (~/.gitolite.rc) on the +server, and change the GIT_CONFIG_KEYS line to look like this: + + GIT_CONFIG_KEYS => '.*', + +Otherwise, give it a space-separated list of regular expressions that +define what git-config keys are allowed. For example, this one allows +only variables whose names start with 'gitweb' or with 'gc' to be +defined: + + GIT_CONFIG_KEYS => 'gitweb\..* gc\..*', + + +GIT-DAEMON +---------- + +Gitolite creates the 'git-daemon-export-ok' file for any repo that is +readable by a special user called 'daemon', like so: + + repo foo + R = daemon + + +GITWEB +------ + +Any repo that is readable by a special user called 'gitweb' will be added +to the projects.list file. + + repo foo + R = gitweb + +Or you can set one or more of the following config variables instead: + + repo foo + config gitweb.owner = some person's name + config gitweb.description = some description + config gitweb.category = some category + +**NOTE** + +You will probably need to change the UMASK in the rc file from the +default (0077) to 0027 and add whatever user your gitweb is running as +to the 'git' group. After that, you need to run a one-time 'chmod -R' +on the already created files and directories. + +------------------------------------------------------------------------ + + +CONTACT AND SUPPORT +------------------- + +Mailing list for support and general discussion: + gitolite@googlegroups.com + subscribe address: gitolite+subscribe@googlegroups.com + +Mailing list for announcements and notices: + subscribe address: gitolite-announce+subscribe@googlegroups.com + +IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 +time zone). + +Author: sitaramc@gmail.com, but please DO NOT use this for general support +questions. Subscribe to the list and ask there instead. + + +LICENSE +------- + +The gitolite *code* is released under GPL v2. See COPYING for details. + +This documentation, which is part of the source code repository, is +provided under a Creative Commons Attribution-ShareAlike 3.0 Unported +License -- see http://creativecommons.org/licenses/by-sa/3.0/ diff --git a/README.txt b/README.txt deleted file mode 100644 index 08fed1c..0000000 --- a/README.txt +++ /dev/null @@ -1,373 +0,0 @@ -Github-users: click the 'wiki' link before sending me anything via github. - -Existing users: this is gitolite v3.x. If you are upgrading from v2.x this -file will not suffice; you *must* check the online docs (see below for URL). - ------------------------------------------------------------------------- - - -This file contains BASIC DOCUMENTATION ONLY. - - * It is suitable for a fresh, ssh-based, installation of gitolite and basic - usage of its most important features. - - * It is NOT meant to be exhaustive or detailed. - -The COMPLETE DOCUMENTATION is at: - - http://sitaramc.github.com/gitolite/master-toc.html - -Please go there for what/why/how, concepts, background, troubleshooting, more -details on what is covered here, or advanced features not covered here. - ------------------------------------------------------------------------- - - -BASIC DOCUMENTATION FOR GITOLITE -================================ - -This file contains the following sections: - - INSTALLATION AND SETUP - ADDING USERS AND REPOS - HELP FOR YOUR USERS - BASIC SYNTAX - ACCESS RULES - GROUPS - COMMANDS - THE 'rc' FILE - GIT-CONFIG - GIT-DAEMON - GITWEB - - CONTACT AND SUPPORT - LICENSE - ------------------------------------------------------------------------- - - -INSTALLATION AND SETUP ----------------------- - - Server requirements: - - * any unix system - * sh - * git 1.6.6+ - * perl 5.8.8+ - * openssh 5.0+ - * a dedicated userid to host the repos (in this document, we assume it - is 'git'), with shell access ONLY by 'su - git' from some other userid - on the same server. - - Steps to install: - - * login as 'git' as described above - - * make sure ~/.ssh/authorized_keys is empty or non-existent - - * make sure your ssh public key from your workstation is available at - $HOME/YourName.pub - - * run the following commands: - - git clone git://github.com/sitaramc/gitolite - mkdir -p $HOME/bin - gitolite/install -to $HOME/bin - gitolite setup -pk YourName.pub - - If the last command doesn't run perhaps 'bin' in not in your 'PATH'. - You can either add it, or just run: - - $HOME/bin/gitolite setup -pk YourName.pub - - -ADDING USERS AND REPOS ----------------------- - - Do NOT add new repos or users manually on the server. Gitolite users, - repos, and access rules are maintained by making changes to a special repo - called 'gitolite-admin' and pushing those changes to the server. - - ---- - - To administer your gitolite installation, start by doing this on your - workstation (if you have not already done so): - - git clone git@host:gitolite-admin - - **NOTE**: if you are asked for a password, something has gone wrong. - - Now if you 'cd gitolite-admin', you will see two subdirectories in it: - 'conf' and 'keydir'. - - To add new users alice, bob, and carol, obtain their public keys and add - them to 'keydir' as alice.pub, bob.pub, and carol.pub respectively. - - To add a new repo 'foo' and give different levels of access to these - users, edit the file 'conf/gitolite.conf' and add lines like this: - - repo foo - RW+ = alice - RW = bob - R = carol - - See the 'ACCESS RULES' section later for more details. - - Once you have made these changes, do something like this: - - git add conf - git add keydir - git commit -m 'added foo, gave access to alice, bob, carol' - git push - - When the push completes, gitolite will add the new users to - ~/.ssh/authorized_keys on the server, as well as create a new, empty, repo - called 'foo'. - - -HELP FOR YOUR USERS -------------------- - - Once a user has sent you their public key and you have added them as - specified above and given them access, you have to tell them what URL to - access their repos at. This is usually 'git clone git@host:reponame'; see - man git-clone for other forms. - - **NOTE**: again, if they are asked for a password, something is wrong. - - If they need to know what repos they have access to, they just have to run - 'ssh git@host info'; see 'COMMANDS' section later for more on this. - - -BASIC SYNTAX ------------- - - The basic syntax of the conf file is very simple. - - * Everything is space separated; there are no commas, semicolons, etc., - in the syntax. - - * Comments are in the usual perl/shell style. - - * User and repo names are as simple as possible; they must start with an - alphanumeric, but after that they can also contain '.', '_', or '-'. - - Usernames can optionally be followed by an '@' and a domainname - containing at least one '.'; this allows you to use an email address - as someone's username. - - Reponames can contain '/' characters; this allows you to put your - repos in a tree-structure for convenience. - - * There are no continuation lines. - - -ACCESS RULES ------------- - - This section is mostly 'by example'. - - Gitolite's access rules are very powerful. The simplest use was already - shown above. Here is a slightly more detailed example: - - repo foo - RW+ = alice - - master = bob - - refs/tags/v[0-9] = bob - RW = bob - RW refs/tags/v[0-9] = carol - R = dave - - For clones and fetches, as long as the user is listed with an R, RW - or RW+ in at least one rule, he is allowed to read the repo. - - For pushes, rules are processed in sequence until a rule is found - where the user, the permission (see note 1), and the refex (note 2) - *all* match. At that point, if the permission on the matched rule - was '-', the push is denied, otherwise it is allowed. If no rule - matches, the push is denied. - - Note 1: permission matching: - - * a permission of RW matches only a fast-forward push or create - * a permission of RW+ matches any type of push - * a permission of '-' matches any type of push - - Note 2: refex matching: - (refex = optional regex to match the ref being pushed) - - * an empty refex is treated as 'refs/.*' - * a refex that does not start with 'refs/' is prefixed with 'refs/heads/' - * finally, a '^' is prefixed - * the ref being pushed is matched against this resulting refex - - With all that background, here's what the example rules say: - - * alice can do anything to any branch or tag -- create, push, - delete, rewind/overwrite etc. - - * bob can create or fast-forward push any branch whose name does - not start with 'master' and create any tag whose name does not - start with 'v'+digit. - - * carol can create tags whose names start with 'v'+digit. - - * dave can clone/fetch. - - -GROUPS ------- - - Gitolite allows you to group users or repos for convenience. Here's an - example that creates two groups of users: - - @staff = alice bob carol - @interns = ashok - - repo secret - RW = @staff - - repo foss - RW+ = @staff - RW = @interns - - Group lists accumulate. The following two lines have the same effect as - the earlier definition of @staff above: - - @staff = alice bob - @staff = carol - - You can also use group names in other group names: - - @all-devs = @staff @interns - - Finally, @all is a special group name that is often convenient to use if - you really mean 'all repos' or 'all users'. - - -COMMANDS --------- - - Users can run certain commands remotely, using ssh. For example: - - ssh git@host help - - prints a list of available commands. - - The most commonly used command is 'info'. All commands respond to a - single argument of '-h' with suitable information. - - If you have shell on the server, you have a lot more commands available to - you; try running 'gitolite help'. - - -THE 'rc' FILE --------------- - - Some of the instructions below may require you to edit the rc file - (~/.gitolite.rc on the server). - - The rc file is perl code, 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. - - -GIT-CONFIG ----------- - - Gitolite lets you set git-config values for individual repos without - having to log on to the server and run 'git config' commands: - - repo foo - config hooks.mailinglist = foo-commits@example.tld - config hooks.emailprefix = '[foo] ' - config foo.bar = '' - config foo.baz = - - **WARNING** - - The last syntax shown above is the *only* way to *delete* a config - variable once you have added it. Merely removing it from the conf - file will *not* delete it from the repo.git/config file. - - **SECURITY NOTE** - - Some git-config keys allow arbitrary code to be run on the server. - - If all of your gitolite admins already have shell access to the server - account hosting it, you can edit the rc file (~/.gitolite.rc) on the - server, and change the GIT_CONFIG_KEYS line to look like this: - - GIT_CONFIG_KEYS => '.*', - - Otherwise, give it a space-separated list of regular expressions that - define what git-config keys are allowed. For example, this one allows - only variables whose names start with 'gitweb' or with 'gc' to be - defined: - - GIT_CONFIG_KEYS => 'gitweb\..* gc\..*', - - -GIT-DAEMON ----------- - - Gitolite creates the 'git-daemon-export-ok' file for any repo that is - readable by a special user called 'daemon', like so: - - repo foo - R = daemon - - -GITWEB ------- - - Any repo that is readable by a special user called 'gitweb' will be added - to the projects.list file. - - repo foo - R = gitweb - - Or you can set one or more of the following config variables instead: - - repo foo - config gitweb.owner = some person's name - config gitweb.description = some description - config gitweb.category = some category - - **NOTE** - - You will probably need to change the UMASK in the rc file from the - default (0077) to 0027 and add whatever user your gitweb is running as - to the 'git' group. After that, you need to run a one-time 'chmod -R' - on the already created files and directories. - - ------------------------------------------------------------------------- - - -CONTACT AND SUPPORT -------------------- - - Mailing list for support and general discussion: - gitolite@googlegroups.com - subscribe address: gitolite+subscribe@googlegroups.com - - Mailing list for announcements and notices: - subscribe address: gitolite-announce+subscribe@googlegroups.com - - IRC: #git and #gitolite on freenode. Note that I live in India (UTC+0530 - time zone). - - Author: sitaramc@gmail.com, but please DO NOT use this for general support - questions. Subscribe to the list and ask there instead. - - -LICENSE -------- - - The gitolite *code* is released under GPL v2. See COPYING for details. - - This documentation, which is part of the source code repository, is - provided under a Creative Commons Attribution-ShareAlike 3.0 Unported - License -- see http://creativecommons.org/licenses/by-sa/3.0/