Merge branch 'master' into shadow
Conflicts: builder/kojid
This commit is contained in:
commit
64fce8d49f
5 changed files with 143 additions and 29 deletions
|
|
@ -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'])
|
||||
|
|
|
|||
27
cli/koji
27
cli/koji
|
|
@ -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]")
|
||||
|
|
|
|||
106
hub/kojihub.py
106
hub/kojihub.py
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue