共享库全局变量中的字符串插值

String interpolation in a shared library's global variable

云蜂 2.289.1.2

我正在根据 Jenkinsfile string interpolation 指南更改代码。 注意:我知道 Groovy 字符串插值需要包含变量的双引号。

共享库中的几个全局变量(在vars/下)有几个sh。

目前(不使用 Jenkins 的字符串插值指令),下面指定的命令会给出警告(在每个命令后显示)。

第一个命令: 此命令无法填充 custom/user-defined 变量,但 似乎 填充了用户名和密码:

String resultingImage = "${repo}/${parameters.openshiftProject}/${appImageName}"
                    .toLowerCase()
// tag images
withCredentials([usernamePassword(
                credentialsId: pushCredentialsId,
                passwordVariable: 'password',
                usernameVariable: 'username')]) {

    parameters[IMAGE_TAGS].each { tagName ->
        sh 'set +x skopeo copy docker://$resultingImage:latest docker://$resultingImage:$tagName --src-tls-verify=false --src-creds=$username:$password --dest-creds=$username:$password echo "done copying ${resultingImage}:${tagName}"'
              }
  }

输出:

[Pipeline] withCredentials
Masking supported pattern matches of $username or $password
[Pipeline] {
[Pipeline] sh
+ set +x skopeo copy docker://:latest docker://: --src-tls-verify=false '--src-creds=****:****' '--dest-creds=****:****' echo 'done copying :'

如果使用双引号,则会显示以下警告,但命令格式正确:

[Pipeline] {
[Pipeline] sh
Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure.
         Affected argument(s) used the following variable(s): [password, username]
         See https://jenkins.io/redirect/groovy-string-interpolation for details.
+ set +x

第二个命令: 这会引发错误(似乎 凭证已正确检索),无论我使用“${chartTarballName}”还是 ${chartTarballName}或 $chartTarballName:

sh 'curl -f -u $username:$password -T "${chartTarballName}" $chartPublishRepo/$chartTarballName'

错误:

[Pipeline] sh
+ curl -f -u ****:**** -T '' /
curl: (3) <url> malformed
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
ERROR: script returned exit code 3

如果使用双引号,则会显示以下警告,但命令格式正确:

Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure.
Affected argument(s) used the following variable(s): [password, username]
See https://jenkins.io/redirect/groovy-string-interpolation for details.
+ curl -f -u ****:**** -T exp-calculator-0.14.11.tgz https://repository.net/artifactory/stable-local/exp-calculator-0.14.11.tgz

我猜想这些插值规则只适用于声明性管道指令,不适用于共享库中的脚本管道、全局变量(至少是用户定义的变量)和其他 Groovy DSL脚本。

更新 1:

单引号似乎只适用于标准指令管道指令:

pipeline {
    environment {
        CUSTOM_ENV_VAR = 'This is an environment variable'
    }
    agent  any
    stages {
        stage('build') {
            steps {
                withCredentials([string(credentialsId: 'sq_token', variable: 'SECRET')]) {
                    sh ("echo $SECRET")
                    sh ('echo $SECRET $CUSTOM_ENV_VAR')
                    
                    script {
                       String scriptBlockVariable = 'This is a variable in a script block'
                       sh ('echo $scriptBlockVariable')
                       sh ('echo $SECRET $scriptBlockVariable')
                    }
                }
            }
        }
    }
}

输出:

[Pipeline] stage
[Pipeline] { (build)
[Pipeline] withCredentials
Masking supported pattern matches of $SECRET
[Pipeline] {
[Pipeline] sh
Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure.
         Affected argument(s) used the following variable(s): [SECRET]
         See https://jenkins.io/redirect/groovy-string-interpolation for details.
+ echo ****
****
[Pipeline] sh
+ echo **** This is an environment variable
**** This is an environment variable
[Pipeline] script
[Pipeline] {
[Pipeline] sh
+ echo

[Pipeline] sh
+ echo ****
****
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // withCredentials
[Pipeline] }
[Pipeline] // stage

试着这样看:当你执行一个使用解释器的作业时,如shbatpowershell,有两个单独的上下文保存参数执行。
第一个上下文是实际的 groovy 代码,它包含代码定义的所有参数,它可以是输入参数、全局参数或在代码中使用 def 关键字定义的任何参数。
第二个上下文是参数集,每当您 运行 解释器步骤(shbatpowershell 时,这些参数将被加载到执行 运行time 环境中),此参数将作为环境参数提供给这些步骤。

第一个上下文groovy运行的string interpolation只能访问代码中定义的变量,而[=78=传递和执行的命令] 步骤只能访问第二个上下文中的参数。在您的情况下,您将两者混合在一起。

现在让我们检查一下不同的关键字及其范围:
用于定义参数的简单 def 语句将使它可用于 第一个上下文 - groovy 代码以及字符串插值。
声明管道中的 parameters 块是一个特殊关键字,它使参数在 两种上下文中都可用 - 它可用于 groovy 代码,但也作为运行 shell 步 environment.It 时间环境的环境变量支持常规参数和凭据。
脚本化管道不能使用 parameters 指令,相反它们有一个不同的关键字用于向执行环境添加参数,称为 withEnv:

withEnv - Sets one or more environment variables within a block. These are available to any external processes spawned within that scope.

withEnv 仅支持常规参数,因此引入了另一个关键字来支持凭据:withCredentials 可以像 withEnv 步骤那样设置凭据参数。

回到你的问题:

Jenkins确实recommends不对敏感参数使用字符串插值,而是将它们传递给执行环境(context 2)并让shell 步骤将它们用作环境变量,因此您需要用单引号定义字符串,但另一方面,您希望使用代码中定义的参数 (context 1)只能使用需要双引号的字符串插值进行评估。所以你实际上是在尝试同时使用来自两个上下文的参数,这有点棘手。

处理这种混合物有两种选择:

1 - 在 withEnv 关键字旁边使用 withCredentials,使用 shell 语法参数参考 ($) 用单引号定义字符串(禁用字符串插值)并让 shell 从环境变量中提取所有参数 。类似于:

String resultingImage = "${repo}/${parameters.openshiftProject}/${appImageName}".toLowerCase()
// tag images
withCredentials([usernamePassword(credentialsId: pushCredentialsId, passwordVariable: 'password',usernameVariable: 'username')]) {
    parameters[IMAGE_TAGS].each { tagName ->
        withEnv(['TAG_NAME=tagName', "IMAGE=${resultingImage}"]) {
            sh 'set +x skopeo copy docker://$IMAGE:latest docker://$IMAGE:$TAG_NAME --src-tls-verify=false --src-creds=$username:$password --dest-creds=$username:$password echo "done copying $IMAGE:$TAG_NAME"'
        }
    }
}

2 - 将命令字符串的创建分成几个部分,每个部分处理正确的上下文 - groovy 将在创建命令时评估参数,仅评估相关参数 将被 shell 命令提取。类似于:

String resultingImage = "${repo}/${parameters.openshiftProject}/${appImageName}".toLowerCase()
// tag images
withCredentials([usernamePassword(credentialsId: pushCredentialsId, passwordVariable: 'password', usernameVariable: 'username')]) {
    parameters[IMAGE_TAGS].each { tagName ->
        sh 'set +x skopeo copy docker://' + resultingImage + ':latest docker://' + "${resultingImage}:${tagName}" + '--src-tls-verify=false --src-creds=$username:$password --dest-creds=$username:$password echo' + /"done copying ${resultingImage}:${tagName}"/
    }
}

这里非常nice article介绍了Jenkins的环境变量和用法