jenkins - 防止扩展 Jenkins 作业参数中的环境变量

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

问题

我正在做一个 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 创建了一个新的 Jenkins 安装。 Docker 镜像,在没有任何插件(甚至是默认设置)的情况下对其进行配置,并使用 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-10779 Non-existing parameters are not empty but replaced with parameter name
  • JENKINS-16143 Jenkins escapes 2 dollar signs in the Parameterized Build fields
  • JENKINS-26916 There should be an option to turn on/off variable substitution in build parameters
  • Jenkins text parameter - special characters garbled (unwanted variable substitution)
  • 最佳答案

    作为一种解决方法,我们可以添加一个初始构建步骤,直接读取所有参数并将它们编码到 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 批准此脚本第一次加载。因为它已经对所有参数进行了编码,所以您永远不需要修改它,并且无需重新批准就可以在其他作业中重用它。

    后续的“执行 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(…) 执行,其中有一条注释解释了不存在变量的异常处理(非替换):

    Unlike shell, undefined variables are left as-is (this behavior is the same as Ant.)



    这些扩展是无条件执行的,因此如果不修改或替换 Jenkins 中的几个类,就无法禁用它。

    关于jenkins - 防止扩展 Jenkins 作业参数中的环境变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54676455/

    相关文章:

    python - 将 python 脚本的输出获取到 Jenkinsfile 中的变量中

    javascript - 如何访问 React JS 网络应用程序中的环境变量?

    windows - 如何解析文件路径中的用户环境变量

    apache2 - 无法访问 Jenkins

    jenkins - 如何解决-Jenkins错误: Server rejected the private key(s) for slave

    jenkins - Jenkins Pipeline 中的 StreamingTemplateEngine 与普通 Groovy 中的 StreamingTemplateEngine

    java - 常规字符串到日期转换并添加天数

    java - Groovy 模拟文件构造函数,验证写入新创建的文件

    rest - 使用 REST 创建作业并在 jenkins 中执行它们

    python - 使用脚本参数 ("env: No match."的 pycharm 远程调试问题)