From 4f7d3d86515099774d6f1df869e40e89aa635119 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Fri, 16 Mar 2012 07:24:47 +0530 Subject: [PATCH] Q: all doc stuff --- doc/add.mkd | 34 +++ doc/commands.mkd | 26 ++ doc/conf.mkd | 31 +++ doc/cust.mkd | 23 ++ doc/dev-notes.mkd | 116 ++++++++ doc/dev-status.mkd | 35 +++ doc/extras/auth.mkd | 89 ++++++ doc/extras/gitolite-and-ssh.mkd | 145 ++++++++++ doc/extras/nagp.mkd | 64 +++++ doc/extras/regex.mkd | 34 +++ doc/extras/ssh-troubleshooting.mkd | 427 +++++++++++++++++++++++++++++ doc/extras/ssh.mkd | 11 + doc/extras/unique.mkd | 6 + doc/g2alt.mkd | 10 + doc/g2dropped.mkd | 2 + doc/g2incompat.mkd | 35 +++ doc/g2migr.mkd | 122 +++++++++ doc/g3why.mkd | 97 +++++++ doc/group.mkd | 32 +++ doc/hooks.mkd | 9 + doc/index.mkd | 67 +++++ doc/install.mkd | 58 ++++ doc/list | 43 +++ doc/minreq.mkd | 32 +++ doc/misc.mkd | 80 ++++++ doc/mkdoc | 88 ++++++ doc/pw.mkd | 45 +++ doc/qi.mkd | 26 ++ doc/rc.mkd | 20 ++ doc/refex.mkd | 30 ++ doc/repo.mkd | 23 ++ doc/rules.mkd | 82 ++++++ doc/sugar.mkd | 11 + doc/testing.mkd | 31 +++ doc/triggers.mkd | 90 ++++++ doc/users.mkd | 96 +++++++ doc/vref.mkd | 254 +++++++++++++++++ doc/why.mkd | 46 ++++ doc/write-types.mkd | 31 +++ dot.pl | 31 +++ 40 files changed, 2532 insertions(+) create mode 100644 doc/add.mkd create mode 100644 doc/commands.mkd create mode 100644 doc/conf.mkd create mode 100644 doc/cust.mkd create mode 100644 doc/dev-notes.mkd create mode 100644 doc/dev-status.mkd create mode 100644 doc/extras/auth.mkd create mode 100644 doc/extras/gitolite-and-ssh.mkd create mode 100644 doc/extras/nagp.mkd create mode 100644 doc/extras/regex.mkd create mode 100644 doc/extras/ssh-troubleshooting.mkd create mode 100644 doc/extras/ssh.mkd create mode 100644 doc/extras/unique.mkd create mode 100644 doc/g2alt.mkd create mode 100644 doc/g2dropped.mkd create mode 100644 doc/g2incompat.mkd create mode 100644 doc/g2migr.mkd create mode 100644 doc/g3why.mkd create mode 100644 doc/group.mkd create mode 100644 doc/hooks.mkd create mode 100644 doc/index.mkd create mode 100644 doc/install.mkd create mode 100644 doc/list create mode 100644 doc/minreq.mkd create mode 100644 doc/misc.mkd create mode 100755 doc/mkdoc create mode 100644 doc/pw.mkd create mode 100644 doc/qi.mkd create mode 100644 doc/rc.mkd create mode 100644 doc/refex.mkd create mode 100644 doc/repo.mkd create mode 100644 doc/rules.mkd create mode 100644 doc/sugar.mkd create mode 100644 doc/testing.mkd create mode 100644 doc/triggers.mkd create mode 100644 doc/users.mkd create mode 100644 doc/vref.mkd create mode 100644 doc/why.mkd create mode 100644 doc/write-types.mkd create mode 100644 dot.pl diff --git a/doc/add.mkd b/doc/add.mkd new file mode 100644 index 0000000..21d1a61 --- /dev/null +++ b/doc/add.mkd @@ -0,0 +1,34 @@ +# adding users and repos + +Do NOT add repos directly on the server. Clone the 'gitolite-admin' repo to +your workstation, make changes to it, then add, commit, and push. When the +push hits the server, the server "acts" upon your changes. + +Full documentation on the conf file is [here][conf]. + +Here's a sample sequence, on your workstation, after your install is done + + git clone git@host:gitolite-admin + cd gitolite-admin + vi conf/gitolite.conf + + # now add lines like these: + repo foo + RW+ = me + RW = alice + R = wally + # now save the file and add it + git add conf + + # add a couple of users; get their pubkeys by email or something, then: + cp /some/where/alice.pub keydir + cp /else/where/wally.pub keydir + git add keydir + + # now commit and push + git commit -m 'added repo foo' + git push + + # at this point gitolite will create the new repo 'foo' (if it did not + # already exist) then update the authorized keys file to include alice and + # wally's pubkeys diff --git a/doc/commands.mkd b/doc/commands.mkd new file mode 100644 index 0000000..da2baa4 --- /dev/null +++ b/doc/commands.mkd @@ -0,0 +1,26 @@ +# gitolite "commands" + +Gitolite comes with several commands that users can run. Remote user run the +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 only a subset of what the server user will +see. + +You add commands to the "allowed from remote" list by adding its name (or +uncommenting it if it's already added but commented out) to the COMMANDS hash +in the [rc][] file. + +If you write your own commands, put them in src/commands. + +**Note that this is also the place that all triggered programs go**. In fact, +all standalone programs related to gitolite go here. diff --git a/doc/conf.mkd b/doc/conf.mkd new file mode 100644 index 0000000..15c3756 --- /dev/null +++ b/doc/conf.mkd @@ -0,0 +1,31 @@ +# the gitolite.conf file + +This file is the crux of all of gitolite's access control. The basic syntax +is very simple. + +Note: `+` means one or more user or user group names, `+` means +one or more repo or repo group names, and `*` means zero or more +refexes. + + * [group][group] definitions (optional, for convenience) + + @ = + + @ = + + + * [repo][repo] definitions and access [rules][] + + repo + + * = + + # one or more such lines + + * [gitolite options][options] that apply to the repo(s) in the last + "repo ..." line, for example: + + option deny-rules = 1 + + * [git config][git-config] keys and values that also apply to the last named + repo(s), for example: + + config hooks.emailprefix = '[%GL_REPO] ' + +In addition, you can also have [include][] statements. diff --git a/doc/cust.mkd b/doc/cust.mkd new file mode 100644 index 0000000..fb79b21 --- /dev/null +++ b/doc/cust.mkd @@ -0,0 +1,23 @@ +# customising gitolite + +Here are the ways you can customise gitolite on the server. + +First, learn about: + + * [git hooks][hooks] and [virtual refs][vref] + + * [commands][] for your [users][] to run own][dev-notes] + + * [triggers][] to be run by gitolite as various points in its execution + + * [syntactic sugar][sugar] to change the conf language for your convenience + +For all of the above: + + * [edit the rc file][rc] to enable optional features that are shipped in a + disabled state + + * [write your own][dev-notes] + +(Note: "trigger" is the same concept as "hook", applied to gitolite; I just +chose a different name to avoid constant ambiguity in documentation). diff --git a/doc/dev-notes.mkd b/doc/dev-notes.mkd new file mode 100644 index 0000000..854c547 --- /dev/null +++ b/doc/dev-notes.mkd @@ -0,0 +1,116 @@ +# notes for developers + +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. + +Hints for developers wishing to help migrate features over from g2 are +[here][dev-hints]. + +Here are some random notes on developing hooks, commands, triggers, and sugar +scripts. + +## environment variables + +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. + +## 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: none yet + + * `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/Gitolite/Easy.pm (the +perl API module) for ideas. + +### the perl API + +...is implemented by Gitolite::Easy; see src/Gitolite/Easy.pm. This is a work +in progress; for example it does not yet have the equivalent of `gitolite +git-config`. I'll add it when I or someone else needs it. + +## your own hooks + +### anything but the update hook + +If you want to add your own hook, it's easy as long as it's not the 'update' +hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`. + +The rest is between you and 'man githooks' :-) + +### 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 to src/VREF. Let's say it is called "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 now 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. + +## your own commands + +You can add your own commands. You can run them on the server (example, +`gitolite access`). Then you can enable certain commands to be allowed to run +by a remote user by adding them to the "COMMANDS" hash of the [rc][] file. + +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. + +## your own trigger programs + +Trigger programs are just commands whose names have been added to the +appropriate list in the [rc][] file. Triggers get specific arguments +depending on when they are called; see [here][triggers] 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. + +Look in the distributed [rc][] file for example programs; at this point there +aren't many. + +## your own "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. + diff --git a/doc/dev-status.mkd b/doc/dev-status.mkd new file mode 100644 index 0000000..29ae450 --- /dev/null +++ b/doc/dev-status.mkd @@ -0,0 +1,35 @@ +## #dev-status g3 development status + +Not yet done (will be tackled in this order unless someone asks): + + * detailed documentation for new features + * querying the outside world for group info (see gl-get-membership-program + in g2) + * mirroring + * pulling in documentation for things that are the same in g2 + * "unrestricted arguments" for some ADCs (like git-annexe) + * smart http + * special features (no-create-repos, shell-access, gl-all-read-all, etc) + +Help needed: + + * I'd like distro packagers to play with it and help with migration advice + for distro-upgrades + * [rsync][pw2], htpasswd + * 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 + * 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 + * some documentation + * distro packaging instructions + * migration advice for common cases diff --git a/doc/extras/auth.mkd b/doc/extras/auth.mkd new file mode 100644 index 0000000..0918f07 --- /dev/null +++ b/doc/extras/auth.mkd @@ -0,0 +1,89 @@ +# 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][ssh-troubleshooting]. + +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][gitolite-and-ssh], you +know that gitolite is meant to be invoked as: + + /full/path/to/gl-auth-command 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 there! + +The default mode of using gitolite does use ssh keys, but all it's doing is +helping you **setup** ssh-based authentication **as a convenience to you**. + +You don't have to use it, though. And many people don't. The examples I know +are [smart http][http], and ldap-backed sshd. In both cases, gitolite has no +role to play in creating users, setting up their passwords/keys, etc. There's +even a `GL_NO_SETUP_AUTHKEYS` option to make sure gitolite doesn't meddle with +the authkeys file in such installations. + +## 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 *probably* won't. I'm willing to change +my mind if enough people convince me they need it. (There's a mailing list if +you want to find others who also need the same thing.) + +While we're on the subject, locking someone out is *not* a security issue. +Even if you locked yourself (the admin) out, 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. + +## appendix: 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. + +Finally, gitolite allows you to store *group* information externally too. See +[here][ldap] for more on this. + diff --git a/doc/extras/gitolite-and-ssh.mkd b/doc/extras/gitolite-and-ssh.mkd new file mode 100644 index 0000000..380b81c --- /dev/null +++ b/doc/extras/gitolite-and-ssh.mkd @@ -0,0 +1,145 @@ +## #glssh how gitolite uses ssh + +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]/gl-auth-command sitaram",[more options] ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA18S2t... + command="[path]/gl-auth-command 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]/gl-auth-command 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 `gl-auth-command` 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/nagp.mkd b/doc/extras/nagp.mkd new file mode 100644 index 0000000..7f783db --- /dev/null +++ b/doc/extras/nagp.mkd @@ -0,0 +1,64 @@ +# not a gitolite problem + +These are issues I do not want to be emailed about. That does not mean you +cannot get help -- in all cases, you're welcome to ask on [irc or the mailing +list][contact]. Irc especially has people with much more patience than I +have, God bless them... + +## specific clients, or specific server OSs + +These are things I can not support. That does not mean they will not work +with gitolite -- on the contrary, lots of people are using them. + +But I personally don't use them, and I won't use them, and in my admittedly +limited experience they have given me good reason to stay well away. + +Please ask for help on the [mailing list or IRC][contact]. Please do not +email me directly. + + * putty/plink + * jgit/Eclipse + * Mac OS client or server + * windows as a server + * ...probably some more I forgot; will update this list as I remember... + +## 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 + +Example 1: when a first `git push` to a new repo fails, it is not because of +gitolite, it is because you need to say `git push origin master` or something. +This is a git issue. + +There are several such examples. 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 a 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> + +---- + +In addition, the original nagp has more funny stuff... diff --git a/doc/extras/regex.mkd b/doc/extras/regex.mkd new file mode 100644 index 0000000..c334c2c --- /dev/null +++ b/doc/extras/regex.mkd @@ -0,0 +1,34 @@ +# 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-troubleshooting.mkd b/doc/extras/ssh-troubleshooting.mkd new file mode 100644 index 0000000..aeee3d9 --- /dev/null +++ b/doc/extras/ssh-troubleshooting.mkd @@ -0,0 +1,427 @@ +## #sshts ssh troubleshooting + +**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. + +### 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 knew it, 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`). + +### (Other resources) + +People who think installing gitolite is too hard should take a look at this +[tutorial][tut] to **see how simple it *actually* is**. + +### 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][stsapp2_] and continue with +the rest in sequence. [Appendix 5][stsapp5_] 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_RC` 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][stsapp2_]. + + * 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][sshhostaliases]. + +### random tips, tricks, and notes + +#### giving shell access to gitolite users + +We've managed (thanks to an idea from Jesse Keating) to make it possible for a +single key to allow both gitolite access *and* shell access. + +This is done by copying the pubkey (to which you want to give shell access) to +the server and running + + gl-tool add-shell-user ~/foo.pub + +**IMPORTANT UPGRADE NOTE**: previous implementations of this feature were +crap. There was no easy/elegant way to ensure that someone who had repo admin +access would not manage to get himself shell access. + +Giving someone shell access requires that you should have shell access in the +first place, so the simplest way is to enable it from the server side only. + +#### losing your admin key + +If you lost the admin key, and need to re-establish ownership of the +gitolite-admin repository with a fresh key, get a shell on the server and use +the program called `gl-admin-push` that comes with gitolite. See instructions +[here][adminpush]. + +#### 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) results in: + + WARNING: a pubkey file can only have one line (key); ignoring YourName.pub + +To convert ssh2-compatible keys to openssh run: + + 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 [contrib/putty.mkd][contrib_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 `gl-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! + + * 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 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. + +### #stsapp2_ appendix 2: which key is which -- running sshkeys-lint + +Follow these steps on the client: + + * get a copy of `~/.ssh/authorized_keys` from the server and put it in + `/tmp/foo` or something + + * cd to `~/.ssh` + + * run `sshkeys-lint *.pub < /tmp/foo` + +This tells you, for each pubkey, what type of access (if any) it has to the +server. + +Note that it is not trying to log in or anything -- it's just comparing bits +of text (the contents of STDIN taken as an authkeys file, and the contents of +each of the `*.pub` files one by one). + +> Note: It's also a stand-alone program, so even if your gitolite version is +> old, you can safely bring over just this program from a more recent +> gitolite and use it, without having to upgrade gitolite itself. + +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 `gl-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 `gl-setup 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][sshhostaliases]). + + * (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. + +### F=sshhostaliases appendix 4: 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 + +### #stsapp5_ 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 `gl-auth-command`. + +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/extras/ssh.mkd b/doc/extras/ssh.mkd new file mode 100644 index 0000000..a5ee5d4 --- /dev/null +++ b/doc/extras/ssh.mkd @@ -0,0 +1,11 @@ +# ssh + +There are two documents you need to read, in order: + + * [gitolite and ssh][glssh] -- this explains how gitolite uses openssh's + features to provide any number of virtual users over just one actual + (unix) user, and so on + + * [ssh troubleshooting][sshts] -- this is a rather long document but as far + as I know almost every known ssh related issue is in here. If you find + something missing, send me an email with details. diff --git a/doc/extras/unique.mkd b/doc/extras/unique.mkd new file mode 100644 index 0000000..3864769 --- /dev/null +++ b/doc/extras/unique.mkd @@ -0,0 +1,6 @@ +# unique setups + +This page is for unique setups that I support. At present there is only one +-- Fedora. + + diff --git a/doc/g2alt.mkd b/doc/g2alt.mkd new file mode 100644 index 0000000..a578805 --- /dev/null +++ b/doc/g2alt.mkd @@ -0,0 +1,10 @@ +## #g2alt alternate implementations for some g2 features + +The following g2 features have been dropped but suitable (or better) +alternatives exist. + +### gl-time for performance measurement + +Take a look at the 'cpu-time' program that you can set to run from the +`POST_GIT` trigger. Just set it to run as the last program in that sequence +so it covers all previous programs. diff --git a/doc/g2dropped.mkd b/doc/g2dropped.mkd new file mode 100644 index 0000000..ab5f63c --- /dev/null +++ b/doc/g2dropped.mkd @@ -0,0 +1,2 @@ +## #g2dropped g2 features dropped + diff --git a/doc/g2incompat.mkd b/doc/g2incompat.mkd new file mode 100644 index 0000000..c425ec2 --- /dev/null +++ b/doc/g2incompat.mkd @@ -0,0 +1,35 @@ +## #g2incompat compatibility with g2 + +The following incompatibilities exist, in vaguely decreasing order of +severity. **The ones in the first section are IMPORTANT because they allow +access that was previously not allowed -- please fix your config before using +the new gitolite!** + +### fallthru in NAME rules + +Fallthru on all VREFs is "success" now, so any NAME/ rules you have **MUST** +change the ruleset in some way. The simplest is to add the following line to +the end of each repo's rule list: + + - NAME/ = @all + +### subconf command in admin repo + +(This is also affected by the previous issue, 'fallthru in 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 + - 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. diff --git a/doc/g2migr.mkd b/doc/g2migr.mkd new file mode 100644 index 0000000..21cc4b2 --- /dev/null +++ b/doc/g2migr.mkd @@ -0,0 +1,122 @@ +## #g2migr migrating from g2 + + + +**This document is a *MUST* read if you are currently using g2 and want to +move to g3.** + + + +First things first: g2 will be supported for a good long time. My current +*expert* users do not cause me any load anyway. + +Migration should be straightforward, but it is not automatic. When you first +run "gitolite setup [...]", gitolite3 will try to detect at least the big +problems. However, converting the RC file and the conf files is (as of now) +still a manual exercise, though not very difficult. + +You must first read about [incompatible][g2incompat] features and +[dropped][g2dropped] features. Some features have been replaced with +[alternatives][g2alt]. + +Since the majority of changes are in the rc file, we list them all here. + +### rc file differences + +**DROPPED** variables (possible high impact): these could be show-stoppers for +migration, at least for now. + + * `BIG_INFO_CAP` -- 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_ALL_READ_ALL` -- same + + * `GL_NO_CREATE_REPOS` -- 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. + + * `HTPASSWD_FILE`, `RSYNC_BASE`, `SVNSERVE` -- need work. Email me if you + are using any of these. + + * `GL_GET_MEMBERSHIPS_PGM` -- is on my todo list + + * `GL_LOGT` -- is now fixed; you can't change it. Email me if this is a + problem. + +**DROPPED** variables (medium impact): these have alternative implementations +or mechanisms, but you have to do some setup work. + + * `GL_ADMINDIR` -- this 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. + + * `REPO_BASE` -- this 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. + + * `PROJECTS_LIST` -- it's called `GITWEB_PROJECTS_LIST` now, but 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. + + `WEB_INTERFACE` and `GITWEB_URI_ESCAPE` are also gone; patches to the + update program to directly do those things are welcome. + + * `GL_NO_DAEMON_NO_GITWEB` -- uncomment the appropriate lines in the rc + file, in both the `POST_COMPILE` and `POST_CREATE` trigger sections. + + * `NICE_VALUE` -- use the `PRE_GIT` trigger to attach a program that renices + the pid given by $GL_TID (that's the pid of the initial gitolite entry + point, usually gitolite-shell, and propagates from there once set). + + You may have to add this list to the rc file; if you don't know perl use + one of the others as a model or ask me. + + * `GIT_PATH` -- gone, not needed. Just add these lines to the end of the rc + file: + + $ENV{PATH}="...whatever you want..."; + 1; + + * `GL_NO_SETUP_AUTHKEYS` -- comment out the lines that call ssh-authkeys, in + the rc file. + + * `GL_WILDREPOS_DEFPERMS` -- if you need this, add a `POST_CREATE` script + that does it. Or email me and I will write it for you. + + * `UPDATE_CHAINS_TO` -- use a [vref][] instead. You can directly use the + chained-to script as a VREF; it'll work. + + * `ADMIN_POST_UPDATE_CHAINS_TO` -- add your script to the `POST_COMPILE` + trigger chain. You won't be getting any arguments but for the admin repo + the only argument that ever comes in is "refs/heads/master" anyway. + + * `GL_ADC_PATH` -- obsolete; use [commands][] or add [your own][dev-notes]. + + * `GL_ALL_INCLUDES_SPECIAL` -- obsolete; @all always includes gitweb and + daemon now. Use [deny-rules][] if you want to say `R = @all` but not have + it be visible to gitweb or daemon. + + * `GL_PERFLOGT` -- see the entry for "gl-time" in the [alternative + implementations][g2alt] page. + +**DROPPED** variables (no impact/low impact): these variables should not +actually affect anything anyway, so even if you had them set you should not +feel their loss. + + * `GL_CONF`, `GL_KEYDIR`, and `GL_CONF_COMPILED` -- you had no business + touching these anyway; if you did, move them into the expected default + locations before attempting to run `gitolite setup` + * `GL_PACKAGE_HOOKS` -- not needed anymore, but check if you had any custom + hooks set there and copy them across. + * `GL_WILDREPOS` -- dropped; this feature is default now. + * `GL_BIG_CONFIG` -- dropped; this feature is default now. + +**RENAMED** variables (no impact): these are functionally the same but are +renamed. + + * `REPO_UMASK` is now `UMASK` + * `GL_GITCONFIG_KEYS` is now `GITCONFIG_KEYS` + * `GL_WILDREPOS_PERM_CATS` is now the ROLES hash in the rc file + * `GL_SITE_INFO` is not `SITE_INFO` diff --git a/doc/g3why.mkd b/doc/g3why.mkd new file mode 100644 index 0000000..ae6cad0 --- /dev/null +++ b/doc/g3why.mkd @@ -0,0 +1,97 @@ +# 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/group.mkd b/doc/group.mkd new file mode 100644 index 0000000..f9e14b0 --- /dev/null +++ b/doc/group.mkd @@ -0,0 +1,32 @@ +# parts of the conf file + +## #group 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/hooks.mkd b/doc/hooks.mkd new file mode 100644 index 0000000..499714d --- /dev/null +++ b/doc/hooks.mkd @@ -0,0 +1,9 @@ +# hooks and gitolite + +Gitolite uses the `update` hook for all repos. In addition, it uses the +`post-update` hook for the gitolite-admin repo. + +If you want to add your own hook, it's easy as long as it's not the 'update' +hook. Just add it to `$HOME/.gitolite/hooks/common` and run `gitolite setup`. + +The rest is between you and 'man githooks' :-) diff --git a/doc/index.mkd b/doc/index.mkd new file mode 100644 index 0000000..0756294 --- /dev/null +++ b/doc/index.mkd @@ -0,0 +1,67 @@ +# 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. + +For current gitolite (call it "g2" for convenience) users, + + * [Why][g3why] I rewrote gitolite. + * Development [status][dev-status] (**should change often for a while**) + * Specific migration [issues and steps][g2migr]. + +Quick links: + + * [Minimum requirements][minreq]. + * Here's how to [get started][qi] installing and setting it up + * Don't know ssh well enough? [Learn][ssh]. It's **IMPORTANT**. + * [Add users and repos][add]. + * Learn about fine-grained access control with the [conf][] file + * Explain gitolite to your [users][]. + +Not so "quick" links: + + * The "master table of contents" link at the top of each page is the + **first** place you should check when looking for anything. + + * Want to do more than just add users and repos and control their access? + Here's how to [customise][cust] your server installation. + +Additional reading for Unix newbies: + + * [Regular Expressions][regex] + +## #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 + httpd 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 new file mode 100644 index 0000000..bc08162 --- /dev/null +++ b/doc/install.mkd @@ -0,0 +1,58 @@ +# different ways to install gitolite + +Gitolite has only one server side "command" now, much like git itself. And +it's been designed so that you don't even really have to *install* it, as you +will see. + +## simplest + +1. Put all of `src` in one place, doesn't matter where; let's call it + /foo/bar. + +2. Use the full path to run any gitolite commands, for example: + + /foo/bar/gitolite setup -pk sitaram.pub + +## almost as simple + +1. (same as above) + +2. Symlink /foo/bar/gitolite to some directory that is on your PATH. For + example: + + ln -sf /foo/bar/gitolite ~/bin + + Now you can just say + + gitolite setup -pk sitaram.pub + +## packagers + +1. Put src/Gitolite in `/usr/share/perl5/vendor_perl` or some such place. + +2. Put the rest of src anywhere your distro policy allows. (Fedora keeps + git's 150 executables in /usr/libexec/git-core, so maybe + /usr/libexec/gitolite?) + +3. Symlink 'gitolite' to /usr/bin or something, similar to step 2 above, + + OR + + Put it directly in /usr/bin, and hardcode `GL_BINDIR` into it to tell it + where the others are. I'd prefer it if you did not do this but you can. + +---- + +Bottom line: + + * `GL_BINDIR` must point to a place that contains `commands`, `VREF`, and + `syntactic-sugar` (so they must all be sibling directories). + * The `Gitolite` directory can also be there, or it can be anywhere in + perl's `@INC` path. + +## upgrading + +Just put the new version on top of wherever you kept the old one. That's it. + +If you feel it should require a little more effort, pretend I said "you have +to then run `gitolite setup`". Can't hurt... diff --git a/doc/list b/doc/list new file mode 100644 index 0000000..b9f7411 --- /dev/null +++ b/doc/list @@ -0,0 +1,43 @@ + +index.mkd +why.mkd + +g3why.mkd +dev-status.mkd +g2migr.mkd +g2incompat.mkd +g2dropped.mkd +g2alt.mkd + +minreq.mkd +qi.mkd +install.mkd +add.mkd +conf.mkd +users.mkd + +rc.mkd +cust.mkd + +group.mkd +repo.mkd +rules.mkd +refex.mkd +write-types.mkd + +dev-notes.mkd +commands.mkd +hooks.mkd +triggers.mkd +sugar.mkd +vref.mkd + +misc.mkd +pw.mkd +testing.mkd +extras/auth.mkd +extras/nagp.mkd +extras/regex.mkd +extras/ssh.mkd +extras/gitolite-and-ssh.mkd +extras/ssh-troubleshooting.mkd diff --git a/doc/minreq.mkd b/doc/minreq.mkd new file mode 100644 index 0000000..c3ab4f4 --- /dev/null +++ b/doc/minreq.mkd @@ -0,0 +1,32 @@ +# minimum requirements for gitolite + +**Client**: + + * git 1.6.6 or greater + * an ssh client that can talk to an openssh server, and can generate keys in + openssh's default format (the pubkey is just one long line). Gitolite + will [not currently][pw1] convert such keys. + +For people still using Windows, msysgit works fine. If you're using +[putty/plink][ens], God bless you. (It'll work, but I still want him to bless +you). + +TODO: when smart http support works, ssh will no longer be a *requirement*, +merely a *strong* suggestion :-) + +**Server** + + * git 1.6.6 or greater + * perl 5.8.8 or greater + * an ssh server compatible with openssh, especially it's authorized keys + file format and features. + * any Unix or Unix like OS. That said, I've occasionally had some weird + reports from [Mac OSX servers][ens]; good luck. + * a single, dedicated, userid to host it (usually 'git' or 'gitolite'). + +These version numbers are subject to fine-tuning as I get feedback and make +fixes where possible and needed. + +Sshd must be configured so that each users authkeys file is in the user's +`$HOME`, inside `.ssh/authorized_keys`, and not in some central +/var/something. diff --git a/doc/misc.mkd b/doc/misc.mkd new file mode 100644 index 0000000..0b8c9e7 --- /dev/null +++ b/doc/misc.mkd @@ -0,0 +1,80 @@ +# odds and ends + +Most of these items don't fit anywhere or fit in more than one place or are of +the nature of background information. + +## #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" from the "conf" directory. + +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 relative to the gitolite-admin repo's + "conf/" directory. + + * 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]. + +## #deny-rules applying deny rules at the pre-git access check + +The access [rules][] rules section describes the problem. To recap, you want +this: + + @staff = alice bob wally ashok + + repo foo + RW+ = alice # line 1 + RW+ dev = bob # line 2 + - = wally # line 3 + RW temp/ = @staff # line 4 + +to deny Wally even *read* access. + +The way to do this is to add this line to the repo: + + option deny-rules = 1 + +If you want this for all your repos, just add this somewhere at the top of +your conf file + + repo @all + option deny-rules = 1 + +## #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. diff --git a/doc/mkdoc b/doc/mkdoc new file mode 100755 index 0000000..3d977fc --- /dev/null +++ b/doc/mkdoc @@ -0,0 +1,88 @@ +#!/usr/bin/perl + +my $MKD = "$ENV{HOME}/Markdown.pl"; + +# run this like so: + +# $0 *.mkd >mt.mkd 2>mf + +use 5.10.0; +use strict; +use warnings; + +chomp(@ARGV = `cat list`) if not @ARGV; +@ARGV = grep { $_ ne 'master-toc.mkd' and /./ } @ARGV; +my @save = @ARGV; +my $css = join("", ); + +my $mt = "# gitolite master table of contents/index\n"; +my $mf = ''; +my $fh; + +while (<>) { + $ARGV =~ /^(?:.*\/)?([^\/]+)\.mkd$/; + my $b = $1; + + if (/^(#+) (?:#(\S+) )?(.*)/) { + if ( length($1) == 1 ) { + $mt .= "\n"; + $mt .= " * [$3][$b]\n"; + $mf .= "[$b]: $b.html\n"; + } else { + $mt .= " " x ( 4 * ( length($1) - 1 ) ); + $mt .= " * "; + $mt .= ( + $2 + ? "[$3][$2]" + : "$3" + ); + $mt .= "\n"; + $mf .= "[$2]: $b.html#$2\n" if $2; + } + } +} + +open($fh, ">", "master-toc.mkd") + 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 ("master-toc.mkd", @save) { + $mkd =~ /^(?:.*\/)?([^\/]+)\.mkd$/; + my $b = $1; + + open($fh, ">", "../html/$b.html") + and print $fh $css + and close $fh; + + my $mkt = `cat $mkd`; + $mkt =~ s/^(#+) #(\S+) /$1 <\/a> /mg; + open($fh, "|-", "$MKD >> ../html/$b.html") + and print $fh $mkt, $mf + and close $fh; +} + +__DATA__ + + + +

+ master TOC +| + main page +| + license +

diff --git a/doc/pw.mkd b/doc/pw.mkd new file mode 100644 index 0000000..ceaf995 --- /dev/null +++ b/doc/pw.mkd @@ -0,0 +1,45 @@ +# patches welcome :-) + +These are places where I could use some help, with hints about how you would +go about it. In addition, any of the items in [dev-status][] are up for +grabs, if you wish to jump in. But let me know before you start, and how you +plan to go about it. + +## #pw2 rsync + +The crux of the old rsync ADC was an access check to a repo whose name starts +with EXTCMD. g2 would treat repos whose names start with EXTCMD as "don't +create this repo". g3 makes no such distinctions, but you can get the same +effect by using a repo group name that does not exist: + + repo @rsync-set1 + ...rules... + +and check that in the script. (It might mean adding one more function to +Gitolite::Easy but that's... easy!) + +## #pw1 converting non-openssh pubkeys automatically + +Gitolite's [triggers][] has can be used to fix this. Here's pseudo-code: + + chdir $(gitolite query-rc -n GL_ADMIN_BASE)/keydir + for each *.pub file in this directory and its subdirectories + detect its format and convert it + # just overwrite it; the original is saved in git anyway + +Let's say the program is called "convert-non-openssh-keys". You send it to me +and I add it to src/commands/post-compile/. Then I update the default rc file +to look at least like this instead + + POST_COMPILE => + [ + # 'post-compile/convert-non-openssh-keys', + 'post-compile/ssh-authkeys', + ... + ... + ], + +making sure to place it *before* ssh-authkeys, and anyone who needs it can +just uncomment it. + +Done! diff --git a/doc/qi.mkd b/doc/qi.mkd new file mode 100644 index 0000000..3337070 --- /dev/null +++ b/doc/qi.mkd @@ -0,0 +1,26 @@ +# getting started + +The quickest install, assuming your `$PATH` contains `$HOME/bin`, is: + + * get the software + + git clone git://github.com/sitaramc/gitolite + + # (until this becomes "master") + cd gitolite + git checkout -f g3 + + * install it + + ln -sf $PWD/src/gitolite $HOME/bin + +If you don't like that, there are [other install methods][install]. + +Once the install is done, setup: + + gitolite setup -pk your-name.pub + +And that's it. + +Next steps are usually [adding][add] users and repos and learning about +[access control][conf]. diff --git a/doc/rc.mkd b/doc/rc.mkd new file mode 100644 index 0000000..03613d0 --- /dev/null +++ b/doc/rc.mkd @@ -0,0 +1,20 @@ +# the "rc" file ($HOME/.gitolite.rc) + +The rc file for g3 is quite different from that of g2. It has been designed +to be (a) the only thing unique to your site, for most installations and (b) +easy to extend when new needs show up, without having to touch core gitolite. + +g2 had a nasty rc file where every variable had to be declared. As a result, +ADCs that needed their own settings could not use it. + +Now it's a perl hash, and you can add any keys you want. + +Please look at the 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`) + +Their purposes are to be found in each of their individual documentation files +around; start with [customising gitolite][cust]. diff --git a/doc/refex.mkd b/doc/refex.mkd new file mode 100644 index 0000000..e7d8aad --- /dev/null +++ b/doc/refex.mkd @@ -0,0 +1,30 @@ +## #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. + +The only extra info you need is: + + * for convenience, a refex not starting with `refs/` is assumed to start + with `refs/heads/`. This means normal branches can be referred to 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 allow all these: + + refs/heads/master + refs/heads/master1 + refs/heads/master2 + refs/heads/master/full + + If you want to restrict to just the one specific ref, use + + RW master$ = alice diff --git a/doc/repo.mkd b/doc/repo.mkd new file mode 100644 index 0000000..2c3509b --- /dev/null +++ b/doc/repo.mkd @@ -0,0 +1,23 @@ +## #repo repo definitions + +Example: + + 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 diff --git a/doc/rules.mkd b/doc/rules.mkd new file mode 100644 index 0000000..c54b43f --- /dev/null +++ b/doc/rules.mkd @@ -0,0 +1,82 @@ +## #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 + +### when does gitolite check access + +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 is a particular rule line 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] + + * then 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]. + +### 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 one optionally followed by an `M`. And by now you +know what they all mean. + diff --git a/doc/sugar.mkd b/doc/sugar.mkd new file mode 100644 index 0000000..016de55 --- /dev/null +++ b/doc/sugar.mkd @@ -0,0 +1,11 @@ +# syntactic sugar + +Sugar scripts help you change the perceived syntax of the conf language. The +base syntax of the language is as described [here][conf], 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. diff --git a/doc/testing.mkd b/doc/testing.mkd new file mode 100644 index 0000000..feb2ad7 --- /dev/null +++ b/doc/testing.mkd @@ -0,0 +1,31 @@ +# testing gitolite + +Here's how to *run* the tests: + + git clone git://github.com/sitaramc/gitolite + cd gitolite + git checkout -f g3 + + # if you're not ok with your ~/.ssh getting clobbered + prove + + # if you're ok with your ~/.ssh getting clobbered + # prove t/*.t t/ssh* + +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. + +There are 2 specific tests that deal with ssh though, which are run only on +request, as you can see above, because they clobber your `~/.ssh`. You have +been warned. diff --git a/doc/triggers.mkd b/doc/triggers.mkd new file mode 100644 index 0000000..50e74bd --- /dev/null +++ b/doc/triggers.mkd @@ -0,0 +1,90 @@ +# gitolite triggers + +## intro and sample rc excerpt + +Gitolite fires off external commands at six 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) + +## 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). + +## triggers and arguments + +All triggers receive the name of the trigger as a string (example, +`"POST_COMPILE"`) as the first argument, so they can know who invoked them. +(This allows you to write the same program and fire it from more than one +trigger, as above). In addition, they may receive other arguments pertaining +to the event that happened. + + * `ACCESS_CHECK`: this fires once after each access check. The first is + just before invoking git-receive-pack or git-upload-pack. The second, + which only applies to "write" operations, is from git's own 'update' hook. + + Arguments: repo name, user name, [attempted access][perm], the ref being + updated, and the result of the access check. + + The 'ref' is `any` for the first check, because at that point we don't + know what the actual ref is. For the second check it could be, say, + `refs/heads/master` or some such. + + The result is a text field that the `access()` function returned. + Programmatically, the only thing you should rely on is that if it contains + the upper case word "DENIED" then access was denied, otherwise it was + allowed. + + * `PRE_GIT`: before running the git command. + + Arguments: repo name, user name, [attempted access][perm], the string + `any`, and the git command ('git-receive-pack', 'git-upload-pack', or + 'git-upload-archive') being invoked. + + * `POST_GIT`: after the git command returns. + + Arguments: same as for `PRE_GIT`, followed by the output of the perl + function "times" (i.e., 4 CPU times: user, system, cumulative user, + cumulative system) + + * `POST_COMPILE`: 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. + + Programs run by this trigger receive no extra arguments. + + * `PRE_CREATE` and `POST_CREATE`: before and after a new "[wild][]" repo is + created by user action. + + Arguments: repo name, user name. diff --git a/doc/users.mkd b/doc/users.mkd new file mode 100644 index 0000000..f9064b6 --- /dev/null +++ b/doc/users.mkd @@ -0,0 +1,96 @@ +# 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" ;-) + +This document has some text, and a lot of links. Most of this info *is* +available in the rest of the documentation, but it's scattered and sparse. +Collecting all of it, or at least links to it, in one place sounds useful. + +## 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 in addition to the "R" +and the "W"). + +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/vref.mkd b/doc/vref.mkd new file mode 100644 index 0000000..c5263df --- /dev/null +++ b/doc/vref.mkd @@ -0,0 +1,254 @@ +# virtual refs + +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. + +Another example is detecting duplicate pubkeys in a push to the admin repo: + + repo gitolite-admin + # ... normal rules ... + - VREF/DUPKEYS = @all + +---- + +## 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. + +## 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 and dupkeys examples 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 +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; 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 the refex itself (plus an optional message), so that it matches + the line which invoked it + +### 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 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 + +### number of new files + +If a dev pushes more than 2 *new* files, the top commit needs to have a +signed-off by line in its commit message. For example if he has 4 new files +this text should be: + + 4 new files signed-off by: + +The config entry for this is below (`NO_SIGNOFF` applies only to, and thus +implies, `NEWFILES`): + + RW+ VREF/COUNT/2/NO_SIGNOFF = sitaram + - VREF/COUNT/2/NO_SIGNOFF = @all + +Notice how the refex in both cases is *exactly* the same. If you make it +different (even change the number on my access line), things won't work. + +Junior devs can't push more than 10 new files, even with a signed-off by line: + + - VREF/COUNT/10/NEWFILES = @junior_devs + +### 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) + +### catching duplicate pubkeys + +We covered this as a teaser example at the start. + +## 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 'in core' feature called [merge check][mergecheck] +does, 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 new file mode 100644 index 0000000..3d05124 --- /dev/null +++ b/doc/why.mkd @@ -0,0 +1,46 @@ +# Why is gitolite needed? + +Gitolite is separate from git, and needs to be installed and configured. So... +why do we bother? + +Gitolite is useful in any server that is going to host multiple git +repositories, each with many developers, where some sort of access control is +required. + +In theory, this can be done with plain old Unix permissions: each user is a +member of one or more groups, each group "owns" one or more repositories, and +using unix permissions (especially the setgid bit -- `chmod g+s`) you can +allow/disallow users access to repos. + +But there are several disadvantages here: + + * every user needs a userid and password on the server. This is usually a + killer, especially in tightly controlled environments + * adding/removing access rights involves complex `usermod -G ...` mumblings + which most admins would rather not deal with + * *viewing* (aka auditing) 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 pretty much + impossible without extraneous tools + * errors or omissions in setting the permissions exactly can cause problems + of either kind: false accepts or false rejects + * without going into ACLs it is not possible to give some people read-only + access while some others have read-write access to a repo (unless you make + it world-readable). Group access just doesn't have enough granularity + * it is absolutely impossible to restrict pushing by branch name or tag + name. + +Gitolite does away with all this: + + * it uses ssh magic to remove the need to give actual unix userids to + developers + * it uses a simple but powerful config file format to specify access rights + * access control changes are affected by modifying this file, adding or + removing user's public keys, and "compiling" the configuration + * this also makes auditing trivial -- all the data is in one place, and + changes to the configuration are also logged, so you can audit them. + * finally, the config file allows distinguishing between read-only and + read-write access, not only at the repository level, but at the branch + level within repositories. + diff --git a/doc/write-types.mkd b/doc/write-types.mkd new file mode 100644 index 0000000..e899318 --- /dev/null +++ b/doc/write-types.mkd @@ -0,0 +1,31 @@ +## #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 C + 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). + diff --git a/dot.pl b/dot.pl new file mode 100644 index 0000000..40b9a7c --- /dev/null +++ b/dot.pl @@ -0,0 +1,31 @@ +#!/usr/bin/perl +use strict; +use warnings; + +my @a = `grep -r use.Gitolite . | grep -i '^./gitolite'`; + +# chomp(@a); +open( my $fh, "|-", "tee module-tree.gv | dot -Tpng | tee module-tree.png | display" ); + +@a = map { + print $fh "#$_"; + s/^\.\/gitolite\///i; + s/-/_/g; + s/\.\///; + s/\//_/g; + s/\.pm:/ -> /; + s/use Gitolite:://; + s/::/_/g; + s/:/ -> /; + s/;//; + s/^(\S+) -> \1$//; + s/.* -> Rc//; + s/.* -> Common//; + $_; +} @a; + +# open(my $fh, "|-", "cat > /tmp/junkg3"); +print $fh "digraph G {\n"; +print $fh $_ for @a; +print $fh "}\n"; +close $fh;