package org.jenkinsci.plugins.workflow.cps; import com.cloudbees.groovy.cps.Continuable; import com.cloudbees.groovy.cps.Outcome; import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException; import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox; import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext; import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval; import java.util.concurrent.Callable; import javax.annotation.CheckForNull; /** * {@link Continuable} that executes code inside sandbox execution. * * @author Kohsuke Kawaguchi */ class SandboxContinuable extends Continuable { private final CpsThread thread; SandboxContinuable(Continuable src, CpsThread thread) { super(src); this.thread = thread; } @Override public Outcome run0(final Outcome cn) { try { CpsFlowExecution e = thread.group.getExecution(); return GroovySandbox.runInSandbox(new Callable<Outcome>() { @Override public Outcome call() { Outcome outcome = SandboxContinuable.super.run0(cn); RejectedAccessException x = findRejectedAccessException(outcome.getAbnormal()); if (x != null) { ScriptApproval.get().accessRejected(x, ApprovalContext.create()); } return outcome; } }, new GroovyClassLoaderWhitelist(CpsWhitelist.get(), e.getTrustedShell().getClassLoader(), e.getShell().getClassLoader())); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new AssertionError(e); // Callable doesn't throw anything } } private static @CheckForNull RejectedAccessException findRejectedAccessException(@CheckForNull Throwable t) { if (t == null) { return null; } else if (t instanceof RejectedAccessException) { return (RejectedAccessException) t; } else { return findRejectedAccessException(t.getCause()); } } }