nosync-quiet option added courtesy Robin Johnson (Gentoo project)
[gitolite-doc.git] / docs / conf-2.mkd
blob23156c241d186c80cc3b7a54f5e49b7cb5781f34
1 # the "conf" file (`conf/gitolite.conf`)
3 <center>(part 2)</center>
5 ----
7 # access control rule matching
9 Access control rule matching is pretty simple.  From the previous section,
10 you know what "permission", "refex", "user", and "repo" are.  Here's how the
11 rules are used to decide whether to allow or deny a request.
13 Access is checked once only for "read" operations, but twice for "write"s.
15 (Note that the `deny-rules` option, mentioned below, is explained in more
16 detail in a later section.)
18 **Check #1**: the first check happens as soon as gitolite-shell receives
19 control (from sshd or httpd).  gitolite-shell will pass control to
20 git-upload-pack or git-receive-pack only if this check succeeds.
22 *   collect all the rules pertaining to this repo *and* this user
23 *   ignore all the refexes; they don't apply to the first access check
24 *   **if** the `deny-rules` option is **not** in effect for this repo, discard
25     all the `-` (deny) rules
26 *   look at the rules *in sequence*:
27     *   if you find a `-`, access is denied
28     *   for a "read" operation (clone, fetch, ...), if you find a rule
29         containing `R`, access is allowed
30     *   for a "write" operation (push), if you find a rule containing `W`,
31         access is allowed
32     *   if there are no more rules left, access is denied
34 **Check #2**: the second check only happens for "push" operations.  It is
35 invoked by `git-receive-pack` running the gitolite-installed `update` hook.
36 If access is denied, the update hook fails, and git then aborts the push for
37 this ref.  (See `man githooks` for more.)
39 In the following description, we use the word `operation` instead of `W`,
40 because the actual operation could be a plain, fast-forward, push (`W`) or a
41 rewind/delete (`+`).  <span class="gray">Other, less commonly used, values are "C", "D",
42 or "M"; see [here][write-types].</span>
44 *   collect all the rules pertaining to this repo *and* this user
45 *   discard all the rules where the refex does not match the ref (branch or
46     tag) being pushed
47 *   look at the rules *in sequence*:
48     *   if you find a `-`, access is denied
49     *   if you find a rule containing the operation you are performing, access
50         is allowed
51     *   if there are no more rules left, access is denied
53 ## an example
55 Just to be clear, let's work out an example of what happens when dilbert tries
56 to push a branch called "xyz".
58 We'll pretend the rule list looks like this:
60 ```gitolite
61 # managers should be able to read any repo
62 repo @all
63     R                       =   @managers
65 # ...other rules for other repos...
67 repo foo bar
69     RW+                     =   alice @teamleads
70     -   master              =   dilbert @devteam
71     -   refs/tags/v[0-9]    =   dilbert @devteam
72     RW+ dev/                =   dilbert @devteam
73     RW                      =   dilbert @devteam
74     R                       =   @managers
75 ```
77 After adding a default refex and expanding the supplied ones (see the
78 [refex][] section earlier), this is what it looks like.  We've added line
79 numbers for convenience; we'll see why later.
81 [refex]: conf#the-refex-field
83 ```gitolite-nu
84 # managers should be able to read any repo
85 repo @all
86     R                       =   @managers
88     # ...other rules for other repos...
90 repo foo bar
92     RW+ refs/.*             =   alice @teamleads
93     -   refs/heads/master   =   dilbert @devteam
94     -   refs/tags/v[0-9]    =   dilbert @devteam
95     RW+ refs/heads/dev/     =   dilbert @devteam
96     RW  refs/.*             =   dilbert @devteam
97     R                       =   @managers
98 ```
100 This represents a set of rules that are basically this:
102     repo    user        perm    ref                 (from line)
104      foo     @managers  R                                3
105      foo     alice      RW+      refs/.*                 9
106      foo     @teamleads RW+      refs/.*                 9
107      foo     dilbert    -        refs/heads/master       10
108      foo     @devteam   -        refs/heads/master       10
109      foo     dilbert    -        refs/tags/v[0-9]        11
110      foo     @devteam   -        refs/tags/v[0-9]        11
111      foo     dilbert    RW+      refs/heads/dev/         12
112      foo     @devteam   RW+      refs/heads/dev/         12
113      foo     dilbert    RW       refs/.*                 13
114      foo     @devteam   RW       refs/.*                 13
115      foo     @managers  R                                14
117 Which of these rules apply for dilbert?  We'll assume he's not a team lead, as
118 *that* would defeat the whole purpose of this example!  We *know* he's not a
119 manager, as that would defeat the whole purpose of the comic! Finally, we
120 assume he's also not part of "@devteam", (otherwise why would you name him
121 separately in all those lines?).
123 So we discard all those rules, which leaves us, for repo "foo" and user
124 "dilbert":
126     perm    ref                 (from line)
128     -        refs/heads/master       10
129     -        refs/tags/v[0-9]        11
130     RW+      refs/heads/dev/         12
131     RW       refs/.*                 13
133 So what happens when dilbert tries to push a branch called "xyz"?
135 At check #1, the data gitolite has is that "oper" is "W" (and ref of course is
136 unknown).  We discard lines 10 and 11 (the `deny-rules` option is off by
137 default, so we ignore `-` rules).  Line 12 supplies a perm of "RW+", which
138 contains "W" (the "oper") so access is allowed.
140 At check #2, the data gitolite has is that "oper" is "W" and ref is
141 `refs/heads/xyz`.  We discard the first three rules, since the ref does not
142 match any of those refexes.  That leaves just line 13.
144 If the push were a fast-forward push, the "oper" would be "W", and since it is
145 contained in the perm for rule 13, access is allowed.
147 However, if he were to try a rewind-push, then the "oper" would be "+", which
148 is not contained in "RW", it wouldn't match, then control would go back for
149 the *next* rule, and since there aren't any more, access would be denied.
151 ----
153 # tracing the access control decision
155 <span class="gray">(v3.6.1)</span> Gitolite can help you trace this logic quickly and easily.
156 Here's one example run, with the above rules.  This one tests whether dilbert
157 can push to repo foo (check #1).  Note that the syntax for specifying an
158 unknown ref in this command is 'any'.
160     $ gitolite access -s foo dilbert W any
161     legend:
162         d => skipped deny rule due to ref unknown or 'any',
163         r => skipped due to refex not matching,
164         p => skipped due to perm (W, +, etc) not matching,
165         D => explicitly denied,
166         A => explicitly allowed,
167         F => denied due to fallthru (no rules matched)
169       d        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
170       d        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
171       A        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam
173     refs/heads/dev/
175 Now see what happens when we try check #2 (we've omitted the legend in the
176 output, since it's always the same):
178     $ gitolite access -s foo dilbert W xyz
180       r        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
181       r        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
182       r        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam
183       A        gitolite.conf:13         RW  refs/.*             =   dilbert @devteam
185     refs/.*
187 And if you try a force push:
189     $ gitolite access -s foo dilbert + refs/heads/xyz
191       r        gitolite.conf:10         -   refs/heads/master   =   dilbert @devteam
192       r        gitolite.conf:11         -   refs/tags/v[0-9]    =   dilbert @devteam
193       r        gitolite.conf:12         RW+ refs/heads/dev/     =   dilbert @devteam
194       p        gitolite.conf:13         RW  refs/.*             =   dilbert @devteam
195       F           (fallthru)
197     + refs/heads/xyz foo dilbert DENIED by fallthru
199 I hope that was useful!  Be sure you correlated the output of 'gitolite access
200 -s' with the rule workflow pictures and corresponding descriptions to cement
201 your understanding.
203 # read access respecting deny rules
205 Normally, deny rules are ignored by access check #1 (the one that runs
206 *before* git-upload-pack or git-receive-pack is called by gitolite-shell);
207 they apply only to check #2 (the update hook check).
209 But sometimes you want this "pre-git" access check to respect deny rules;
210 i.e., use the flow of check #2, not check #1.  You tell gitolite to do this by
211 setting the "deny-rules" option for the repo; when you do that, the flow of
212 check #2 is used for both stages, before git *and* in the update hook.
214 ## example 1
216 Here's an example. Here, we have lots of repos, which should all be accessible
217 by gitweb or daemon, so we want the convenience provided by lines 6 and 7 (we
218 don't want to put line 7 in *each* repo).  However, we also have some secret
219 repos (maybe the gitolite-admin repo and some others that we will list), which
220 we want to prevent gitweb or daemon from seeing.
222 How do we do that?
224 The naive approach -- putting in a deny rule just for those repos -- doesn't
225 work.  In fact nothing else seems to work either; you'll have to replace the
226 `@all` with an exhaustive list of *all repos other than the secret repos*.
228 ```gitolite-nu
229 @secret = gitolite-admin secret-repo/..*
230 repo @secret
231     -   =   gitweb daemon
234 repo @all
235     R   =   gitweb daemon
237 # ...other repos and rules...
240 That's... painful!
242 What you really want is for that repo to always use check #2, even when it
243 doesn't actually have a ref to test for.
245 ```gitolite-nu
246 @secret = gitolite-admin secret-repo/..*
247 repo @secret
248     -   =   gitweb daemon
249     option deny-rules = 1
251 repo @all
252     R   =   gitweb daemon
254 # ...other repos and rules...
257 This is done by adding *one* line, line 4 in this example.  This sets a
258 gitolite ["option"](options) that says you want "deny rules" to be applicable
259 even for read access.
261 Once you do that, all you need to do is to ensure that the first rule
262 encountered by these two "users" for those repos is a deny rule, so that it
263 can take effect first.  In this example, the placement of lines 2, 3 vis-a-vis
264 lines 6, 7 matters -- don't switch them!
266 ## example 2
268 In this example the "open" repos are fewer in number, so it is the opposite
269 situation to the above in terms of our ability to enumerate all the repos.
271 ```gitolite
272 @open = git gitolite foss/..* [...]
274 repo @all
275     -   =   gitweb daemon
276     option deny-rules = 1
278 repo @open
279     R   =   gitweb daemon
280     option deny-rules = 0
283 To see why this works, you need to understand that for [options](options) and
284 [config](git-config) lines, a later setting [overrides][override_conf] earlier
285 ones.  So we set it to 1 for all repos, then selectively set it to 0 for some.
287 This means the "deny-rules" option applies to *all the repos except the "open"
288 repos*, and so the first rule encountered by gitweb and daemon is a deny rule,
289 so they are denied read access.  The "open" repos, on the other hand, get the
290 normal default behaviour, which is to ignore deny rules for read access, and
291 thus they only see the "R" permission.
293 [override_conf]: git-config#overriding-config-values
295 ----
297 # appendix 1: different types of write operations
299 Git supplies enough information to the update hook to be able to distinguish
300 several types of writes.
302 The most common are:
304   * `RW` -- create a ref or fast-forward push a ref.  No rewinds or deletes.
305   * `RW+` -- create, fast-forward push, rewind push, or delete a ref.
307 Sometimes you want to allow people to push, but not *create* a ref.  Or
308 rewind, but not *delete* a ref.  The `C` and `D` qualifiers help here.
310   * If a rule specifies `RWC` or `RW+C`, then *rules that do NOT have the C
311     qualifier will no longer permit **creating** a ref in that repo*.
313     <font color="gray">Please do not confuse this with the standalone `C`
314     permission that allows someone to [create][] a **repo**</font>
316   * If a rule specifies `RWD` or `RW+D`, then *rules that do NOT have the D
317     qualifier will no longer permit **deleting** a ref in that repo*.
319 [create]: wild#user-creating-a-specific-repo
321 Note: These two can be combined, so you can have `RWCD` and `RW+CD` as well.
323 One very rare need is to reject merge commits (a commit series that is not a
324 straight line of commits).  The `M` qualifier helps here:
326   * When a rule has `M` appended to the permissions, *rules that do NOT have
327     it will reject a commit sequence that contains a merge commit* (i.e., they
328     only accept a straight line series of commits).
330 ## summary of permissions
332 The full set of permissions, in regex syntax, is `-|R|RW+?C?D?M?`.  This
333 expands to one of `-`, `R`, `RW`, `RW+`, `RWC`, `RW+C`, `RWD`, `RW+D`, `RWCD`,
334 or `RW+CD`, all but the first two optionally followed by an `M`.
336 ----
338 # appendix 2: gitolite access check flow
340 Here's lots more detail on the access check process, with flow diagrams.
342 When do the access checks happen and what are the four pieces of data (repo,
343 user, operation, ref) in each case?
345 read        | write
346 ----------- | -------------
347 ![](a1.png) | ![](a2.png)
349 In these pictures the access checks are marked in yellow.
351 The picture on the left is for a read (git clone, fetch, ls-remote).  There is
352 only one access check for a read operation.  If access is denied, the
353 operation aborts.  Otherwise, gitolite-shell invokes git-upload-pack.
355 Notice the information available to the access check.  The "oper" (operation)
356 is "R", indicating a read operation.  The "ref" is listed as "unknown",
357 although we could also call it "irrelevant"!
359 **Access check #1** proceeds with those 4 bits of information, and either
360 passes or fails.  If it passes, gitolite passes control to "git-upload-pack"
361 and its job is done.
363 ----
365 The flow for a push operation (the picture on the right) is *very* similar
366 upto the first access check. The "oper" is "W" now, although the "ref" is
367 still unknown. <span class="gray">Even though this *is* a push, at this stage in the
368 protocol nothing on the server knows what branch or tag or combination of them
369 are coming down the wire, since we haven't executed git-receive-pack
370 yet!</span>
372 If it succeeds, gitolite passes control to "git-receive-pack", but its job is
373 not done yet.  *Git* will eventually invoke the update hook (see 'man
374 githooks'). Gitolite has already grabbed this hook, which receives from git
375 the ref name being pushed, as well as enough information to compute whether
376 this push is a "fast-forward push" or a "rewind push".  Based on this,
377 gitolite sets the "oper" field to "W" or "+", respectively.
379 **Access check #2** proceeds with this information.  The result is sent back
380 to git-receive-pack (in the form of an exit code; again, see 'man githooks'),
381 and the push fails or succeeds based on that.
383 [c1c2]: conf#putting-it-all-together
385 ## putting it all together
387 At this point, we have the following pieces of information:
389 *   A set of rules, each containing 4 pieces of data: repo, user, perm, refex.
390     They are in the sequence they were found in the conf file.
392     We discard all rules that do not apply to this repo and this user, which
393     means our set of rules have only two fields: perm, refex.
395     As a quick reminder, perm is one of R, RW, RW+, or `-`.
397 *   Four elements that make up the access being attempted: repo, user, oper,
398     ref.
400     Again, as a reminder, the "oper" is **one letter**.  For "check #1" it is
401     either R or W, and for check #2 it can be W or +.
403 <span class="gray">Note on permissions and "oper": there are other [types of
404 permissions][write-types], but for our discussion these are enough.  The
405 others are rare, and anyway it is easy to extrapolate to them.</span>
407 [write-types]: conf-2#appendix-1-different-types-of-write-operations
409 With that background, here's the flow.  The one on the left is for check #1
410 (ref is unknown) while the one on the right is for check #2 (ref is known).
412 ref unknown | ref known
413 ----------- | -------------
414 ![](a3.png) | ![](a4.png)
416 As you can see, deny rules are ignored by check #1 -- they're not tested in
417 any way.  For check #2, if there is a deny rule whose refex matched the ref,
418 access is denied (as you'd expect).
420 # appendix 3: embedding test code in your conf
422 As of v3.6.7, it is possible to embed test code within gitolite.conf.  This
423 can be useful if your conf file is complicated, and you need a way to make
424 sure that any changes are not messing with your most important restrictions.
426 Full details, including preparation and caveats, are in
427 `contrib/utils/testconf`, but here's a teaser example:
429     repo foo
430         RW+     =   u1
431         RW      =   u2
433     =begin testconf
434     gitolite access -q foo u1 + any || echo FAILED
435     gitolite access -q foo u2 + any && echo FAILED
436     gitolite access -q foo u2 W any || echo FAILED
437     =end