Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-31201

Job DSL support for ScriptApproval (was: Groovy postbuild ignores RUN_SCRIPTS permission)

    Details

    • Similar Issues:

      Description

      The Groovy Postbuild plugin doesn't appear to adhere to the Jenkins.RUN_SCRIPTS permission at all. I'm generating jobs using the Job DSL Plugin and have given the RUN_SCRIPTS permission to the anonymous user.

      When I generate scripts this plugin still requires the script approval.

      Authentication is enabled but anonymous is given RunScripts permission. I would assume anybody would be able to create scripts (including the Job DSL plugin generated jobs).

        Attachments

          Issue Links

            Activity

            Hide
            sag47 Sam Gleske added a comment -

            Possibly related to JENKINS-22661? The behavior seems different, though.

            Show
            sag47 Sam Gleske added a comment - Possibly related to JENKINS-22661 ? The behavior seems different, though.
            Hide
            sag47 Sam Gleske added a comment -

            I reverse engineered how script approvals work and automatically approve scripts via hashing. I didn't have time for an upstream fix for this and I don't know what it would be.

            Show
            sag47 Sam Gleske added a comment - I reverse engineered how script approvals work and automatically approve scripts via hashing. I didn't have time for an upstream fix for this and I don't know what it would be.
            Hide
            sag47 Sam Gleske added a comment -

            The workaround in Job DSL is essentially:

            job {
                publishers {
                    def groovyscript = "some groovy script"
                    groovyPostBuild(groovyscript, Behavior.DoNothing)
                    //pre-approve post-build groovy scripts
                    def scriptApproval = Jenkins.instance.getExtensionList('org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval')[0]
                    scriptApproval.approveScript(scriptApproval.hash(groovyscript, 'groovy'))
                }
            }
            
            Show
            sag47 Sam Gleske added a comment - The workaround in Job DSL is essentially: job { publishers { def groovyscript = "some groovy script" groovyPostBuild(groovyscript, Behavior.DoNothing) //pre-approve post-build groovy scripts def scriptApproval = Jenkins.instance.getExtensionList( 'org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval' )[0] scriptApproval.approveScript(scriptApproval.hash(groovyscript, 'groovy' )) } }
            Hide
            jglick Jesse Glick added a comment -

            Nothing specific to Groovy Postbuild.

            The originally reported situation is nonsensical. If you granted anonymous RUN_SCRIPTS, it is game over—you may as well disable security altogether, in which case script approval is also skipped.

            The legitimate case is that you have a secured instance in which there is an administrator who is the only one able to create jobs (otherwise anyone could create a Job DSL project), and you want projects created via DSL to have their scripts preapproved. This probably requires a new API in script-security and a call to that API from job-dsl in createNewItem/updateExistingItem to associate a user with the item. (Really that user ought to have been defined by the authorize-project plugin, and job-dsl itself should use script-security to guard scripts. As written, it can only be used in an installation in which no one other than superusers have any write permissions, and all SCM commits are trusted.)

            Show
            jglick Jesse Glick added a comment - Nothing specific to Groovy Postbuild. The originally reported situation is nonsensical. If you granted anonymous RUN_SCRIPTS , it is game over—you may as well disable security altogether, in which case script approval is also skipped. The legitimate case is that you have a secured instance in which there is an administrator who is the only one able to create jobs (otherwise anyone could create a Job DSL project), and you want projects created via DSL to have their scripts preapproved. This probably requires a new API in script-security and a call to that API from job-dsl in createNewItem / updateExistingItem to associate a user with the item. (Really that user ought to have been defined by the authorize-project plugin, and job-dsl itself should use script-security to guard scripts. As written, it can only be used in an installation in which no one other than superusers have any write permissions, and all SCM commits are trusted.)
            Hide
            sag47 Sam Gleske added a comment -

            That's precisely our setup. Everything is programmatically generated and there are no human super users.

            Show
            sag47 Sam Gleske added a comment - That's precisely our setup. Everything is programmatically generated and there are no human super users.
            Hide
            sag47 Sam Gleske added a comment - - edited

            I essentially wanted to disable the script security plugin and giving Anonymous RUN_SCRIPTS permission is how I could accomplish that. However, the Groovy postbuild plugin doesn't even adhere to the runscripts permission. I still think that's a bug in the groovy postbuild plugin. Though, the Job DSL plugin could support it.

            In any case, I already pre-approve the scripts so this no longer is blocking me.

            Show
            sag47 Sam Gleske added a comment - - edited I essentially wanted to disable the script security plugin and giving Anonymous RUN_SCRIPTS permission is how I could accomplish that. However, the Groovy postbuild plugin doesn't even adhere to the runscripts permission. I still think that's a bug in the groovy postbuild plugin. Though, the Job DSL plugin could support it. In any case, I already pre-approve the scripts so this no longer is blocking me.
            Hide
            jglick Jesse Glick added a comment -

            the Groovy postbuild plugin doesn't even adhere to the runscripts permission

            For whole-script approval mode (as opposed to the Groovy sandbox), RUN_SCRIPTS is checked only for actual users who are saving a configuration—or anonymous if somehow the configuration is being saved from a web request made by a non-logged-in user. If a job definition comes out of the blue, as it seems to when Job DSL creates it without any further API calls, there is no information available to decide whether or not it should be trusted. Granting RUN_SCRIPTS to anonymous, besides disabling all security on your instance, would not accomplish that because there is not even a recognized event during which to check the security context.

            As I say, the only way to make this work is to offer a new API which Job DSL could call to signify that it is intentionally creating or overwriting job configuration on behalf of an unidentified but fully trusted agent.

            Show
            jglick Jesse Glick added a comment - the Groovy postbuild plugin doesn't even adhere to the runscripts permission For whole-script approval mode (as opposed to the Groovy sandbox), RUN_SCRIPTS is checked only for actual users who are saving a configuration—or anonymous if somehow the configuration is being saved from a web request made by a non-logged-in user. If a job definition comes out of the blue, as it seems to when Job DSL creates it without any further API calls, there is no information available to decide whether or not it should be trusted. Granting RUN_SCRIPTS to anonymous , besides disabling all security on your instance, would not accomplish that because there is not even a recognized event during which to check the security context. As I say, the only way to make this work is to offer a new API which Job DSL could call to signify that it is intentionally creating or overwriting job configuration on behalf of an unidentified but fully trusted agent.
            Hide
            nels4784 Jeffrey Nelson added a comment -

            Any ideas when a solution for this issue could be worked on?

            My project is now building many pipelines where the starting job uses the Active Choices Param plugin with complex groovy scripts. Without some solution to this problem, we are stuck manually approving all (60+) scripts that are all near identical.

            Show
            nels4784 Jeffrey Nelson added a comment - Any ideas when a solution for this issue could be worked on? My project is now building many pipelines where the starting job uses the Active Choices Param plugin with complex groovy scripts. Without some solution to this problem, we are stuck manually approving all (60+) scripts that are all near identical.
            Hide
            nels4784 Jeffrey Nelson added a comment -

            Figured out a workaround.

            1. Write a scriptler script that approves pending scripts with a given identifier (we used something simple like '// SCRIPTLER AUTO APPROVE'). Thanks to Sam Gleske for pointing me to the code to approve a script.

            – Select 'Permission' option (Allow execution by user with RunScripts permission)
            – Select 'Restriction' option (Script is always executed on Master)
            – Script parameter: "approvalPrefix"

            – Script:

            import jenkins.model.Jenkins
            
            def scriptApproval = Jenkins.instance.getExtensionList('org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval')[0]
            def hashesToApprove = scriptApproval.pendingScripts.findAll{ it.script.startsWith(approvalPrefix) }.collect{ it.getHash() }
            hashesToApprove.each { 
              scriptApproval.approveScript(it)
            }

            2. use the configure UI to add another step to your DSL seed job to run this scriptler script created in step 1
            3. add '// SCRIPTLER AUTO APPROVE' at the top of any groovy script you want approved

            If your DSL seed job is itself configured by DSL, complete steps 4-5
            4. look at the config.xml generated by manually adding this step to your DSL seed job. You need to grab the value in the 'builderId' field
            5. add the additional step to your DSL seed job to run this scriptler script created above in step 1.
            – dsl for adding the step:

                  def approvePrefixParam = {
                    name 'approvalPrefix'
                    value '// SCRIPTLER AUTO APPROVE'
                  }
                  
                  configure { project ->
                    project / builders << 'org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder' {
                      builderId(<builderIdGrabbedFromXml>)
                      scriptId('approveGroovyScripts.groovy')
                      propagateParams(false)
                      parameters {
                        'org.jenkinsci.plugins.scriptler.config.Parameter' approvePrefixParam
                      }
                    }
                  }
            Show
            nels4784 Jeffrey Nelson added a comment - Figured out a workaround. 1. Write a scriptler script that approves pending scripts with a given identifier (we used something simple like '// SCRIPTLER AUTO APPROVE'). Thanks to Sam Gleske for pointing me to the code to approve a script. – Select 'Permission' option (Allow execution by user with RunScripts permission) – Select 'Restriction' option (Script is always executed on Master) – Script parameter: "approvalPrefix" – Script: import jenkins.model.Jenkins def scriptApproval = Jenkins.instance.getExtensionList( 'org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval' )[0] def hashesToApprove = scriptApproval.pendingScripts.findAll{ it.script.startsWith(approvalPrefix) }.collect{ it.getHash() } hashesToApprove.each { scriptApproval.approveScript(it) } 2. use the configure UI to add another step to your DSL seed job to run this scriptler script created in step 1 3. add '// SCRIPTLER AUTO APPROVE' at the top of any groovy script you want approved If your DSL seed job is itself configured by DSL, complete steps 4-5 4. look at the config.xml generated by manually adding this step to your DSL seed job. You need to grab the value in the 'builderId' field 5. add the additional step to your DSL seed job to run this scriptler script created above in step 1. – dsl for adding the step: def approvePrefixParam = { name 'approvalPrefix' value ' // SCRIPTLER AUTO APPROVE' } configure { project -> project / builders << 'org.jenkinsci.plugins.scriptler.builder.ScriptlerBuilder' { builderId(<builderIdGrabbedFromXml>) scriptId( 'approveGroovyScripts.groovy' ) propagateParams( false ) parameters { 'org.jenkinsci.plugins.scriptler.config.Parameter' approvePrefixParam } } }
            Hide
            jglick Jesse Glick added a comment -

            Without some solution to this problem

            Best to switch to using the Groovy sandbox, which bypasses all these issues.

            Show
            jglick Jesse Glick added a comment - Without some solution to this problem Best to switch to using the Groovy sandbox, which bypasses all these issues.
            Hide
            jglick Jesse Glick added a comment -

            Probably the way this should work is that you should use the Authorize Project plugin to associate an (administrative) authentication with the DSL job. Then whatever in Job DSL actually writes out the job definition and loads it—this seems to be JenkinsJobManagement.createOrUpdateConfig—just needs to be run as part of that authentication, which I think is already the case. That would suffice for ScriptApproval.configuring to associate the script with the administrator. Needs to be tested, but it is possible this already works without code changes, if your system is properly configured.

            Show
            jglick Jesse Glick added a comment - Probably the way this should work is that you should use the Authorize Project plugin to associate an (administrative) authentication with the DSL job. Then whatever in Job DSL actually writes out the job definition and loads it—this seems to be JenkinsJobManagement.createOrUpdateConfig —just needs to be run as part of that authentication, which I think is already the case. That would suffice for ScriptApproval.configuring to associate the script with the administrator. Needs to be tested, but it is possible this already works without code changes, if your system is properly configured.

              People

              • Assignee:
                Unassigned
                Reporter:
                sag47 Sam Gleske
              • Votes:
                7 Vote for this issue
                Watchers:
                12 Start watching this issue

                Dates

                • Created:
                  Updated: