mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 17:05:43 +01:00
Detect core plugins and prevent installation
This commit is contained in:
@@ -47,19 +47,20 @@ public final class InstalledPlugin implements Plugin
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new plugin wrapper.
|
* Constructs a new plugin wrapper.
|
||||||
*
|
* @param descriptor wrapped plugin
|
||||||
* @param descriptor wrapped plugin
|
|
||||||
* @param classLoader plugin class loader
|
* @param classLoader plugin class loader
|
||||||
* @param webResourceLoader web resource loader
|
* @param webResourceLoader web resource loader
|
||||||
* @param directory plugin directory
|
* @param directory plugin directory
|
||||||
|
* @param core marked as core or not
|
||||||
*/
|
*/
|
||||||
public InstalledPlugin(InstalledPluginDescriptor descriptor, ClassLoader classLoader,
|
public InstalledPlugin(InstalledPluginDescriptor descriptor, ClassLoader classLoader,
|
||||||
WebResourceLoader webResourceLoader, Path directory)
|
WebResourceLoader webResourceLoader, Path directory, boolean core)
|
||||||
{
|
{
|
||||||
this.descriptor = descriptor;
|
this.descriptor = descriptor;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.webResourceLoader = webResourceLoader;
|
this.webResourceLoader = webResourceLoader;
|
||||||
this.directory = directory;
|
this.directory = directory;
|
||||||
|
this.core = core;
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- get methods ----------------------------------------------------------
|
//~--- get methods ----------------------------------------------------------
|
||||||
@@ -120,6 +121,10 @@ public final class InstalledPlugin implements Plugin
|
|||||||
return webResourceLoader;
|
return webResourceLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCore() {
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|
||||||
/** plugin class loader */
|
/** plugin class loader */
|
||||||
@@ -133,4 +138,6 @@ public final class InstalledPlugin implements Plugin
|
|||||||
|
|
||||||
/** plugin web resource loader */
|
/** plugin web resource loader */
|
||||||
private final WebResourceLoader webResourceLoader;
|
private final WebResourceLoader webResourceLoader;
|
||||||
|
|
||||||
|
private final boolean core;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public class PluginDto extends HalRepresentation {
|
|||||||
private String category;
|
private String category;
|
||||||
private String avatarUrl;
|
private String avatarUrl;
|
||||||
private boolean pending;
|
private boolean pending;
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
private Boolean core;
|
||||||
private Set<String> dependencies;
|
private Set<String> dependencies;
|
||||||
|
|
||||||
public PluginDto(Links links) {
|
public PluginDto(Links links) {
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ public abstract class PluginDtoMapper {
|
|||||||
Links.Builder links = linkingTo()
|
Links.Builder links = linkingTo()
|
||||||
.self(resourceLinks.installedPlugin()
|
.self(resourceLinks.installedPlugin()
|
||||||
.self(information.getName()));
|
.self(information.getName()));
|
||||||
if (availablePlugin.isPresent()
|
if (!plugin.isCore()
|
||||||
|
&& availablePlugin.isPresent()
|
||||||
&& !availablePlugin.get().isPending()
|
&& !availablePlugin.get().isPending()
|
||||||
&& PluginPermissions.manage().isPermitted()
|
&& PluginPermissions.manage().isPermitted()
|
||||||
) {
|
) {
|
||||||
@@ -81,6 +82,8 @@ public abstract class PluginDtoMapper {
|
|||||||
dto.setPending(value.isPending());
|
dto.setPending(value.isPending());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dto.setCore(plugin.isCore());
|
||||||
|
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import com.google.inject.Singleton;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
|
import sonia.scm.ScmConstraintViolationException;
|
||||||
import sonia.scm.event.ScmEventBus;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.lifecycle.RestartEvent;
|
import sonia.scm.lifecycle.RestartEvent;
|
||||||
import sonia.scm.version.Version;
|
import sonia.scm.version.Version;
|
||||||
@@ -54,6 +55,7 @@ import java.util.function.Predicate;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
import static sonia.scm.ContextEntry.ContextBuilder.entity;
|
||||||
|
import static sonia.scm.ScmConstraintViolationException.Builder.doThrow;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -139,6 +141,13 @@ public class DefaultPluginManager implements PluginManager {
|
|||||||
@Override
|
@Override
|
||||||
public void install(String name, boolean restartAfterInstallation) {
|
public void install(String name, boolean restartAfterInstallation) {
|
||||||
PluginPermissions.manage().check();
|
PluginPermissions.manage().check();
|
||||||
|
|
||||||
|
getInstalled(name)
|
||||||
|
.map(InstalledPlugin::isCore)
|
||||||
|
.ifPresent(
|
||||||
|
core -> doThrow().violation("plugin is a core plugin and cannot be updated").when(core)
|
||||||
|
);
|
||||||
|
|
||||||
List<AvailablePlugin> plugins = collectPluginsToInstall(name);
|
List<AvailablePlugin> plugins = collectPluginsToInstall(name);
|
||||||
List<PendingPluginInstallation> pendingInstallations = new ArrayList<>();
|
List<PendingPluginInstallation> pendingInstallations = new ArrayList<>();
|
||||||
for (AvailablePlugin plugin : plugins) {
|
for (AvailablePlugin plugin : plugins) {
|
||||||
|
|||||||
@@ -461,13 +461,16 @@ public final class PluginProcessor
|
|||||||
Path descriptorPath = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
|
Path descriptorPath = directory.resolve(PluginConstants.FILE_DESCRIPTOR);
|
||||||
|
|
||||||
if (Files.exists(descriptorPath)) {
|
if (Files.exists(descriptorPath)) {
|
||||||
|
|
||||||
|
boolean core = Files.exists(directory.resolve("core"));
|
||||||
|
|
||||||
ClassLoader cl = createClassLoader(classLoader, smp);
|
ClassLoader cl = createClassLoader(classLoader, smp);
|
||||||
|
|
||||||
InstalledPluginDescriptor descriptor = createDescriptor(cl, descriptorPath);
|
InstalledPluginDescriptor descriptor = createDescriptor(cl, descriptorPath);
|
||||||
|
|
||||||
WebResourceLoader resourceLoader = createWebResourceLoader(directory);
|
WebResourceLoader resourceLoader = createWebResourceLoader(directory);
|
||||||
|
|
||||||
plugin = new InstalledPlugin(descriptor, cl, resourceLoader, directory);
|
plugin = new InstalledPlugin(descriptor, cl, resourceLoader, directory, core);
|
||||||
} else {
|
} else {
|
||||||
logger.warn("found plugin directory without plugin descriptor");
|
logger.warn("found plugin directory without plugin descriptor");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.mockito.InjectMocks;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import sonia.scm.NotFoundException;
|
import sonia.scm.NotFoundException;
|
||||||
|
import sonia.scm.ScmConstraintViolationException;
|
||||||
import sonia.scm.event.ScmEventBus;
|
import sonia.scm.event.ScmEventBus;
|
||||||
import sonia.scm.lifecycle.RestartEvent;
|
import sonia.scm.lifecycle.RestartEvent;
|
||||||
|
|
||||||
@@ -177,6 +178,31 @@ class DefaultPluginManagerTest {
|
|||||||
verify(eventBus, never()).post(any());
|
verify(eventBus, never()).post(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUpdateNormalPlugin() {
|
||||||
|
AvailablePlugin available = createAvailable("scm-git-plugin", "2");
|
||||||
|
InstalledPlugin installed = createInstalled("scm-git-plugin", "1");
|
||||||
|
when(installed.isCore()).thenReturn(false);
|
||||||
|
lenient().when(center.getAvailable()).thenReturn(ImmutableSet.of(available));
|
||||||
|
when(loader.getInstalledPlugins()).thenReturn(ImmutableSet.of(installed));
|
||||||
|
|
||||||
|
manager.install("scm-git-plugin", false);
|
||||||
|
|
||||||
|
verify(installer).install(available);
|
||||||
|
verify(eventBus, never()).post(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotUpdateCorePlugin() {
|
||||||
|
AvailablePlugin available = createAvailable("scm-git-plugin", "2");
|
||||||
|
InstalledPlugin installed = createInstalled("scm-git-plugin", "1");
|
||||||
|
when(installed.isCore()).thenReturn(true);
|
||||||
|
lenient().when(center.getAvailable()).thenReturn(ImmutableSet.of(available));
|
||||||
|
when(loader.getInstalledPlugins()).thenReturn(ImmutableSet.of(installed));
|
||||||
|
|
||||||
|
assertThrows(ScmConstraintViolationException.class, () -> manager.install("scm-git-plugin", false));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldInstallDependingPlugins() {
|
void shouldInstallDependingPlugins() {
|
||||||
AvailablePlugin review = createAvailable("scm-review-plugin", "1");
|
AvailablePlugin review = createAvailable("scm-review-plugin", "1");
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public class DefaultUberWebResourceLoaderTest extends WebResourceLoaderTestBase
|
|||||||
private InstalledPlugin createPluginWrapper(Path directory)
|
private InstalledPlugin createPluginWrapper(Path directory)
|
||||||
{
|
{
|
||||||
return new InstalledPlugin(null, null, new PathWebResourceLoader(directory),
|
return new InstalledPlugin(null, null, new PathWebResourceLoader(directory),
|
||||||
directory);
|
directory, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
//~--- fields ---------------------------------------------------------------
|
//~--- fields ---------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user