Skip to content

Conversation

kevinAlbs
Copy link
Contributor

@kevinAlbs kevinAlbs commented Apr 21, 2022

GODRIVER-2352

Add Unified Test Format support for 1.8. This is a prerequisite for the Go implementation of the CSFLE Key Management API.

Background & Motivation

See mongodb/specifications@e91f0ec and mongodb/specifications@0f65908 for the Unified Test Format changes.

Notes

ClientEncryption.Close() calls Disconnect on the keyVaultClient. Client entities used as keyVaultClients are tracked to prevent the test runner from calling Disconnect twice.

@kevinAlbs kevinAlbs changed the title DRIVERS-2017 POC of ClientEncryption in Unified Test Format GODRIVER-2352 Add clientEncryption entity to unified test format May 12, 2022
@kevinAlbs kevinAlbs marked this pull request as ready for review May 12, 2022 16:37
return newEntityNotFoundError("client", ceo.KeyVaultClient)
}

ce, err := mongo.NewClientEncryption(keyVaultClient.Client, options.ClientEncryption().SetKeyVaultNamespace(ceo.KeyVaultNamespace).SetKmsProviders(kmsProviders))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Consider wrapping this line to make it easier to read.

E.g.

ce, err := mongo.NewClientEncryption(
 	keyVaultClient.Client,
 	options.ClientEncryption().
 	 	SetKeyVaultNamespace(ceo.KeyVaultNamespace).
 	 	SetKmsProviders(kmsProviders))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

// getKmsCredential processes a value of an input KMS provider credential.
// An empty document returns from the environment.
// A string is returned as-is.
func getKmsCredential(kmsDocument bson.Raw, credentialName string, defaultValue string) (*string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unless there's a specific reason to return a *string, it's typically more idiomatic to return a string and use the string zero-value ("") as the return value in case of an error.

E.g.

 func getKmsCredential(kmsDocument bson.Raw, credentialName string, defaultValue string) (string, error) {
	// ...
	return "", err
	// ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. That is good to know. My instinct is to use pointer for optional.

// getKmsCredential processes a value of an input KMS provider credential.
// An empty document returns from the environment.
// A string is returned as-is.
func getKmsCredential(kmsDocument bson.Raw, credentialName string, defaultValue string) (*string, error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: If all defaultValues come from environment variables, consider replacing the defaultValue parameter with an environment variable name parameter and perform the env var lookup in getKmsCredential. That would allow more specific messaging about any missing environment variables rather than the less specific "Please set CSFLE environment variables" message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea. Some credentials have default values and no environment variable. Updated to separate the defaultValue from the environment variable, and print the environment variable in the error message.


// CSFLEEnabled returns true if driver is built with Client Side Field Level Encryption support.
// Client Side Field Level Encryption support is enabled with the cse build tag.
func CSFLEEnabled() bool {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Functions that don't modify anything and return only a bool conventionally have "is" or "has" in the name. Consider updating to the slightly more conventional IsCSFLEEnabled().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@kevinAlbs kevinAlbs requested a review from matthewdale May 16, 2022 23:34
Copy link
Member

@prestonvasquez prestonvasquez left a comment

Choose a reason for hiding this comment

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

Very cool!

Comment on lines 760 to 761
if rob.CSFLE != nil {
if *rob.CSFLE != IsCSFLEEnabled() {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if rob.CSFLE != nil {
if *rob.CSFLE != IsCSFLEEnabled() {
if rob.CSFLE != nil && *rob.CSFLE != IsCSFLEEnabled() {

Suggestion to combine the two if lines into one to lower cyclomatic complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

if local, ok := ceo.KmsProviders["local"]; ok {
kmsProviders["local"] = make(map[string]interface{})

defaultLocalKeyBase64 := "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk"
Copy link
Member

Choose a reason for hiding this comment

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

Should this be exposed in the repository?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this local master key is used to encrypt test data. It is not sensitive, and is included in the specification test README.

if kmip, ok := ceo.KmsProviders["kmip"]; ok {
kmsProviders["kmip"] = make(map[string]interface{})

kmipEndpoint, err := getKmsCredential(kmip, "endpoint", "", "localhost:5698")
Copy link
Member

Choose a reason for hiding this comment

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

Is the port always 5698 or could this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is expected to be 5698 from the specification test README

Start a KMIP test server on port 5698 by running drivers-evergreen-tools/.evergreen/csfle/kms_kmip_server.py.

@kevinAlbs kevinAlbs requested a review from prestonvasquez May 17, 2022 17:09
Copy link
Collaborator

@matthewdale matthewdale left a comment

Choose a reason for hiding this comment

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

Looks good 👍

// A string is returned as-is.
func getKmsCredential(kmsDocument bson.Raw, credentialName string, envVar string, defaultValue string) (string, error) {
credentialVal, err := kmsDocument.LookupErr(credentialName)
if err == nil {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Consider inverting this error check to return early so you can un-indent the rest of the function code.

E.g.

credentialVal, err := kmsDocument.LookupErr(credentialName)
if err == bsoncore.ErrElementNotFound {
 	return "", nil
}
if err != nil {
 	return "", err
}
// ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

return str, nil
}

if doc, ok := credentialVal.DocumentOK(); ok {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Similar to above, consider inverting this check to return early.

E.g.

doc, ok := credentialVal.DocumentOK()
if !ok {
	return "", fmt.Errorf("expected String or Document for %v, got: %v", credentialName, credentialVal)
}
// ...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@kevinAlbs kevinAlbs merged commit cb28f46 into mongodb:master May 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants