gitolite/doc/admin-defined-commands.mkd
Sitaram Chamarty 6efea9d7a3 (doc) admin-defined commands doc fixes:
- make the warning less juvenile ;-)
  - de-emphasise the connection to wild repos; it's not as deep as the
    doc made it out to be
  - move the historical stuff out of the way
2011-09-25 10:13:50 +05:30

253 lines
9.9 KiB
Markdown

## admin defined commands
Summary: this document describes a mechanism to allow users controlled access
to specific programs or scripts, without giving them full shell access.
**WARNING**: careless use of this feature, including inadequate review of
allowed commands or scripts, could compromise this security and allow users to
grant themselves full shell access, accidentally or otherwise.
----
In this document:
* <a href="#_background">background</a>
* <a href="#_setting_it_up">setting it up</a>
* <a href="#_configuring_ADCs">configuring ADCs</a>
* <a href="#_anatomy_of_a_command">anatomy of a command</a>
* <a href="#_example_uses_and_sample_commands_in_contrib">example uses and sample commands in contrib</a>
* <a href="#_fork">fork</a>
* <a href="#_deleting_trashing_repos">deleting/trashing repos</a>
* <a href="#_enable_disable_push_access_temporarily">enable/disable push access temporarily</a>
* <a href="#_bonus_restricted_admin">(bonus) restricted admin</a>
* <a href="#_how_this_feature_came_about">how this feature came about</a>
----
<a name="_background"></a>
### background
Allowing users to get a shell is a no-no if you're using gitolite, but there
are times when you want them to be able to run specific commands or custom
scripts that you (the admin) have pre-approved to be "safe". Here's how to
enable such commands.
However, as the warning at the top says, careless use could allow users to
defeat this security and get a shell. Every command you approve must be
checked to be sure it cannot be compromised.
To help you with this, gitolite restricts ADCs arguments to only some very
safe characters (see `$ADC_CMD_ARGS_PATT` in `src/gitolite_rc.pm`). The code
inside the ADC, however, is *your* responsibility. The sample ADCs shipped
with gitolite (in `contrib/adc`) should be OK, but an extra pair of eyes never
hurt :-) so please review before installing them.
<font color="gray">
Finally, although this is a generic way to allow specific commands to be run,
most of the examples and sample ADCs pertain to allowing users to manage their
"own" repos. If that's your use case, please read
[doc/wildcard-repositories.mkd][wild] before you continue here.
</font>
<a name="_setting_it_up"></a>
### setting it up
This can only be setup by someone who has shell access to the server. Edit
the rc file and update the `$GL_ADC_PATH` variable to point to, say,
`/home/git/bin/adc`. *Nothing happens unless this variable is set and
pointing to a directory*. Then put in whatever such commands you create into
that directory. If you have a command called "foo" in that directory, then a
user can invoke it by saying:
ssh git@server foo argument list
**WARNING: When gitolite takes control, this directory is checked first, and
if the requested command exists, it is executed. It is therefore quite easy
to inadvertently *hide* some of the "official" commands (like "info",
"expand", "setperms", etc., or worse, say "git-upload-pack"!) by creating
executable files with those names in this directory. So don't do that -- you
have been warned!**
<a name="_configuring_ADCs"></a>
#### configuring ADCs
I didn't want to put configuration variables for ADCs also into the main 'rc'
file, so I chose to put them in the `adc.common-functions` file instead. Take
a look at it sometime.
<a name="_anatomy_of_a_command"></a>
### anatomy of a command
You can basically do whatever you want in such a command -- go wild! It's
upto you to check the permissions of *each* repo that the user is manipulating
using your command -- you can `rm -rf $GL_REPO_BASE_ABS` if you like and
gitolite wouldn't stop you.
The current directory (`$PWD`) will be set to the `$HOME` of `git@server` (or
whatever id you're using). It won't be any specific repo, it won't even be
the base directory of all the repos.
Gitolite defines a few environment variables, as well as allows you to
directly query the ownership and access permissions of any repository.
The environment variables available are:
* `GL_USER` -- the name of the user invoking the command
* `GL_BINDIR` -- the directory containing all the binaries (in particular,
`gitolite.pm`, which is all we really care about here)
* `GL_REPO_BASE_ABS` -- the absolute path of the base directory containing
all the repos
There are a few other variables also available but the above are the only ones
you should rely on. Please treat any other variables you notice as being
internal/undocumented/subject to change.
[Implementation note: some of the distro packagers don't seem to like
`GL_BINDIR`. I have not tested this in those scenarios, but they probably put
`gitolite.pm` somewhere in perl's lib path anyway, so it ought to work].
In addition, all the arguments of the command are also available to you, so
you can define your own command syntaxes. Gitolite checks these arguments to
make sure they fit a very conservative pattern (see `$ADC_CMD_ARGS_PATT` in
`src/gitolite.pm`), so take that into consideration when designing your
commands and usage.
Finally, you can call gitolite to query ownership and permissions for the
current user (which may not necessarily be the owner). This is done loosely
as follows (don't use this exact code yet though):
perl -I$GL_BINDIR -Mgitolite -e "cli_repo_rights('reponame')"
which will print two space-separated words: permissions and owner. Something
like `_____R__W u1` or maybe `____@R_@W <gitolite>`. (The `u1` indicates the
queried repo is a wildcard repo created by user `u1`; for meanings of the "@"
see doc/report-output.mkd)
But that's cumbersome. There's a bash shell function called
`get_rights_and_owner` in `contrib/adc/adc.common-functions` that is much more
convenient. See any of the other samples for how to use it.
If you don't like this, roll your own. If you don't like bash, do the eqvt in
your language of choice.
<a name="_example_uses_and_sample_commands_in_contrib"></a>
### example uses and sample commands in contrib
<a name="_fork"></a>
#### fork
A user would use the fork command like this:
ssh git@server fork from to
where "from" is a repo to which the user invoking the fork has "R" access, and
"to" is a repo that does not yet exist and to which he has "C" access.
(Reminder: these access checks are done by the "fork" script, **not** within
gitolite -- once again, you are responsible for making sure your scripts
maintain the security of the system!)
Strictly speaking this command is not really needed. Even without all this
"admin-defined commands" setup you could still do the following, purely from
the client side:
git clone git@server:from
cd from
git remote add new git@server:to
git push new refs/*:refs/*
or some such incantation.
<a name="rmrepo"></a>
<a name="_deleting_trashing_repos"></a>
#### deleting/trashing repos
See the [repo-deletion document][rdR] for details about this.
[rdR]: http://sitaramc.github.com/gitolite/contrib/adc/repo-deletion.html
<a name="_enable_disable_push_access_temporarily"></a>
#### enable/disable push access temporarily
If you want to disable push access to gitolite temporarily (maybe for
maintenance), anyone with write access to the gitolite-admin repo can do this:
ssh git@server able dis @all # able dis ==> dis able
To re-enable after the maint work is done:
ssh git@server able en @all # able en ==> en able
You can also do this for one or more individual repos; in place of `@all`,
just use a space separated list of reponames (exactly as they would appear in
the config file). Wildcards are not supported; patches welcome ;-)
Note: please see [this][diswr] for more on this.
[diswr]: http://sitaramc.github.com/gitolite/doc/3-faq-tips-etc.html#_disabling_write_access_to_take_backups
<a name="_bonus_restricted_admin"></a>
#### (bonus) restricted admin
It's rather important to me (and presumably others in the "corporate" world)
to separate permission to push to the "gitolite-admin" repo from unrestricted
shell access to the server. This issue has been visited often in the past.
Until now, though, this was binary -- you either had full shell access or none
at all. If there were tasks that legitimately needed to be done from the
shell on the server, it often meant you had to break that separation or load
the few people who did have shell access already.
Now, however, it is possible to provide scripts to do what you want, and put
them in `$GL_ADC_PATH`. `contrib/adc/restrict-admin` is a commented sample --
as you can see, it cleverly makes use of the fact that you can now check for
the invoking uses access to any repo in the system. In this case it checks if
he has "W" access to the gitolite-admin repo, and if he does, allows the
script to proceed.
[Note that this particular use does not require `$GL_WILDREPOS` to be enabled,
because it's not using any wildcard repos].
[xkcd224]: http://xkcd.com/224/
[lazy]: http://c2.com/cgi/wiki?LazinessImpatienceHubris
[wild]: http://sitaramc.github.com/gitolite/doc/wildcard-repositories.html
----
<a name="_how_this_feature_came_about"></a>
### how this feature came about
<font color="gray">
Gitolite was named to be short for "gitosis-lite". Someone now wants to turn
it into a "github-lite" :-) and even had some code to start me off thinking.
Since my first impulse on being asked for a feature is to say no, I was
casting about for a reason when he gave me one: he first made some noises
about perl, then said something about rewriting it all in scheme. Nice... I
resisted the urge to point him to [this][xkcd224], told him that's a great
idea and he should go for it, mentally blessing him for letting me off the
hook on coding it ;-) [Laziness][lazy] *is* the first virtue you know!
And that was that. For a couple of days.
Soon, though, I realised that there could be a pretty big bonus in this for
tightly controlled setups, so I went and coded it all anyway. See the section
on "restricted admin" for what's really exciting about this for *me*.
</font>