kojid: extend SCM.assert_allowed with hub policy
This is a simple extention of `SCM.assert_allowed` - `assert_allowed_by_policy` will set the default "use_common" to False which is different to the old behavior - `channel`, `user_id`, `scratch` are passed in the `policy_data` with scminfo right now. This is a prototype for this change, and there are some other solutions could be implemented too - Use a scmpolicy plugin as `postSCMCheckout` callback, the pro is that we can do more checks after the source is initialized on builder, meanwhile, the con is that the source will be downloaded even it is denied by policy. It might be a potential risk? - Do the scm check in hub's `make_task`, this looks straightforward, but may lack some builder's information fixes: #2757
This commit is contained in:
parent
ec70d21c41
commit
47c4b5d70b
8 changed files with 431 additions and 25 deletions
|
|
@ -1633,7 +1633,17 @@ class BuildMavenTask(BaseBuildTask):
|
|||
self.opts = opts
|
||||
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm_policy_opts = {
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': self.opts.get('scratch')
|
||||
}
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts=scm_policy_opts)
|
||||
repo_id = opts.get('repo_id')
|
||||
if not repo_id:
|
||||
raise koji.BuildError('A repo_id must be provided')
|
||||
|
|
@ -1707,7 +1717,11 @@ class BuildMavenTask(BaseBuildTask):
|
|||
if self.opts.get('patches'):
|
||||
patchlog = self.workdir + '/patches.log'
|
||||
patch_scm = SCM(self.opts.get('patches'))
|
||||
patch_scm.assert_allowed(self.options.allowed_scms)
|
||||
patch_scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts=scm_policy_opts)
|
||||
self.run_callbacks('preSCMCheckout', scminfo=patch_scm.get_info(),
|
||||
build_tag=build_tag, scratch=opts.get('scratch'),
|
||||
buildroot=buildroot)
|
||||
|
|
@ -1990,7 +2004,16 @@ class WrapperRPMTask(BaseBuildTask):
|
|||
assert False # pragma: no cover
|
||||
|
||||
scm = SCM(spec_url)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': opts.get('scratch')
|
||||
})
|
||||
|
||||
repo_id = opts.get('repo_id')
|
||||
if not repo_id:
|
||||
|
|
@ -2979,7 +3002,16 @@ class ImageTask(BaseTaskHandler):
|
|||
self.logger.debug("ksfile = %s" % ksfile)
|
||||
if self.opts.get('ksurl'):
|
||||
scm = SCM(self.opts['ksurl'])
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': self.opts.get('scratch')
|
||||
})
|
||||
logfile = os.path.join(self.workdir, 'checkout.log')
|
||||
self.run_callbacks('preSCMCheckout', scminfo=scm.get_info(),
|
||||
build_tag=build_tag, scratch=self.opts.get('scratch'),
|
||||
|
|
@ -3453,7 +3485,16 @@ class LiveMediaTask(ImageTask):
|
|||
can find the checked out templates.
|
||||
"""
|
||||
scm = SCM(self.opts['lorax_url'])
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': self.opts.get('scratch')
|
||||
})
|
||||
logfile = os.path.join(self.workdir, 'lorax-templates-checkout.log')
|
||||
checkout_dir = scm.checkout(build_root.tmpdir(),
|
||||
self.session, self.getUploadDir(), logfile)
|
||||
|
|
@ -3700,7 +3741,16 @@ class OzImageTask(BaseTaskHandler):
|
|||
self.logger.debug("ksfile = %s" % ksfile)
|
||||
if self.opts.get('ksurl'):
|
||||
scm = SCM(self.opts['ksurl'])
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': self.opts.get('scratch')
|
||||
})
|
||||
logfile = os.path.join(self.workdir, 'checkout-%s.log' % self.arch)
|
||||
self.run_callbacks('preSCMCheckout', scminfo=scm.get_info(),
|
||||
build_tag=build_tag, scratch=self.opts.get('scratch'))
|
||||
|
|
@ -4527,7 +4577,16 @@ class BuildIndirectionImageTask(OzImageTask):
|
|||
self.logger.debug("filepath = %s" % filepath)
|
||||
if fileurl:
|
||||
scm = SCM(fileurl)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': self.opts.get('scratch')
|
||||
})
|
||||
self.run_callbacks('preSCMCheckout', scminfo=scm.get_info(),
|
||||
build_tag=build_tag, scratch=self.opts.get('scratch'))
|
||||
logfile = os.path.join(self.workdir, 'checkout.log')
|
||||
|
|
@ -4935,12 +4994,20 @@ class BuildSRPMFromSCMTask(BaseBuildTask):
|
|||
return self.checkHostArch(tag, hostdata)
|
||||
|
||||
def handler(self, url, build_tag, opts=None):
|
||||
# will throw a BuildError if the url is invalid
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
|
||||
if opts is None:
|
||||
opts = {}
|
||||
# will throw a BuildError if the url is invalid
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': opts.get('scratch')
|
||||
})
|
||||
repo_id = opts.get('repo_id')
|
||||
if not repo_id:
|
||||
raise koji.BuildError("A repo id must be provided")
|
||||
|
|
@ -6362,6 +6429,8 @@ def get_options():
|
|||
'mock_bootstrap_image': False,
|
||||
'pkgurl': None,
|
||||
'allowed_scms': '',
|
||||
'allowed_scms_by_config': True,
|
||||
'allowed_scms_by_policy': False,
|
||||
'scm_credentials_dir': None,
|
||||
'support_rpm_source_layout': True,
|
||||
'yum_proxy': None,
|
||||
|
|
@ -6390,7 +6459,7 @@ def get_options():
|
|||
elif name in ['offline_retry', 'use_createrepo_c', 'createrepo_skip_stat',
|
||||
'createrepo_update', 'use_fast_upload', 'support_rpm_source_layout',
|
||||
'build_arch_can_fail', 'no_ssl_verify', 'log_timestamps',
|
||||
'allow_noverifyssl']:
|
||||
'allow_noverifyssl', 'allowed_scms_by_config', 'allowed_scms_by_policy']:
|
||||
defaults[name] = config.getboolean('kojid', name)
|
||||
elif name in ['plugin', 'plugins']:
|
||||
defaults['plugin'] = value.split()
|
||||
|
|
|
|||
|
|
@ -77,6 +77,14 @@ topurl=http://hub.example.com/kojifiles
|
|||
; is run by default.
|
||||
allowed_scms=scm.example.com:/cvs/example git.example.org:/example svn.example.org:/users/*:no
|
||||
|
||||
; If use the option allowed_scms above for allowing / denying SCM, default: true
|
||||
; allowed_scms_use_config = true
|
||||
|
||||
; If use hub policy build_from_scm for allowing / denying SCM, default: false
|
||||
; notice that if both options are enabled, both assertions will be applied, and user_common and
|
||||
; source_cmd will be overridden by the policy's result.
|
||||
; allowed_scms_use_policy = false
|
||||
|
||||
; A directory to bind mount into Source RPM creation so that some
|
||||
; credentials can be supplied when required to fetch sources, e.g.
|
||||
; when the place the sources are fetched from requires all accesses to
|
||||
|
|
|
|||
|
|
@ -524,6 +524,13 @@ _default_policies = {
|
|||
has_perm admin :: allow
|
||||
all :: deny
|
||||
''',
|
||||
'build_from_scm': '''
|
||||
has_perm admin :: allow
|
||||
# match scmtype CVS CVS+SSH && match scmhost scm.example.com && match scmrepository /cvs/example :: allow
|
||||
# match scmtype GIT GIT+SSH && match scmhost git.example.org && match scmrepository /example :: allow
|
||||
# match scmtype SVN SVN+SSH && match scmhost svn.example.org && match scmrepository /users/* :: allow
|
||||
all :: deny
|
||||
''', # noqa: E501
|
||||
'package_list': '''
|
||||
has_perm admin :: allow
|
||||
has_perm tag :: allow
|
||||
|
|
|
|||
|
|
@ -327,7 +327,16 @@ class SCM(object):
|
|||
# return parsed values
|
||||
return (scheme, user, netloc, path, query, fragment)
|
||||
|
||||
def assert_allowed(self, allowed):
|
||||
def assert_allowed(self, allowed='', session=None, by_config=True, by_policy=False, opts=None):
|
||||
if by_config:
|
||||
self.assert_allowed_by_config(allowed or '')
|
||||
if by_policy:
|
||||
if session is None:
|
||||
raise koji.ConfigurationError(
|
||||
'When allowed SCM assertion is by policy, session must be passed in.')
|
||||
self.assert_allowed_by_policy(session, **(opts or {}))
|
||||
|
||||
def assert_allowed_by_config(self, allowed):
|
||||
"""
|
||||
Check this scm against allowed list and apply options
|
||||
|
||||
|
|
@ -396,6 +405,74 @@ class SCM(object):
|
|||
raise koji.BuildError(
|
||||
'%s:%s is not in the list of allowed SCMs' % (self.host, self.repository))
|
||||
|
||||
def assert_allowed_by_policy(self, session, **opts):
|
||||
"""
|
||||
Check this scm against hub policy: build_from_scm and apply options
|
||||
|
||||
The policy data is the combination of scminfo with scm prefix and kwargs.
|
||||
It should at least contain following keys:
|
||||
|
||||
- scmurl
|
||||
- scmscheme
|
||||
- scmuser
|
||||
- scmhost
|
||||
- scmrepository
|
||||
- scmmodule
|
||||
- scmrevision
|
||||
- scmtype
|
||||
|
||||
More keys could be added in opts. You can pass any reasonable data which could be handled
|
||||
by policy tests, like:
|
||||
|
||||
- scratch (if the task is scratch)
|
||||
- channel (which channel the task is assigned)
|
||||
- user_id (the task owner)
|
||||
|
||||
The format of the action returned from build_from_scm could be one of following forms::
|
||||
|
||||
allow [use_common] [source_cmd]
|
||||
deny [reason]
|
||||
|
||||
If use_common is not set, use_common property is False.
|
||||
If source_cmd is none, it will be parsed as None. If it not set, the default value:
|
||||
['make', 'sources'], or the value set by :func:`~koji.daemon.SCM.assert_allowed_by_config`
|
||||
will be set.
|
||||
|
||||
Policy example:
|
||||
|
||||
build_from_scm =
|
||||
bool scratch :: allow none
|
||||
match scmhost scm.example.com :: allow use_common make sources
|
||||
match scmhost scm2.example.com :: allow
|
||||
all :: deny
|
||||
|
||||
|
||||
:param koji.ClientSession session: the session object to call hub xmlrpc APIs.
|
||||
It should be a host session.
|
||||
|
||||
:raises koji.BuildError: if the scm is denied.
|
||||
"""
|
||||
policy_data = {}
|
||||
for k, v in six.iteritems(self.get_info()):
|
||||
if not k.startswith('scm'):
|
||||
k = 'scm' + k
|
||||
policy_data[k] = v
|
||||
policy_data.update(opts)
|
||||
result = (session.host.evalPolicy('build_from_scm', policy_data) or '').split()
|
||||
is_allowed = result and result[0].lower() in ('yes', 'true', 'allow', 'allowed')
|
||||
if not is_allowed:
|
||||
raise koji.BuildError(
|
||||
'SCM: %s:%s is not allowed, reason: %s' % (self.host, self.repository,
|
||||
' '.join(result[1:]) or None))
|
||||
# Apply options when it's allowed
|
||||
applied = result[1:]
|
||||
self.use_common = len(applied) != 0 and applied[0].lower() == 'use_common'
|
||||
idx = 1 if self.use_common else 0
|
||||
self.source_cmd = applied[idx:] or self.source_cmd
|
||||
if self.source_cmd is not None and len(self.source_cmd) > 0 \
|
||||
and self.source_cmd[0].lower() == 'none':
|
||||
self.source_cmd = None
|
||||
|
||||
def checkout(self, scmdir, session=None, uploadpath=None, logfile=None):
|
||||
"""
|
||||
Checkout the module from SCM. Accepts the following parameters:
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ class BaseTaskHandler(object):
|
|||
self.workdir = workdir
|
||||
self.logger = logging.getLogger("koji.build.BaseTaskHandler")
|
||||
self.manager = None
|
||||
self.taskinfo = None
|
||||
|
||||
def setManager(self, manager):
|
||||
"""Set the manager attribute
|
||||
|
|
@ -597,15 +598,20 @@ class BaseTaskHandler(object):
|
|||
|
||||
def run_callbacks(self, plugin, *args, **kwargs):
|
||||
if 'taskinfo' not in kwargs:
|
||||
try:
|
||||
taskinfo = self.taskinfo
|
||||
except AttributeError:
|
||||
self.taskinfo = self.session.getTaskInfo(self.id, request=True)
|
||||
taskinfo = self.taskinfo
|
||||
kwargs['taskinfo'] = taskinfo
|
||||
kwargs['taskinfo'] = self.taskinfo
|
||||
kwargs['session'] = self.session
|
||||
koji.plugin.run_callbacks(plugin, *args, **kwargs)
|
||||
|
||||
@property
|
||||
def taskinfo(self):
|
||||
if not getattr(self, '_taskinfo', None):
|
||||
self._taskinfo = self.session.getTaskInfo(self.id, request=True, strict=True)
|
||||
return self._taskinfo
|
||||
|
||||
@taskinfo.setter
|
||||
def taskinfo(self, taskinfo):
|
||||
self._taskinfo = taskinfo
|
||||
|
||||
|
||||
class FakeTask(BaseTaskHandler):
|
||||
Methods = ['someMethod']
|
||||
|
|
|
|||
|
|
@ -8,9 +8,40 @@ import unittest
|
|||
|
||||
import koji
|
||||
import koji.daemon
|
||||
import koji.policy
|
||||
|
||||
from koji.daemon import SCM
|
||||
|
||||
policy = {
|
||||
'one': '''
|
||||
match scmhost goodserver :: allow none
|
||||
match scmhost badserver :: deny
|
||||
match scmhost maybeserver && match scmrepository /badpath/* :: deny
|
||||
all :: allow
|
||||
''',
|
||||
'two': '''
|
||||
match scmhost default :: allow
|
||||
match scmhost nocommon :: allow
|
||||
match scmhost common :: allow use_common
|
||||
match scmhost srccmd :: allow fedpkg sources
|
||||
match scmhost nosrc :: allow none
|
||||
match scmhost mixed && match scmrepository /foo/* :: allow
|
||||
match scmhost mixed && match scmrepository /bar/* :: allow use_common
|
||||
match scmhost mixed && match scmrepository /baz/* :: allow fedpkg sources
|
||||
match scmhost mixed && match scmrepository /foobar/* :: allow use_common fedpkg sources
|
||||
match scmhost mixed && match scmrepository /foobaz/* :: allow use_common none
|
||||
'''
|
||||
}
|
||||
|
||||
class FakePolicy(object):
|
||||
|
||||
def __init__(self, rule):
|
||||
base_tests = koji.policy.findSimpleTests(vars(koji.policy))
|
||||
self.ruleset = koji.policy.SimpleRuleSet(rule.splitlines(), base_tests)
|
||||
|
||||
def evalPolicy(self, name, data):
|
||||
return self.ruleset.apply(data)
|
||||
|
||||
|
||||
class TestSCM(unittest.TestCase):
|
||||
|
||||
|
|
@ -67,8 +98,22 @@ class TestSCM(unittest.TestCase):
|
|||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
self.assertEqual(scm.scmtype, 'GIT')
|
||||
|
||||
def test_assert_allowed_basic(self):
|
||||
scm = SCM("git://scm.example.com/path1#1234")
|
||||
|
||||
# session must be passed
|
||||
with self.assertRaises(koji.GenericError) as cm:
|
||||
scm.assert_allowed(session=None, by_config=False, by_policy=True)
|
||||
self.assertEqual(str(cm.exception),
|
||||
'When allowed SCM assertion is by policy, session must be passed in.')
|
||||
|
||||
# allowed could not be None
|
||||
scm.assert_allowed_by_config = mock.MagicMock()
|
||||
scm.assert_allowed(allowed=None, by_config=True, by_policy=False)
|
||||
scm.assert_allowed_by_config.assert_called_once_with('')
|
||||
|
||||
@mock.patch('logging.getLogger')
|
||||
def test_allowed(self, getLogger):
|
||||
def test_allowed_by_config(self, getLogger):
|
||||
config = '''
|
||||
goodserver:*:no
|
||||
!badserver:*
|
||||
|
|
@ -104,7 +149,7 @@ class TestSCM(unittest.TestCase):
|
|||
raise AssertionError("allowed bad url: %s" % url)
|
||||
|
||||
@mock.patch('logging.getLogger')
|
||||
def test_badrule(self, getLogger):
|
||||
def test_badrule_by_config(self, getLogger):
|
||||
config = '''
|
||||
bogus-entry-should-be-ignored
|
||||
goodserver:*:no
|
||||
|
|
@ -115,7 +160,7 @@ class TestSCM(unittest.TestCase):
|
|||
scm.assert_allowed(config)
|
||||
|
||||
@mock.patch('logging.getLogger')
|
||||
def test_opts(self, getLogger):
|
||||
def test_opts_by_config(self, getLogger):
|
||||
config = '''
|
||||
default:*
|
||||
nocommon:*:no
|
||||
|
|
@ -196,6 +241,181 @@ class TestSCM(unittest.TestCase):
|
|||
with self.assertRaises(koji.BuildError):
|
||||
scm.assert_allowed(config)
|
||||
|
||||
def test_allowed_by_policy(self):
|
||||
good = [
|
||||
"git://goodserver/path1#1234",
|
||||
"git+ssh://maybeserver/path1#1234",
|
||||
]
|
||||
bad = [
|
||||
"cvs://badserver/projects/42#ref",
|
||||
"svn://badserver/projects/42#ref",
|
||||
"git://maybeserver/badpath/project#1234",
|
||||
"git://maybeserver//badpath/project#1234",
|
||||
"git://maybeserver////badpath/project#1234",
|
||||
"git://maybeserver/./badpath/project#1234",
|
||||
"git://maybeserver//.//badpath/project#1234",
|
||||
"git://maybeserver/goodpath/../badpath/project#1234",
|
||||
"git://maybeserver/goodpath/..//badpath/project#1234",
|
||||
"git://maybeserver/..//badpath/project#1234",
|
||||
]
|
||||
session = mock.MagicMock()
|
||||
session.host.evalPolicy.side_effect = FakePolicy(policy['one']).evalPolicy
|
||||
for url in good:
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(session=session, by_config=False, by_policy=True)
|
||||
for url in bad:
|
||||
scm = SCM(url)
|
||||
with self.assertRaises(koji.BuildError) as cm:
|
||||
scm.assert_allowed(session=session, by_config=False, by_policy=True)
|
||||
self.assertRegexpMatches(str(cm.exception), '^SCM: .* is not allowed, reason: None$')
|
||||
|
||||
def test_opts_by_policy(self):
|
||||
session = mock.MagicMock()
|
||||
session.host.evalPolicy.side_effect = FakePolicy(policy['two']).evalPolicy
|
||||
|
||||
url = "git://default/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://nocommon/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://common/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://srccmd/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://nosrc/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, None)
|
||||
|
||||
url = "git://mixed/foo/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/bar/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/baz/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://mixed/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
with self.assertRaises(koji.BuildError):
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
|
||||
url = "git://mixed/foo/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/bar/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/baz/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://mixed/foobar/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://mixed/foobaz/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertIsNone(scm.source_cmd)
|
||||
|
||||
url = "git://nomatch/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
with self.assertRaises(koji.BuildError):
|
||||
scm.assert_allowed_by_policy(session=session)
|
||||
|
||||
def test_assert_allowed_by_both(self):
|
||||
config = '''
|
||||
default:*:no:
|
||||
mixed:/foo/*:yes
|
||||
mixed:/bar/*:no
|
||||
mixed:/baz/*:no:centpkg,sources
|
||||
mixed:/foobar/*:no:
|
||||
mixed:/foobaz/*:no:centpkg,sources
|
||||
'''
|
||||
|
||||
session = mock.MagicMock()
|
||||
session.host.evalPolicy.side_effect = FakePolicy(policy['two']).evalPolicy
|
||||
|
||||
url = "git://default/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost default :: allow
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertIsNone(scm.source_cmd)
|
||||
|
||||
url = "git://mixed/foo/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost mixed && match scmrepository /foo/* :: allow
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/bar/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost mixed && match scmrepository /bar/* :: allow use_common
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['make', 'sources'])
|
||||
|
||||
url = "git://mixed/baz/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost mixed && match scmrepository /baz/* :: allow fedpkg sources
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, False)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://mixed/foobar/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost mixed && match scmrepository /foobar/* :: allow use_common fedpkg sources
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertEqual(scm.source_cmd, ['fedpkg', 'sources'])
|
||||
|
||||
url = "git://mixed/foobaz/koji.git#1234"
|
||||
scm = SCM(url)
|
||||
# match scmhost mixed && match scmrepository /foobaz/* :: allow use_common none
|
||||
scm.assert_allowed(allowed=config, session=session, by_config=True, by_policy=True)
|
||||
self.assertEqual(scm.use_common, True)
|
||||
self.assertIsNone(scm.source_cmd)
|
||||
|
||||
|
||||
class TestSCMCheckouts(unittest.TestCase):
|
||||
|
||||
|
|
|
|||
17
vm/kojivmd
17
vm/kojivmd
|
|
@ -138,6 +138,8 @@ def get_options():
|
|||
'offline_retry': True,
|
||||
'offline_retry_interval': 120,
|
||||
'allowed_scms': '',
|
||||
'allowed_scms_by_config': True,
|
||||
'allowed_scms_by_policy': False,
|
||||
'cert': None,
|
||||
'serverca': None}
|
||||
if config.has_section('kojivmd'):
|
||||
|
|
@ -149,7 +151,8 @@ def get_options():
|
|||
defaults[name] = int(value)
|
||||
except ValueError:
|
||||
quit("value for %s option must be a valid integer" % name)
|
||||
elif name in ['offline_retry', 'no_ssl_verify']:
|
||||
elif name in ['offline_retry', 'no_ssl_verify', 'allowed_scms_by_config',
|
||||
'allowed_scms_by_policy']:
|
||||
defaults[name] = config.getboolean('kojivmd', name)
|
||||
elif name in ['plugin', 'plugins']:
|
||||
defaults['plugin'] = value.split()
|
||||
|
|
@ -325,8 +328,16 @@ class WinBuildTask(MultiPlatformTask):
|
|||
# verify the urls before passing them to the VM
|
||||
for url in [source_url] + koji.util.to_list(subopts.values()):
|
||||
scm = SCM(url)
|
||||
scm.assert_allowed(self.options.allowed_scms)
|
||||
|
||||
scm.assert_allowed(allowed=self.options.allowed_scms,
|
||||
session=self.session,
|
||||
by_config=self.options.allowed_scms_use_config,
|
||||
by_policy=self.options.allowed_scms_use_policy,
|
||||
opts={
|
||||
'user_id': self.taskinfo['owner'],
|
||||
'channel': self.session.getChannel(self.taskinfo['channel_id'],
|
||||
strict=True)['name'],
|
||||
'scratch': opts.get('scratch')
|
||||
})
|
||||
task_info = self.session.getTaskInfo(self.id)
|
||||
target_info = self.session.getBuildTarget(target)
|
||||
if not target_info:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ server=http://hub.example.com/kojihub
|
|||
; dir, and will raise an exception if it cannot.
|
||||
allowed_scms=scm.example.com:/cvs/example git.example.org:/example svn.example.org:/users/*:no
|
||||
|
||||
; If use the option allowed_scms above for allowing / denying SCM, default: true
|
||||
; allowed_scms_use_config = true
|
||||
|
||||
; If use hub policy: build_from_scm for allowing / denying SCM, default: false
|
||||
; notice that if both options are enabled, both assertions will be applied, and user_common
|
||||
; will be overridden by the policy's result.
|
||||
; allowed_scms_use_policy = false
|
||||
|
||||
; The mail host to use for sending email notifications
|
||||
smtphost=example.com
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue