Jenkins groovy security problems - security

I am trying to get all the files matching a filter. Here is my code:
import static groovy.io.FileType.FILES
node {
try{
stage('get files')
new File('.').eachFileRecurse(FILES) {
if(it.name.endsWith('.nuspec')) {
echo it.Name
}
}
}catch(err) {
echo 'Err: Incremental Build failed with Error: ' + err.toString()
}finally {
}
I get the following error:
Err: Incremental Build failed with Error: org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use new java.io.File java.lang.String
I've checked there are No pending script approvals.
I can't find any option to disable sandboxing.
The script runs fine when I try it in the script console.
How do I allow the script to run on my builds?
Thanks!

https://jenkins.io/doc/pipeline/steps/pipeline-utility-steps/#findfiles-find-files-in-the-workspace
def files = findFiles(glob: '**/*.nuspec')
echo "${files[0].name} ${files[0].path} ${files[0].directory} ${files[0].length} ${files[0].lastModified}"

Related

How to access groovy function inside sh in below jenkins pipeline script

def Greet(name) {
echo "Hello ${name}"
}
pipeline {
agent any
stages {
stage('Test') {
steps {
sh """
Greet('Build Team')
"""
}
}
}
}
I am trying to call 'Greet' function from the stage 'Test' inside the shell . But getting error as
/var/lib/jenkins/workspace/Check1#tmp/durable-ce807c1d/script.sh: line 2: syntax error near unexpected token `'Bob''
Any one let me know how we can call 'Greet' function from the stage 'Test' inside the shell .

Electron app in production mode fails to run external script via child_process.spawnSync API in Mac but works perfectly in Linux

The app computes the sum of the exponentials of the two entered integers using an R code. The inputs are passed in the form of a JSON object to the R code via child_process.spawnSync API of node.js.
The app was packaged using electron-packager(v15.2.0) and its structure is as shown in the screenshot below. Source code to reproduce this issue can be obtained from this GitHub folder: https://github.com/wasimaftab/Utils/tree/master/test_js_r_interaction
index.js file contains the code to interact with R. Important note, you need to install rjson R package before attempting to run the electron app as it is used in R to extract the arguments from json object.
In Ubuntu (18.04) the output as expected, see the screenshot below,
The same code fails in Mac (Catalina 10.15.7) after packaging but, works perfectly in development mode, see the screenshot below.
The actual error is as follows:
Error: spawnSync Rscript ENOENT
at Object.spawnSync (internal/child_process.js:1041:20)
at Object.spawnSync (child_process.js:625:24)
at callSync (file:///Users/admin/Desktop/test_js_r_interaction/release-builds-mac/test_js_r_interaction-darwin-x64/test_js_r_interaction.app/Contents/Resources/app.asar/src/index.js:25:23)
at HTMLButtonElement.<anonymous> (file:///Users/admin/Desktop/test_js_r_interaction/release-builds-mac/test_js_r_interaction-darwin-x64/test_js_r_interaction.app/Contents/Resources/app.asar/src/index.js:84:20)
and the js code to interact with R is as follows:
const path = require("path");
const child_process = require('child_process');
const RSCRIPT = 'Rscript';
const defaultOptions = {
verboseResult: false
}
function parseStdout(output) {
try {
output = output.substr(output.indexOf('"{'), output.lastIndexOf('}"'));
return JSON.parse(JSON.parse(output));
} catch (err) {
return err;
}
}
function callSync(script, args, options) {
options = options || defaultOptions;
const result = args ?
child_process.spawnSync(RSCRIPT, [script, JSON.stringify(args)]) :
child_process.spawnSync(RSCRIPT, [script]);
if (result.status == 0) {
const ret = parseStdout(result.stdout.toString());
if (!(ret instanceof Error)) {
if (options.verboseResult) {
return {
pid: result.pid,
result: ret
};
} else {
return ret;
};
} else {
return {
pid: result.pid,
error: ret.message
};
}
} else if (result.status == 1) {
return {
pid: result.pid,
error: result.stderr.toString()
};
} else {
return {
pid: result.pid,
error: result.stderr.toString()
//error: result.stdout.toString()
};
}
}
I will appreciate any suggestion to fix this issue, thanks in advance
The error you're getting, ENOENT, suggests that your OS cannot find Rscript. This can result from the following scenarios:
Rscript is not even installed.
Rscript is installed, but not executable without a "shell". To check whether it is installed, open a Terminal and execute the command as your Electron application would.
If Rscript can be executed from within a Terminal, there could be something wrong with how the installation has set your paths up. There shouldn't be, really, but it might be necessary to execute spawnSync with additional options, such as { shell: true } to get the correct value of PATH.
If Rscript cannot be executed from within a Terminal, forcing Electron to spawn a shell via the above options (which really is what a Terminal does) will not solve this problem. In this case, try to use the complete path to Rscript as the command instead, if you happen to know where it should be installed.
If neither of those solutions help, try reinstalling Rscript altogether and try again. As I can see nothing which would be wrong with your code, I believe it is a problem of installation.
For more information on child_process.spawnSync (command, args, options), see its documentation.

Reading an environment variable set by a test in Jenkins pipeline

Not found any reference to this particular question.
I am looking to find a way to achieve something like this in a Jenkins pipeline which runs our acceptance tests using Protractor and Cucumber.js:
steps {
container('selenium') {
script {
try {
{
//run tests
}
}
catch (err) {
if (env.testFailed == 'true') {
println "A test failure exists - build status updated to failure"
currentBuild.result = 'FAILURE'
error "Test(s) have failed"
}
else {
println "No test failures exist - build status updated to success"
currentBuild.result = 'SUCCESS'
}
}
}
}
}
This would fail the build if the env var of testFailed is 'true'. The reason for this is we are encountering bugs with Protractor-Cucumber framework where if a failed test retries and passes the exit code of the stage is still 1.
So in the After hook of each test I am setting the env var using node.js to true if the Scenario status is failed:
if (scenario.result.status === Status.FAILED) {
process.env.testFailed = 'true';
}
if (scenario.result.status === Status.PASSED) {
process.env.testFailed = 'false';
}
The problem I have found is that the Jenkins pipeline fails to read the env var value in the code block of the catch section. It is always null.
Any ideas?
1) change the After hook to write the true/false flag to a file in sync.
2) read the file in catch block
catch(err) {
testFailed = sh(script:'cat result.flag.txt', returnStdout: true).trim()
if(testFailed == 'true') {
...
}
}
Another option if there is total/passed/failed case number in output of npm test
lines = []
try {
lines = sh(script:'npm test', returnStdout: true).readLines();
}
catch(err) {
size = lines.size()
// parse the last 20 lines to extract fail/pass/total number
for(int i=size-20;i<size;i++) {
line[i]
}
}
WHY IT DOESN'T WORK NOW?
I see that you're running your tests in a container. When you set an environment variable, it's reflected on the scope of your container not the Jenkins master server
WHAT YOU COULD TRY TO DO
This actually depends on how you run the tests, but this should be an option
// run tests here
// you should have a variable for your container
def exit_code = sh(script: "sudo docker inspect ${container.id} --format='{{.State.ExitCode}}'", returnStdout: true)
sh "exit ${exit_code}"
This actually also depends how you start the tests inside the container,
So if you update your answer with this information I could help you

Gradle: How to upload release APK file over FTP after build

I want to upload automatically the APK file to the server when building the release version.
To do so, I'm going to use FTP protocol.
I'm new regarding Gradle scripting. I used those 2 questions (this and this) as a base but something is not working out.
Could anyone point out what it is?
This is the code (on build.gradle):
gradle.buildFinished {
println("---- Build finished. This message appears ----")
task ftp << {
project.logger.lifecycle('-- This message does not appear --')
ant {
taskdef(name: 'ftp',
classname: 'org.apache.tools.ant.taskdefs.optional.net.FTP',
classpath: configurations.ftpAntTask.asPath)
def destination = "ftp://xxxxxxxxxx#xxx.surftown.com/xxxxx/"
def source = null
android.applicationVariants.all { variant ->
if ( (variant.name).equals("release") ) {
variant.outputs.each { output ->
source = output.outputFile
}
}
}
def user = 'xxxxxxxxx'
def pass = 'xxxxxxxxx'
ftp(server: source, userid: user, password: pass, remoteDir: destination)
}
}
gradle.buildFinished registers a hook executed at the end of the build. In your case it just creates the ftp task.
Use this if the build task is involved :
build.finalizedBy(ftp)
Otherwise, to make sure it works whatever the invoked task :
tasks.all*.finalizedBy(ftp)
By the way, it was explained in the comment section of first answer of your first link.

How to use createTempFile in groovy/Jenkins to create a file in non-default directory?

What I am trying to achieve is to create a temporary file in groovy in workspace directory, but as an example /tmp/foo will be good enough.
So, here is perfectly working java code:
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
class foo {
public static void main(String[] args) {
try {
String s="/tmp/foo";
Path p=Paths.get(s);
Path tmp=Files.createTempFile(p,"pref",".suf");
System.out.println(tmp.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
however, when used in context of Jenkins pipeline it simply does not work:
def mktemp() {
//String s=pwd(tmp:true)
String s="/tmp/foo"
Path p=Paths.get(s)
Path tmp=Files.createTempFile(p,"pref",".suf")
return tmp;
}
The result is array element type mismatch message with nothing helpful in pipeline log:
java.lang.IllegalArgumentException: array element type mismatch
at java.lang.reflect.Array.set(Native Method)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovyCallSiteSelector.parametersForVarargs(GroovyCallSiteSelector.java:104)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovyCallSiteSelector.matches(GroovyCallSiteSelector.java:51)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovyCallSiteSelector.findMatchingMethod(GroovyCallSiteSelector.java:197)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovyCallSiteSelector.staticMethod(GroovyCallSiteSelector.java:191)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onStaticCall(SandboxInterceptor.java:153)
at org.kohsuke.groovy.sandbox.impl.Checker$2.call(Checker.java:184)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedStaticCall(Checker.java:188)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:95)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)
at WorkflowScript.mktemp(WorkflowScript:16)
The java.io.File.createTempFile() is not any better. In plain java code it works perfectly. In groovy it throws java.io.IOException: No such file or directory.
BTW, /tmp/foo directory exists, methods are added on script approval screen.
From the IOException I suspect you're calling mktemp from within a node {} block and expecting to create the temporary file on that node. Pipeline scripts are run entirely on the Jenkins master. Pipeline steps that interact with the filesystem (e.g. writeFile) are aware of node {} blocks and will be sent over to the node to be executed there, but any pure-Java methods know nothing about remote nodes and are going to interact with the master's filesystem.

Resources