Skip to content

Commit

Permalink
Merge pull request #2 from adamgoose/doppler
Browse files Browse the repository at this point in the history
Adding Doppler Provider
  • Loading branch information
jondot authored Mar 27, 2021
2 parents f68d454 + 26205ac commit b7fbc13
Show file tree
Hide file tree
Showing 218 changed files with 37,122 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mocks:
mockgen -source pkg/providers/aws_ssm.go -destination pkg/providers/mock_providers/aws_ssm_mock.go
mockgen -source pkg/providers/consul.go -destination pkg/providers/mock_providers/consul_mock.go
mockgen -source pkg/providers/dotenv.go -destination pkg/providers/mock_providers/dotenv_mock.go
mockgen -source pkg/providers/doppler.go -destination pkg/providers/mock_providers/doppler_mock.go
mockgen -source pkg/providers/etcd.go -destination pkg/providers/mock_providers/etcd_mock.go
mockgen -source pkg/providers/google_secretmanager.go -destination pkg/providers/mock_providers/google_secretmanager_mock.go
mockgen -source pkg/providers/hashicorp_vault.go -destination pkg/providers/mock_providers/hashicorp_vault_mock.go
Expand Down
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,32 @@ dotenv:
path: ~/my-dot-env.env
```

## Doppler

### Authentication

Install the [doppler cli][dopplercli] then run `doppler login`. You'll also need to configure your desired "project" for any given directory using `doppler configure`. Alternatively, you can set a global project by running `doppler configure set project <my-project>` from your home directory.

### Features

* Sync - `yes`
* Mapping - `yes`
* Key format
* `env` - env key like

### Example Config

```yaml
doppler:
env_sync:
path: prd
env:
MG_KEY:
path: prd
field: OTHER_MG_KEY # (optional)
```

[dopplercli]: https://docs.doppler.com/docs/cli

# Security Model

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/Azure/go-autorest/autorest/azure/auth v0.5.7 // indirect
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
github.com/Azure/go-autorest/autorest/validation v0.3.1 // indirect
github.com/DopplerHQ/cli v0.0.0-20210309042056-414bede8a50e
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38
github.com/alecthomas/colour v0.1.0 // indirect
github.com/alecthomas/kong v0.2.15
Expand Down
49 changes: 49 additions & 0 deletions go.sum

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions pkg/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (p *BuiltinProviders) ProviderHumanToMachine() map[string]string {
".env": "dotenv",
"Vercel": "vercel",
"Azure Key Vault": "azure_keyvault",
"Doppler": "doppler",
}
}

Expand All @@ -52,6 +53,8 @@ func (p *BuiltinProviders) GetProvider(name string) (core.Provider, error) {
return providers.NewVercel()
case "azure_keyvault":
return providers.NewAzureKeyVault()
case "doppler":
return providers.NewDoppler()
default:
return nil, fmt.Errorf("provider %s does not exist", name)
}
Expand Down
99 changes: 99 additions & 0 deletions pkg/providers/doppler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package providers

import (
"fmt"
"sort"

"github.com/DopplerHQ/cli/pkg/configuration"
"github.com/DopplerHQ/cli/pkg/http"
"github.com/DopplerHQ/cli/pkg/models"
"github.com/DopplerHQ/cli/pkg/utils"
"github.com/spectralops/teller/pkg/core"
)

type DopplerClient interface {
GetSecrets(host string, verifyTLS bool, apiKey string, project string, config string) ([]byte, http.Error)
}

type dopplerClient struct{}

func (dopplerClient) GetSecrets(host string, verifyTLS bool, apiKey, project, config string) ([]byte, http.Error) {
return http.GetSecrets(host, verifyTLS, apiKey, project, config)
}

type Doppler struct {
client DopplerClient
config models.ScopedOptions
}

func NewDoppler() (core.Provider, error) {
configuration.Setup()
configuration.LoadConfig()

return &Doppler{
client: dopplerClient{},
config: configuration.Get(configuration.Scope),
}, nil
}

func (h *Doppler) Name() string {
return "doppler"
}

func (h *Doppler) GetMapping(p core.KeyPath) ([]core.EnvEntry, error) {
s, err := h.getConfig(p.Path)
if err != nil {
return nil, err
}

entries := []core.EnvEntry{}
for k, v := range s {
entries = append(entries, core.EnvEntry{
Key: k,
Value: v.ComputedValue,
Provider: h.Name(),
ResolvedPath: p.Path,
})
}
sort.Sort(core.EntriesByKey(entries))
return entries, nil
}

func (h *Doppler) Get(p core.KeyPath) (*core.EnvEntry, error) {
s, err := h.getConfig(p.Path)
if err != nil {
return nil, err
}

key := p.Env
if p.Field != "" {
key = p.Field
}

v, ok := s[key]
if !ok {
return nil, fmt.Errorf("field at '%s' does not exist", p.Path)
}

return &core.EnvEntry{
Key: p.Env,
Value: v.ComputedValue,
ResolvedPath: p.Path,
Provider: h.Name(),
}, nil
}

func (h *Doppler) getConfig(config string) (map[string]models.ComputedSecret, error) {
r, herr := h.client.GetSecrets(
h.config.APIHost.Value,
utils.GetBool(h.config.VerifyTLS.Value, true),
h.config.Token.Value,
h.config.EnclaveProject.Value,
config,
)
if !herr.IsNil() {
return nil, herr.Err
}

return models.ParseSecrets(r)
}
38 changes: 38 additions & 0 deletions pkg/providers/doppler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package providers

import (
"testing"

"github.com/DopplerHQ/cli/pkg/http"
"github.com/DopplerHQ/cli/pkg/models"
"github.com/golang/mock/gomock"
"github.com/spectralops/teller/pkg/providers/mock_providers"
)

func TestDoppler(t *testing.T) {
ctrl := gomock.NewController(t)
// Assert that Bar is invoked.
defer ctrl.Finish()
client := mock_providers.NewMockDopplerClient(ctrl)
path := "settings/prod/billing-svc"
pathmap := "settings/prod/billing-svc/all"
out := []byte(`{
"secrets": {
"MG_KEY": {
"computed": "shazam"
},
"SMTP_PASS": {
"computed": "mailman"
}
}
}`)

client.EXPECT().GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Eq(path)).Return(out, http.Error{}).AnyTimes()
client.EXPECT().GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Eq(pathmap)).Return(out, http.Error{}).AnyTimes()

s := Doppler{
client: client,
config: models.ScopedOptions{},
}
AssertProvider(t, &s, true)
}
50 changes: 50 additions & 0 deletions pkg/providers/mock_providers/doppler_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions pkg/wizard_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,14 @@ providers:
FOO_BAR:
path: foobar
{{end}}
{{- if index .ProviderKeys "doppler" }}
# set your doppler project with "doppler configure set project <my-project>"
doppler:
env_sync:
path: prd
env:
FOO_BAR:
path: prd
{{end}}
`
Loading

0 comments on commit b7fbc13

Please sign in to comment.