Magnolia Groovy Access Taskmanager - groovy

I'd like to access the taskmanager in Magnolia CMS from within a Groovy script. Reason is to archive old tasks in the system (half automatically).
What I tried is something like this:
import info.magnolia.task.*
import info.magnolia.jcr.predicate.NodeTypePredicate;
import info.magnolia.importexport.DataTransporter
repository = "tasks"
nodeType = "mgnl:task"
session = ctx.getJCRSession(repository)
collection = NodeUtil.collectAllChildren(session.getRootNode(), new NodeTypePredicate(nodeType))
collection.each { node->
println(node)
println(node.name)
taskManager.archiveTask(node.name);
println "node done"
}
But taskmanager is of course not known. How can I get access to it using Groovy?

All the components such as managers, registries and others are usually injected and available in Magnolia via guice containers.
Either you can turn your script to class and let guice instantiate it for you or you can use shortcut to get the instance of component you want from guice container like:
tasksManager = Components.getComponent(TasksManager.class)

Related

Jenkins Script to Restrict all builds to a given node

We've recently added a second slave node to our Jenkins build environment running a different OS (Linux instead of Windows) for specific builds. Unsurprisingly, this means we need to restrict builds via the "Restrict where this project can be run" setting. However we have a lot of builds (100+) so the prospect of clicking through them all to change this setting manually isn't thrilling me.
Can someone provide a groovy script to achieve this via the Jenkins script console? I've used similar scripts in the past for changing other settings but I can't find any reference for this particular setting.
Managed to figure out the script for myself based on previous scripts and the Jenkins source. Script is as follows:
import hudson.model.*
import hudson.model.labels.*
import hudson.maven.*
import hudson.tasks.*
import hudson.plugins.git.*
hudsonInstance = hudson.model.Hudson.instance
allItems = hudsonInstance.allItems
buildableItems = allItems.findAll{ job -> job instanceof BuildableItemWithBuildWrappers }
buildableItems.each { item ->
boolean shouldSave = false
item.allJobs.each { job ->
job.assignedLabel = new LabelAtom('windows-x86')
}
}
Replace 'windows-x86' with whatever your node label needs to be. You could also do conditional changes based on item.name to filter out some jobs, if necessary.
You could try the Jenkins Job-DSL plugin
which would allow you to create a job to alter your other jobs. This works by providing a build step in a groovy based DSL to modify other jobs.
This one here would add a label to the job 'xxxx'. I've cheated a bit by using the job itself as a template.
job{
using 'xxxx'
name 'xxxx'
label 'Linux'
}
You might need to adjust it if some of you jobs are different types

GroovyClassLoader Hierarchy and CompilerConfiguration

Problem:
Create GroovyClassLoader GCLA with explicitly set CompilerConfiguration
Create another GroovyClassLoader GCLB with different CompilerConfiguration that sets the BaseScriptClass and uses GCLA as parent
-> a script loaded in GCLB will not have the BaseScriptClass set correctly (but uses the potentially set basescript of GCLA)
Long Story:
My application uses four Groovy scripts to allow customization of certain actions. Each script provides a small DSL, where the DLSs are different for each script. When the action is excecuted in the application, the corresponding script will be called. Additionally some common groovy scripts can be loaded at application startup for storing of common data or definition of helper functions.
The scripts are heavily typechecked at the start of the application.
My first approach was to have one GroovyClassLoader which first loads the common groovy scripts and then does a loadClass for each of the scripts. The DSL is created by simply adding corresponding elements to the binding of each script befor the script is run. The GroovyClassLoader uses a CompilerConfiguration with TypeCheck-Extensions to typecheck the scripts.
This works quite well but has two severe limitations:
the typechecking has to be performed based on the name of the script (because the DSLs for each script is different)
the typechecking script gets quite complicated because it has to handle all four DSLs
To get rid of the named limitations I tried to use a distinct GroovyClassLoader (with my actual ClassLoader as parent) for each of the script (i. e. one per DSL) and set a corresponding ScriptBaseClass which provides the functionality for the DSL. This works very well: the typechecking code is reduced drastically, I can have distinct typechecking scripts for each DSL and I don't have to mess with the name of the script.
But I don't get this to work with the common groovy scripts. As soon as I try to use the GroovyClassLoader of the common scripts as parent for the GroovyClassLoader of the DSL scripts, the DSL no longer gets the correct BaseScriptClass although it's explictly set in the CompilerConfiguration. It seems that the child GroovyClassLoader uses the BaseScriptClass of the parent GroovyClassLoader.
Any ideas of how to get this working?
UPDATE
In my original post I did not mention that I'm using scala. Actually I tried the following code snippet:
val rootConfig = {
val cf = new CompilerConfiguration(CompilerConfiguration.DEFAULT)
cf.setSourceEncoding("UTF-8")
cf.addCompilationCustomizers(new ASTTransformationCustomizer(classOf[CompileStatic]))
cf
}
val childConfig = {
val cfg = new CompilerConfiguration(CompilerConfiguration.DEFAULT)
cfg.setSourceEncoding("UTF-8")
cfg.setScriptBaseClass("NonExisting")
cfg.addCompilationCustomizers(new ASTTransformationCustomizer(classOf[CompileStatic]))
cfg
}
val rootGCL = new GroovyClassLoader(getClass.getClassLoader, rootConfig, false)
val childGCL = new GroovyClassLoader(rootGCL, childConfig, false)
This does not work and the child ClassLoader seems to ignore the CompilerConfiguration completely: it does not complain about the non-exiting BaseScriptClass and if I switch off the static-compilation in the rootConfig it will not even perform the static checks.
If I move the ClassLoader creation to a Java file everything works as expected
GroovyClassLoader has several constructor. For example one for ClassLoader and one for GroovyClassLoader. The GroovyClassLoader version will take the configuration from it. But if you do for example new GroovyClassLoader((ClassLoader) parent) or go with giving the configuration yourself. And for that it is even enough to give null as configuration. The constructor logic will take CompilerConfiguration.DEFAULT then to configure the GroovyClassLoader: new GroovyClassLoader(parent,null) and if you want to be very sure no strange paths are added to the GroovyClassLoader, use the variant with a boolean new GroovyClassLoader(parent,null,false)

Jenkins Groovy Postbuild use static file instead of script

Is it possible to load an external groovy script into the groovy post build plugin instead of pasting the script content into each job? We have approximately 200 jobs so updating them all is rather time consuming. I know that I could write a script to update the config files directly (as in this post: Add Jenkins Groovy Postbuild step to all jobs), but these jobs run 24x7 so finding a window when I can restart Jenkins or reload the config is problematic.
Thanks!
Just put the following in the "Groovy script:" field:
evaluate(new File("... groovy script file name ..."));
Also, you might want to go even further.
What if script name or path changes?
Using Template plugin you can create a single "template" job, define call to groovy script (above line) in there, and in all jobs that need it add post-build action called "Use publishers from another project" referencing this template project.
Update: This is what really solved it for me: https://issues.jenkins-ci.org/browse/JENKINS-21480
"I am able to do just that by doing the following. Enter these lines in lieu of the script in the "Groovy script" box:"
// Delegate to an external script
// The filename must match the class name
import JenkinsPostBuild
def postBuild = new JenkinsPostBuild(manager)
postBuild.run()
"Then in the "Additional groovy classpath" box enter the path to that file."
We do it in the following fashion.
We have a file c:\somepath\MyScriptLibClass.groovy (accessible for Jenkins) which contains code of a groovy class MyScriptLibClass. The class contains a number of functions designed to act like static methods (to be mixed in later).
We include this functions writing the following statement in the beginning of sytem groovy and postbuild groovy steps:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
This could look a bit ugly but you need to write it only once for script. You could include more than one script and also use inheritance between library classes.
Here you see that all methods from the library class are mixed in the current script. So if your class looks like:
class MyScriptLibClass {
def setBuildName( String str ){
binding?.variables['manager'].build.displayName = str
}
}
in Groovy Postbuild you could write just:
[ // include lib scripts
'MyScriptLibClass'
].each{ this.metaClass.mixin(new GroovyScriptEngine('c:\\somepath').loadScriptByName(it+'.groovy')) }
setBuildName( 'My Greatest Build' )
and it will change your current build's name.
There are also other ways to load external groovy classes and it is not necessary to use mixing in. For instance you can take a look here Compiling and using Groovy classes from Java at runtime?
How did I solve this:
Create file $JENKINS_HOME/scripts/PostbuildActions.groovy with following content:
public class PostbuildActions {
void setBuildName(Object manager, String str ){
binding?.variables['manager'].build.displayName = str
}
}
In this case in Groovy Postbuild you could write:
File script = new File("${manager.envVars['JENKINS_HOME']}/scripts/PostbuildActions.groovy")
Object actions = new GroovyClassLoader(getClass().getClassLoader()).parseClass(script).newInstance();
actions.setBuildName(manager, 'My Greatest Build');
If you wish to have the Groovy script in your Code Repository, and loaded onto the Build / Test Slave in the workspace, then you need to be aware that Groovy Postbuild runs on the Master.
For us, the master is a Unix Server, while the Build/Test Slaves are Windows PCs on the local network. As a result, prior to using the script, we must open a channel from the master to the Slave, and use a FilePath to the file.
The following worked for us:
// Get an Instance of the Build object, and from there
// the channel from the Master to the Workspace
build = Thread.currentThread().executable
channel = build.workspace.channel;
// Open a FilePath to the script
fp = new FilePath(channel, build.workspace.toString() + "<relative path to the script in Unix notation>")
// Some have suggested that the "Not NULL" check is redundant
// I've kept it for completeness
if(fp != null)
{
// 'Evaluate' requires a string, so read the file contents to a String
script = fp.readToString();
// Execute the script
evaluate(script);
}
I've just faced with the same task and tried to use #Blaskovicz approach.
Unfortunately it does not work for me, but I find upgraded code here (Zach Auclair)
Publish here with minor changes:
postbuild task
//imports
import hudson.model.*
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import java.io.File;
// define git file
def postBuildFile = manager.build.getEnvVars()["WORKSPACE"] + "/Jenkins/SimpleTaskPostBuildReporter.GROOVY"
def file = new File(postBuildFile)
// load custom class from file
Class groovy = this.class.classLoader.parseClass(file);
// create custom object
GroovyObject groovyObj = (GroovyObject) groovy.newInstance(manager);
// do report
groovyObj.report();
postbuild class file in git repo (SimpleTaskPostBuildReporter.GROOVY)
class SimpleTaskPostBuildReporter {
def manager
public SimpleTaskPostBuildReporter(Object manager){
if(manager == null) {
throw new RuntimeException("Manager object can't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}
I haven't tried this exactly.
You could try the Jenkins Job DSL plugin which allows you to rebuild jobs from within jenkins using a Groovy DSL and supports post build groovy steps directly from the wiki
Groovy Postbuild
Executes Groovy scripts after a build.
groovyPostBuild(String script, Behavior behavior = Behavior.DoNothing)
Arguments:
script The Groovy script to execute after the build. See the plugin's
page for details on what can be done. behavior optional. If the script
fails, allows you to set mark the build as failed, unstable, or do
nothing. The behavior argument uses an enum, which currently has three
values: DoNothing, MarkUnstable, and MarkFailed.
Examples:
This example will run a groovy script that prints hello, world and if
that fails, it won't affect the build's status:
groovyPostBuild('println "hello, world"') This example will run a
groovy script, and if that fails will mark the build as failed:
groovyPostBuild('// some groovy script', Behavior.MarkFailed) This example
will run a groovy script, and if that fails will mark the
build as unstable:
groovyPostBuild('// some groovy script', Behavior.MarkUnstable) (Since 1.19)
There is a facility to use a template job (this is the bit I haven't tried) which could be the job itself so you only need to add the post build step. If you don't use a template you need to recode the whole project.
My approach is to have a script to regenerate or create all jobs from scratch just so I don't have to apply the same upgrade multiple times. Regenerated jobs keep their build history
I was able to get the following to work (I also posted on this jira issue).
in my postbuild task
this.class.classLoader.parseClass("/home/jenkins/GitlabPostbuildReporter.groovy")
GitlabPostbuildReporter.newInstance(manager).report()
in my file on disk at /home/jenkins/GitlabPostbuildReporter.groovy
class GitlabPostbuildReporter {
def manager
public GitlabPostbuildReporter(manager){
if(manager == null) {
throw new RuntimeException("Manager object musn't be null")
}
this.manager = manager
}
public def report() {
// do work with manager object
}
}

How do you forbid users from doing evil things in Groovy Scripts?

I'm planning to integrate Groovy Script Engine to my game so it will give the game nice moddability but how do you prevent players from writing evil scripts like deleting all files on C: drive?
Groovy includes library like java.io.File by default so it will be pretty easy to do once they decided to write such scripts.
I guess I can't prevent users from writing something like while(1==1){} but is there anyway to at least not let them allow to delete/modify files or something dangerous for PCs?
There's a blog post by Cedric Champeau on customising the Groovy Compilation process, the second part of it shows how to use SecureASTCustomizer and CompilerConfiguration to limit what Scripts can do (and then has examples of defining your own AST checks for System.exit, etc...
Look into the SecurityContext class.
The Groovy Web Console appears to have already solved this problem, because it won't execute something like System.exit(1). The source code is available on GitHub, so you can see how they did it.
If you're not sure where to start, I suggest getting in touch with the author, who should be able to point you in the right direction.
I know this is a old question. I'm posting this as it might help some people out there.
We needed to allow end-users to upload Groovy scripts and execute them as part of a web application (that does a lot of other things). Our concern was that within these Groovy scripts, some users might attempt to read files from the file system, read System properties, call System.exit(), etc.
I looked into http://mrhaki.blogspot.com/2014/04/groovy-goodness-restricting-script.html but that will not prevent an expert Groovy developer from bypassing the checks as pointed out by others in other posts.
I then tried to get http://www.sdidit.nl/2012/12/groovy-dsl-executing-scripts-in-sandbox.html working but setting the Security Manager and Policy implementation at runtime did not work for me. I kept running into issues during app server startup and web page access. It seemed like by the time the Policy implementation took hold, it was too late and "CodeSources" (in Java-Security-speak) already took its access settings from the default Java policy file.
I then stumbled across the excellent white paper by Ted Neward (http://www.tedneward.com/files/Papers/JavaPolicy/JavaPolicy.pdf) that explained quite convincingly that the best approach (for my use case) was to set the Policy implementation on JVM startup (instead of dynamically later on).
Below is the approach that worked for me (that combines Rene's and Ted's approaches). BTW: We're using Groovy 2.3.10.
In the [JDK_HOME]/jre/lib/security/java.security file, set the "policy.provider" value to "com.yourcompany.security.MySecurityPolicy".
Create the MySecurityPolicy class:
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AllPermission;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.security.Policy;
import java.util.HashSet;
import java.util.Set;
public class MySecurityPolicy extends Policy {
private final Set<URL> locations;
public MySecurityPolicy() {
try {
locations = new HashSet<URL>();
locations.add(new URL("file", "", "/groovy/shell"));
locations.add(new URL("file", "", "/groovy/script"));
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
#Override
public PermissionCollection getPermissions(CodeSource codeSource) {
// Do not store these in static or instance variables. It won't work. Also... they're cached by security infrastructure ... so this is okay.
PermissionCollection perms = new Permissions();
if (!locations.contains(codeSource.getLocation())) {
perms.add(new AllPermission());
}
return perms;
}
}
Jar up MySecurityPolicy and drop the jar in [JDK_HOME]/jre/lib/ext directory.
Add "-Djava.security.manager" to the JVM startup options. You do not need to provide a custom security manager. The default one works fine.
The "-Djava.security.manager" option enables Java Security Manager for the whole application. The application and all its dependencies will have "AllPermission" and will thereby be allowed to do anything.
Groovy scripts run under the "/groovy/shell" and "/groovy/script" "CodeSources". They're not necessarily physical directories on the file system. The code above does not give Groovy scripts any permissions.
Users could still do the following:
Thread.currentThread().interrupt();
while (true) {} (infinite loop)
You could prepend the following (dynamically at runtime) to the beginning of every script before passing it onto the Groovy shell for execution:
#ThreadInterrupt
import groovy.transform.ThreadInterrupt
#TimedInterrupt(5)
import groovy.transform.TimedInterrupt
These are expalined at http://www.jroller.com/melix/entry/upcoming_groovy_goodness_automatic_thread
The first one handles "Thread.currentThread().interrupt()" a little more gracefully (but it doesn't prevent the user from interupting the thread). Perhaps, you could use AST to prevent interupts to some extent. In our case, it's not a big issue as each Groovy script execution runs in its own thread and if bad actors wish to kill their own thread, they could knock themselves out.
The second one prevents the infinite loop in that all scripts time out after 5 seconds. You can adjust the time.
Note that I noticed a performance degradation in the Groovy script execution time but did not notice a significant degradation in the rest of the web application.
Hope that helps.

Is it possible to automatically preload user classes into the groovy interpreter?

Is there any way to automatically load user classes in the groovy interpreter, the way System.out is automatically loaded (so you don't have to import System.out to use println)? I want to be able to write scripts that employ custom classes and run the scripts in the groovy interpreter without having to import all the classes all the time.
Yep, you just need to create a profile/rc file. Just create a file at ~/.groovy/groovysh.profile and put your imports in there. You'll also want to make sure that any additional classes you want to include are part of your CLASSPATH.
ex: ~/.groovy/groovysh.profile:
import org.apache.commons.lang.StringUtils
println "in groovysh.profile"
Then run groovysh and use a method from StringUtils:
% groovysh
in groovysh.profile
Groovy Shell (1.7.3, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
---------------------------------------------------------------------------------------------------------------------------------
groovy:000> StringUtils.isWhitespace(" ")
===> true
groovy:000>
You can see that the import is in place (and that it also printed out the println I had in the profile. This example will only work if you've got the commons-lang jar file is in your classpath.
See the Groovy Shell page for more details.
Groovy adds some methods to Object, including methods like println and printf that you'd expect on printWriters. They implicitly use System.out. This is actually how groovy makes if feel like System.out is globally available.
If you want to import a set of classes by default, so they can be used without specifying the full package name, Ted's comment about groovysh.profile applies.
However, if you want a specific object, like System.out, global available so its methods can be called without referencing the object, then you can add some dynamic methods to Object. For example, to make the logging methods of the default global JDK logger globally available:
Object.metaClass.info = { String message ->
java.util.logging.Logger.global.info(message)
}
Object.metaClass.warning = { String message ->
java.util.logging.Logger.global.warning(message)
}
Object.metaClass.severe = { String message ->
java.util.logging.Logger.global.severe(message)
}
etc...
Once those methods are applied to the base Object metaClass, any object can call info("message") and have it logged, effectively making Logger.global available in the same way System.out is.

Resources