diff --git a/pom.xml b/pom.xml
index 5f9267abe..d8a3d3adf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -11,7 +11,7 @@
warnings
hpi
Warnings Plug-in
- 4.61
+ 4.63-SNAPSHOT
http://wiki.jenkins-ci.org/x/G4CGAQ
This plug-in reads the compiler warnings from the console log file and generates a trend report.
@@ -44,7 +44,12 @@
org.jvnet.hudson.plugins
analysis-core
- 1.82
+ 1.86
+
+
+ org.jenkins-ci.plugins
+ script-security
+ 1.25
org.jenkins-ci.plugins
@@ -57,11 +62,6 @@
commons-digester3
3.2
-
- org.jenkins-ci.plugins
- script-security
- 1.17
-
org.jenkins-ci.plugins.workflow
workflow-scm-step
diff --git a/src/main/java/hudson/plugins/warnings/GroovyParser.java b/src/main/java/hudson/plugins/warnings/GroovyParser.java
index e6e27e813..f8675c28f 100644
--- a/src/main/java/hudson/plugins/warnings/GroovyParser.java
+++ b/src/main/java/hudson/plugins/warnings/GroovyParser.java
@@ -12,12 +12,16 @@
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
-import groovy.lang.GroovyShell;
+import jenkins.model.Jenkins;
import hudson.Extension;
import hudson.model.AbstractDescribableImpl;
import hudson.model.Descriptor;
-import hudson.plugins.warnings.parser.*;
+import hudson.plugins.warnings.parser.AbstractWarningsParser;
+import hudson.plugins.warnings.parser.DynamicDocumentParser;
+import hudson.plugins.warnings.parser.DynamicParser;
+import hudson.plugins.warnings.parser.GroovyExpressionMatcher;
+import hudson.plugins.warnings.parser.Warning;
import hudson.util.FormValidation;
import hudson.util.FormValidation.Kind;
@@ -28,7 +32,6 @@
* @author Ulli Hafner
*/
public class GroovyParser extends AbstractDescribableImpl {
-
private static final int MAX_EXAMPLE_SIZE = 4096;
private final String name;
@@ -223,6 +226,7 @@ public AbstractWarningsParser getParser() {
public static class DescriptorImpl extends Descriptor {
private static final String NEWLINE = "\n";
private static final int MAX_MESSAGE_LENGTH = 60;
+ private static final FormValidation NO_RUN_SCRIPT_PERMISSION_WARNING = FormValidation.warning(Messages.Warnings_GroovyParser_Warning_NoRunScriptPermission());
private FormValidation validate(final String name, final String message) {
if (StringUtils.isBlank(name)) {
@@ -293,13 +297,16 @@ public FormValidation doCheckRegexp(@QueryParameter(required = true) final Strin
* @return the validation result
*/
public FormValidation doCheckScript(@QueryParameter(required = true) final String script) {
+ if (!canRunScripts()) {
+ return NO_RUN_SCRIPT_PERMISSION_WARNING;
+ }
try {
if (StringUtils.isBlank(script)) {
return FormValidation.error(Messages.Warnings_GroovyParser_Error_Script_isEmpty());
}
- GroovyShell groovyShell = new GroovyShell(WarningsDescriptor.class.getClassLoader());
- groovyShell.parse(script);
+ GroovyExpressionMatcher matcher = new GroovyExpressionMatcher(script, null);
+ matcher.compile();
return FormValidation.ok();
}
@@ -308,6 +315,10 @@ public FormValidation doCheckScript(@QueryParameter(required = true) final Strin
}
}
+ private boolean canRunScripts() {
+ return Jenkins.getInstance().getACL().hasPermission(Jenkins.RUN_SCRIPTS);
+ }
+
/**
* Parses the example message with the specified regular expression and script.
*
@@ -321,6 +332,9 @@ public FormValidation doCheckScript(@QueryParameter(required = true) final Strin
*/
public FormValidation doCheckExample(@QueryParameter final String example,
@QueryParameter final String regexp, @QueryParameter final String script) {
+ if (!canRunScripts()) {
+ return NO_RUN_SCRIPT_PERMISSION_WARNING;
+ }
if (StringUtils.isNotBlank(example) && StringUtils.isNotBlank(regexp) && StringUtils.isNotBlank(script)) {
FormValidation response = parseExample(script, example, regexp, containsNewline(regexp));
if (example.length() <= MAX_EXAMPLE_SIZE) {
diff --git a/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java b/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java
index 684ea322c..4adeb6558 100644
--- a/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java
+++ b/src/main/java/hudson/plugins/warnings/WarningsDescriptor.java
@@ -3,6 +3,7 @@
import java.io.IOException;
import java.util.Collection;
+import org.jenkinsci.Symbol;
import org.kohsuke.stapler.Ancestor;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.QueryParameter;
@@ -28,7 +29,7 @@
*
* @author Ulli Hafner
*/
-@Extension(ordinal = 100) // NOCHECKSTYLE
+@Extension(ordinal = 100) @Symbol("warnings")
public final class WarningsDescriptor extends PluginDescriptor implements StaplerProxy {
/** The ID of this plug-in is used as URL. */
static final String PLUGIN_ID = "warnings";
diff --git a/src/main/java/hudson/plugins/warnings/WarningsPublisher.java b/src/main/java/hudson/plugins/warnings/WarningsPublisher.java
index 1143a2caf..acc849e94 100644
--- a/src/main/java/hudson/plugins/warnings/WarningsPublisher.java
+++ b/src/main/java/hudson/plugins/warnings/WarningsPublisher.java
@@ -9,6 +9,9 @@
import java.util.Set;
import org.apache.commons.lang.StringUtils;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
+import org.jenkinsci.plugins.scriptsecurity.scripts.ApprovalContext;
+import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
@@ -367,19 +370,29 @@ private List parseConsoleLog(final Run, ?> run, final FilePath w
String parserName = parser.getParserName();
logger.log("Parsing warnings in console log with parser " + parserName);
- Collection warnings = new ParserRegistry(ParserRegistry.getParsers(parserName),
- getDefaultEncoding()).parse(run.getLogFile());
- if (!workspace.isRemote()) {
- guessModuleNames(workspace, warnings);
- }
- ParserResult project = new ParserResult(workspace, canResolveRelativePaths());
- project.addAnnotations(warnings);
+ try {
+ Collection warnings = new ParserRegistry(ParserRegistry.getParsers(parserName),
+ getDefaultEncoding()).parse(run.getLogFile());
+ if (!workspace.isRemote()) {
+ guessModuleNames(workspace, warnings);
+ }
+ ParserResult project = new ParserResult(workspace, canResolveRelativePaths());
+ project.addAnnotations(warnings);
- results.add(annotate(run, workspace, filterWarnings(project, logger), parserName));
+ results.add(annotate(run, workspace, filterWarnings(project, logger), parserName));
+ }
+ catch (RejectedAccessException exception) {
+ handleRejectedException(logger, parserName, exception);
+ }
}
return results;
}
+ private void handleRejectedException(final PluginLogger logger, final String parserName, final RejectedAccessException exception) {
+ logger.log(Messages.Warnings_GroovyParser_Warning_Rejected(parserName, exception.getMessage()));
+ ScriptApproval.get().accessRejected(exception, ApprovalContext.create());
+ }
+
private ParserResult filterWarnings(final ParserResult project, final PluginLogger logger) {
WarningsFilter filter = new WarningsFilter();
if (filter.isActive(getIncludePattern(), getExcludePattern(), getMessagesPattern(), getCategoriesPattern())) {
@@ -410,11 +423,17 @@ private List parseFiles(final Run, ?> run, final FilePath worksp
FilesParser parser = new FilesParser(PLUGIN_NAME, filePattern,
new FileWarningsParser(ParserRegistry.getParsers(parserName), getDefaultEncoding()),
shouldDetectModules(), isMavenBuild(run), canResolveRelativePaths());
- ParserResult project = workspace.act(parser);
- logger.logLines(project.getLogMessages());
+ ParserResult project = null;
+ try {
+ project = workspace.act(parser);
+ logger.logLines(project.getLogMessages());
- returnIfCanceled();
- results.add(annotate(run, workspace, filterWarnings(project, logger), configuration.getParserName()));
+ returnIfCanceled();
+ results.add(annotate(run, workspace, filterWarnings(project, logger), configuration.getParserName()));
+ }
+ catch (RejectedAccessException exception) {
+ handleRejectedException(logger, parserName, exception);
+ }
}
return results;
}
diff --git a/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java b/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java
index 92ce2aa7e..65e951475 100644
--- a/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java
+++ b/src/main/java/hudson/plugins/warnings/parser/AbstractWarningsParser.java
@@ -8,10 +8,10 @@
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.StringEscapeUtils;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.Whitelisted;
import org.jvnet.localizer.Localizable;
import hudson.ExtensionPoint;
-
import hudson.plugins.analysis.util.model.FileAnnotation;
import hudson.plugins.analysis.util.model.Priority;
import hudson.plugins.warnings.Messages;
@@ -189,6 +189,7 @@ protected String getId() {
* the message of the warning
* @return the warning
*/
+ @Whitelisted
public Warning createWarning(final String fileName, final int start, final String category, final String message) {
return new Warning(fileName, start, getGroup(), category, message);
}
@@ -205,6 +206,7 @@ public Warning createWarning(final String fileName, final int start, final Strin
* the message of the warning
* @return the warning
*/
+ @Whitelisted
public Warning createWarning(final String fileName, final int start, final String message) {
return createWarning(fileName, start, StringUtils.EMPTY, message);
}
@@ -224,6 +226,7 @@ public Warning createWarning(final String fileName, final int start, final Strin
* the priority of the warning
* @return the warning
*/
+ @Whitelisted
public Warning createWarning(final String fileName, final int start, final String category, final String message, final Priority priority) {
return new Warning(fileName, start, getGroup(), category, message, priority);
}
@@ -246,6 +249,7 @@ public Warning createWarning(final String fileName, final int start, final Strin
* @return the warning
* @since 4.24
*/
+ @Whitelisted
public Warning createWarning(final String fileName, final int start, final String type, final String category, final String message, final Priority priority) {
return new Warning(fileName, start, type, category, message, priority);
}
@@ -264,6 +268,7 @@ public Warning createWarning(final String fileName, final int start, final Strin
* the priority of the warning
* @return the warning
*/
+ @Whitelisted
public Warning createWarning(final String fileName, final int start, final String message, final Priority priority) {
return createWarning(fileName, start, StringUtils.EMPTY, message, priority);
}
@@ -295,6 +300,7 @@ public String getLargeImage() {
* the line number (as a string)
* @return the line number
*/
+ @Whitelisted
protected final int getLineNumber(final String lineNumber) {
return convertLineNumber(lineNumber);
}
@@ -309,6 +315,7 @@ protected final int getLineNumber(final String lineNumber) {
* @return the line number
* @since 4.37
*/
+ @Whitelisted
public static int convertLineNumber(final String lineNumber) {
if (StringUtils.isNotBlank(lineNumber)) {
try {
@@ -328,6 +335,7 @@ public static int convertLineNumber(final String lineNumber) {
* @return the escaped text
* @see StringEscapeUtils#escapeXml11
*/
+ @Whitelisted
protected String escapeXml(final String text) {
return StringEscapeUtils.escapeXml10(text);
}
diff --git a/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java b/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java
index 0faf3de2e..980360769 100644
--- a/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java
+++ b/src/main/java/hudson/plugins/warnings/parser/GroovyExpressionMatcher.java
@@ -1,11 +1,15 @@
package hudson.plugins.warnings.parser;
import java.io.Serializable;
+import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import org.codehaus.groovy.control.CompilationFailedException;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
+import org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.GroovySandbox;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
@@ -26,7 +30,6 @@ public class GroovyExpressionMatcher implements Serializable {
private transient Script compiled;
-
/**
* Creates a new instance of {@link GroovyExpressionMatcher}.
*
@@ -43,19 +46,30 @@ public GroovyExpressionMatcher(final String script, final Warning falsePositive)
private void compileScriptIfNotYetDone() {
synchronized (script) {
if (compiled == null) {
- GroovyShell shell = new GroovyShell(WarningsDescriptor.class.getClassLoader());
try {
- compiled = shell.parse(script);
+ compiled = compile();
}
catch (CompilationFailedException exception) {
LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during compiling: ", exception);
}
-
- compiled.getBinding().setVariable("falsePositive", falsePositive);
}
}
}
+ /**
+ * Compiles the script.
+ *
+ * @return the compiled script
+ * @throws CompilationFailedException if the script contains compile errors
+ */
+ public Script compile() throws CompilationFailedException {
+ ClassLoader loader = GroovySandbox.createSecureClassLoader(WarningsDescriptor.class.getClassLoader());
+ Binding binding = new Binding();
+ binding.setVariable("falsePositive", falsePositive);
+ GroovyShell shell = new GroovyShell(loader, binding, GroovySandbox.createSecureCompilerConfiguration());
+ return shell.parse(script);
+ }
+
/**
* Creates a new annotation for the specified match.
*
@@ -64,16 +78,20 @@ private void compileScriptIfNotYetDone() {
* @param lineNumber
* the current line number
* @return a new annotation for the specified pattern
+ * @throws RejectedAccessException if the Groovy sandbox rejected the parsing script
*/
- public Warning createWarning(final Matcher matcher, final int lineNumber) {
+ public Warning createWarning(final Matcher matcher, final int lineNumber) throws RejectedAccessException {
try {
Object result = run(matcher, lineNumber);
if (result instanceof Warning) {
return (Warning)result;
}
}
+ catch (RejectedAccessException exception) {
+ throw exception; // Groovy sandbox rejected the parsing script: needs to be presented to the user
+ }
catch (Exception exception) { // NOPMD NOCHECKSTYLE: catch all exceptions of the Groovy script
- LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during parsing: ", exception);
+ LOGGER.log(Level.SEVERE, "Groovy dynamic warnings parser: exception during execution: ", exception);
}
return falsePositive;
}
@@ -86,15 +104,29 @@ public Warning createWarning(final Matcher matcher, final int lineNumber) {
* @param lineNumber
* the current line number
* @return unchecked result of the script
+ * @throws RejectedAccessException if the Groovy sandbox rejected the parsing script
*/
- public Object run(final Matcher matcher, final int lineNumber) {
+ public Object run(final Matcher matcher, final int lineNumber) throws RejectedAccessException {
compileScriptIfNotYetDone();
Binding binding = compiled.getBinding();
binding.setVariable("matcher", matcher);
binding.setVariable("lineNumber", lineNumber);
- return compiled.run();
+ try {
+ return GroovySandbox.runInSandbox(new Callable