我正在从事Jenkins工作,该工作接受用户的一些参数。我遇到了一个不受欢迎的行为:在我的脚本有机会读取它们之前,Jenkins似乎正在扩展参数环境变量中的环境变量引用。
如果用户为参数输入foo-$BUILD_NUMBER
,我的脚本实际看到的是像foo-123
;环境变量已扩展。如果输入值包含$$
,我的脚本只能看到一个$
。但是,如果它包含环境中不存在的$variable
,则该值保持不变(不会引发任何类型的错误)。
这很不方便,因为它甚至发生在密码字段中,我通常使用可以包含$
字符的密码生成器。我不希望我的密码可能会被默默地破坏。
我的初始测试用例如下,使用Jenkins Job Builder Groovy DSL。
new BaseJobBuilder(
jobName: 'example',
jobBuildName: 'example-${BUILD_NUMBER}',
).build(this).with {
parameters {
nonStoredPasswordParam('SERVICE_PASSWORD')
}
steps {
shell('echo "$SERVICE_PASSWORD";')
}
}
但是,对于更简化的测试用例,我从jenkins/jenkins:lts
Docker映像创建了一个新的Jenkins安装,配置它没有任何插件(甚至是默认设置),并使用Web UI创建了一个等效的工作。
当我使用值hello $BUILD_NUMBER $HOME world
为我的参数SERVICE_PASSWORD
运行这些作业中的任何一个时,输出扩展了变量,而不是我想要的文字值。
Started by user jeremy
Building in workspace /var/jenkins_home/workspace/jeremy
[jeremy] $ /bin/sh -xe /tmp/jenkins2451955822062381529.sh
+ echo hello 3 /var/jenkins_home world
hello 3 /var/jenkins_home world
Finished: SUCCESS
有没有办法在Jenkins进行变量扩展/插值之前访问Jenkins的原始参数值,或以其他方式禁用或绕过这种行为?
如何接受可能包含$
美元字符的原始文本参数而不会有被破坏的风险?
作为一种解决方法,我们可以添加一个初始构建步骤,直接读取所有参数并在base64中对它们进行编码,然后将编码值导出为新的环境变量。 Base64编码的值不能包含任何美元字符$
,因此可以通过以后的构建步骤安全地读取它们,这可以解码它们以获得原始值而无需任何扩展。
我们使用the Groovy plugin的“System Groovy Script”构建步骤来实现它,它运行一个自定义Groovy脚本,可直接访问构建状态(感谢daspilker的建议)。如果您正在使用DSL,可以使用systemGroovyCommand("""…""")
调用添加它。
import hudson.EnvVars;
import hudson.model.Executor;
import hudson.model.Environment;
def build = Executor.currentExecutor().currentExecutable;
def newVariables = [:];
build.getBuildVariables().each { name, value ->
def encodedName = name + "_B64";
def encodedValue = value.bytes.encodeBase64().toString();
newVariables.put(encodedName, encodedValue);
}
build.getEnvironments().add(Environment.create(new EnvVars(newVariables)))
您的Jenkins管理员可能需要在第一次加载时从the In-process Script Approval page批准此脚本。因为它已经对所有参数进行了编码,所以您永远不需要对其进行修改,并且无需重新批准即可在其他作业中重复使用它。
随后的“执行Shell”步骤现在将能够解码原始值。
set -eu +vx;
echo "directly from environment: $SERVICE_PASSWORD";
SERVICE_PASSWORD="$(echo "$SERVICE_PASSWORD_B64" | base64 --decode)";
echo "via base-64 encoded value: $SERVICE_PASSWORD";
我们可以使用hello $BUILD_NUMBER $HOME world
的原始测试值来确认它的工作原理:
directly from environment: hello 12 /var/jenkins_home world
via base-64 encoded value: hello $BUILD_NUMBER $HOME world
从环境变量读取参数时,无法禁用变量扩展。此行为与具体参数无关,而是与Jenkins如何处理环境变量有关。在hudson.model.AbstractBuild.getEnvironment(…)
方法聚合构建的所有环境变量之后,它应用hudson.EnvVars.resolve(…)
函数对所有环境变量的内容执行互变量扩展。根据确切的构建配置,it may还使用hudson.EnvVars.overrideExpandingAll(…)
,它采用拓扑排序变量的额外步骤,以确保非循环引用都以正确的顺序扩展。实际的字符串操作由hudson.util.replaceMacro(…)
执行,其中有一条注释解释了不存在的变量的异常处理(非替换):
与shell不同,未定义的变量保持原样(此行为与Ant相同。)
这些扩展是无条件执行的,因此如果不修改或替换Jenkins中的几个类,就无法禁用它。