防止在Jenkins工作参数中扩展环境变量

时间:2019-02-13 17:49:11

标签: jenkins groovy environment-variables jenkins-plugins jenkins-job-dsl

问题

我正在从事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进行变量扩展/插值之前访问其原始参数值,或者以其他方式禁用或规避此行为?

我如何接受可能包含$个美元字符的原始文本参数,而又不会使其受到损坏的风险?

相关链接

1 个答案:

答案 0 :(得分:1)

作为一种解决方法,我们可以添加一个初始构建步骤,该步骤直接读取所有参数并将其编码为base64,然后将编码后的值导出为新的环境变量。 Base64编码的值不能包含任何美元字符$,因此可以在以后的构建步骤中安全地读取它们,后者可以对其进行解码以获取原始值,而无需进行任何扩展。

我们使用the Groovy plugin中的“系统Groovy脚本”构建步骤来实现这一点,该步骤运行一个定制的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时批准该脚本。因为它已经对所有参数进行了编码,所以您永远不需要修改它,并且无需重新批准就可以在其他作业中重用它。

随后的“执行外壳”步骤现在将能够解码原始值。

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中的几个类,就无法禁用它。