Add security notifications to inform about vulnerabilities (#1924)

Add security notifications in SCM-Manager to inform running instances about known security issues. These alerts can be core or plugin specific and will be shown to every user in the header.

Co-authored-by: Matthias Thieroff <matthias.thieroff@cloudogu.com>
Co-authored-by: Philipp Ahrendt <philipp.ahrendt@cloudogu.com>
Co-authored-by: Sebastian Sdorra <sebastian.sdorra@cloudogu.com>
This commit is contained in:
Eduard Heimbuch
2022-01-19 11:58:55 +01:00
committed by GitHub
parent 07fa753f80
commit 63ec4e6172
42 changed files with 1379 additions and 420 deletions

View File

@@ -30,6 +30,7 @@ import com.google.common.base.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
@@ -84,6 +85,16 @@ public final class ExplodedSmp
//~--- get methods ----------------------------------------------------------
/**
* Returns {@code true} if the exploded smp contains a core plugin
* @return {@code true} for a core plugin
* @since 2.30.0
*/
public boolean isCore() {
return Files.exists(path.resolve(PluginConstants.FILE_CORE));
}
/**
* Returns the path to the plugin directory.
*

View File

@@ -34,6 +34,7 @@ import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.SCMContext;
import sonia.scm.lifecycle.classloading.ClassLoaderLifeCycle;
import javax.xml.bind.JAXBContext;
@@ -175,7 +176,7 @@ public final class PluginProcessor
Set<ExplodedSmp> plugins = concat(installedPlugins, newlyInstalledPlugins);
logger.trace("start building plugin tree");
PluginTree pluginTree = new PluginTree(plugins);
PluginTree pluginTree = new PluginTree(SCMContext.getContext().getStage(), plugins);
logger.info("install plugin tree:\n{}", pluginTree);
@@ -468,16 +469,13 @@ public final class PluginProcessor
Path descriptorPath = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
if (Files.exists(descriptorPath)) {
boolean core = Files.exists(directory.resolve(PluginConstants.FILE_CORE));
ClassLoader cl = createClassLoader(classLoader, smp);
InstalledPluginDescriptor descriptor = createDescriptor(cl, descriptorPath);
WebResourceLoader resourceLoader = createWebResourceLoader(directory);
plugin = new InstalledPlugin(descriptor, cl, resourceLoader, directory, core);
plugin = new InstalledPlugin(descriptor, cl, resourceLoader, directory, smp.isCore());
} else {
logger.warn("found plugin directory without plugin descriptor");
}

View File

@@ -24,10 +24,10 @@
package sonia.scm.plugin;
//~--- non-JDK imports --------------------------------------------------------
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.Stage;
import java.util.Arrays;
import java.util.Collection;
@@ -35,76 +35,62 @@ import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
//~--- JDK imports ------------------------------------------------------------
/**
*
* @author Sebastian Sdorra
*/
public final class PluginTree
{
public final class PluginTree {
/** Field description */
private static final int SCM_VERSION = 2;
/**
* the logger for PluginTree
*/
private static final Logger logger =
LoggerFactory.getLogger(PluginTree.class);
private static final Logger LOG = LoggerFactory.getLogger(PluginTree.class);
//~--- constructors ---------------------------------------------------------
private final Stage stage;
private final List<PluginNode> rootNodes;
/**
* Constructs ...
*
*
* @param smps
*/
public PluginTree(ExplodedSmp... smps)
{
this(Arrays.asList(smps));
public PluginTree(Stage stage, ExplodedSmp... smps) {
this(stage, Arrays.asList(smps));
}
/**
* Constructs ...
*
*
* @param smps
*/
public PluginTree(Collection<ExplodedSmp> smps)
{
public PluginTree(Stage stage, Collection<ExplodedSmp> smps) {
this.stage = stage;
smps.forEach(s -> {
InstalledPluginDescriptor plugin = s.getPlugin();
logger.trace("plugin: {}", plugin.getInformation().getName());
logger.trace("dependencies: {}", plugin.getDependencies());
logger.trace("optional dependencies: {}", plugin.getOptionalDependencies());
LOG.trace("plugin: {}", plugin.getInformation().getName());
LOG.trace("dependencies: {}", plugin.getDependencies());
LOG.trace("optional dependencies: {}", plugin.getOptionalDependencies());
});
rootNodes = new SmpNodeBuilder().buildNodeTree(smps);
for (ExplodedSmp smp : smps)
{
InstalledPluginDescriptor plugin = smp.getPlugin();
for (ExplodedSmp smp : smps) {
checkIfSupported(smp);
}
}
if (plugin.getScmVersion() != SCM_VERSION)
{
//J-
throw new PluginException(
String.format(
"scm version %s of plugin %s does not match, required is version %s",
plugin.getScmVersion(), plugin.getInformation().getId(), SCM_VERSION
)
);
//J+
}
private void checkIfSupported(ExplodedSmp smp) {
InstalledPluginDescriptor plugin = smp.getPlugin();
PluginCondition condition = plugin.getCondition();
if (plugin.getScmVersion() != SCM_VERSION) {
throw new PluginException(
String.format(
"scm version %s of plugin %s does not match, required is version %s",
plugin.getScmVersion(), plugin.getInformation().getId(), SCM_VERSION
)
);
}
if (!condition.isSupported())
{
//J-
checkIfConditionsMatch(smp, plugin);
}
private void checkIfConditionsMatch(ExplodedSmp smp, InstalledPluginDescriptor plugin) {
PluginCondition condition = plugin.getCondition();
if (!condition.isSupported()) {
if (smp.isCore() && stage == Stage.DEVELOPMENT) {
LOG.warn("plugin {} does not match conditions {}", plugin.getInformation().getId(), condition);
} else {
throw new PluginConditionFailedException(
condition,
String.format(
@@ -112,29 +98,17 @@ public final class PluginTree
plugin.getInformation().getId(), condition
)
);
//J+
}
}
}
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @return
*/
public List<PluginNode> getLeafLastNodes()
{
public List<PluginNode> getLeafLastNodes() {
LinkedHashSet<PluginNode> leafFirst = new LinkedHashSet<>();
rootNodes.forEach(node -> appendLeafFirst(leafFirst, node));
LinkedList<PluginNode> leafLast = new LinkedList<>();
leafFirst.forEach(leafLast::addFirst);
return leafLast;
}
@@ -143,9 +117,6 @@ public final class PluginTree
leafFirst.add(node);
}
//~--- methods --------------------------------------------------------------
@Override
public String toString() {
StringBuilder buffer = new StringBuilder();
@@ -163,8 +134,4 @@ public final class PluginTree
}
}
//~--- fields ---------------------------------------------------------------
/** Field description */
private final List<PluginNode> rootNodes;
}