Merge branch 'master' into shadow

Conflicts:

	builder/kojid
This commit is contained in:
Mike McLean 2008-11-04 00:12:28 -05:00
commit 64fce8d49f
5 changed files with 143 additions and 29 deletions

View file

@ -1532,10 +1532,6 @@ class BuildTask(BaseTaskHandler):
repo_info = None
#we'll wait for a repo later (self.getRepo)
task_info = session.getTaskInfo(self.id)
# only allow admins to perform non-scratch builds from srpm
if not SCM.is_scm_url(src) and not opts.get('scratch') \
and not 'admin' in session.getUserPerms(task_info['owner']):
raise koji.BuildError, "only admins may peform non-scratch builds from srpm"
target_info = None
if target:
target_info = session.getBuildTarget(target)
@ -1562,6 +1558,18 @@ class BuildTask(BaseTaskHandler):
if not taginfo:
raise koji.GenericError, 'neither tag nor target: %s' % target
dest_tag = taginfo['id']
if not SCM.is_scm_url(src) and not opts.get('scratch'):
#let hub policy decide
policy_data = {
'user_id' : task_info['owner'],
'source' : src,
'task_id' : self.id,
'target' : target['id'],
'build_tag' : build_tag, #id
}
if not self.opts.get('skip_tag'):
policy_data['tag'] = dest_tag #id
session.assertPolicy('build_from_srpm', policy_data)
srpm = self.getSRPM(src)
h = self.readSRPMHeader(srpm)
data = koji.get_header_fields(h,['name','version','release','epoch'])

View file

@ -1958,7 +1958,7 @@ def anon_handle_list_buildroot(options, session, args):
opts['componentBuildrootID'] = buildrootID
data = session.listRPMs(**opts)
fmt = "%(nvr)s"
fmt = "%(nvr)s.%(arch)s"
output = [ fmt % x for x in data]
output.sort()
for line in output:
@ -4021,6 +4021,31 @@ def anon_handle_wait_repo(options, session, args):
print "Unsuccessfully waited %s for a new %s repo" % (koji.util.duration(start), tag)
return 1
_search_types = ('package', 'build', 'tag', 'target', 'user', 'host', 'rpm', 'file')
def anon_handle_search(options, session, args):
"Search koji"
usage = _("usage: %prog sync [options] search_type pattern")
usage += _('\nAvailable search types: %s') % ', '.join(_search_types)
usage += _("\n(Specify the --help global option for a list of other help options)")
parser = optparse.OptionParser(usage=usage)
parser.add_option("-r", "--regex", action="store_true", help=_("treat pattern as regex"))
parser.add_option("--exact", action="store_true", help=_("exact matches only"))
main_options = options
(options, args) = parser.parse_args(args)
type = args[0]
if type not in _search_types:
parser.error(_("Unknown search type: %s") % type)
pattern = args[1]
matchType = 'glob'
if options.regex:
matchType = 'regexp'
elif options.exact:
matchType = 'exact'
data = session.search(pattern, type, matchType)
for row in data:
print row['name']
def handle_help(options, session, args):
"List available commands"
usage = _("usage: %prog help [options]")

View file

@ -3930,24 +3930,37 @@ class HasTagTest(koji.policy.BaseSimpleTest):
class BuildTagTest(koji.policy.BaseSimpleTest):
"""Check the build tag of the build
Build tag is determined by the buildroots of the component rpms"""
If build_tag is not provided in policy data, it is determined by the
buildroots of the component rpms
"""
name = 'buildtag'
def run(self, data):
#in theory, we should find only one unique build tag
#it is possible that some rpms could have been imported later and hence
#not have a buildroot.
#or if the entire build was imported, there will be no buildroots
rpms = context.handlers.call('listRPMs', buildID=data['build'])
args = self.str.split()[1:]
for rpminfo in rpms:
if rpminfo['buildroot_id'] is None:
continue
tagname = get_buildroot(rpminfo['buildroot_id'])['tag_name']
if data.has_key('build_tag'):
tagname = get_tag(data['build_tag'])
for pattern in args:
if fnmatch.fnmatch(tagname, pattern):
return True
#otherwise...
return False
#else
return False
elif data.has_key('build'):
#determine build tag from buildroots
#in theory, we should find only one unique build tag
#it is possible that some rpms could have been imported later and hence
#not have a buildroot.
#or if the entire build was imported, there will be no buildroots
rpms = context.handlers.call('listRPMs', buildID=data['build'])
args = self.str.split()[1:]
for rpminfo in rpms:
if rpminfo['buildroot_id'] is None:
continue
tagname = get_buildroot(rpminfo['buildroot_id'])['tag_name']
for pattern in args:
if fnmatch.fnmatch(tagname, pattern):
return True
#otherwise...
return False
else:
return False
class ImportedTest(koji.policy.BaseSimpleTest):
"""Check if any part of a build was imported
@ -3980,6 +3993,42 @@ class IsBuildOwnerTest(koji.policy.BaseSimpleTest):
#otherwise...
return False
class UserInGroupTest(koji.policy.BaseSimpleTest):
"""Check if user is in group(s)
args are treated as patterns and matched against group name
true is user is in /any/ matching group
"""
name = "user_in_group"
def run(self, data):
user = get_user(data['user_id'])
groups = koji.auth.get_user_groups(user['id'])
args = self.str.split()[1:]
for group_id, group in groups.iteritems():
for pattern in args:
if fnmatch.fnmatch(group, pattern):
return True
#otherwise...
return False
class HasPermTest(koji.policy.BaseSimpleTest):
"""Check if user has permission(s)
args are treated as patterns and matched against permission name
true is user has /any/ matching permission
"""
name = "has_perm"
def run(self, data):
user = get_user(data['user_id'])
perms = koji.auth.get_user_perms(user['id'])
args = self.str.split()[1:]
for perm in perms:
for pattern in args:
if fnmatch.fnmatch(perm, pattern):
return True
#otherwise...
return False
class SourceTest(koji.policy.MatchTest):
"""Match build source
@ -3989,14 +4038,20 @@ class SourceTest(koji.policy.MatchTest):
name = "source"
field = '_source'
def run(self, data):
build = get_build(data['build'])
if build['task_id'] is None:
#imported, no source to match against
if data.has_key('source'):
data[self.field] = data['source']
elif data.has_key('build'):
#crack open the build task
build = get_build(data['build'])
if build['task_id'] is None:
#imported, no source to match against
return False
task = Task(build['task_id'])
params = task.getRequest()
#signature is (src, target, opts=None)
data[self.field] = params[0]
else:
return False
task = Task(build['task_id'])
params = task.getRequest()
#signature is (src, target, opts=None)
data[self.field] = params[0]
return super(SourceTest, self).run(data)
class PolicyTest(koji.policy.BaseSimpleTest):
@ -4049,9 +4104,12 @@ def check_policy(name, data, default='deny', strict=False):
"""
ruleset = context.policy.get(name)
if not ruleset:
result = default
if context.opts.get('MissingPolicyOk'):
# for backwards compatibility, this is the default
result = "allow"
else:
result = "deny"
reason = "missing policy"
#XXX - maybe this should be an error condition
else:
result = ruleset.apply(data)
if result is None:
@ -6396,12 +6454,12 @@ class HostExports(object):
rpmfile = '%s/%s' % (koji.pathinfo.work(), rpmfile)
import_changelog(build, rpmfile, replace=True)
def checkPolicy(name, data, default='deny', strict=False):
def checkPolicy(self, name, data, default='deny', strict=False):
host = Host()
host.verify()
return check_policy(name, data, default=default, strict=strict)
def assertPolicy(name, data, default='deny'):
def assertPolicy(self, name, data, default='deny'):
host = Host()
host.verify()
check_policy(name, data, default=default, strict=True)

View file

@ -379,6 +379,8 @@ def load_config(req):
['KojiTraceback', 'string', None],
['EnableFunctionDebug', 'boolean', False],
['MissingPolicyOK', 'boolean', True],
['LockOut', 'boolean', False],
['ServerOffline', 'string', False],
['OfflineMessage', 'string', None],
@ -411,6 +413,10 @@ def load_config(req):
if cf and config.has_section('policy'):
#for the moment, we simply transfer the policy conf to opts
opts['policy'] = dict(config.items('policy'))
else:
opts['policy'] = {}
for pname, text in _default_policies.iteritems():
opts['policy'].setdefault(pname, text)
# use configured KojiDir
if opts.get('KojiDir') is not None:
koji.BASEDIR = opts['KojiDir']
@ -435,6 +441,13 @@ def load_plugins(opts):
sys.stderr.flush()
return tracker
_default_policies = {
'build_from_srpm' : '''
has_perm admin :: allow
all :: deny
''',
}
def get_policy(opts, plugins):
if not opts.get('policy'):
return

View file

@ -50,6 +50,16 @@ class FalseTest(BaseSimpleTest):
return False
class AllTest(TrueTest):
name = 'all'
#alias for true
class NoneTest(FalseTest):
name = 'none'
#alias for false
class MatchTest(BaseSimpleTest):
"""Matches a field in the data against glob patterns