Skip to content
5 changes: 5 additions & 0 deletions core/src/main/java/hudson/FilePath.java
Original file line number Diff line number Diff line change
Expand Up @@ -3781,6 +3781,11 @@
Path currentFilePath = parentFile.toPath();
while (!remainingPath.isEmpty()) {
Path directChild = this.getDirectChild(currentFilePath, remainingPath);
// --- FIX #2: Handle if directChild is null ---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extra comment text is incorrect now and doesn't help comprehension

Suggested change
// --- FIX #2: Handle if directChild is null ---

if (directChild == null) {

Check warning on line 3785 in core/src/main/java/hudson/FilePath.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 3785 is only partially covered, one branch is missing
return false;

Check warning on line 3786 in core/src/main/java/hudson/FilePath.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 3786 is not covered by tests
}
Copy link

Copilot AI Jan 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add test coverage for the case where getDirectChild returns null. While the existing isDescendant tests are comprehensive, none appear to exercise the specific edge case where getDirectChild would return null (when the child path cannot be resolved to a direct child of the parent path).

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

none appear to exercise the specific edge case where getDirectChild would return null (when the child path cannot be resolved to a direct child of the parent path).

I don't think that edge case can be exercised because there is specific code in the method that rejects absolute paths

// ---------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't help comprehension of the change

Suggested change
// ---------------------------------------------

Path childUsingFullPath = currentFilePath.resolve(remainingPath);
String childUsingFullPathAbs = childUsingFullPath.toAbsolutePath().toString();
String directChildAbs = directChild.toAbsolutePath().toString();
Expand Down
13 changes: 13 additions & 0 deletions core/src/test/java/hudson/FilePathTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1297,4 +1297,17 @@ private static File newFolder(File root, String... subDirs) throws IOException {
}
return result;
}

@Test
@Issue("SpotBugs")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use the @Issue annotation for bug reports. No need to annotate a test for a null pointer exception

Suggested change
@Issue("SpotBugs")

public void testIsDescendantWithParentTraversal() throws Exception {
File tmp = Util.createTempDir();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use the JUnit @TempDir annotation to allow the JUnit framework to perform the directory cleanup rather than using try / finally to perform the cleanup yourself. There are several examples available in the Jenkins tests.

try {
FilePath parent = new FilePath(tmp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coverage report says that the return false line is not covered. It was also not reached when I ran the test in the debugger. Please adjust the test to show the null pointer exception before your change.

Also, if you use the variable temp it is already available in the test class as a TempDir that will be automatically deleted at the end of the test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made several attempts to reach the added return null from a test. I was unsuccessful. I'm curious if you can find a way to reach it that I missed.

// This checks the specific case that causes getDirectChild to return null
assertFalse(parent.isDescendant(".."), "Parent directory '..' should not be a descendant");
} finally {
Util.deleteRecursive(tmp);
}
}
Comment on lines +1301 to +1306
Copy link

Copilot AI Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is redundant with existing comprehensive test coverage for isDescendant. Tests in isDescendant_regularFiles() (lines 1042, 1049-1050, 1053-1057, 1060-1061) already validate the behavior with ".." path traversals, including cases like "sub/../sub/sub-regular.txt", "../protected/secret.txt", "./../workspace", and "./../../root/workspace/regular.txt".

The new test doesn't add meaningful coverage beyond what's already tested. Consider removing this test to avoid redundancy, or if there's a specific edge case this test targets that isn't covered by existing tests, update the test comment to explain what unique scenario is being validated.

Copilot uses AI. Check for mistakes.
}
Loading