/** * @param execution * Instantiated {@link CpsGroovyShell} will be used to load scripts for this execution. */ public CpsGroovyShellFactory(@Nullable CpsFlowExecution execution) { this.execution = execution; this.sandbox = execution!=null && execution.isSandbox(); this.decorators = GroovyShellDecorator.all(); }
CpsThread(CpsThreadGroup group, int id, Continuable program, FlowHead head, ContextVariableSet contextVariables) { this.group = group; this.id = id; this.program = group.getExecution().isSandbox() ? new SandboxContinuable(program,this) : program; this.head = head; this.contextVariables = contextVariables; }
/** * Environment to start executing the script in. * During sandbox execution, we need to call sandbox interceptor while executing asynchronous code. */ private Env createInitialEnv() { return Envs.empty( isSandbox() ? new SandboxInvoker() : new DefaultInvoker()); } });
/** Runs the extra tests for replayability beyond {@link #isEnabled()} that require a blocking load of the execution. */ /* accessible to Jelly */ public boolean isReplayableSandboxTest() { CpsFlowExecution exec = getExecutionBlocking(); if (exec != null) { if (!exec.isSandbox()) { // We have to check for ADMIN because un-sandboxed code can execute arbitrary on-master code return Jenkins.get().hasPermission(Jenkins.RUN_SCRIPTS); } return true; } return false; }
/** * For use in projects that want initiate a replay via the Java API. * * @param replacementMainScript main script; replacement for {@link #getOriginalScript} * @param replacementLoadedScripts auxiliary scripts, keyed by class name; replacement for {@link #getOriginalLoadedScripts} * @return build queue item */ public @CheckForNull Queue.Item run2(@Nonnull String replacementMainScript, @Nonnull Map<String,String> replacementLoadedScripts) { List<Action> actions = new ArrayList<Action>(); CpsFlowExecution execution = getExecutionBlocking(); if (execution == null) { return null; } actions.add(new ReplayFlowFactoryAction(replacementMainScript, replacementLoadedScripts, execution.isSandbox())); actions.add(new CauseAction(new Cause.UserIdCause(), new ReplayCause(run))); for (Class<? extends Action> c : COPIED_ACTIONS) { actions.addAll(run.getActions(c)); } return ParameterizedJobMixIn.scheduleBuild2(run.getParent(), 0, actions.toArray(new Action[actions.size()])); }
/* accessible to Jelly */ public boolean isEnabled() { if (!run.hasPermission(REPLAY)) { return false; } if (!run.getParent().isBuildable()) { return false; } CpsFlowExecution exec = getExecutionLazy(); if (exec != null) { return exec.isSandbox() || Jenkins.get().hasPermission(Jenkins.RUN_SCRIPTS); // We have to check for ADMIN because un-sandboxed code can execute arbitrary on-master code } else { // If the execution hasn't been lazy-loaded then we will wait to do deeper checks until someone tries to lazy load // OR until isReplayableSandboxTest is invoked b/c they actually try to replay the build return true; } }
@Override public CpsFlowExecution create(FlowDefinition def, FlowExecutionOwner owner, List<? extends Action> actions) throws IOException { Run original = Run.fromExternalizableId(originRunId); String origScript = null; boolean origSandbox = true; if (original instanceof FlowExecutionOwner.Executable) { FlowExecutionOwner originalOwner = ((FlowExecutionOwner.Executable) original).asFlowExecutionOwner(); if (originalOwner != null) { try { for (FlowCopier copier : ExtensionList.lookup(FlowCopier.class)) { copier.copy(originalOwner, owner); } } catch (InterruptedException x) { throw new IOException("Failed to copy metadata", x); } FlowExecution origExecution = originalOwner.getOrNull(); if (origExecution instanceof CpsFlowExecution) { origScript = ((CpsFlowExecution) origExecution).getScript(); origSandbox = ((CpsFlowExecution) origExecution).isSandbox(); } } } if (origScript != null) { return new CpsFlowExecution(origScript, origSandbox, owner); } else { return null; } }
/** * Creates {@link Continuable} that executes the given invocation and pass its result to {@link FutureCallback}. * * The {@link Continuable} itself will just yield null. {@link CpsThreadGroup} considers the whole * execution a failure if any of the threads fail, so this behaviour ensures that a problem in the closure * body won't terminate the workflow. */ private Continuable createContinuable(CpsThread currentThread, CpsCallableInvocation inv) { // we need FunctionCallEnv that acts as the back drop of try/catch block. // TODO: we need to capture the surrounding calling context to capture variables, and switch to ClosureCallEnv FunctionCallEnv caller = new FunctionCallEnv(null, onSuccess, null, null); if (currentThread.getExecution().isSandbox()) caller.setInvoker(new SandboxInvoker()); // catch an exception thrown from body and treat that as a failure TryBlockEnv env = new TryBlockEnv(caller, null); env.addHandler(Throwable.class, onFailure); return new Continuable( // this source location is a place holder for the step implementation. // perhaps at some point in the future we'll let the Step implementation control this. inv.invoke(env, null, onSuccess)); }
WorkflowRun b = p.getLastBuild(); CpsFlowExecution e = (CpsFlowExecution) b.getExecution(); assertTrue(e.isSandbox()); SemaphoreStep.success("three/1", null); SemaphoreStep.waitForStart("four/1", b);