Fix error message when reading a resource/module past root dir (#1234)

This commit is contained in:
Daniel Chao
2025-10-09 10:16:33 -07:00
committed by GitHub
parent 3a29ea8998
commit 42dcad25c6
4 changed files with 43 additions and 30 deletions
@@ -145,17 +145,17 @@ public final class SecurityManagers {
@Override @Override
public void checkResolveModule(URI uri) throws SecurityManagerException { public void checkResolveModule(URI uri) throws SecurityManagerException {
checkRead(uri, allowedModules, "moduleNotInAllowList"); checkRead(uri, allowedModules, false);
} }
@Override @Override
public void checkResolveResource(URI resource) throws SecurityManagerException { public void checkResolveResource(URI resource) throws SecurityManagerException {
checkRead(resource, allowedResources, "resourceNotInAllowList"); checkRead(resource, allowedResources, true);
} }
@Override @Override
public void checkReadResource(URI uri) throws SecurityManagerException { public void checkReadResource(URI uri) throws SecurityManagerException {
checkRead(uri, allowedResources, "resourceNotInAllowList"); checkRead(uri, allowedResources, true);
} }
@Override @Override
@@ -185,21 +185,21 @@ public final class SecurityManagers {
} }
} }
private void checkRead(URI uri, List<Pattern> allowedPatterns, String errorMessageKey) private void checkRead(URI uri, List<Pattern> allowedPatterns, boolean isResource)
throws SecurityManagerException { throws SecurityManagerException {
for (var pattern : allowedPatterns) { for (var pattern : allowedPatterns) {
if (pattern.matcher(uri.toString()).lookingAt()) { if (pattern.matcher(uri.toString()).lookingAt()) {
checkIsUnderRootDir(uri, errorMessageKey); checkIsUnderRootDir(uri, isResource);
return; return;
} }
} }
var message = ErrorMessages.create(errorMessageKey, uri); var messageKey = isResource ? "resourceNotInAllowList" : "moduleNotInAllowList";
var message = ErrorMessages.create(messageKey, uri);
throw new SecurityManagerException(message); throw new SecurityManagerException(message);
} }
private void checkIsUnderRootDir(URI uri, String errorMessageKey) private void checkIsUnderRootDir(URI uri, boolean isResource) throws SecurityManagerException {
throws SecurityManagerException {
if (!uri.isAbsolute()) { if (!uri.isAbsolute()) {
throw new AssertionError("Expected absolute URI but got: " + uri); throw new AssertionError("Expected absolute URI but got: " + uri);
} }
@@ -220,7 +220,8 @@ public final class SecurityManagers {
} }
if (!path.startsWith(rootDir)) { if (!path.startsWith(rootDir)) {
var message = ErrorMessages.create(errorMessageKey, uri); var errorMessageKey = isResource ? "resourcePastRootDir" : "modulePastRootDir";
var message = ErrorMessages.create(errorMessageKey, uri, rootDir);
throw new SecurityManagerException(message); throw new SecurityManagerException(message);
} }
} }
@@ -690,6 +690,12 @@ Refusing to read resource `{0}` because it does not match any entry in the resou
moduleNotInAllowList=\ moduleNotInAllowList=\
Refusing to load module `{0}` because it does not match any entry in the module allowlist (`--allowed-modules`). Refusing to load module `{0}` because it does not match any entry in the module allowlist (`--allowed-modules`).
resourcePastRootDir=\
Refusing to read resource `{0}` because it is not within the root directory (`--root-dir`).
modulePastRootDir=\
Refusing to load module `{0}` because it is not within the root directory (`--root-dir`).
insufficientModuleTrustLevel=\ insufficientModuleTrustLevel=\
Refusing to import module `{0}` because importing module `{1}` has an insufficient trust level. Refusing to import module `{0}` because importing module `{1}` has an insufficient trust level.
@@ -269,27 +269,35 @@ class EvaluatorTest {
@Test @Test
fun `cannot import module located outside root dir`(@TempDir tempDir: Path) { fun `cannot import module located outside root dir`(@TempDir tempDir: Path) {
val evaluator = val evaluator =
EvaluatorBuilder.preconfigured() with(EvaluatorBuilder.preconfigured()) {
.setSecurityManager( rootDir = tempDir
SecurityManagers.standard( build()
SecurityManagers.defaultAllowedModules, }
SecurityManagers.defaultAllowedResources,
SecurityManagers.defaultTrustLevels,
tempDir,
)
)
.build()
val module = tempDir.resolve("test.pkl") val module = tempDir.resolve("test.pkl").writeString("amends \"/non/existing.pkl\"")
module.writeString(
"""
amends "/non/existing.pkl"
"""
.trimIndent()
)
val e = assertThrows<PklException> { evaluator.evaluate(path(module)) } val e = assertThrows<PklException> { evaluator.evaluate(path(module)) }
assertThat(e.message).contains("Refusing to load module `file:///non/existing.pkl`") assertThat(e.message)
.contains(
"Refusing to load module `file:///non/existing.pkl` because it is not within the root directory (`--root-dir`)."
)
}
@Test
fun `cannot read resource located outside root dir`(@TempDir tempDir: Path) {
val evaluator =
with(EvaluatorBuilder.preconfigured()) {
rootDir = tempDir
build()
}
val module = tempDir.resolve("test.pkl").writeString("res = read(\"/bar.txt\")")
val e = assertThrows<PklException> { evaluator.evaluate(path(module)) }
assertThat(e)
.hasMessageContaining(
"Refusing to read resource `file:///bar.txt` because it is not within the root directory (`--root-dir`)."
)
} }
@Test @Test
@@ -306,9 +306,7 @@ class EvaluatorsTest : AbstractTest() {
val result = runTask("evalTest", expectFailure = true) val result = runTask("evalTest", expectFailure = true)
assertThat(result.output).contains("Refusing to load module") assertThat(result.output).contains("Refusing to load module")
assertThat(result.output) assertThat(result.output)
.contains( .contains("because it is not within the root directory (`--root-dir`).")
"because it does not match any entry in the module allowlist (`--allowed-modules`)."
)
} }
@Test @Test