Check whether the remote cache accepts absolute symlinks before uploading them.
Closes #16354.
PiperOrigin-RevId: 477812051
Change-Id: I12419094b2e9fab1d4d66c5f94f331ebaaf20695
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteCache.java
index 1fc369b..60ebc08 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteCache.java
@@ -20,6 +20,7 @@
import static com.google.devtools.build.lib.remote.util.Utils.getFromFuture;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
@@ -83,17 +84,26 @@
private final CountDownLatch closeCountDownLatch = new CountDownLatch(1);
protected final AsyncTaskCache.NoResult<Digest> casUploadCache = AsyncTaskCache.NoResult.create();
+ protected final CacheCapabilities cacheCapabilities;
protected final RemoteCacheClient cacheProtocol;
protected final RemoteOptions options;
protected final DigestUtil digestUtil;
public RemoteCache(
- RemoteCacheClient cacheProtocol, RemoteOptions options, DigestUtil digestUtil) {
+ CacheCapabilities cacheCapabilities,
+ RemoteCacheClient cacheProtocol,
+ RemoteOptions options,
+ DigestUtil digestUtil) {
+ this.cacheCapabilities = cacheCapabilities;
this.cacheProtocol = cacheProtocol;
this.options = options;
this.digestUtil = digestUtil;
}
+ public CacheCapabilities getCacheCapabilities() {
+ return cacheCapabilities;
+ }
+
public CachedActionResult downloadActionResult(
RemoteActionExecutionContext context, ActionKey actionKey, boolean inlineOutErr)
throws IOException, InterruptedException {
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
index 2414c9f..421313e 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
@@ -23,6 +23,7 @@
import static com.google.devtools.build.lib.remote.util.RxUtils.toTransferResult;
import static java.lang.String.format;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
import com.google.common.base.Throwables;
@@ -59,10 +60,11 @@
public class RemoteExecutionCache extends RemoteCache {
public RemoteExecutionCache(
+ CacheCapabilities cacheCapabilities,
RemoteCacheClient protocolImpl,
RemoteOptions options,
DigestUtil digestUtil) {
- super(protocolImpl, options, digestUtil);
+ super(cacheCapabilities, protocolImpl, options, digestUtil);
}
/**
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
index 154d139..ef33003 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionService.java
@@ -1270,6 +1270,7 @@
return UploadManifest.create(
remoteOptions,
+ remoteCache.getCacheCapabilities(),
digestUtil,
remotePathResolver,
action.getActionKey(),
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
index 3d792d0..0c96be6 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java
@@ -16,8 +16,10 @@
import static java.util.concurrent.TimeUnit.SECONDS;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.DigestFunction;
import build.bazel.remote.execution.v2.ServerCapabilities;
+import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy;
import com.google.auth.Credentials;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
@@ -125,6 +127,11 @@
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
+ private static final CacheCapabilities DISK_CACHE_CAPABILITIES =
+ CacheCapabilities.newBuilder()
+ .setSymlinkAbsolutePathStrategy(SymlinkAbsolutePathStrategy.Value.ALLOWED)
+ .build();
+
private final ListeningScheduledExecutorService retryScheduler =
MoreExecutors.listeningDecorator(Executors.newScheduledThreadPool(1));
@@ -181,7 +188,7 @@
return !Strings.isNullOrEmpty(options.remoteDownloader);
}
- private static void verifyServerCapabilities(
+ private static ServerCapabilities getAndVerifyServerCapabilities(
RemoteOptions remoteOptions,
ReferenceCountedChannel channel,
CallCredentials credentials,
@@ -202,7 +209,7 @@
capabilities = rsc.get(env.getBuildRequestId(), env.getCommandId().toString());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- return;
+ return null;
}
checkClientServerCompatibility(
capabilities,
@@ -210,6 +217,7 @@
digestUtil.getDigestFunction(),
env.getReporter(),
requirement);
+ return capabilities;
}
private void initHttpAndDiskCache(
@@ -248,7 +256,8 @@
handleInitFailure(env, e, Code.CACHE_INIT_FAILURE);
return;
}
- RemoteCache remoteCache = new RemoteCache(cacheClient, remoteOptions, digestUtil);
+ RemoteCache remoteCache =
+ new RemoteCache(DISK_CACHE_CAPABILITIES, cacheClient, remoteOptions, digestUtil);
actionContextProvider =
RemoteActionContextProvider.createForRemoteCaching(
executorService, env, remoteCache, /* retryScheduler= */ null, digestUtil);
@@ -483,44 +492,51 @@
//
// If they point to different endpoints, we check the endpoint with execution or cache
// capabilities respectively.
+ ServerCapabilities execCapabilities = null;
+ ServerCapabilities cacheCapabilities = null;
try {
if (execChannel != null) {
if (cacheChannel != execChannel) {
- verifyServerCapabilities(
- remoteOptions,
- execChannel,
- credentials,
- retrier,
- env,
- digestUtil,
- ServerCapabilitiesRequirement.EXECUTION);
- verifyServerCapabilities(
- remoteOptions,
- cacheChannel,
- credentials,
- retrier,
- env,
- digestUtil,
- ServerCapabilitiesRequirement.CACHE);
+ execCapabilities =
+ getAndVerifyServerCapabilities(
+ remoteOptions,
+ execChannel,
+ credentials,
+ retrier,
+ env,
+ digestUtil,
+ ServerCapabilitiesRequirement.EXECUTION);
+ cacheCapabilities =
+ getAndVerifyServerCapabilities(
+ remoteOptions,
+ cacheChannel,
+ credentials,
+ retrier,
+ env,
+ digestUtil,
+ ServerCapabilitiesRequirement.CACHE);
} else {
- verifyServerCapabilities(
- remoteOptions,
- execChannel,
- credentials,
- retrier,
- env,
- digestUtil,
- ServerCapabilitiesRequirement.EXECUTION_AND_CACHE);
+ execCapabilities =
+ cacheCapabilities =
+ getAndVerifyServerCapabilities(
+ remoteOptions,
+ execChannel,
+ credentials,
+ retrier,
+ env,
+ digestUtil,
+ ServerCapabilitiesRequirement.EXECUTION_AND_CACHE);
}
} else {
- verifyServerCapabilities(
- remoteOptions,
- cacheChannel,
- credentials,
- retrier,
- env,
- digestUtil,
- ServerCapabilitiesRequirement.CACHE);
+ cacheCapabilities =
+ getAndVerifyServerCapabilities(
+ remoteOptions,
+ cacheChannel,
+ credentials,
+ retrier,
+ env,
+ digestUtil,
+ ServerCapabilitiesRequirement.CACHE);
}
} catch (IOException e) {
String errorMessage =
@@ -602,7 +618,8 @@
}
execChannel.release();
RemoteExecutionCache remoteCache =
- new RemoteExecutionCache(cacheClient, remoteOptions, digestUtil);
+ new RemoteExecutionCache(
+ cacheCapabilities.getCacheCapabilities(), cacheClient, remoteOptions, digestUtil);
actionContextProvider =
RemoteActionContextProvider.createForRemoteExecution(
executorService,
@@ -637,7 +654,9 @@
}
}
- RemoteCache remoteCache = new RemoteCache(cacheClient, remoteOptions, digestUtil);
+ RemoteCache remoteCache =
+ new RemoteCache(
+ cacheCapabilities.getCacheCapabilities(), cacheClient, remoteOptions, digestUtil);
actionContextProvider =
RemoteActionContextProvider.createForRemoteCaching(
executorService, env, remoteCache, retryScheduler, digestUtil);
diff --git a/src/main/java/com/google/devtools/build/lib/remote/UploadManifest.java b/src/main/java/com/google/devtools/build/lib/remote/UploadManifest.java
index a7fc6ed..b75c897 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/UploadManifest.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/UploadManifest.java
@@ -22,9 +22,11 @@
import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
+import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy;
import build.bazel.remote.execution.v2.Tree;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
@@ -77,6 +79,7 @@
private final ActionResult.Builder result;
private final boolean followSymlinks;
private final boolean allowDanglingSymlinks;
+ private final boolean allowAbsoluteSymlinks;
private final Map<Digest, Path> digestToFile = new HashMap<>();
private final Map<Digest, ByteString> digestToBlobs = new HashMap<>();
@Nullable private ActionKey actionKey;
@@ -85,6 +88,7 @@
public static UploadManifest create(
RemoteOptions remoteOptions,
+ CacheCapabilities cacheCapabilities,
DigestUtil digestUtil,
RemotePathResolver remotePathResolver,
ActionKey actionKey,
@@ -105,7 +109,10 @@
remotePathResolver,
result,
/* followSymlinks= */ !remoteOptions.incompatibleRemoteSymlinks,
- /* allowDanglingSymlinks= */ remoteOptions.incompatibleRemoteDanglingSymlinks);
+ /* allowDanglingSymlinks= */ remoteOptions.incompatibleRemoteDanglingSymlinks,
+ /* allowAbsoluteSymlinks= */ cacheCapabilities
+ .getSymlinkAbsolutePathStrategy()
+ .equals(SymlinkAbsolutePathStrategy.Value.ALLOWED));
manifest.addFiles(outputFiles);
manifest.setStdoutStderr(outErr);
manifest.addAction(actionKey, action, command);
@@ -143,12 +150,14 @@
RemotePathResolver remotePathResolver,
ActionResult.Builder result,
boolean followSymlinks,
- boolean allowDanglingSymlinks) {
+ boolean allowDanglingSymlinks,
+ boolean allowAbsoluteSymlinks) {
this.digestUtil = digestUtil;
this.remotePathResolver = remotePathResolver;
this.result = result;
this.followSymlinks = followSymlinks;
this.allowDanglingSymlinks = allowDanglingSymlinks;
+ this.allowAbsoluteSymlinks = allowAbsoluteSymlinks;
}
private void setStdoutStderr(FileOutErr outErr) throws IOException {
@@ -191,13 +200,19 @@
FileStatus statFollow = file.statIfFound(Symlinks.FOLLOW);
if (statFollow == null) {
if (allowDanglingSymlinks) {
+ if (target.isAbsolute() && !allowAbsoluteSymlinks) {
+ throw new IOException(
+ String.format(
+ "Action output %s is an absolute symbolic link to %s, which is not allowed by"
+ + " the remote cache",
+ file, target));
+ }
// Report symlink to a file since we don't know any better.
- // TODO(tjgq): Check for the SymlinkAbsolutePathStrategy.ALLOW server capability before
- // uploading an absolute symlink.
addFileSymbolicLink(file, target);
} else {
throw new IOException(
- String.format("Action output %s is a dangling symbolic link to %s ", file, target));
+ String.format(
+ "Action output %s is a dangling symbolic link to %s. ", file, target));
}
} else if (statFollow.isSpecialFile()) {
illegalOutput(file);
diff --git a/src/test/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploaderTest.java b/src/test/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploaderTest.java
index 5cc44a9..42602fa 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploaderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/ByteStreamBuildEventArtifactUploaderTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import com.google.bytestream.ByteStreamProto.WriteRequest;
import com.google.bytestream.ByteStreamProto.WriteResponse;
@@ -469,7 +470,8 @@
.when(cacheClient)
.findMissingDigests(any(), any());
- return new RemoteCache(cacheClient, remoteOptions, DIGEST_UTIL);
+ return new RemoteCache(
+ CacheCapabilities.getDefaultInstance(), cacheClient, remoteOptions, DIGEST_UTIL);
}
private ByteStreamBuildEventArtifactUploader newArtifactUploader(RemoteCache remoteCache) {
diff --git a/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java b/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
index a876bc4..c11f2e2 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/FakeActionInputFileCache.java
@@ -27,6 +27,7 @@
import com.google.devtools.build.lib.vfs.FileStatus;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
+import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Symlinks;
import com.google.devtools.build.lib.vfs.SyscallCache;
import java.io.IOException;
@@ -77,4 +78,13 @@
setDigest(input, digest.getHash());
return digest;
}
+
+ public Digest createScratchInputSymlink(ActionInput input, String target) throws IOException {
+ Path inputFile = execRoot.getRelative(input.getExecPath());
+ inputFile.getParentDirectory().createDirectoryAndParents();
+ inputFile.createSymbolicLink(PathFragment.create(target));
+ Digest digest = digestUtil.compute(inputFile);
+ setDigest(input, digest.getHash());
+ return digest;
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/GrpcCacheClientTest.java b/src/test/java/com/google/devtools/build/lib/remote/GrpcCacheClientTest.java
index 5bb3122..4df12d4 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/GrpcCacheClientTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/GrpcCacheClientTest.java
@@ -26,6 +26,7 @@
import build.bazel.remote.execution.v2.Action;
import build.bazel.remote.execution.v2.ActionCacheGrpc.ActionCacheImplBase;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageImplBase;
import build.bazel.remote.execution.v2.Digest;
@@ -98,7 +99,8 @@
public void testVirtualActionInputSupport() throws Exception {
RemoteOptions options = Options.getDefaults(RemoteOptions.class);
RemoteExecutionCache client =
- new RemoteExecutionCache(newClient(options), options, DIGEST_UTIL);
+ new RemoteExecutionCache(
+ CacheCapabilities.getDefaultInstance(), newClient(options), options, DIGEST_UTIL);
PathFragment execPath = PathFragment.create("my/exec/path");
VirtualActionInput virtualActionInput =
ActionsTestUtil.createVirtualActionInput(execPath, "hello");
@@ -286,7 +288,8 @@
// arrange
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
Digest fooDigest = DIGEST_UTIL.computeAsUtf8("foo-contents");
Digest barDigest = DIGEST_UTIL.computeAsUtf8("bar-contents");
@@ -309,7 +312,8 @@
public void testUploadDirectory() throws Exception {
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest fooDigest =
fakeFileCache.createScratchInput(ActionInputHelper.fromPath("a/foo"), "xyz");
@@ -373,7 +377,8 @@
public void testUploadDirectoryEmpty() throws Exception {
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest barDigest =
fakeFileCache.createScratchInputDirectory(
@@ -412,7 +417,8 @@
public void testUploadDirectoryNested() throws Exception {
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest wobbleDigest =
fakeFileCache.createScratchInput(ActionInputHelper.fromPath("bar/test/wobble"), "xyz");
@@ -480,6 +486,7 @@
UploadManifest uploadManifest =
UploadManifest.create(
remoteCache.options,
+ remoteCache.cacheCapabilities,
remoteCache.digestUtil,
remotePathResolver,
actionKey,
@@ -565,7 +572,8 @@
serviceRegistry.addService(ServerInterceptors.intercept(actionCache, interceptor));
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
remoteCache.downloadActionResult(
context,
DIGEST_UTIL.asActionKey(DIGEST_UTIL.computeAsUtf8("key")),
@@ -576,7 +584,8 @@
public void testUpload() throws Exception {
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest fooDigest =
fakeFileCache.createScratchInput(ActionInputHelper.fromPath("a/foo"), "xyz");
@@ -652,7 +661,8 @@
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
remoteOptions.maxOutboundMessageSize = 80; // Enough for one digest, but not two.
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest fooDigest =
fakeFileCache.createScratchInput(ActionInputHelper.fromPath("a/foo"), "xyz");
@@ -717,7 +727,8 @@
public void testUploadCacheMissesWithRetries() throws Exception {
RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
GrpcCacheClient client = newClient(remoteOptions);
- RemoteCache remoteCache = new RemoteCache(client, remoteOptions, DIGEST_UTIL);
+ RemoteCache remoteCache =
+ new RemoteCache(CacheCapabilities.getDefaultInstance(), client, remoteOptions, DIGEST_UTIL);
final Digest fooDigest =
fakeFileCache.createScratchInput(ActionInputHelper.fromPath("a/foo"), "xyz");
diff --git a/src/test/java/com/google/devtools/build/lib/remote/InMemoryRemoteCache.java b/src/test/java/com/google/devtools/build/lib/remote/InMemoryRemoteCache.java
index 3a79cac..4c8e3e1 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/InMemoryRemoteCache.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/InMemoryRemoteCache.java
@@ -15,6 +15,7 @@
import static java.nio.charset.StandardCharsets.UTF_8;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import com.google.devtools.build.lib.remote.common.RemoteActionExecutionContext;
import com.google.devtools.build.lib.remote.common.RemoteCacheClient;
@@ -30,19 +31,21 @@
class InMemoryRemoteCache extends RemoteExecutionCache {
InMemoryRemoteCache(
- Map<Digest, byte[]> casEntries,
- RemoteOptions options,
- DigestUtil digestUtil) {
- super(new InMemoryCacheClient(casEntries), options, digestUtil);
+ Map<Digest, byte[]> casEntries, RemoteOptions options, DigestUtil digestUtil) {
+ super(
+ CacheCapabilities.getDefaultInstance(),
+ new InMemoryCacheClient(casEntries),
+ options,
+ digestUtil);
}
InMemoryRemoteCache(RemoteOptions options, DigestUtil digestUtil) {
- super(new InMemoryCacheClient(), options, digestUtil);
+ super(CacheCapabilities.getDefaultInstance(), new InMemoryCacheClient(), options, digestUtil);
}
InMemoryRemoteCache(
RemoteCacheClient cacheProtocol, RemoteOptions options, DigestUtil digestUtil) {
- super(cacheProtocol, options, digestUtil);
+ super(CacheCapabilities.getDefaultInstance(), cacheProtocol, options, digestUtil);
}
Digest addContents(RemoteActionExecutionContext context, String txt)
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
index 4b13e10..352f258 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcherTest.java
@@ -15,6 +15,7 @@
import static com.google.common.truth.Truth.assertThat;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
@@ -107,6 +108,10 @@
DigestUtil.buildDigest(entry.getKey().asBytes(), entry.getValue().length),
entry.getValue());
}
- return new RemoteCache(new InMemoryCacheClient(cacheEntries), options, digestUtil);
+ return new RemoteCache(
+ CacheCapabilities.getDefaultInstance(),
+ new InMemoryCacheClient(cacheEntries),
+ options,
+ digestUtil);
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
index ff70a90..196938e 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.spy;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.RequestMetadata;
import com.google.common.collect.ImmutableList;
@@ -588,11 +589,18 @@
}
private RemoteCache newRemoteCache(RemoteCacheClient remoteCacheClient) {
- return new RemoteCache(remoteCacheClient, Options.getDefaults(RemoteOptions.class), digestUtil);
+ return new RemoteCache(
+ CacheCapabilities.getDefaultInstance(),
+ remoteCacheClient,
+ Options.getDefaults(RemoteOptions.class),
+ digestUtil);
}
private RemoteExecutionCache newRemoteExecutionCache(RemoteCacheClient remoteCacheClient) {
return new RemoteExecutionCache(
- remoteCacheClient, Options.getDefaults(RemoteOptions.class), digestUtil);
+ CacheCapabilities.getDefaultInstance(),
+ remoteCacheClient,
+ Options.getDefaults(RemoteOptions.class),
+ digestUtil);
}
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
index a52073c..4fb988a6 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteExecutionServiceTest.java
@@ -34,6 +34,7 @@
import static org.mockito.Mockito.when;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
import build.bazel.remote.execution.v2.DirectoryNode;
@@ -43,6 +44,7 @@
import build.bazel.remote.execution.v2.OutputSymlink;
import build.bazel.remote.execution.v2.Platform;
import build.bazel.remote.execution.v2.RequestMetadata;
+import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy;
import build.bazel.remote.execution.v2.SymlinkNode;
import build.bazel.remote.execution.v2.Tree;
import com.google.common.base.Throwables;
@@ -1367,11 +1369,10 @@
.isEmpty();
}
- @Test
- public void uploadOutputs_uploadRelativeDanglingSymlink_works() throws Exception {
+ private void doUploadDanglingSymlink(PathFragment targetPath) throws Exception {
// arrange
Path linkPath = execRoot.getRelative("outputs/link");
- linkPath.createSymbolicLink(PathFragment.create("some/path"));
+ linkPath.createSymbolicLink(targetPath);
Artifact outputSymlink =
ActionsTestUtil.createUnresolvedSymlinkArtifactWithExecPath(
artifactRoot, linkPath.relativeTo(execRoot));
@@ -1392,11 +1393,30 @@
// assert
ActionResult.Builder expectedResult = ActionResult.newBuilder();
- expectedResult.addOutputFileSymlinksBuilder().setPath("outputs/link").setTarget("some/path");
+ expectedResult
+ .addOutputFileSymlinksBuilder()
+ .setPath("outputs/link")
+ .setTarget(targetPath.toString());
assertThat(manifest.getActionResult()).isEqualTo(expectedResult.build());
}
@Test
+ public void uploadOutputs_uploadRelativeDanglingSymlink() throws Exception {
+ doUploadDanglingSymlink(PathFragment.create("some/path"));
+ }
+
+ @Test
+ public void uploadOutputs_uploadAbsoluteDanglingSymlink() throws Exception {
+ when(cache.getCacheCapabilities())
+ .thenReturn(
+ CacheCapabilities.newBuilder()
+ .setSymlinkAbsolutePathStrategy(SymlinkAbsolutePathStrategy.Value.ALLOWED)
+ .build());
+
+ doUploadDanglingSymlink(PathFragment.create("/some/path"));
+ }
+
+ @Test
public void uploadOutputs_emptyOutputs_doNotPerformUpload() throws Exception {
// Test that uploading an empty output does not try to perform an upload.
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteModuleTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteModuleTest.java
index a01856e..2deeff8 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteModuleTest.java
@@ -25,6 +25,7 @@
import build.bazel.remote.execution.v2.ExecutionCapabilities;
import build.bazel.remote.execution.v2.GetCapabilitiesRequest;
import build.bazel.remote.execution.v2.ServerCapabilities;
+import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy;
import com.google.auth.Credentials;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -76,6 +77,32 @@
@RunWith(JUnit4.class)
public final class RemoteModuleTest {
+ private static final ServerCapabilities CACHE_ONLY_CAPS =
+ ServerCapabilities.newBuilder()
+ .setLowApiVersion(ApiVersion.current.toSemVer())
+ .setHighApiVersion(ApiVersion.current.toSemVer())
+ .setCacheCapabilities(
+ CacheCapabilities.newBuilder()
+ .addDigestFunctions(Value.SHA256)
+ .setActionCacheUpdateCapabilities(
+ ActionCacheUpdateCapabilities.newBuilder().setUpdateEnabled(true).build())
+ .setSymlinkAbsolutePathStrategy(SymlinkAbsolutePathStrategy.Value.ALLOWED)
+ .build())
+ .build();
+
+ private static final ServerCapabilities EXEC_AND_CACHE_CAPS =
+ ServerCapabilities.newBuilder()
+ .setLowApiVersion(ApiVersion.current.toSemVer())
+ .setHighApiVersion(ApiVersion.current.toSemVer())
+ .setExecutionCapabilities(
+ ExecutionCapabilities.newBuilder()
+ .setExecEnabled(true)
+ .setDigestFunction(Value.SHA256)
+ .build())
+ .setCacheCapabilities(
+ CacheCapabilities.newBuilder().addDigestFunctions(Value.SHA256).build())
+ .build();
+
private static CommandEnvironment createTestCommandEnvironment(RemoteOptions remoteOptions)
throws IOException, AbruptExitException {
CoreOptions coreOptions = Options.getDefaults(CoreOptions.class);
@@ -157,19 +184,7 @@
@Test
public void testVerifyCapabilities_executionAndCacheForSingleEndpoint() throws Exception {
- ServerCapabilities caps =
- ServerCapabilities.newBuilder()
- .setLowApiVersion(ApiVersion.current.toSemVer())
- .setHighApiVersion(ApiVersion.current.toSemVer())
- .setExecutionCapabilities(
- ExecutionCapabilities.newBuilder()
- .setExecEnabled(true)
- .setDigestFunction(Value.SHA256)
- .build())
- .setCacheCapabilities(
- CacheCapabilities.newBuilder().addDigestFunctions(Value.SHA256).build())
- .build();
- CapabilitiesImpl executionServerCapabilitiesImpl = new CapabilitiesImpl(caps);
+ CapabilitiesImpl executionServerCapabilitiesImpl = new CapabilitiesImpl(EXEC_AND_CACHE_CAPS);
String executionServerName = "execution-server";
Server executionServer = createFakeServer(executionServerName, executionServerCapabilitiesImpl);
executionServer.start();
@@ -197,18 +212,7 @@
@Test
public void testVerifyCapabilities_cacheOnlyEndpoint() throws Exception {
- ServerCapabilities cacheOnlyCaps =
- ServerCapabilities.newBuilder()
- .setLowApiVersion(ApiVersion.current.toSemVer())
- .setHighApiVersion(ApiVersion.current.toSemVer())
- .setCacheCapabilities(
- CacheCapabilities.newBuilder()
- .addDigestFunctions(Value.SHA256)
- .setActionCacheUpdateCapabilities(
- ActionCacheUpdateCapabilities.newBuilder().setUpdateEnabled(true).build())
- .build())
- .build();
- CapabilitiesImpl cacheServerCapabilitiesImpl = new CapabilitiesImpl(cacheOnlyCaps);
+ CapabilitiesImpl cacheServerCapabilitiesImpl = new CapabilitiesImpl(CACHE_ONLY_CAPS);
String cacheServerName = "cache-server";
Server cacheServer = createFakeServer(cacheServerName, cacheServerCapabilitiesImpl);
cacheServer.start();
@@ -505,4 +509,68 @@
assertThat(credentials.getRequestMetadata(URI.create("https://foo.example.org"))).isNotEmpty();
assertThat(credentials.getRequestMetadata(URI.create("https://bar.example.org"))).isEmpty();
}
+
+ @Test
+ public void testCacheCapabilities_propagatedToRemoteCache() throws Exception {
+ CapabilitiesImpl cacheServerCapabilitiesImpl = new CapabilitiesImpl(CACHE_ONLY_CAPS);
+ String cacheServerName = "cache-server";
+ Server cacheServer = createFakeServer(cacheServerName, cacheServerCapabilitiesImpl);
+ cacheServer.start();
+
+ try {
+ RemoteModule remoteModule = new RemoteModule();
+ remoteModule.setChannelFactory(
+ (target, proxy, options, interceptors) ->
+ InProcessChannelBuilder.forName(target).directExecutor().build());
+
+ RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
+ remoteOptions.remoteCache = cacheServerName;
+
+ CommandEnvironment env = createTestCommandEnvironment(remoteOptions);
+
+ remoteModule.beforeCommand(env);
+
+ assertThat(Thread.interrupted()).isFalse();
+ RemoteActionContextProvider actionContextProvider = remoteModule.getActionContextProvider();
+ assertThat(actionContextProvider).isNotNull();
+ assertThat(actionContextProvider.getRemoteCache()).isNotNull();
+ assertThat(actionContextProvider.getRemoteCache().getCacheCapabilities())
+ .isEqualTo(CACHE_ONLY_CAPS.getCacheCapabilities());
+ } finally {
+ cacheServer.shutdownNow();
+ cacheServer.awaitTermination();
+ }
+ }
+
+ @Test
+ public void testCacheCapabilities_propagatedToRemoteExecutionCache() throws Exception {
+ CapabilitiesImpl executionServerCapabilitiesImpl = new CapabilitiesImpl(EXEC_AND_CACHE_CAPS);
+ String executionServerName = "execution-server";
+ Server executionServer = createFakeServer(executionServerName, executionServerCapabilitiesImpl);
+ executionServer.start();
+
+ try {
+ RemoteModule remoteModule = new RemoteModule();
+ remoteModule.setChannelFactory(
+ (target, proxy, options, interceptors) ->
+ InProcessChannelBuilder.forName(target).directExecutor().build());
+
+ RemoteOptions remoteOptions = Options.getDefaults(RemoteOptions.class);
+ remoteOptions.remoteExecutor = executionServerName;
+
+ CommandEnvironment env = createTestCommandEnvironment(remoteOptions);
+
+ remoteModule.beforeCommand(env);
+
+ assertThat(Thread.interrupted()).isFalse();
+ RemoteActionContextProvider actionContextProvider = remoteModule.getActionContextProvider();
+ assertThat(actionContextProvider).isNotNull();
+ assertThat(actionContextProvider.getRemoteCache()).isNotNull();
+ assertThat(actionContextProvider.getRemoteCache().getCacheCapabilities())
+ .isEqualTo(EXEC_AND_CACHE_CAPS.getCacheCapabilities());
+ } finally {
+ executionServer.shutdownNow();
+ executionServer.awaitTermination();
+ }
+ }
}
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerWithGrpcRemoteExecutorTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerWithGrpcRemoteExecutorTest.java
index 0559485..ccbfd7a 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerWithGrpcRemoteExecutorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteSpawnRunnerWithGrpcRemoteExecutorTest.java
@@ -27,6 +27,7 @@
import build.bazel.remote.execution.v2.ActionCacheGrpc.ActionCacheImplBase;
import build.bazel.remote.execution.v2.ActionResult;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Command;
import build.bazel.remote.execution.v2.ContentAddressableStorageGrpc.ContentAddressableStorageImplBase;
import build.bazel.remote.execution.v2.Digest;
@@ -292,7 +293,8 @@
new GrpcCacheClient(
channel.retain(), callCredentialsProvider, remoteOptions, retrier, DIGEST_UTIL);
RemoteExecutionCache remoteCache =
- new RemoteExecutionCache(cacheProtocol, remoteOptions, DIGEST_UTIL);
+ new RemoteExecutionCache(
+ CacheCapabilities.getDefaultInstance(), cacheProtocol, remoteOptions, DIGEST_UTIL);
RemoteExecutionService remoteExecutionService =
new RemoteExecutionService(
directExecutor(),
diff --git a/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java b/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java
index 21116c4..bc75807 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/UploadManifestTest.java
@@ -207,7 +207,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -233,7 +234,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("link/foo"));
@@ -265,7 +267,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -291,7 +294,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("link/foo"));
@@ -323,7 +327,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -349,7 +354,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("link/foo"));
@@ -381,7 +387,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
assertThat(um.getDigestToFile()).isEmpty();
@@ -406,7 +413,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
assertThat(um.getDigestToFile()).isEmpty();
@@ -429,7 +437,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(link)));
assertThat(e).hasMessageThat().contains("dangling");
assertThat(e).hasMessageThat().contains("/execroot/link");
@@ -437,8 +446,9 @@
}
@Test
- public void actionResult_noFollowSymlinks_allowDanglingSymlinks_absoluteDanglingSymlinkAsSymlink()
- throws Exception {
+ public void
+ actionResult_noFollowSymlinks_allowDanglingSymlinks_noAllowAbsoluteSymlinks_absoluteDanglingSymlinkAsError()
+ throws Exception {
ActionResult.Builder result = ActionResult.newBuilder();
Path link = execRoot.getRelative("link");
Path target = execRoot.getRelative("target");
@@ -450,7 +460,31 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ true);
+ /*allowDanglingSymlinks=*/ true,
+ /*allowAbsoluteSymlinks=*/ false);
+ IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(link)));
+ assertThat(e).hasMessageThat().contains("absolute");
+ assertThat(e).hasMessageThat().contains("/execroot/link");
+ assertThat(e).hasMessageThat().contains("target");
+ }
+
+ @Test
+ public void
+ actionResult_noFollowSymlinks_allowDanglingSymlinks_allowAbsoluteSymlinks_absoluteDanglingSymlinkAsSymlink()
+ throws Exception {
+ ActionResult.Builder result = ActionResult.newBuilder();
+ Path link = execRoot.getRelative("link");
+ Path target = execRoot.getRelative("target");
+ link.createSymbolicLink(target);
+
+ UploadManifest um =
+ new UploadManifest(
+ digestUtil,
+ remotePathResolver,
+ result,
+ /*followSymlinks=*/ false,
+ /*allowDanglingSymlinks=*/ true,
+ /*allowAbsoluteSymlinks=*/ true);
um.addFiles(ImmutableList.of(link));
assertThat(um.getDigestToFile()).isEmpty();
@@ -473,7 +507,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(link)));
assertThat(e).hasMessageThat().contains("dangling");
assertThat(e).hasMessageThat().contains("/execroot/link");
@@ -494,7 +529,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ true);
+ /*allowDanglingSymlinks=*/ true,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(link));
assertThat(um.getDigestToFile()).isEmpty();
@@ -519,7 +555,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -556,7 +593,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("dir/link/foo"));
@@ -598,7 +636,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -635,7 +674,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("dir/link/foo"));
@@ -676,7 +716,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(target);
assertThat(um.getDigestToFile()).containsExactly(digest, link);
@@ -713,7 +754,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
Digest digest = digestUtil.compute(foo);
assertThat(um.getDigestToFile()).containsExactly(digest, execRoot.getRelative("dir/link/foo"));
@@ -755,7 +797,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
assertThat(um.getDigestToFile()).isEmpty();
@@ -791,7 +834,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
assertThat(um.getDigestToFile()).isEmpty();
@@ -825,7 +869,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(dir)));
assertThat(e).hasMessageThat().contains("dangling");
assertThat(e).hasMessageThat().contains("/execroot/dir/link");
@@ -849,7 +894,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ true);
+ /*allowDanglingSymlinks=*/ true,
+ /*allowAbsoluteSymlinks=*/ false);
IOException e = assertThrows(IOException.class, () -> um.addFiles(ImmutableList.of(dir)));
assertThat(e).hasMessageThat().contains("dangling");
assertThat(e).hasMessageThat().contains("/execroot/dir/link");
@@ -873,7 +919,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
assertThat(um.getDigestToFile()).isEmpty();
@@ -907,7 +954,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ true);
+ /*allowDanglingSymlinks=*/ true,
+ /*allowAbsoluteSymlinks=*/ false);
um.addFiles(ImmutableList.of(dir));
assertThat(um.getDigestToFile()).isEmpty();
@@ -939,7 +987,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
UserExecException e =
assertThrows(UserExecException.class, () -> um.addFiles(ImmutableList.of(special)));
assertThat(e).hasMessageThat().contains("special file");
@@ -958,7 +1007,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
UserExecException e =
assertThrows(UserExecException.class, () -> um.addFiles(ImmutableList.of(link)));
assertThat(e).hasMessageThat().contains("special file");
@@ -976,7 +1026,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ false,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
UserExecException e =
assertThrows(UserExecException.class, () -> um.addFiles(ImmutableList.of(dir)));
assertThat(e).hasMessageThat().contains("special file");
@@ -994,7 +1045,8 @@
remotePathResolver,
result,
/*followSymlinks=*/ true,
- /*allowDanglingSymlinks=*/ false);
+ /*allowDanglingSymlinks=*/ false,
+ /*allowAbsoluteSymlinks=*/ false);
UserExecException e =
assertThrows(UserExecException.class, () -> um.addFiles(ImmutableList.of(dir)));
assertThat(e).hasMessageThat().contains("special file");
diff --git a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
index be8a26a..fef1f08 100644
--- a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
+++ b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/ExecutionServer.java
@@ -356,6 +356,7 @@
UploadManifest manifest =
UploadManifest.create(
cache.getRemoteOptions(),
+ cache.getCacheCapabilities(),
digestUtil,
RemotePathResolver.createDefault(workingDirectory),
actionKey,
diff --git a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/OnDiskBlobStoreCache.java b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/OnDiskBlobStoreCache.java
index 300afcb..8ce78cf 100644
--- a/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/OnDiskBlobStoreCache.java
+++ b/src/tools/remote/src/main/java/com/google/devtools/build/remote/worker/OnDiskBlobStoreCache.java
@@ -15,10 +15,12 @@
import static com.google.devtools.build.lib.remote.util.Utils.getFromFuture;
+import build.bazel.remote.execution.v2.CacheCapabilities;
import build.bazel.remote.execution.v2.Digest;
import build.bazel.remote.execution.v2.Directory;
import build.bazel.remote.execution.v2.DirectoryNode;
import build.bazel.remote.execution.v2.FileNode;
+import build.bazel.remote.execution.v2.SymlinkAbsolutePathStrategy;
import build.bazel.remote.execution.v2.SymlinkNode;
import com.google.devtools.build.lib.remote.RemoteCache;
import com.google.devtools.build.lib.remote.common.RemoteActionExecutionContext;
@@ -32,8 +34,14 @@
/** A {@link RemoteCache} backed by an {@link DiskCacheClient}. */
class OnDiskBlobStoreCache extends RemoteCache {
+ private static final CacheCapabilities CAPABILITIES =
+ CacheCapabilities.newBuilder()
+ .setSymlinkAbsolutePathStrategy(SymlinkAbsolutePathStrategy.Value.ALLOWED)
+ .build();
+
public OnDiskBlobStoreCache(RemoteOptions options, Path cacheDir, DigestUtil digestUtil) {
super(
+ CAPABILITIES,
new DiskCacheClient(cacheDir, /* verifyDownloads= */ true, digestUtil),
options,
digestUtil);