Skip to content

Commit

Permalink
feat: implement CreateSecret and DeleteSecret operations (#35)
Browse files Browse the repository at this point in the history
Closes #33.
Add create secret and delete secret operations to the SDK.
  • Loading branch information
michaelsauter committed Jun 26, 2023
1 parent eee8425 commit 6f30855
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ _artifacts
**/*/bin
mage_output_file.go
dist/
/test_config.json
10 changes: 2 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,8 @@ Create `test_config.json`:
const roleName = "test-role"
```

`vault/secret_test.go` declares:

```golang
const secretName = "/test/secret"
```

The tests assume that `roleName` can exists and has privilege to create, read,
and delete a client, and read `secretName`.
The tests assume that `roleName` exists and has privilege to create, read,
and delete a client, as well as create, read and delete secrets with a `test:` path prefix.

## Use

Expand Down
36 changes: 35 additions & 1 deletion vault/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ type Secret struct {
secretResource
}

// Secret gets the secret at path from the DSV of the given tenant
// Secret [gets the secret] at path from the DSV of the given tenant.
//
// [gets the secret]: https://dsv.secretsvaultcloud.com/api#operation/getSecret
func (v Vault) Secret(path string) (*Secret, error) {
data, err := v.accessResource(http.MethodGet, secretsResource, path, nil)
if err != nil {
Expand All @@ -36,3 +38,35 @@ func (v Vault) Secret(path string) (*Secret, error) {
}
return secret, nil
}

// DeleteSecret [deletes the secret] at path from the DSV of the given tenant.
//
// [deletes the secret]: https://dsv.secretsvaultcloud.com/api#operation/deleteSecret
func (v Vault) DeleteSecret(path string) error {
_, err := v.accessResource(http.MethodDelete, secretsResource, path, nil)
return err
}

// SecretCreateRequest represents the request body of the CreateSecret operation.
type SecretCreateRequest struct {
Attributes map[string]interface{} `json:"attributes"`
Data map[string]interface{} `json:"data"`
Description string `json:"description"`
}

// CreateSecret [creates the secret] at path in the DSV of the given tenant.
//
// [creates the secret]: https://dsv.secretsvaultcloud.com/api#operation/createSecret
func (v Vault) CreateSecret(path string, req *SecretCreateRequest) (*Secret, error) {
d, err := v.accessResource(http.MethodPost, secretsResource, path, req)
if err != nil {
return nil, err
}

secret := &Secret{}
if err := json.Unmarshal(d, secret); err != nil {
log.Printf("[DEBUG] error parsing response from /%s/%s: %q", secretsResource, path, d)
return nil, err
}
return secret, nil
}
80 changes: 75 additions & 5 deletions vault/secret_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,90 @@
//go:build integration
package vault

import "testing"
import (
"math/rand"
"testing"
"time"
)

const secretName = "/test/secret"
const letterBytes = "abcdefghijklmnopqrstuvwxyz"

func init() {
rand.Seed(time.Now().UnixNano())
}

// TestSecret tests Secret
func TestSecret(t *testing.T) {
secret, err := dsv.Secret(secretName)
path := makeRandomSecretPath()
_, cleanup := createSecret(t, path)
defer cleanup()

secret, err := dsv.Secret(path)

if err != nil {
t.Fatalf("Secret for path=%s: %s", path, err)
return
}

if secret.Data == nil {
t.Error("secret.Data is nil")
}
}

func TestCreateSecret(t *testing.T) {
path := makeRandomSecretPath()
secret, err := dsv.CreateSecret(
path, &SecretCreateRequest{Data: map[string]interface{}{"foo": "bar"}},
)

if err != nil {
t.Error("calling secrets.Secret:", err)
t.Fatalf("CreateSecret for path=%s: %s", path, err)
return
} else {
defer func() { deleteSecret(t, path) }()
}

if secret.Data == nil {
t.Error("secret.Data is nil")
}
}

func TestDeleteSecret(t *testing.T) {
path := makeRandomSecretPath()
_, _ = createSecret(t, path) // no cleanup required as test tries to delete anyway

err := dsv.DeleteSecret(path)
if err != nil {
t.Errorf("DeleteSecret for path=%s: %s", path, err)
}
}

// createSecret creates a secret with given path and returns the created secret as well
// as a cleanup function which should be deferred to remove the secret from the vault.
func createSecret(t *testing.T, path string) (s *Secret, cleanup func()) {
t.Helper()
s, err := dsv.CreateSecret(path, &SecretCreateRequest{Data: map[string]interface{}{
"foo": "bar",
}})
if err != nil {
t.Fatal(err)
}
cleanup = func() { deleteSecret(t, path) }
return
}

// deleteSecret deletes the secret given by path from the vault.
func deleteSecret(t *testing.T, path string) {
t.Helper()
if err := dsv.DeleteSecret(path); err != nil {
t.Fatal(err)
}
}

// makeRandomSecretPath creates a pseudo-random secret path.
func makeRandomSecretPath() string {
b := make([]byte, 10)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return "test:" + string(b)
}

0 comments on commit 6f30855

Please sign in to comment.