Merge branch 'master' into wildrepos

master brought in:

  - full email addresses as usernames
  - repo-specific git config

Conflicts:
	doc/3-faq-tips-etc.mkd
	src/gitolite.pm
	src/gl-compile-conf
This commit is contained in:
Sitaram Chamarty 2009-12-11 11:19:54 +05:30
commit ff28acb059
6 changed files with 169 additions and 26 deletions

View file

@ -6,9 +6,13 @@
# the description string for gitweb) # the description string for gitweb)
# - comments in the normal shell-ish style; no surprises there # - comments in the normal shell-ish style; no surprises there
# - there are NO continuation lines of any kind # - there are NO continuation lines of any kind
# - user/repo names as simple as possible # - user/repo names as simple as possible; they must start with an
# (usernames: only alphanumerics, ".", "_", "-"; # alphanumeric, but after that they can also contain ".", "_", "-".
# reponames: same, plus "/", but not at the start) # - 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)
# objectives, over and above gitosis: # objectives, over and above gitosis:
# - simpler syntax # - simpler syntax
@ -87,7 +91,8 @@
repo gitolite-admin repo gitolite-admin
RW+ = @admins RW+ = @admins
# "@all" is a special, predefined, group name # "@all" is a special, predefined, group name of all users
# (everyone who has a pubkey in keydir)
repo testing repo testing
RW+ = @all RW+ = @all
@ -181,3 +186,26 @@ repo linux perl
# give gitweb access as described above if you're specifying a description # give gitweb access as described above if you're specifying a description
gitolite "Sitaram Chamarty" = "fast, secure, access control for git in a corporate environment" gitolite "Sitaram Chamarty" = "fast, secure, access control for git in a corporate environment"
# REPO SPECIFIC GITCONFIG
# -----------------------
# (Thanks to teemu dot matilainen at iki dot fi)
# this should be specified within a "repo" stanza
# syntax:
# config sectionname.keyname = [optional value_string]
# example usage: if you placed a hook in src/hooks that requires configuration
# information that is specific to each repo, you could do this:
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 3
# examples above) or "git config --unset-all section.key" (for the last
# example). Other forms (--add, the value_regex, etc) are not supported.

View file

@ -37,13 +37,16 @@ Assumptions/pre-requisites:
* git is installed on that server (and so is perl) * git is installed on that server (and so is perl)
* you have a userid on that server * you have a userid on that server
* you have ssh-pubkey (**password-less**) login to that userid * you have ssh-pubkey (**password-less**) login to that userid
* (if you have only password access, run `ssh-keygen -t rsa` to create a * if you have only password access, run `ssh-keygen -t rsa` to create a
new keypair if needed, then run `ssh-copy-id user@host`) new keypair if needed, then run `ssh-copy-id user@host`. If you do
not have `ssh-copy-id`, read doc/3-faq-tips-etc.mkd and look for
`ssh-copy-id` in that file for instructions
* you have a clone or an archive of gitolite somewhere on your workstation * you have a clone or an archive of gitolite somewhere on your workstation
* if you don't have one, just run `git clone git://github.com/sitaramc/gitolite`
If so, just `cd` to that clone and run `src/gl-easy-install` and follow the Once you have all this, just `cd` to that clone and run `src/gl-easy-install`
prompts! (Running it without any arguments shows you usage plus other useful and follow the prompts! (Running it without any arguments shows you usage
info). plus other useful info).
#### typical example run #### typical example run

View file

@ -9,6 +9,7 @@ In this document:
* adding users and repos * adding users and repos
* specifying gitweb and daemon access * specifying gitweb and daemon access
* custom hooks * custom hooks
* custom git config
### administer ### administer
@ -90,3 +91,25 @@ just run easy install once again; it'll do it to existing repos also.
implements all the branch-level permissions in gitolite. If you fiddle with implements all the branch-level permissions in gitolite. If you fiddle with
the hooks directory, please make sure you do not mess with this file the hooks directory, please make sure you do not mess with this file
accidentally, or all your fancy per-branch permissions will stop working.** accidentally, or all your fancy per-branch permissions will stop working.**
#### custom git config
The custom hooks feature is a blunt instrument -- all repos get the hook you
specified and will run it. In order to make it a little more fine-grained,
you could set your hooks to only work if a certain "gitconfig" variable was
set. Which means we now need a way to specify "git config" settings on a per
repository basis.
Thanks to Teemu (teemu dot matilainen at iki dot fi), gitolite now does this
very easily. For security reasons, this can only be done from the master
config file (i.e., if you're using delegation, the delegated admins cannot
specify git config settings).
Please see `conf/example.conf` for syntax. Note that this only supports the
basic forms of the "git config" command:
git config section.key value # value may be an empty string
git config --unset-all section.key
It does not (currently) support other options like `--add`, the `value_regex`,
etc.

View file

@ -19,22 +19,32 @@ In this document:
* what repos do I have access to? * what repos do I have access to?
* "exclude" (or "deny") rules * "exclude" (or "deny") rules
* "personal" branches * "personal" branches
* custom hooks and custom git config
* repos named with wildcards * repos named with wildcards
* design choices * design choices
* keeping the parser and the access control separate * keeping the parser and the access control separate
### common errors and mistakes ### common errors and mistakes
* forgetting to suffix `.git` to the end of the reponame in the `git clone`.
This suffix is *not* used in the gitolite config file for the sake of
clarity and cleaner syntax, but don't let that fool you. It's a
convention in the git world that **bare repos** end with `.git`.
* adding `repositories/` at the start of the repo name in the `git clone`. * adding `repositories/` at the start of the repo name in the `git clone`.
This error is typically made by the *admin* himself -- because he knows This error is typically made by the *admin* himself -- because he knows
what `$REPO_BASE` is set to and thinks he has to provide that prefix on what `$REPO_BASE` is set to and thinks he has to provide that prefix on
the client side also :-) In fact gitolite prepends `$REPO_BASE` when it the client side also :-) In fact gitolite prepends `$REPO_BASE`
is required anyway, so you shouldn't do the same thing! internally, so you shouldn't also do the same thing!
* being able to clone but getting errors on push. Most likely caused by a
combination of:
* you already have shell access to the server, not just "gitolite"
access, *and*
* you cloned using `git clone git@server:repositories/repo.git` (notice
there's an extra "repositories/" in there?)
In other words, you used a key that completely bypassed gitolite and went
straight to the shell to do the clone.
Please see doc/6-ssh-troubleshooting.mkd for what all this means.
### git version dependency ### git version dependency
@ -67,6 +77,27 @@ normal way, since it's not empty anymore.
### other errors, warnings, notes... ### other errors, warnings, notes...
* 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!)]
* cloning an empty repo is only possible with clients greater than 1.6.2. * cloning an empty repo is only possible with clients greater than 1.6.2.
So at least one of your clients needs to have a recent git. Once at least So at least one of your clients needs to have a recent git. Once at least
one commit has been made, older clients can also use it one commit has been made, older clients can also use it
@ -345,12 +376,36 @@ gitolite knows these two keys belong to the same person.
Note that you don't say "sitaram@laptop" and so on in the **config** file -- Note that you don't say "sitaram@laptop" and so on in the **config** file --
as far as the config file is concerned there's just **one** user called as far as the config file is concerned there's just **one** user called
"sitaram" -- so you only say "sitaram" there. Only the **pubkey files** have "sitaram" -- so you only say "sitaram" there.
the extra "@" stuff.
I think this is easier to maintain if you have to delete or change one of I think this is easier to maintain if you have to delete or change one of
those keys. those keys.
However, now that `sitaramc@gmail.com` is also a valid username, we need to
distinguish between `sitaramc@gmail.com.pub` and `sitaramc@desktop.pub`. We
do that by requiring that the multi-key suffix you use (like "desktop" and
"laptop") should not have a `"."` in it. If it does, it looks like an email
address. The following table lists sample pubkey filenames and the
corresponding derived usernames (which is what goes into the
`conf/gitolite.conf` file):
* old style multikeys; not mistaken for emails because there is no "." in
hostname part
sitaramc.pub sitaramc
sitaramc@laptop.pub sitaramc
sitaramc@desktop.pub sitaramc
* new style, email keys; there is a "." in hostname part; so it's an email
address
sitaramc@gmail.com.pub sitaramc@gmail.com
* multikeys *with* email address
sitaramc@gmail.com@laptop.pub sitaramc@gmail.com
sitaramc@gmail.com@desktop.pub sitaramc@gmail.com
#### support for git installed outside default PATH #### support for git installed outside default PATH
The normal solution is to add to the system default PATH somehow, either by The normal solution is to add to the system default PATH somehow, either by
@ -507,6 +562,12 @@ first check:
Just don't *show* the user this config file; it might sound insulting :-) Just don't *show* the user this config file; it might sound insulting :-)
#### custom hooks and custom git config
You can specify hooks that you want to propagate to all repos, as well as
per-repo "gitconfig" settings. Please see `doc/2-admin.mkd` and
`conf/example.conf` for details.
#### repos named with wildcards #### repos named with wildcards
**This feature only exists in the "wildrepos" branch!** Please see **This feature only exists in the "wildrepos" branch!** Please see

View file

@ -24,9 +24,9 @@ $WARN = "\n\t\t***** WARNING *****\n ";
$R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/; $R_COMMANDS=qr/^(git[ -]upload-pack|git[ -]upload-archive)$/;
$W_COMMANDS=qr/^git[ -]receive-pack$/; $W_COMMANDS=qr/^git[ -]receive-pack$/;
# note that REPONAME_PATT allows a "/" also, which USERNAME_PATT doesn't # note that REPONAME_PATT allows "/", while USERNAME_PATT allows "@"
$REPONAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._/-]*$); # very simple pattern $REPONAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._/-]*$); # very simple pattern
$USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._-]*$); # very simple pattern $USERNAME_PATT=qr(^\@?[0-9a-zA-Z][0-9a-zA-Z._\@-]*$); # very simple pattern
# same as REPONAME, plus some common regex metas # same as REPONAME, plus some common regex metas
$REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._/-]*$); $REPOPATT_PATT=qr(^\@?[0-9a-zA-Z][\\^.$|()[\]*+?{}0-9a-zA-Z._/-]*$);

View file

@ -36,11 +36,11 @@ $Data::Dumper::Sortkeys = sub { return [ reverse sort keys %{$_[0]} ]; };
# - anytime a pubkey is added/deleted # - anytime a pubkey is added/deleted
# - anytime gitolite.conf is changed # - anytime gitolite.conf is changed
# input: # input:
# - GL_CONF (default: ~/.gitolite/gitolite.conf) # - GL_CONF (default: ~/.gitolite/conf/gitolite.conf)
# - GL_KEYDIR (default: ~/.gitolite/keydir) # - GL_KEYDIR (default: ~/.gitolite/keydir)
# output: # output:
# - ~/.ssh/authorized_keys (dictated by sshd) # - ~/.ssh/authorized_keys (dictated by sshd)
# - GL_CONF_COMPILED (default: ~/.gitolite/gitolite.conf-compiled.pm) # - GL_CONF_COMPILED (default: ~/.gitolite/conf/gitolite.conf-compiled.pm)
# security: # security:
# - touches a very critical system file that manages the restrictions on # - touches a very critical system file that manages the restrictions on
# incoming users. Be sure to audit AUTH_COMMAND and AUTH_OPTIONS (see # incoming users. Be sure to audit AUTH_COMMAND and AUTH_OPTIONS (see
@ -111,6 +111,9 @@ my %rurp_seen = ();
# catch usernames<->pubkeys mismatches; search for "lint" below # catch usernames<->pubkeys mismatches; search for "lint" below
my %user_list = (); my %user_list = ();
# repo configurations
my %repo_config = ();
# gitweb descriptions and owners; plain text, keyed by "$repo.git" # gitweb descriptions and owners; plain text, keyed by "$repo.git"
my %desc = (); my %desc = ();
my %owner = (); my %owner = ();
@ -129,7 +132,7 @@ sub expand_list
for my $item (@list) for my $item (@list)
{ {
die "$ABRT bad user or repo name $item\n" unless $item =~ $REPOPATT_PATT; die "$ABRT bad user or repo name $item\n" unless $item =~ $REPOPATT_PATT or $item =~ $USERNAME_PATT;
if ($item =~ /^@/) # nested group if ($item =~ /^@/) # nested group
{ {
die "$ABRT undefined group $item\n" unless $groups{$item}; die "$ABRT undefined group $item\n" unless $groups{$item};
@ -182,7 +185,6 @@ sub parse_conf_file
# store the members of each group as hash key. Keep track of when # store the members of each group as hash key. Keep track of when
# the group was *first* created by using $fragment as the *value* # the group was *first* created by using $fragment as the *value*
do { $groups{$1}{$_} ||= $fragment } for ( expand_list( split(' ', $2) ) ); do { $groups{$1}{$_} ||= $fragment } for ( expand_list( split(' ', $2) ) );
# again, we take the more "relaxed" pattern
die "$ABRT bad group $1\n" unless $1 =~ $REPONAME_PATT; die "$ABRT bad group $1\n" unless $1 =~ $REPONAME_PATT;
} }
# repo(s) # repo(s)
@ -278,6 +280,16 @@ sub parse_conf_file
} }
} }
} }
# configuration
elsif (/^config (.+) = ?(.*)/)
{
my ($key, $value) = ($1, $2);
die "$WARN $fragment attempting to set repo configuration\n" if $fragment ne 'master';
for my $repo (@repos) # each repo in the current stanza
{
$repo_config{$repo}{$key} = $value;
}
}
# very simple syntax for the gitweb description of repo; one of: # very simple syntax for the gitweb description of repo; one of:
# reponame = "some description string" # reponame = "some description string"
# reponame "owner name" = "some description string" # reponame "owner name" = "some description string"
@ -379,6 +391,22 @@ warn "\n\t\t***** WARNING *****\n" .
"\t\"git version dependency\" in doc/3-faq-tips-etc.mkd\n" "\t\"git version dependency\" in doc/3-faq-tips-etc.mkd\n"
if $git_version < 10602; # that's 1.6.2 to you if $git_version < 10602; # that's 1.6.2 to you
# ----------------------------------------------------------------------------
# update repo configurations
# ----------------------------------------------------------------------------
for my $repo (keys %repo_config) {
wrap_chdir("$repo_base_abs/$repo.git");
while ( my ($key, $value) = each(%{ $repo_config{$repo} }) ) {
if ($value) {
$value =~ s/^"(.*)"$/$1/;
system("git", "config", $key, $value);
} else {
system("git", "config", "--unset-all", $key);
}
}
}
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# handle gitweb and daemon # handle gitweb and daemon
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
@ -450,7 +478,7 @@ for my $pubkey (glob("*"))
print STDERR "WARNING: pubkey files should end with \".pub\", ignoring $pubkey\n"; print STDERR "WARNING: pubkey files should end with \".pub\", ignoring $pubkey\n";
next; next;
} }
my $user = $pubkey; $user =~ s/(\@.+)?\.pub$//; my $user = $pubkey; $user =~ s/(\@[^.]+)?\.pub$//;
# lint check 2 # lint check 2
print STDERR "WARNING: pubkey $pubkey exists but user $user not in config\n" print STDERR "WARNING: pubkey $pubkey exists but user $user not in config\n"
unless $user_list{$user}; unless $user_list{$user};