mirror of
https://github.com/apple/pkl.git
synced 2026-04-20 23:41:27 +02:00
Prevent --multiple-file-output-path writes from following symlinks outside the target directory (#1467)
This commit is contained in:
@@ -240,8 +240,7 @@ constructor(
|
|||||||
|
|
||||||
for ((pathSpec, fileOutput) in output) {
|
for ((pathSpec, fileOutput) in output) {
|
||||||
checkPathSpec(pathSpec)
|
checkPathSpec(pathSpec)
|
||||||
val resolvedPath = realOutputDir.resolve(pathSpec).normalize()
|
val (realPath, resolvedPath) = realOutputDir.resolveRealPath(Path.of(pathSpec))
|
||||||
val realPath = if (resolvedPath.exists()) resolvedPath.toRealPath() else resolvedPath
|
|
||||||
if (!realPath.startsWith(realOutputDir)) {
|
if (!realPath.startsWith(realOutputDir)) {
|
||||||
throw CliException(
|
throw CliException(
|
||||||
"Output file conflict: `output.files` entry `\"$pathSpec\"` in module `$moduleUri` resolves to file path `$realPath`, which is outside output directory `$realOutputDir`."
|
"Output file conflict: `output.files` entry `\"$pathSpec\"` in module `$moduleUri` resolves to file path `$realPath`, which is outside output directory `$realOutputDir`."
|
||||||
@@ -269,4 +268,22 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves [rel] against this Path name-by-name. At each step, the real path is resolved if the
|
||||||
|
* file exists. The normalized real path and normalized resolved path are returned. This has a
|
||||||
|
* similar effect to `this.resolve(rel).toRealPath().normalize()`, but the real paths account for
|
||||||
|
* symlinks in the middle of the relative path so the full path need not exist.
|
||||||
|
*/
|
||||||
|
private fun Path.resolveRealPath(rel: Path): Pair<Path, Path> {
|
||||||
|
assert(!rel.isAbsolute)
|
||||||
|
var resolved = this
|
||||||
|
var real = this
|
||||||
|
for (name in rel) {
|
||||||
|
resolved = resolved.resolve(name)
|
||||||
|
real = real.resolve(name)
|
||||||
|
if (real.exists()) real = real.toRealPath()
|
||||||
|
}
|
||||||
|
return real.normalize() to resolved.normalize()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -931,6 +931,37 @@ result = someLib.x
|
|||||||
.hasMessageContaining("which is outside output directory")
|
.hasMessageContaining("which is outside output directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisabledOnOs(OS.WINDOWS)
|
||||||
|
fun `multiple file output throws if files are written outside the base path via symlink`() {
|
||||||
|
val output = tempDir.resolve(".output").createDirectories()
|
||||||
|
val outside = tempDir.resolve("outside").createDirectories()
|
||||||
|
output.resolve("outside").createSymbolicLinkPointingTo(outside)
|
||||||
|
|
||||||
|
val moduleUri =
|
||||||
|
writePklFile(
|
||||||
|
"test.pkl",
|
||||||
|
"""
|
||||||
|
output {
|
||||||
|
files {
|
||||||
|
["outside/foo.txt"] {
|
||||||
|
text = "bar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
.trimIndent(),
|
||||||
|
)
|
||||||
|
val options =
|
||||||
|
CliEvaluatorOptions(
|
||||||
|
CliBaseOptions(sourceModules = listOf(moduleUri), workingDir = tempDir),
|
||||||
|
multipleFileOutputPath = ".output",
|
||||||
|
)
|
||||||
|
assertThatCode { evalToConsole(options) }
|
||||||
|
.hasMessageStartingWith("Output file conflict:")
|
||||||
|
.hasMessageContaining("which is outside output directory")
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `multiple file output throws if file path is a directory`() {
|
fun `multiple file output throws if file path is a directory`() {
|
||||||
tempDir.resolve(".output/myDir").createDirectories()
|
tempDir.resolve(".output/myDir").createDirectories()
|
||||||
|
|||||||
Reference in New Issue
Block a user