Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to export a portion of secrets #65

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
6 changes: 5 additions & 1 deletion cmd/ejson2env/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func main() {
Name: "quiet, q",
Usage: "Suppress export statement",
},
cli.StringSliceFlag{
Name: "include, i",
Usage: "Export only a subset of environment variables",
},
}

app.Action = func(c *cli.Context) {
Expand Down Expand Up @@ -69,7 +73,7 @@ func main() {
fail(fmt.Errorf("no secrets.ejson filename passed"))
}

if err := ejson2env.ReadAndExportEnv(filename, keydir, userSuppliedPrivateKey, exportFunc); nil != err {
if err := ejson2env.ReadAndExportEnv(filename, keydir, userSuppliedPrivateKey, exportFunc, c.StringSlice("include")); nil != err {
fail(err)
}
}
Expand Down
4 changes: 4 additions & 0 deletions man/ejson2env.1.ronn
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ workflow example.
If set, assumes that the key that decrypts the passed ejson file was
passed in on standard input.

* `--include`=<key>:
If set, include in the output only the specified key(s). Can be provided
more than once.

## WORKFLOW

### 1: Add environment variables to an ejson file
Expand Down
28 changes: 26 additions & 2 deletions secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,39 @@ func IsEnvError(err error) bool {
return (errNoEnv == err || errEnvNotMap == err)
}

// FilterEnv removes any key from the secrets that's not in include.
// If include is empty, return the secrets unchanged.
func FilterEnv(originalEnv map[string]string, include []string) (map[string]string, error) {
if len(include) == 0 {
return originalEnv, nil
}

filteredEnv := make(map[string]string, len(include))
for _, key := range include {
if value, exists := originalEnv[key]; exists {
filteredEnv[key] = value
} else {
return map[string]string{}, fmt.Errorf("key not found in ejson file: %s", key)
}
}

return filteredEnv, nil
}

// ReadAndExportEnv wraps the read, extract, and export steps. Returns
// an error if any step fails.
func ReadAndExportEnv(filename, keyDir, privateKey string, exportFunc ExportFunction) error {
func ReadAndExportEnv(filename, keyDir, privateKey string, exportFunc ExportFunction, include []string) error {
envValues, err := ReadAndExtractEnv(filename, keyDir, privateKey)

if nil != err && !IsEnvError(err) {
return fmt.Errorf("could not load environment from file: %s", err)
}

exportFunc(output, envValues)
filteredEnv, err := FilterEnv(envValues, include)
if nil != err {
return err
}

exportFunc(output, filteredEnv)
return nil
}
17 changes: 13 additions & 4 deletions secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,31 @@ func TestReadAndExportEnv(t *testing.T) {
tests := []struct {
name string
exportFunc ExportFunction
include []string
expectedOutput string
}{
{
name: "ExportEnv",
exportFunc: ExportEnv,
expectedOutput: "export test_key='test value'\n",
include: make([]string, 0),
expectedOutput: "export test_key='test value'\nexport test_key_2='test value 2'\nexport test_key_3='test value 3'\n",
},
{
name: "ExportQuiet",
exportFunc: ExportQuiet,
expectedOutput: "test_key='test value'\n",
include: make([]string, 0),
expectedOutput: "test_key='test value'\ntest_key_2='test value 2'\ntest_key_3='test value 3'\n",
},
{
name: "ExportInclude",
exportFunc: ExportEnv,
include: []string{"test_key", "test_key_3"},
expectedOutput: "export test_key='test value'\nexport test_key_3='test value 3'\n",
},
}

for _, test := range tests {
err := ReadAndExportEnv("testdata/test-expected-usage.ejson", "./key", TestKeyValue, test.exportFunc)
err := ReadAndExportEnv("testdata/test-expected-usage.ejson", "./key", TestKeyValue, test.exportFunc, test.include)
if nil != err {
t.Errorf("testing %s failed: %s", test.name, err)
continue
Expand All @@ -72,7 +81,7 @@ func TestReadAndExportEnvWithBadEjson(t *testing.T) {
output = os.Stdout
}()

err = ReadAndExportEnv("bad.ejson", "./key", TestKeyValue, ExportEnv)
err = ReadAndExportEnv("bad.ejson", "./key", TestKeyValue, ExportEnv, make([]string, 0))
if nil == err {
t.Fatal("failed to fail when loading a broken ejson file")
}
Expand Down
4 changes: 3 additions & 1 deletion testdata/test-expected-usage.ejson
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"_public_key": "795e671066eef17025c816b6d7c4f5c658b191cfaa31baca69963d761606415c",
"environment": {
"test_key": "EJ[1:dgKp4cmFm42z8pfH/FJD8KRpaum5ZB6zACbuYvNFrGA=:wwS8w2C2Ihrg62M6E8H/G1Tt5gXocugo:Rv1qmluaq4HZHfr1lVtvAXxHrHsZSYio2wI=]"
"test_key": "EJ[1:dgKp4cmFm42z8pfH/FJD8KRpaum5ZB6zACbuYvNFrGA=:wwS8w2C2Ihrg62M6E8H/G1Tt5gXocugo:Rv1qmluaq4HZHfr1lVtvAXxHrHsZSYio2wI=]",
"test_key_2": "EJ[1:J2tLLU5iE4QqgzM1hOpK44jv8DhC8+1VYJGEh+2AJkE=:tRz/uG5NHkzRYmJ8+SUQMZxoMSO/gNR9:lnUJz70aqVT6Y3oQtybXHKDC88srWAhPbiqTuA==]",
"test_key_3": "EJ[1:CP6m/QOGqF4mXVzMrvuHtw9eFUq3OEJobv6AbjDgJWM=:l8rkRosxfPmzTOCdPPsC5arkwVzKj2PM:NGL6F62pADDuOfFOh6hfA2ObSYRVo1D4uMgrYQ==]"
}
}
Loading