doc/3 reorg; one section was getting too long!

This commit is contained in:
Sitaram Chamarty 2010-02-11 09:03:26 +05:30
parent 0e96c2f08a
commit 7e34a39050

View file

@ -10,28 +10,33 @@ In this document:
* `@all` syntax for repos * `@all` syntax for repos
* umask setting * umask setting
* getting a tar file from a clone * getting a tar file from a clone
* differences from gitosis * features
* simpler syntax * syntax and normal usage
* two levels of access rights checking * simpler syntax
* file/dir NAME based restrictions * one user, many keys
* error checking the config file * security, access control, and auditing
* including config lines from other files * two levels of access rights checking
* delegating parts of the config file * better logging
* easier to specify gitweb "description" and gitweb/daemon access * "exclude" (or "deny") rules
* easier to link gitweb authorisation with gitolite * file/dir NAME based restrictions
* better logging * delegating parts of the config file
* one user, many keys * convenience features
* support for git installed outside default PATH * what repos do I have access to?
* what repos do I have access to? * error checking the config file
* "exclude" (or "deny") rules * including config lines from other files
* "personal" branches * support for git installed outside default PATH
* custom hooks and custom git config * "personal" branches
* repos named with wildcards * custom hooks and custom git config
* access control for external commands * helping with gitweb
* easier to specify gitweb "description" and gitweb/daemon access
* easier to link gitweb authorisation with gitolite
* advanced features
* repos named with wildcards
* access control for external commands
* 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
* 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
@ -53,7 +58,7 @@ In this document:
Please see doc/6-ssh-troubleshooting.mkd for what all this means. Please see doc/6-ssh-troubleshooting.mkd for what all this means.
### git version dependency ## git version dependency
Here's a workaround for a version dependency that the normal flow of gitolite Here's a workaround for a version dependency that the normal flow of gitolite
has. has.
@ -82,9 +87,9 @@ and then push. Something like:
Once this is done, the repo is available for cloning by anyone else in the Once this is done, the repo is available for cloning by anyone else in the
normal way, since it's not empty anymore. normal way, since it's not empty anymore.
### other errors, warnings, notes... ## other errors, warnings, notes...
#### ssh-copy-id ### ssh-copy-id
don't have `ssh-copy-id`? This is broadly what that command does, if you want 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 to replicate it manually. The input is your pubkey, typically
@ -107,7 +112,7 @@ 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 they're already set that way anyway. (Or if they're not, you've got
bigger problems than gitolite install not working!)] bigger problems than gitolite install not working!)]
#### cloning an empty repo ### cloning an empty repo
Cloning an empty repo is only possible with clients greater than 1.6.2. So at 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 one least one of your clients needs to have a recent git. Once at least one
@ -118,7 +123,7 @@ end hung up unexpectedly`. However, you can ignore this, since it doesn't
seem to hurt anything. [Update 2009-09-14; this has been fixed in git seem to hurt anything. [Update 2009-09-14; this has been fixed in git
1.6.4.3] 1.6.4.3]
#### `@all` syntax for repos ### `@all` syntax for repos
There *is* a way to use the `@all` syntax for repos also, as described in There *is* a way to use the `@all` syntax for repos also, as described in
`conf/example.conf`. However, there is an important difference between this `conf/example.conf`. However, there is an important difference between this
@ -132,12 +137,12 @@ and the old `@all` (for users):
* This means that if you really want *all* repos, you'd better put this para * This means that if you really want *all* repos, you'd better put this para
at the **end** of the config file! at the **end** of the config file!
#### umask setting ### umask setting
Gitweb not able to read your repos? You can change the umask for newly Gitweb not able to read your repos? You can change the umask for newly
created repos to something more relaxed -- see the `~/.gitolite.rc` file created repos to something more relaxed -- see the `~/.gitolite.rc` file
### getting a tar file from a clone ## getting a tar file from a clone
You can clone the repo from github or indefero, then execute a make command to You can clone the repo from github or indefero, then execute a make command to
extract a tar file of the branch you want. Please use the make command, not a extract a tar file of the branch you want. Please use the make command, not a
@ -153,13 +158,9 @@ plain "git archive", because the Makefile adds a file called
<a name="diff"></a> <a name="diff"></a>
### differences from gitosis ## features
Apart from the big ones listed in the top level README, and subjective ones ### syntax and normal usage
like "better config file format", there are some small, but significant and
concrete, differences from gitosis.
<a name="simpler_syntax"></a>
#### simpler syntax #### simpler syntax
@ -204,6 +205,51 @@ do not worry that this causes some duplication or inefficiency. It doesn't
See the "specify gitweb/daemon access" section below for one more example. See the "specify gitweb/daemon access" section below for one more example.
#### one user, many keys
I have a laptop and a desktop I need to access the server from. I have
different private keys on them, but as far as gitolite is concerned both of
them should be treated as "sitaram". How does this work?
In gitosis, the admin creates a single "sitaram.pub" containing one line for
each of my pubkeys. In gitolite, we keep them separate: "sitaram@laptop.pub"
and "sitaram@desktop.pub". The part before the "@" is the username, so
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 --
as far as the config file is concerned there's just **one** user called
"sitaram" -- so you only say "sitaram" there.
I think this is easier to maintain if you have to delete or change one of
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
### security, access control, and auditing
#### two levels of access rights checking #### two levels of access rights checking
Gitolite has two levels of access checks. The **first check** is what I will Gitolite has two levels of access checks. The **first check** is what I will
@ -239,6 +285,89 @@ any of the refexes match, the push succeeds. If none of them match, it fails.
Gitolite also allows "exclude" or "deny" rules. See later in this document Gitolite also allows "exclude" or "deny" rules. See later in this document
for details. for details.
Apart from the big ones listed in the top level README, and subjective ones
like "better config file format", gitolite has evolved to have many useful
fearures than the original goal of "gitosis + branch-level access control".
<a name="simpler_syntax"></a>
#### better logging
If you have been too liberal with the permission to rewind, it has built-in
logging as an emergency fallback if someone goes too far, or for audit
purposes [`*`]. The logfile names and location are configurable, and can
include the year/month/day etc in the filename for easy archival or further
processing. The log file even tells you which pattern in the config file
matched to allow that specific access to proceed.
> [`*`] setting `core.logAllRefUpdates true` does provide a safety net
> against over-zealous rewinds, but it does not tell you "who". And
> strangely, management does not seem to share the view that "blame" is just
> a synonym for "annotate" ;-)]
The log lines look like this:
2009-09-19.10:24:37 + b4e76569659939 4fb16f2a88d8b5 myrepo refs/heads/master user2 refs/heads/master
The "+" at the start indicates a non-fast forward update, in this case from
b4e76569659939 to 4fb16f2a88d8b5. So b4e76569659939 is the one to restore!
Can it get easier?
The other parts of the log line are the name of the repo, the refname being
updated, the user updating it, and the refex pattern (from the config file)
that matched, in case you need to debug the config file itself.
<a name="multikeys"></a>
#### "exclude" (or "deny") rules
Here is an illustrative explanation of "deny" rules. However, please be sure
to read the "DENY/EXCLUDE RULES" section in `conf/example.conf` for important
notes/caveats before using "deny" rules.
Take a look at the following snippet, which *seems* to say that "bruce" can
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
staffers can't:
@staff = bruce whitfield martin
[... and later ...]
RW refs/tags/v[0-9] = bruce
RW refs/tags = @staff
But that's not how the matching works. As long as any refex matches the
refname being updated, it's a "yes". Since the second refex (which says
"anything containing `refs/tags`") is a superset of the first one, it lets
anyone on `@staff` create versioned tags, not just Bruce.
One way to fix this is to allow "excludes" -- some changes in syntax, combined
with a rigorous, ordered, interpretation would do it.
Let's recap the **existing semantics**:
> the first matching refex that has the permission you're looking for (`W`
> or `+`), results in success. A fallthrough results in failure
Here are the **new semantics**, with changes from the "main" one in bold:
> the first matching refex that has the permission you're looking for (`W`
> or `+`) **or a minus (`-`)**, results in success **or failure,
> respectively**. A fallthrough **also** results in failure
So the example we started with becomes, if you use "deny" rules:
RW refs/tags/v[0-9] = bruce
- refs/tags/v[0-9] = @staff
RW refs/tags = @staff
And here's how it works:
* for non-version tags, only the 3rd rule matches, so anyone on staff can
push them
* for version tags by bruce, the first rule matches so he can push them
* for version tags by staffers *other than bruce*, the second rule matches
before the third one, and it has a `-` as the permission, so the push
fails
#### file/dir NAME based restrictions #### file/dir NAME based restrictions
In addition to branch-name based restrictions, gitolite also allows you to In addition to branch-name based restrictions, gitolite also allows you to
@ -248,6 +377,46 @@ changed, treating each filename as a "ref" to be matched.
Please see `conf/example.conf` for syntax and examples. Please see `conf/example.conf` for syntax and examples.
#### delegating parts of the config file
You can now split up the config file and delegate the authority to specify
access control for their own pieces. See
[doc/5-delegation.mkd](http://github.com/sitaramc/gitolite/blob/pu/doc/5-delegation.mkd)
for details.
<a name="gwd"></a>
### convenience features
#### what repos do I have access to?
Sometimes there are too many repos, maybe even named similarly, or with the
potential for typos, confusion about hyphens/underscores or upper/lower case,
etc. You'd just like a simple way to know what repos you have access to.
Easy! Just use ssh and try to log in as if you were attempting to get a
shell:
$ ssh gitolite info
PTY allocation request failed on channel 0
hello sitaram, the gitolite version here is v0.6-17-g94ed189
you have the following permissions:
R W Anu-WSD
R ROtest
R W SecureBrowse
R W entrans
R W git-notes
R W gitolite
R W gitolite-admin
R W indic_web_input
R W proxy
@ @ testing
R W vkc
Note that until this version, we used to put out an ugly `need
SSH_ORIGINAL_COMMAND` error, just like gitosis used to. All we did is put
that code path to better use :-)
#### error checking the config file #### error checking the config file
gitosis does not do any. I just found out that if you mis-spell `members` as gitosis does not do any. I just found out that if you mis-spell `members` as
@ -261,14 +430,94 @@ you know right away.
See the entry under "INCLUDE SOME OTHER FILE" in `conf/example.conf`. See the entry under "INCLUDE SOME OTHER FILE" in `conf/example.conf`.
#### delegating parts of the config file #### support for git installed outside default PATH
You can now split up the config file and delegate the authority to specify The normal solution is to add to the system default PATH somehow, either by
access control for their own pieces. See munging `/etc/profile` or by enabling `PermitUserEnvironment` in
[doc/5-delegation.mkd](http://github.com/sitaramc/gitolite/blob/pu/doc/5-delegation.mkd) `/etc/ssh/sshd_config` and then setting the PATH in `~/.ssh/.environment`.
for details. All these are security risks because they allow a lot more than just you and
your git install :-)
<a name="gwd"></a> And if you don't have root, you can't do this anyway.
The only solution till now has been to ask every client to set the config
parameters `remote.<name>.receivepack` and `remote.<name>.uploadpack`. But
telling *every* client to do so is a pain...
Gitolite lets you specify the directory in which git binaries are to be found,
via a new variable (`$GIT_PATH`) in the "rc" file. If this variable is
non-empty, it will be appended to the PATH environment variable before
attempting to run git stuff.
Very easy, very simple, and completely transparent to the users :-)
<a name="myrights"></a>
#### "personal" branches
"personal" branches are great for corporate environments, where
unauthenticated pull/clone is a no-no. Since a dev workstation cannot do
authentication, even work shared just between 2 devs has to go *via* the
server. This causes 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 (e.g., `refs/personal/<devname>/*`), with full
permissions for that dev and read-only for everyone else. And you get
this without adding a single line to the access config file -- pretty
much fire and forget as far as the admin is concerned, even if there is
constant churn in the project teams.
Not bad for something that took just *one* line of code to implement.
And that's one clean, readable, line, by the way ;-)
The admin would set `$PERSONAL_BRANCH_PREFIX` in the rc file and communicate
this to all users. It could be something like `refs/heads/personal`, which
means all such branches will show up in `git branch` lookups and `git clone`
will fetch them. Or he could use, say, `refs/personal`, which means it won't
show up in any normal "branch-y" commands and stuff, and generally be much
less noisy.
**Note that a user who has NO write access cannot have personal branches**; if
you read the section (above) on "two levels of access rights checking" you'll
understand why.
For instance, in the following example, `user3` cannot push to any
`refs/heads/personal/user3/*` branches because the first level check stops him
cold:
# assume $PERSONAL = 'refs/heads/personal' in ~/.gitolite.rc
repo myrepo
RW+ master = sitaram
RW+ release = qa_guy
RW = user1 user2
R = user3
If we relax that check, *any* access becomes *write* access. Yes it will be
caught later, by the hook, but it's good practice to catch things in multiple
places.
If you want `user3` to have his own personal branch, but without write access
to any of the "real" branches (like "master", "release", etc.), just use a
dummy branch. Choose a name that will never exist in practice, or even if
someone creates it, we don't care. For example, this will get him past the
first check:
RW dummy = user3
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.
### helping with gitweb
Although gitweb is a completely separate program, gitolite can do quite a
lot to help you manage gitweb access as well; once the initial setup is
complete, you can do it all from within the gitolite config file!
#### easier to specify gitweb "description" and gitweb/daemon access #### easier to specify gitweb "description" and gitweb/daemon access
@ -392,237 +641,7 @@ already done and we just use it!
[leho]: http://leho.kraav.com/news/2009/10/27/using-apache-authentication-with-gitweb-gitosis-repository-access-control/ [leho]: http://leho.kraav.com/news/2009/10/27/using-apache-authentication-with-gitweb-gitosis-repository-access-control/
#### better logging ### advanced features
If you have been too liberal with the permission to rewind, it has built-in
logging as an emergency fallback if someone goes too far, or for audit
purposes [`*`]. The logfile names and location are configurable, and can
include the year/month/day etc in the filename for easy archival or further
processing. The log file even tells you which pattern in the config file
matched to allow that specific access to proceed.
> [`*`] setting `core.logAllRefUpdates true` does provide a safety net
> against over-zealous rewinds, but it does not tell you "who". And
> strangely, management does not seem to share the view that "blame" is just
> a synonym for "annotate" ;-)]
The log lines look like this:
2009-09-19.10:24:37 + b4e76569659939 4fb16f2a88d8b5 myrepo refs/heads/master user2 refs/heads/master
The "+" at the start indicates a non-fast forward update, in this case from
b4e76569659939 to 4fb16f2a88d8b5. So b4e76569659939 is the one to restore!
Can it get easier?
The other parts of the log line are the name of the repo, the refname being
updated, the user updating it, and the refex pattern (from the config file)
that matched, in case you need to debug the config file itself.
<a name="multikeys"></a>
#### one user, many keys
I have a laptop and a desktop I need to access the server from. I have
different private keys on them, but as far as gitolite is concerned both of
them should be treated as "sitaram". How does this work?
In gitosis, the admin creates a single "sitaram.pub" containing one line for
each of my pubkeys. In gitolite, we keep them separate: "sitaram@laptop.pub"
and "sitaram@desktop.pub". The part before the "@" is the username, so
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 --
as far as the config file is concerned there's just **one** user called
"sitaram" -- so you only say "sitaram" there.
I think this is easier to maintain if you have to delete or change one of
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
The normal solution is to add to the system default PATH somehow, either by
munging `/etc/profile` or by enabling `PermitUserEnvironment` in
`/etc/ssh/sshd_config` and then setting the PATH in `~/.ssh/.environment`.
All these are security risks because they allow a lot more than just you and
your git install :-)
And if you don't have root, you can't do this anyway.
The only solution till now has been to ask every client to set the config
parameters `remote.<name>.receivepack` and `remote.<name>.uploadpack`. But
telling *every* client to do so is a pain...
Gitolite lets you specify the directory in which git binaries are to be found,
via a new variable (`$GIT_PATH`) in the "rc" file. If this variable is
non-empty, it will be appended to the PATH environment variable before
attempting to run git stuff.
Very easy, very simple, and completely transparent to the users :-)
<a name="myrights"></a>
#### what repos do I have access to?
Sometimes there are too many repos, maybe even named similarly, or with the
potential for typos, confusion about hyphens/underscores or upper/lower case,
etc. You'd just like a simple way to know what repos you have access to.
Easy! Just use ssh and try to log in as if you were attempting to get a
shell:
$ ssh gitolite info
PTY allocation request failed on channel 0
hello sitaram, the gitolite version here is v0.6-17-g94ed189
you have the following permissions:
R W Anu-WSD
R ROtest
R W SecureBrowse
R W entrans
R W git-notes
R W gitolite
R W gitolite-admin
R W indic_web_input
R W proxy
@ @ testing
R W vkc
Note that until this version, we used to put out an ugly `need
SSH_ORIGINAL_COMMAND` error, just like gitosis used to. All we did is put
that code path to better use :-)
#### "exclude" (or "deny") rules
Here is an illustrative explanation of "deny" rules. However, please be sure
to read the "DENY/EXCLUDE RULES" section in `conf/example.conf` for important
notes/caveats before using "deny" rules.
Take a look at the following snippet, which *seems* to say that "bruce" can
write versioned tags (anything containing `refs/tags/v[0-9]`), but the other
staffers can't:
@staff = bruce whitfield martin
[... and later ...]
RW refs/tags/v[0-9] = bruce
RW refs/tags = @staff
But that's not how the matching works. As long as any refex matches the
refname being updated, it's a "yes". Since the second refex (which says
"anything containing `refs/tags`") is a superset of the first one, it lets
anyone on `@staff` create versioned tags, not just Bruce.
One way to fix this is to allow "excludes" -- some changes in syntax, combined
with a rigorous, ordered, interpretation would do it.
Let's recap the **existing semantics**:
> the first matching refex that has the permission you're looking for (`W`
> or `+`), results in success. A fallthrough results in failure
Here are the **new semantics**, with changes from the "main" one in bold:
> the first matching refex that has the permission you're looking for (`W`
> or `+`) **or a minus (`-`)**, results in success **or failure,
> respectively**. A fallthrough **also** results in failure
So the example we started with becomes, if you use "deny" rules:
RW refs/tags/v[0-9] = bruce
- refs/tags/v[0-9] = @staff
RW refs/tags = @staff
And here's how it works:
* for non-version tags, only the 3rd rule matches, so anyone on staff can
push them
* for version tags by bruce, the first rule matches so he can push them
* for version tags by staffers *other than bruce*, the second rule matches
before the third one, and it has a `-` as the permission, so the push
fails
#### "personal" branches
"personal" branches are great for corporate environments, where
unauthenticated pull/clone is a no-no. Since a dev workstation cannot do
authentication, even work shared just between 2 devs has to go *via* the
server. This causes 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 (e.g., `refs/personal/<devname>/*`), with full
permissions for that dev and read-only for everyone else. And you get
this without adding a single line to the access config file -- pretty
much fire and forget as far as the admin is concerned, even if there is
constant churn in the project teams.
Not bad for something that took just *one* line of code to implement.
And that's one clean, readable, line, by the way ;-)
The admin would set `$PERSONAL_BRANCH_PREFIX` in the rc file and communicate
this to all users. It could be something like `refs/heads/personal`, which
means all such branches will show up in `git branch` lookups and `git clone`
will fetch them. Or he could use, say, `refs/personal`, which means it won't
show up in any normal "branch-y" commands and stuff, and generally be much
less noisy.
**Note that a user who has NO write access cannot have personal branches**; if
you read the section (above) on "two levels of access rights checking" you'll
understand why.
For instance, in the following example, `user3` cannot push to any
`refs/heads/personal/user3/*` branches because the first level check stops him
cold:
# assume $PERSONAL = 'refs/heads/personal' in ~/.gitolite.rc
repo myrepo
RW+ master = sitaram
RW+ release = qa_guy
RW = user1 user2
R = user3
If we relax that check, *any* access becomes *write* access. Yes it will be
caught later, by the hook, but it's good practice to catch things in multiple
places.
If you want `user3` to have his own personal branch, but without write access
to any of the "real" branches (like "master", "release", etc.), just use a
dummy branch. Choose a name that will never exist in practice, or even if
someone creates it, we don't care. For example, this will get him past the
first check:
RW dummy = user3
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
@ -642,9 +661,9 @@ who has shell access anyway).
Please see the config files (both of them) for examples and usage. Please see the config files (both of them) for examples and usage.
### design choices ## design choices
#### keeping the parser and the access control separate ### keeping the parser and the access control separate
There are two programs concerned with access control: There are two programs concerned with access control: