-
Bug
-
Resolution: Duplicate
-
Minor
-
Jenkins: 2.138.1
BlueOcean plugin: 1.8.2
A clean install on Windows 7 with just a standard set of plugins
Reproed with Chrome on Windows and Firefox on a Linux desktop
-
Powered by SuggestiMate
When a string is displayed in the BlueOcean UI from an "echo" step, the string "Print Message" is displayed IF the string being echoed contains a substring that matches the contents of any environment variable.
Repro steps:
Create a pipeline with this code:
pipeline { agent any stages { stage('test') { environment { THING = 'foobarbuzz' } steps { echo "blah" echo "foobarbuzz" echo "foobarZZZbuzz" echo "This is a $THING here" } } } }
Run the pipeline via Blue Ocean
Observe that there are four step labels displayed in the Blue Ocean UI. (see attached screenshot) The first and third steps display the strings from "echo" as expected. But, the second and fourth steps display only "Print Message" and don't show the expected string. The user needs to click the step to expand it to see the string. I would expect that all strings from all echo statements should show up in the main Blue Ocean UI and would not require some to be manually expended.
- duplicates
-
JENKINS-47101 Pipeline withCredentials step does not mask step descriptions for variables with the same name as existing system variables
-
- Resolved
-
- is duplicated by
-
JENKINS-60939 Multiple Echo in stage not rendering.
-
- Closed
-
- is related to
-
JENKINS-55612 Add optional label attribute for echo step to improve usability
-
- Open
-
[JENKINS-53649] Strings from the "echo" step are suppressed in BlueOcean UI if they contain values found in an environment variable
I've created a step and implemented the String argumentsToString(Map<String, Object> namedArgs) method and it works most of the time, but it seems that if the argument has and env value in it the argument passed is empty. Is there a way to disable this behaviour or override it?
Works with Strings = Displays Correctly
I'm on the same boat... I observed the following:
- Strings work as expected
echo "Running Sonar Scan with reports at ${context.reports.sonarqube.server}"
- If the Strings are separate, they just work (notice the space between the variable and the String "/dashboard/index/"
echo "Running Sonar Scan with reports at ${context.reports.sonarqube.server} /dashboard/index/"
Doesn't work with GStringImpl = Print Message
- But concatenating Strings with variables, it will result in a GStringImpl, which won't work
echo "Running Sonar Scan with reports at ${context.reports.sonarqube.server}" def url = "${context.reports.sonarqube.server}/dashboard/index/${context.library.groupId}:${context.library.artifactId}" echo "URL is ${url}"
- If I concat the String on the same URL above it won't work either
echo "Running Sonar Scan with reports at ${context.reports.sonarqube.server}/dashboard/index/"
marcellodesales i do not think this is related to GStrings. I've tested with pure hardcoded strings and if any part of the string matches a value of an enviroment variable the string is not shown.
I also question this String/GStringImpl correlation. You can reproduce this issue by echoing a static string multiple times, as shown in the original attachment for this issue. In my own case, echoing the exact same static string multiple times produced inconsistent results.
Same happens if echo uses a variable from parameters (i.e. anything from params.*). Does not matter if the variable is a String or not, even explicitly converting the params value to String does not help.
String param_str String text_var_2 parameters { string(name: 'str_param', defaultValue: 'no value') } ... param_str = params.str_param.toString() echo "string text in double quotes is ${param_str}" echo "simple quoted string is here" echo 'simple quoted string is here' echo 'Single quoted with str ' + param_str + ' is here' echo param_str text_var_2 = 'Single quoted str ' + param_str + ' combined' echo "GString global text2 is ${text_var_2}" echo 'String global text2 is' + text_var_2
The output is as this:
Anything that contains the variable from param is "Print Message".
If a variable is a simple string or a calculated integer - it is shown in the step label normally.
ianfixes hbfernandes I will have to take it back after looking at your examples... So far we have observed:
- Values with references to params
- Values with references to env
This is definitely an annoying situation when we want to show information to users
My $0.02 – this is such an annoying bug. And seemingly trivial to fix.
We had been telling our users to look in the Blue Ocean output to see what happened to their build, because the graphic view of pipelines has the potential to make it much clearer.
But then they see 10 or 20 or 50 "Print message" lines and have to click most of them to see the important messages.
It's not clear there is any purpose behind hiding the text.
And we often have to tell them how to find their way to the "pipeline.log" to get the full story.
So it's easier to tell people to just go to the old style console log
larry_west, I've found an ugly workaround to this - avoid using env and params in echo output as much as possible and then make a second echo showing the actual output. This still leaves lots of "Print message" in BlueOcean output, but at least people can see the actual action within the step.
But you are right, this is very annoying and users become reluctant to use BO because of this.
A workaround that we're having success with is removing informational echo calls and instead using the `label` property on `sh`. This was recently introduced in the Pipeline: Nodes and Processes plugin - required us to upgrade.
So
echo Doing the thing...
sh ./the_thing.sh
becomes
sh(script: "./the_thing.sh", label: "Doing the thing...")
and has the nice side effect of reducing the number of rows overall in Blue Ocean.
https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script
https://plugins.jenkins.io/workflow-durable-task-step
mcw Can you specify the versions you tested those? I guess we can just write a script instruction to not echo anything and place the actual String in the label... have you tried that?
mcw Even using {{label:}}s produces inconsistent results:
Those two steps in the red box are both of the form:
sh label: <label_name>, script: '''...'''
The first one is in the steps portion of the stage and looks like:
sh label: env.STAGE_NAME, script: '''...'''
and the second one is in the post->success portion of the stage and looks like:
sh label: "Collect artifacts", script: '''...'''
But as you can see, they are displayed quite differently.
I've opened JENKINS-59918 about this, FWIW.
It's been a year and this hasn't been fixed. Perhaps the standard/static Jenkins community is starting to die out a little bit in favor of things like Jenkins-X.
I would also be very happy about this issue being resolved (in order to nicely show a parameter value) and actually would have hoped that this is easy for someone like bitwiseman (of course I am not just trying to challenge him in any way )...
The workaround with sh step using label attribute also requires a node wrapping context and thus is quite some runtime overhead too.
JENKINS-55612 could also be considered some overhead with respect to written pipeline code.
I am quite confused/concerned/surprised about the mentioned/found inconsistencies and whether or not this is actually on purpose (cf. parameter and env values) and why?
Another workaround is adding a non-printable anywhere in the middle, e.g. for an URL parameter: echo "URL: '${params.URL.replace('.', '.\u007F')}'"
I believe this is one of the little bugs that are not really serious but still would make many people happy when fixed, because it is so annoying.
I've found a generic workaround that doesn't use a shell step, so it's much more efficient. The trick is to temporarily clear the EnvVars for the duration of the "echo" call.
DISCLAIMER: This workaround disables the masking of secrets during the echo call, so use it at your own risk and especially don't use it within "withCredentials" scope!
If anyone has an idea to prevent this issue, please reply. We could propably call "getContext" to detect any "withCredentials" context and fallback to plain "echo" in this case. I could live with an occassional "Print Message" in "withCredentials" scopes. Unfortunately "getContext" prints a message on its own, so it's not very useful .
Sample code:
pipeline{ agent any environment { MY_ENV1 = 'foobarbaz' } parameters { string(name: 'MY_PARAM', defaultValue: 'bazbarfoo') } stages { stage('test') { steps { script { env.MY_ENV2 = 'foobazbar' withEnv(['MY_ENV3=bazfoobar']) { // Any of the resolved variable values trigger the "Print message" of plain echo def msg = "MY_ENV1=$MY_ENV1, MY_ENV2=$MY_ENV2, MY_ENV3=$MY_ENV3, MY_PARAM=$MY_PARAM" echo "echo: $msg" // Displays "Print Message" as the step label myecho "myecho: $msg" // Displays the message as the step label, as expected } } } } } } // Workaround for "Print message" that is displayed by original echo step if the message // contains a value of an environment variable or a pipeline parameter. // // WARNING: This disables masking of secrets in the output, so don't call it within witCredentials{} scope! void myecho( String msg ) { withContext( new MyEnvClearer() ) { echo msg } } // Clears all environment variables, to be used from withContext{}. class MyEnvClearer extends org.jenkinsci.plugins.workflow.steps.EnvironmentExpander { @NonCPS void expand( hudson.EnvVars env ) throws IOException, InterruptedException { env.clear() } }
In the same vein as zett42 I created a groovy library to wrap his method for easy use in my pipelines.
I call the file unsafeEcho.groovy and call it via
unsafeEcho "SHORT_BUILD_VERSION: $SHORT_BUILD_VERSION"
#!/usr/bin/env groovy // Workaround for "Print message" that is displayed by original echo step if the message // contains a value of an environment variable or a pipeline parameter. // // WARNING: This disables masking of secrets in the output, so don't call it void call( String msg ) { withContext( new unsafeEchoClearer() ) { echo msg } } // Clears all environment variables, to be used from withContext{}. class unsafeEchoClearer extends org.jenkinsci.plugins.workflow.steps.EnvironmentExpander { @NonCPS void expand( hudson.EnvVars env ) throws IOException, InterruptedException { env.clear() } }
Been affected by this issue as well and debugged further. Based on my findings the "flaw" is in the attempt of locating environment variables that might be credentials bindings.
My "slightly more than minimal failing" example after configuring a secret text with the id hello is:
withEnv(['FOO=bar']) { echo "Testing bar world" withCredentials([string(credentialsId: 'hello', variable: 'MY_SECRET')]) { echo "Testing bar world" withEnv(['BAR=baz']) { echo "Testing bar world" withCredentials([string(credentialsId: 'hello', variable: 'MY_OTHER_SECRET')]) { echo "Testing bar world" } } } }
The issue is that we can currently not cleanly separate credentials from other env variables. As a result, all env vars are effectively treated as credentials and their output is masked. That's also why I don't think this is an issue with Blue Ocean.
I think the system would function as intended if only env vars used as credentials were passed in as constructors to ArgumentsActionImpl at https://github.com/jenkinsci/workflow-cps-plugin/blame/master/src/main/java/org/jenkinsci/plugins/workflow/cps/DSL.java#L246.
jglick what would be a clean way to only determine env vars that were added as credentials?
Well known limitation of the current design. Essentially the same problem as what is described in JENKINS-47101, though with different symptoms. APIs to solve this have been discussed recently, but no promises.
jglick JENKINS-47101 seems to be the conflicting requirement to suppress credentials in a step, which is different from this issue where non-credentials are suppressed.
Where are these discussions taking place? Would be happy to help!
What if `EnvironmentExpander` had a method to yield only env vars that represent a `Secret`. With that the env vars passed into the sanitization could only retain those and argument masking should work as intended!?
JENKINS-47101seems to be the conflicting requirement
Yes, as I said the symptoms are different. The underlying problem is the lack of an API to determine whether environment variables are sensitive, something like AbstractBuild.getSensitiveBuildVariables but suited to Pipeline’s needs; in lieu of that, workflow-cps assumes most variables are sensitive, but makes exemptions for a fixed list of common system variables. And yes EnvironmentExpander is the likely locus of such a new API, such as Set<String> getSensitiveVariables().
This does not happen for me for the step echo "Executing On: $env.NODE_NAME" but I do observe it using echo "branch sync @ $scmVars.P4_CHANGELIST" (scmVars returned from the p4sync step) and echo "$tp_mkspec sync @ $env.P4_CHANGELIST" (tp_mkspec is a groovy var)