From 93570b20d774e4b6a129d7ca7bf25f19e1eeecc1 Mon Sep 17 00:00:00 2001 From: Adrian Utrilla Date: Tue, 12 Sep 2017 09:59:23 -0700 Subject: [PATCH] Fix golint errors --- Makefile | 2 +- cmd/sops/codes/codes.go | 2 ++ cmd/sops/common/common.go | 32 ++++++++++++----- cmd/sops/decrypt.go | 17 +++++---- cmd/sops/edit.go | 10 +++--- cmd/sops/encrypt.go | 2 +- cmd/sops/main.go | 16 ++++----- cmd/sops/rotate.go | 2 +- cmd/sops/set.go | 2 +- cmd/sops/subcommand/groups/add.go | 4 ++- cmd/sops/subcommand/groups/delete.go | 4 ++- cmd/sops/subcommand/keyservice/keyservice.go | 2 ++ {yaml => config}/config.go | 4 ++- {yaml => config}/config_test.go | 2 +- {yaml => config}/test_resources/example.yaml | 0 keyservice/client.go | 6 ++++ keyservice/keyservice.go | 1 + keyservice/server.go | 10 ++++-- kms/keysource.go | 2 ++ pgp/keysource.go | 4 ++- sops.go | 36 +++++++++++--------- stores/stores.go | 5 ++- stores/yaml/store.go | 4 +-- 23 files changed, 107 insertions(+), 62 deletions(-) rename {yaml => config}/config.go (94%) rename {yaml => config}/config_test.go (99%) rename {yaml => config}/test_resources/example.yaml (100%) diff --git a/Makefile b/Makefile index c5af1a2c6..e051f18d9 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ test: $(GO) test -coverprofile=coverage_tmp.txt -covermode=atomic $(PROJECT) && cat coverage_tmp.txt >> coverage.txt $(GO) test $(PROJECT)/aes -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt $(GO) test $(PROJECT)/cmd/sops -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt - $(GO) test $(PROJECT)/yaml -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt + $(GO) test $(PROJECT)/config -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt $(GO) test $(PROJECT)/stores/yaml -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt $(GO) test $(PROJECT)/stores/json -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt gpg --import pgp/sops_functional_tests_key.asc 2>&1 1>/dev/null || exit 0 diff --git a/cmd/sops/codes/codes.go b/cmd/sops/codes/codes.go index c7e83205c..c1bef5379 100644 --- a/cmd/sops/codes/codes.go +++ b/cmd/sops/codes/codes.go @@ -1,5 +1,7 @@ +// Package codes the exit statuses returned by the sops binary package codes +// Exit statuses returned by the binary const ( CouldNotReadInputFile int = 2 CouldNotWriteOutputFile int = 3 diff --git a/cmd/sops/common/common.go b/cmd/sops/common/common.go index b6fa9873a..f25c1ab38 100644 --- a/cmd/sops/common/common.go +++ b/cmd/sops/common/common.go @@ -12,16 +12,23 @@ import ( "gopkg.in/urfave/cli.v1" ) +// DecryptTreeOpts are the options needed to decrypt a tree type DecryptTreeOpts struct { - Tree *sops.Tree - Stash map[string][]interface{} + // Tree is the tree to be decrypted + Tree *sops.Tree + // Stash is a map to save information between encryption-decryption round-trips, such as IVs + Stash map[string][]interface{} + // KeyServices are the key services to be used for decryption of the data key KeyServices []keyservice.KeyServiceClient - IgnoreMac bool - Cipher sops.DataKeyCipher + // IgnoreMac is whether or not to ignore the Message Authentication Code included in the SOPS tree + IgnoreMac bool + // Cipher is the cryptographic cipher to use to decrypt the values inside the tree + Cipher sops.DataKeyCipher } -func DecryptTree(opts DecryptTreeOpts) ([]byte, error) { - dataKey, err := opts.Tree.Metadata.GetDataKeyWithKeyServices(opts.KeyServices) +// DecryptTree decrypts the tree passed in through the DecryptTreeOpts and additionally returns the decrypted data key +func DecryptTree(opts DecryptTreeOpts) (dataKey []byte, err error) { + dataKey, err = opts.Tree.Metadata.GetDataKeyWithKeyServices(opts.KeyServices) if err != nil { return nil, cli.NewExitError(err.Error(), codes.CouldNotRetrieveKey) } @@ -42,13 +49,19 @@ func DecryptTree(opts DecryptTreeOpts) ([]byte, error) { return dataKey, nil } +// EncryptTreeOpts are the options needed to encrypt a tree type EncryptTreeOpts struct { - Tree *sops.Tree - Stash map[string][]interface{} - Cipher sops.DataKeyCipher + // Tree is the tree to be encrypted + Tree *sops.Tree + // Stash is a map to save information between encryption-decryption round-trips, such as IVs + Stash map[string][]interface{} + // Cipher is the cryptographic cipher to use to encrypt the values inside the tree + Cipher sops.DataKeyCipher + // DataKey is the key the cipher should use to encrypt the values inside the tree DataKey []byte } +// EncryptTree encrypts the tree passed in through the EncryptTreeOpts func EncryptTree(opts EncryptTreeOpts) error { mac, err := opts.Tree.Encrypt(opts.DataKey, opts.Cipher, opts.Stash) if err != nil { @@ -63,6 +76,7 @@ func EncryptTree(opts EncryptTreeOpts) error { return nil } +// LoadEncryptedFile loads an encrypted SOPS file, returning a SOPS tree func LoadEncryptedFile(inputStore sops.Store, inputPath string) (*sops.Tree, error) { fileBytes, err := ioutil.ReadFile(inputPath) if err != nil { diff --git a/cmd/sops/decrypt.go b/cmd/sops/decrypt.go index f0502a037..eb5c3e45c 100644 --- a/cmd/sops/decrypt.go +++ b/cmd/sops/decrypt.go @@ -20,7 +20,7 @@ type decryptOpts struct { KeyServices []keyservice.KeyServiceClient } -func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) { +func decrypt(opts decryptOpts) (decryptedFile []byte, err error) { tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) if err != nil { return nil, err @@ -38,7 +38,7 @@ func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) { } if len(opts.Extract) > 0 { - return Extract(tree, opts.Extract, opts.OutputStore) + return extract(tree, opts.Extract, opts.OutputStore) } decryptedFile, err = opts.OutputStore.Marshal(tree.Branch) if err != nil { @@ -47,7 +47,7 @@ func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) { return decryptedFile, err } -func Extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (output []byte, err error) { +func extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (output []byte, err error) { v, err := tree.Branch.Truncate(path) if err != nil { return nil, fmt.Errorf("error truncating tree: %s", err) @@ -59,11 +59,10 @@ func Extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (outpu return nil, cli.NewExitError(fmt.Sprintf("Error dumping file: %s", err), codes.ErrorDumpingTree) } return decrypted, err - } else { - bytes, err := outputStore.MarshalValue(v) - if err != nil { - return nil, cli.NewExitError(fmt.Sprintf("Error dumping tree: %s", err), codes.ErrorDumpingTree) - } - return bytes, nil } + bytes, err := outputStore.MarshalValue(v) + if err != nil { + return nil, cli.NewExitError(fmt.Sprintf("Error dumping tree: %s", err), codes.ErrorDumpingTree) + } + return bytes, nil } diff --git a/cmd/sops/edit.go b/cmd/sops/edit.go index c5e6369f2..44d0f79cc 100644 --- a/cmd/sops/edit.go +++ b/cmd/sops/edit.go @@ -76,7 +76,7 @@ type runEditorUntilOkOpts struct { Tree *sops.Tree } -func EditExample(opts editExampleOpts) ([]byte, error) { +func editExample(opts editExampleOpts) ([]byte, error) { // Load the example file var fileBytes []byte if _, ok := opts.InputStore.(*json.BinaryStore); ok { @@ -109,10 +109,10 @@ func EditExample(opts editExampleOpts) ([]byte, error) { } stash := make(map[string][]interface{}) - return edit(opts.editOpts, &tree, dataKey, stash) + return editTree(opts.editOpts, &tree, dataKey, stash) } -func Edit(opts editOpts) ([]byte, error) { +func edit(opts editOpts) ([]byte, error) { // Load the file tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) if err != nil { @@ -127,10 +127,10 @@ func Edit(opts editOpts) ([]byte, error) { return nil, err } - return edit(opts, tree, dataKey, stash) + return editTree(opts, tree, dataKey, stash) } -func edit(opts editOpts, tree *sops.Tree, dataKey []byte, stash map[string][]interface{}) ([]byte, error) { +func editTree(opts editOpts, tree *sops.Tree, dataKey []byte, stash map[string][]interface{}) ([]byte, error) { // Create temporary file for editing tmpdir, err := ioutil.TempDir("", "") if err != nil { diff --git a/cmd/sops/encrypt.go b/cmd/sops/encrypt.go index 342f14c3c..9de763b2e 100644 --- a/cmd/sops/encrypt.go +++ b/cmd/sops/encrypt.go @@ -23,7 +23,7 @@ type encryptOpts struct { GroupQuorum int } -func Encrypt(opts encryptOpts) (encryptedFile []byte, err error) { +func encrypt(opts encryptOpts) (encryptedFile []byte, err error) { // Load the file fileBytes, err := ioutil.ReadFile(opts.InputPath) if err != nil { diff --git a/cmd/sops/main.go b/cmd/sops/main.go index 8507feec6..145a7b9a5 100644 --- a/cmd/sops/main.go +++ b/cmd/sops/main.go @@ -30,7 +30,7 @@ import ( "go.mozilla.org/sops/pgp" "go.mozilla.org/sops/stores/json" yamlstores "go.mozilla.org/sops/stores/yaml" - "go.mozilla.org/sops/yaml" + "go.mozilla.org/sops/config" "gopkg.in/urfave/cli.v1" ) @@ -306,7 +306,7 @@ func main() { if err != nil { return err } - output, err = Encrypt(encryptOpts{ + output, err = encrypt(encryptOpts{ OutputStore: outputStore, InputStore: inputStore, InputPath: fileName, @@ -326,7 +326,7 @@ func main() { if err != nil { return cli.NewExitError(fmt.Errorf("error parsing --extract path: %s", err), codes.InvalidTreePathFormat) } - output, err = Decrypt(decryptOpts{ + output, err = decrypt(decryptOpts{ OutputStore: outputStore, InputStore: inputStore, InputPath: fileName, @@ -356,7 +356,7 @@ func main() { for _, k := range pgp.MasterKeysFromFingerprintString(c.String("add-pgp")) { rmMasterKeys = append(rmMasterKeys, k) } - output, err = Rotate(rotateOpts{ + output, err = rotate(rotateOpts{ OutputStore: outputStore, InputStore: inputStore, InputPath: fileName, @@ -376,7 +376,7 @@ func main() { if err != nil { return err } - output, err = Set(setOpts{ + output, err = set(setOpts{ OutputStore: outputStore, InputStore: inputStore, InputPath: fileName, @@ -405,14 +405,14 @@ func main() { ShowMasterKeys: c.Bool("show-master-keys"), } if fileExists { - output, err = Edit(opts) + output, err = edit(opts) } else { // File doesn't exist, edit the example file instead keyGroups, err := keyGroups(c, fileName) if err != nil { return err } - output, err = EditExample(editExampleOpts{ + output, err = editExample(editExampleOpts{ editOpts: opts, UnencryptedSuffix: c.String("unencrypted-suffix"), KeyGroups: keyGroups, @@ -557,7 +557,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) { return nil, cli.NewExitError(fmt.Sprintf("Error loading config file: %s", err), codes.ErrorReadingConfig) } } - groups, err := yaml.KeyGroupsForFile(file, confBytes, kmsEncryptionContext) + groups, err := config.KeyGroupsForFile(file, confBytes, kmsEncryptionContext) if err != nil { return nil, err } diff --git a/cmd/sops/rotate.go b/cmd/sops/rotate.go index 707cd0666..be38daf8e 100644 --- a/cmd/sops/rotate.go +++ b/cmd/sops/rotate.go @@ -22,7 +22,7 @@ type rotateOpts struct { KeyServices []keyservice.KeyServiceClient } -func Rotate(opts rotateOpts) ([]byte, error) { +func rotate(opts rotateOpts) ([]byte, error) { tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) if err != nil { return nil, err diff --git a/cmd/sops/set.go b/cmd/sops/set.go index 2cffae7f0..474638418 100644 --- a/cmd/sops/set.go +++ b/cmd/sops/set.go @@ -21,7 +21,7 @@ type setOpts struct { KeyServices []keyservice.KeyServiceClient } -func Set(opts setOpts) ([]byte, error) { +func set(opts setOpts) ([]byte, error) { // Load the file // TODO: Issue #173: if the file does not exist, create it with the contents passed in as opts.Value tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) diff --git a/cmd/sops/subcommand/groups/add.go b/cmd/sops/subcommand/groups/add.go index 30efa528d..69215943f 100644 --- a/cmd/sops/subcommand/groups/add.go +++ b/cmd/sops/subcommand/groups/add.go @@ -8,6 +8,7 @@ import ( "go.mozilla.org/sops/keyservice" ) +// AddOpts are the options for adding a key group to a SOPS file type AddOpts struct { InputPath string InputStore sops.Store @@ -18,6 +19,7 @@ type AddOpts struct { KeyServices []keyservice.KeyServiceClient } +// Add adds a key group to a SOPS file func Add(opts AddOpts) error { tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) if err != nil { @@ -37,7 +39,7 @@ func Add(opts AddOpts) error { if err != nil { return err } - var outputFile *os.File = os.Stdout + var outputFile = os.Stdout if opts.InPlace { var err error outputFile, err = os.Create(opts.InputPath) diff --git a/cmd/sops/subcommand/groups/delete.go b/cmd/sops/subcommand/groups/delete.go index 35422f56c..00a461396 100644 --- a/cmd/sops/subcommand/groups/delete.go +++ b/cmd/sops/subcommand/groups/delete.go @@ -8,6 +8,7 @@ import ( "go.mozilla.org/sops/keyservice" ) +// DeleteOpts are the options for deleting a key group from a SOPS file type DeleteOpts struct { InputPath string InputStore sops.Store @@ -25,6 +26,7 @@ func min(a, b int) int { return a } +// Delete deletes a key group from a SOPS file func Delete(opts DeleteOpts) error { tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath) if err != nil { @@ -47,7 +49,7 @@ func Delete(opts DeleteOpts) error { if err != nil { return err } - var outputFile *os.File = os.Stdout + var outputFile = os.Stdout if opts.InPlace { var err error outputFile, err = os.Create(opts.InputPath) diff --git a/cmd/sops/subcommand/keyservice/keyservice.go b/cmd/sops/subcommand/keyservice/keyservice.go index 69043a3d3..11c2eeea3 100644 --- a/cmd/sops/subcommand/keyservice/keyservice.go +++ b/cmd/sops/subcommand/keyservice/keyservice.go @@ -12,11 +12,13 @@ import ( "google.golang.org/grpc" ) +// Opts are the options the key service server can take type Opts struct { Network string Address string } +// Run runs a SOPS key service server func Run(opts Opts) error { lis, err := net.Listen(opts.Network, opts.Address) if err != nil { diff --git a/yaml/config.go b/config/config.go similarity index 94% rename from yaml/config.go rename to config/config.go index b18678e3d..160076fee 100644 --- a/yaml/config.go +++ b/config/config.go @@ -1,4 +1,4 @@ -package yaml //import "go.mozilla.org/sops/yaml" +package config //import "go.mozilla.org/sops/config" import ( "fmt" @@ -71,6 +71,8 @@ func (f *configFile) load(bytes []byte) error { return nil } +// KeyGroupsForFile returns the key groups that should be use for a given file, based on the file's path and the +// configuration func KeyGroupsForFile(filepath string, confBytes []byte, kmsEncryptionContext map[string]*string) ([]sops.KeyGroup, error) { var err error if confBytes == nil { diff --git a/yaml/config_test.go b/config/config_test.go similarity index 99% rename from yaml/config_test.go rename to config/config_test.go index dc4ad257e..5d3c0d2af 100644 --- a/yaml/config_test.go +++ b/config/config_test.go @@ -1,4 +1,4 @@ -package yaml +package config import ( "os" diff --git a/yaml/test_resources/example.yaml b/config/test_resources/example.yaml similarity index 100% rename from yaml/test_resources/example.yaml rename to config/test_resources/example.yaml diff --git a/keyservice/client.go b/keyservice/client.go index f5f171074..8fa6cb7b9 100644 --- a/keyservice/client.go +++ b/keyservice/client.go @@ -6,19 +6,25 @@ import ( "google.golang.org/grpc" ) +// LocalClient is a key service client that performs all operations locally type LocalClient struct { Server Server } +// NewLocalClient creates a new local client func NewLocalClient() LocalClient { return LocalClient{Server{}} } +// Decrypt processes a decrypt request locally +// See keyservice/server.go for more details func (c LocalClient) Decrypt(ctx context.Context, req *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) { return c.Server.Decrypt(ctx, req) } +// Encrypt processes an encrypt request locally +// See keyservice/server.go for more details func (c LocalClient) Encrypt(ctx context.Context, req *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) { return c.Server.Encrypt(ctx, req) diff --git a/keyservice/keyservice.go b/keyservice/keyservice.go index 193b9e615..2bc16acdf 100644 --- a/keyservice/keyservice.go +++ b/keyservice/keyservice.go @@ -8,6 +8,7 @@ import ( "go.mozilla.org/sops/pgp" ) +// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers func KeyFromMasterKey(mk keys.MasterKey) Key { switch mk := mk.(type) { case *pgp.MasterKey: diff --git a/keyservice/server.go b/keyservice/server.go index cb9120ff6..7b3cca51a 100644 --- a/keyservice/server.go +++ b/keyservice/server.go @@ -6,8 +6,10 @@ import ( "golang.org/x/net/context" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) +// Server is a key service server that uses SOPS MasterKeys to fulfill requests type Server struct{} func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error) { @@ -58,6 +60,8 @@ func (ks *Server) decryptWithKms(key *KmsKey, ciphertext []byte) ([]byte, error) return []byte(plaintext), err } +// Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted +// result func (ks Server) Encrypt(ctx context.Context, req *EncryptRequest) (*EncryptResponse, error) { key := *req.Key @@ -79,12 +83,14 @@ func (ks Server) Encrypt(ctx context.Context, Ciphertext: ciphertext, }, nil case nil: - return nil, grpc.Errorf(codes.NotFound, "Must provide a key") + return nil, status.Errorf(codes.NotFound, "Must provide a key") default: - return nil, grpc.Errorf(codes.NotFound, "Unknown key type") + return nil, status.Errorf(codes.NotFound, "Unknown key type") } } +// Decrypt takes a decrypt request and decrypts the provided ciphertext with the provided key, returning the decrypted +// result func (ks Server) Decrypt(ctx context.Context, req *DecryptRequest) (*DecryptResponse, error) { key := *req.Key diff --git a/kms/keysource.go b/kms/keysource.go index 243dd3b7a..70d2b8092 100644 --- a/kms/keysource.go +++ b/kms/keysource.go @@ -33,10 +33,12 @@ type MasterKey struct { EncryptionContext map[string]*string } +// EncryptedDataKey returns the encrypted data key this master key holds func (key *MasterKey) EncryptedDataKey() []byte { return []byte(key.EncryptedKey) } +// SetEncryptedDataKey sets the encrypted data key for this master key func (key *MasterKey) SetEncryptedDataKey(enc []byte) { key.EncryptedKey = string(enc) } diff --git a/pgp/keysource.go b/pgp/keysource.go index 2b3e1e4cb..115ca01da 100644 --- a/pgp/keysource.go +++ b/pgp/keysource.go @@ -28,10 +28,12 @@ type MasterKey struct { CreationDate time.Time } +// EncryptedDataKey returns the encrypted data key this master key holds func (key *MasterKey) EncryptedDataKey() []byte { return []byte(key.EncryptedKey) } +// SetEncryptedDataKey sets the encrypted data key for this master key func (key *MasterKey) SetEncryptedDataKey(enc []byte) { key.EncryptedKey = string(enc) } @@ -77,7 +79,7 @@ func (key *MasterKey) encryptWithCryptoOpenPGP(dataKey []byte) error { fingerprints := key.fingerprintMap(ring) entity, ok := fingerprints[key.Fingerprint] if !ok { - return fmt.Errorf("Key with fingerprint %s is not available in keyring.", key.Fingerprint) + return fmt.Errorf("key with fingerprint %s is not available in keyring", key.Fingerprint) } encbuf := new(bytes.Buffer) armorbuf, err := armor.Encode(encbuf, "PGP MESSAGE", nil) diff --git a/sops.go b/sops.go index 3d22afa8f..ab35d2c18 100644 --- a/sops.go +++ b/sops.go @@ -1,5 +1,5 @@ /* -Package Sops manages JSON, YAML and BINARY documents to be encrypted or decrypted. +Package sops manages JSON, YAML and BINARY documents to be encrypted or decrypted. This package should not be used directly. Instead, Sops users should install the command line client via `go get -u go.mozilla.org/sops/cmd/sops`, or use the @@ -112,9 +112,9 @@ type Tree struct { } // Truncate truncates the tree to the path specified -func (tree TreeBranch) Truncate(path []interface{}) (interface{}, error) { +func (branch TreeBranch) Truncate(path []interface{}) (interface{}, error) { log.Printf("Truncating tree to %s", path) - var current interface{} = tree + var current interface{} = branch for _, component := range path { switch component := component.(type) { case string: @@ -142,7 +142,7 @@ func (tree TreeBranch) Truncate(path []interface{}) (interface{}, error) { return current, nil } -func (tree TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (interface{}, error) { +func (branch TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (interface{}, error) { switch in := in.(type) { case string: return onLeaves(in, path) @@ -155,20 +155,20 @@ func (tree TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in case float64: return onLeaves(in, path) case TreeBranch: - return tree.walkBranch(in, path, onLeaves) + return branch.walkBranch(in, path, onLeaves) case []interface{}: - return tree.walkSlice(in, path, onLeaves) + return branch.walkSlice(in, path, onLeaves) default: return nil, fmt.Errorf("Cannot walk value, unknown type: %T", in) } } -func (tree TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) ([]interface{}, error) { +func (branch TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) ([]interface{}, error) { for i, v := range in { if _, ok := v.(Comment); ok { continue } - newV, err := tree.walkValue(v, path, onLeaves) + newV, err := branch.walkValue(v, path, onLeaves) if err != nil { return nil, err } @@ -177,7 +177,7 @@ func (tree TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func( return in, nil } -func (tree TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (TreeBranch, error) { +func (branch TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (TreeBranch, error) { for i, item := range in { if _, ok := item.Key.(Comment); ok { continue @@ -187,7 +187,7 @@ func (tree TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in return nil, fmt.Errorf("Tree contains a non-string key (type %T): %s. Only string keys are"+ "supported", item.Key, item.Key) } - newV, err := tree.walkValue(item.Value, append(path, key), onLeaves) + newV, err := branch.walkValue(item.Value, append(path, key), onLeaves) if err != nil { return nil, err } @@ -282,7 +282,7 @@ func (tree Tree) GenerateDataKey() ([]byte, []error) { return newKey, tree.Metadata.UpdateMasterKeys(newKey) } -// GenerateDataKey generates a new random data key and encrypts it with all MasterKeys. +// GenerateDataKeyWithKeyServices generates a new random data key and encrypts it with all MasterKeys. func (tree *Tree) GenerateDataKeyWithKeyServices(svcs []keyservice.KeyServiceClient) ([]byte, []error) { newKey := make([]byte, 32) _, err := rand.Read(newKey) @@ -306,6 +306,7 @@ type Metadata struct { DataKey []byte } +// KeyGroup is a slice of SOPS MasterKeys that all encrypt the same part of the data key type KeyGroup []keys.MasterKey // Store provides a way to load and save the sops tree along with metadata @@ -326,10 +327,11 @@ func (m *Metadata) MasterKeyCount() int { return count } +// UpdateMasterKeysWithKeyServices encrypts the data key with all master keys using the provided key services func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyservice.KeyServiceClient) (errs []error) { if len(svcs) == 0 { return []error{ - fmt.Errorf("No key services provided, cansnot update master keys."), + fmt.Errorf("no key services provided, cannot update master keys"), } } var parts [][]byte @@ -345,11 +347,11 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser log.Printf("Multiple KeyGroups found, proceeding with Shamir with quorum %d", m.ShamirQuorum) parts, err = shamir.Split(dataKey, len(m.KeyGroups), m.ShamirQuorum) if err != nil { - errs = append(errs, fmt.Errorf("Could not split data key into parts for Shamir: %s", err)) + errs = append(errs, fmt.Errorf("could not split data key into parts for Shamir: %s", err)) return } if len(parts) != len(m.KeyGroups) { - errs = append(errs, fmt.Errorf("Not enough parts obtained from Shamir. Need %d, got %d", len(m.KeyGroups), len(parts))) + errs = append(errs, fmt.Errorf("not enough parts obtained from Shamir: need %d, got %d", len(m.KeyGroups), len(parts))) return } } @@ -365,7 +367,7 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser Plaintext: part, }) if err != nil { - keyErrs = append(keyErrs, fmt.Errorf("Failed to encrypt new data key with master key %q: %v\n", key.ToString(), err)) + keyErrs = append(keyErrs, fmt.Errorf("failed to encrypt new data key with master key %q: %v", key.ToString(), err)) continue } key.SetEncryptedDataKey(rsp.Ciphertext) @@ -423,12 +425,12 @@ func (m Metadata) GetDataKeyWithKeyServices(svcs []keyservice.KeyServiceClient) var dataKey []byte if len(m.KeyGroups) > 1 { if len(parts) < m.ShamirQuorum { - return nil, fmt.Errorf("Not enough parts to recover data key with Shamir. Need %d, have %d.", m.ShamirQuorum, len(parts)) + return nil, fmt.Errorf("not enough parts to recover data key with Shamir: need %d, have %d", m.ShamirQuorum, len(parts)) } var err error dataKey, err = shamir.Combine(parts) if err != nil { - return nil, fmt.Errorf("Could not get data key from shamir parts: %s", err) + return nil, fmt.Errorf("could not get data key from shamir parts: %s", err) } } else { if len(parts) != 1 { diff --git a/stores/stores.go b/stores/stores.go index b7571eb1f..76b3d7eaf 100644 --- a/stores/stores.go +++ b/stores/stores.go @@ -10,12 +10,13 @@ import ( "go.mozilla.org/sops/pgp" ) +// SopsFile is a struct used by the stores as a helper unmarshal the SOPS metadata type SopsFile struct { Data interface{} `yaml:"data" json:"data"` Metadata Metadata `yaml:"sops" json:"sops"` } -// metadata is stored in SOPS encrypted files, and it contains the information necessary to decrypt the file. +// Metadata is stored in SOPS encrypted files, and it contains the information necessary to decrypt the file. // This struct is just used for serialization, and SOPS uses another struct internally, sops.Metadata. It exists // in order to allow the binary format to stay backwards compatible over time, but at the same time allow the internal // representation SOPS uses to change over time. @@ -49,6 +50,7 @@ type kmskey struct { EncryptedDataKey string `yaml:"enc" json:"enc"` } +// MetadataFromInternal converts an internal SOPS metadata representation to a representation appropriate for storage func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata { var m Metadata m.LastModified = sopsMetadata.LastModified.Format(time.RFC3339) @@ -101,6 +103,7 @@ func kmsKeysFromGroup(group sops.KeyGroup) (keys []kmskey) { return } +// ToInternal converts a storage-appropriate Metadata struct to a SOPS internal representation func (m *Metadata) ToInternal() (sops.Metadata, error) { lastModified, err := time.Parse(time.RFC3339, m.LastModified) if err != nil { diff --git a/stores/yaml/store.go b/stores/yaml/store.go index 021522734..e6b672192 100644 --- a/stores/yaml/store.go +++ b/stores/yaml/store.go @@ -134,14 +134,14 @@ func (store Store) MarshalWithMetadata(tree sops.TreeBranch, metadata sops.Metad return out, nil } -// MarshalInterface takes any value and marshals it into a yaml document +// MarshalValue takes any value and marshals it into a yaml document func (store Store) MarshalValue(v interface{}) ([]byte, error) { v = store.treeValueToYamlValue(v) return (&yaml.YAMLMarshaler{Indent: 4}).Marshal(v) } // UnmarshalMetadata takes a yaml document as a string and extracts sops' metadata from it -func (s *Store) UnmarshalMetadata(in []byte) (sops.Metadata, error) { +func (store *Store) UnmarshalMetadata(in []byte) (sops.Metadata, error) { file := stores.SopsFile{} err := yaml.Unmarshal(in, &file) if err != nil {