diff --git a/.ci/openshift-ci/test-gitea-no-pat-oauth-flow.sh b/.ci/openshift-ci/test-gitea-no-pat-oauth-flow.sh
index af58e0be7a7..27e93606d48 100644
--- a/.ci/openshift-ci/test-gitea-no-pat-oauth-flow.sh
+++ b/.ci/openshift-ci/test-gitea-no-pat-oauth-flow.sh
@@ -31,8 +31,8 @@ trap "catchFinish" EXIT SIGINT
setupTestEnvironment ${OCP_NON_ADMIN_USER_NAME}
setupSSHKeyPairs "${GITEA_PRIVATE_KEY}" "${GITEA_PUBLIC_KEY}"
-testFactoryResolverResponse ${PUBLIC_REPO_SSH_URL} 200
-testFactoryResolverResponse ${PRIVATE_REPO_SSH_URL} 200
+testFactoryResolverResponse ${PUBLIC_REPO_SSH_URL} 500
+testFactoryResolverResponse ${PRIVATE_REPO_SSH_URL} 500
testFactoryResolverResponse ${PUBLIC_REPO_RAW_PATH_URL} 200
testCloneGitRepoProjectShouldExists ${PUBLIC_REPO_WORKSPACE_NAME} ${PUBLIC_PROJECT_NAME} ${PUBLIC_REPO_SSH_URL} ${USER_CHE_NAMESPACE}
diff --git a/wsmaster/che-core-api-factory-git-ssh/pom.xml b/wsmaster/che-core-api-factory-git-ssh/pom.xml
index 349d1eff6f0..12613a20c8b 100644
--- a/wsmaster/che-core-api-factory-git-ssh/pom.xml
+++ b/wsmaster/che-core-api-factory-git-ssh/pom.xml
@@ -26,6 +26,10 @@
true
+
+ com.google.guava
+ guava
+
jakarta.inject
jakarta.inject-api
diff --git a/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolver.java b/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolver.java
index 890e3a8b255..0ce68f53fe5 100644
--- a/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolver.java
+++ b/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2024 Red Hat, Inc.
+ * Copyright (c) 2012-2025 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/
@@ -12,7 +12,6 @@
package org.eclipse.che.api.factory.server.git.ssh;
import static org.eclipse.che.api.factory.server.FactoryResolverPriority.LOWEST;
-import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION;
import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;
import static org.eclipse.che.dto.server.DtoFactory.newDto;
@@ -35,7 +34,7 @@
import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
/**
- * Provides Factory Parameters resolver for Git Ssh repositories.
+ * Provides Factory Parameters resolver for SSH urls of unsupported Git providers.
*
* @author Anatolii Bazko
*/
@@ -90,15 +89,11 @@ public FactoryMetaDto createFactory(@NotNull final Map factoryPa
gitSshUrl, urlFetcher, personalAccessTokenManager),
extractOverrideParams(factoryParameters),
true)
- .orElseGet(
- () -> newDto(FactoryDevfileV2Dto.class).withV(CURRENT_VERSION).withSource("repo"))
+ .orElseThrow(() -> new ApiException("Failed to fetch devfile"))
.acceptVisitor(new GitSshFactoryVisitor(gitSshUrl));
}
- /**
- * Visitor that puts the default devfile or updates devfile projects into the Git Ssh Factory, if
- * needed.
- */
+ /** Visitor that updates factory dto with git ssh information. */
private class GitSshFactoryVisitor implements FactoryVisitor {
private final GitSshUrl gitSshUrl;
diff --git a/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrl.java b/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrl.java
index ae180c9e07b..9e3ac61d8de 100644
--- a/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrl.java
+++ b/wsmaster/che-core-api-factory-git-ssh/src/main/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2023 Red Hat, Inc.
+ * Copyright (c) 2012-2025 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/
@@ -73,6 +73,9 @@ public Optional filename() {
@Override
public String location() {
+ // Since we do not know the location from an SSH URL, we return the filename instead. The
+ // devfile content fetcher will always fail to fetch the devfile in this case.
+ // TODO: throw an error in order to avoid http request to fetch the devfile content.
return devfileFilename;
}
};
diff --git a/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolverTest.java b/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolverTest.java
new file mode 100644
index 00000000000..befedeb5b77
--- /dev/null
+++ b/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshFactoryParametersResolverTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2012-2025 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/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.factory.server.git.ssh;
+
+import static java.util.Collections.singletonMap;
+import static org.eclipse.che.api.factory.shared.Constants.CURRENT_VERSION;
+import static org.eclipse.che.api.factory.shared.Constants.URL_PARAMETER_NAME;
+import static org.eclipse.che.dto.server.DtoFactory.newDto;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+import org.eclipse.che.api.core.ApiException;
+import org.eclipse.che.api.factory.server.scm.AuthorisationRequestManager;
+import org.eclipse.che.api.factory.server.scm.PersonalAccessTokenManager;
+import org.eclipse.che.api.factory.server.urlfactory.DevfileFilenamesProvider;
+import org.eclipse.che.api.factory.server.urlfactory.URLFactoryBuilder;
+import org.eclipse.che.api.factory.shared.dto.FactoryDevfileV2Dto;
+import org.eclipse.che.api.factory.shared.dto.ScmInfoDto;
+import org.eclipse.che.api.workspace.server.devfile.FileContentProvider;
+import org.eclipse.che.api.workspace.server.devfile.URLFetcher;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(MockitoTestNGListener.class)
+public class GitSshFactoryParametersResolverTest {
+
+ @Mock private DevfileFilenamesProvider devfileFilenamesProvider;
+ @Mock private URLFetcher urlFetcher;
+ @Mock private URLFactoryBuilder urlFactoryBuilder;
+ @Mock private PersonalAccessTokenManager personalAccessTokenManager;
+ @Mock private AuthorisationRequestManager authorisationRequestManager;
+ @Mock private GitSshURLParser gitSshURLParser;
+ @Mock private GitSshUrl gitSshUrl;
+ private GitSshFactoryParametersResolver gitSshFactoryParametersResolver;
+
+ @BeforeMethod
+ protected void init() {
+ gitSshFactoryParametersResolver =
+ new GitSshFactoryParametersResolver(
+ gitSshURLParser,
+ urlFetcher,
+ urlFactoryBuilder,
+ personalAccessTokenManager,
+ authorisationRequestManager);
+ }
+
+ @Test
+ public void ShouldNotAcceptMissingParameter() {
+ // given
+ Map parameters = singletonMap("foo", "this is a foo bar");
+ // when
+ boolean accept = gitSshFactoryParametersResolver.accept(parameters);
+ // then
+ assertFalse(accept);
+ }
+
+ @Test
+ public void ShouldNotAcceptInvalidUrl() {
+ // given
+ String url = "https://provider.com/user/repo.git";
+ when(gitSshURLParser.isValid(eq(url))).thenReturn(false);
+ Map parameters = singletonMap(URL_PARAMETER_NAME, url);
+ // when
+ boolean accept = gitSshFactoryParametersResolver.accept(parameters);
+ // then
+ assertFalse(accept);
+ }
+
+ @Test
+ public void shouldAcceptValidUrl() {
+ // given
+ String url = "git@provider.com:user/repo.git";
+ when(gitSshURLParser.isValid(eq(url))).thenReturn(true);
+ Map parameters = singletonMap(URL_PARAMETER_NAME, url);
+ // when
+ boolean accept = gitSshFactoryParametersResolver.accept(parameters);
+ // then
+ assertTrue(accept);
+ }
+
+ @Test
+ public void shouldCreateFactoryWithDevfile() throws Exception {
+ // given
+ String url = "git@provider.com:user/repo.git";
+ when(gitSshUrl.getProviderName()).thenReturn("git-ssh");
+ when(gitSshUrl.getRepositoryLocation()).thenReturn("repository-location");
+ ImmutableMap params = ImmutableMap.of(URL_PARAMETER_NAME, url);
+ when(gitSshURLParser.parse(eq(url))).thenReturn(gitSshUrl);
+ when(urlFactoryBuilder.createFactoryFromDevfile(
+ eq(gitSshUrl), any(FileContentProvider.class), eq(Collections.emptyMap()), eq(true)))
+ .thenReturn(Optional.of(generateDevfileV2Factory()));
+ // when
+ FactoryDevfileV2Dto factory =
+ (FactoryDevfileV2Dto) gitSshFactoryParametersResolver.createFactory(params);
+ // then
+ ScmInfoDto scmInfo = factory.getScmInfo();
+ assertEquals(scmInfo.getScmProviderName(), "git-ssh");
+ assertEquals(scmInfo.getRepositoryUrl(), "repository-location");
+ }
+
+ @Test(
+ expectedExceptions = ApiException.class,
+ expectedExceptionsMessageRegExp = "Failed to fetch devfile")
+ public void shouldThrowException() throws Exception {
+ // given
+ String url = "git@provider.com:user/repo.git";
+ ImmutableMap params = ImmutableMap.of(URL_PARAMETER_NAME, url);
+ when(gitSshURLParser.parse(eq(url))).thenReturn(gitSshUrl);
+ when(urlFactoryBuilder.createFactoryFromDevfile(
+ eq(gitSshUrl), any(FileContentProvider.class), eq(Collections.emptyMap()), eq(true)))
+ .thenReturn(Optional.empty());
+ // when
+ FactoryDevfileV2Dto factory =
+ (FactoryDevfileV2Dto) gitSshFactoryParametersResolver.createFactory(params);
+ }
+
+ private FactoryDevfileV2Dto generateDevfileV2Factory() {
+ return newDto(FactoryDevfileV2Dto.class)
+ .withV(CURRENT_VERSION)
+ .withSource("repo")
+ .withDevfile(Map.of("schemaVersion", "2.0.0"));
+ }
+}
diff --git a/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrlTest.java b/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrlTest.java
new file mode 100644
index 00000000000..f997b7702dc
--- /dev/null
+++ b/wsmaster/che-core-api-factory-git-ssh/src/test/java/org/eclipse/che/api/factory/server/git/ssh/GitSshUrlTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012-2025 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/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.factory.server.git.ssh;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import org.eclipse.che.api.factory.server.urlfactory.RemoteFactoryUrl.DevfileLocation;
+import org.mockito.testng.MockitoTestNGListener;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+@Listeners(MockitoTestNGListener.class)
+public class GitSshUrlTest {
+
+ @Test
+ public void shouldReturnDevfileLocations() throws Exception {
+ String[] devfileNames = {"devfile.yaml", ".devfile.yaml"};
+ GitSshUrl sshUrl =
+ new GitSshUrl()
+ .withRepository("repository")
+ .withHostName("hostname")
+ .withDevfileFilenames(Arrays.asList(devfileNames));
+ List devfileLocations = sshUrl.devfileFileLocations();
+ assertEquals(devfileLocations.size(), 2);
+ assertEquals(devfileLocations.get(0).location(), "devfile.yaml");
+ assertEquals(devfileLocations.get(1).location(), ".devfile.yaml");
+ }
+}