Skip to content

Commit

Permalink
[JENKINS-46177] Support GroovySandbox in Publisher/Builder/Parameters (
Browse files Browse the repository at this point in the history
…#33)

* Initial approach to detect whether sandbox is enabled or current plugin versions are obsolted and unsecured

Change-Id: I98ebba01b9907135e775b506a3b36659f1ca506d

* [JENKINS-46177] Groovy sandbox checker for Publisher/Build/Parameters

Change-Id: I23b018ca9cb05b2a909360e5c3f0411171ae88d9

* Support Groovy plugin version 2.X and 1.X too

Change-Id: I8b7d0eca71777115c67b65f73204f6bc48c57646

* Removed unused plugin, since it is not possible to install a default plugin version usinig the pom and reinstall another version usign the plugin annotation

Change-Id: I435f9d0be548685bcbaef50416fcc4eb53e50f4a

* Added IT

Change-Id: If6a5963fef2c051f3ec27f00d4de6e6141031158
  • Loading branch information
v1v committed Aug 15, 2017
1 parent be509f7 commit a2cb600
Show file tree
Hide file tree
Showing 8 changed files with 421 additions and 37 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -122,7 +122,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>groovy</artifactId>
<version>1.10</version>
<version>2.0</version>
<scope>test</scope>
</dependency>

Expand Down
@@ -1,9 +1,14 @@
package org.jenkins.ci.plugins.jenkinslint.check;

import hudson.model.Item;
import hudson.model.Job;
import hudson.PluginWrapper;
import hudson.model.*;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.util.List;
import java.util.logging.Level;

/**
Expand All @@ -19,32 +24,148 @@ public GroovySandboxChecker(boolean enabled) {

public boolean executeCheck(Item item) {
LOG.log(Level.FINE, "executeCheck " + item);
boolean found = false;
if (item instanceof Job) {
// Pipeline support
if (item.getClass().getSimpleName().equals("WorkflowJob")) {
try {
Object getDefinition = item.getClass().getMethod("getDefinition", null).invoke(item);
if (getDefinition.getClass().getSimpleName().equals("CpsFlowDefinition")) {
return !isSandbox(getDefinition);
found = !isPipelineSandbox(getDefinition);
}
} catch (Exception e) {
LOG.log(Level.FINE, "Exception " + e.getMessage(), e.getCause());
}
}
}
return false;
PluginWrapper plugin = Jenkins.getInstance().pluginManager.getPlugin("groovy");
if (plugin!=null && plugin.getVersionNumber().isNewerThan(new hudson.util.VersionNumber("1.30"))) {
if (item.getClass().getSimpleName().equals("MavenModuleSet")) {
try {
Object getPrebuilders = item.getClass().getMethod("getPrebuilders", null).invoke(item);
if (!isSystemSandbox((List) getPrebuilders)) {
found = true;
}
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
if (item instanceof Project && !isSystemSandbox(((Project) item).getBuilders())) {
found = true;
}
if (item.getClass().getSimpleName().equals("MatrixProject")) {
try {
Object getBuilders = item.getClass().getMethod("getBuilders", null).invoke(item);
if (!isSystemSandbox((List) getBuilders)) {
found = true;
}
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
}

if (item instanceof AbstractProject) {
if (!isSandboxInPublisher(((AbstractProject) item).getPublishersList())) {
found = true;
}

if (((AbstractProject) item).getProperty(ParametersDefinitionProperty.class) != null) {
if (!isSandboxParameters(((ParametersDefinitionProperty) ((AbstractProject) item).getProperty(ParametersDefinitionProperty.class)).getParameterDefinitions())) {
found = true;
}
}
}

return found;
}

private boolean isSandbox(Object object) {
private boolean isPipelineSandbox(Object object) {
boolean status = true;
if (object != null) {
try {
Object isSandbox = object.getClass().getMethod("isSandbox", null).invoke(object);
return ((Boolean) isSandbox);
return isSandbox(object.getClass().getMethod("isSandbox", null).invoke(object));
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
return status;
}

private boolean isSystemSandbox(List<Builder> builders) {
boolean status = true;
if (builders != null && builders.size() > 0 ) {
for (Builder builder : builders) {
if (builder.getClass().getName().endsWith("SystemGroovy")) {
try {
Object source = builder.getClass().getMethod("getSource",null).invoke(builder);
if (source.getClass().getName().endsWith("StringSystemScriptSource")) {
Object scriptSource = source.getClass().getMethod("getScript",null).invoke(source);
if (scriptSource.getClass().getName().endsWith("SecureGroovyScript")) {
if (!isSandbox(scriptSource.getClass().getMethod("isSandbox",null).invoke(scriptSource))) {
status = false;
}
}
}
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
}
}
return status;
}

private boolean isSandboxInPublisher(DescribableList<Publisher, Descriptor<Publisher>> publishersList) {
boolean status = true;
for (Publisher publisher : publishersList) {
if (publisher.getClass().getName().endsWith("GroovyPostbuildRecorder")) {
LOG.log(Level.FINEST, "GroovyPostbuildRecorder " + publisher);
try {
Object scriptSource = publisher.getClass().getMethod("getScript",null).invoke(publisher);
if (scriptSource.getClass().getName().endsWith("SecureGroovyScript")) {
if (!isSandbox(scriptSource.getClass().getMethod("isSandbox",null).invoke(scriptSource))) {
status = false;
}
}
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
}
return status;
}

private boolean isSandboxParameters(List<ParameterDefinition> properties) {
boolean status = true;
for (ParameterDefinition property : properties) {
if (property.getClass().getName().endsWith("ChoiceParameter") ||
property.getClass().getName().endsWith("CascadeChoiceParameter") ||
property.getClass().getName().endsWith("DynamicReferenceParameter") ) {
LOG.log(Level.FINEST, "unochoice " + property);
try {
Object scriptSource = property.getClass().getMethod("getScript",null).invoke(property);
if (scriptSource.getClass().getName().endsWith("GroovyScript")) {
Object script = scriptSource.getClass().getMethod("getScript", null).invoke(scriptSource);
if (script != null && script.getClass().getName().endsWith("SecureGroovyScript")) {
if (!isSandbox(script.getClass().getMethod("isSandbox", null).invoke(script))) {
status = false;
}
}
}
} catch (Exception e) {
LOG.log(Level.WARNING, "Exception " + e.getMessage(), e.getCause());
}
}
}
return status;
}

private boolean isSandbox(Object command) {
boolean status = false;
if (command instanceof Boolean) {
status = ((Boolean) command).booleanValue();
}
return status;
}
}
@@ -1,5 +1,6 @@
package org.jenkins.ci.plugins.jenkinslint.check;

import hudson.PluginWrapper;
import hudson.model.AbstractProject;
import hudson.model.Descriptor;
import hudson.model.Item;
Expand All @@ -10,6 +11,7 @@
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.util.DescribableList;
import jenkins.model.Jenkins;
import org.jenkins.ci.plugins.jenkinslint.model.AbstractCheck;

import java.util.List;
Expand Down Expand Up @@ -82,16 +84,30 @@ public boolean executeCheck(Item item) {
return found;
}

private boolean isSystemExit (List<Builder> builders) {
private boolean isSystemExit(List<Builder> builders) {
boolean status = false;
if (builders != null && builders.size() > 0 ) {
for (Builder builder : builders) {
if (builder.getClass().getName().endsWith("SystemGroovy")) {
try {
Object scriptSource = builder.getClass().getMethod("getScriptSource",null).invoke(builder);
if (scriptSource.getClass().getName().endsWith("StringScriptSource")) {
if (containsSystemExit(scriptSource.getClass().getMethod("getCommand",null).invoke(scriptSource))) {
status = true;
// INFO: Groovy Version 2.0 support Secured Sandbox and changed its implementation
PluginWrapper plugin = Jenkins.getInstance().pluginManager.getPlugin("groovy");
if (plugin!=null && plugin.getVersionNumber().isOlderThan(new hudson.util.VersionNumber("2.0.0"))) {
Object scriptSource = builder.getClass().getMethod("getScriptSource", null).invoke(builder);
if (scriptSource.getClass().getName().endsWith("StringScriptSource")) {
if (containsSystemExit(scriptSource.getClass().getMethod("getCommand", null).invoke(scriptSource))) {
status = true;
}
}
} else {
Object scriptSource = builder.getClass().getMethod("getSource", null).invoke(builder);
if (scriptSource.getClass().getName().endsWith("StringSystemScriptSource")) {
Object script = scriptSource.getClass().getMethod("getScript", null).invoke(scriptSource);
if (script != null && script.getClass().getName().endsWith("SecureGroovyScript")) {
if (containsSystemExit(script.getClass().getMethod("getScript", null).invoke(script))) {
status = true;
}
}
}
}
} catch (Exception e) {
Expand All @@ -103,7 +119,6 @@ private boolean isSystemExit (List<Builder> builders) {
return status;
}


private boolean isSystemExitInPublisher (DescribableList<Publisher, Descriptor<Publisher>> publishersList) {
boolean status = false;
for (Publisher publisher : publishersList) {
Expand Down
Expand Up @@ -133,6 +133,12 @@ PollingSCMTriggerCheckerDesc=\
PollingSCMTriggerCheckerSeverity=High
SandboxCheckerDesc=\
Groovy scripts run in same JVM as Jenkins master, \
<a href=https://issues.jenkins-ci.org/browse/JENKINS-14023>JENKINS-14023</a>.\
SandboxCheckerSeverity=High
SlaveDescriptionCheckerDesc=\
Jenkins slave description might help you to know what it does and further details.\
Expand Down
Expand Up @@ -89,6 +89,7 @@ public void testUITable() throws Exception {
assertTrue(content.contains(htmlLint("TimerTriggerChecker", "JL-19")));
assertTrue(content.contains(htmlLint("GitRefSubmoduleChecker", "JL-20")));
assertTrue(content.contains(htmlLint("BFAChecker", "JL-21")));
assertTrue(content.contains(htmlLint("GroovySandboxChecker", "JL-22")));
}

@Issue("JENKINS-46176")
Expand Down
@@ -0,0 +1,59 @@
package org.jenkins.ci.plugins.jenkinslint.check;

import hudson.model.ParametersDefinitionProperty;
import org.biouno.unochoice.CascadeChoiceParameter;
import org.biouno.unochoice.ChoiceParameter;
import org.biouno.unochoice.DynamicReferenceParameter;
import org.biouno.unochoice.model.GroovyScript;
import org.jenkins.ci.plugins.jenkinslint.AbstractTestCase;
import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript;

/**
* Created by vicmar02 on 07/08/2017.
*/
public class GroovyAbstractCheckerTestCase extends AbstractTestCase {

protected ParametersDefinitionProperty createChoiceParameter(String content) {
GroovyScript script = new GroovyScript(createScript(content),createScript(content));
ChoiceParameter cp = new ChoiceParameter("param", "desc", script, "", false);
return new ParametersDefinitionProperty(cp);
}

protected ParametersDefinitionProperty createCascadeChoiceParameter(String content) {
GroovyScript script = new GroovyScript(createScript(content),createScript(content));
CascadeChoiceParameter ccp = new CascadeChoiceParameter("param", "desc", script, "", "", false);
return new ParametersDefinitionProperty(ccp);
}

protected ParametersDefinitionProperty createDynamicReferenceParameter(String content) {
GroovyScript script = new GroovyScript(createScript(content),createScript(content));
DynamicReferenceParameter drp = new DynamicReferenceParameter("param", "desc", script, "", "", false);
return new ParametersDefinitionProperty(drp);
}

private SecureGroovyScript createScript (String content) {
return new SecureGroovyScript(content,false,null);
}

protected ParametersDefinitionProperty createChoiceParameter(String content, Boolean sandbox) {
GroovyScript script = new GroovyScript(createScript(content, sandbox),createScript(content, sandbox));
ChoiceParameter cp = new ChoiceParameter("param", "desc", script, "", false);
return new ParametersDefinitionProperty(cp);
}

protected ParametersDefinitionProperty createCascadeChoiceParameter(String content, Boolean sandbox) {
GroovyScript script = new GroovyScript(createScript(content, sandbox),createScript(content, sandbox));
CascadeChoiceParameter ccp = new CascadeChoiceParameter("param", "desc", script, "", "", false);
return new ParametersDefinitionProperty(ccp);
}

protected ParametersDefinitionProperty createDynamicReferenceParameter(String content, Boolean sandbox) {
GroovyScript script = new GroovyScript(createScript(content, sandbox),createScript(content, sandbox));
DynamicReferenceParameter drp = new DynamicReferenceParameter("param", "desc", script, "", "", false);
return new ParametersDefinitionProperty(drp);
}

private SecureGroovyScript createScript (String content, Boolean sandbox) {
return new SecureGroovyScript(content,sandbox,null);
}
}

0 comments on commit a2cb600

Please sign in to comment.