ikiwiki/ tips/ untrusted git push

This tip will describe how to allow anyone on the planet to `git push` changes into your wiki, without needing a special account. All a user needs to know is:

    git clone git://your.wiki/path
    # now modify any of the files the wiki would let you modify on the web
    git push

This is a wonderful thing to set up for users, because then they can work on the wiki while offline, and they don't need to mess around with web browsers.

## security

But, you might be wondering, how can this possibly be secure. Won't users upload all sorts of garbage, change pages you don't want them to edit, and so on.

The key to making it secure is configuring ikiwiki to run as your git repository's `pre-receive` hook. There it will examine every change that untrusted users push into the wiki, and reject pushes that contain changes that cannot be made using the web interface.

So, unless you have the attachment plugin turned on, non-page files cannot be added. And if it's turned on, whatever `allowed_attachments` checks you have configured will also check files pushed into git.

And, unless you have the remove plugin turned on, no files can be deleted.

And if you have `locked_pages` configured, then it will also affect what's pushed into git.

Untrusted committers will also not be able to upload files with strange modes, or push to any branch except for the configured `gitorigin_branch`, or manipulate tags.

One thing to keep an eye on is uploading large files. It may be easier to do this via git push than using the web, and that could be abused.

Also, no checking is done that the authors of commits are right, so people can make a commit that pretends to be done by someone else.

## user setup

Add a dedicated user who will push in untrusted commits. This user should have a locked password, and `git-shell` as its shell.

    root@bluebird:/home/joey>adduser --shell=/usr/bin/git-shell --disabled-password anon
    Adding user `anon' ...

## ikiwiki setup

You should set up ikiwiki before turning on anonymous push in git.

Edit your wiki's setup file, and uncomment the lines for `git_test_receive_wrapper` and `untrusted_committers`.

    # git pre-receive hook to generate
    git_test_receive_wrapper => '/srv/git/ikiwiki.info/.git/hooks/pre-receive',
    # unix users whose commits should be checked by the pre-receive hook
    untrusted_committers => ['anon'],

The `git_test_receive_wrapper` will become the git `pre-receive` hook. The `untrusted_committers` list is the list of unix users who will be pushing in untrusted changes. It should not include the user that ikiwiki normally runs as.

Once you're done modifying the setup file, don't forget to run `ikiwiki --setup ikiwiki.setup --refresh --wrappers` on it.

## git setup

You'll need to arrange the permissions on your bare git repository so that user anon can write to it. One way to do it is to create a group, and put both anon and your regular user in that group. Then make the bare git repository owned and writable by the group. See git for some more tips on setting up a git repository with multiple committers.

Note that anon should not be able to write to the `srcdir`, only to the bare git repository for your wiki.

If you want to allow git over `ssh`, generate a ssh key for anon, and publish the private key for other people to use. This is optional; you can use `git-daemon` instead and not worry about keys.

Now set up `git-daemon`. It will need to run as user `anon`, and be configured to export your wiki's bare git repository. I set it up as follows in `/etc/inetd.conf`, and ran `/etc/init.d/openbsd-inetd restart`.

    git     stream  tcp     nowait  anon          /usr/bin/git-daemon git-daemon --inetd --export-all --interpolated-path=/srv/git/%H%D /srv/git

At this point you should be able to `git clone git://your.wiki/path` from anywhere, and check out the source to your wiki. But you won't be able to push to it yet, one more change is needed to turn that on. Edit the `config` file of your bare git repository, and allow `git-daemon` to receive pushes:

    [daemon]
        receivepack = true

Now pushes should be accepted, and your wiki immediatly be updated. If it doesn't, check your git repo's permissions, and make sure that the `post-update` and `pre-receive` hooks are suid so they run as the user who owns the `srcdir`.

## infelicities

If a user tries to push a changeset that ikiwiki doesn't like, it will abort the push before refs are updated. However, the changeset will still be present in your repository, wasting space. Since nothing refers to it, it will be expired eventually. You can speed up the expiry by running `git prune`.