|
@@ -43,6 +43,7 @@ type client struct {
|
|
|
const (
|
|
const (
|
|
|
refTypeName = "name"
|
|
refTypeName = "name"
|
|
|
refTypeID = "id"
|
|
refTypeID = "id"
|
|
|
|
|
+ refTypePath = "path"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
type scwSecretRef struct {
|
|
type scwSecretRef struct {
|
|
@@ -66,23 +67,6 @@ func decodeScwSecretRef(key string) (*scwSecretRef, error) {
|
|
|
}, nil
|
|
}, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func (c *client) getSecretByName(ctx context.Context, name string) (*smapi.Secret, error) {
|
|
|
|
|
- request := smapi.GetSecretByNameRequest{
|
|
|
|
|
- SecretName: name,
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- response, err := c.api.GetSecretByName(&request, scw.WithContext(ctx))
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- //nolint:errorlint
|
|
|
|
|
- if _, isErrNotFound := err.(*scw.ResourceNotFoundError); isErrNotFound {
|
|
|
|
|
- return nil, errNoSecretForName
|
|
|
|
|
- }
|
|
|
|
|
- return nil, err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return response, nil
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
|
func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) ([]byte, error) {
|
|
|
scwRef, err := decodeScwSecretRef(ref.Key)
|
|
scwRef, err := decodeScwSecretRef(ref.Key)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -99,6 +83,8 @@ func (c *client) GetSecret(ctx context.Context, ref esv1beta1.ExternalSecretData
|
|
|
//nolint:errorlint
|
|
//nolint:errorlint
|
|
|
if _, isNotFoundErr := err.(*scw.ResourceNotFoundError); isNotFoundErr {
|
|
if _, isNotFoundErr := err.(*scw.ResourceNotFoundError); isNotFoundErr {
|
|
|
return nil, esv1beta1.NoSecretError{}
|
|
return nil, esv1beta1.NoSecretError{}
|
|
|
|
|
+ } else if errors.Is(err, errNoSecretForName) {
|
|
|
|
|
+ return nil, esv1beta1.NoSecretError{}
|
|
|
}
|
|
}
|
|
|
return nil, err
|
|
return nil, err
|
|
|
}
|
|
}
|
|
@@ -121,41 +107,49 @@ func (c *client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if scwRef.RefType != refTypeName {
|
|
|
|
|
- return fmt.Errorf("secrets can only be pushed by name")
|
|
|
|
|
|
|
+ listSecretReq := &smapi.ListSecretsRequest{
|
|
|
|
|
+ ProjectID: &c.projectID,
|
|
|
|
|
+ Page: scw.Int32Ptr(1),
|
|
|
|
|
+ PageSize: scw.Uint32Ptr(1),
|
|
|
}
|
|
}
|
|
|
- secretName := scwRef.Value
|
|
|
|
|
|
|
+ var secretName string
|
|
|
|
|
|
|
|
- // First, we do a GetSecretVersion() to resolve the secret id and the last revision number.
|
|
|
|
|
|
|
+ switch scwRef.RefType {
|
|
|
|
|
+ case refTypeName:
|
|
|
|
|
+ listSecretReq.Name = &scwRef.Value
|
|
|
|
|
+ secretName = scwRef.Value
|
|
|
|
|
+ default:
|
|
|
|
|
+ return fmt.Errorf("secrets can only be pushed by name")
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
var secretID string
|
|
var secretID string
|
|
|
- secretExists := false
|
|
|
|
|
existingSecretVersion := int64(-1)
|
|
existingSecretVersion := int64(-1)
|
|
|
|
|
|
|
|
- secretVersion, err := c.api.GetSecretVersionByName(&smapi.GetSecretVersionByNameRequest{
|
|
|
|
|
- SecretName: secretName,
|
|
|
|
|
- Revision: "latest",
|
|
|
|
|
- }, scw.WithContext(ctx))
|
|
|
|
|
|
|
+ // list secret by ref
|
|
|
|
|
+ listSecrets, err := c.api.ListSecrets(listSecretReq, scw.WithContext(ctx))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- //nolint:errorlint
|
|
|
|
|
- if notFoundErr, ok := err.(*scw.ResourceNotFoundError); ok {
|
|
|
|
|
- if notFoundErr.Resource == "secret_version" {
|
|
|
|
|
- secretExists = true
|
|
|
|
|
|
|
+ return err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // secret exists
|
|
|
|
|
+ if len(listSecrets.Secrets) > 0 {
|
|
|
|
|
+ secretID = listSecrets.Secrets[0].ID
|
|
|
|
|
+
|
|
|
|
|
+ // get the latest version
|
|
|
|
|
+ secretVersion, err := c.api.GetSecretVersion(&smapi.GetSecretVersionRequest{
|
|
|
|
|
+ SecretID: secretID,
|
|
|
|
|
+ Revision: "latest",
|
|
|
|
|
+ }, scw.WithContext(ctx))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ var errNotNound *scw.ResourceNotFoundError
|
|
|
|
|
+ if !errors.As(err, &errNotNound) {
|
|
|
|
|
+ return err
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- return err
|
|
|
|
|
|
|
+ existingSecretVersion = int64(secretVersion.Revision)
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- secretExists = true
|
|
|
|
|
- existingSecretVersion = int64(secretVersion.Revision)
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- if secretExists {
|
|
|
|
|
if existingSecretVersion != -1 {
|
|
if existingSecretVersion != -1 {
|
|
|
- // If the secret exists, we can fetch its last value to see if we have any change to make.
|
|
|
|
|
-
|
|
|
|
|
- secretID = secretVersion.SecretID
|
|
|
|
|
-
|
|
|
|
|
data, err := c.accessSpecificSecretVersion(ctx, secretID, secretVersion.Revision)
|
|
data, err := c.accessSpecificSecretVersion(ctx, secretID, secretVersion.Revision)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return err
|
|
return err
|
|
@@ -165,22 +159,8 @@ func (c *client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv
|
|
|
// No change to push.
|
|
// No change to push.
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- // If the secret exists but has no versions, we need an additional GetSecret() to resolve the secret id.
|
|
|
|
|
- // This may happen if a push was interrupted.
|
|
|
|
|
-
|
|
|
|
|
- secret, err := c.api.GetSecretByName(&smapi.GetSecretByNameRequest{
|
|
|
|
|
- SecretName: secretName,
|
|
|
|
|
- }, scw.WithContext(ctx))
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return err
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- secretID = secret.ID
|
|
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- // If the secret does not exist, we need to create it.
|
|
|
|
|
-
|
|
|
|
|
secret, err := c.api.CreateSecret(&smapi.CreateSecretRequest{
|
|
secret, err := c.api.CreateSecret(&smapi.CreateSecretRequest{
|
|
|
ProjectID: c.projectID,
|
|
ProjectID: c.projectID,
|
|
|
Name: secretName,
|
|
Name: secretName,
|
|
@@ -206,7 +186,7 @@ func (c *client) PushSecret(ctx context.Context, value []byte, _ *apiextensionsv
|
|
|
|
|
|
|
|
c.cache.Put(secretID, createSecretVersionResponse.Revision, value)
|
|
c.cache.Put(secretID, createSecretVersionResponse.Revision, value)
|
|
|
|
|
|
|
|
- if secretExists && existingSecretVersion != -1 {
|
|
|
|
|
|
|
+ if existingSecretVersion != -1 {
|
|
|
_, err := c.api.DisableSecretVersion(&smapi.DisableSecretVersionRequest{
|
|
_, err := c.api.DisableSecretVersion(&smapi.DisableSecretVersionRequest{
|
|
|
SecretID: secretID,
|
|
SecretID: secretID,
|
|
|
Revision: fmt.Sprintf("%d", existingSecretVersion),
|
|
Revision: fmt.Sprintf("%d", existingSecretVersion),
|
|
@@ -225,21 +205,30 @@ func (c *client) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemot
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if scwRef.RefType != refTypeName {
|
|
|
|
|
|
|
+ listSecretReq := &smapi.ListSecretsRequest{
|
|
|
|
|
+ ProjectID: &c.projectID,
|
|
|
|
|
+ Page: scw.Int32Ptr(1),
|
|
|
|
|
+ PageSize: scw.Uint32Ptr(1),
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ switch scwRef.RefType {
|
|
|
|
|
+ case refTypeName:
|
|
|
|
|
+ listSecretReq.Name = &scwRef.Value
|
|
|
|
|
+ default:
|
|
|
return fmt.Errorf("secrets can only be pushed by name")
|
|
return fmt.Errorf("secrets can only be pushed by name")
|
|
|
}
|
|
}
|
|
|
- secretName := scwRef.Value
|
|
|
|
|
|
|
|
|
|
- secret, err := c.getSecretByName(ctx, secretName)
|
|
|
|
|
|
|
+ listSecrets, err := c.api.ListSecrets(listSecretReq, scw.WithContext(ctx))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- if errors.Is(err, errNoSecretForName) {
|
|
|
|
|
- return nil
|
|
|
|
|
- }
|
|
|
|
|
return err
|
|
return err
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if len(listSecrets.Secrets) == 0 {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
request := smapi.DeleteSecretRequest{
|
|
request := smapi.DeleteSecretRequest{
|
|
|
- SecretID: secret.ID,
|
|
|
|
|
|
|
+ SecretID: listSecrets.Secrets[0].ID,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
err = c.api.DeleteSecret(&request, scw.WithContext(ctx))
|
|
err = c.api.DeleteSecret(&request, scw.WithContext(ctx))
|
|
@@ -254,12 +243,10 @@ func (c *client) Validate() (esv1beta1.ValidationResult, error) {
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
|
|
|
|
|
- page := int32(1)
|
|
|
|
|
- pageSize := uint32(0)
|
|
|
|
|
_, err := c.api.ListSecrets(&smapi.ListSecretsRequest{
|
|
_, err := c.api.ListSecrets(&smapi.ListSecretsRequest{
|
|
|
ProjectID: &c.projectID,
|
|
ProjectID: &c.projectID,
|
|
|
- Page: &page,
|
|
|
|
|
- PageSize: &pageSize,
|
|
|
|
|
|
|
+ Page: scw.Int32Ptr(1),
|
|
|
|
|
+ PageSize: scw.Uint32Ptr(0),
|
|
|
}, scw.WithContext(ctx))
|
|
}, scw.WithContext(ctx))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return esv1beta1.ValidationResultError, nil
|
|
return esv1beta1.ValidationResultError, nil
|
|
@@ -294,11 +281,9 @@ func (c *client) GetSecretMap(ctx context.Context, ref esv1beta1.ExternalSecretD
|
|
|
func (c *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
|
|
func (c *client) GetAllSecrets(ctx context.Context, ref esv1beta1.ExternalSecretFind) (map[string][]byte, error) {
|
|
|
request := smapi.ListSecretsRequest{
|
|
request := smapi.ListSecretsRequest{
|
|
|
ProjectID: &c.projectID,
|
|
ProjectID: &c.projectID,
|
|
|
- Page: new(int32),
|
|
|
|
|
- PageSize: new(uint32),
|
|
|
|
|
|
|
+ Page: scw.Int32Ptr(1),
|
|
|
|
|
+ PageSize: scw.Uint32Ptr(50),
|
|
|
}
|
|
}
|
|
|
- *request.Page = 1
|
|
|
|
|
- *request.PageSize = 50
|
|
|
|
|
|
|
|
|
|
if ref.Path != nil {
|
|
if ref.Path != nil {
|
|
|
return nil, fmt.Errorf("searching by path is not supported")
|
|
return nil, fmt.Errorf("searching by path is not supported")
|
|
@@ -388,16 +373,33 @@ func (c *client) accessSecretVersion(ctx context.Context, secretRef *scwSecretRe
|
|
|
secretID = response.SecretID
|
|
secretID = response.SecretID
|
|
|
secretRevision = response.Revision
|
|
secretRevision = response.Revision
|
|
|
case refTypeName:
|
|
case refTypeName:
|
|
|
- request := smapi.GetSecretVersionByNameRequest{
|
|
|
|
|
- SecretName: secretRef.Value,
|
|
|
|
|
- Revision: versionSpec,
|
|
|
|
|
|
|
+ request := &smapi.ListSecretsRequest{
|
|
|
|
|
+ ProjectID: &c.projectID,
|
|
|
|
|
+ Page: scw.Int32Ptr(1),
|
|
|
|
|
+ PageSize: scw.Uint32Ptr(1),
|
|
|
|
|
+ Name: &secretRef.Value,
|
|
|
}
|
|
}
|
|
|
- response, err := c.api.GetSecretVersionByName(&request, scw.WithContext(ctx))
|
|
|
|
|
|
|
+
|
|
|
|
|
+ response, err := c.api.ListSecrets(request, scw.WithContext(ctx))
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return nil, err
|
|
return nil, err
|
|
|
}
|
|
}
|
|
|
- secretID = response.SecretID
|
|
|
|
|
- secretRevision = response.Revision
|
|
|
|
|
|
|
+
|
|
|
|
|
+ if len(response.Secrets) == 0 {
|
|
|
|
|
+ return nil, errNoSecretForName
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ secretID = response.Secrets[0].ID
|
|
|
|
|
+
|
|
|
|
|
+ secretVersion, err := c.api.GetSecretVersion(&smapi.GetSecretVersionRequest{
|
|
|
|
|
+ SecretID: secretID,
|
|
|
|
|
+ Revision: versionSpec,
|
|
|
|
|
+ }, scw.WithContext(ctx))
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ return nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ secretRevision = secretVersion.Revision
|
|
|
default:
|
|
default:
|
|
|
return nil, fmt.Errorf("invalid secret reference: %q", secretRef.Value)
|
|
return nil, fmt.Errorf("invalid secret reference: %q", secretRef.Value)
|
|
|
}
|
|
}
|