Jenkins pipeline script issue with wget and variables in URL - jenkins

I have checked many suggestions regarding the issue, but didn't find a suitable solution.
Initially my pipeline code was working fine but with a Jenkins security warning The following steps that have been detected may have insecure interpolation of sensitive variables. sh: [pass, user]
My code is as below:
withCredentials([usernamePassword(credentialsId: 'Jenkins-Nexus-tech', passwordVariable: 'pass', usernameVariable: 'user')]){
sh "wget --user=$user --password=$pass 'https://nexus.mycompany.io/repository/updated-maven-releases/com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war' "
}
Warning:
[Pipeline] sh
Warning: A secret was passed to "sh" using Groovy String interpolation, which is insecure.
Affected argument(s) used the following variable(s): [pass, user]
See https://jenkins.io/redirect/groovy-string-interpolation for details.
To avoid the Jenkins security warning as suggested in https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#interpolation-of-sensitive-environment-variables , I have modified my code as below. But with different permutation and combination of single and double quotes it is not working. It is throwing Bad substitution error:
withCredentials([usernamePassword(credentialsId: 'Jenkins-Nexus-tech', passwordVariable: 'pass', usernameVariable: 'user')]){
sh 'wget --user=$user --password=$pass \"https://nexus.mycompany.io/repository/updated-maven-releases/com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war\" '
}
I have tried with 3 single quotes. with this I am not getting the warning but it is unable to substitute the variables in the wget URL:
withCredentials([usernamePassword(credentialsId: 'Jenkins-Nexus-tech', passwordVariable: 'pass', usernameVariable: 'user')]){
sh '''wget --user=$user --password=$pass 'https://nexus.mycompany.io/repository/updated-maven-releases/com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war' '''
}
Error is as below as it can't substitute the values of the variable
[Pipeline] sh
+ wget --user=**** --password=**** https://nexus.mycompany.io/repository/updated-maven-releases/com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war
HTTP request sent, awaiting response... 404 com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war
ERROR 404: com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war.
It would be really great if someone can assist here.

The suggestion outlined in the page you mention suggests you do not use Groovy string interpolation to pass sensitive data to sh steps. The suggestion is to let the sh script instead get the values from the environment.
However, in your case you still need the value held in the params.AuthorizationServerVersion in your sh step.
Groovy string interpolation is only used when the string is within double quotes. String interpolation is turned off when the string is in single quotes.
When a string is in double quotes, you can escape $s using a backslash. This will prevent inserting the contents of a variable into the string when you don't want this to occur.
What you can do, then, is use double quotes, escape the $s on the variables you want to read from the environment, and leave the $s un-escaped on the variables you want to access directly from your Groovy code.
An example, using the withCredentials plugin:
withCredentials([string(credentialsId: 'mytoken', variable: 'THE_TOKEN')]) {
sh "some_command --that-uses \$THE_TOKEN --as-an-environment-variable --and-also-uses $params.A_PARAMETER"
}
Here, the token is injected into the environment as a secret, and is used in the sh script by escaping the $. This means the actual Unix shell (bash, zsh, or whatever) will get the literal $ and expand it as specified by that shell language.
The $ for $params.A_PARAMETER is not escaped, and is within double quotes, so Groovy will perform string interpolation and replace $params.A_PARAMETER with the value of the parameter at runtime as the string is constructed in memory, before the string is passed as an argument to the sh step.
In your specific case, this is what you can use (within your withCredentials block, of course):
sh "wget --user=\$user --password=\$pass 'https://nexus.mycompany.io/repository/updated-maven-releases/com/mycompany/project/authorization-server/${params.AuthorizationServerVersion}/authorization-server-${params.AuthorizationServerVersion}.war'"
Note that the $ on $user and $pass are escaped, but the $ on ${params.AuthorizationServerVersion} is not escaped.

Related

In a Jenkins script, can I bind credentials inside a conditional expression?

I am trying to run a script to dictate whether a Jenkins step runs. This script needs credentials, which we access by calling withCredentials.
Here's a slightly reduced example:
stage('Sample test stage') {
when {
expression {
withCredentials([usernamePassword(credentialsId: 'MY_CREDENTIALS_ID', usernameVariable: 'MY_USERNAME', passwordVariable: 'MY_TOKEN')]) {
return sh([returnStdout: true, script: 'node bin/my-script ${MY_TOKEN}']).trim().startsWith('success')
}
}
}
steps {
echo 'I should only run when the script passes'
}
}
However, this doesn't work. Jenkins returns the error: "syntax error: bad substitution."
I'm assuming it's down to the syntax used when trying to pass in the credentials. I've tried a couple of variations, such as returning withCredentials and wrapping the whole expression in withCredentials, but both of them had fairly dramatic errors.
I cannot find any documentation on this, which makes me wonder if it's illegal
I feel quite silly. There's a difference between " and ' in Groovy. Within single quotes, only Bash substitutions will work. Within double quotes, both Groovy and Bash substitutions will work.

Passing Jenkins environment variable with spaces to shell script

I am unable to properly pass a variable with spaces in Jenkinsfile to shell command
I have tried using quotes (double and single) backspaces and various other combination. Jenkins will treat the string like as 2 item and single quoted them.
The variable in question in the Jenkins file.
MYTIME = 2022-01-02 03:04:05
In Jenkinsfile
stage('list') {
steps{
sh script:'ansible-playbook -i ./hosts.ini ./ping_playbook.yml -e time=\\"$TIME\\" --limit ${ENV}', label: "ping test"
}
}
Jenkins will run it as
ansible-playbook -i ./lzhxjp-test-update/lzhxjp/hosts.ini .ping_playbook.yml -e 'time="2022-01-02' '11:22:33"' --limit sdktest
How do I put it so that Jenkins interpret it as -e time="2022-01-02 11:22:33"
Inside single-quoted strings no variables are expanded by Jenkins (Groovy to be exact).
Single-quoted strings are plain java.lang.String and don’t support interpolation.
https://groovy-lang.org/syntax.html#all-strings
Thus it is passed directly into the shell and therefore already subject to shell quoting, you can remove the \\ before the " and then the shell the will expand "$TIME" correctly.

What is use of sh ''' <command > ''' - three ticks - in a Jenkinsfile?

I have a Jenkinsfile which uses three tick marks surrounding a command to execute as in:
sh ''' command '''
We have no idea why three tick marks are required or what role they perform.
This syntax is seen in the Jenkinsfile doc set.
This has nothing at all to do with bash (in which triple-quotes have no special meaning at all), and everything to do with Groovy (the separate, non-bash interpreter that parses Jenkinsfiles).
In Groovy, but not in bash, strings must use triple-quotes to span multiple lines.
In the context of a sh directive in a Jenkinsfile, the content of your triple-quoted string is passed to a shell as a script to execute; however, the syntax is parsed by Groovy, so it's only Groovy that cares about the quotes themselves (as opposed to the quoted content).
Can you give more idea about what kind of command is it, is it a unix command or some script ?
The single quote and its variation like '''(3 ticks) as mentioned in question skip the variable expansion, and it could used to show what is being executed.
echo '''Updating JAVA_HOME variable :
export $JAVA_HOME="$NEW_JAVA_HOME" '''
However in your question, a command (some string) is enclosed between 3 ticks marks and sh tries to execute this command or script. One such example below
$ echo "echo hello" > /tmp/tesh.sh
$ sh '''/tmp/test.sh'''
hello

How to use parameterized build in jenkins pipeline?

I am having these lines in my Jenkinsfile:
parameters {
string(name: 'DATABASE', defaultValue: 'jenkinsdatabase',
description: 'The name of the database')
}
(...)
Now I want to use the value of ${params.DATABASE} in a step of a stage e.g.
sh 'mysql --user ${USER} -p${PASSWORD} --host ${HOST} -e "DROP DATABASE IF EXISTS ${params.DATABASE};CREATE DATABASE ${params.DATABASE} DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci; commit;";export GRADLE_OPTS="-Xms1536m -Xmx1536m"'
But this ends with a exeception: Bad substitution
Can anybody help me?
Your sh script body uses single quotes around it.
sh '...'
Since these are single quotes, string interpolation will not occur. This means that all of your $ strings will use the shell variable substitution instead of the Groovy substitution. You are getting a Bad substitution in the shell because the shell won't be able to substitute ${params.DATABASE} because that is an invalid shell substitution.
params is a Groovy variable, so switching your single quotes to double quotes will perform string interpolation of the variables.
sh "..."

CHANGE_AUTHOR_EMAIL and CHANGE_ID environment variables return "No such property: ..."

Given the following pipeline:
stages {
stage ("Checkout SCM") {
steps {
checkout scm
sh "echo ${CHANGE_AUTHOR_EMAIL}"
sh "echo ${CHANGE_ID}"
}
}
}
Why do these variables fail to resolve and provide a value?
Eventually I want to use these environment variables to send an email and merge a pull request:
post {
failure {
emailext (
attachLog: true,
subject: '[Jenkins] $PROJECT_NAME :: Build #$BUILD_NUMBER :: build failure',
to: '$CHANGE_AUTHOR_EMAIL',
replyTo: 'iadar#...',
body: '''<p>You are receiving this email because your pull request was involved in a failed build. Check the attached log file, or the console output at: $BUILD_URL to view the build results.</p>'''
)
}
}
and
sh "curl -X PUT -d '{\'commit_title\': \'Merge pull request\'}' <git url>/pulls/${CHANGE_ID}/merge?access_token=<token>"
Oddly enough, $PROJECT_NAME, $BUILD_NUMBER, $BUILD_URL do work...
Update: this may be an open bug... https://issues.jenkins-ci.org/browse/JENKINS-40486 :-(
Is there any workaround to get these values?
You need to be careful about how you refer to environment variables depending on whether it is shell or Groovy code, and how you are quoting.
When you do sh "echo ${CHANGE_ID}", what actually happens is that Groovy will interpolate the string first, by replacing ${CHANGE_ID} with the Groovy property CHANGE_ID, and that's where your error message is from. In Groovy, the environment variables are wrapped in env.
If you want to refer to the environment variables directly from your shell script, you either have to interpolate with env, use single quotes, or escape the dollar sign. All of the following should work:
sh 'echo $CHANGE_ID'
sh "echo \$CHANGE_ID"
sh "echo ${env.CHANGE_ID}"
For anyone who may come across this, these variables are available only if the checkbox for Build origin PRs (merged with base branch) was checked (this is in a multi-branch job).
See more in this other Jenkins issue: https://issues.jenkins-ci.org/browse/JENKINS-39838

Resources