我写了一些在Jenkins Pipelines中使用的常规实用方法。一个简单的例子是:
// src/org/package/utils.groovy def remove_file(String file) { new File(file).delete() }
但是,正如预期的那样,这在Jenkins Pipeline中引发了以下异常:
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException:不允许脚本使用新的java.io.File java.lang.String
根据Script Security Plugin文档,我可以使用@Whitelisted
方法注释绕过它:
@Whitelisted def remove_file(String file) { new File(file).delete() }
根据这个问题,我可以使用@NonCPS
批注来绕过它(当然,此方法中的代码当然也不必可序列化):
@NonCPS def remove_file(String file) { new File(file).delete() }
共享库正在全局变量中使用,如下所示:
// vars/var.groovy import org.package.utils def method(body) { ... new utils().remove_file('file') ... }
库/ var正在导入,并在Jenkinsfile中使用,如下所示:
library identifier: 'lib@master', retriever: modernSCM( [$class: 'GitSCMSource', remote: 'https://github.com/org/repo.git']) pipeline { ... script { var.method { // body } } ... }
在列出的基于代码的导入管道共享库的方法中,我上面使用的方法似乎是唯一与标准Jenkins Pipeline插件集实际兼容的方法,所以我采用了这种方法。
这两个方法都未能绕过Jenkins Pipeline抛出的安全异常。绕过使用代码的脚本安全性插件并避免手动/人为错误的解决方案(例如在GUI中修改白名单)的最佳解决方案是什么?
我想根据您的最新评论和您对原始问题的更新,我了解发生了什么。我将尝试阐明全局共享库和“常规”共享库之间的区别。
在撰写本文时,有几种不同的方法可以在Jenkins实例中注册共享库。
Jenkins安装在全球范围内 -适用于所有管道执行。
对于Folder
-文件夹中的所有项目都有可用的管道库
自动库 -文档中提供的示例是GitHub Branch Source Plugin
库注册需要一些设置:
名称 -与library
步骤和@Library
注释一起使用的库名称
默认版本 -提交,分支,标签或其他一些标识符
隐式加载 -如果应隐式加载库(即,使用者不需要使用@Library
或library
)
检索方法 -如何检索SCM(例如使用Git或Mercurial)
允许覆盖默认版本 -如果使用者可以使用与默认版本不同的版本
上面提到的全局共享库绕过了安全沙箱,这意味着它们可以做任何事情。以下是一些相关文档:
由于这些库将在全球范围内可用,因此系统中的任何管道都可以利用这些库中实现的功能。
这些库被认为是“受信任的”:它们可以在Java,Groovy,Jenkins内部API,Jenkins插件或第三方库中运行任何方法。这使您可以定义将不安全的API分别封装在更高级别的包装器中的库,以供任何管道使用。请注意,任何能够将提交推送到此SCM存储库的人都可以无限制地访问Jenkins。您需要
Overall/RunScripts
配置这些库的权限(通常这将授予Jenkins管理员)。
这些是唯一绕过安全沙箱检查的管道库。其他类型(如文件夹库)经过安全检查,这意味着您无法执行new File(file).delete()
。
在管道中,用户可以访问对其可用的所有共享库。从安装或文件夹中隐式加载的库(上面称为“ 隐式加载”选项)在脚本类路径上自动可用。必须使用@Library
注释或library
步骤来引入其他库。
例如,假设您有一个包含以下选项的库:
名称 -my-shared-lib
默认版本 -master
隐式加载 -false
检索方法 -对某些存储库的现代Git SCM设置
允许覆盖默认版本 -true
您可以从管道中提取此特定库的几种方法是:
@Library('my-shared-lib')
-使用默认版本
@Library('my-shared-lib@develop')
-与覆盖版本一起使用 develop
def myLib = library('my-shared-lib')-与默认版本一起使用
def myLib = library('my-shared-lib@develop')
-与覆盖版本一起使用 develop
这些都将使用先前配置的库。
在您的示例中,您使用的是library
步骤,但是从远程存储库动态加载,而不是使用注册版本。这就是为什么要指定retriever
参数的原因。请记住,任何不是全局共享库的库 都不能绕过安全沙箱。
如果要使库绕过沙箱,则需要在Jenkins安装中将其注册为全局共享库。
附带说明new File(file).delete()
-请小心在Jenkins管道内编写“常规” Groovy(有关原因,请参见此答案)。