How to change the current working directory in Groovy - groovy

Now, I am writting a Groovy script to invoke other's interface. But I need change my current working path when running the script. I know it is not possible in Java. Is it possible in Groovy?

If you can run other script as separate process, you can give ProcessBuilder parameter working dir:
def processBuilder=new ProcessBuilder(command)
processBuilder.directory(new File("Working dir"))
def process = processBuilder.start()
or
command.execute(null, new File("Working dir"))
so that process will switch to your new folder and execute it there.

As Groovy runs on JVM, the same restrictions apply. Unfortunately it is not possible.
Changing the current working directory in Java?
JDK bug

Java/groovy doesn't really "Have" a working directory as far as I can tell. The shell that launched groovy has one and any child "commands" inherit from that shell diretly.
Java also seems to read the current directory of the shell and store it in "user.dir". This is used as a base for the "File" object so if you System.setProperty("user.dir", "c:/windows") it will change future invocations of new File(".") but will not change the parent shell directory (and therefore not the child directories).
Here are three "Work-Arounds" that may work for different scenarios:
1) I KIND OF overcame this for a very specific task... I wanted to implement "cd" as a groovy script. It was only possible because all my scripts were already being "wrapped" in a batch file. I made it so that my script could create a file called "afterburner.cmd" that, if it existed, would be executed when the script exits. There was some batch file trickery to make this work.
A startup cmd file could also "Set" the current directory before invoking your groovy script/app.
By the way, Having a startup cmd has been much more helpful than I'd thought it would be--It makes your environment constant and allows you to more easily deploy your "Scripts" to other machines. I even have mine compile my scripts to .classes because it turned out to be faster to compile a .groovy to a .class and start the .class with "Java" than it was to just run the script with "groovy"--and usually you can skip the compile step which makes it a LOT faster!
2) For a few small commands, you might write a method like this:
def currentDir = "C:\\"
def exec(command, dir = null) {
"cmd /c cd /d ${dir?:currentDir} && $command".execute().text
}
// Default dir is currentDir
assert exec("dir").endsWith("C:\\>")
// different dir for this command only
assert exec("dir", "c:\\users").endsWith("C:\\users")
// Change default dir
currentDir = "C:\\windows"
assert exec("dir").endsWith("C:\\windows")
it will be slower than "".execute() if "cmd" is not required.
3) Code a small class that maintains an "Open" command shell (I did this once, there is a bit of complexity), but the idea is:
def process="cmd".execute()
def in=process.in
def out=process.out
def err=process.err
Now "in" is an input stream that you could spin off/read from and "out" is an output stream that you can write commands to, keep an eye on "err" to detect errors.
The class should write a command to the output, read the input until the command has completed then return the output to the user.
The problem is detecting when the output of any given command is complete. In general you can detect a "C:..." prompt and assume that this means that the command has finished executing. You could also use a timeout. Both are pretty fallible. You can set that shell's prompt to something unique to make it much less fallible.
The advantage is that this shell can remain open for the entire life of your app and can significantly increase speed since you aren't repeatedly creating "cmd" shells. If you create a class (let's call it "CommandShell") that wraps your Process object then it should be really easy to use:
def cmd=new CommandShell()
println cmd.execute("cd /d c:\\")
println cmd.execute("dir") // Will be the dir of c:\
I wrote a groovy class like this once, it's a lot of experimenting and your instance can be trashed by commands like "exit" but it's possible.

you can wrap it up in a dir block.
eg :
dir('yourdirectory') {
codeblock
}

Related

Is it possible to break out of a restricted (custom) shell?

Not sure if this is the right place to ask.
Say I write a shell that takes stdin input, filters this input so let's say only certain commands like
ls (list contents of binary directory and subdirectory)
update (git clone)
build (go build)
test (go test)
start (systemctl start this.service only)
stop (systemctl stop this.service only)
running (is the binary being executed and with how many GOMAXPROCS?)
usage (memory, cpu usage)
gensvc (generate .service file)
exit (leave shell/logout)
work, you guessed it, I'm trying to give a user only very limited maintenance access over ssh.
Say I'm careful with \0 (I'd write it in Go anyway using bufio.Scanner)
Is there any way to stop the running shell and execute /bin/sh or similar or any way to get around this shell?
The idea is a user should push their stuff via git to a bare repo, this repo is cloned to the filesystem to a certain directory, then go build is called and the binary is ran with a systemd .service file that is generated previously.
Thinking logically, if the user is only able to write certain strings that are accepted, no there is no way. But maybe you know of one, some ctrl+z witchcraft ;) or whatever.
The only attack surface is the input string or rather bytes. Of course the user could git push a program that builds its own shell or runs certain commands, but that's out of scope (I would remove capabilities with systemd and restrict device access and forbid anything but the connection to the database server, private tmp and all, namespace and subnamespace it TODO)
The only problem I see is git pushing but I'm sure I could work around that in a git only mode argv and adding it to ~/.ssh/authorized_keys. something like lish gitmode and execute stdin commands if they start with git or something like it.
Example:
https://gist.github.com/dalu/ce2ef43a2ef5c390a819
If you're only allowed certain commands, your "shell" will read the command, parse it and then execute it then you should be fine, unless I misunderstood it.
Go "memory" can't be executed, not without you doing some nasty hacks with assembly anyway, so you don't have to worry about shell injection.
Something along these lines should be safe:
func getAction() (name string, args []string) {
// read stdin to get the command of the user
}
func doAction() {
for {
action, args := getAction()
switch action {
case "update": //let's assume the full command is: update https://repo/path.git
if len(args) != 1 {
//error
}
out, err := exec.Command("/usr/bin/git", "clone", "--recursive", args[0]).CombinedOutput()
// do stuff with out and err
}
}
}
If you are implementing the shell yourself and directly executing the commands via exec() or implementing them internally, then it is certainly possible to produce a secure restricted shell. If you are just superficially checking a command line before passing it on to a real shell then there will probably be edge cases you might not expect.
With that said, I'd be a bit concerned about the test command you've listed. Is it intended to run the test suite of a Go package the user uploads? If so, I wouldn't even try to exploit the restricted shell if I was an attacker: I'd simply upload a package with tests that perform the actions I want. The same could be said for build/start.
Have it reviewed by a pentesting team.
People can be very creative when breaking out a sandbox of any type. Only if you never accept the user's input you can consider yourself rather safe on premises (but here any command is an input) - paper security assumptions are considered a weak to assess the software. They are similar to 'no-bug' assumptions for an algorithm on paper: as soon as you implement it, 99% of time a bug raises

Read file from Jenkins workspace with System groovy script

I have a question very similar to this: Reading file from Workspace in Jenkins with Groovy script
However I need to read the file from a System Groovy script so the solution of using Text-finder or the Groovy PostBuild plugin will not work.
How can I get the workspace path from a system groovy script? I have tried the following:
System.getenv('WORKSPACE')
System.getProperty("WORKSPACE")
build.buildVariableResolver.resolve("WORKSPACE")
Thanks!
If you have a file called "a.txt" in your workspace, along with a script called "sysgvy.groovy" that you want to execute as a system groovy script. Suppose your "sysgvy.groovy" script needs to read the file "a.txt".
The issue of this topic is that if your script read "a.txt" directly without providing any path, "sysgvy.groovy" executes and will throw an error saying cannot find "a.txt".
I have tested and found that the following method works good.
def build = Thread.currentThread().executable
Then use
build.workspace.toString()+"\\a.txt"
as the full location string to replace "a.txt".
It's also important to run on the Jenkins master machine by placing "a.txt" and "sysgvy.groovy" onto Jenkins master machine's workspace. Executing on slave machine does not work.
Try it, the file should be found and get read in the script without any problem.
If there is problem with variable Thread, it is just that some modules need to be imported. So add these lines to the start of code:
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
Each build has a workspace, so you need to find the desired project first. (The terms "job" and "project" are used rather interchangeable in Jenkins - also in the API.)
After that, you can either cross your fingers and just call getWorkspace(), which is deprecated (see JavaDoc for details).
Or you can find a specific build (e.g. the last), which can give you the workspace used for that specific build via the getWorkspace() method as it is defined in the AbstractBuild class.
Example code:
Jenkins.instance.getJob('<job-name>').lastBuild.workspace;
Just use
build.workspace
The "build" variable is available keyword in System Groovy Script.

Calling a sh script from node.js

I have a node.js application, which connect everyday to a server.
On this server, a new version of the app can be available, if so, the installed app download it, check if the download is complete, and if so, stop itself calling a shell script, which replace the old app by the new one, and start it.
I m struggling at starting the update script.
I know I can start it with child_process_execFile function, which I do:
var execF = require('child_process').execFile;
var PATH = process.argv[1].substr(0, process.argv[1].lastIndexOf('/')+1),
filename = 'newapp.js',
execF(PATH + 'up.sh', [PATH + filename], function () {console.log('done'); return ;});
up.sh, for now is just:
cat $1 > /home/pi/test
I get 'done' printed in the console, but test isn t created.
I know that execFile create a subprocess, is it what block the script to do that?
If I suceed to start this, I know I only have to make some cp in the script to have my app auto-updating.
EDIT:
Started as usual (calling the script from console), it work well, is there a reason for the script to don t execute when called from node.js?
I'd suggest that you consider using a module that can do this for you automatically rather than duplicating the effort. Or, at least use their technique as inspiration for you own requirements.
One example is: https://github.com/edwardhotchkiss/always
It's simple to use:
Usage: always <app.js>
=> always app.js
Then, anytime your code changes, the app is killed, and restarted.
As you can see in the source, it uses the Monitor class to watch a specified file, and then uses spawn to kick it off (and of course kill to end the process when a change has happened).
Unfortunately, the [always] output is currently hardcoded into the code, but it would be a simple change/pull request I'm sure to make it optional/configurable. If the author doesn't accept your change, you could just modify a local copy of the code (as it's quite simple overall).
Make sure when you spawn/exec the process you are executing the shell that will be processing the script and not the script itself.
Should be something like
execF("/usr/bin/sh", [PATH + 'up.sh', PATH + filename]);

Using GroovyShell as "expression evaluator/engine" (or: How to reuse GroovyShell)

I'm using GroovyShell as an "expression evaluator/engine" inside my program. It accepts two inputs: (a) one or more init scripts (b) user-defined script. Both are then concatenated at runtime as big chunk of script (text) and feed to the shell.
String initScripts = getFromDB()
String userScript = getFromUser()
def shell = new GroovyShell()
output = shell.evaluate(initScripts + userScript)
The above code will run in a loop, where the contents of userScript will vary.
So far, initScripts only contain variable definitions (e.g. def $yyyy = new Date().format('yyyy')) which might be referenced in userScript (e.g. print "$yyyy 001").
Is there any more efficient approach for this? (E.g. reusing the shell, how?) Because right now it's very slow.
Edit: Groovy is a must. Please don't recommend other scripting engine.
Edit: I'm thinking whether GroovyShell can do this (pseudo-code):
def shell = new GroovyShell()
shell.evaluate(initScripts)
for each userScript in DB {
shell.put(userScript )
def result = shell.evaluateThat()
println "Result is $result"
}
Is this possible? (Last time I googled it's not possible, but I'm hoping I'm wrong)
You can cache the GroovyShell, you don't need to create a new one always:
final static GroovyShell shell = new GroovyShell()
Also if you run one Script many times you may cache them too. You can create a Script with GroovyShell.parse(String scriptText), use Script.run() to run the script.
This section of the documentation might help too, instead of scripts you can also create groovy objects dynamically.
I guess you could avoid the weight of building a full groovy environment each time.
Since Java 6, there is a scripting API support in Java, which allows you to use lightweight scripting engines.
As an example, see this page in groovy website explaining how to start a groovy script in a Java application using GroovyScriptEngineImpl.
notice you may loose some groovy goodnesses, like maybe Groovy grape, but you'll be able to
reuse your script engine
ensure your script evals in application context (eventually benefitting from Java objects usage)
EDIT one important thing to notice is that neither GroovyScriptEngineImpl nor GroovyShell can guarantee you any kind of thread safety, as any groovy script is free to spawn any number of thread. In fact, the only way you could guarantte thread safety would be by installing a SecurityManager forbidding thread operations. In fact, even that wouldn't guarantee thread safety (as this thread safety could only be achieved by ensuring all your Java code base is thread safe).
I end up doing this:
def shell = new GroovyShell()
shell.evaluate(initScripts)
for( i in 1..count )
{
output = shell.evaluate(userScripts);
}
And just to be safe, you can put shell in ThreadLocal or pool.

Running a script from Groovy

In order to get my setup a bit closer to "one click deployment", I would like to use groovy scripts to start/stop other processes controlled by bat scripts, running in different parts of the filesystem and even on different machines.
How to execute these scripts and how to do it from their respective working directory?
I know Java's
java.lang.Runtime's exec()
However there are lots of issues with this and I wondered if Groovy had some kind of shorthand for this as well?
Thanks!
Groovy added an execute() method to plain old String, so try this:
println "ls -la".execute().text
The execute() method can be used to change directories if you prefix it with the "cmd /c" command, and then use ampersand (assuming Windows) to chain commands together.
Example, assuming you want to go to subdirectory subdir and run a couple of batch files from there:
println "cmd /c cd subdir & batch1.bat & batch2.bat".execute().text
Not sure if there isn't a better way, but this does work.
You can also use ProcessBuilder which is a surprisingly convienent Java class introduced in java 5.
ProcessBuilder lets you
determine the working directory
determine which environmental variables the process should have
See http://download.oracle.com/javase/1.5.0/docs/api/java/lang/ProcessBuilder.html for a brief example and more documentation.
If you aren't afraid to create some reusable code you could create an object that wraps an .execute() process. I created something like this and use it regularly.
Create a new process with:
def proc="cmd".execute()
After that you can use "consumeProcessOutput()" to manage the input and output of "proc". Anything you send to it will be acted on as though you typed it into a shell, and all the output of that shell will be available to you.
I wrapped all this up in a closure so that you could do this:
cmd("cd \\ \n dir ") {
if(it.contains("AUTOEXEC.BAT"))
println it;
return true;
}
To get a display that shows only the autoexec.bat line. Note that until you return true from the closure, the stdin of that process is available so you can send more lines of text and interact with it indefinitely.
I use it quite a bit because commands like "cd" and "Dir" don't work in windows with .execute(), so a simple:
def directoryListing=cmd("cd\\\ndir")
will get me a quick directory listing with ease.

Resources