代码之家  ›  专栏  ›  技术社区  ›  Jeremy Meo

用Jenkins作业DSL防止参数中环境变量的插值

  •  0
  • Jeremy Meo  · 技术社区  · 7 年前

    问题

    我在做一个Jenkins的工作,它接受用户的一些参数。我遇到了一个不受欢迎的行为:在我的脚本有机会读取环境变量之前,Jenkins似乎正在扩展参数环境变量中的环境变量引用。

    如果用户输入 foo-$BUILD_NUMBER 对于一个参数,我的脚本实际上看到的是 foo-123 $$ ,我的脚本只看到一个 $ . 但是,如果它包含 $variable

    这很不方便,因为它甚至出现在密码字段中,我通常使用一个密码生成器,它可以包括 角色。我不希望我的密码可能会被悄悄地损坏。

    例子

    我的初始测试用例如下,使用Jenkins作业生成器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镜像,在没有任何插件的情况下进行配置(甚至默认),并使用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的原始参数值受到变量扩展/插值之前,是否有任何方法可以访问它们,或者以其他方式禁用或规避此行为?

    如何接受可能包含 $ 美元字符没有被损坏的风险?

    0 回复  |  直到 7 年前
        1
  •  1
  •   Jeremy Meo    7 年前

    作为解决方法,我们可以添加一个初始构建步骤,直接读取所有参数并将其编码到 base64 $ ,以便以后的构建步骤可以安全地读取它们,这些步骤可以对它们进行解码以获得原始值,而无需任何扩展。

    我们通过一个“System Groovy脚本”构建步骤来实现 the Groovy plugin 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

    接下来的“Execute 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
    

    hudson.model.AbstractBuild.getEnvironment(…) 方法聚合生成的所有环境变量,它应用 hudson.EnvVars.resolve(…) 要执行的功能 所有环境变量内容的互变量展开 . 根据具体的构建配置, it may 同时使用 hudson.EnvVars.overrideExpandingAll(…) ,这需要对变量进行拓扑排序,以确保非循环引用都以正确的顺序展开。实际的字符串操作由 hudson.util.replaceMacro(…) 它有一个注释来解释不存在的变量的异常处理(不替换):

    与shell不同,未定义的变量保持原样(此行为与Ant相同)

    这些扩展是无条件执行的,因此没有办法在不修改或替换Jenkins中的几个类的情况下禁用它。