Skip to content
Newer
Older
100755 120 lines (102 sloc) 3.15 KB
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
1 #!/usr/bin/env python
2
3 #
4 # Simple wrapper around the git commands to ensure that we only speak
5 # git. Should be referenced in the authorized_keys file.
6 #
7 # Copyright (C) 2010 PostgreSQL Global Development Group
8 # Author: Magnus Hagander <magnus@hagander.net>
9 #
10 # Released under the PostgreSQL license
11 #
12 # Looks for a config file in the same directory as gitwrap.py called
13 # gitwrap.ini, containing:
14 #
15 # [paths]
16 # logfile=/some/where/gitwrap.log
6667771 @mhagander Have gitwrap support multiple top-level repositories.
authored Sep 3, 2010
17 # repobase=/some/where/
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
18 #
19
20 import sys
21 import os
22 import os.path
63ea484 @mhagander Include timestamp in log messages.
authored Sep 20, 2010
23 import datetime
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
24 import ConfigParser
25
26 ALLOWED_COMMANDS = ('git-upload-pack', 'git-receive-pack')
27
28 class Logger(object):
29 def __init__(self, cfg):
30 self.user = "Unknown"
31 self.logfile = cfg.get('paths','logfile')
32
33 def log(self, message):
34 f = open(self.logfile,"a")
63ea484 @mhagander Include timestamp in log messages.
authored Sep 20, 2010
35 f.write("%s (%s): %s" % (datetime.datetime.now(), self.user, message))
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
36 f.write("\n")
37 f.close()
38
39 def setuser(self, user):
40 if user:
41 self.user = user
42
43 class InternalException(Exception):
44 pass
45
46 class PgGit(object):
47 user = None
48 command = None
49 path = None
50
51 def __init__(self, cfg):
52 self.cfg = cfg
53 self.logger = Logger(cfg)
6667771 @mhagander Have gitwrap support multiple top-level repositories.
authored Sep 3, 2010
54 self.repobase = cfg.get('paths', 'repobase')
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
55
56 def parse_commandline(self):
57 if len(sys.argv) != 2:
58 raise InternalException("Can only be run with one commandline argument!")
59 self.user = sys.argv[1]
60 self.logger.setuser(self.user)
61
62 def parse_command(self):
63 env = os.environ.get('SSH_ORIGINAL_COMMAND', None)
64 if not env:
65 raise InternalException("No SSH_ORIGINAL_COMMAND present!")
66
67 # env contains "git-<command> <argument>" or "git <command> <argument>"
68 command, args = env.split(None, 1)
69 if command == "git":
70 subcommand, args = args.split(None,1)
71 command = "git-%s" % subcommand
72 if not command in ALLOWED_COMMANDS:
73 raise InternalException("Command '%s' not allowed" % command)
74
75 self.command = command
76 if not args.startswith("'/"):
77 raise InternalException("Expected git path to start with slash!")
78
6667771 @mhagander Have gitwrap support multiple top-level repositories.
authored Sep 3, 2010
79 self.path = os.path.normpath("%s/%s" % (self.repobase, args[2:].rstrip("'")))
80 if not self.path.startswith(self.repobase):
81 raise InternalException("Attempt to escape root directory")
82 if not self.path.endswith(".git"):
83 raise InternalException("Repository paths must end in .git")
84 if not os.path.isdir(self.path):
85 raise InternalException("Repository does not exist")
f609dcf @mhagander Add a git command wrapper script, adapted from the one running on git…
authored Jul 21, 2010
86
87 def run_command(self):
88 self.logger.log("Running \"git shell %s %s\"" % (self.command, "'%s'" % self.path))
89 os.execvp('git', ['git', 'shell', '-c', "%s %s" % (self.command, "'%s'" % self.path) ])
90
91 def run(self):
92 try:
93 self.parse_commandline()
94 self.parse_command()
95 self.run_command()
96 except InternalException, e:
97 try:
98 self.logger.log(e)
99 except Exception, e:
100 pass
101 sys.stderr.write("%s\n" % e)
102 sys.exit(1)
103 except Exception, e:
104 try:
105 self.logger.log(e)
106 except Exception, e:
107 # If we failed to log, try once more with a new logger, otherwise,
108 # just accept that we failed.
109 try:
110 Logger().log(e)
111 except:
112 pass
113 sys.stderr.write("An unhandled exception occurred on the server\n")
114 sys.exit(1)
115
116 if __name__ == "__main__":
117 c = ConfigParser.ConfigParser()
118 c.read("%s/gitwrap.ini" % os.path.abspath(sys.path[0]))
119 PgGit(c).run()
Something went wrong with that request. Please try again.