From c11fe272ea01d17e26218453b48a72044b980d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=8F=99=ED=99=98?= <66408194+dev-donghwan@users.noreply.github.com> Date: Fri, 31 Jul 2026 00:23:32 +0900 Subject: [PATCH] [ZEPPELIN-6530] Fix operator precedence in SSL store path checks and make isWindowsPath null-safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What is this PR for? `getKeyStorePath()` and `getTrustStorePath()` in `ZeppelinConfiguration` contain a mis-parenthesized condition: ```java if (path != null && path.startsWith("/") || isWindowsPath(path)) { ``` The condition is meant to answer a single question — "is `path` an absolute path (Unix `/...` or Windows `C:\...`)?" — with `path != null` guarding the whole check. But since `&&` binds tighter than `||`, it actually parses as `(path != null && path.startsWith("/")) || isWindowsPath(path)`, leaving `isWindowsPath(path)` outside the null guard. `isWindowsPath` dereferences its argument, so a null `path` would throw an NPE. Note on reachability: with the current defaults this NPE is latent rather than user-facing. `ZEPPELIN_SSL_KEYSTORE_PATH` has a non-null default (`"keystore"`), so `getKeyStorePath()` never sees a null path, and `getTrustStorePath()` falls back to `getKeyStorePath()` when the truststore path is unset. So this PR is a correctness/hardening fix, not a fix for a currently reproducible crash. This PR: - restores the intended grouping in both methods — `path != null && (path.startsWith("/") || isWindowsPath(path))` — matching the correctly-parenthesized pattern already used in `getAbsoluteDir()` in the same class - makes `isWindowsPath(null)` return `false` instead of throwing, as defense in depth ### What type of PR is it? Bug Fix ### Todos * [x] - Add the missing parentheses in `getKeyStorePath()` / `getTrustStorePath()` * [x] - Make `isWindowsPath` null-safe * [x] - Add a unit test for `isWindowsPath(null)` ### What is the Jira issue? * https://issues.apache.org/jira/browse/ZEPPELIN-6530 ### How should this be tested? * `./mvnw test -pl zeppelin-server -Dtest=ZeppelinConfigurationTest` * The new `isWindowsPathTestNull` asserts `isWindowsPath(null)` returns `false` (it threw an NPE before this change), following the existing `isWindowsPathTestTrue` / `isWindowsPathTestFalse` convention. ### Screenshots (if appropriate) N/A ### Questions: * Does the license files need to update? No * Is there breaking changes for older versions? No — behavior is unchanged for all reachable inputs; only the (previously unreachable) null case changes from NPE to the intended relative-path fallback * Does this needs documentation? No Closes #5353 from dev-donghwan/ZEPPELIN-6530. Signed-off-by: ChanHo Lee --- .../org/apache/zeppelin/conf/ZeppelinConfiguration.java | 6 +++--- .../apache/zeppelin/conf/ZeppelinConfigurationTest.java | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java index 252fd51a9bd..179dcce6e85 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/conf/ZeppelinConfiguration.java @@ -353,7 +353,7 @@ public String getServerContextPath() { public String getKeyStorePath() { String path = getString(ConfVars.ZEPPELIN_SSL_KEYSTORE_PATH); - if (path != null && path.startsWith("/") || isWindowsPath(path)) { + if (path != null && (path.startsWith("/") || isWindowsPath(path))) { return path; } else { return getAbsoluteDir( @@ -385,7 +385,7 @@ public String getTrustStorePath() { if (path == null) { path = getKeyStorePath(); } - if (path != null && path.startsWith("/") || isWindowsPath(path)) { + if (path != null && (path.startsWith("/") || isWindowsPath(path))) { return path; } else { return getAbsoluteDir( @@ -667,7 +667,7 @@ public String getInterpreterPortRange() { } public boolean isWindowsPath(String path){ - return path.matches("^[A-Za-z]:\\\\.*"); + return path != null && path.matches("^[A-Za-z]:\\\\.*"); } public boolean isPathWithScheme(String path){ diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java index 63fcd0da212..a5cb0037fd0 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/conf/ZeppelinConfigurationTest.java @@ -72,6 +72,14 @@ void isWindowsPathTestFalse() { assertFalse(isIt); } + @Test + void isWindowsPathTestNull() { + + ZeppelinConfiguration zConf = ZeppelinConfiguration.load("zeppelin-test-site.xml"); + Boolean isIt = zConf.isWindowsPath(null); + assertFalse(isIt); + } + @Test void isPathWithSchemeTestTrue() {