diff --git a/builder/kojid b/builder/kojid index ecf8451f..3dfc5009 100755 --- a/builder/kojid +++ b/builder/kojid @@ -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() diff --git a/builder/kojid.conf b/builder/kojid.conf index 4dc2a87e..777a421f 100644 --- a/builder/kojid.conf +++ b/builder/kojid.conf @@ -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 diff --git a/hub/kojixmlrpc.py b/hub/kojixmlrpc.py index 468461be..196e4730 100644 --- a/hub/kojixmlrpc.py +++ b/hub/kojixmlrpc.py @@ -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 diff --git a/koji/daemon.py b/koji/daemon.py index bcd01b21..3eba1a7e 100644 --- a/koji/daemon.py +++ b/koji/daemon.py @@ -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: diff --git a/koji/tasks.py b/koji/tasks.py index ca741caa..0a03c725 100644 --- a/koji/tasks.py +++ b/koji/tasks.py @@ -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'] diff --git a/tests/test_scm.py b/tests/test_scm.py index 54b26910..2ce67b46 100644 --- a/tests/test_scm.py +++ b/tests/test_scm.py @@ -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): diff --git a/vm/kojivmd b/vm/kojivmd index 89e96cf0..75ab017d 100755 --- a/vm/kojivmd +++ b/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: diff --git a/vm/kojivmd.conf b/vm/kojivmd.conf index 78e3f249..e6ae14fd 100644 --- a/vm/kojivmd.conf +++ b/vm/kojivmd.conf @@ -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