33import edu .umd .cs .findbugs .annotations .NonNull ;
44import groovy .lang .GroovyShell ;
55import groovy .lang .Script ;
6+ import hudson .Launcher ;
7+ import hudson .model .AbstractBuild ;
68import hudson .model .TaskListener ;
79import java .io .PrintStream ;
810import java .io .Serial ;
911import java .util .*;
1012import java .util .concurrent .ConcurrentLinkedQueue ;
13+ import jenkins .model .Jenkins ;
1114import jenkins .security .MasterToSlaveCallable ;
15+ import jenkins .security .Roles ;
1216import org .apache .commons .collections .map .LRUMap ;
1317import org .jenkinsci .plugins .scriptler .Messages ;
1418import org .jenkinsci .plugins .scriptler .config .Parameter ;
19+ import org .jenkinsci .remoting .Role ;
20+ import org .jenkinsci .remoting .RoleChecker ;
1521
1622/**
1723 * Inspired by hudson.util.RemotingDiagnostics.Script, but adding parameters.
@@ -27,6 +33,9 @@ public class GroovyScript extends MasterToSlaveCallable<Object, RuntimeException
2733
2834 private final boolean failWithException ;
2935 private final TaskListener listener ;
36+ private final transient AbstractBuild <?, ?> build ;
37+ private final transient Launcher launcher ;
38+ private transient ClassLoader cl ;
3039
3140 @ SuppressWarnings ("unchecked" )
3241 private static final Map <String , ConcurrentLinkedQueue <Script >> cache = Collections .synchronizedMap (new LRUMap (10 ));
@@ -41,30 +50,57 @@ public class GroovyScript extends MasterToSlaveCallable<Object, RuntimeException
4150 }
4251
4352 /**
44- * Constructor
53+ * This constructor can only be used when the script is executed on the built-in node, because launcher and build
54+ * can not be transferred to an agent and therefore the execution will fail
4555 * @param script the script to be executed
4656 * @param parameters the parameters to be passed to the script
4757 * @param failWithException should the job fail with an exception
4858 * @param listener access to logging via listener
59+ * @param launcher the launcher
60+ * @param build the current build
4961 */
5062 public GroovyScript (
5163 String script ,
5264 @ NonNull Collection <Parameter > parameters ,
5365 boolean failWithException ,
54- TaskListener listener ) {
66+ TaskListener listener ,
67+ Launcher launcher ,
68+ AbstractBuild <?, ?> build ) {
5569 this .script = script ;
5670 this .parameters = new ArrayList <>(parameters );
5771 this .failWithException = failWithException ;
5872 this .listener = listener ;
73+ this .cl = getClassLoader ();
74+ this .build = build ;
75+ this .launcher = launcher ;
76+ }
77+
78+ /**
79+ * Constructor
80+ * @param script the script to be executed
81+ * @param parameters the parameters to be passed to the script
82+ * @param failWithException should the job fail with an exception
83+ * @param listener access to logging via listener
84+ */
85+ public GroovyScript (
86+ String script ,
87+ @ NonNull Collection <Parameter > parameters ,
88+ boolean failWithException ,
89+ TaskListener listener ) {
90+ this (script , parameters , failWithException , listener , null , null );
5991 }
6092
6193 public ClassLoader getClassLoader () {
62- return Thread . currentThread ().getContextClassLoader () ;
94+ return Jenkins . get ().getPluginManager (). uberClassLoader ;
6395 }
6496
6597 public Object call () {
98+ // if we run locally, cl!=null. Otherwise the delegating classloader will be available as context classloader.
99+ if (cl == null ) {
100+ cl = Thread .currentThread ().getContextClassLoader ();
101+ }
66102 PrintStream logger = listener .getLogger ();
67- GroovyShell shell = new GroovyShell (getClassLoader () );
103+ GroovyShell shell = new GroovyShell (cl );
68104
69105 for (Parameter param : parameters ) {
70106 final String paramName = param .getName ();
@@ -77,7 +113,9 @@ public Object call() {
77113
78114 // set default variables
79115 shell .setVariable ("out" , logger );
80- setShellVariables (shell );
116+ shell .setVariable ("listener" , listener );
117+ if (build != null ) shell .setVariable ("build" , build );
118+ if (launcher != null ) shell .setVariable ("launcher" , launcher );
81119
82120 ConcurrentLinkedQueue <Script > scriptPool = cache .get (script );
83121 if (scriptPool == null ) {
@@ -115,8 +153,13 @@ public Object call() {
115153 }
116154 }
117155
118- protected void setShellVariables (@ NonNull GroovyShell shell ) {
119- shell .setVariable ("listener" , listener );
156+ @ Override
157+ public void checkRoles (RoleChecker roleChecker ) throws SecurityException {
158+ if (launcher != null && build != null ) {
159+ roleChecker .check (this , Roles .MASTER );
160+ } else {
161+ roleChecker .check (this , Role .UNKNOWN );
162+ }
120163 }
121164
122165 private static final class ScriptlerExecutionException extends RuntimeException {
0 commit comments