572 lines
22 KiB
Markdown
572 lines
22 KiB
Markdown
# F=conf the access control file `gitolite.conf`
|
|
|
|
Gitolite has an advanced access control language that is designed to be
|
|
powerful but easy to use. Other objectives were that it should be even easier
|
|
to read, review and audit the rules, and it should scale to thousands of repos
|
|
and users. There was also, in the author's mind, a desperate need to create
|
|
something as different as possible from the brain-dead, nausea-inducing
|
|
"Windows INI" style syntax that some other popular tools seem to favour.
|
|
|
|
This document describes the syntax and semantics of the access control rules
|
|
and other configuration directives in the `gitolite.conf` file.
|
|
|
|
## #syntax 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)
|
|
|
|
### continuation lines
|
|
|
|
There are no continuation lines -- gitolite does not process C-style
|
|
backslash-escaped newlines as anything special. However, the section on
|
|
"groups" will tell you how you can break up large lists of names in a group
|
|
definition into multiple lines.
|
|
|
|
### 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" from the same directory as
|
|
the main config file. You can also use an absolute path if you like, although
|
|
in the interests of cloning the admin-repo sanely you should avoid doing this!
|
|
|
|
You can also use a glob, as in:
|
|
|
|
include "*.conf"
|
|
|
|
which will include all the ".conf" files from the directory in which the main
|
|
config file exists.
|
|
|
|
Files that have been already processed once are skipped, with a warning.
|
|
|
|
<font color="gray">Advanced users: `subconf`, a command that is very closely
|
|
related to `include`, is documented [here][subconf].</font>
|
|
|
|
## F=bac basic access control
|
|
|
|
Here's a very basic set of rules:
|
|
|
|
repo gitolite-admin
|
|
RW+ = sitaram
|
|
|
|
repo testing
|
|
RW+ = @all
|
|
|
|
repo gitolite simplicity
|
|
RW+ = sitaram dilbert
|
|
RW = alice ashok
|
|
R = wally
|
|
|
|
It should be easy to guess what most of this means:
|
|
|
|
* `R` means "read" permission
|
|
* `RW` means "read and write", but no rewind
|
|
* `RW+` means "read and write", with rewind allowed
|
|
|
|
A "rewind" is more often called a "non-fast forward push"; see git docs for
|
|
what that is. The `+` was chosen because it is part of the "git push" syntax
|
|
for non-ff pushes.
|
|
|
|
Note that *tags* are generally considered "write once", so they are treated
|
|
specially by gitolite: you need rewind permission (`RW+`) to *overwrite* a
|
|
tag with a new value.
|
|
|
|
In a later section you'll see some more advanced permissions.
|
|
|
|
### how rules are matched
|
|
|
|
It's important to understand that there're two levels at which access control
|
|
happens. Please see [this][2levels] for details, especially about the first level
|
|
check. Much of the complexity applies only to the second level check, so that
|
|
is all we will be discussing here. This check is done by the update hook, and
|
|
determines whether the push succeeds or fails.
|
|
|
|
For basic permissions like this, matching is simple. Gitolite already knows:
|
|
|
|
* the user
|
|
* the repo
|
|
* the branch or tag ("ref") being pushed
|
|
* whether it is a normal (ff) push or a rewind (non-ff) push.
|
|
|
|
Gitolite goes down the list of rules matching the user, repo, and the ref.
|
|
The first matching rule that has the permission you're looking for (`W` or
|
|
`+`), results in success. A fallthrough results in failure.
|
|
|
|
### branches, tags, and specifying "refex"es
|
|
|
|
One of the original goals of gitolite was to allow access control at the
|
|
branch/tag (aka "ref") level. The git source code contains a sample update
|
|
hook that has the following in it:
|
|
|
|
# from Documentation/howto/update-hook-example.txt:
|
|
|
|
refs/heads/master junio
|
|
+refs/heads/pu junio
|
|
refs/heads/cogito$ pasky
|
|
refs/heads/bw/.* linus
|
|
refs/heads/tmp/.* .*
|
|
refs/tags/v[0-9].* junio
|
|
|
|
If you did this in gitolite, this is what the equivalents would be:
|
|
|
|
repo git
|
|
RW master$ = junio # line 1
|
|
RW+ pu$ = junio # line 2
|
|
RW cogito$ = pasky # line 3
|
|
RW bw/ = linus # line 4
|
|
RW tmp/ = @all # line 5
|
|
RW refs/tags/v[0-9] = junio # line 6
|
|
|
|
The following points will help you understand these rules. (Git recap:
|
|
branches and tags together are called "ref"s in git. A branch ref usually
|
|
looks like "refs/heads/foo", while a tag ref looks like "refs/tags/bar")
|
|
|
|
* the general syntax of a paragraph of rules is:
|
|
|
|
# start line:
|
|
repo [one or more repos and/or repo groups]
|
|
# followed by one or more permissions lines:
|
|
[permission] [zero or more refexes] = [one or more users]
|
|
|
|
* a **refex** is a *perl regex* that matches a ref. When you try to push a
|
|
commit to a branch or a tag, that "ref" is matched against the refex part
|
|
of each rule.
|
|
|
|
* if the refex does not start with `refs/`, gitolite assumes a prefix of
|
|
`refs/heads/`. This is useful because *branch* matching is the most
|
|
common case, as you can see this applies to lines 1 through 5 here.
|
|
|
|
* if no refex appears, the rule applies to all refs in that repo (as if you
|
|
had specified `refs/.*` as the refex).
|
|
|
|
* refexes are prefix-matched (they are internally anchored with `^` before
|
|
being used). This means only the beginning of the actual ref needs to
|
|
match the refex, unless the refex has an explicit `$` meta-character at
|
|
the end (like the first 3 lines in our example do).
|
|
|
|
Line 5, for instance, allows anyone to push a branch inside the "tmp/"
|
|
namespace, while line 6 provides the ability to push version tags; "v1",
|
|
"v1.0", "v2.0rc1", all match the criterion specified by `v[0-9]` because
|
|
this is a prefix match only.
|
|
|
|
### groups
|
|
|
|
Gitolite allows you to define **groups** of repos. users, or even refexes. A
|
|
group is semantically (but *not* syntactically) like a `#define` in C. Here
|
|
is an example of each kind:
|
|
|
|
@oss_repos = gitolite linux git perl rakudo entrans vkc
|
|
@staff = sitaram some_dev another-dev
|
|
@important = master$ QA_done refs/tags/v[0-9]
|
|
|
|
The syntax of a group definition is simply:
|
|
|
|
@groupname = [one or more names]
|
|
|
|
A group can *accumulate* values. For example:
|
|
|
|
@staff = sitaram some_dev another-dev
|
|
@staff = au.thor
|
|
|
|
is the same as
|
|
|
|
@staff = sitaram some_dev another-dev au.thor
|
|
|
|
This is more convenient than continuation lines, because it allows you to add
|
|
to a group anywhere. Many people generate their gitolite.conf itself from
|
|
some *other* database, and it is very useful to be able to do this sort of
|
|
thing.
|
|
|
|
Groups can include other groups, and the included group will be expanded to
|
|
whatever value it *currently* has:
|
|
|
|
@staff = sitaram some_dev another-dev # line 1
|
|
@staff = au.thor # line 2
|
|
@interns = indy james # line 3
|
|
@alldevs = bob @interns @staff # line 4
|
|
|
|
"@alldevs" expands to 7 names now. However, remember that the config file is
|
|
parsed in a single-pass, so later *additions* to a group name cannot affect
|
|
earlier *uses* of it. If you moved line 2 to the end, "@alldevs" would only
|
|
have 6 names in it.
|
|
|
|
#### the special `@all` group
|
|
|
|
There's a special group called `@all` that includes all authenticated users
|
|
when used as a username; you've seen examples of it earlier.
|
|
|
|
Advanced users: also see the entry for `GL_ALL_INCLUDES_SPECIAL` in the
|
|
documentation for [`~/.gitolite.rc`][rc].
|
|
|
|
When used as a reponame, it includes all repos.
|
|
|
|
### F=rpr_ side note: "R" permissions for refs
|
|
|
|
You can control "read" access only at the repo level, not at the branch level.
|
|
For example, this **won't** limit Wally to reading only the master branch:
|
|
|
|
repo foo
|
|
R master = wally # WILL NOT DO WHAT YOU THINK IT DOES!!
|
|
|
|
and this **won't** prevent him from reading it:
|
|
|
|
repo foo
|
|
- master = wally # WILL NOT DO WHAT YOU THINK IT DOES!!
|
|
R = wally
|
|
|
|
This (inability to distinguish one ref from another during a read operation)
|
|
is a git issue, not a gitolite issue.
|
|
|
|
There are 3 ways around this, though:
|
|
|
|
* switch to gerrit, which has its own git stack, its own sshd, and God knows
|
|
what else. All written in Java, the COBOL of the internet era ;-)
|
|
* bug the git people to add this feature in ;-)
|
|
* use a separate repo for Wally.
|
|
|
|
Using separate repos is not that hard with gitolite. Here's how to maintain a
|
|
[partial copy][partialcopy] of the main repo and keep it synced (while not
|
|
allowing the secret branches into it).
|
|
|
|
## F=aac advanced access control
|
|
|
|
The previous section is sufficient for most common needs, but gitolite can go
|
|
a lot further than that.
|
|
|
|
### #deny "deny" rules
|
|
|
|
#### warnings and required reading
|
|
|
|
Gitolite performs access checks at 2 levels. The first check is performed for
|
|
both read *and* write operations, while the second one happens only for write
|
|
operations.
|
|
|
|
**Required reading**: [this section][2levels] of the documentation.
|
|
|
|
**Warning**: When using deny rules, the order of your rules matters, where
|
|
earlier it did not. If you're just starting to add a deny rule to an existing
|
|
ruleset, it's a good idea to review the entire ruleset once, to make sure
|
|
you're doing it right.
|
|
|
|
#### "deny" rules for refs in a repo
|
|
|
|
You can use "deny" rules for the second check, to prevent people pushing
|
|
branches or tags that they should not be allowed to.
|
|
|
|
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.
|
|
|
|
So how do we say "these people can create any tags except tags that look like
|
|
this pattern"?
|
|
|
|
One way to fix this is to allow "deny" rules. We make a small addition to the
|
|
permissions syntax, and define a more rigorous, ordered, interpretation.
|
|
|
|
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
|
|
|
|
#### "deny" rules for the entire repo
|
|
|
|
The previous section described deny rules for the second check, which is a
|
|
fairly common need. However, gitolite does not process deny rules for the
|
|
first check -- it's usually simple enough to make sure your config file does
|
|
not allow the particular user/repo combindation at all.
|
|
|
|
But there's one case where this becomes cumbersome: when you want to create
|
|
exceptions to uses of `@all`.
|
|
|
|
For example, if you want gitweb to show `@all` repos except the special
|
|
'gitolite-admin' repo, you must manually (and laboriously) maintain a list of
|
|
all your repos (except gitolite-admin) and use that in place of `@all`. Oh
|
|
joy...
|
|
|
|
But now you can do this:
|
|
|
|
repo gitolite-admin
|
|
- = gitweb daemon
|
|
[... other access rules ...]
|
|
config gitolite-options.deny-repo = 1
|
|
|
|
repo @all
|
|
R = gitweb daemon
|
|
|
|
Here are some notes on how/why this works:
|
|
|
|
* The order is important -- the deny rule must come first.
|
|
|
|
* The 'config' line is what tells git to behave differently, i.e., apply
|
|
deny rules for the first check also.
|
|
|
|
* Since there is no "ref" to match against the refexes in the rules,
|
|
gitolite just ignores the refexes, and simply looks at the permission (R,
|
|
RW, "-", etc) and the user list.
|
|
|
|
### #rwcd creating and deleting branches
|
|
|
|
Since the beginning of gitolite, `RW` gave the ability, not only to update,
|
|
but to *create* a branch (that matched the refex). Similarly, `RW+` meant
|
|
being able to not only rewind, but also delete a ref. Conceptually, a rewind
|
|
is almost the same as a delete+push (the only difference I can see is if you
|
|
had core.logAllRefUpdates set, which is *not* a default setting).
|
|
|
|
However, there seem to be cases where it is useful to distinguish these cases.
|
|
Arguments can be made on all sides if you're dealing with new users, so
|
|
gitolite supports that.
|
|
|
|
We'll look at the delete/rewind case in detail first:
|
|
|
|
* if the rules for a repo do not contain a `D` anywhere, then `RW+` will
|
|
allow both rewind and delete operations. Apart from being more convenient
|
|
if you don't need this separation, this also ensures backward
|
|
compatibility for setups created before this separation feature was added
|
|
to gitolite).
|
|
|
|
* if, however, *any* of the rules for a repo contains a `D` (example: `RWD`,
|
|
`RW+D`, etc) then `RW+` by itself will permit only a rewind, not a delete
|
|
|
|
The same thing applies to create/push, where if you have permissions like
|
|
`RWC` or `RW+C` anywhere in that repo, a simple `RW` or `RW+` can no longer
|
|
*create* a new ref.
|
|
|
|
You can combine the `C` and `D` also. Thus, the set of permissions you now
|
|
know about are, in regex syntax: `R|RW+?C?D?`. See a later section for the
|
|
full set of permissions possible.
|
|
|
|
Some usage hints:
|
|
|
|
* if you find that `RW+` no longer allows creation/deletion but you can't
|
|
see a `C`/`D` permission in the rules, remember that gitolite allows a
|
|
repo config to be specified in multiple places for convenience, included
|
|
delegated or included files. Be sure to search everywhere :)
|
|
|
|
* a quick way to make this the default for *all* your repos is:
|
|
|
|
repo @all
|
|
RWCD dummy-branch = foo
|
|
|
|
where foo can be either the administrator, or if you can ignore the
|
|
warning message when you push, a non-existant user.
|
|
|
|
## summary: permissions
|
|
|
|
The full set of permissions, in regex syntax: `-|R|RW+?C?D?`. This expands to
|
|
one of `-`, `R`, `RW`, `RW+`, `RWC`, `RW+C`, `RWD`, `RW+D`, `RWCD`, or
|
|
`RW+CD`. and by now you know what they all mean.
|
|
|
|
[Side note: There is one more very important permissions to be dealt with --
|
|
the standalone `C`, which is not really a "ref" level permission and can be
|
|
found in doc/wildcard-repositories.mkd.]
|
|
|
|
## F=confother_ other tips
|
|
|
|
### personal branches
|
|
|
|
Gitolite lets you define a "personal" or "scratch" namespace prefix for each
|
|
developer. See [here][pers] for details.
|
|
|
|
### #ruleaccum rule accumulation
|
|
|
|
(Also see [this][ruleaccum2] for a different example that may be more
|
|
intuitive for some people).
|
|
|
|
Gitolite lets you specify access rules for a repo in bits and pieces, and
|
|
accumulates them in the same sequence they were given. This is very
|
|
convenient. Let's say you have a mix of open source and closed source
|
|
projects, and "bosses" should have read access to all projects, and everyone
|
|
should have read access to open source projects. Assuming the appropriate
|
|
group definitions, this would work:
|
|
|
|
# all bosses have read access to all projects
|
|
repo @open @closed @topsecret
|
|
R = @bosses
|
|
|
|
# everyone has read access to "open" projects
|
|
repo @open
|
|
R = @bosses @devs @interns
|
|
|
|
If you notice that `@bosses` are given read access to `@open` via both rules,
|
|
don't worry that this causes some duplication or inefficiency. It doesn't :-)
|
|
|
|
Elsewhere in the file, you would specify access for individual repos (like RW,
|
|
RW+, etc). Gitolite combines all of these access rules, maintaining the
|
|
textual order in which they occur, when authorising a push.
|
|
|
|
And although this example used groups, you can use reponames as well, or mix
|
|
and match them. You can even distribute rulesets across multiple "include"
|
|
files if you wish.
|
|
|
|
Just remember that if you use [deny rules][deny] anywhere then the *order of the
|
|
rules matters*!
|
|
|
|
This feature also helps people who generate their gitolite.conf itself from
|
|
some *other* database -- it allows them much more flexibility in how they
|
|
generate rules.
|
|
|
|
### #gwd specifying gitweb and daemon access
|
|
|
|
Gitolite allows you to specify access for git-daemon and gitweb. This is a
|
|
feature that I personally do not use (corporate environments don't like
|
|
unauthenticated access of any kind to any repo!), but someone wanted it, so
|
|
here goes.
|
|
|
|
Gitolite has two pre-defined, "special", usernames: `daemon` and `gitweb`.
|
|
|
|
To make a repo or repo group accessible via "git daemon", just give read
|
|
permission to the special user "daemon". Similarly, give read permission to
|
|
`gitweb` to allow the gitweb CGI to show the repo. Something like this:
|
|
|
|
repo foo bar baz
|
|
R = gitweb daemon
|
|
|
|
This gives you a quick way to offer multiple repos up for gitweb and/or daemon
|
|
access.
|
|
|
|
However, **setting a description** for the project also enables gitweb
|
|
permissions so you can do it that way if you want. Of course in this case you
|
|
have to deal with each repo separately. Add lines like this to gitolite.conf:
|
|
|
|
foo = "some description"
|
|
bar = "some other description"
|
|
baz = "yet another description"
|
|
|
|
You can also **specify an owner** for gitweb to show, if you like; for example
|
|
I might use:
|
|
|
|
gitolite "Sitaram Chamarty" = "fast, secure, fine-grained, access control for git"
|
|
|
|
These lines are standalone, so you can add them anywhere in the conf file.
|
|
|
|
Note that gitolite does **not** install or configure gitweb/git-daemon -- that
|
|
is a one-time setup you must do separately. All gitolite does is:
|
|
|
|
* for daemon, create the file `git-daemon-export-ok` in the repository
|
|
* for gitweb, add the repo (plus owner name, if given) to the list of
|
|
projects to be served by gitweb (see the config file variable
|
|
`$PROJECTS_LIST`, which should have the same value you specified for
|
|
`$projects_list` when setting up gitweb)
|
|
* put the description, if given, in `$repo/description`
|
|
|
|
The "compile" script will keep these files consistent with the config settings
|
|
-- this includes removing such settings/files if you remove "read" permissions
|
|
for the special usernames or remove the description line.
|
|
|
|
Please **note** that giving permissions to these special users via `@all`
|
|
(that is, using either `repo @all` or `R = @all`), will not work unless you
|
|
set the rc-file variable `$GL_ALL_INCLUDES_SPECIAL` to `1`. Also, **NOTE**
|
|
that giving them read access to `repo @all` means the `gitolite-admin` repo is
|
|
also accessible. **It is upto you to decide if that is OK in your
|
|
environment**.
|
|
|
|
### #rsgc repo specific `git config` commands
|
|
|
|
(Thanks to teemu dot matilainen at iki dot fi)
|
|
|
|
> ----
|
|
|
|
> **Note**: this won't work unless the rc file has the right settings;
|
|
> please see `$GL_GITCONFIG_KEYS` in the [rc file doc][rc] for details and
|
|
> security information.
|
|
|
|
> ----
|
|
|
|
Sometimes you want to specify `git config` settings for your repos.
|
|
|
|
For example, say you have a custom post-receive hook that sends an email when
|
|
a push happens, and this hook looks in the config for whom to send the email
|
|
to, etc.
|
|
|
|
You can set these git config values within a "repo" paragraph:
|
|
|
|
repo gitolite
|
|
config hooks.mailinglist = gitolite-commits@example.tld
|
|
config hooks.emailprefix = "[gitolite] "
|
|
config foo.bar = ""
|
|
config foo.baz =
|
|
|
|
The syntax is simple:
|
|
|
|
config sectionname.keyname = [optional value_string]
|
|
|
|
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
|
|
`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 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 gitolite.mirror.master = "frodo"
|
|
config gitolite.mirror.slaves = "sam gollum"
|
|
|
|
repo top-secret-project
|
|
# only sam, because we don't trust gollum
|
|
config gitolite.mirror.slaves = "sam"
|
|
|
|
The "delete config variable" syntax can also be used, if you wish:
|
|
|
|
repo highlander # there can be only one!
|
|
config gitolite.mirror.master =
|
|
config gitolite.mirror.slaves =
|
|
|
|
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.
|