diff --git a/cmd/esec/commands/cli.go b/cmd/esec/commands/cli.go index 532e03f..a28b10b 100644 --- a/cmd/esec/commands/cli.go +++ b/cmd/esec/commands/cli.go @@ -6,8 +6,10 @@ import ( "fmt" "github.com/alecthomas/kong" "github.com/mscno/esec" + "github.com/mscno/esec/pkg/fileutils" "io" "os" + "path" "strings" ) @@ -51,77 +53,35 @@ func (c *KeygenCmd) Run(ctx *cliCtx) error { } type EncryptCmd struct { - File string `arg:"" help:"Message to encrypt" default:""` + File string `arg:"" help:"File or Environment to encrypt" default:""` Format string `help:"File format" default:".ejson" short:"f"` DryRun bool `help:"Print the encrypted message without writing to file" short:"d"` } func (c *EncryptCmd) Run(ctx *cliCtx) error { - //var data []byte - //var err error - //if c.File != "" { - // data, err = os.ReadFile(c.File) - // if err != nil { - // return err - // } - //} - //if c.File == "" { - // data, err = io.ReadAll(os.Stdin) - // if err != nil { - // return err - // } - //} - // - //format, err := esec.detectFormat(c.File) - //if err != nil { - // return err - //} - // - //bs := bytes.NewReader(data) - //var buf bytes.Buffer - //_, err = esec.Encrypt(bs, &buf, format) - //if err != nil { - // return err - //} - //if c.File != "" && !c.DryRun { - // err = os.WriteFile(c.File, buf.Bytes(), 0644) - // if err != nil { - // return err - // } - //} else { - // fmt.Println(buf.String()) - //} - - format, err := esec.ParseFormat(c.Format) + format, err := fileutils.ParseFormat(c.Format) if err != nil { return fmt.Errorf("error parsing format flag %q: %v", c.Format, err) } - n, err := esec.EncryptInputInPlace(c.File, format) + filePath, err := processFileOrEnv(c.File, format) + if err != nil { + return fmt.Errorf("error processing file or env %q: %v", c.File, err) + } + + n, err := esec.EncryptFileInPlace(filePath) fmt.Printf("Encrypted %d bytes\n", n) return err } type DecryptCmd struct { - File string `arg:"" help:"File to decrypt" default:""` + File string `arg:"" help:"File or Environment to decrypt" default:""` Format string `help:"File format" default:".ejson" short:"f"` KeyFromStdin bool `help:"Read the key from stdin" short:"k"` KeyDir string `help:"Directory containing the '.esec_keyring' file" default:"." short:"d"` } func (c *DecryptCmd) Run(ctx *cliCtx) error { - //var reader io.Reader - //if c.File != "" { - // file, err := os.Open(c.File) - // if err != nil { - // return err - // } - // defer file.Close() - // reader = file - //} else { - // reader = os.Stdin - //} - var key string if c.KeyFromStdin { data, err := io.ReadAll(os.Stdin) @@ -132,17 +92,55 @@ func (c *DecryptCmd) Run(ctx *cliCtx) error { key = strings.TrimSpace(key) } - format, err := esec.ParseFormat(c.Format) + format, err := fileutils.ParseFormat(c.Format) if err != nil { return fmt.Errorf("error parsing format flag %q: %v", c.Format, err) } + fileName, err := processFileOrEnv(c.File, format) + if err != nil { + fmt.Errorf("error processing file or env: %v", err) + } + var buf bytes.Buffer - data, err := esec.DecryptInput(c.File, c.KeyDir, key, format) + data, err := esec.DecryptFile(fileName, c.KeyDir, key) if err != nil { return err } + buf.Read(data) fmt.Println(string(data)) return nil } + +func processFileOrEnv(input string, defaultFileFormat fileutils.FileFormat) (filename string, err error) { + // Check if input starts with any valid format + isFile := false + for _, format := range fileutils.ValidFormats() { + if strings.Contains(path.Base(input), string(format)) { + isFile = true + break + } + } + + if isFile { + return input, nil + } + + // Input is treated as an environment + environment := input + // Validate environment string + if strings.ContainsAny(environment, ".\\/") { + return "", fmt.Errorf("invalid environment name: %s - should not contain dots or path separators", input) + } + + for _, char := range environment { + if !strings.Contains("abcdefghijklmnopqrstuvwxyz0123456789", string(char)) { + return "", fmt.Errorf("invalid environment name: %s - should be lowercase alphanumeric", input) + } + } + + // Generate filename using the default format (.env) + filename = fileutils.GenerateFilename(defaultFileFormat, environment) + return path.Clean(filename), nil +} diff --git a/cmd/esec/commands/cli_test.go b/cmd/esec/commands/cli_test.go new file mode 100644 index 0000000..7b21497 --- /dev/null +++ b/cmd/esec/commands/cli_test.go @@ -0,0 +1,257 @@ +package commands + +import ( + "bytes" + "github.com/alecthomas/assert/v2" + "github.com/mscno/esec/pkg/fileutils" + "io" + "os" + "strings" + "testing" +) + +func TestKeygenCmd(t *testing.T) { + cmd := &KeygenCmd{} + + // Capture CLI output + out, err := captureOutput(func() error { + return cmd.Run(&cliCtx{}) + }) + + // Ensure no errors + assert.Equal(t, err, "") + + // Validate output contains keys + assert.Contains(t, out, "Public Key:") + assert.Contains(t, out, "Private Key:") +} + +func TestEncryptCmd(t *testing.T) { + // Create a temporary file + tmpFile, err := os.CreateTemp("", ".ejson") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) // Clean up after test + + // Write test data + _, err = tmpFile.Write([]byte(`{"ESEC_PUBLIC_KEY":"493ffcfba776a045fba526acb0baff44c9639b98b9f27123cca67c808d4e171d","secret": "test123"}`)) + assert.NoError(t, err) + tmpFile.Close() + + // Create command + cmd := &EncryptCmd{File: tmpFile.Name(), Format: ".ejson"} + + // Run command + out, errString := captureOutput(func() error { + return cmd.Run(&cliCtx{}) + }) + + // Check expected output + assert.Equal(t, errString, "") + assert.Equal(t, out, "Encrypted 347 bytes\n") +} + +func TestEncryptCmdBadFile(t *testing.T) { + // Create a temporary file + tmpFile, err := os.CreateTemp("", ".ejson") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) // Clean up after test + + // Write test data + _, err = tmpFile.Write([]byte(`{"secret": "test123"}`)) + assert.NoError(t, err) + tmpFile.Close() + + // Create command + cmd := &EncryptCmd{File: tmpFile.Name(), Format: ".ejson"} + + // Run command + out, errString := captureOutput(func() error { + return cmd.Run(&cliCtx{}) + }) + + // Check expected output + assert.Equal(t, errString, "public key not present in ecfg file") + assert.Equal(t, out, "") +} + +func TestDecryptCmd(t *testing.T) { + // Create a temporary file + tmpFile, err := os.CreateTemp("", ".ejson") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) // Clean up after test + os.Setenv("ESEC_PRIVATE_KEY", "24ab5041def8c84077bacce66524cc2ad37266ada17429e8e3c1db534dd2c2c5") + // Write test data + _, err = tmpFile.Write([]byte(`{"_ESEC_PUBLIC_KEY":"493ffcfba776a045fba526acb0baff44c9639b98b9f27123cca67c808d4e171d","secret": "ESEC[1:HMvqzjm4wFgQzL0qo6fDsgfiS1e7y1knsTvgskUEvRo=:gwjm0ng6DE3FlL8F617cRMb8cBeJ2v1b:KryYDmzxT0OxjuLlIgZHx73DhNvE]"}`)) + assert.NoError(t, err) + tmpFile.Close() + + // Create command + cmd := &DecryptCmd{File: tmpFile.Name(), Format: ".ejson"} + + // Run command + out, errString := captureOutput(func() error { + return cmd.Run(&cliCtx{}) + }) + + // Check expected output + assert.Equal(t, errString, "") + assert.Equal(t, out, "{\"_ESEC_PUBLIC_KEY\":\"493ffcfba776a045fba526acb0baff44c9639b98b9f27123cca67c808d4e171d\",\"secret\": \"hello\"}\n") +} + +func TestProcessFileOrEnv(t *testing.T) { + tests := []struct { + name string + input string + wantFilename string + wantEnv string + wantErr bool + wantErrPrefix string // partial error message to check + }{ + { + name: "simple env file", + input: ".env", + wantFilename: ".env", + wantEnv: "", + wantErr: false, + }, + { + name: "env file with environment", + input: ".env.prod", + wantFilename: ".env.prod", + wantEnv: "prod", + wantErr: false, + }, + { + name: "ejson file with environment", + input: ".ejson.staging", + wantFilename: ".ejson.staging", + wantEnv: "staging", + wantErr: false, + }, + { + name: "env string prod", + input: ".env.prod", + wantFilename: ".env.prod", + wantEnv: "prod", + wantErr: false, + }, + { + name: "env string staging", + input: ".env.staging", + wantFilename: ".env.staging", + wantEnv: "staging", + wantErr: false, + }, + { + name: "env string dev", + input: "dev", + wantFilename: ".ejson.dev", + wantEnv: "dev", + wantErr: false, + }, + { + name: "blank string", + input: "", + wantFilename: ".ejson", + wantEnv: "", + wantErr: false, + }, + { + name: "invalid file prefix", + input: ".invalid", + wantErr: true, + wantErrPrefix: "invalid environment name: .invalid - should not contain dots or path separators", + }, + { + name: "uppercase environment", + input: "PROD", + wantErr: true, + wantErrPrefix: "invalid environment name", + }, + { + name: "environment with dot", + input: "prod.test", + wantErr: true, + wantErrPrefix: "invalid environment name", + }, + { + name: "environment with slash", + input: "prod/test", + wantErr: true, + wantErrPrefix: "invalid environment name: prod/test - should not contain dots or path separators", + }, + { + name: "environment with slash", + input: "prod/.ejson", + wantErr: false, + wantFilename: "prod/.ejson", + wantEnv: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotFilename, err := processFileOrEnv(tt.input, fileutils.Ejson) + + // Check error cases + if tt.wantErr { + if err == nil { + t.Errorf("ProcessFileOrEnv() error = nil, want error with prefix %v", tt.wantErrPrefix) + return + } + if !strings.HasPrefix(err.Error(), tt.wantErrPrefix) { + t.Errorf("ProcessFileOrEnv() error = %v, want error with prefix %v", err, tt.wantErrPrefix) + } + return + } + + // Check non-error cases + if err != nil { + t.Errorf("ProcessFileOrEnv() unexpected error = %v", err) + return + } + + if gotFilename != tt.wantFilename { + t.Errorf("ProcessFileOrEnv() filename = %v, want %v", gotFilename, tt.wantFilename) + } + + //if gotEnv != tt.wantEnv { + // t.Errorf("ProcessFileOrEnv() env = %v, want %v", gotEnv, tt.wantEnv) + //} + }) + } +} + +// Helper function to capture CLI output +func captureOutput(f func() error) (string, string) { + // Save original stdout and stderr + oldOut := os.Stdout + oldErr := os.Stderr + + // Create new pipes to capture output + rOut, wOut, _ := os.Pipe() + rErr, wErr, _ := os.Pipe() + + os.Stdout = wOut + os.Stderr = wErr + + // Run function while capturing output + err := f() + if err != nil { + return "", err.Error() + } + // Close writers + wOut.Close() + wErr.Close() + + // Read output from pipes + var outBuf, errBuf bytes.Buffer + io.Copy(&outBuf, rOut) + io.Copy(&errBuf, rErr) + + // Restore original stdout and stderr + os.Stdout = oldOut + os.Stderr = oldErr + + return outBuf.String(), errBuf.String() +} diff --git a/esec.go b/esec.go index 5a92b66..e9b16ad 100644 --- a/esec.go +++ b/esec.go @@ -8,10 +8,12 @@ import ( "github.com/joho/godotenv" "github.com/mscno/esec/pkg/crypto" "github.com/mscno/esec/pkg/dotenv" + "github.com/mscno/esec/pkg/fileutils" "github.com/mscno/esec/pkg/format" "github.com/mscno/esec/pkg/json" "io" "os" + "path" "path/filepath" "strings" ) @@ -32,22 +34,15 @@ func GenerateKeypair() (pub string, priv string, err error) { type FileFormat string const ( - Env FileFormat = ".env" - Ejson FileFormat = ".ejson" - Eyaml FileFormat = ".eyaml" - Eyml FileFormat = ".eyml" - Etoml FileFormat = ".etoml" + FileFormatEnv FileFormat = ".env" + FileFormatEjson FileFormat = ".ejson" + FileFormatEyaml FileFormat = ".eyaml" + FileFormatEyml FileFormat = ".eyml" + FileFormatEtoml FileFormat = ".etoml" ) -// EncryptInputInPlace takes a string that represents a file path or an environment variable. -// It determines if the input is a file or an environment variable, and encrypts the corresponding data. -func EncryptInputInPlace(filePath string, fileFormat FileFormat) (int, error) { - filePath, _, err := processFileOrEnv(filePath, fileFormat) - if err != nil { - return -1, fmt.Errorf("error processing file or env: %v", err) - } - - return EncryptFileInPlace(filePath) +func validFormats() []FileFormat { + return []FileFormat{FileFormatEnv, FileFormatEjson, FileFormatEyaml, FileFormatEyml, FileFormatEtoml} } // EncryptFileInPlace takes a path to a file on disk, which must be a valid ecfg file @@ -66,12 +61,12 @@ func EncryptFileInPlace(filePath string) (int, error) { return -1, err } - formatType, err := ParseFormat(filePath) + formatType, err := fileutils.ParseFormat(filePath) if err != nil { return -1, err } - newdata, err := encryptData(data, formatType) + newdata, err := encryptData(data, FileFormat(formatType)) if err != nil { return -1, err } @@ -98,17 +93,12 @@ func Encrypt(in io.Reader, out io.Writer, fileFormat FileFormat) (int, error) { } func encryptData(data []byte, fileFormat FileFormat) ([]byte, error) { - // Extract the public key - var formatter format.FormatHandler - switch fileFormat { - case Env: - formatter = &dotenv.DotEnvFormatter{} - case Ejson: - formatter = &json.JsonFormatter{} - default: - return nil, fmt.Errorf("unsupported format: %s", fileFormat) + // Get the formatter for the file format + formatter, err := getFormatter(fileFormat) + if err != nil { + return nil, err } - + // Extract the public key pubkey, err := formatter.ExtractPublicKey(data) if err != nil { return nil, err @@ -131,7 +121,7 @@ func encryptData(data []byte, fileFormat FileFormat) ([]byte, error) { return formattedData, nil } -// DecryptFromVault retrieves and decrypts a file from an embedded filesystem. +// DecryptFromEmbedFS retrieves and decrypts a file from an embedded filesystem. // It determines the environment name automatically unless an override is provided. // The function reads the encrypted file based on the specified format, then decrypts it // and returns the decrypted data. @@ -144,23 +134,20 @@ func encryptData(data []byte, fileFormat FileFormat) ([]byte, error) { // Returns: // - The decrypted file content as a byte slice. // - An error if any step fails (e.g., environment detection, file reading, decryption). -func DecryptFromVault(v embed.FS, envOverride string, format FileFormat) ([]byte, error) { +func DecryptFromEmbedFS(v embed.FS, format FileFormat, envOverride string) ([]byte, error) { // Try to determine the environment name automatically. - envName, err := sniffEnvName() - if err != nil { - return nil, fmt.Errorf("error sniffing environment name: %v", err) - } - - // If an environment override is provided, use it instead of the detected name. - if envOverride != "" { - envName = envOverride + var err error + envName := envOverride + // If an environment override is not provided, use it instead of the detected name. + if envOverride == "" { + envName, err = sniffEnvName() + if err != nil { + return nil, fmt.Errorf("error sniffing environment name: %v", err) + } } // Generate the filename based on the format and environment name. - fileName, err := generateFilename(format, envName) - if err != nil { - return nil, err // Return the error if filename generation fails. - } + fileName := fileutils.GenerateFilename(fileutils.FileFormat(format), envName) // Attempt to read the file from the embedded filesystem. data, err := v.ReadFile(fileName) @@ -177,21 +164,11 @@ func DecryptFromVault(v embed.FS, envOverride string, format FileFormat) ([]byte return decryptData(privkey, data, format) } -// DecryptInput reads an encrypted input string, determines if it is a file or environment variable, and decrypts the corresponding data. -func DecryptInput(input string, keydir string, userSuppliedPrivateKey string, format FileFormat) ([]byte, error) { - fileName, _, err := processFileOrEnv(input, format) - if err != nil { - fmt.Errorf("error processing file or env: %v", err) - } - - return DecryptFile(fileName, keydir, userSuppliedPrivateKey) -} - // DecryptFile reads an encrypted file from disk, decrypts it, and returns the decrypted data. func DecryptFile(filePath string, keydir string, userSuppliedPrivateKey string) ([]byte, error) { envName, err := parseEnvironment(filePath) if err != nil { - fmt.Errorf("error processing file or env: %v", err) + fmt.Errorf("error parsing env from file: %v", err) } data, err := os.ReadFile(filePath) @@ -199,7 +176,7 @@ func DecryptFile(filePath string, keydir string, userSuppliedPrivateKey string) return nil, err } - fileFormat, err := ParseFormat(filePath) + fileFormat, err := fileutils.ParseFormat(filePath) if err != nil { return nil, err } @@ -209,7 +186,7 @@ func DecryptFile(filePath string, keydir string, userSuppliedPrivateKey string) return nil, err } - decryptedData, err := decryptData(privkey, data, fileFormat) + decryptedData, err := decryptData(privkey, data, FileFormat(fileFormat)) if err != nil { return nil, err } @@ -239,27 +216,28 @@ func Decrypt(in io.Reader, out io.Writer, envName string, fileFormat FileFormat, } func decryptData(privkey [32]byte, data []byte, fileFormat FileFormat) ([]byte, error) { - var formatter format.FormatHandler - switch fileFormat { - case Env: - formatter = &dotenv.DotEnvFormatter{} - case Ejson: - formatter = &json.JsonFormatter{} - default: - return nil, fmt.Errorf("unsupported format: %s", fileFormat) + // Get the formatter for the file format + formatter, err := getFormatter(fileFormat) + if err != nil { + return nil, err } + + // Extract the public key pubkey, err := formatter.ExtractPublicKey(data) if err != nil { return nil, err } + // Create a keypair using the extracted public and provided private keys myKP := crypto.Keypair{ Public: pubkey, Private: privkey, } + // Create a decrypter using the private key decrypter := myKP.Decrypter() + // Decrypt the data decryptedData, err := formatter.TransformScalarValues(data, decrypter.Decrypt) if err != nil { return nil, err @@ -313,3 +291,65 @@ func findPrivateKey(keyPath, envName, userSuppliedPrivateKey string) ([32]byte, // Parse and return the private key. return format.ParseKey(privKeyString) } + +// getFormatter returns the appropriate FormatHandler based on the given file format. +func getFormatter(fileFormat FileFormat) (format.FormatHandler, error) { + switch fileFormat { + case FileFormatEnv: + return &dotenv.DotEnvFormatter{}, nil + case FileFormatEjson: + return &json.JsonFormatter{}, nil + default: + return nil, fmt.Errorf("unsupported format: %s", fileFormat) + } +} + +func sniffEnvName() (string, error) { + var setKeys []string + + // Scan environment variables for keys starting with ESEC_PRIVATE_KEY + for _, envVar := range os.Environ() { + if strings.HasPrefix(envVar, EsecPrivateKey) { + key := strings.SplitN(envVar, "=", 2)[0] + setKeys = append(setKeys, key) + } + } + + switch len(setKeys) { + case 0: + return "", nil // Default to "" (blank env) if no key is found + case 1: + // Extract the environment name from the key + if setKeys[0] == EsecPrivateKey { + return "", nil + } + return strings.ToLower(strings.TrimPrefix(setKeys[0], EsecPrivateKey+"_")), nil + default: + return "", fmt.Errorf("multiple private keys found: %v", setKeys) + } +} + +// Helper functions from before +func parseEnvironment(filename string) (string, error) { + filename = path.Base(filename) + + validPrefixes := []string{string(FileFormatEnv), string(FileFormatEjson), string(FileFormatEyaml), string(FileFormatEyml), string(FileFormatEtoml)} + isValidPrefix := false + for _, prefix := range validPrefixes { + if strings.HasPrefix(filename, prefix) { + isValidPrefix = true + break + } + } + + if !isValidPrefix { + return "", fmt.Errorf("invalid file type: %s", filename) + } + + parts := strings.Split(filename, ".") + if len(parts) <= 2 { + return "", nil + } + + return parts[len(parts)-1], nil +} diff --git a/esec_test.go b/esec_test.go index 9df9c28..bc23d43 100644 --- a/esec_test.go +++ b/esec_test.go @@ -3,6 +3,7 @@ package esec import ( "bytes" "github.com/alecthomas/assert/v2" + "os" "regexp" "strings" "testing" @@ -38,7 +39,7 @@ func TestEncryptFileInPlace(t *testing.T) { func TestEncrypt(t *testing.T) { t.Run("invalid json file", func(t *testing.T) { - _, err := Encrypt(bytes.NewBuffer([]byte(`{"a": "b"]`)), bytes.NewBuffer(nil), Ejson) + _, err := Encrypt(bytes.NewBuffer([]byte(`{"a": "b"]`)), bytes.NewBuffer(nil), FileFormatEjson) if err == nil { t.Errorf("expected error, but none was received") } else if !strings.Contains(err.Error(), "invalid character") { @@ -48,7 +49,7 @@ func TestEncrypt(t *testing.T) { t.Run("invalid key", func(t *testing.T) { // invalid key - _, err := Encrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "invalid"}`)), bytes.NewBuffer(nil), Ejson) + _, err := Encrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "invalid"}`)), bytes.NewBuffer(nil), FileFormatEjson) if err == nil { t.Errorf("expected error, but none was received") } else if !strings.Contains(err.Error(), "public key has invalid format") { @@ -59,7 +60,7 @@ func TestEncrypt(t *testing.T) { t.Run("valid keypair", func(t *testing.T) { // valid keypair var output bytes.Buffer - _, err := Encrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "b"}`)), &output, Ejson) + _, err := Encrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "b"}`)), &output, FileFormatEjson) assertNoError(t, err) match := regexp.MustCompile(`{"_ESEC_PUBLIC_KEY": "8d8.*", "a": "ESEC.*"}`) if match.Find(output.Bytes()) == nil { @@ -71,7 +72,7 @@ func TestEncrypt(t *testing.T) { func TestDecryptFile(t *testing.T) { t.Run("invalid json file", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"a": "b"]`)), bytes.NewBuffer(nil), "", Ejson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"a": "b"]`)), bytes.NewBuffer(nil), "", FileFormatEjson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") if err == nil { t.Errorf("expected error, but none was received") } else if !strings.Contains(err.Error(), "invalid character") { @@ -81,7 +82,7 @@ func TestDecryptFile(t *testing.T) { t.Run("missing key", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"_missing": "invalid"}`)), bytes.NewBuffer(nil), "", Ejson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"_missing": "invalid"}`)), bytes.NewBuffer(nil), "", FileFormatEjson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") if err == nil { t.Errorf("expected error, but none was received") } else { @@ -93,7 +94,7 @@ func TestDecryptFile(t *testing.T) { t.Run("invalid key", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "invalid"}`)), bytes.NewBuffer(nil), "", Ejson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "invalid"}`)), bytes.NewBuffer(nil), "", FileFormatEjson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") if err == nil { t.Errorf("expected error, but none was received") } else { @@ -105,7 +106,7 @@ func TestDecryptFile(t *testing.T) { t.Run("invalid file and invalid message format", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "b"}`)), bytes.NewBuffer(nil), "", Ejson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "b"}`)), bytes.NewBuffer(nil), "", FileFormatEjson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") if err == nil { t.Errorf("expected error, but none was received") } else { @@ -117,7 +118,7 @@ func TestDecryptFile(t *testing.T) { t.Run("valid file, but invalid keypath", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "ESEC[1:KR1IxNZnTZQMP3OR1NdOpDQ1IcLD83FSuE7iVNzINDk=:XnYW1HOxMthBFMnxWULHlnY4scj5mNmX:ls1+kvwwu2ETz5C6apgWE7Q=]"}`)), bytes.NewBuffer(nil), "", Ejson, "/tmp", "") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "ESEC[1:KR1IxNZnTZQMP3OR1NdOpDQ1IcLD83FSuE7iVNzINDk=:XnYW1HOxMthBFMnxWULHlnY4scj5mNmX:ls1+kvwwu2ETz5C6apgWE7Q=]"}`)), bytes.NewBuffer(nil), "", FileFormatEjson, "/tmp", "") if err == nil { t.Errorf("expected error, but none was received") } else { @@ -129,7 +130,7 @@ func TestDecryptFile(t *testing.T) { t.Run("valid file, but invalid userkey", func(t *testing.T) { // invalid json file - _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "ESEC[1:KR1IxNZnTZQMP3OR1NdOpDQ1IcLD83FSuE7iVNzINDk=:XnYW1HOxMthBFMnxWULHlnY4scj5mNmX:ls1+kvwwu2ETz5C6apgWE7Q=]"}`)), bytes.NewBuffer(nil), "", Ejson, "", "586518639ad138d6c0ce76ce6fc30f54a40e3c5e066b93f0151cebe0ee6ea391") + _, err := Decrypt(bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "ESEC[1:KR1IxNZnTZQMP3OR1NdOpDQ1IcLD83FSuE7iVNzINDk=:XnYW1HOxMthBFMnxWULHlnY4scj5mNmX:ls1+kvwwu2ETz5C6apgWE7Q=]"}`)), bytes.NewBuffer(nil), "", FileFormatEjson, "", "586518639ad138d6c0ce76ce6fc30f54a40e3c5e066b93f0151cebe0ee6ea391") if err == nil { t.Errorf("expected error, but none was received") } else { @@ -146,7 +147,7 @@ func TestDecryptFile(t *testing.T) { bytes.NewBuffer([]byte(`{"_ESEC_PUBLIC_KEY": "8d8647e2eeb6d2e31228e6df7da3df921ec3b799c3f66a171cd37a1ed3004e7d", "a": "ESEC[1:KR1IxNZnTZQMP3OR1NdOpDQ1IcLD83FSuE7iVNzINDk=:XnYW1HOxMthBFMnxWULHlnY4scj5mNmX:ls1+kvwwu2ETz5C6apgWE7Q=]"}`)), &out, "", - Ejson, + FileFormatEjson, "", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") assertNoError(t, err) @@ -156,3 +157,105 @@ func TestDecryptFile(t *testing.T) { } }) } + +func TestSniffEnvName(t *testing.T) { + tests := []struct { + name string + envVars map[string]string + wantEnv string + wantErr bool + wantErrPrefix string + }{ + { + name: "No environment variables set", + envVars: map[string]string{}, + wantEnv: "", + wantErr: false, + }, + { + name: "Only ESEC_PRIVATE_KEY set", + envVars: map[string]string{"ESEC_PRIVATE_KEY": "somevalue"}, + wantEnv: "", + wantErr: false, + }, + { + name: "One valid ESEC_PRIVATE_KEY with environment", + envVars: map[string]string{"ESEC_PRIVATE_KEY_PROD": "somevalue"}, + wantEnv: "prod", + wantErr: false, + }, + { + name: "One valid ESEC_PRIVATE_KEY with uppercase environment", + envVars: map[string]string{"ESEC_PRIVATE_KEY_STAGING": "somevalue"}, + wantEnv: "staging", // Should return lowercase + wantErr: false, + }, + { + name: "Multiple private keys found", + envVars: map[string]string{ + "ESEC_PRIVATE_KEY_PROD": "somevalue", + "ESEC_PRIVATE_KEY_DEV": "somevalue", + "ESEC_PRIVATE_KEY_STAGING": "somevalue", + }, + wantErr: true, + wantErrPrefix: "multiple private keys found", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Backup original environment + originalEnv := os.Environ() + defer func() { + os.Clearenv() + for _, e := range originalEnv { + parts := splitEnvVar(e) + if len(parts) == 2 { + os.Setenv(parts[0], parts[1]) + } + } + }() + + // Set up test environment variables + os.Clearenv() + for key, value := range tt.envVars { + os.Setenv(key, value) + } + + // Run SniffEnvName() + gotEnv, err := sniffEnvName() + + // Check error case + if tt.wantErr { + if err == nil { + t.Errorf("SniffEnvName() error = nil, want error with prefix %v", tt.wantErrPrefix) + return + } + if !containsPrefix(err.Error(), tt.wantErrPrefix) { + t.Errorf("SniffEnvName() error = %v, want error with prefix %v", err, tt.wantErrPrefix) + } + return + } + + // Check non-error case + if err != nil { + t.Errorf("SniffEnvName() unexpected error = %v", err) + return + } + + if gotEnv != tt.wantEnv { + t.Errorf("SniffEnvName() = %v, want %v", gotEnv, tt.wantEnv) + } + }) + } +} + +// Helper function to split an environment variable string (KEY=VALUE) +func splitEnvVar(envVar string) []string { + return strings.SplitN(envVar, "=", 2) +} + +// Helper function to check if an error message contains a prefix +func containsPrefix(errMsg, prefix string) bool { + return len(errMsg) >= len(prefix) && errMsg[:len(prefix)] == prefix +} diff --git a/helper.go b/helper.go deleted file mode 100644 index a930c8c..0000000 --- a/helper.go +++ /dev/null @@ -1,141 +0,0 @@ -package esec - -import ( - "fmt" - "os" - "path" - "path/filepath" - "strings" -) - -// ParseFormat attempts to determine the format type based on the file prefix. -func ParseFormat(input string) (FileFormat, error) { - formats := []FileFormat{Env, Ejson, Eyaml, Eyml, Etoml} - - base := filepath.Base(input) - for _, format := range formats { - if strings.HasPrefix(base, string(format)) { - return format, nil - } - } - - return "", fmt.Errorf("unsupported format: %s", input) -} - -func processFileOrEnv(input string, defaultFileFormat FileFormat) (filename string, environment string, err error) { - // First, check if it's a valid filename by looking for valid prefixes - validFormats := map[FileFormat]bool{ - Env: true, - Ejson: true, - Eyaml: true, - Eyml: true, - Etoml: true, - } - - // Check if input starts with any valid format - isFile := false - for format := range validFormats { - if strings.Contains(path.Base(input), string(format)) { - isFile = true - break - } - } - - if isFile { - // Input is a filename, parse the environment from it - environment, err = parseEnvironment(path.Base(input)) - if err != nil { - return "", "", fmt.Errorf("invalid filename: %v", err) - } - return input, environment, nil - } - - // Input is treated as an environment - environment = input - // Validate environment string - if strings.ContainsAny(environment, ".\\/") { - return "", "", fmt.Errorf("invalid environment name: %s - should not contain dots or path separators", input) - } - - for _, char := range environment { - if !strings.Contains("abcdefghijklmnopqrstuvwxyz0123456789", string(char)) { - return "", "", fmt.Errorf("invalid environment name: %s - should be lowercase alphanumeric", input) - } - } - - if !isFile { - // Generate filename using the default format (.env) - filename, err = generateFilename(defaultFileFormat, environment) - if err != nil { - return "", "", fmt.Errorf("error generating filename: %v", err) - } - } - - return path.Clean(filename), input, nil -} - -// Helper functions from before -func parseEnvironment(filename string) (string, error) { - filename = path.Base(filename) - - validPrefixes := []string{string(Env), string(Ejson), string(Eyaml), string(Eyml), string(Etoml)} - isValidPrefix := false - for _, prefix := range validPrefixes { - if strings.HasPrefix(filename, prefix) { - isValidPrefix = true - break - } - } - - if !isValidPrefix { - return "", fmt.Errorf("invalid file type: %s", filename) - } - - parts := strings.Split(filename, ".") - if len(parts) <= 2 { - return "", nil - } - - return parts[len(parts)-1], nil -} - -func generateFilename(format FileFormat, environment string) (string, error) { - validFormats := map[FileFormat]bool{ - Env: true, Ejson: true, Eyaml: true, Eyml: true, Etoml: true, - } - - if !validFormats[format] { - return "", fmt.Errorf("invalid format: %s", format) - } - - if environment == "" { - return string(format), nil - } - - return fmt.Sprintf("%s.%s", format, environment), nil -} - -func sniffEnvName() (string, error) { - var setKeys []string - - // Scan environment variables for keys starting with ESEC_PRIVATE_KEY - for _, envVar := range os.Environ() { - if strings.HasPrefix(envVar, EsecPrivateKey) { - key := strings.SplitN(envVar, "=", 2)[0] - setKeys = append(setKeys, key) - } - } - - switch len(setKeys) { - case 0: - return "", nil // Default to "" (blank env) if no key is found - case 1: - // Extract the environment name from the key - if setKeys[0] == EsecPrivateKey { - return "", nil - } - return strings.ToLower(strings.TrimPrefix(setKeys[0], EsecPrivateKey+"_")), nil - default: - return "", fmt.Errorf("multiple private keys found: %v", setKeys) - } -} diff --git a/helper_test.go b/helper_test.go deleted file mode 100644 index 04e7885..0000000 --- a/helper_test.go +++ /dev/null @@ -1,233 +0,0 @@ -package esec - -import ( - "os" - "strings" - "testing" -) - -func TestProcessFileOrEnv(t *testing.T) { - tests := []struct { - name string - input string - wantFilename string - wantEnv string - wantErr bool - wantErrPrefix string // partial error message to check - }{ - { - name: "simple env file", - input: ".env", - wantFilename: ".env", - wantEnv: "", - wantErr: false, - }, - { - name: "env file with environment", - input: ".env.prod", - wantFilename: ".env.prod", - wantEnv: "prod", - wantErr: false, - }, - { - name: "ejson file with environment", - input: ".ejson.staging", - wantFilename: ".ejson.staging", - wantEnv: "staging", - wantErr: false, - }, - { - name: "env string prod", - input: ".env.prod", - wantFilename: ".env.prod", - wantEnv: "prod", - wantErr: false, - }, - { - name: "env string staging", - input: ".env.staging", - wantFilename: ".env.staging", - wantEnv: "staging", - wantErr: false, - }, - { - name: "env string dev", - input: "dev", - wantFilename: ".ejson.dev", - wantEnv: "dev", - wantErr: false, - }, - { - name: "blank string", - input: "", - wantFilename: ".ejson", - wantEnv: "", - wantErr: false, - }, - { - name: "invalid file prefix", - input: ".invalid", - wantErr: true, - wantErrPrefix: "invalid environment name: .invalid - should not contain dots or path separators", - }, - { - name: "uppercase environment", - input: "PROD", - wantErr: true, - wantErrPrefix: "invalid environment name", - }, - { - name: "environment with dot", - input: "prod.test", - wantErr: true, - wantErrPrefix: "invalid environment name", - }, - { - name: "environment with slash", - input: "prod/test", - wantErr: true, - wantErrPrefix: "invalid environment name: prod/test - should not contain dots or path separators", - }, - { - name: "environment with slash", - input: "prod/.ejson", - wantErr: false, - wantFilename: "prod/.ejson", - wantEnv: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotFilename, gotEnv, err := processFileOrEnv(tt.input, Ejson) - - // Check error cases - if tt.wantErr { - if err == nil { - t.Errorf("processFileOrEnv() error = nil, want error with prefix %v", tt.wantErrPrefix) - return - } - if !strings.HasPrefix(err.Error(), tt.wantErrPrefix) { - t.Errorf("processFileOrEnv() error = %v, want error with prefix %v", err, tt.wantErrPrefix) - } - return - } - - // Check non-error cases - if err != nil { - t.Errorf("processFileOrEnv() unexpected error = %v", err) - return - } - - if gotFilename != tt.wantFilename { - t.Errorf("processFileOrEnv() filename = %v, want %v", gotFilename, tt.wantFilename) - } - - if gotEnv != tt.wantEnv { - t.Errorf("processFileOrEnv() env = %v, want %v", gotEnv, tt.wantEnv) - } - }) - } -} - -func TestSniffEnvName(t *testing.T) { - tests := []struct { - name string - envVars map[string]string - wantEnv string - wantErr bool - wantErrPrefix string - }{ - { - name: "No environment variables set", - envVars: map[string]string{}, - wantEnv: "", - wantErr: false, - }, - { - name: "Only ESEC_PRIVATE_KEY set", - envVars: map[string]string{EsecPrivateKey: "somevalue"}, - wantEnv: "", - wantErr: false, - }, - { - name: "One valid ESEC_PRIVATE_KEY with environment", - envVars: map[string]string{"ESEC_PRIVATE_KEY_PROD": "somevalue"}, - wantEnv: "prod", - wantErr: false, - }, - { - name: "One valid ESEC_PRIVATE_KEY with uppercase environment", - envVars: map[string]string{"ESEC_PRIVATE_KEY_STAGING": "somevalue"}, - wantEnv: "staging", // Should return lowercase - wantErr: false, - }, - { - name: "Multiple private keys found", - envVars: map[string]string{ - "ESEC_PRIVATE_KEY_PROD": "somevalue", - "ESEC_PRIVATE_KEY_DEV": "somevalue", - "ESEC_PRIVATE_KEY_STAGING": "somevalue", - }, - wantErr: true, - wantErrPrefix: "multiple private keys found", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // Backup original environment - originalEnv := os.Environ() - defer func() { - os.Clearenv() - for _, e := range originalEnv { - parts := splitEnvVar(e) - if len(parts) == 2 { - os.Setenv(parts[0], parts[1]) - } - } - }() - - // Set up test environment variables - os.Clearenv() - for key, value := range tt.envVars { - os.Setenv(key, value) - } - - // Run sniffEnvName() - gotEnv, err := sniffEnvName() - - // Check error case - if tt.wantErr { - if err == nil { - t.Errorf("sniffEnvName() error = nil, want error with prefix %v", tt.wantErrPrefix) - return - } - if !containsPrefix(err.Error(), tt.wantErrPrefix) { - t.Errorf("sniffEnvName() error = %v, want error with prefix %v", err, tt.wantErrPrefix) - } - return - } - - // Check non-error case - if err != nil { - t.Errorf("sniffEnvName() unexpected error = %v", err) - return - } - - if gotEnv != tt.wantEnv { - t.Errorf("sniffEnvName() = %v, want %v", gotEnv, tt.wantEnv) - } - }) - } -} - -// Helper function to split an environment variable string (KEY=VALUE) -func splitEnvVar(envVar string) []string { - return strings.SplitN(envVar, "=", 2) -} - -// Helper function to check if an error message contains a prefix -func containsPrefix(errMsg, prefix string) bool { - return len(errMsg) >= len(prefix) && errMsg[:len(prefix)] == prefix -} diff --git a/pkg/crypto/crypto.go b/pkg/crypto/crypto.go index 989b4c5..ccb2c29 100644 --- a/pkg/crypto/crypto.go +++ b/pkg/crypto/crypto.go @@ -116,10 +116,6 @@ func (e *Encrypter) encrypt(message []byte) (*boxedMessage, error) { if err != nil { return nil, err } - fmt.Printf("Encrypting message with nonce %x\n", nonce) - fmt.Printf("Encrypter public key: %x\n", e.Keypair.Public) - fmt.Printf("Encrypter private key: %x\n", e.Keypair.Private) - fmt.Printf("Decrypter public key: %x\n", e.PeerPublic) out := box.SealAfterPrecomputation(nil, message, &nonce, &e.SharedKey) return &boxedMessage{ diff --git a/pkg/fileutils/fileformats.go b/pkg/fileutils/fileformats.go new file mode 100644 index 0000000..d7c7856 --- /dev/null +++ b/pkg/fileutils/fileformats.go @@ -0,0 +1,40 @@ +package fileutils + +import ( + "fmt" + "path/filepath" + "strings" +) + +type FileFormat string + +const ( + Env FileFormat = ".env" + Ejson FileFormat = ".ejson" + Eyaml FileFormat = ".eyaml" + Eyml FileFormat = ".eyml" + Etoml FileFormat = ".etoml" +) + +func ValidFormats() []FileFormat { + return []FileFormat{Env, Ejson, Eyaml, Eyml, Etoml} +} + +// ParseFormat attempts to determine the format type based on the file prefix. +func ParseFormat(input string) (FileFormat, error) { + base := filepath.Base(input) + for _, format := range ValidFormats() { + if strings.HasPrefix(base, string(format)) { + return format, nil + } + } + + return "", fmt.Errorf("unsupported format: %s", input) +} + +func GenerateFilename(format FileFormat, environment string) string { + if environment != "" { + return fmt.Sprintf("%s.%s", format, environment) + } + return string(format) +} diff --git a/pkg/fileutils/fileformats_test.go b/pkg/fileutils/fileformats_test.go new file mode 100644 index 0000000..9beb2b1 --- /dev/null +++ b/pkg/fileutils/fileformats_test.go @@ -0,0 +1,68 @@ +package fileutils + +import ( + "fmt" + "github.com/alecthomas/assert/v2" + "testing" +) + +func TestGenerateFilename(t *testing.T) { + tests := []struct { + format FileFormat + environment string + expected string + }{ + {Env, "", ".env"}, + {Ejson, "", ".ejson"}, + {Eyaml, "prod", ".eyaml.prod"}, + {Eyml, "staging", ".eyml.staging"}, + {Etoml, "dev", ".etoml.dev"}, + } + + for _, tt := range tests { + t.Run(fmt.Sprintf("%s-%s", tt.format, tt.environment), func(t *testing.T) { + got := GenerateFilename(tt.format, tt.environment) + if got != tt.expected { + t.Errorf("GenerateFilename(%q, %q) = %q; want %q", tt.format, tt.environment, got, tt.expected) + } + }) + } +} + +func TestParseFormat_ValidFormats(t *testing.T) { + tests := []struct { + input string + expected FileFormat + }{ + {".env", Env}, + {".ejson", Ejson}, + {".eyaml", Eyaml}, + {".eyml", Eyml}, + {".etoml", Etoml}, + } + + for _, tt := range tests { + t.Run(tt.input, func(t *testing.T) { + format, err := ParseFormat(tt.input) + assert.NoError(t, err) + assert.Equal(t, tt.expected, format) + }) + } +} + +func TestParseFormat_InvalidFormats(t *testing.T) { + tests := []string{ + "config.txt", + "secrets.yaml", + "data.json", + "unknown.file", + } + + for _, input := range tests { + t.Run(input, func(t *testing.T) { + format, err := ParseFormat(input) + assert.Error(t, err) + assert.Equal(t, format, "") + }) + } +} diff --git a/testdata/embed_test.go b/testdata/embed_test.go index 3d749f5..29651ec 100644 --- a/testdata/embed_test.go +++ b/testdata/embed_test.go @@ -8,26 +8,26 @@ import ( ) func TestEmbedDecryptWithNoVars(t *testing.T) { - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "private key not found in environment variables, and keyring file does not exist at \".esec-keyring\"") } func TestEmbedDecryptWithNoVarsAndOverride(t *testing.T) { - _, err := esec.DecryptFromVault(TestEmbed, "dev", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "dev", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "private key not found in environment variables, and keyring file does not exist at \".esec-keyring\"") } func TestEmbedDecryptWithNoVarsAndMissingFile(t *testing.T) { - _, err := esec.DecryptFromVault(TestEmbed, "missing", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "missing", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "error reading file from vault: open .ejson.missing: file does not exist") } func TestEmbedDecryptBadKey(t *testing.T) { os.Setenv("ESEC_PRIVATE_KEY", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "couldn't decrypt message") } @@ -35,26 +35,26 @@ func TestEmbedDecryptBadKey(t *testing.T) { func TestEmbedDecryptMultipleKeys(t *testing.T) { os.Setenv("ESEC_PRIVATE_KEY", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") os.Setenv("ESEC_PRIVATE_KEYS", "c5caa31a5b8cb2be0074b37c56775f533b368b81d8fd33b94181f79bd6e47f87") - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "error sniffing environment name: multiple private keys found: [ESEC_PRIVATE_KEY ESEC_PRIVATE_KEYS]") } func TestEmbedDecryptGoodKey(t *testing.T) { os.Setenv("ESEC_PRIVATE_KEY", "24ab5041def8c84077bacce66524cc2ad37266ada17429e8e3c1db534dd2c2c5") - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.NoError(t, err) } func TestEmbedDecryptGoodKeyWithDevSuffix(t *testing.T) { os.Setenv("ESEC_PRIVATE_KEY_DEV", "24ab5041def8c84077bacce66524cc2ad37266ada17429e8e3c1db534dd2c2c5") - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.NoError(t, err) } func TestEmbedDecryptGoodKeyWithMissingSuffix(t *testing.T) { os.Setenv("ESEC_PRIVATE_KEY_MISSING", "24ab5041def8c84077bacce66524cc2ad37266ada17429e8e3c1db534dd2c2c5") - _, err := esec.DecryptFromVault(TestEmbed, "", esec.Ejson) + _, err := esec.DecryptFromEmbedFS(TestEmbed, "", esec.FileFormatEjson) assert.Error(t, err) assert.Contains(t, err.Error(), "error reading file from vault: open .ejson.missing: file does not exist") }