Secrets: Add inline secure value delete when owned method (#108993)
This commit is contained in:
@@ -217,5 +217,40 @@ func (s *inlineSecureValueService) CreateInline(ctx context.Context, owner commo
|
||||
}
|
||||
|
||||
func (s *inlineSecureValueService) DeleteWhenOwnedByResource(ctx context.Context, owner common.ObjectReference, name string) error {
|
||||
return fmt.Errorf("not implemented yet")
|
||||
ctx, span := s.tracer.Start(ctx, "InlineSecureValueService.DeleteWhenOwnedByResource", trace.WithAttributes(
|
||||
attribute.String("owner.namespace", owner.Namespace),
|
||||
attribute.String("owner.apiGroup", owner.APIGroup),
|
||||
attribute.String("owner.apiVersion", owner.APIVersion),
|
||||
attribute.String("owner.kind", owner.Kind),
|
||||
attribute.String("owner.name", owner.Name),
|
||||
attribute.String("secureValue.name", name),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
authInfo, ok := authlib.AuthInfoFrom(ctx)
|
||||
if !ok {
|
||||
return fmt.Errorf("missing auth info in context")
|
||||
}
|
||||
|
||||
if owner.Namespace == "" || !authlib.NamespaceMatches(authInfo.GetNamespace(), owner.Namespace) {
|
||||
return fmt.Errorf("owner namespace %s does not match auth info namespace %s", owner.Namespace, authInfo.GetNamespace())
|
||||
}
|
||||
|
||||
if owner.APIGroup == "" || owner.APIVersion == "" || owner.Kind == "" || owner.Name == "" {
|
||||
return fmt.Errorf("owner reference must have a valid API group, API version, kind and name")
|
||||
}
|
||||
|
||||
owned, err := s.isSecureValueOwnedByResource(ctx, owner, name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error checking if secure value %s is owned by %v: %w", name, owner, err)
|
||||
}
|
||||
|
||||
if owned {
|
||||
if _, err := s.secureValueService.Delete(ctx, xkube.Namespace(owner.Namespace), name); err != nil {
|
||||
return fmt.Errorf("error deleting secure value %s for owner %v: %w", name, owner, err)
|
||||
}
|
||||
}
|
||||
|
||||
// if it is not owned, this is a no-op
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,8 +5,10 @@ import (
|
||||
|
||||
common "github.com/grafana/grafana/pkg/apimachinery/apis/common/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/service"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/testutils"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/xkube"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -347,3 +349,164 @@ func TestIntegration_InlineSecureValue_CreateInline(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntegration_InlineSecureValue_DeleteWhenOwnedByResource(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tracer := noop.NewTracerProvider().Tracer("test")
|
||||
|
||||
defaultNs := "org-1234"
|
||||
owner := common.ObjectReference{
|
||||
APIGroup: "prometheus.datasource.grafana.app",
|
||||
APIVersion: "v1alpha1",
|
||||
Kind: "DataSourceConfig",
|
||||
Name: "test-datasource",
|
||||
Namespace: defaultNs,
|
||||
}
|
||||
|
||||
t.Run("happy path deletes an owned secure value", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tu := testutils.Setup(t)
|
||||
|
||||
sv1 := "test-secure-value-1"
|
||||
createdSv1, err := tu.CreateSv(t.Context(), func(cfg *testutils.CreateSvConfig) {
|
||||
cfg.Sv.Name = sv1
|
||||
cfg.Sv.Namespace = defaultNs
|
||||
cfg.Sv.OwnerReferences = []metav1.OwnerReference{owner.ToOwnerReference()}
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, createdSv1)
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, tu.SecureValueService, nil)
|
||||
|
||||
ctx := testutils.CreateServiceAuthContext(t.Context(), "", defaultNs, nil)
|
||||
|
||||
err = svc.DeleteWhenOwnedByResource(ctx, owner, sv1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make sure it got deleted
|
||||
sv, err := tu.SecureValueService.Read(ctx, xkube.Namespace(owner.Namespace), sv1)
|
||||
require.ErrorIs(t, err, contracts.ErrSecureValueNotFound)
|
||||
require.Nil(t, sv)
|
||||
})
|
||||
|
||||
t.Run("when the auth info is missing it returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, nil, nil)
|
||||
err := svc.DeleteWhenOwnedByResource(t.Context(), common.ObjectReference{}, "")
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("when the owner namespace does not match auth info namespace it returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, nil, nil)
|
||||
|
||||
reqNs := "org-2345"
|
||||
ctx := testutils.CreateUserAuthContext(t.Context(), reqNs, map[string][]string{})
|
||||
|
||||
err := svc.DeleteWhenOwnedByResource(ctx, owner, "")
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("when the owner namespace is empty it returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, nil, nil)
|
||||
|
||||
ctx := testutils.CreateUserAuthContext(t.Context(), defaultNs, map[string][]string{})
|
||||
|
||||
err := svc.DeleteWhenOwnedByResource(ctx, common.ObjectReference{}, "")
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("when the owner reference has empty fields it returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, nil, nil)
|
||||
|
||||
owner := common.ObjectReference{
|
||||
Namespace: defaultNs,
|
||||
}
|
||||
|
||||
createAuthCtx := testutils.CreateOBOAuthContext(t.Context(), "service-identity", defaultNs, nil, nil)
|
||||
|
||||
require.Error(t, svc.DeleteWhenOwnedByResource(createAuthCtx, owner, ""))
|
||||
|
||||
owner.APIGroup = "prometheus.datasource.grafana.app"
|
||||
require.Error(t, svc.DeleteWhenOwnedByResource(createAuthCtx, owner, ""))
|
||||
|
||||
owner.APIVersion = "v1alpha1"
|
||||
require.Error(t, svc.DeleteWhenOwnedByResource(createAuthCtx, owner, ""))
|
||||
|
||||
owner.Kind = "DataSourceConfig"
|
||||
require.Error(t, svc.DeleteWhenOwnedByResource(createAuthCtx, owner, ""))
|
||||
owner.Kind = ""
|
||||
|
||||
owner.Name = "test-datasource"
|
||||
require.Error(t, svc.DeleteWhenOwnedByResource(createAuthCtx, owner, ""))
|
||||
})
|
||||
|
||||
t.Run("when the secure value exists but the owner does not match, it returns an error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tu := testutils.Setup(t)
|
||||
|
||||
sv1 := "test-secure-value-1"
|
||||
createdSv1, err := tu.CreateSv(t.Context(), func(cfg *testutils.CreateSvConfig) {
|
||||
cfg.Sv.Name = sv1
|
||||
cfg.Sv.Namespace = defaultNs
|
||||
cfg.Sv.OwnerReferences = []metav1.OwnerReference{
|
||||
{
|
||||
APIVersion: "another.example.com/v0alpha1",
|
||||
Kind: "another-kind",
|
||||
Name: "another-name",
|
||||
},
|
||||
}
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, createdSv1)
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, tu.SecureValueService, nil)
|
||||
|
||||
ctx := testutils.CreateServiceAuthContext(t.Context(), "", defaultNs, nil)
|
||||
|
||||
err = svc.DeleteWhenOwnedByResource(ctx, owner, sv1)
|
||||
require.Error(t, err)
|
||||
|
||||
// make sure it still exists
|
||||
sv, err := tu.SecureValueService.Read(ctx, xkube.Namespace(owner.Namespace), sv1)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sv)
|
||||
require.Equal(t, sv1, sv.GetName())
|
||||
})
|
||||
|
||||
t.Run("when the secure value exists but it is shared (no owner), it does not return an error (noop)", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tu := testutils.Setup(t)
|
||||
|
||||
sv1 := "test-secure-value-1"
|
||||
createdSv1, err := tu.CreateSv(t.Context(), func(cfg *testutils.CreateSvConfig) {
|
||||
cfg.Sv.Name = sv1
|
||||
cfg.Sv.Namespace = defaultNs
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, createdSv1)
|
||||
|
||||
svc := service.ProvideInlineSecureValueService(tracer, tu.SecureValueService, nil)
|
||||
|
||||
ctx := testutils.CreateServiceAuthContext(t.Context(), "", defaultNs, nil)
|
||||
|
||||
err = svc.DeleteWhenOwnedByResource(ctx, owner, sv1)
|
||||
require.NoError(t, err)
|
||||
|
||||
// make sure it still exists
|
||||
sv, err := tu.SecureValueService.Read(ctx, xkube.Namespace(owner.Namespace), sv1)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sv)
|
||||
require.Equal(t, sv1, sv.GetName())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user