From 0cf815a3bea63de672100283a15503a5dc0859d5 Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Tue, 5 Aug 2025 20:17:52 +0200 Subject: [PATCH 1/2] Do not follow symlinks by default when building repository index (cherry picked from commit 21661c26cd50e8b02bb1dc296ef0efdfe5b0260c) --- .../source/index/RepoIndexBuilder.java | 17 +++-------------- .../trace/api/config/CiVisibilityConfig.java | 2 ++ .../src/main/java/datadog/trace/api/Config.java | 8 ++++++++ 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java index 805cb4e56c1..1028d55f777 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java @@ -104,6 +104,7 @@ private static final class RepoIndexingFileVisitor implements FileVisitor private final RepoIndexingStats indexingStats; private final Path repoRoot; private final AtomicInteger sourceRootCounter; + private final boolean followSymlinks; private RepoIndexingFileVisitor( Config config, @@ -120,29 +121,17 @@ private RepoIndexingFileVisitor( packageTree = new PackageTree(config); indexingStats = new RepoIndexingStats(); sourceRootCounter = new AtomicInteger(); + followSymlinks = config.isCiVisibilityRepoIndexFollowSymlinks(); } @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - if (Files.isSymbolicLink(dir) && readSymbolicLink(dir).startsWith(repoRoot)) { - // The path is a symlink that points inside the repo. - // We'll visit the folder that it points to anyway, - // moreover, we don't want two different results for one file - // (one containing the symlink, the other - the actual folder). + if (Files.isSymbolicLink(dir) && !followSymlinks) { return FileVisitResult.SKIP_SUBTREE; } return FileVisitResult.CONTINUE; } - private static Path readSymbolicLink(Path path) { - try { - return Files.readSymbolicLink(path); - } catch (Exception e) { - log.debug("Could not read symbolic link {}", path, e); - return path; - } - } - @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { indexingStats.filesVisited++; diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java index ad93aa9dfc7..e39832f1432 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/CiVisibilityConfig.java @@ -44,6 +44,8 @@ public final class CiVisibilityConfig { "civisibility.ciprovider.integration.enabled"; public static final String CIVISIBILITY_REPO_INDEX_DUPLICATE_KEY_CHECK_ENABLED = "civisibility.repo.index.duplicate.key.check.enabled"; + public static final String CIVISIBILITY_REPO_INDEX_FOLLOW_SYMLINKS = + "civisibility.repo.index.follow.symlinks"; public static final String CIVISIBILITY_EXECUTION_SETTINGS_CACHE_SIZE = "civisibility.execution.settings.cache.size"; public static final String CIVISIBILITY_JVM_INFO_CACHE_SIZE = "civisibility.jvm.info.cache.size"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index 5ff002d4144..1d257c56542 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -254,6 +254,7 @@ import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_REMOTE_ENV_VARS_PROVIDER_KEY; import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_REMOTE_ENV_VARS_PROVIDER_URL; import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_REPO_INDEX_DUPLICATE_KEY_CHECK_ENABLED; +import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_REPO_INDEX_FOLLOW_SYMLINKS; import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_RESOURCE_FOLDER_NAMES; import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS; import static datadog.trace.api.config.CiVisibilityConfig.CIVISIBILITY_SCALATEST_FORK_MONITOR_ENABLED; @@ -1001,6 +1002,7 @@ public static String getHostName() { private final boolean ciVisibilityTestSkippingEnabled; private final boolean ciVisibilityCiProviderIntegrationEnabled; private final boolean ciVisibilityRepoIndexDuplicateKeyCheckEnabled; + private final boolean ciVisibilityRepoIndexFollowSymlinks; private final int ciVisibilityExecutionSettingsCacheSize; private final int ciVisibilityJvmInfoCacheSize; private final int ciVisibilityCoverageRootPackagesLimit; @@ -2261,6 +2263,8 @@ PROFILING_DATADOG_PROFILER_ENABLED, isDatadogProfilerSafeInCurrentEnvironment()) configProvider.getBoolean(CIVISIBILITY_CIPROVIDER_INTEGRATION_ENABLED, true); ciVisibilityRepoIndexDuplicateKeyCheckEnabled = configProvider.getBoolean(CIVISIBILITY_REPO_INDEX_DUPLICATE_KEY_CHECK_ENABLED, true); + ciVisibilityRepoIndexFollowSymlinks = + configProvider.getBoolean(CIVISIBILITY_REPO_INDEX_FOLLOW_SYMLINKS, false); ciVisibilityExecutionSettingsCacheSize = configProvider.getInteger(CIVISIBILITY_EXECUTION_SETTINGS_CACHE_SIZE, 16); ciVisibilityJvmInfoCacheSize = configProvider.getInteger(CIVISIBILITY_JVM_INFO_CACHE_SIZE, 8); @@ -3822,6 +3826,10 @@ public boolean isCiVisibilityRepoIndexDuplicateKeyCheckEnabled() { return ciVisibilityRepoIndexDuplicateKeyCheckEnabled; } + public boolean isCiVisibilityRepoIndexFollowSymlinks() { + return ciVisibilityRepoIndexFollowSymlinks; + } + public int getCiVisibilityExecutionSettingsCacheSize() { return ciVisibilityExecutionSettingsCacheSize; } From 56f32103b262b49d768b8678bf6c1677b193442b Mon Sep 17 00:00:00 2001 From: Nikita Tkachenko Date: Wed, 6 Aug 2025 11:11:48 +0200 Subject: [PATCH 2/2] Restore the check to avoid following symlinks that point inside the repo (cherry picked from commit c427509dfc41c5a04b7e24ecf52e04a9116d90bc) --- .../source/index/RepoIndexBuilder.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java index 1028d55f777..23b93ec5580 100644 --- a/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java +++ b/dd-java-agent/agent-ci-visibility/src/main/java/datadog/trace/civisibility/source/index/RepoIndexBuilder.java @@ -126,12 +126,31 @@ private RepoIndexingFileVisitor( @Override public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - if (Files.isSymbolicLink(dir) && !followSymlinks) { - return FileVisitResult.SKIP_SUBTREE; + if (Files.isSymbolicLink(dir)) { + if (!followSymlinks) { + // Configured to skip symlinks + return FileVisitResult.SKIP_SUBTREE; + } + if (readSymbolicLink(dir).startsWith(repoRoot)) { + // The path is a symlink that points inside the repo. + // We'll visit the folder that it points to anyway, + // moreover, we don't want two different results for one file + // (one containing the symlink, the other - the actual folder). + return FileVisitResult.SKIP_SUBTREE; + } } return FileVisitResult.CONTINUE; } + private static Path readSymbolicLink(Path path) { + try { + return Files.readSymbolicLink(path); + } catch (Exception e) { + log.debug("Could not read symbolic link {}", path, e); + return path; + } + } + @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { indexingStats.filesVisited++;