@@ -3,17 +3,24 @@ package providers
33import (
44 "context"
55 "fmt"
6+ "regexp"
7+ "sort"
8+ "strings"
69
710 secretmanager "cloud.google.com/go/secretmanager/apiv1"
811 secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1"
912
1013 "github.com/googleapis/gax-go/v2"
1114 "github.com/spectralops/teller/pkg/core"
1215 "github.com/spectralops/teller/pkg/logging"
16+ "google.golang.org/api/iterator"
1317)
1418
1519type GoogleSMClient interface {
1620 AccessSecretVersion (ctx context.Context , req * secretmanagerpb.AccessSecretVersionRequest , opts ... gax.CallOption ) (* secretmanagerpb.AccessSecretVersionResponse , error )
21+ DestroySecretVersion (ctx context.Context , req * secretmanagerpb.DestroySecretVersionRequest , opts ... gax.CallOption ) (* secretmanagerpb.SecretVersion , error )
22+ ListSecrets (ctx context.Context , in * secretmanagerpb.ListSecretsRequest , opts ... gax.CallOption ) * secretmanager.SecretIterator
23+ AddSecretVersion (ctx context.Context , req * secretmanagerpb.AddSecretVersionRequest , opts ... gax.CallOption ) (* secretmanagerpb.SecretVersion , error )
1724}
1825type GoogleSecretManager struct {
1926 client GoogleSMClient
@@ -33,18 +40,46 @@ func (a *GoogleSecretManager) Name() string {
3340}
3441
3542func (a * GoogleSecretManager ) Put (p core.KeyPath , val string ) error {
36- return fmt .Errorf ("provider %q does not implement write yet" , a .Name ())
43+ reg := regexp .MustCompile (`(?i)/versions/\d+$` )
44+ res := reg .ReplaceAllString (p .Path , "" )
45+ return a .addSecret (res , val )
3746}
3847func (a * GoogleSecretManager ) PutMapping (p core.KeyPath , m map [string ]string ) error {
39- return fmt .Errorf ("provider %q does not implement write yet" , a .Name ())
48+ for k , v := range m {
49+ path := fmt .Sprintf ("%v/secrets/%v" , p .Path , k )
50+ err := a .addSecret (path , v )
51+ if err != nil {
52+ return err
53+ }
54+ }
55+
56+ return nil
4057}
4158
4259func (a * GoogleSecretManager ) GetMapping (kp core.KeyPath ) ([]core.EnvEntry , error ) {
43- return nil , fmt .Errorf ("does not support full env sync (path: %s)" , kp .Path )
60+ secrets , err := a .getSecrets (kp .Path )
61+ if err != nil {
62+ return nil , err
63+ }
64+
65+ entries := []core.EnvEntry {}
66+
67+ for _ , val := range secrets {
68+ path := fmt .Sprintf ("%s/%s" , val , "versions/latest" )
69+ secretVal , err := a .getSecret (path )
70+ if err != nil {
71+ return nil , err
72+ }
73+ key := strings .TrimPrefix (val , kp .Path )
74+ entries = append (entries , kp .FoundWithKey (key , secretVal ))
75+ }
76+ sort .Sort (core .EntriesByKey (entries ))
77+
78+ return entries , nil
4479}
4580
4681func (a * GoogleSecretManager ) Get (p core.KeyPath ) (* core.EnvEntry , error ) {
47- secret , err := a .getSecret (p )
82+ secret , err := a .getSecret (p . Path )
4883 if err != nil {
4984 return nil , err
5085 }
@@ -54,16 +89,16 @@ func (a *GoogleSecretManager) Get(p core.KeyPath) (*core.EnvEntry, error) {
5489}
5590
5691func (a * GoogleSecretManager ) Delete (kp core.KeyPath ) error {
57- return fmt . Errorf ( "%s does not implement delete yet" , a . Name () )
92+ return a . deleteSecret ( kp . Path )
5893}
5994
6095func (a * GoogleSecretManager ) DeleteMapping (kp core.KeyPath ) error {
6196 return fmt .Errorf ("%s does not implement delete yet" , a .Name ())
6297}
6398
64- func (a * GoogleSecretManager ) getSecret (kp core. KeyPath ) (string , error ) {
99+ func (a * GoogleSecretManager ) getSecret (path string ) (string , error ) {
65100 r := secretmanagerpb.AccessSecretVersionRequest {
66- Name : kp . Path ,
101+ Name : path ,
67102 }
68103 a .logger .WithField ("path" , r .Name ).Debug ("get secret" )
69104
@@ -73,3 +108,44 @@ func (a *GoogleSecretManager) getSecret(kp core.KeyPath) (string, error) {
73108 }
74109 return string (secret .Payload .Data ), nil
75110}
111+
112+ func (a * GoogleSecretManager ) deleteSecret (path string ) error {
113+ req := & secretmanagerpb.DestroySecretVersionRequest {
114+ Name : path ,
115+ }
116+ _ , err := a .client .DestroySecretVersion (context .TODO (), req )
117+ return err
118+ }
119+
120+ func (a * GoogleSecretManager ) addSecret (path , val string ) error {
121+ req := & secretmanagerpb.AddSecretVersionRequest {
122+ Parent : path ,
123+ Payload : & secretmanagerpb.SecretPayload {
124+ Data : []byte (val ),
125+ },
126+ }
127+
128+ _ , err := a .client .AddSecretVersion (context .TODO (), req )
129+ return err
130+ }
131+
132+ func (a * GoogleSecretManager ) getSecrets (path string ) ([]string , error ) {
133+ req := & secretmanagerpb.ListSecretsRequest {
134+ Parent : path ,
135+ }
136+ entries := []string {}
137+
138+ it := a .client .ListSecrets (context .TODO (), req )
139+ for {
140+ resp , err := it .Next ()
141+ if err == iterator .Done {
142+ break
143+ }
144+
145+ if err != nil {
146+ return nil , err
147+ }
148+ entries = append (entries , resp .Name )
149+ }
150+ return entries , nil
151+ }
0 commit comments