It would be great to support git-annex 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:
fatal: unrecognized command 'git-annex-shell '/home/w-...'' ...
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 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:
#!/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
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:
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) {
That way the tokenizer operates on a copy of the string instead of garbling the environment directly.
Now, I know that:
- this is clunky
- it's python (heretic! burn! burn!)
- there's more comments than code (but I took a while to figure that stuff out, so better to share)
- it doesn't solve git-annex support in ikiwiki (ie. the objects won't get pushed to the source repo)
- it's 1h30AM on a friday
But:
- it's a start!
- it works (ie. it will drop keys, share configs, etc)
- 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