Skip to content

Commit 79eab54

Browse files
authored
Development: Cleanup GitService (#11396)
1 parent 7c932aa commit 79eab54

File tree

6 files changed

+149
-269
lines changed

6 files changed

+149
-269
lines changed

src/main/java/de/tum/cit/aet/artemis/buildagent/service/BuildJobGitService.java

Lines changed: 135 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
import java.net.URISyntaxException;
88
import java.nio.file.InvalidPathException;
99
import java.nio.file.Path;
10+
import java.util.Collections;
11+
import java.util.List;
12+
import java.util.Map;
13+
import java.util.Optional;
1014

1115
import jakarta.annotation.Nullable;
1216
import jakarta.annotation.PostConstruct;
@@ -17,11 +21,22 @@
1721
import org.eclipse.jgit.api.CloneCommand;
1822
import org.eclipse.jgit.api.Git;
1923
import org.eclipse.jgit.api.GitCommand;
24+
import org.eclipse.jgit.api.LsRemoteCommand;
2025
import org.eclipse.jgit.api.TransportCommand;
26+
import org.eclipse.jgit.api.TransportConfigCallback;
2127
import org.eclipse.jgit.api.errors.GitAPIException;
2228
import org.eclipse.jgit.api.errors.InvalidRefNameException;
29+
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
30+
import org.eclipse.jgit.transport.CredentialItem;
2331
import org.eclipse.jgit.transport.CredentialsProvider;
32+
import org.eclipse.jgit.transport.SshConfigStore;
33+
import org.eclipse.jgit.transport.SshConstants;
34+
import org.eclipse.jgit.transport.SshTransport;
35+
import org.eclipse.jgit.transport.URIish;
2436
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
37+
import org.eclipse.jgit.transport.sshd.JGitKeyCache;
38+
import org.eclipse.jgit.transport.sshd.SshdSessionFactory;
39+
import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder;
2540
import org.slf4j.Logger;
2641
import org.slf4j.LoggerFactory;
2742
import org.springframework.beans.factory.annotation.Value;
@@ -50,21 +65,19 @@ public class BuildJobGitService extends AbstractGitService {
5065
@Value("${artemis.version-control.build-agent-use-ssh:false}")
5166
private boolean useSshForBuildAgent;
5267

68+
@Value("${artemis.version-control.ssh-private-key-folder-path:#{null}}")
69+
private Optional<String> gitSshPrivateKeyPath;
70+
71+
@Value("${artemis.version-control.ssh-template-clone-url:#{null}}")
72+
private Optional<String> sshUrlTemplate;
73+
5374
private CredentialsProvider credentialsProvider;
5475

55-
/**
56-
* Determines whether to use SSH.
57-
* <p>
58-
* This method overrides the default behavior of {@code AbstractGitService} and returns the configuration flag
59-
* {@code useSshForBuildAgent} to indicate if SSH should be used.
60-
* </p>
61-
*
62-
* @return {@code true} if SSH should be used; {@code false} otherwise.
63-
*/
64-
@Override
65-
protected boolean useSsh() {
66-
return useSshForBuildAgent;
67-
}
76+
private JGitKeyCache jgitKeyCache;
77+
78+
protected TransportConfigCallback sshCallback;
79+
80+
private SshdSessionFactory sshdSessionFactory;
6881

6982
/**
7083
* initialize the BuildJobGitService, in particular which authentication mechanism should be used
@@ -89,10 +102,108 @@ public void init() {
89102
}
90103
}
91104

105+
protected boolean useSsh() {
106+
return useSshForBuildAgent;
107+
}
108+
109+
/**
110+
* Configures the SSH settings for the JGit SSH session factory.
111+
*/
112+
protected void configureSsh() {
113+
CredentialsProvider.setDefault(new CustomCredentialsProvider());
114+
final var sshSessionFactoryBuilder = getSshdSessionFactoryBuilder(gitSshPrivateKeyPath, localVCBaseUri);
115+
jgitKeyCache = new JGitKeyCache();
116+
sshdSessionFactory = sshSessionFactoryBuilder.build(jgitKeyCache);
117+
sshCallback = transport -> {
118+
if (transport instanceof SshTransport sshTransport) {
119+
transport.setTimeout(JGIT_TIMEOUT_IN_SECONDS);
120+
sshTransport.setSshSessionFactory(sshdSessionFactory);
121+
}
122+
else {
123+
log.error("Cannot use ssh properly because of mismatch of Jgit transport object: {}", transport);
124+
}
125+
};
126+
}
127+
128+
protected static SshdSessionFactoryBuilder getSshdSessionFactoryBuilder(Optional<String> gitSshPrivateKeyPath, URI gitUri) {
129+
// @formatter:off
130+
return new SshdSessionFactoryBuilder()
131+
.setConfigStoreFactory((homeDir, configFile, localUserName) -> new CustomSshConfigStore(gitUri))
132+
.setSshDirectory(Path.of(gitSshPrivateKeyPath.orElseThrow()).toFile())
133+
.setHomeDirectory(Path.of(System.getProperty("user.home")).toFile());
134+
// @formatter:on
135+
}
136+
92137
@PreDestroy
93-
@Override
94138
public void cleanup() {
95-
super.cleanup();
139+
if (useSsh()) {
140+
jgitKeyCache.close();
141+
sshdSessionFactory.close();
142+
}
143+
}
144+
145+
static class CustomCredentialsProvider extends CredentialsProvider {
146+
147+
@Override
148+
public boolean isInteractive() {
149+
return false;
150+
}
151+
152+
@Override
153+
public boolean supports(CredentialItem... items) {
154+
return true;
155+
}
156+
157+
// Note: the following method allows us to store known hosts
158+
@Override
159+
public boolean get(URIish uri, CredentialItem... items) throws UnsupportedCredentialItem {
160+
for (CredentialItem item : items) {
161+
if (item instanceof CredentialItem.YesNoType yesNoItem) {
162+
yesNoItem.setValue(true);
163+
}
164+
}
165+
return true;
166+
}
167+
}
168+
169+
record CustomSshConfigStore(URI gitUri) implements SshConfigStore {
170+
171+
@Override
172+
public HostConfig lookup(String hostName, int port, String userName) {
173+
return new HostConfig() {
174+
175+
@Override
176+
public String getValue(String key) {
177+
return null;
178+
}
179+
180+
@Override
181+
public List<String> getValues(String key) {
182+
return Collections.emptyList();
183+
}
184+
185+
@Override
186+
public Map<String, String> getOptions() {
187+
log.debug("getOptions: {}:{}", hostName, port);
188+
if (hostName.equals(gitUri.getHost())) {
189+
return Collections.singletonMap(SshConstants.STRICT_HOST_KEY_CHECKING, SshConstants.NO);
190+
}
191+
else {
192+
return Collections.emptyMap();
193+
}
194+
}
195+
196+
@Override
197+
public Map<String, List<String>> getMultiValuedOptions() {
198+
return Collections.emptyMap();
199+
}
200+
};
201+
}
202+
203+
@Override
204+
public HostConfig lookupDefault(String hostName, int port, String userName) {
205+
return lookup(hostName, port, userName);
206+
}
96207
}
97208

98209
/**
@@ -183,4 +294,13 @@ private CredentialsProvider getCachedCredentialsProvider() {
183294
}
184295
return credentialsProvider;
185296
}
297+
298+
@Override
299+
protected LsRemoteCommand lsRemoteCommand() {
300+
return authenticate(Git.lsRemoteRepository());
301+
}
302+
303+
private CloneCommand cloneCommand() {
304+
return authenticate(Git.cloneRepository());
305+
}
186306
}

0 commit comments

Comments
 (0)