#4364 Add support for username and password based authentication for pagure-ci
Merged 5 years ago by pingou. Opened 5 years ago by pingou.

file modified
+12
@@ -46,6 +46,8 @@ 

      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 @@ 

          ],

      )

  

+     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",

          [

file modified
+17 -3
@@ -42,7 +42,11 @@ 

  

      # 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 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 @@ 

          "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

      )

file modified
+7 -10
@@ -463,23 +463,20 @@ 

  

      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:

@@ -6,6 +6,12 @@ 

  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 @@ 

                  '<pre>\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(

+                 '<title>Settings Pagure CI - somenamespace/test3 - '

+                 'Pagure</title>', output_text)

+             self.assertIn(

+                 '<label for="ci_url">URL to the project on the CI '

+                 'service</label>', output_text)

+             self.assertIn(

+                 '<label for="ci_job">Name of the job to trigger'

+                 '</label>', output_text)

+             self.assertIn(

+                 '<input class="form-check-input mt-2" id="active_pr" name="active_pr" '

+                 'type="checkbox" value="y">', 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(

+                 '<h5 class="pl-2 font-weight-bold text-muted">'

+                 'Project Settings</h5>\n', output_text)

+             self.assertIn(

+                 '<title>Settings - somenamespace/test3 - Pagure</title>',

+                 output_text)

+             self.assertIn(

+                 '<h5 class="pl-2 font-weight-bold text-muted">'

+                 'Project Settings</h5>\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(

+                 '<title>Settings Pagure CI - somenamespace/test3 - '

+                 'Pagure</title>', output_text)

+             self.assertIn(

+                 '<label for="ci_url">URL to the project on the CI '

+                 'service</label>', output_text)

+             self.assertIn(

+                 '<label for="ci_job">Name of the job to trigger'

+                 '</label>', output_text)

+             self.assertIn(

+                 '<input checked class="form-check-input mt-2" id="active_pr" name="active_pr" '

+                 'type="checkbox" value="y">', output_text)

+             self.assertIn(

+                 '<pre>\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)

@@ -587,6 +587,8 @@ 

          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 @@ 

          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',

We used to query jenkins directly via an username provided URL, we
switch to using the python jenkins library, which requires username and
password to be specified in a different way.
This commit asks for the user to specify the username and password to
use to authenticate to jenkins and provides them to the python jenkins
library as they should be.

Fixes https://pagure.io/pagure/issue/4120

Signed-off-by: Pierre-Yves Chibon pingou@pingoured.fr

@pingou Does this mean arbitrary Jenkins servers can be connected to pagure projects, too?

@ngompa that has always been the case

@pingou silly me, I missed that bit :stuck_out_tongue:

Pull-Request has been merged by pingou

5 years ago