Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .evergreen/setup-env.bash
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Java configurations for evergreen

# On Windows Evergreen hosts `OS` is a native environment variable set to
# "Windows_NT". It is not set on other platforms, so default it from `uname`
# to avoid an unbound variable error under `set -u`.
if [ -z "${OS:-}" ]; then
case "$(uname -s)" in
CYGWIN*|MINGW*|MSYS*|Windows_NT) OS="Windows_NT" ;;
*) OS="$(uname -s)" ;;
esac
fi

if [ "Windows_NT" == "$OS" ]; then
export JDK8="/cygdrive/c/java/jdk8"
export JDK11="/cygdrive/c/java/jdk11"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ public void asStringTest() {
}

@Test
public void asStringTestNestedPre82() {
assumeTrue(serverVersionLessThan(8, 2));
public void asStringTestNestedPre83() {
assumeTrue(serverVersionLessThan(8, 3));

// Arrays and documents are not (yet) supported:
assertThrows(MongoCommandException.class, () ->
Expand All @@ -202,7 +202,7 @@ public void asStringTestNestedPre82() {

@Test
public void asStringTestNested() {
assumeTrue(serverVersionAtLeast(8, 2));
assumeTrue(serverVersionAtLeast(8, 3));

assertExpression("[1,2]", ofIntegerArray(1, 2).asString());
assertExpression("{\"a\":1}", of(Document.parse("{a: 1}")).asString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ public static synchronized MongoClient getMongoClient() {
return;
}
if (defaultDatabase != null) {
defaultDatabase.drop();
try {
defaultDatabase.drop();
} catch (Exception e) {
// ignore
}
}
mongoClient.close();
mongoClient = null;
Expand Down
119 changes: 66 additions & 53 deletions mongodb-crypt/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,45 @@ abstract class VerifyLibmongocryptTask : DefaultTask() {
return
}

// The gpg shipped on the Evergreen Windows hosts is a Cygwin build that only understands POSIX paths.
// Handed a native Windows path ("C:\dir") it treats the backslash path as relative, prepends its working
// directory, and fails with "no writable keyring found". Translate drive-letter paths to the Cygwin form
// ("C:\dir" -> "/cygdrive/c/dir") on Windows so every path argument (homedir, key, signatures, tarballs)
// is parsed correctly; other platforms pass paths through unchanged.
val isWindows = System.getProperty("os.name").startsWith("Windows", ignoreCase = true)
Comment thread
nhachicha marked this conversation as resolved.
fun toGpgPath(path: String): String {
if (!isWindows) {
return path
}
val driveLetter = Regex("^([A-Za-z]):[\\\\/](.*)$").matchEntire(path) ?: return path.replace('\\', '/')
val (drive, rest) = driveLetter.destructured
return "/cygdrive/${drive.lowercase(java.util.Locale.ROOT)}/${rest.replace('\\', '/')}"
}

// Run gpg capturing both streams; on non-zero exit throw with the captured output appended so the
// underlying gpg diagnostic is visible instead of Gradle's opaque "finished with non-zero exit value N".
fun runGpg(vararg args: String, onFailure: (String) -> String) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice 👍

val out = ByteArrayOutputStream()
val err = ByteArrayOutputStream()
val result =
execOps.exec {
commandLine(listOf("gpg") + args)
standardOutput = out
errorOutput = err
isIgnoreExitValue = true
}
val combined = (out.toString().trim() + "\n" + err.toString().trim()).trim()
logger.info("gpg ${args.joinToString(" ")} -> exit ${result.exitValue}\n$combined")
if (result.exitValue != 0) {
throw GradleException("${onFailure(combined)}\ngpg command: gpg ${args.joinToString(" ")}")
}
}

val versionOut = ByteArrayOutputStream()
try {
execOps.exec {
commandLine("gpg", "--version")
standardOutput = ByteArrayOutputStream()
standardOutput = versionOut
}
} catch (e: Exception) {
throw GradleException(
Expand All @@ -180,6 +215,7 @@ abstract class VerifyLibmongocryptTask : DefaultTask() {
"or pass -PskipCryptVerify=true for offline development builds.",
e)
}
logger.lifecycle("Using gpg:\n${versionOut.toString().trim().lineSequence().firstOrNull() ?: ""}")

val home =
gnupgHome.get().asFile.apply {
Expand All @@ -193,41 +229,28 @@ abstract class VerifyLibmongocryptTask : DefaultTask() {
setExecutable(false, false)
setExecutable(true, true)
}
val homedir = toGpgPath(home.path)
logger.lifecycle(
"libmongocrypt verify: gnupgHome=${home.path} -> $homedir (exists=${home.exists()}, " +
"writable=${home.canWrite()}), publicKey=${publicKey.get().asFile.path} " +
"(exists=${publicKey.get().asFile.exists()})")

execOps.exec {
commandLine(
"gpg",
"--homedir",
home.path,
"--batch",
"--quiet",
"--no-autostart",
"--import",
publicKey.get().asFile.path)
standardOutput = ByteArrayOutputStream()
errorOutput = ByteArrayOutputStream()
runGpg("--homedir", homedir, "--batch", "--no-autostart", "--import", toGpgPath(publicKey.get().asFile.path)) {
output ->
"Failed to import libmongocrypt signing key into scratch keyring at ${home.path}.\n$output"
}

try {
execOps.exec {
commandLine(
"gpg",
"--homedir",
home.path,
"--batch",
"--no-autostart",
"--with-colons",
"--fingerprint",
expectedFingerprint.get())
standardOutput = ByteArrayOutputStream()
errorOutput = ByteArrayOutputStream()
}
} catch (e: Exception) {
throw GradleException(
runGpg(
"--homedir",
homedir,
"--batch",
"--no-autostart",
"--with-colons",
"--fingerprint",
expectedFingerprint.get()) { output ->
"Imported libmongocrypt signing key fingerprint does not match expected value " +
"${expectedFingerprint.get()}. The downloaded public key may have been rotated.",
e)
}
"${expectedFingerprint.get()}. The downloaded public key may have been rotated.\n$output"
}

// Pair tarballs with signatures by basename; ConfigurableFileCollection.files is an
// unordered Set, so zipping the two collections could mismatch pairs.
Expand All @@ -238,28 +261,18 @@ abstract class VerifyLibmongocryptTask : DefaultTask() {
signaturesByName[signatureName]
?: throw GradleException(
"Missing signature $signatureName for ${tarball.name}; expected it next to the tarball.")
val verifyErr = ByteArrayOutputStream()
try {
execOps.exec {
commandLine(
"gpg",
"--homedir",
home.path,
"--batch",
"--quiet",
"--no-autostart",
"--trust-model",
"always",
"--verify",
signature.path,
tarball.path)
standardOutput = ByteArrayOutputStream()
errorOutput = verifyErr
runGpg(
"--homedir",
homedir,
"--batch",
"--no-autostart",
"--trust-model",
"always",
"--verify",
toGpgPath(signature.path),
toGpgPath(tarball.path)) { output ->
"GPG signature verification failed for ${tarball.name}:\n$output"
}
} catch (e: Exception) {
throw GradleException(
"GPG signature verification failed for ${tarball.name}:\n${verifyErr.toString().trim()}", e)
}
}

verificationStamp
Expand Down