It would be great to support [git-annex](https://git-annex.branchable.com/) in ikiwiki-hosting. One of the things that would need to change would be the `iki-git-shell` command, which currently doesn't allow `git-annex-shell` to run, which breaks `git-annex`. I tried setting the `annex-shell` variable on the client side to `git annex-shell` to try to workaround the issue, but it still fails with:

<pre>
fatal: unrecognized command 'git-annex-shell '/home/w-...''
...
</pre>

The client then sets the `annex-ignore` variable and ignores that remote. And of course we'd also need [ikiwiki itself to support git-annex](https://ikiwiki.info/todo/git-annex_support/) but that's another story - at least allowing uploads would be a nice start.

The workaround, of course, is to set `git-annex-shell` as the command in the `authorized_keys` file instead of `iki-git-shell`... but that doesn't quite work because the remote URLs change completely.

So one solution is to exploit the `git-shell-commands` extension of `git-shell`, which allows running arbitrary commands from `git-shell`. Since `git-annex` starts with `git`, it will clear the `iki-git-shell` checks - but it fails in `git-shell` because it's not a recognized git command. To fix this, we need to add the following script in `$HOME/git-shell-commands/git-annex-shell`:

<pre>
#!/usr/bin/python

import os
import re
import shlex
import sys

try:
    # original command is like:
    # "git-annex-shell 'configlist' '/'"
    # argv is expected to be:
    # ['git-shell-commands/git-annex-shell', '/home/.../source.git/']
    # the last argument is the sanitized repo path from iki-git-shell
    # so parse the original command string into an array safely
    orig_argv = shlex.split(os.environ['SSH_ORIGINAL_COMMAND'])
    # construct the command with the original command and the safe repo path
    cmd = ['git-annex-shell', '-c', orig_argv[1], sys.argv[1]]
    # if we have more arguments, shove them in (skipping unsafe path)
    cmd += orig_argv[3:]
    # restrict git-shell to known commands
    os.environ['GIT_ANNEX_SHELL_LIMITED'] = 'true'
    # restrict git-annex to the sanitized repository
    os.environ['GIT_ANNEX_SHELL_DIRECTORY'] = sys.argv[1]
    # keep all commands as readonly, disabled
    #os.environ['GIT_ANNEX_SHELL_READONLY'] = 'true'
    # split into that new command
    os.execlp('git-annex-shell', *cmd)
except Exception as e:
    print "git-annex-shell wrapper improperly called: %s" % e
</pre>

This will not work out of the box with `iki-git-shell` because the C code garbles the `SSH_ORIG_COMMAND` with `strtok`. The following patch is also necessary to carry the command down below:

<pre>
diff --git a/iki-git-shell.c b/iki-git-shell.c
index 70250ad..37639a2 100644
--- a/iki-git-shell.c
+++ b/iki-git-shell.c
@@ -74,6 +74,10 @@ int main (int argc, char **argv) {
                fprintf(stderr, "error: SSH_ORIGINAL_COMMAND not set\n");
                exit(1);
        }
+       if (asprintf(&command, command) == -1) {
+               perror("asprintf");
+               exit(1);
+       }

        s=strtok(command, " -"); /* handle "git-" and "git " */
        if (! s) {
</pre>

That way the tokenizer operates on a copy of the string instead of garbling the environment directly.

Now, I know that:

 1. this is clunky
 2. it's python (heretic! burn! burn!)
 3. there's more comments than code (but I took a while to figure that stuff out, so better to share)
 4. it doesn't solve git-annex support in ikiwiki (ie. the objects won't get pushed to the source repo)
 5. it's 1h30AM on a friday

But:

 1. it's a start!
 2. it works (ie. it will drop keys, share configs, etc)
 3. it should be fairly secure

Your feedback would be greatly appreciated here. At the very least I think the patch on iki-git-shell can't hurt, unless hiding the original git command was deliberate. 

Thanks! -- [[anarcat]]
