Skip to content

Commit

Permalink
Merge pull request #109 from nitrictech/feature/secret-local
Browse files Browse the repository at this point in the history
Add local dev secret plugin
  • Loading branch information
jyecusch authored Aug 4, 2021
2 parents 7ff20fa + 7cb1b76 commit 2da56cc
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.5.2
github.com/golang/snappy v0.0.3 // indirect
github.com/google/addlicense v0.0.0-20210727174409-874627749a46
github.com/google/addlicense v0.0.0-20210729153508-ef04bb38a16b
github.com/google/uuid v1.1.2
github.com/googleapis/gax-go/v2 v2.0.5
github.com/mitchellh/mapstructure v1.4.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ github.com/google/addlicense v0.0.0-20210428195630-6d92264d7170 h1:jLUa4MO3autxl
github.com/google/addlicense v0.0.0-20210428195630-6d92264d7170/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA=
github.com/google/addlicense v0.0.0-20210727174409-874627749a46 h1:1locMH9PVZH3LXvogcvdTxf2/9J4YT/9W3BSXrTN4/U=
github.com/google/addlicense v0.0.0-20210727174409-874627749a46/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA=
github.com/google/addlicense v0.0.0-20210729153508-ef04bb38a16b h1:KwI0NOpYd3rzKojfjeRerF7rzjeTwvJARVsgGf5TWmY=
github.com/google/addlicense v0.0.0-20210729153508-ef04bb38a16b/go.mod h1:EMjYTRimagHs1FwlIqKyX3wAM0u3rA+McvlIIWmSamA=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
Expand Down
123 changes: 123 additions & 0 deletions pkg/plugins/secret/dev/dev.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2021 Nitric Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package secret_service

import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/google/uuid"
"github.com/nitric-dev/membrane/pkg/plugins/secret"
"github.com/nitric-dev/membrane/pkg/utils"
)

const DEFAULT_DIR = ".nitric/secrets/"

type DevSecretService struct {
secret.UnimplementedSecretPlugin
secDir string
}

func (s *DevSecretService) secretFileName(sec *secret.Secret, v string) string {
return fmt.Sprintf("%s/%s_%s.txt", s.secDir, sec.Name, v)
}

func (s *DevSecretService) Put(sec *secret.Secret, val []byte) (*secret.SecretPutResponse, error) {
if sec == nil {
return nil, fmt.Errorf("provide non-empty secret")
}
if len(sec.Name) == 0 {
return nil, fmt.Errorf("provide non-blank secret name")
}
if len(val) == 0 {
return nil, fmt.Errorf("provide non-blank secret value")
}

var versionId = uuid.New().String()
//Creates a new file in the form:
// DIR/Name_Version.txt
file, err := os.Create(s.secretFileName(sec, versionId))
if err != nil {
return nil, fmt.Errorf("error creating secret store: %v", err)
}
writer := bufio.NewWriter(file)
writer.WriteString(string(val))
writer.Flush()

//Creates a new file as latest
latestFile, err := os.Create(s.secretFileName(sec, "latest"))
if err != nil {
return nil, fmt.Errorf("error creating latest secret: %v", err)
}
latestWriter := bufio.NewWriter(latestFile)
latestWriter.WriteString(string(val))
latestWriter.WriteString("," + versionId)
latestWriter.Flush()

return &secret.SecretPutResponse{
SecretVersion: &secret.SecretVersion{
Secret: &secret.Secret{
Name: sec.Name,
},
Version: versionId,
},
}, nil
}

func (s *DevSecretService) Access(sv *secret.SecretVersion) (*secret.SecretAccessResponse, error) {
if sv.Secret.Name == "" {
return nil, fmt.Errorf("provide non-blank name")
}
if sv.Version == "" {
return nil, fmt.Errorf("provide non-blank version")
}

content, err := ioutil.ReadFile(s.secretFileName(sv.Secret, sv.Version))
if err != nil {
return nil, fmt.Errorf("error reading secret store: %v", err)
}

splitContent := strings.Split(string(content), ",")
return &secret.SecretAccessResponse{
SecretVersion: &secret.SecretVersion{
Secret: &secret.Secret{
Name: sv.Secret.Name,
},
Version: splitContent[len(splitContent)-1],
},
Value: []byte(splitContent[0]),
}, nil
}

//Create new secret store
func New() (secret.SecretService, error) {
secDir := utils.GetEnv("LOCAL_SEC_DIR", DEFAULT_DIR)

//Check whether file exists
_, err := os.Stat(secDir)
if os.IsNotExist(err) {
//Make directory if not present
err := os.MkdirAll(secDir, 0777)
if err != nil {
return nil, err
}
}
return &DevSecretService{
secDir: secDir,
}, nil
}
27 changes: 27 additions & 0 deletions pkg/plugins/secret/dev/dev_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2021 Nitric Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package secret_service_test

import (
"testing"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

func TestPubsub(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Dev Secret Plugin Suite")
}
148 changes: 148 additions & 0 deletions pkg/plugins/secret/dev/dev_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright 2021 Nitric Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package secret_service_test

import (
"os"

"github.com/nitric-dev/membrane/pkg/plugins/secret"
secretPlugin "github.com/nitric-dev/membrane/pkg/plugins/secret/dev"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("Dev Secret Manager", func() {
os.Setenv("LOCAL_SEC_DIR", "./.nitric/")

AfterSuite(func() {
// Cleanup default secrect directory
os.RemoveAll("./.nitric/")
})

testSecret := secret.Secret{
Name: "Test",
}
testSecretVal := []byte("Super Secret Message")
When("Put", func() {
When("Putting a secret to a non-existent secret", func() {
secretPlugin, _ := secretPlugin.New()
It("Should successfully store a secret", func() {
response, err := secretPlugin.Put(&testSecret, testSecretVal)
By("Not returning an error")
Expect(err).ShouldNot(HaveOccurred())

By("Returning a non nil response")
Expect(response).ShouldNot(BeNil())
})
})
When("Putting a secret to an existing secret", func() {
secretPlugin, _ := secretPlugin.New()
It("Should succesfully store a secret", func() {
response, err := secretPlugin.Put(&testSecret, testSecretVal)
By("Not returning an error")
Expect(err).ShouldNot(HaveOccurred())

By("Returning a non nil response")
Expect(response).ShouldNot(BeNil())
})
})
When("Putting a secret with an empty name", func() {
secretPlugin, _ := secretPlugin.New()
It("Should throw an error", func() {
emptySecretName := &secret.Secret{}
response, err := secretPlugin.Put(emptySecretName, testSecretVal)
By("Returning an error")
Expect(err).Should(HaveOccurred())

By("Returning a nil response")
Expect(response).Should(BeNil())
})
})
})
When("Get", func() {
When("Getting a secret that exists", func() {
secretPlugin, _ := secretPlugin.New()
It("Should return the secret", func() {
putResponse, _ := secretPlugin.Put(&testSecret, testSecretVal)
response, err := secretPlugin.Access(putResponse.SecretVersion)
By("Not returning an error")
Expect(err).ShouldNot(HaveOccurred())
By("Returning a response")
Expect(response.SecretVersion.Secret.Name).Should(Equal(testSecret.Name))
Expect(response.Value).Should(Equal(testSecretVal))
})
})
When("Getting the latest secret", func() {
secretPlugin, _ := secretPlugin.New()
It("Should return the latest secret", func() {
putResponse, _ := secretPlugin.Put(&testSecret, testSecretVal)
response, err := secretPlugin.Access(&secret.SecretVersion{
Secret: &secret.Secret{
Name: testSecret.Name,
},
Version: "latest",
})
By("Not returning an error")
Expect(err).ShouldNot(HaveOccurred())
By("Returning a response")
Expect(response.SecretVersion.Secret.Name).Should(Equal(testSecret.Name))
Expect(response.SecretVersion.Version).Should(Equal(putResponse.SecretVersion.Version))
Expect(response.Value).Should(Equal(testSecretVal))
})
})
When("Getting a secret that doesn't exist", func() {
secretPlugin, _ := secretPlugin.New()
It("Should return an error", func() {
response, err := secretPlugin.Access(&secret.SecretVersion{
Secret: &secret.Secret{
Name: "test-id",
},
Version: "test-version-id",
})
By("Returning an error")
Expect(err).Should(HaveOccurred())
By("Returning a nil response")
Expect(response).Should(BeNil())
})
})
When("Getting a secret with an empty id", func() {
secretPlugin, _ := secretPlugin.New()
It("Should return an error", func() {
response, err := secretPlugin.Access(&secret.SecretVersion{
Secret: &secret.Secret{},
Version: "test-version-id",
})
By("Returning an error")
Expect(err).Should(HaveOccurred())
By("Returning a nil response")
Expect(response).Should(BeNil())
})
})
When("Getting a secret with an empty version id", func() {
secretPlugin, _ := secretPlugin.New()
It("Should return an error", func() {
response, err := secretPlugin.Access(&secret.SecretVersion{
Secret: &secret.Secret{
Name: "test-id",
},
})
By("Returning an error")
Expect(err).Should(HaveOccurred())
By("Returning a nil response")
Expect(response).Should(BeNil())
})
})
})
})
3 changes: 3 additions & 0 deletions pkg/providers/dev/membrane.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
gateway_plugin "github.com/nitric-dev/membrane/pkg/plugins/gateway/dev"
queue_service "github.com/nitric-dev/membrane/pkg/plugins/queue/dev"
boltdb_storage_service "github.com/nitric-dev/membrane/pkg/plugins/storage/boltdb"
secret_service "github.com/nitric-dev/membrane/pkg/plugins/secret/dev"
)

func main() {
Expand All @@ -35,6 +36,7 @@ func main() {
signal.Notify(term, os.Interrupt, syscall.SIGTERM)
signal.Notify(term, os.Interrupt, syscall.SIGINT)

secretPlugin, _ := secret_service.New()
documentPlugin, _ := boltdb_service.New()
eventsPlugin, _ := events_service.New()
gatewayPlugin, _ := gateway_plugin.New()
Expand All @@ -47,6 +49,7 @@ func main() {
GatewayPlugin: gatewayPlugin,
QueuePlugin: queuePlugin,
StoragePlugin: storagePlugin,
SecretPlugin: secretPlugin,
})

if err != nil {
Expand Down

0 comments on commit 2da56cc

Please sign in to comment.