diff --git a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java index 1e6b133832..c9ee281ec4 100644 --- a/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java +++ b/wsmaster/che-core-api-factory/src/main/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2023 Red Hat, Inc. + * Copyright (c) 2012-2024 Red Hat, Inc. * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ @@ -17,6 +17,7 @@ import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME; import jakarta.validation.constraints.NotNull; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; @@ -30,8 +31,10 @@ import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl; import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder; import org.eclipse.che.api.factory.shared.dto.FactoryMetaDto; +import org.eclipse.che.api.workspace.server.devfile.DevfileParser; import org.eclipse.che.api.workspace.server.devfile.URLFetcher; import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider; +import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException; /** * {@link FactoryParametersResolver} implementation to resolve factory based on url parameter as a @@ -45,13 +48,15 @@ public class RawDevfileUrlFactoryParameterResolver extends BaseFactoryParameterR protected final URLFactoryBuilder urlFactoryBuilder; protected final URLFetcher urlFetcher; + private final DevfileParser devfileParser; @Inject public RawDevfileUrlFactoryParameterResolver( - URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher) { + URLFactoryBuilder urlFactoryBuilder, URLFetcher urlFetcher, DevfileParser devfileParser) { super(null, urlFactoryBuilder, PROVIDER_NAME); this.urlFactoryBuilder = urlFactoryBuilder; this.urlFetcher = urlFetcher; + this.devfileParser = devfileParser; } /** @@ -64,7 +69,17 @@ public RawDevfileUrlFactoryParameterResolver( @Override public boolean accept(Map factoryParameters) { String url = factoryParameters.get(URL_PARAMETER_NAME); - return !isNullOrEmpty(url) && PATTERN.matcher(url).matches(); + return !isNullOrEmpty(url) && PATTERN.matcher(url).matches() || containsDevfile(url); + } + + private boolean containsDevfile(String requestURL) { + try { + String fetch = urlFetcher.fetch(requestURL); + devfileParser.parseYaml(fetch); + return true; + } catch (IOException | DevfileFormatException e) { + return !e.getMessage().startsWith("Cannot construct instance of"); + } } @Override diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolverTest.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolverTest.java index 68d7e1999d..6f0d65edbe 100644 --- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolverTest.java +++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/RawDevfileUrlFactoryParameterResolverTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.testng.Assert.assertFalse; import static org.testng.Assert.fail; import static org.testng.AssertJUnit.assertEquals; @@ -38,9 +39,11 @@ import org.eclipse.che.api.workspace.server.devfile.DevfileVersionDetector; import org.eclipse.che.api.workspace.server.devfile.URLFetcher; import org.eclipse.che.api.workspace.server.devfile.URLFileContentProvider; +import org.eclipse.che.api.workspace.server.devfile.exception.DevfileFormatException; import org.eclipse.che.api.workspace.server.devfile.validator.ComponentIntegrityValidator; import org.eclipse.che.api.workspace.server.devfile.validator.ComponentIntegrityValidator.NoopComponentIntegrityValidator; import org.eclipse.che.api.workspace.server.devfile.validator.DevfileIntegrityValidator; +import org.eclipse.che.api.workspace.server.model.impl.devfile.DevfileImpl; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -63,6 +66,7 @@ public class RawDevfileUrlFactoryParameterResolverTest { + " reference: ../localfile\n"; @Mock private URLFetcher urlFetcher; + @Mock private DevfileParser devfileParser; @InjectMocks private RawDevfileUrlFactoryParameterResolver rawDevfileUrlFactoryParameterResolver; @@ -84,7 +88,7 @@ public void shouldResolveRelativeFiles() throws Exception { "editor", "plugin", false, devfileParser, new DevfileVersionDetector()); RawDevfileUrlFactoryParameterResolver res = - new RawDevfileUrlFactoryParameterResolver(factoryBuilder, urlFetcher); + new RawDevfileUrlFactoryParameterResolver(factoryBuilder, urlFetcher, devfileParser); // set up our factory with the location of our devfile that is referencing our localfile Map factoryParameters = new HashMap<>(); @@ -106,7 +110,7 @@ public void shouldFilterAndProvideOverrideParameters() throws Exception { URLFetcher urlFetcher = mock(URLFetcher.class); RawDevfileUrlFactoryParameterResolver res = - new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher); + new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser); Map factoryParameters = new HashMap<>(); factoryParameters.put(URL_PARAMETER_NAME, "http://myloc/devfile"); @@ -137,7 +141,7 @@ public void shouldThrowExceptionOnInvalidURL(String url, String message) throws URLFetcher urlFetcher = mock(URLFetcher.class); RawDevfileUrlFactoryParameterResolver res = - new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher); + new RawDevfileUrlFactoryParameterResolver(urlFactoryBuilder, urlFetcher, devfileParser); Map factoryParameters = new HashMap<>(); factoryParameters.put(URL_PARAMETER_NAME, url); @@ -156,7 +160,11 @@ public void shouldThrowExceptionOnInvalidURL(String url, String message) throws } @Test(dataProvider = "devfileUrls") - public void shouldAcceptRawDevfileUrl(String url) { + public void shouldAcceptRawDevfileUrl(String url) throws Exception { + // given + when(urlFetcher.fetch(eq(url))).thenReturn(DEVFILE); + when(devfileParser.parseYaml(eq(DEVFILE))).thenReturn(mock(DevfileImpl.class)); + // when boolean result = rawDevfileUrlFactoryParameterResolver.accept(singletonMap(URL_PARAMETER_NAME, url)); @@ -166,11 +174,33 @@ public void shouldAcceptRawDevfileUrl(String url) { } @Test - public void shouldNotAcceptRawDevfileUrl() { + public void shouldAcceptRawDevfileUrlWithUnrecognizedDevfile() throws Exception { + // given + String url = "https://host/path/devfile"; + when(urlFetcher.fetch(eq(url))).thenReturn(DEVFILE); + when(devfileParser.parseYaml(eq(DEVFILE))) + .thenThrow(new DevfileFormatException("Unrecognized field \"schemaVersion\"")); + + // when + boolean result = + rawDevfileUrlFactoryParameterResolver.accept(singletonMap(URL_PARAMETER_NAME, url)); + + // then + assertTrue(result); + } + + @Test + public void shouldNotAcceptGitRepositoryUrl() throws Exception { + // given + String gitRepositoryUrl = "https://host/user/repo.git"; + when(urlFetcher.fetch(eq(gitRepositoryUrl))).thenReturn("unsupported content"); + when(devfileParser.parseYaml(eq("unsupported content"))) + .thenThrow(new DevfileFormatException("Cannot construct instance of ...")); + // when boolean result = rawDevfileUrlFactoryParameterResolver.accept( - singletonMap(URL_PARAMETER_NAME, "https://host/user/repo.git")); + singletonMap(URL_PARAMETER_NAME, gitRepositoryUrl)); // then assertFalse(result); @@ -195,10 +225,12 @@ private Object[] devfileUrls() { "https://host/path/.devfile.yaml", "https://host/path/any-name.yaml", "https://host/path/any-name.yml", + "https://host/path/any-name", "https://host/path/devfile.yaml?token=TOKEN123", "https://host/path/.devfile.yaml?token=TOKEN123", "https://host/path/any-name.yaml?token=TOKEN123", - "https://host/path/any-name.yml?token=TOKEN123" + "https://host/path/any-name.yml?token=TOKEN123", + "https://host/path/any-name?token=TOKEN123" }; } }