--- /dev/null
+import ConfigParser
+import string
+
+import path
+import log
+
+class User:
+ def __init__(self, p, login):
+ self.login = login
+ self.privs = []
+ self.emails = []
+
+ if p.has_option(login, "emails"):
+ self.emails = string.split(p.get(login, "emails"))
+ else:
+ log.alert("acl: [%s] has no emails" % login)
+
+ if p.has_option(login, "privs"):
+ for p in string.split(p.get(login, "privs")):
+ l = string.split(p, ":")
+ if len(l) != 2 or l[0] == "" or l[1] == "":
+ log.alert("acl: invalid priv format: '%s' [%s]" % (p, login))
+ else:
+ self.privs.append((l[0], l[1]))
+ else:
+ log.alert("acl: [%s] has no privs" % login)
+
+ def can_do(self, what, where):
+ for (pwhat, pwhere) in self.privs:
+ if pwhat[0] == "!":
+ ret = 0
+ pwhat = pwhat[1:]
+ else:
+ ret = 1
+ if pwhat == "*" or pwhat == what:
+ if pwhere == "*" or pwhere == where:
+ return ret
+
+ return 0
+
+ def mail_to(self):
+ return self.emails[0]
+
+ def notify_about_failure(self, msg):
+ # FIXME: send email here
+ print "mailto %s: %s" % (self.mail_to(), msg)
+
+ def get_login(self):
+ return self.login
+
+class ACL_Conf:
+ def __init__(self):
+ p = ConfigParser.ConfigParser()
+ p.readfp(open(path.acl_conf))
+ self.users = {}
+ for login in p.sections():
+ user = User(p, login)
+ for e in user.emails:
+ self.users[e] = user
+
+ def user(self, ems):
+ for e in ems:
+ if self.users.has_key(e):
+ return self.users[e]
+ return None
+
+acl = ACL_Conf()
--- /dev/null
+import fcntl
+
+import path
+
+def lock(n):
+ f = open(path.lock_dir + n, "w")
+ fcntl.flock(f, fcntl.LOCK_EX)
+ return f
--- /dev/null
+import sys
+
+def log(s):
+ sys.stderr.write("LOG: %s\n" % s)
+
+def alert(s):
+ log("alert: %s" % s)
+
+def error(s):
+ log("error: %s" % s)
+
+def warn(s):
+ log("warning: %s" % s)
+
+def notice(s):
+ log("notice: %s" % s)
--- /dev/null
+import os.path
+
+root_dir = os.path.expanduser('~/pld-builder.new/')
+conf_dir = root_dir + "config/"
+spool_dir = root_dir + "spool/"
+lock_dir = root_dir + "lock/"
+
+acl_conf = conf_dir + "acl.conf"
+
+queue_file = spool_dir + "queue"
+processed_ids_file = spool_dir + "processed_ids"
+counter_file = spool_dir + "counter"
class Group:
def __init__(self, e):
self.batches = []
- self.is_group = 1
+ self.kind = 'group'
self.id = attr(e, "id")
self.no = int(attr(e, "no"))
self.priority = 2
self.time = time.time()
+ self.requester = None
for c in e.childNodes:
if is_blank(c): continue
if c.nodeType != Element.ELEMENT_NODE:
self.time = int(text(c))
else:
raise "xml: evil group child (%s)" % c.nodeName
+ if self.requester == None:
+ raise "xml: no requester"
def dump(self):
print "group: %s @%d" % (self.id, self.priority)
self.bconds_with = []
self.bconds_without = []
self.builders = []
+ self.branch = ""
+ self.src_rpm = ""
+ self.info = ""
+ self.spec = ""
for c in e.childNodes:
if is_blank(c): continue
if c.nodeType != Element.ELEMENT_NODE:
self.spec = text(c)
elif c.nodeName == "info":
self.info = text(c)
+ elif c.nodeName == "branch":
+ self.branch = text(c)
elif c.nodeName == "builder":
self.builders.append(text(c))
elif c.nodeName == "with":
def dump(self):
print " batch: %s/%s" % (self.src_rpm, self.spec)
print " info: %s" % self.info
+ print " branch: %s" % self.branch
print " with: %s" % string.join(self.bconds_with)
print " without: %s" % string.join(self.bconds_without)
print " for: %s" % string.join(self.builders)
<batch>
<src-rpm>%s</src-rpm>
<spec>%s</spec>
- <info>%s</info>\n\n""" % (escape(self.src_rpm),
- escape(self.spec), escape(self.info)))
+ <branch>%s</branch>
+ <info>%s</info>\n""" % (escape(self.src_rpm),
+ escape(self.spec), escape(self.branch), escape(self.info)))
for b in self.bconds_with:
f.write(" <with>%s</with>\n" % escape(b))
- f.write("\n")
for b in self.bconds_without:
f.write(" <without>%s</without>\n" % escape(b))
- f.write("\n")
for b in self.builders:
f.write(" <builder>%s</builder>\n" % escape(b))
f.write(" </batch>\n")
--- /dev/null
+import email
+import string
+import time
+import os
+import StringIO
+
+import gpg
+import request
+import log
+import path
+from acl import acl
+from lock import lock
+from bqueue import B_Queue
+
+def check_double_id(id):
+ id_nl = id + "\n"
+
+ ids = open(path.processed_ids_file)
+ for i in ids.xreadlines():
+ if i == id_nl:
+ # FIXME: security email here
+ log.alert("request %s already processed" % r.id)
+ return 1
+ ids.close()
+
+ ids = open(path.processed_ids_file, "a")
+ ids.write(id_nl)
+ ids.close()
+
+ return 0
+
+def handle_group(r):
+ lock("request")
+ user = r.acl_user
+ if check_double_id(r.id):
+ return
+
+ if not user.can_do("src", "src"):
+ msg ="user %s is not allowed to src:src" % (user.get_login())
+ log.error(msg)
+ user.notify_about_failure(msg)
+ return
+
+ for batch in r.batches:
+ for bld in batch.builders:
+ if not user.can_do("binary", bld):
+ msg ="user %s is not allowed to binary:%s" % (user.get_login(), bld)
+ log.error(msg)
+ user.notify_about_failure(msg)
+ return
+
+ r.time = time.time()
+ log.notice("queued %s from %s" % (r.id, user.get_login()))
+ q = B_Queue(path.queue_file)
+ q.lock(0)
+ q.read()
+ q.add(r)
+ q.write()
+ q.unlock()
+
+def handle_request(f):
+ sio = StringIO.StringIO()
+ sio.write(f.read())
+ sio.seek(0)
+ (em, body) = gpg.verify_sig(sio)
+ user = acl.user(em)
+ if user == None:
+ # FIXME: security email here
+ log.alert("invalid signature, or not in acl %s" % em)
+ return
+ r = request.parse_request(body)
+ r.acl_user = user
+ if r.kind == 'group':
+ handle_group(r)
+ else:
+ msg = "%s: don't know how to handle requests of this kind '%s'" \
+ % (user.get_login(), r.kind)
+ log.alert(msg)
+ user.notify_about_failure(msg)