diff --git a/diff/src/main/scala/proteus/diff/Git.scala b/diff/src/main/scala/proteus/diff/Git.scala index 8650341..a430572 100644 --- a/diff/src/main/scala/proteus/diff/Git.scala +++ b/diff/src/main/scala/proteus/diff/Git.scala @@ -12,7 +12,11 @@ object Git { * Extracts all files at the given ref into a temp dir via a `git archive | tar -x` pipeline. * Much faster than invoking `git show` per file (one subprocess pair vs N+1). */ - def extractProtos(ref: String, cwd: Option[Path] = None): Either[String, Path] = { + def extractProtos(ref: String, cwd: Option[Path] = None): Either[String, Path] = + if (ref.startsWith("-")) Left(s"invalid git ref: $ref") + else extractProtosUnchecked(ref, cwd) + + private def extractProtosUnchecked(ref: String, cwd: Option[Path]): Either[String, Path] = { val tmp = Files.createTempDirectory("proteus-diff-git-") sys.addShutdownHook(deleteRecursively(tmp)) diff --git a/diff/src/test/scala/proteus/diff/GitSpec.scala b/diff/src/test/scala/proteus/diff/GitSpec.scala index 5156e53..a8aa20f 100644 --- a/diff/src/test/scala/proteus/diff/GitSpec.scala +++ b/diff/src/test/scala/proteus/diff/GitSpec.scala @@ -72,6 +72,16 @@ object GitSpec extends ZIOSpecDefault { Git.extractProtos("definitely-not-a-ref-12345", Some(dir)).isLeft } assertTrue(isLeft) + }, + test("extractProtos rejects a ref that looks like a git option") { + val (fileWritten, isLeft) = withRepo { dir => + writeFile(dir.resolve("a.proto"), """syntax = "proto3"; message Foo {}""") + commit(dir, "initial") + val evil = dir.resolve("evil.tar") + val result = Git.extractProtos(s"--output=${evil.toString}", Some(dir)) + (Files.exists(evil), result.isLeft) + } + assertTrue(isLeft, !fileWritten) } ) }