From 82148bdd389c561da09c36fd0a3ef00cfd330ef0 Mon Sep 17 00:00:00 2001
From: geargyri <georgios.argyriou@cern.ch>
Date: Mar 14 2023 13:02:25 +0000
Subject: [PATCH 1/2] add policy check


Related: https://pagure.io/koji/issue/3183

---

diff --git a/builder/kojid b/builder/kojid
index 6184b87..1447b9b 100755
--- a/builder/kojid
+++ b/builder/kojid
@@ -2563,6 +2563,23 @@ class BuildBaseImageTask(BuildImageTask):
                 "imagefactory, oz and possibly python-hashlib")
             raise koji.ApplianceError('ImageFactory functions not available')
 
+        # Policy check
+        task_info = self.session.getTaskInfo(self.id)
+        policy_data = {
+            'user_id': task_info['owner'],
+            'source': opts.get('ksurl'),
+            'task_id': self.id,
+            'build_tag': build_tag,  # id
+            'skip_tag': bool(self.opts.get('skip_tag')),
+            'scratch': bool(opts.get('scratch')),
+            'from_scm': False,
+            'repo_id': opts.get('repo_id'),
+            'target': target_info['name'],
+        }
+        if not self.opts.get('skip_tag'):
+            policy_data['tag'] = target_info['dest_tag']  # id
+        self.session.host.assertPolicy('build_rpm', policy_data)
+
         # build image(s)
         bld_info = None
         try:
@@ -2635,7 +2652,7 @@ class BuildBaseImageTask(BuildImageTask):
                 for arch in results:
                     if arch in ignored_arches:
                         continue
-                    ks = os.path.basename(opts.get('kickstart'))
+                    ks = os.path.basename(opts['kickstart'])
                     if ks in results[arch]['files']:
                         if saw_ks:
                             results[arch]['files'].remove(ks)
diff --git a/cli/koji_cli/commands.py b/cli/koji_cli/commands.py
index 2519060..c1b94be 100644
--- a/cli/koji_cli/commands.py
+++ b/cli/koji_cli/commands.py
@@ -6004,9 +6004,6 @@ def _build_image_oz(options, task_opts, session, args):
     # Upload the KS file to the staging area.
     # If it's a URL, it's kojid's job to go get it when it does the checkout.
     if not task_opts.ksurl:
-        if not task_opts.scratch:
-            # only scratch builds can omit ksurl
-            raise koji.GenericError("Non-scratch builds must provide ksurl")
         ksfile = task_opts.kickstart
         serverdir = unique_path('cli-image')
         session.uploadWrapper(ksfile, serverdir, callback=callback)
diff --git a/kojihub/kojihub.py b/kojihub/kojihub.py
index f705837..dd5583b 100644
--- a/kojihub/kojihub.py
+++ b/kojihub/kojihub.py
@@ -10322,8 +10322,6 @@ class RootExports(object):
                         'only admins may create high-priority tasks')
 
             taskOpts['priority'] = koji.PRIO_DEFAULT + priority
-        if 'scratch' not in opts and 'ksurl' not in opts:
-            raise koji.ActionNotAllowed('Non-scratch builds must provide ksurl')
 
         return make_task('image', [name, version, arches, target, inst_tree, opts], **taskOpts)
 
diff --git a/tests/test_cli/test_image_build.py b/tests/test_cli/test_image_build.py
index 42e2e56..99c2b8c 100644
--- a/tests/test_cli/test_image_build.py
+++ b/tests/test_cli/test_image_build.py
@@ -185,6 +185,36 @@ class TestBuildImageOz(utils.CliTestCase):
             '/path/to/cli-image',
             callback=None)
 
+    def test_build_image_oz_local_ks(self):
+        task_id = 107
+        # self.task_options.kickstart will be
+        # changed in _build_image_oz()
+        ksfile = self.task_options.kickstart
+        self.task_options.ksurl = None
+        self.task_options.scratch = False
+
+        self.session.getBuildTarget.return_value = self.target_info
+        self.session.getTag.return_value = self.tag_info
+        self.session.buildImageOz.return_value = task_id
+
+        self.task_options.background = True
+        self.running_in_bg.return_value = True
+        with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout:
+            _build_image_oz(
+                self.options, self.task_options, self.session, self.args)
+        expected = '' + '\n'
+        expected += "Created task: %d" % task_id + "\n"
+        expected += "Task info: %s/taskinfo?taskID=%s" % \
+                    (self.options.weburl, task_id) + "\n"
+        self.assert_console_message(stdout, expected)
+        self.watch_tasks.assert_not_called()
+        self.session.buildImageOz.assert_called_once()
+        self.unique_path.assert_called_with('cli-image')
+        self.session.uploadWrapper.assert_called_with(
+            ksfile,
+            '/path/to/cli-image',
+            callback=None)
+
     def test_build_image_oz_exception(self):
         self.session.getBuildTarget.return_value = {}
         with self.assertRaises(koji.GenericError) as cm:

From ea047d1363d6ada1efd474dee11cd6a2148eef83 Mon Sep 17 00:00:00 2001
From: Tomas Kopecek <tkopecek@redhat.com>
Date: Mar 14 2023 13:15:42 +0000
Subject: [PATCH 2/2] fix unit tests


---

diff --git a/tests/test_cli/test_image_build.py b/tests/test_cli/test_image_build.py
index 99c2b8c..ea44c27 100644
--- a/tests/test_cli/test_image_build.py
+++ b/tests/test_cli/test_image_build.py
@@ -228,13 +228,6 @@ class TestBuildImageOz(utils.CliTestCase):
         self.assertEqual(str(cm.exception),
                          'No such destination tag: %s' % self.target_info['dest_tag_name'])
 
-        self.session.getTag.return_value = self.tag_info
-        with self.assertRaises(koji.GenericError) as cm:
-            self.task_options.ksurl = None
-            self.task_options.scratch = False
-            _build_image_oz(self.options, self.task_options, self.session, self.args)
-        self.assertEqual(str(cm.exception), 'Non-scratch builds must provide ksurl')
-
 
 class TestImageBuild(utils.CliTestCase):
     def setUp(self):
diff --git a/tests/test_hub/test_build_image_oz.py b/tests/test_hub/test_build_image_oz.py
index e7ba584..49a29dc 100644
--- a/tests/test_hub/test_build_image_oz.py
+++ b/tests/test_hub/test_build_image_oz.py
@@ -50,12 +50,3 @@ class TestBuildImageOz(unittest.TestCase):
             self.exports.buildImageOz(self.name, self.version, self.arches, self.target,
                                       self.inst_tree, priority=priority)
         self.assertEqual("only admins may create high-priority tasks", str(cm.exception))
-
-    def test_opts_without_expected_keys(self):
-        priority = 10
-        opts = {}
-        self.context.session.assertPerm.side_effect = None
-        with self.assertRaises(koji.ActionNotAllowed) as cm:
-            self.exports.buildImageOz(self.name, self.version, self.arches, self.target,
-                                      self.inst_tree, opts=opts, priority=priority)
-        self.assertEqual("Non-scratch builds must provide ksurl", str(cm.exception))

