|
11 | 11 |
|
12 | 12 | import org.elasticsearch.common.settings.Settings;
|
13 | 13 | import org.elasticsearch.core.SuppressForbidden;
|
| 14 | +import org.elasticsearch.entitlement.runtime.policy.FileAccessTree.ExclusiveFileEntitlement; |
14 | 15 | import org.elasticsearch.entitlement.runtime.policy.FileAccessTree.ExclusivePath;
|
15 | 16 | import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement;
|
| 17 | +import org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.FileData; |
16 | 18 | import org.elasticsearch.test.ESTestCase;
|
17 | 19 | import org.junit.BeforeClass;
|
18 | 20 |
|
|
26 | 28 | import java.util.Map;
|
27 | 29 |
|
28 | 30 | import static org.elasticsearch.core.PathUtils.getDefaultFileSystem;
|
| 31 | +import static org.elasticsearch.entitlement.runtime.policy.FileAccessTree.buildExclusivePathList; |
| 32 | +import static org.elasticsearch.entitlement.runtime.policy.FileAccessTree.normalizePath; |
| 33 | +import static org.elasticsearch.entitlement.runtime.policy.Platform.WINDOWS; |
| 34 | +import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ; |
| 35 | +import static org.elasticsearch.entitlement.runtime.policy.entitlements.FilesEntitlement.Mode.READ_WRITE; |
29 | 36 | import static org.hamcrest.Matchers.equalTo;
|
30 | 37 | import static org.hamcrest.Matchers.is;
|
31 | 38 |
|
@@ -195,7 +202,7 @@ public void testNormalizePath() {
|
195 | 202 | }
|
196 | 203 |
|
197 | 204 | public void testNormalizeDirectorySeparatorWindows() {
|
198 |
| - assumeTrue("normalization of windows paths", Platform.WINDOWS.isCurrent()); |
| 205 | + assumeTrue("normalization of windows paths", WINDOWS.isCurrent()); |
199 | 206 |
|
200 | 207 | assertThat(FileAccessTree.normalizePath(Path.of("C:\\a\\b")), equalTo("C:\\a\\b"));
|
201 | 208 | assertThat(FileAccessTree.normalizePath(Path.of("C:/a.xml")), equalTo("C:\\a.xml"));
|
@@ -254,7 +261,7 @@ public void testJdkAccess() {
|
254 | 261 |
|
255 | 262 | @SuppressForbidden(reason = "don't care about the directory location in tests")
|
256 | 263 | public void testFollowLinks() throws IOException {
|
257 |
| - assumeFalse("Windows requires admin right to create symbolic links", Platform.WINDOWS.isCurrent()); |
| 264 | + assumeFalse("Windows requires admin right to create symbolic links", WINDOWS.isCurrent()); |
258 | 265 |
|
259 | 266 | Path baseSourceDir = Files.createTempDirectory("fileaccess_source");
|
260 | 267 | Path source1Dir = baseSourceDir.resolve("source1");
|
@@ -347,18 +354,102 @@ public void testInvalidExclusiveAccess() {
|
347 | 354 | assertThat(tree.canWrite(path("a")), is(false));
|
348 | 355 | }
|
349 | 356 |
|
| 357 | + public void testDuplicatePrunedPaths() { |
| 358 | + List<String> inputPaths = List.of("/a", "/a", "/a/b", "/a/b", "/b/c", "b/c/d", "b/c/d", "b/c/d", "e/f", "e/f"); |
| 359 | + List<String> outputPaths = List.of("/a", "/b/c", "b/c/d", "e/f"); |
| 360 | + var actual = FileAccessTree.pruneSortedPaths(inputPaths.stream().map(p -> normalizePath(path(p))).toList()); |
| 361 | + var expected = outputPaths.stream().map(p -> normalizePath(path(p))).toList(); |
| 362 | + assertEquals(expected, actual); |
| 363 | + } |
| 364 | + |
| 365 | + public void testDuplicateExclusivePaths() { |
| 366 | + // Bunch o' handy definitions |
| 367 | + var originalFileData = FileData.ofPath(path("/a/b"), READ).withExclusive(true); |
| 368 | + var fileDataWithWriteMode = FileData.ofPath(path("/a/b"), READ_WRITE).withExclusive(true); |
| 369 | + var original = new ExclusiveFileEntitlement("component1", "module1", new FilesEntitlement(List.of(originalFileData))); |
| 370 | + var differentComponent = new ExclusiveFileEntitlement("component2", original.moduleName(), original.filesEntitlement()); |
| 371 | + var differentModule = new ExclusiveFileEntitlement(original.componentName(), "module2", original.filesEntitlement()); |
| 372 | + var differentPath = new ExclusiveFileEntitlement( |
| 373 | + original.componentName(), |
| 374 | + original.moduleName(), |
| 375 | + new FilesEntitlement( |
| 376 | + List.of(FileData.ofPath(path("/c/d"), originalFileData.mode()).withExclusive(originalFileData.exclusive())) |
| 377 | + ) |
| 378 | + ); |
| 379 | + var differentMode = new ExclusiveFileEntitlement( |
| 380 | + original.componentName(), |
| 381 | + original.moduleName(), |
| 382 | + new FilesEntitlement(List.of(fileDataWithWriteMode)) |
| 383 | + ); |
| 384 | + var differentPlatform = new ExclusiveFileEntitlement( |
| 385 | + original.componentName(), |
| 386 | + original.moduleName(), |
| 387 | + new FilesEntitlement(List.of(originalFileData.withPlatform(WINDOWS))) |
| 388 | + ); |
| 389 | + var originalExclusivePath = new ExclusivePath("component1", "module1", normalizePath(path("/a/b"))); |
| 390 | + |
| 391 | + // Some basic tests |
| 392 | + |
| 393 | + assertEquals( |
| 394 | + "Single element should trivially work", |
| 395 | + List.of(originalExclusivePath), |
| 396 | + buildExclusivePathList(List.of(original), TEST_PATH_LOOKUP) |
| 397 | + ); |
| 398 | + assertEquals( |
| 399 | + "Two identical elements should be combined", |
| 400 | + List.of(originalExclusivePath), |
| 401 | + buildExclusivePathList(List.of(original, original), TEST_PATH_LOOKUP) |
| 402 | + ); |
| 403 | + |
| 404 | + // Don't merge things we shouldn't |
| 405 | + |
| 406 | + var distinctEntitlements = List.of(original, differentComponent, differentModule, differentPath); |
| 407 | + var distinctPaths = List.of( |
| 408 | + originalExclusivePath, |
| 409 | + new ExclusivePath("component2", original.moduleName(), originalExclusivePath.path()), |
| 410 | + new ExclusivePath(original.componentName(), "module2", originalExclusivePath.path()), |
| 411 | + new ExclusivePath(original.componentName(), original.moduleName(), normalizePath(path("/c/d"))) |
| 412 | + ); |
| 413 | + assertEquals( |
| 414 | + "Distinct elements should not be combined", |
| 415 | + distinctPaths, |
| 416 | + buildExclusivePathList(distinctEntitlements, TEST_PATH_LOOKUP) |
| 417 | + ); |
| 418 | + |
| 419 | + // Do merge things we should |
| 420 | + |
| 421 | + List<ExclusiveFileEntitlement> interleavedEntitlements = new ArrayList<>(); |
| 422 | + distinctEntitlements.forEach(e -> { |
| 423 | + interleavedEntitlements.add(e); |
| 424 | + interleavedEntitlements.add(original); |
| 425 | + }); |
| 426 | + assertEquals( |
| 427 | + "Identical elements should be combined wherever they are in the list", |
| 428 | + distinctPaths, |
| 429 | + buildExclusivePathList(interleavedEntitlements, TEST_PATH_LOOKUP) |
| 430 | + ); |
| 431 | + |
| 432 | + var equivalentEntitlements = List.of(original, differentMode, differentPlatform); |
| 433 | + var equivalentPaths = List.of(originalExclusivePath); |
| 434 | + assertEquals( |
| 435 | + "Exclusive paths should be combined even if the entitlements are different", |
| 436 | + equivalentPaths, |
| 437 | + buildExclusivePathList(equivalentEntitlements, TEST_PATH_LOOKUP) |
| 438 | + ); |
| 439 | + } |
| 440 | + |
350 | 441 | public void testWindowsAbsolutPathAccess() {
|
351 |
| - assumeTrue("Specific to windows for paths with a root (DOS or UNC)", Platform.WINDOWS.isCurrent()); |
| 442 | + assumeTrue("Specific to windows for paths with a root (DOS or UNC)", WINDOWS.isCurrent()); |
352 | 443 |
|
353 | 444 | var fileAccessTree = FileAccessTree.of(
|
354 | 445 | "test",
|
355 | 446 | "test",
|
356 | 447 | new FilesEntitlement(
|
357 | 448 | List.of(
|
358 |
| - FilesEntitlement.FileData.ofPath(Path.of("\\\\.\\pipe\\"), FilesEntitlement.Mode.READ), |
359 |
| - FilesEntitlement.FileData.ofPath(Path.of("D:\\.gradle"), FilesEntitlement.Mode.READ), |
360 |
| - FilesEntitlement.FileData.ofPath(Path.of("D:\\foo"), FilesEntitlement.Mode.READ), |
361 |
| - FilesEntitlement.FileData.ofPath(Path.of("C:\\foo"), FilesEntitlement.Mode.READ_WRITE) |
| 449 | + FileData.ofPath(Path.of("\\\\.\\pipe\\"), READ), |
| 450 | + FileData.ofPath(Path.of("D:\\.gradle"), READ), |
| 451 | + FileData.ofPath(Path.of("D:\\foo"), READ), |
| 452 | + FileData.ofPath(Path.of("C:\\foo"), FilesEntitlement.Mode.READ_WRITE) |
362 | 453 | )
|
363 | 454 | ),
|
364 | 455 | TEST_PATH_LOOKUP,
|
@@ -394,7 +485,7 @@ static FilesEntitlement entitlement(Map<String, String> value) {
|
394 | 485 | static List<ExclusivePath> exclusivePaths(String componentName, String moduleName, String... paths) {
|
395 | 486 | List<ExclusivePath> exclusivePaths = new ArrayList<>();
|
396 | 487 | for (String path : paths) {
|
397 |
| - exclusivePaths.add(new ExclusivePath(componentName, moduleName, path(path).toString())); |
| 488 | + exclusivePaths.add(new ExclusivePath(componentName, moduleName, normalizePath(path(path)))); |
398 | 489 | }
|
399 | 490 | return exclusivePaths;
|
400 | 491 | }
|
|
0 commit comments