Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
4e2da4d
add a whitelist for repo URI schemes to prevent abuse.
laurayco Jun 10, 2025
4468dca
config allowed URIs & update tests
laurayco Jun 23, 2025
220d95d
remove unneeded output
laurayco Jun 23, 2025
4f8a5df
Merge branch 'master' into repo-uri-filter
laurayco Jun 23, 2025
2495bcb
read fields into git client config
laurayco Jul 1, 2025
942856e
git url scheme whitelist in IT list.
laurayco Jul 1, 2025
4f5c049
add file:// prefix to path URI
laurayco Jul 1, 2025
7f28b39
change data type
laurayco Jul 1, 2025
50aec6a
Merge branch 'master' into repo-uri-filter
ibodrov Jul 4, 2025
f476188
Merge branch 'master' into repo-uri-filter
laurayco Jul 7, 2025
5976cc8
add URI to repo initialization
laurayco Jul 9, 2025
a5f67df
add URI to repo initialization
laurayco Jul 9, 2025
759f571
add URI to repo initialization
laurayco Jul 9, 2025
b9c34b2
add URI to repo initialization
laurayco Jul 9, 2025
d32edd5
Merge branch 'master' into repo-uri-filter
laurayco Jul 9, 2025
2c430ba
add URI to repo initialization
laurayco Jul 10, 2025
be086ab
add URI to repo initialization
laurayco Jul 11, 2025
d2c129e
add URI to repo initialization
laurayco Jul 15, 2025
84efa4e
add URI to repo initialization
laurayco Jul 15, 2025
15ab935
add URI to repo initialization. unfortunately if you add "file://" to…
laurayco Jul 15, 2025
0121bd1
not sure how this worked before to be entirely honest, this should fi…
laurayco Jul 22, 2025
8211f08
Merge branch 'master' into repo-uri-filter
laurayco Jul 22, 2025
9870bd0
remove dead code, fix typo
laurayco Jul 23, 2025
c1f5d89
undo change; return to correct test project
laurayco Jul 23, 2025
807817c
revert bad changes addressed by getRepoPath function updates.
laurayco Jul 23, 2025
93d21fb
remove dead code
laurayco Jul 23, 2025
c7a57ea
unholy abomination
laurayco Jul 24, 2025
d6676fd
add configurations for console ITs
laurayco Jul 24, 2025
60b6d8d
add configurations for console ITs. (using correct .conf files this t…
laurayco Jul 24, 2025
d9bd0ca
add configurations for process v1/v2 ITs. Don't know which config fil…
laurayco Jul 24, 2025
a01694f
add configurations for process v1/v2 ITs which use the docker images.
laurayco Jul 28, 2025
6c7b7c5
Merge branch 'master' into repo-uri-filter
laurayco Jul 28, 2025
7595dfa
add configurations for process v1/v2 ITs which use the docker images …
laurayco Jul 28, 2025
544a066
wrong config section
laurayco Aug 5, 2025
4d30b60
Merge branch 'master' into repo-uri-filter
laurayco Aug 5, 2025
8e59f9f
add URI to repo init
laurayco Aug 5, 2025
aec9918
Merge branch 'master' into repo-uri-filter
laurayco Aug 6, 2025
3f90d62
missing file
laurayco Aug 6, 2025
7c04a58
Merge branch 'master' into repo-uri-filter
laurayco Aug 7, 2025
aec2c04
Merge branch 'master' into repo-uri-filter
laurayco Aug 9, 2025
608bfdc
Merge branch 'master' into repo-uri-filter
laurayco Aug 11, 2025
153da56
support clone from github app
benbroadaway Aug 30, 2025
a517fea
server up
benbroadaway Sep 8, 2025
8faf526
server provider impl
benbroadaway Sep 9, 2025
f02613b
- adding token cache
dankle Sep 11, 2025
4cc3295
improving gitclient logic
dankle Sep 11, 2025
fea8621
Added agent token
dankle Sep 11, 2025
b10bbf7
- e2e gitauth working
dankle Sep 11, 2025
3f96121
Merge remote-tracking branch 'oss/master'
benbroadaway Sep 12, 2025
52e5888
cache tokens with eviction. improve error messages. fallback to git.o…
benbroadaway Sep 13, 2025
8578f24
fix obfuscation. use weight for cache instead of size
benbroadaway Sep 13, 2025
bcdbf11
fix ssh url handling
benbroadaway Sep 14, 2025
6ec6e09
support clone with secret-provided app info
benbroadaway Sep 14, 2025
708fd26
get token metrics. load pk data in app install object instead of path
benbroadaway Sep 14, 2025
be797dd
agent support for app secret. cache size metric.
benbroadaway Sep 14, 2025
c3d81d5
move dupliated handling to common.
benbroadaway Sep 15, 2025
fff08e8
rename canHandle to supports.
benbroadaway Sep 15, 2025
3ea9076
bump snapshot version
benbroadaway Sep 15, 2025
104c281
fix static token config loading
benbroadaway Sep 15, 2025
3404e00
remove duplication. rename api permission
benbroadaway Sep 16, 2025
4406426
version up
benbroadaway Sep 17, 2025
f521438
add addUserInfoToUri method to AuthTokenProvider, simplify GitClient.…
benbroadaway Sep 18, 2025
e9b4365
fix urlPattern impls. removed unused configs
benbroadaway Sep 18, 2025
2cd6493
fix git.systemAuth. add timeouts for gh calls. use max weight from co…
benbroadaway Sep 18, 2025
2f7c7ff
fix enum names. config defaults and comments
benbroadaway Sep 19, 2025
6e3c223
obfuscate user and token
benbroadaway Sep 19, 2025
77c9c75
snapshot version up
benbroadaway Sep 19, 2025
ebca144
fix regex matching for base url
benbroadaway Sep 19, 2025
6c98092
tests up. support query params in github app repo pattern
benbroadaway Sep 19, 2025
eaecaa0
Merge remote-tracking branch 'oss/master' into b2broad/git-app-clone
benbroadaway Sep 19, 2025
a007ee1
tests up
benbroadaway Sep 20, 2025
1391f5d
common tests up
benbroadaway Sep 20, 2025
af92f9a
allow file scheme in runtime-v2 docker tests
benbroadaway Sep 20, 2025
12faf65
don't override scheme config in dev container config
benbroadaway Sep 20, 2025
54629dd
github app unit tests
benbroadaway Sep 21, 2025
4156400
server and agent token providers tests
benbroadaway Sep 21, 2025
dbba08d
add SystemResourceIT
benbroadaway Sep 22, 2025
bff30fd
Merge remote-tracking branch 'oss/master'
benbroadaway Sep 22, 2025
028d0bb
fix module version
benbroadaway Sep 22, 2025
ff547ea
escape backslash in it agent config
benbroadaway Sep 22, 2025
c710eb1
create role first
benbroadaway Sep 22, 2025
f7dcaa0
less confusing name ExternalTokenAuth -> MappingAuthConfig
benbroadaway Sep 23, 2025
92442e4
Merge remote-tracking branch 'oss/master' into repo-uri-filter
benbroadaway Sep 24, 2025
16c97b5
don't serialize secondsUntilExpiration
benbroadaway Sep 24, 2025
fbaf6f4
comparable cache key
benbroadaway Oct 1, 2025
240e363
reuse HttpClient in token provider
benbroadaway Oct 1, 2025
95340b7
Merge remote-tracking branch 'oss/master'
benbroadaway Oct 15, 2025
f9be546
up
benbroadaway Oct 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions agent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
<groupId>com.walmartlabs.concord</groupId>
<artifactId>concord-common</artifactId>
</dependency>
<dependency>
<groupId>com.walmartlabs.concord</groupId>
<artifactId>concord-github-app-installation</artifactId>
</dependency>
<dependency>
<groupId>com.walmartlabs.concord</groupId>
<artifactId>concord-client2</artifactId>
Expand Down Expand Up @@ -143,6 +147,11 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<!-- dependency tree fix for mvnd -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package com.walmartlabs.concord.agent;

/*-
* *****
* Concord
* -----
* Copyright (C) 2017 - 2025 Walmart Inc.
* -----
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =====
*/

import com.typesafe.config.Config;
import com.walmartlabs.concord.agent.remote.ApiClientFactory;
import com.walmartlabs.concord.client2.ApiException;
import com.walmartlabs.concord.client2.SystemApi;
import com.walmartlabs.concord.common.AuthTokenProvider;
import com.walmartlabs.concord.common.ExternalAuthToken;
import com.walmartlabs.concord.common.cfg.MappingAuthConfig;
import com.walmartlabs.concord.github.appinstallation.GitHubAppInstallation;
import com.walmartlabs.concord.sdk.Secret;

import javax.annotation.Nullable;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Optional;

public class AgentAuthTokenProvider implements AuthTokenProvider {

private final List<AuthTokenProvider> authTokenProviders;

@Inject
public AgentAuthTokenProvider(ConcordServerTokenProvider concordProvider,
GitHubAppInstallation githubProvider,
AuthTokenProvider.OauthTokenProvider oauthTokenProvider) {

this.authTokenProviders = List.of(
concordProvider,
githubProvider,
oauthTokenProvider
);
}

@Override
public boolean supports(URI repo, @Nullable Secret secret) {
return authTokenProviders.stream()
.anyMatch(p -> p.supports(repo, secret));
}

public Optional<ExternalAuthToken> getToken(URI repo, @Nullable Secret secret) {
for (var k : authTokenProviders) {
if (k.supports(repo, secret)) {
return k.getToken(repo, secret);
}
}

return Optional.empty();
}

public static class ConcordServerTokenProvider implements AuthTokenProvider {

private static final String CFG_ENABLED = "externalTokenProvider.enabled";
private static final String CFG_URL_PATTERN = "externalTokenProvider.urlPattern";

private final SystemApi systemApi;
private final MappingAuthConfig.ConcordServerAuthConfig auth;

@Inject
public ConcordServerTokenProvider(ApiClientFactory apiClientFactory, Config config) {
this.auth = initAuth(config);

try {
this.systemApi = new SystemApi(apiClientFactory.create(null));
} catch (IOException e) {
throw new RuntimeException("Error initializing System API client", e);
}
}

private static MappingAuthConfig.ConcordServerAuthConfig initAuth(Config config) {
if (!config.hasPath(CFG_ENABLED) || !config.getBoolean(CFG_ENABLED)) {
return null;
}

return config.hasPath(CFG_URL_PATTERN)
? MappingAuthConfig.ConcordServerAuthConfig.builder()
.urlPattern(MappingAuthConfig.assertBaseUrlPattern(config.getString(CFG_URL_PATTERN)))
.build()
: null;
}

@Override
public boolean supports(URI repo, @Nullable Secret secret) {
if (auth == null) {
return false;
}

// Maybe support secret input? This requires elevated api access permission

return auth.canHandle(repo);
}

@Override
public Optional<ExternalAuthToken> getToken(URI repo, @Nullable Secret secret) {
try {
var resp = systemApi.getExternalToken(repo);

return Optional.of(ExternalAuthToken.StaticToken.builder()
.token(resp.getToken())
.username(resp.getUsername())
.expiresAt(resp.getExpiresAt())
.build());
} catch (ApiException e) {
if (e.getCode() == 403) {
// User needs externalTokenLookup permission
throw new RuntimeException("No permission to get auth token from concord server.");
}

throw new RuntimeException("Error retrieving concord-provided auth token", e);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import com.walmartlabs.concord.agent.remote.ApiClientFactory;
import com.walmartlabs.concord.agent.remote.QueueClientProvider;
import com.walmartlabs.concord.common.ObjectMapperProvider;
import com.walmartlabs.concord.common.cfg.OauthTokenConfig;
import com.walmartlabs.concord.config.ConfigModule;
import com.walmartlabs.concord.github.appinstallation.cfg.GitHubAppInstallationConfig;
import com.walmartlabs.concord.server.queueclient.QueueClient;

import javax.inject.Named;
Expand Down Expand Up @@ -59,6 +61,10 @@ public void configure(Binder binder) {
binder.bind(DockerConfiguration.class).in(SINGLETON);
binder.bind(RuntimeConfiguration.class).asEagerSingleton();
binder.bind(GitConfiguration.class).in(SINGLETON);
binder.bind(OauthTokenConfig.class).to(GitConfiguration.class).in(SINGLETON);
binder.bind(GitHubConfiguration.class).in(SINGLETON);
binder.bind(GitHubAppInstallationConfig.class).to(GitHubConfiguration.class).in(SINGLETON);
binder.bind(AgentAuthTokenProvider.ConcordServerTokenProvider.class).in(SINGLETON);
binder.bind(ImportConfiguration.class).in(SINGLETON);
binder.bind(PreForkConfiguration.class).in(SINGLETON);
binder.bind(RepositoryCacheConfiguration.class).in(SINGLETON);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import javax.inject.Inject;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;

public class RepositoryManager {
Expand All @@ -46,29 +45,33 @@ public class RepositoryManager {
private final RepositoryCache repositoryCache;
private final GitConfiguration gitCfg;


@Inject
public RepositoryManager(SecretClient secretClient,
GitConfiguration gitCfg,
RepositoryCacheConfiguration cacheCfg,
ObjectMapper objectMapper,
DependencyManager dependencyManager) throws IOException {
DependencyManager dependencyManager,
AgentAuthTokenProvider agentAuthTokenProvider) throws IOException {

this.secretClient = secretClient;
this.gitCfg = gitCfg;

GitClientConfiguration clientCfg = GitClientConfiguration.builder()
.oauthToken(gitCfg.getToken())
.oauthToken(gitCfg.getOauthToken())
.defaultOperationTimeout(gitCfg.getDefaultOperationTimeout())
.fetchTimeout(gitCfg.getFetchTimeout())
.httpLowSpeedLimit(gitCfg.getHttpLowSpeedLimit())
.httpLowSpeedTime(gitCfg.getHttpLowSpeedTime())
.allowedSchemes(gitCfg.getAllowedSchemes())
.sshTimeout(gitCfg.getSshTimeout())
.sshTimeoutRetryCount(gitCfg.getSshTimeoutRetryCount())
.build();

List<RepositoryProvider> providers = Arrays.asList(new MavenRepositoryProvider(dependencyManager), new GitCliRepositoryProvider(clientCfg));
this.providers = new RepositoryProviders(providers);

this.providers = new RepositoryProviders(List.of(
new MavenRepositoryProvider(dependencyManager),
new GitCliRepositoryProvider(clientCfg, agentAuthTokenProvider)
));
this.repositoryCache = new RepositoryCache(cacheCfg.getCacheDir(),
cacheCfg.getInfoDir(),
cacheCfg.getLockTimeout(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,21 @@
*/

import com.typesafe.config.Config;
import com.walmartlabs.concord.common.cfg.MappingAuthConfig;
import com.walmartlabs.concord.common.cfg.OauthTokenConfig;

import javax.inject.Inject;
import java.time.Duration;
import java.util.List;
import java.util.Optional;

import static com.walmartlabs.concord.agent.cfg.Utils.getStringOrDefault;

public class GitConfiguration {
public class GitConfiguration implements OauthTokenConfig {

private final String token;
private final String oauthUsername;
private final String oauthUrlPattern;
private final boolean shallowClone;
private final boolean checkAlreadyFetched;
private final Duration defaultOperationTimeout;
Expand All @@ -39,10 +45,14 @@ public class GitConfiguration {
private final Duration sshTimeout;
private final int sshTimeoutRetryCount;
private final boolean skip;
private final List<String> allowedSchemes;
private final List<? extends Config> authConfigs;

@Inject
public GitConfiguration(Config cfg) {
this.token = getStringOrDefault(cfg, "git.oauth", () -> null);
this.oauthUsername = getStringOrDefault(cfg, "git.oauthUsername", () -> null);
this.oauthUrlPattern = getStringOrDefault(cfg, "git.oauthUrlPattern", () -> null);
this.shallowClone = cfg.getBoolean("git.shallowClone");
this.checkAlreadyFetched = cfg.getBoolean("git.checkAlreadyFetched");
this.defaultOperationTimeout = cfg.getDuration("git.defaultOperationTimeout");
Expand All @@ -52,10 +62,23 @@ public GitConfiguration(Config cfg) {
this.sshTimeout = cfg.getDuration("git.sshTimeout");
this.sshTimeoutRetryCount = cfg.getInt("git.sshTimeoutRetryCount");
this.skip = cfg.getBoolean("git.skip");
this.allowedSchemes = cfg.getStringList("git.allowedSchemes");
this.authConfigs = cfg.getConfigList("git.systemAuth");
}

public String getToken() {
return token;
@Override
public Optional<String> getOauthToken() {
return Optional.ofNullable(token);
}

@Override
public Optional<String> getOauthUsername() {
return Optional.ofNullable(oauthUsername);
}

@Override
public Optional<String> getOauthUrlPattern() {
return Optional.ofNullable(oauthUrlPattern);
}

public boolean isShallowClone() {
Expand Down Expand Up @@ -93,4 +116,47 @@ public int getSshTimeoutRetryCount() {
public boolean isSkip() {
return skip;
}

public List<String> getAllowedSchemes() { return allowedSchemes; }

public List<MappingAuthConfig> getSystemAuth() {
return authConfigs.stream()
.map(o -> {
AuthSource type = AuthSource.valueOf(o.getString("type").toUpperCase());

return (AuthConfig) switch (type) {
case OAUTH_TOKEN -> OauthConfig.from(o);
};
})
.map(AuthConfig::toGitAuth)
.toList();

}

enum AuthSource {
OAUTH_TOKEN
}

public interface AuthConfig {
MappingAuthConfig toGitAuth();
}

public record OauthConfig(String urlPattern, String token) implements AuthConfig {

static OauthConfig from(Config cfg) {
return new OauthConfig(
cfg.getString("urlPattern"),
cfg.getString("token")
);
}

@Override
public MappingAuthConfig.OauthAuthConfig toGitAuth() {
return MappingAuthConfig.OauthAuthConfig.builder()
.urlPattern(MappingAuthConfig.assertBaseUrlPattern(this.urlPattern()))
.token(this.token())
.build();
}
}

}
Loading
Loading