Skip to content

Commit

Permalink
Merge branch 'master' into GeneralNonBlockingStepExecution-JENKINS-49337
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Jan 11, 2019
2 parents a63e30a + d09583e commit 891418a
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 8 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -97,7 +97,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>script-security</artifactId>
<version>1.48</version>
<version>1.50</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
Expand Down
Expand Up @@ -27,6 +27,7 @@
import hudson.Extension;
import hudson.model.Action;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.model.TaskListener;
Expand All @@ -39,11 +40,13 @@
import org.jenkinsci.plugins.workflow.flow.FlowDurabilityHint;
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
import org.jenkinsci.plugins.workflow.flow.GlobalDefaultFlowDurabilityLevel;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

import net.sf.json.JSON;
import net.sf.json.JSONArray;
import org.codehaus.groovy.control.CompilationFailedException;
Expand All @@ -57,6 +60,7 @@
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.interceptor.RequirePOST;

/**
* @author Kohsuke Kawaguchi
Expand Down Expand Up @@ -125,14 +129,19 @@ public String getDisplayName() {
return "Pipeline script";
}

@RequirePOST
public FormValidation doCheckScript(@QueryParameter String value, @QueryParameter boolean sandbox) {
return sandbox ? FormValidation.ok() : ScriptApproval.get().checking(value, GroovyLanguage.get());
}

public JSON doCheckScriptCompile(@QueryParameter String value) {
@RequirePOST
public JSON doCheckScriptCompile(@AncestorInPath Item job, @QueryParameter String value) {
if (!job.hasPermission(Job.CONFIGURE)) {
return CpsFlowDefinitionValidator.CheckStatus.SUCCESS.asJSON();
}
try {
CpsGroovyShell trusted = new CpsGroovyShellFactory(null).forTrusted().build();
new CpsGroovyShellFactory(null).withParent(trusted).build().getClassLoader().parseClass(value);
new CpsGroovyShellFactory(null).withParent(trusted).withSandbox(true).build().getClassLoader().parseClass(value);
} catch (CompilationFailedException x) {
return JSONArray.fromObject(CpsFlowDefinitionValidator.toCheckStatus(x).toArray());
}
Expand Down
Expand Up @@ -84,10 +84,11 @@ private CpsTransformer makeCpsTransformer() {
}

private CompilerConfiguration makeConfig() {
CompilerConfiguration cc = new CompilerConfiguration();
CompilerConfiguration cc = sandbox ? GroovySandbox.createBaseCompilerConfiguration() : new CompilerConfiguration();

cc.addCompilationCustomizers(makeImportCustomizer());
cc.addCompilationCustomizers(makeCpsTransformer());

cc.setScriptBaseClass(CpsScript.class.getName());

for (GroovyShellDecorator d : decorators) {
Expand Down
Expand Up @@ -73,6 +73,7 @@
import org.jenkinsci.plugins.workflow.flow.FlowExecutionOwner;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
Expand Down Expand Up @@ -346,12 +347,14 @@ private static String diff(String script, String oldText, String nueText) throws
}

// Stub, we do not need to do anything here.
@RequirePOST
public FormValidation doCheckScript() {
return FormValidation.ok();
}

public JSON doCheckScriptCompile(@QueryParameter String value) {
return Jenkins.get().getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class).doCheckScriptCompile(value);
@RequirePOST
public JSON doCheckScriptCompile(@AncestorInPath Item job, @QueryParameter String value) {
return Jenkins.get().getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class).doCheckScriptCompile(job, value);
}

public static final Permission REPLAY = new Permission(Run.PERMISSIONS, "Replay", Messages._Replay_permission_description(), Item.CONFIGURE, PermissionScope.RUN);
Expand Down
Expand Up @@ -534,4 +534,20 @@ public void finalizer() throws Exception {
jenkins.assertLogContains("Object.finalize()", b);
jenkins.assertLogNotContains("Should never get here", b);
}

@Issue("SECURITY-266")
@Test
public void sandboxRejectsASTTransforms() throws Exception {
WorkflowJob p = jenkins.jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition("import groovy.transform.*\n" +
"import jenkins.model.Jenkins\n" +
"import org.jenkinsci.plugins.workflow.job.WorkflowJob\n" +
"@ASTTest(value={ assert Jenkins.get().createProject(WorkflowJob.class, \"should-not-exist\") })\n" +
"@Field int x\n" +
"echo 'hello'\n", true));
WorkflowRun b = jenkins.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0));
jenkins.assertLogContains("Annotation ASTTest cannot be used in the sandbox", b);

assertNull(jenkins.jenkins.getItem("should-not-exist"));
}
}
Expand Up @@ -25,19 +25,76 @@
package org.jenkinsci.plugins.workflow.cps;

import static org.hamcrest.Matchers.containsString;

import hudson.model.Item;
import hudson.model.User;
import hudson.security.ACL;
import hudson.security.ACLContext;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Rule;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;

public class CpsFlowDefinitionValidatorTest {

@Rule public JenkinsRule r = new JenkinsRule();

@Test public void doCheckScriptCompile() throws Exception {
CpsFlowDefinition.DescriptorImpl d = r.jenkins.getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class);
assertThat(d.doCheckScriptCompile("echo 'hello'").toString(), containsString("\"success\""));
assertThat(d.doCheckScriptCompile("echo 'hello").toString(), containsString("\"fail\""));
WorkflowJob job = r.jenkins.createProject(WorkflowJob.class, "w");
assertThat(d.doCheckScriptCompile(job, "echo 'hello'").toString(), containsString("\"success\""));
assertThat(d.doCheckScriptCompile(job, "echo 'hello").toString(), containsString("\"fail\""));
}

@Issue("SECURITY-1266")
@Test
public void blockASTTest() throws Exception {
CpsFlowDefinition.DescriptorImpl d = r.jenkins.getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class);
WorkflowJob job = r.jenkins.createProject(WorkflowJob.class, "w");
assertThat(d.doCheckScriptCompile(job, "import groovy.transform.*\n" +
"import jenkins.model.Jenkins\n" +
"import org.jenkinsci.plugins.workflow.job.WorkflowJob\n" +
"@ASTTest(value={ assert Jenkins.get().createProject(WorkflowJob.class, \"should-not-exist\") })\n" +
"@Field int x\n" +
"echo 'hello'\n").toString(), containsString("Annotation ASTTest cannot be used in the sandbox"));

assertNull(r.jenkins.getItem("should-not-exist"));
}

@Issue("SECURITY-1266")
@Test
public void blockGrab() throws Exception {
CpsFlowDefinition.DescriptorImpl d = r.jenkins.getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class);
WorkflowJob job = r.jenkins.createProject(WorkflowJob.class, "w");
assertThat(d.doCheckScriptCompile(job, "@Grab(group='foo', module='bar', version='1.0')\n" +
"def foo\n").toString(), containsString("Annotation Grab cannot be used in the sandbox"));
}

@Issue("SECURITY-1266")
@Test
public void configureRequired() throws Exception {
CpsFlowDefinition.DescriptorImpl d = r.jenkins.getDescriptorByType(CpsFlowDefinition.DescriptorImpl.class);

r.jenkins.setSecurityRealm(r.createDummySecurityRealm());
// Set up an administrator, and three developer users with varying levels of access.
r.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().
grant(Jenkins.ADMINISTER).everywhere().to("admin").
grant(Jenkins.READ, Item.CONFIGURE).everywhere().to("dev1").
grant(Jenkins.READ).everywhere().to("dev2"));
WorkflowJob job = r.jenkins.createProject(WorkflowJob.class, "w");

try (ACLContext context = ACL.as(User.getById("admin", true))) {
assertThat(d.doCheckScriptCompile(job, "echo 'hello").toString(), containsString("fail"));
}
try (ACLContext context = ACL.as(User.getById("dev1", true))) {
assertThat(d.doCheckScriptCompile(job, "echo 'hello").toString(), containsString("fail"));
}
try (ACLContext context = ACL.as(User.getById("dev2", true))) {
assertThat(d.doCheckScriptCompile(job, "echo 'hello").toString(), containsString("success"));
}
}
}

0 comments on commit 891418a

Please sign in to comment.