From d78bbe8c3eecc9b3592c1b1387b784571286e5f1 Mon Sep 17 00:00:00 2001 From: Sitaram Chamarty Date: Sun, 11 Oct 2009 08:31:59 +0530 Subject: [PATCH] lots of doc changes reflecting "push to admin" is default now :) - added comments to easy install to help do it manually - README: some stuff moved to tips doc, brief summary of extras (over gitosis) added - INSTALL: major revamp, easy install and manual install, much shorter and much more readable! plus other docs changed as needed, and updated the tips doc to roll in some details from "update.mkd" in the "ml" branch --- README.mkd | 112 +++++++++++++-------------------- conf/example.gitolite.rc | 2 +- doc/0-INSTALL.mkd | 127 +++++++++----------------------------- doc/0-UPGRADE.mkd | 40 ++++++++++-- doc/1-migrate.mkd | 63 ++++++++----------- doc/2-admin.mkd | 55 +++-------------- doc/3-faq-tips-etc.mkd | 130 +++++++++++++++++++++++---------------- doc/4-push-to-admin.mkd | 5 ++ src/00-easy-install.sh | 99 +++++++++++++++++++++++++---- 9 files changed, 313 insertions(+), 320 deletions(-) diff --git a/README.mkd b/README.mkd index fe85675bc..7cbbaf348 100644 --- a/README.mkd +++ b/README.mkd @@ -9,17 +9,16 @@ ---- -Gitolite is the bare essentials of gitosis, with a completely different -config file that allows (at last!) access control down to the branch level, -including specifying who can and cannot *rewind* a given branch. It is -released under GPL v2. See COPYING for details. +Gitolite is a rewrite of gitosis, with a completely different config file that +allows (at last!) access control down to the branch level, including +specifying who can and cannot *rewind* a given branch. In this document: * why - * what's gone - * what's new - * the workflow + * what's extra + * security + * contact and license ---- @@ -32,30 +31,15 @@ a typical $DAYJOB setting, there are some issues: and be done * often, "python-setuptools" isn't installed (and on a Solaris9 I was trying to help remotely, we never did manage to install it eventually) - * or you don't have root access, or the ability to add users + * you don't have root access, or the ability to add users (this is also true + for people who have just one userid on a hosting provider) * the most requested feature (see "what's new?") had to be written anyway -### what's gone - -While I was pondering the need to finally learn python[1] , I also realised -that: - - * no one in $DAYJOB type environments will use or approve access methods - that work without any authentication, so I didn't need gitweb/daemon - support in the tool or in the config file. - - Update 2009-09-24: I don't use this feature but someone wanted it, so I - added it... see the "faq, tips, etc" document for more - - * the idea that you admin it by pushing to a special repo is nice, but not - really necessary because of how rarely these changes are made, especially - considering how much code is involved in that piece - All of this pointed to a rewrite. In perl, naturally :-) -### what's new +### what's extra -Per-branch permissions. You will not believe how often I am asked this at +**Per-branch permissions**. You will not believe how often I am asked this at $DAYJOB. This is almost the single reason I started *thinking* about rolling my own gitosis in the first place. @@ -65,50 +49,42 @@ deleting a branch (which is really just an extreme form of rewind). I needed something in between allowing anyone to do it (the default) and disabling it completely (`receive.denyNonFastForwards` or `receive.denyDeletes`). -Take a look at the example config file in the repo to see how I do this. I -copied the basic idea from `update-hook-example.txt` (it's one of the "howto"s -that come with the git source tree). However, please note the difference in -the size and complexity of the *operational code* between the update hook in -that example, and in mine :-) The reason is in the next section. - -### the workflow - -In order to get per-branch access, you *must* use an update hook. However, -that only gets invoked on a push; "read" access still has to be controlled -right at the beginning, before git even enters the scene (just the way gitosis -currently works). +Here're **some more features**. All of them are documented in detail +somewhere in the `doc/` subdirectory. + + * simpler, yet far more powerful, config file syntax, including specifying + gitweb/daemon access. You'll need this power if you manage lots of users + + repos + combinations of access + * config file syntax gets checked upfront, and much more thoroughly + * if your requirements are still too complex, you can split up the config + file and delegate authority over parts of it + * more comprehensive logging [aka: management does not think "blame" is just + a synonym for "annotate" :-)] + * "personal namespace" prefix for each dev + * migration guide and simple converter for gitosis conf file + * "exclude" (or "deny" rights in the config file) -- this is the "rebel" + branch in the repository, and always will be ;-) + +### security + +Due to the environment in which this was created and the need it fills, I +consider this a "security" program, albeit a very modest one. The code is +very small and easily reviewable -- the 2 programs that actually control +access when a user logs in total about 200 lines of code (about +80 lines according to "sloccount"). + +For the first person to find a security hole in it, defined as allowing a +normal user (not the gitolite admin) to read a repo, or write/rewind a ref, +that the config file says he shouldn't, and caused by a bug in *code* that is +in the "master" branch, (not in the other branches, or the configuration file +or in Unix, perl, shell, etc.)... well I can't afford 1000 USD rewards like +djb, so you'll have to settle for 1000 INR (Indian Rupees) as a "token" prize +:-) -So: either split the access control into two config files, or have two -completely different programs *both* parse the same one and pick what they -want. Crap... I definitely don't want the hook doing any parsing, (and it -would be nice if the auth-control program didn't have to either). - -So I changed the workflow completely: - - * all admin changes happen *on the server*, in a special directory that - contains the config and the users' pubkeys. But there's no commit and - push afterward - * instead, after making changes, you "compile" the configuration. This - refreshes `~/.ssh/authorized_keys`, as well as puts a parsed form of the - access list in a file for the other two pieces to use. - -The pre-parsed form is basically a huge perl variable. It's human readable -too (never mind what the python guys say!) - -So the admin knows immediately if the config file had any problems, which is -good. Also, the relatively complex parse code is not part of the actual -access control points, which are: - - * the program that is run via `~/.ssh/authorized_keys` (I call it - `gl-auth-command`, equivalent to `gitosis-serve`); this decides whether - git should even be allowed to run (basic R/W/no access) - * the update-hook on each repo, which decides the per-branch permissions - -### footnotes +---- -[1] I hate whitespace to mean anything significant except for text; this is a -personal opinion *only*, so pythonistas please back off :-) +### contact and license -### contact +Gitolite is released under GPL v2. See COPYING for details. sitaramc@gmail.com diff --git a/conf/example.gitolite.rc b/conf/example.gitolite.rc index ea80bec34..700fc0e97 100644 --- a/conf/example.gitolite.rc +++ b/conf/example.gitolite.rc @@ -5,7 +5,7 @@ # this file is meant to be pulled into a perl program using "do" or "require". # You do NOT need to know perl to edit the paths; it should be fairly -# self-explanatory +# self-explanatory and easy to maintain perl syntax :-) # -------------------------------------- diff --git a/doc/0-INSTALL.mkd b/doc/0-INSTALL.mkd index d4f3b44b0..5ef38cfea 100644 --- a/doc/0-INSTALL.mkd +++ b/doc/0-INSTALL.mkd @@ -1,9 +1,24 @@ # installing gitolite +This document tells you how to install gitolite. After the install is done, +you may want to see the "admin" document for adding users, repos, etc. + +There's an easy install script for Linux, and for other Unixes there's a +slightly more manual process. Both are explained here. + +In this document: + + * easy install + * manual install + * other notes + * next steps + +---- + ### easy install -There is now an easy install script that makes installing very easy for the -common case. **This script is meant to be run on your workstation, not on the +There is an easy install script that makes installing very easy for the common +case. **This script is meant to be run on your workstation, not on the server!** It will take care of all the server side work, *and* get you "push-to-admin" too :-) In short, it does **everything**! @@ -35,110 +50,26 @@ info). #### disadvantages - * has been tested only with Linux. However, the script now makes a much - better "document" on what actually needs to be done, so people installing - on non-Linux machines can probably follow the steps in the script and - install if they wish. Sort of "simulate" it... :) + * has been tested only with Linux ### manual install If for some reason you cannot use the easy-install method, (for example, -you're on a non-Linux machine) read on. Unlike the easy install, all the -below stuff is meant to be run on the server. - -#### pre-requisites on the server - -If you managed to install git, you might already have what gitolite needs: - - * git itself, the more recent the better - * perl, typically installed with git, since git sort of needs it; any - version that includes `Data::Dumper`[1] will do. - * one user account on the server, with password access [2] +you're on a non-Linux machine), it's not very complicated. Just open the file +`src/00-easy-install.sh` in a nice, syntax coloring, text editor, and follow +the instructions marked "MANUAL" :-) -A major objective is to allow use by people without root access, permissions -to create other userids, etc. Even if you have root, please add a user just -for gitolite and do all this from that user. +### other notes -#### getting a tar file from a clone - -You can clone the repo from github, then execute a make command to extract a -tar file of the branch you want. Please use the make command, not a plain -"git archive". The comments in the `Makefile` will explain why. - - git clone git://github.com/sitaramc/gitolite.git - cd gitolite - make master.tar - # or maybe "make rebel.tar" or "make pu.tar" - -#### install from tar file - - * make a temp directory somewhere, cd to it, and unpack the tar file - * run `src/install.pl` and follow the prompts - -**When you are told to edit some file, please read the comments in the file**. -And if you can make some time to read the documentation, please do. -Especially if you have problems. - -Notes: - - * At present the location of `~/.gitolite.rc` is fixed (maybe later I'll - change it to a "git config" variable but I don't see much need right now) - - If you edit it and change any paths, be sure to keep the perl syntax -- - you *don't* have to know perl to do so, it's fairly easy to guess in this - limited case. And of course, make sure you adjust the commands shown - above to suit the new locations + * If you edit `~/.gitolite.rc` and change any paths, be sure to keep the + perl syntax -- you *don't* have to know perl to do so, it's fairly easy to + guess in this limited case * the config file is (by default) at `~/.gitolite/conf/gitolite.conf`, though you can change its location in the "rc" file. Edit the file as you - wish. The comments in the file ought to be clear enough but let me know - if not - - * if you want to bring in existing (bare, server) repos into gitolite, this - should work (refer to `~/.gitolite.rc` for *your* values of the pathnames - below): - * backup the repo, then move it to `$BASE_REPO` - * copy `$GL_ADMINDIR/src/update-hook.pl` to - `[reponame].git/hooks/update` -- if you don't do this, per branch - restrictions will not work - * then update the keys and the config file and "compile" (see "admin" - document) - -### Footnotes: - -[1] Actually, due to the way gitolite is architected, you can manage -without `Data::Dumper` on the server if you have no choice. Only -`gl-compile-conf` needs it, so just run that on some other machine and copy -the two output files across. Cumbersome but doable... the advantage of -separating all the hard work into a manually-run piece :) - -[2] If you have *only* pubkey access, and **no** password access, then your -pubkey is already in the server's `~/.ssh/authorized_keys`. If you also need -to access git as a developer (clone, push, etc), do *not* submit this same -pubkey to gitolite -- it won't work. - -Instead, create a different keypair for your "developer" role (by, e.g., -`ssh-keygen -t rsa -f ~/.ssh/gitdev`), then give `~/.ssh/gitdev.pub` to -gitolite as "yourname.pub", just like you would do for any other user. - -Then you create a suitable `~/.ssh/config` to use the correct key -automatically, something like this: - - host gitadm - hostname my.server - user my_userid_on_server - - host gitdev - hostname my.server - user my_userid_on_server - identityfile ~/.ssh/gitdev - -From now on, `ssh gitadm` will get you a command line on the server, to do -gitolite admin and other work. And your repository URLs would look like -`gitdev:reponame.git`. Very, very, simple... - -And as with gitosis, there's more "ssh" magic than "git" magic here :-) + wish. The comments in the example file (`conf/example.conf`) ought to be + clear enough but let me know if not ----- +### next steps -gitolite is released under the GPL v2 license. See COPYING for details +See the "admin" document for how to add users, etc. diff --git a/doc/0-UPGRADE.mkd b/doc/0-UPGRADE.mkd index c106bc7f5..5e242f68e 100644 --- a/doc/0-UPGRADE.mkd +++ b/doc/0-UPGRADE.mkd @@ -1,11 +1,19 @@ # upgrading gitolite atomically +Upgrading is done **manually, on the server** (except the last step, which is +on your admin repo clone), even if you installed it using the easy install +script on the client. First, it's not as difficult as an install so you don't +really need a script. Second, you may have customised the "rc" file +(`~/.gitolite.rc` on the server) and I'm reluctant to mess with that in an +automated way. + ### general upgrade notes If you follow the steps below, you can make the upgrade "atomic", so you don't have to do it at a "quiet" time or something. -1. untar the new version to some temp directory and `cd` to it +1. copy a tar file containing the new version to the server, untar it to some + temp directory and `cd` to it 2. *prepare* the new version of `~/.gitolite.rc`. It **must** have **all** the variables defined in `conf/example.gitolite.rc` (the "new" rc file), @@ -31,12 +39,11 @@ have to do it at a "quiet" time or something. src/install.pl 5. compile the config once again, in case the *internal* format of the - compiled config file (`$GL_CONF_COMPILED`) has changed - - src/gl-compile-conf + compiled config file (`$GL_CONF_COMPILED`) has changed. - (if you've already setup "push-to-admin", this step should be replaced by - a "git push". Make a dummy commit if needed, to make the push happen). + To do this, you have to do a "git push" on the client side. That might + require a dummy change (maybe add a blank line somewhere) because + otherwise the push will not happen. And you're done. @@ -45,6 +52,27 @@ And you're done. If any extra steps beyond the generic ones above are needed, they will be listed here, newest first. +#### upgrading from 410c9ba + +Between 410c9ba and this version, gitolite managed to make "push to admin" the +default for new installs, but in a much more painless way. If you're +upgrading, you're not forced to use "push to admin", but I'd suggest you: + + * make sure you have password-less (pubkey) login to a command line on your + server + * save your `~/.gitolite.rc`, `keydir/*.pub` and your `conf/gitolite.conf` + files from the server, bring them to your workstation + * then run `src/00-easy-install.sh` on the workstation, as if it were a + fresh install + * when the editor pops up to edit the rc file, delete all the lines in + it and copy them from the saved `~/.gitolite.rc` + * at the end of the script, after the gitolite-admin repo has been + cloned successfully, copy the saved `conf/gitolite.conf` and + `keydir/*.pub` to the clone, then add, commit, and push + +Gitolite also learnt to delegate parts of the config to other users. See +`doc/5-delegation.mkd` for details. + #### upgrading from 8217ef9 Between 8217ef9 and this version, gitolite learnt to handle gitweb/daemon diff --git a/doc/1-migrate.mkd b/doc/1-migrate.mkd index fe0b4cfe8..fb0491f4c 100644 --- a/doc/1-migrate.mkd +++ b/doc/1-migrate.mkd @@ -3,14 +3,9 @@ [TODO: make the migration tool fix up gitweb and daemon control also...] Migrating from gitosis to gitolite is pretty easy, because the basic design is -the same. The differences are: +the same. - * gitolite does not use a special repo for the configuration, pubkeys, etc. - You can choose to version that directory but it is not required that you - do so - -Here's how we migrated my work repos (note: substitute real paths, from your -`~/.gitolite.rc`, for `$REPO_BASE` and `$GL_ADMINDIR` below): +Here's how we migrated my work repos: 1. login as the `git` user on the server, and get a bash shell prompt @@ -18,10 +13,17 @@ Here's how we migrated my work repos (note: substitute real paths, from your else. This will prevent users from pushing anything while you do the backup, migration, etc. -3. For added safety, **delete** the post-update hook that gitosis-admin +3. **edit** `~/.ssh/authorized_keys` and **carefully** remove all the lines + containing "gitosis-serve", as well as the marker line that says + "auto-generated by gitosis, DO NOT REMOVE", then save the file. If the + file did not have any other keys and is now empty, don't worry -- save it + anyway because gitolite expects the file to be present (even if it is + empty). + +4. For added safety, **delete** the post-update hook that gitosis-admin installed - rm $REPO_BASE/gitosis-admin.git/hooks/post-update + rm ~/repositories/gitosis-admin.git/hooks/post-update or at least rename it to `.sample` like all the other hooks hanging around, or edit it and comment out the line that calls `gitosis-run-hook @@ -30,39 +32,34 @@ Here's how we migrated my work repos (note: substitute real paths, from your If you do not do this, an accidental push to the gitosis-admin repo will mess up your `~/.ssh/authorized_keys` file -4. take a **backup** of the `$REPO_BASE` directory - -5. untar gitolite to some temporary directory and follow the instructions to - **install** it using `src/install.pl` +5. take a **backup** of the `~/repositories` directory -6. **convert** your gitosis config file: +Now, log off the server and get back to the client: - cd $GL_ADMINDIR - src/conf-convert.pl < ~/.gitosis.conf > conf/gitolite.conf +1. follow instructions to install gitolite; see install document. Make sure + that you **don't** change the default path for `$REPO_BASE`! - be sure to check the file to make sure it converted correctly +2. **convert** your gitosis config file. Substitute the path for your + gitosis-admin clone in `$GSAC` below, and similarly the path for your + gito**lite**-admin clone in `$GLAC` -7. **copy** the update hook to each of the existing repos (if you have repos - in subdirectories, this won't work as is; adapt it): + src/conf-convert.pl < $GSAC/gitosis.conf > $GLAC/gitolite.conf - for i in $REPO_BASE/*.git - do - cp src/update-hook.pl $i/hooks/update - done + Be sure to check the file to make sure it converted correctly -8. **copy** the keys from gitosis's keydir +3. **copy** the keys from gitosis's keydir (same meanings for GSAC and GLAC) - cp $REPO_BASE/gitosis-admin.git/gitosis-export/keydir/* keydir + cp $GSAC/keydir/* $GLAC/keydir -9. **Important: expand** any multi-key files you may have. See the "faq, +4. **Important: expand any multi-key files you may have**. See the "faq, tips, etc" document in the doc directory for an explanation of what multi-keys are, how gitosis does them and how gitolite does it differently. You can split the keys manually, or use the following code (just - copy-paste it into your xterm): + copy-paste it into your xterm after "cd"-ing to your gitolite-admin repo + clone): - cd $GL_ADMINDIR wc -l keydir/*.pub | grep -v total | grep -v -w 1 | while read a b do i=1 @@ -82,12 +79,4 @@ Here's how we migrated my work repos (note: substitute real paths, from your "sitaram@laptop.pub" and "sitaram@desktop.pub" or whatever. *Please check the files to make sure this worked properly* -10. **edit** `~/.ssh/authorized_keys` and **carefully** remove all the lines - containing "gitosis-serve", as well as the marker line that says - "auto-generated by gitosis, DO NOT REMOVE", then save the file. If the - file did not have any other keys and is now empty, don't worry -- save it - anyway because gitolite expects the file to be present (even if it is - empty). - -At this point you're ready to "compile" the configuration. See the "admin" -document for what to do, and how to check the outputs, etc. +5. Check all your changes to your gitolite-admin clone, commit, and push diff --git a/doc/2-admin.mkd b/doc/2-admin.mkd index 8cd22167d..133455acd 100644 --- a/doc/2-admin.mkd +++ b/doc/2-admin.mkd @@ -22,15 +22,15 @@ Please read on to see how to do this correctly. extension, like `sitaram.pub` or `john-smith.pub`. You can also use periods and underscores - * copy all these `*.pub` files to `$GL_KEYDIR` + * copy all these `*.pub` files to `keydir` in your gitolite-admin repo clone - * the config file (`$GL_CONF`) is very well commented, please take a couple - of minutes to read it. Then edit it and + * edit the config file (`conf/gitolite.conf` in your admin repo clone). See + `conf/example.conf` in the gitolite source for details on what goes in + that file, syntax, etc. Just add new repos as needed, and add new users + and give them permissions as required. The users names should be exactly + the same as their keyfile names, but without the `.pub` extension - * add new repos as needed - * add new users and give them permissions as required. The users names - should be exactly the same as their keyfile names, but without the - `.pub` extension + * when done, commit your changes and push #### specifying gitweb and daemon access @@ -51,41 +51,6 @@ one-time setup you must do separately. All this does is: value you specified for `$projects_list` when setting up gitweb) * for daemon, create the file `git-daemon-export-ok` in the repository -`src/gl-compile-conf` will keep these files consistent with the config -settings -- this includes removing such settings if you remove "read" -permissions for the special usernames. - -#### compiling - - * backup your `~/.ssh/authorized_keys` file if you feel nervous :-) - * that's "backup" as in "copy", not "move". The next step won't work if - the file doesn't exist. Even an empty one is fine but it must be - present - * if you don't have an `~/.ssh/authorized_keys` file at all, you may - have logged in with a password, which in turn might mean you are not - familiar with ssh and authkeys etc. If so, please read up at least - [this](http://sitaramc.github.com/0-installing/9-gitolite-basics.html#IMPORTANT_overview_of_ssh), - and preferably also the man pages for sshd and sshd\_config, to make - sure you understand the security implications of what you are doing. - Once you have understood that, create at least an empty - `~/.ssh/authorized_keys` file before proceeding to the next step - - * cd to `$GL_ADMINDIR` and run `src/gl-compile-conf` - -That should be it, really. However, if you want to be doubly sure, or maybe -the first couple of times you use it, you may want to check these: - - * check the outputs - - * `~/.ssh/authorized_keys` should contain one line for each "user" pub - key added, between two "marker" lines (which you should please please - not remove!). The line should contain a "command=" pointing to a - `$GL_ADMINDIR/src/gl-auth-command` file, then some sshd restrictions, the - key, etc. - * `$GL_CONF_COMPILED` should contain an expanded list of the access - control rules. It may look a little long, but it's fairly intuitive! - - * if the run threw up any "initialising empty repo" messages, check the - individual repos (inside `$REPO_BASE`) if you wish. Especially make sure - the `$REPO_BASE/[reponame].git/hooks/update` got copied OK and is - executable +The "compile" script will keep these files consistent with the config settings +-- this includes removing such settings if you remove "read" permissions for +the special usernames. diff --git a/doc/3-faq-tips-etc.mkd b/doc/3-faq-tips-etc.mkd index 66ab95631..f24d30c2b 100644 --- a/doc/3-faq-tips-etc.mkd +++ b/doc/3-faq-tips-etc.mkd @@ -5,19 +5,21 @@ In this document: * common errors and mistakes * git version dependency * other errors, warnings, notes... + * getting a tar file from a clone * differences from gitosis * simpler syntax * two levels of access rights checking * error checking the config file * delegating parts of the config file * easier to specify gitweb/daemon access - * built-in logging + * better logging * one user, many keys * who am I? * other cool things - * developer specific branches + * "personal" branches * design choices * why we don't do "excludes" + * keeping the parser and the access control separate ### common errors and mistakes @@ -37,10 +39,10 @@ In this document: Here's a workaround for a version dependency that the normal flow of gitolite has. -When you edit your config file to create a new repo, and run -`src/gl-compile-conf`, gitolite creates an empty, bare repo for you. -Normally, you're expected to clone this on the client side, and start working --- make your first commit(s), then push, etc. +When you edit your config file to create a new repo, and push the changes to +the server, gitolite creates an empty, bare repo for you. Normally, you're +expected to clone this on the client side, and start working -- make your +first commit(s), then push, etc. However, cloning an empty repo requires a server side git version that is at least 1.6.2. Gitolite detects this when creating a repo, and warns you. @@ -74,21 +76,27 @@ normal way, since it's not empty anymore. * if you specify a repo that is not at the top level `$REPO_BASE`, be sure to manually create the intermediate directories first. For instance if - you specify a new repo called "a/b/c" to the config file and "compile", - the "compile" script will just `mkdir a/b/c.git`, assuming "a/b" has - already been created - - * if you run `git init` inside `$GL_ADMINDIR` (that is, make it a normal, - non-bare, repo), then, everytime you "compile" (run - `src/gl-compile-conf`), any changes to `conf` and `keydir` will - automatically be committed. This is a simple safety net in case you - accidentally delete the whole config or something. Also see - [4-push-to-admin.mkd](http://github.com/sitaramc/gitolite/blob/pu/doc/4-push-to-admin.mkd) - if you really know what you're doing and want "push to admin" + you specify a new repo called "a/b/c" to the config file and push, the + "compile" script will just `mkdir a/b/c.git`, assuming "a/b" has already + been created * gitweb not able to read your repos? You can change the umask for newly created repos to something more relaxed -- see the `~/.gitolite.rc` file +### getting a tar file from a clone + +You can clone the repo from github or indefero, then execute a make command to +extract a tar file of the branch you want. Please use the make command, not a +plain "git archive", because the Makefile adds a file called +`.GITOLITE-VERSION` that will help you identify which version you are using. + + git clone git://github.com/sitaramc/gitolite.git + # (OR) + git clone git://sitaramc.indefero.net/sitaramc/gitolite.git + cd gitolite + make master.tar + # or maybe "make rebel.tar" or "make pu.tar" + ### differences from gitosis Apart from the big ones listed in the top level README, and subjective ones @@ -176,9 +184,8 @@ gitosis does not do any. I just found out that if you mis-spell `members` as `member`, gitosis will silently ignore it, and leave you wondering why access was denied. -In gitolite, you have to "compile" the config file first (this step takes the -place of the commit+push in gitosis), and keyword typos *are* caught so you -know right away. +Gitolite "compiles" the config file first and keyword typos *are* caught so +you know right away. #### delegating parts of the config file @@ -219,24 +226,21 @@ bits and pieces. Here's an example, using short repo names for convenience: repo r2 # ...and so on... -#### built-in logging - -...just in case of emergency :-) +### better logging -Let's say you gave a dev the right to rewind a branch and he went and rewound -it all the way, or pushed something drastically different on it. Now you need -to recover the commit that got wiped out. +If you have been too liberal with the permission to rewind, it has built-in +logging as an emergency fallback if someone goes too far, or for audit +purposes [`*`]. The logfile names and location are configurable, and can +include the year/month/day etc in the filename for easy archival or further +processing. The log file even tells you which pattern in the config file +matched to allow that specific access to proceed. -If you'd remembered to `git config core.logAllRefUpdates` for that repo, or -globally, you'd be fine -- the reflog will tell you. Otherwise you'd be left -grubbing around in `git fsck --unreachable` a bit :-( +> [`*`] setting `core.logAllRefUpdates true` does provide a safety net +> against over-zealous rewinds, but it does not tell you "who". And +> strangely, management does not seem to share the view that "blame" is just +> a synonym for "annotate" ;-)] -And even if you recover the correct commit, you'll never know *who* did it -- -not unless you add a one-line patch to gitosis, plus a `post-receive` hook to -every repository. - -With gitolite, there's a log file in `$GL_ADMINDIR` that contains lines like -this: +The log lines look like this: 2009-09-19.10:24:37 + b4e76569659939 4fb16f2a88d8b5 myrepo refs/heads/master user2 refs/heads/master @@ -283,33 +287,31 @@ In gitolite, it's simple: just ask nicely :-) ### other cool things -#### developer specific branches +### "personal" branches -So I know what gitolite calls me. Big deal... who cares? +"personal" branches are great for corporate environments, where +unauthenticated pull/clone is a no-no. Since a dev workstation cannot do +authentication, even work shared just between 2 devs has to go *via* the +server. This causes the same branch name clutter as in a centralised VCS, +plus setting up permissions for this becomes a chore for the admin. -Here is an idea: give every developer a personal "scratch" namespace within -which she can create, rewind, or delete any branch. For example, I would own -anything under +gitolite lets you define a "personal" or "scratch" namespace prefix for +each developer (e.g., `refs/personal//*`), with full +permissions for that dev and read-only for everyone else. And you get +this without adding a single line to the access config file -- pretty +much fire and forget as far as the admin is concerned, even if there is +constant churn in the project teams. - $PERSONAL_BRANCH_PREFIX/sitaram/ +Not bad for something that took just *one* line of code to implement. +And that's one clean, readable, line, by the way ;-) -The admin could set `$PERSONAL_BRANCH_PREFIX` in the rc file and communicate +The admin would set `$PERSONAL_BRANCH_PREFIX` in the rc file and communicate this to all users. It could be something like `refs/heads/personal`, which means all such branches will show up in `git branch` lookups and `git clone` will fetch them. Or he could use, say, `refs/personal`, which means it won't show up in any normal "branch-y" commands and stuff, and generally be much less noisy. -Yes, I know git is all about allowing private branches, but in a corporate -environment it's not always possible to pull from a co-worker, for the same -reasons you don't have anonymous access (like the git:// protocol). A normal -developer workstation cannot do authentication, so how would they know who's -pulling? This is a perfect way to share code *without* cluttering the global -namespace, and each developer controls his/her own set of branches! - -The amount of code needed? *One line!* I'll spend about 3x more on declaring -and initialising the new variable, and 30x more on documenting it :-) - **Note that a user who has NO write access cannot have personal branches**; if you read the section (above) on "two levels of access rights checking" you'll understand why. @@ -343,6 +345,9 @@ Just don't *show* the user this config file; it might sound insulting :-) #### why we don't do "excludes" +[umm... having said all this, I implemented it anyway; see the "rebel" +branch!] + I found an error in the example conf file. This snippet *seems* to say that "bruce" can write versioned tags (`refs/tags/v[0-9].*`), but the other staffers can't: @@ -387,3 +392,24 @@ The lack of overlap between refexes ensures ***no confusion*** in specifying, understanding, and ***auditing***, what is allowed and what is not. And in security, "no confusion" is a good thing :-) + +#### keeping the parser and the access control separate + +There are two programs concerned with access control: + + * `gl-auth-command`, the program that is run via `~/.ssh/authorized_keys`; + this decides whether git should even be allowed to run (basic R/W/no + access). (This one cannot decide on the branch-level access; it is not + known at this point what branch is being accessed) + * the update-hook on each repo, which decides the per-branch permissions + +I have chosen to keep the relatively complex task of parsing the config file +out of them to keep them simpler (and faster). So any changes to the config +have to be first "compiled", and the access control programs use this +"compiled" version of the config. (The compile step also refreshes +`~/.ssh/authorized_keys`). + +If you choose the "easy install" method, all this is quite transparent to you +anyway. If you cannot use the easy install and must install manually, I have +clear instructions on how to set it up. + diff --git a/doc/4-push-to-admin.mkd b/doc/4-push-to-admin.mkd index 48d1baad2..8791480de 100644 --- a/doc/4-push-to-admin.mkd +++ b/doc/4-push-to-admin.mkd @@ -1,5 +1,10 @@ # "push to admin" in gitolite +**WARNING: THIS DOCUMENT IS OBSOLETE. DO NOT USE. IT IS RETAINED ONLY FOR +HISTORICAL PURPOSES**. Gitolite now does "push-to-admin" by default, and does +it very easily and simply by front-loading the ssh problem. See the install +doc for details. + ---- Gitosis's default mode of admin is by cloning and pushing the `gitosis-admin` diff --git a/src/00-easy-install.sh b/src/00-easy-install.sh index d19c1a5c9..2ca8bf1bb 100755 --- a/src/00-easy-install.sh +++ b/src/00-easy-install.sh @@ -2,9 +2,13 @@ # easy install for gitolite -# this runs on the client side, and itself takes care of all the server side +# you run this on the client side, and it takes care of all the server side # work. You don't have to do anything on the server side directly +# to do a manual install (since I have tested this only on Linux), open this +# script in a nice, syntax coloring, text editor and follow the instructions +# prefixed by the word "MANUAL" in the comments below :-) + # run without any arguments for "usage" info # important setting: bail on any errors (else we have to check every single @@ -63,6 +67,9 @@ EOFU [[ "$1" =~ [^a-zA-Z0-9._-] ]] && die "user '$1' invalid" [[ "$3" =~ [^a-zA-Z0-9._-] ]] && die "admin_name '$3' invalid" +# MANUAL: (info) we'll use "git" as the user, "server" as the host, and +# "sitaram" as the admin_name in example commands shown below, if any + user=$1 host=$2 admin_name=$3 @@ -71,8 +78,9 @@ admin_name=$3 # basic sanity checks # ---------------------------------------------------------------------- -# are we in the right directory? We should have all the gitolite sources -# here... +# MANUAL: make sure you're in the gitolite directory, at the top level. +# The following files should all be visible: + ls src/gl-auth-command \ src/gl-compile-conf \ src/install.pl \ @@ -81,16 +89,23 @@ ls src/gl-auth-command \ conf/example.gitolite.rc >/dev/null || die "cant find at least some files in gitolite sources/config; aborting" -# do we have pubkey auth on the server +# MANUAL: make sure you have password-less (pubkey) auth on the server. That +# is, running "ssh git@server" should log in straight away, without asking for +# a password + ssh -o PasswordAuthentication=no $user@$host pwd >/dev/null || die "pubkey access didn't work; please set it up using 'ssh-copy-id' or something" -# can the "gitolite-admin" repo be safely created in $HOME +# MANUAL: make sure there's no "gitolite-admin" directory in $HOME (actually +# for the manual flow this doesn't matter so much!) + [[ -d $HOME/gitolite-admin ]] && die "please delete or move aside the \$HOME/gitolite-admin directory" -# cool; now let's create a new key for you as a "gitolite user" (as opposed to -# a gitolite admin who needs to login to the server and get a command line) +# MANUAL: create a new key for you as a "gitolite user" (as opposed to you as +# the "gitolite admin" who needs to login to the server and get a command +# line). For example, "ssh-keygen -t rsa ~/.ssh/sitaram"; this would create +# two files in ~/.ssh (sitaram and sitaram.pub) [[ -f $HOME/.ssh/$admin_name.pub ]] && die "pubkey $HOME/.ssh/$admin_name.pub exists; can't proceed" prompt "the next command will create a new keypair for your gitolite access @@ -111,6 +126,15 @@ prompt "the next command will create a new keypair for your gitolite access ssh-keygen -t rsa -f $HOME/.ssh/$admin_name || die "ssh-keygen failed for some reason..." +# MANUAL: copy the pubkey created to the server, say to /tmp. This would be +# "scp ~/.ssh/sitaram.pub git@server:/tmp" (the script does this at a later +# stage, you do it now for convenience). Note: only the pubkey (sitaram.pub). +# Do NOT copy the ~/.ssh/sitaram file -- that is a private key! + +# MANUAL: if you're running ssh-agent (see if you have an environment variable +# called SSH_AGENT_PID in your "env"), you should add this new key. The +# command is "ssh-add ~/.ssh/sitaram" + if [[ -n $SSH_AGENT_PID ]] then prompt "you're running ssh-agent. We'll try and do an ssh-add of the @@ -121,7 +145,17 @@ then ssh-add $HOME/.ssh/$admin_name fi -# ok the gitolite key is done; create a stanza for it in ~/.ssh/config +# MANUAL: you now need to add some lines to the end of your ~/.ssh/config +# file. If the file doesn't exist, create it. Make sure the file is "chmod +# 644". + +# The lines to be included look like this: + +# host gitolite +# hostname server +# user git +# identityfile ~/.ssh/sitaram + echo " host gitolite hostname $host @@ -153,10 +187,22 @@ rm $HOME/.ssh/.gl-stanza # client side stuff almost done; server side now # ---------------------------------------------------------------------- -# setup the gitolite sources and conf on the server +# MANUAL: copy the gitolite directories "src", "conf", and "doc" to the +# server, to a directory called (for example) "gitolite-install". You may +# have to create the directory first. + ssh $user@$host mkdir -p gitolite-install rsync -a src conf doc $user@$host:gitolite-install/ +# MANUAL: now log on to the server (ssh git@server) and get a command line. +# This step is for your convenience; the script does it all from the client +# side but that may be too much typing for manual use ;-) + +# MANUAL: cd to the "gitolite-install" directory where the sources are. Then +# copy conf/example.gitolite.rc as ~/.gitolite.rc and edit it if you wish to +# change any paths. Make a note of the GL_ADMINDIR and REPO_BASE paths; you +# will need them later + # give the user an opportunity to change the rc cp conf/example.gitolite.rc .gitolite.rc # hey here it means "release candidate" ;-) @@ -183,10 +229,17 @@ relevant for a manual install, not this one..." GL_ADMINDIR=$(ssh $user@$host "perl -e 'do \".gitolite.rc\"; print \$GL_ADMINDIR'") REPO_BASE=$( ssh $user@$host "perl -e 'do \".gitolite.rc\"; print \$REPO_BASE'") -# run the install script on the server +# MANUAL: still in the "gitolite-install" directory? Good. Run +# "src/install.pl" + ssh $user@$host "cd gitolite-install; src/install.pl" -# setup the initial config file +# MANUAL: setup the initial config file. Edit $GL_ADMINDIR/conf/gitolite.conf +# and add at least the following lines to it: + +# repo gitolite-admin +# RW+ = sitaram + echo "#gitolite conf #please see conf/example.conf for details on syntax and features @@ -203,28 +256,48 @@ scp gitolite.conf $user@$host:$GL_ADMINDIR/conf/ scp $HOME/.ssh/$admin_name.pub $user@$host:$GL_ADMINDIR/keydir -# run the compile script on the server +# MANUAL: cd to $GL_ADMINDIR and run "src/gl-compile-conf" + ssh $user@$host "cd $GL_ADMINDIR; src/gl-compile-conf" # ---------------------------------------------------------------------- # hey lets go the whole hog on this; setup push-to-admin! # ---------------------------------------------------------------------- -# setup the initial commit for the admin repo +# MANUAL: make the first commit in the admin repo. This is a little more +# complex, so read carefully and substitute the correct paths. What you have +# to do is: + +# cd $REPO_BASE/gitolite-admin.git +# GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir +# GIT_WORK_TREE=$GL_ADMINDIR git commit -am start + +# Substitute $GL_ADMINDIR and $REPO_BASE appropriately. Note there is no +# space around the "=" in the second and third lines. + echo "cd $REPO_BASE/gitolite-admin.git GIT_WORK_TREE=$GL_ADMINDIR git add conf/gitolite.conf keydir GIT_WORK_TREE=$GL_ADMINDIR git commit -am start " | ssh $user@$host +# MANUAL: now that the admin repo is created, you have to set the hooks +# properly. The install program does this. So cd back to the +# "gitolite-install" directory and run "src/install.pl" + ssh $user@$host "cd gitolite-install; src/install.pl" prompt "now we will clone the gitolite-admin repo to your workstation and see if it all hangs together. We'll do this in your \$HOME for now, and you can move it elsewhere later if you wish to." +# MANUAL: you're done! Log out of the server, come back to your workstation, +# and clone the admin repo using "git clone gitolite:gitolite-admin.git"! + cd $HOME git clone gitolite:gitolite-admin.git +# MANUAL: be sure to read the message below; this applies to you too... + echo echo echo ------------------------------------------------------------------------