diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py index ee999a8..795a050 100644 --- a/pagure/hooks/pagure_ci.py +++ b/pagure/hooks/pagure_ci.py @@ -46,6 +46,8 @@ class PagureCITable(BASE): ci_type = sa.Column(sa.String(255), nullable=True) ci_url = sa.Column(sa.String(255), nullable=True, unique=False) ci_job = sa.Column(sa.String(255), nullable=True, unique=False) + ci_username = sa.Column(sa.String(255), nullable=True, unique=False) + ci_password = sa.Column(sa.String(255), nullable=True, unique=False) active = sa.Column(sa.Boolean, nullable=False, default=False) active_commit = sa.Column(sa.Boolean, nullable=False, default=False) active_pr = sa.Column(sa.Boolean, nullable=False, default=False) @@ -114,6 +116,16 @@ class PagureCiForm(FlaskForm): ], ) + ci_username = wtforms.StringField( + "Username to authenticate with if needed", + [wtforms.validators.Optional(), wtforms.validators.Length(max=255)], + ) + + ci_password = wtforms.StringField( + "Password to authenticate with if needed", + [wtforms.validators.Optional(), wtforms.validators.Length(max=255)], + ) + ci_job = wtforms.StringField( "Name of the job to trigger", [ diff --git a/pagure/lib/lib_ci.py b/pagure/lib/lib_ci.py index f2a30ec..eba958a 100644 --- a/pagure/lib/lib_ci.py +++ b/pagure/lib/lib_ci.py @@ -42,7 +42,11 @@ def process_jenkins_build(session, project, build_id, iteration=0): # Jenkins Base URL _log.info("Querying jenkins at: %s", project.ci_hook.ci_url) - jenk = jenkins.Jenkins(project.ci_hook.ci_url) + jenk = jenkins.Jenkins( + project.ci_hook.ci_url, + username=project.ci_hook.ci_username or None, + password=project.ci_hook.ci_password or None, + ) jenkins_name = project.ci_hook.ci_job _log.info( "Querying jenkins for project: %s, build: %s", jenkins_name, build_id @@ -130,7 +134,15 @@ def process_jenkins_build(session, project, build_id, iteration=0): def trigger_jenkins_build( - project_path, url, job, token, branch, branch_to, cause + project_path, + url, + job, + token, + branch, + branch_to, + cause, + ci_username=None, + ci_password=None, ): """ Trigger a build on a jenkins instance.""" try: @@ -150,7 +162,9 @@ def trigger_jenkins_build( "BRANCH_TO": branch_to, } - server = jenkins.Jenkins(url) + server = jenkins.Jenkins( + url, username=ci_username or None, password=ci_password or None + ) _log.info( "Pagure-CI: Triggering at: %s for: %s - data: %s", url, job, data ) diff --git a/pagure/lib/tasks_services.py b/pagure/lib/tasks_services.py index 4cef4e9..eb78d0a 100644 --- a/pagure/lib/tasks_services.py +++ b/pagure/lib/tasks_services.py @@ -463,23 +463,20 @@ def trigger_ci_build( if ci_type == "jenkins": + jenk_project = project if project.is_fork: - url = project.parent.ci_hook.ci_url - job = project.parent.ci_hook.ci_job - token = project.parent.ci_hook.pagure_ci_token - else: - url = project.ci_hook.ci_url - job = project.ci_hook.ci_job - token = project.ci_hook.pagure_ci_token + jenk_project = project.parent trigger_jenkins_build( project_path=project.path, - url=url, - job=job, - token=token, + url=jenk_project.ci_hook.ci_url, + job=jenk_project.ci_hook.ci_job, + token=jenk_project.ci_hook.pagure_ci_token, branch=branch, branch_to=branch_to, cause=cause, + ci_username=jenk_project.ci_hook.ci_username, + ci_password=jenk_project.ci_hook.ci_password, ) else: diff --git a/tests/test_pagure_flask_ui_plugins_pagure_ci.py b/tests/test_pagure_flask_ui_plugins_pagure_ci.py index 1604dc2..a32aaa1 100644 --- a/tests/test_pagure_flask_ui_plugins_pagure_ci.py +++ b/tests/test_pagure_flask_ui_plugins_pagure_ci.py @@ -6,6 +6,12 @@ import unittest import sys import os +import mock + +sys.path.insert(0, os.path.join(os.path.dirname( + os.path.abspath(__file__)), '..')) + +import pagure.lib.tasks_services import tests @@ -277,6 +283,101 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest): '
\nhttp://localhost.localdomain/api/0/ci/jenkins/somenamespace/test3/', output_text) + @mock.patch('pagure.lib.tasks_services.trigger_jenkins_build') + def test_plugin_pagure_ci_namespaced_auth(self, trigger_jenk): + """ Test the pagure ci plugin on/off endpoint. """ + + tests.create_projects(self.session) + tests.create_projects_git(os.path.join(self.path, 'repos')) + + user = tests.FakeUser(username='pingou') + with tests.user_set(self.app.application, user): + output = self.app.get('/somenamespace/test3/settings/Pagure CI') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + 'Settings Pagure CI - somenamespace/test3 - ' + 'Pagure ', output_text) + self.assertIn( + '', output_text) + self.assertIn( + '', output_text) + self.assertIn( + '', output_text) + + csrf_token = output_text.split( + 'name="csrf_token" type="hidden" value="')[1].split('">')[0] + + # Activate hook + data = { + 'active_pr': 'y', + 'ci_url': 'https://jenkins.fedoraproject.org', + 'ci_job': 'test/job', + 'ci_type': 'jenkins', + 'ci_username': 'jenkins_username', + 'ci_password': 'jenkins_password', + 'csrf_token': csrf_token, + } + + # Activate hook + output = self.app.post( + '/somenamespace/test3/settings/Pagure CI', data=data, follow_redirects=True) + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + '' + 'Project Settings
\n', output_text) + self.assertIn( + 'Settings - somenamespace/test3 - Pagure ', + output_text) + self.assertIn( + '' + 'Project Settings
\n', output_text) + self.assertIn( + 'Hook Pagure CI activated', + output_text) + + output = self.app.get('/somenamespace/test3/settings/Pagure CI') + self.assertEqual(output.status_code, 200) + output_text = output.get_data(as_text=True) + self.assertIn( + 'Settings Pagure CI - somenamespace/test3 - ' + 'Pagure ', output_text) + self.assertIn( + '', output_text) + self.assertIn( + '', output_text) + self.assertIn( + '', output_text) + self.assertIn( + '\nhttp://localhost.localdomain/api/0/ci/jenkins/somenamespace/test3/', + output_text) + + output = pagure.lib.tasks_services.trigger_ci_build( + project_name='somenamespace/test3', + cause='PR#ID', + branch='feature', + branch_to='master', + ci_type='jenkins') + self.assertIsNone(output) + trigger_jenk.assert_called_once_with( + branch=u'feature', + cause=u'PR#ID', + ci_password="jenkins_password", + ci_username="jenkins_username", + job=u'test/job', + project_path=u'somenamespace/test3.git', + token=mock.ANY, + url=u'https://jenkins.fedoraproject.org', + branch_to='master', + ) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/tests/test_pagure_lib_task_services.py b/tests/test_pagure_lib_task_services.py index a5063bd..866bbeb 100644 --- a/tests/test_pagure_lib_task_services.py +++ b/tests/test_pagure_lib_task_services.py @@ -587,6 +587,8 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests): trigger_jenk.assert_called_once_with( branch=u'feature', cause=u'PR#ID', + ci_password=None, + ci_username=None, job=u'pagure', project_path=u'test.git', token=u'random_token', @@ -607,6 +609,118 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests): trigger_jenk.assert_called_once_with( branch=u'feature', cause=u'PR#ID', + ci_password=None, + ci_username=None, + job=u'pagure', + project_path=u'forks/foo/test.git', + token=u'random_token', + url=u'https://ci.server.org/', + branch_to='master', + ) + + +class PagureLibTaskServicesJenkinsCIAuthtests(tests.Modeltests): + """ Tests for pagure.lib.task_services """ + + maxDiff = None + + def setUp(self): + """ Set up the environnment, ran before every tests. """ + super(PagureLibTaskServicesJenkinsCIAuthtests, self).setUp() + + pagure.config.config['REQUESTS_FOLDER'] = None + self.sshkeydir = os.path.join(self.path, 'sshkeys') + pagure.config.config['MIRROR_SSHKEYS_FOLDER'] = self.sshkeydir + + tests.create_projects(self.session) + project = pagure.lib.query.get_authorized_project(self.session, 'test') + + # Install the plugin at the DB level + plugin = pagure.lib.plugins.get_plugin('Pagure CI') + dbobj = plugin.db_object() + dbobj.ci_url = 'https://ci.server.org/' + dbobj.ci_job = 'pagure' + dbobj.ci_username = 'jenkins_username' + dbobj.ci_password = 'jenkins_password' + dbobj.pagure_ci_token = 'random_token' + dbobj.project_id = project.id + self.session.add(dbobj) + self.session.commit() + + # Create a fork of test for foo + item = pagure.lib.model.Project( + user_id=2, # foo + name='test', + is_fork=True, + parent_id=1, + description='test project #1', + hook_token='aaabbbccc_foo', + ) + item.close_status = ['Invalid', 'Insufficient data', 'Fixed', 'Duplicate'] + self.session.add(item) + self.session.commit() + + @patch('pagure.lib.tasks_services.trigger_jenkins_build') + def test_trigger_ci_build_invalid_ci(self, trigger_jenk): + """ Test the trigger_ci_build method. """ + output = pagure.lib.tasks_services.trigger_ci_build( + project_name='test', + cause='PR#ID', + branch='feature', + branch_to='master', + ci_type='travis') + self.assertIsNone(output) + trigger_jenk.assert_not_called() + + @patch('pagure.lib.tasks_services.trigger_jenkins_build') + def test_trigger_ci_build_invalid_ci_fork(self, trigger_jenk): + """ Test the trigger_ci_build method. """ + output = pagure.lib.tasks_services.trigger_ci_build( + project_name='forks/foo/test', + cause='PR#ID', + branch='feature', + branch_to='master', + ci_type='travis') + self.assertIsNone(output) + trigger_jenk.assert_not_called() + + @patch('pagure.lib.tasks_services.trigger_jenkins_build') + def test_trigger_ci_build_valid_project(self, trigger_jenk): + """ Test the trigger_ci_build method. """ + output = pagure.lib.tasks_services.trigger_ci_build( + project_name='test', + cause='PR#ID', + branch='feature', + branch_to='master', + ci_type='jenkins') + self.assertIsNone(output) + trigger_jenk.assert_called_once_with( + branch=u'feature', + cause=u'PR#ID', + ci_password="jenkins_password", + ci_username="jenkins_username", + job=u'pagure', + project_path=u'test.git', + token=u'random_token', + url=u'https://ci.server.org/', + branch_to='master', + ) + + @patch('pagure.lib.tasks_services.trigger_jenkins_build') + def test_trigger_ci_build_valid_project_fork(self, trigger_jenk): + """ Test the trigger_ci_build method. """ + output = pagure.lib.tasks_services.trigger_ci_build( + project_name='forks/foo/test', + cause='PR#ID', + branch='feature', + branch_to='master', + ci_type='jenkins') + self.assertIsNone(output) + trigger_jenk.assert_called_once_with( + branch=u'feature', + cause=u'PR#ID', + ci_password="jenkins_password", + ci_username="jenkins_username", job=u'pagure', project_path=u'forks/foo/test.git', token=u'random_token',