diff --git a/api/client/events.go b/api/client/events.go index 8b372a43d06..475499b1f60 100644 --- a/api/client/events.go +++ b/api/client/events.go @@ -62,90 +62,85 @@ func EventToGRPC(in types.Event) (*proto.Event, error) { return &out, nil } switch r := in.Resource.(type) { - case types.Resource153Unwrapper: - switch r := r.Unwrap().(type) { - case *kubewaitingcontainerpb.KubernetesWaitingContainer: - out.Resource = &proto.Event_KubernetesWaitingContainer{ - KubernetesWaitingContainer: r, - } - case *notificationsv1.Notification: - out.Resource = &proto.Event_UserNotification{ - UserNotification: r, - } - case *notificationsv1.GlobalNotification: - out.Resource = &proto.Event_GlobalNotification{ - GlobalNotification: r, - } - case *accessmonitoringrulesv1.AccessMonitoringRule: - out.Resource = &proto.Event_AccessMonitoringRule{ - AccessMonitoringRule: r, - } - case *crownjewelv1.CrownJewel: - out.Resource = &proto.Event_CrownJewel{ - CrownJewel: r, - } - case *dbobjectv1.DatabaseObject: - out.Resource = &proto.Event_DatabaseObject{ - DatabaseObject: r, - } - case *machineidv1.BotInstance: - out.Resource = &proto.Event_BotInstance{ - BotInstance: r, - } - case *clusterconfigpb.AccessGraphSettings: - out.Resource = &proto.Event_AccessGraphSettings{ - AccessGraphSettings: r, - } - case *machineidv1.SPIFFEFederation: - out.Resource = &proto.Event_SPIFFEFederation{ - SPIFFEFederation: r, - } - case *userprovisioningpb.StaticHostUser: - out.Resource = &proto.Event_StaticHostUserV2{ - StaticHostUserV2: r, - } - case *autoupdate.AutoUpdateConfig: - out.Resource = &proto.Event_AutoUpdateConfig{ - AutoUpdateConfig: r, - } - case *autoupdate.AutoUpdateVersion: - out.Resource = &proto.Event_AutoUpdateVersion{ - AutoUpdateVersion: r, - } - case *usertasksv1.UserTask: - out.Resource = &proto.Event_UserTask{ - UserTask: r, - } - case *provisioningv1.PrincipalState: - out.Resource = &proto.Event_ProvisioningPrincipalState{ - ProvisioningPrincipalState: r, - } - case *autoupdate.AutoUpdateAgentRollout: - out.Resource = &proto.Event_AutoUpdateAgentRollout{ - AutoUpdateAgentRollout: r, - } - case *identitycenterv1.Account: - out.Resource = &proto.Event_IdentityCenterAccount{ - IdentityCenterAccount: r, - } - case *identitycenterv1.PrincipalAssignment: - out.Resource = &proto.Event_IdentityCenterPrincipalAssignment{ - IdentityCenterPrincipalAssignment: r, - } - case *identitycenterv1.AccountAssignment: - out.Resource = &proto.Event_IdentityCenterAccountAssignment{ - IdentityCenterAccountAssignment: r, - } - case *workloadidentityv1pb.WorkloadIdentity: - out.Resource = &proto.Event_WorkloadIdentity{ - WorkloadIdentity: r, - } - case *workloadidentityv1pb.WorkloadIdentityX509Revocation: - out.Resource = &proto.Event_WorkloadIdentityX509Revocation{ - WorkloadIdentityX509Revocation: r, - } - default: - return nil, trace.BadParameter("resource type %T is not supported", r) + case types.Resource153UnwrapperT[*kubewaitingcontainerpb.KubernetesWaitingContainer]: + out.Resource = &proto.Event_KubernetesWaitingContainer{ + KubernetesWaitingContainer: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*notificationsv1.Notification]: + out.Resource = &proto.Event_UserNotification{ + UserNotification: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*notificationsv1.GlobalNotification]: + out.Resource = &proto.Event_GlobalNotification{ + GlobalNotification: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*accessmonitoringrulesv1.AccessMonitoringRule]: + out.Resource = &proto.Event_AccessMonitoringRule{ + AccessMonitoringRule: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*crownjewelv1.CrownJewel]: + out.Resource = &proto.Event_CrownJewel{ + CrownJewel: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*dbobjectv1.DatabaseObject]: + out.Resource = &proto.Event_DatabaseObject{ + DatabaseObject: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*machineidv1.BotInstance]: + out.Resource = &proto.Event_BotInstance{ + BotInstance: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*clusterconfigpb.AccessGraphSettings]: + out.Resource = &proto.Event_AccessGraphSettings{ + AccessGraphSettings: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*machineidv1.SPIFFEFederation]: + out.Resource = &proto.Event_SPIFFEFederation{ + SPIFFEFederation: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*userprovisioningpb.StaticHostUser]: + out.Resource = &proto.Event_StaticHostUserV2{ + StaticHostUserV2: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*autoupdate.AutoUpdateConfig]: + out.Resource = &proto.Event_AutoUpdateConfig{ + AutoUpdateConfig: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*autoupdate.AutoUpdateVersion]: + out.Resource = &proto.Event_AutoUpdateVersion{ + AutoUpdateVersion: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*usertasksv1.UserTask]: + out.Resource = &proto.Event_UserTask{ + UserTask: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*provisioningv1.PrincipalState]: + out.Resource = &proto.Event_ProvisioningPrincipalState{ + ProvisioningPrincipalState: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*autoupdate.AutoUpdateAgentRollout]: + out.Resource = &proto.Event_AutoUpdateAgentRollout{ + AutoUpdateAgentRollout: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*identitycenterv1.Account]: + out.Resource = &proto.Event_IdentityCenterAccount{ + IdentityCenterAccount: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*identitycenterv1.PrincipalAssignment]: + out.Resource = &proto.Event_IdentityCenterPrincipalAssignment{ + IdentityCenterPrincipalAssignment: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*identitycenterv1.AccountAssignment]: + out.Resource = &proto.Event_IdentityCenterAccountAssignment{ + IdentityCenterAccountAssignment: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*workloadidentityv1pb.WorkloadIdentity]: + out.Resource = &proto.Event_WorkloadIdentity{ + WorkloadIdentity: r.UnwrapT(), + } + case types.Resource153UnwrapperT[*workloadidentityv1pb.WorkloadIdentityX509Revocation]: + out.Resource = &proto.Event_WorkloadIdentityX509Revocation{ + WorkloadIdentityX509Revocation: r.UnwrapT(), } case *types.ResourceHeader: out.Resource = &proto.Event_ResourceHeader{ diff --git a/api/types/resource_153.go b/api/types/resource_153.go index dbe69a11084..b64f3a97de8 100644 --- a/api/types/resource_153.go +++ b/api/types/resource_153.go @@ -132,37 +132,44 @@ func (r *legacyToResource153Adapter) GetVersion() string { // // Note that CheckAndSetDefaults is a noop for the returned resource and // SetSubKind is not implemented and panics on use. -func Resource153ToLegacy(r Resource153) Resource { - return &resource153ToLegacyAdapter{inner: r} +func Resource153ToLegacy[T Resource153](r T) Resource { + return &resource153ToLegacyAdapter[T]{inner: r} } -// Resource153Unwrapper returns a legacy [Resource] type from a wrapped RFD -// 153 style resource -type Resource153Unwrapper interface { - Unwrap() Resource153 -} +// Resource153Unwrapper returns a legacy [Resource153] type from a wrapped RFD +// 153 style resource. Prefer using the stronger typed [Resource153UnwrapperT] +// where possible. +type Resource153Unwrapper interface{ Unwrap() Resource153 } + +// Resource153UnwrapperT returns a [T] from a wrapped RFD +// 153 style resource. +type Resource153UnwrapperT[T Resource153] interface{ UnwrapT() T } // resource153ToLegacyAdapter wraps a new-style resource in a type implementing // the legacy resource interfaces -type resource153ToLegacyAdapter struct { - inner Resource153 +type resource153ToLegacyAdapter[T Resource153] struct { + inner T } // Unwrap is an escape hatch for Resource153 instances that are piped down into // the codebase as a legacy Resource. // // Ideally you shouldn't depend on this. -func (r *resource153ToLegacyAdapter) Unwrap() Resource153 { +func (r *resource153ToLegacyAdapter[T]) Unwrap() Resource153 { + return r.inner +} + +func (r *resource153ToLegacyAdapter[T]) UnwrapT() T { return r.inner } // MarshalJSON adds support for marshaling the wrapped resource (instead of // marshaling the adapter itself). -func (r *resource153ToLegacyAdapter) MarshalJSON() ([]byte, error) { +func (r *resource153ToLegacyAdapter[T]) MarshalJSON() ([]byte, error) { return json.Marshal(r.inner) } -func (r *resource153ToLegacyAdapter) Expiry() time.Time { +func (r *resource153ToLegacyAdapter[T]) Expiry() time.Time { expires := r.inner.GetMetadata().Expires // return zero time.time{} for zero *timestamppb.Timestamp, instead of 01/01/1970. if expires == nil { @@ -172,7 +179,7 @@ func (r *resource153ToLegacyAdapter) Expiry() time.Time { return expires.AsTime() } -func (r *resource153ToLegacyAdapter) GetKind() string { +func (r *resource153ToLegacyAdapter[T]) GetKind() string { return r.inner.GetKind() } @@ -195,39 +202,39 @@ func Metadata153ToLegacy(md *headerv1.Metadata) Metadata { } } -func (r *resource153ToLegacyAdapter) GetMetadata() Metadata { +func (r *resource153ToLegacyAdapter[T]) GetMetadata() Metadata { return Metadata153ToLegacy(r.inner.GetMetadata()) } -func (r *resource153ToLegacyAdapter) GetName() string { +func (r *resource153ToLegacyAdapter[T]) GetName() string { return r.inner.GetMetadata().Name } -func (r *resource153ToLegacyAdapter) GetRevision() string { +func (r *resource153ToLegacyAdapter[T]) GetRevision() string { return r.inner.GetMetadata().Revision } -func (r *resource153ToLegacyAdapter) GetSubKind() string { +func (r *resource153ToLegacyAdapter[T]) GetSubKind() string { return r.inner.GetSubKind() } -func (r *resource153ToLegacyAdapter) GetVersion() string { +func (r *resource153ToLegacyAdapter[T]) GetVersion() string { return r.inner.GetVersion() } -func (r *resource153ToLegacyAdapter) SetExpiry(t time.Time) { +func (r *resource153ToLegacyAdapter[T]) SetExpiry(t time.Time) { r.inner.GetMetadata().Expires = timestamppb.New(t) } -func (r *resource153ToLegacyAdapter) SetName(name string) { +func (r *resource153ToLegacyAdapter[T]) SetName(name string) { r.inner.GetMetadata().Name = name } -func (r *resource153ToLegacyAdapter) SetRevision(rev string) { +func (r *resource153ToLegacyAdapter[T]) SetRevision(rev string) { r.inner.GetMetadata().Revision = rev } -func (r *resource153ToLegacyAdapter) SetSubKind(subKind string) { +func (r *resource153ToLegacyAdapter[T]) SetSubKind(subKind string) { panic("interface Resource153 does not implement SetSubKind") } @@ -235,9 +242,9 @@ func (r *resource153ToLegacyAdapter) SetSubKind(subKind string) { // the legacy [Resource] and [ResourceWithLabels] interfaces. // // The same caveats that apply to [Resource153ToLegacy] apply. -func Resource153ToResourceWithLabels(r Resource153) ResourceWithLabels { - return &resource153ToResourceWithLabelsAdapter{ - resource153ToLegacyAdapter{ +func Resource153ToResourceWithLabels[T Resource153](r T) ResourceWithLabels { + return &resource153ToResourceWithLabelsAdapter[T]{ + resource153ToLegacyAdapter[T]{ inner: r, }, } @@ -245,12 +252,12 @@ func Resource153ToResourceWithLabels(r Resource153) ResourceWithLabels { // resource153ToResourceWithLabelsAdapter wraps a new-style resource in a // type implementing the legacy resource interfaces -type resource153ToResourceWithLabelsAdapter struct { - resource153ToLegacyAdapter +type resource153ToResourceWithLabelsAdapter[T Resource153] struct { + resource153ToLegacyAdapter[T] } // Origin implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) Origin() string { +func (r *resource153ToResourceWithLabelsAdapter[T]) Origin() string { m := r.inner.GetMetadata() if m == nil { return "" @@ -259,7 +266,7 @@ func (r *resource153ToResourceWithLabelsAdapter) Origin() string { } // SetOrigin implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) SetOrigin(origin string) { +func (r *resource153ToResourceWithLabelsAdapter[T]) SetOrigin(origin string) { m := r.inner.GetMetadata() if m == nil { return @@ -268,7 +275,7 @@ func (r *resource153ToResourceWithLabelsAdapter) SetOrigin(origin string) { } // GetLabel implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) GetLabel(key string) (value string, ok bool) { +func (r *resource153ToResourceWithLabelsAdapter[T]) GetLabel(key string) (value string, ok bool) { m := r.inner.GetMetadata() if m == nil { return "", false @@ -278,7 +285,7 @@ func (r *resource153ToResourceWithLabelsAdapter) GetLabel(key string) (value str } // GetAllLabels implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) GetAllLabels() map[string]string { +func (r *resource153ToResourceWithLabelsAdapter[T]) GetAllLabels() map[string]string { m := r.inner.GetMetadata() if m == nil { return nil @@ -287,12 +294,12 @@ func (r *resource153ToResourceWithLabelsAdapter) GetAllLabels() map[string]strin } // GetStaticLabels implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) GetStaticLabels() map[string]string { +func (r *resource153ToResourceWithLabelsAdapter[T]) GetStaticLabels() map[string]string { return r.GetAllLabels() } // SetStaticLabels implements ResourceWithLabels for the adapter. -func (r *resource153ToResourceWithLabelsAdapter) SetStaticLabels(labels map[string]string) { +func (r *resource153ToResourceWithLabelsAdapter[T]) SetStaticLabels(labels map[string]string) { m := r.inner.GetMetadata() if m == nil { return @@ -303,8 +310,8 @@ func (r *resource153ToResourceWithLabelsAdapter) SetStaticLabels(labels map[stri // MatchSearch implements ResourceWithLabels for the adapter. If the underlying // type exposes a MatchSearch method, this method will defer to that, otherwise // it will match against the resource label values and name. -func (r *resource153ToResourceWithLabelsAdapter) MatchSearch(searchValues []string) bool { - if matcher, ok := r.inner.(interface{ MatchSearch([]string) bool }); ok { +func (r *resource153ToResourceWithLabelsAdapter[T]) MatchSearch(searchValues []string) bool { + if matcher, ok := any(r.inner).(interface{ MatchSearch([]string) bool }); ok { return matcher.MatchSearch(searchValues) } fieldVals := append(utils.MapToStrings(r.GetAllLabels()), r.GetName()) @@ -330,10 +337,10 @@ type UnifiedResource interface { // with the Teleport Unified Resources Cache. // // The same caveats that apply to [Resource153ToLegacy] apply. -func Resource153ToUnifiedResource(r ClonableResource153) UnifiedResource { - return &resource153ToUnifiedResourceAdapter{ - resource153ToResourceWithLabelsAdapter: resource153ToResourceWithLabelsAdapter{ - resource153ToLegacyAdapter{ +func Resource153ToUnifiedResource[T ClonableResource153](r T) UnifiedResource { + return &resource153ToUnifiedResourceAdapter[T]{ + resource153ToResourceWithLabelsAdapter: resource153ToResourceWithLabelsAdapter[T]{ + resource153ToLegacyAdapter[T]{ inner: r, }, }, @@ -342,17 +349,13 @@ func Resource153ToUnifiedResource(r ClonableResource153) UnifiedResource { // resource153ToUnifiedResourceAdapter wraps a [resource153ToLegacyAdapter] to // provide an implementation of [UnifiedResource] -type resource153ToUnifiedResourceAdapter struct { - resource153ToResourceWithLabelsAdapter +type resource153ToUnifiedResourceAdapter[T ClonableResource153] struct { + resource153ToResourceWithLabelsAdapter[T] } // CloneResource clones the underlying resource and wraps it in -func (r *resource153ToUnifiedResourceAdapter) CloneResource() ResourceWithLabels { - // We assume that this type assertion will work because we force `inner` - // to implement ClonableResource153 in [Resource153ToUnifiedResource], which - // is the only externally-visible constructor function. - clone := r.inner.(ClonableResource153).CloneResource() - return Resource153ToUnifiedResource(clone) +func (r *resource153ToUnifiedResourceAdapter[T]) CloneResource() ResourceWithLabels { + return Resource153ToUnifiedResource(r.inner.CloneResource().(T)) } // ProtoResource153 is a Resource153 implemented by a protobuf-generated struct. @@ -361,14 +364,14 @@ type ProtoResource153 interface { proto.Message } -type protoResource153ToLegacyAdapter struct { - inner ProtoResource153 - resource153ToLegacyAdapter +type protoResource153ToLegacyAdapter[T ProtoResource153] struct { + inner T + resource153ToLegacyAdapter[T] } // MarshalJSON adds support for marshaling the wrapped resource (instead of // marshaling the adapter itself). -func (r *protoResource153ToLegacyAdapter) MarshalJSON() ([]byte, error) { +func (r *protoResource153ToLegacyAdapter[T]) MarshalJSON() ([]byte, error) { return protojson.MarshalOptions{ UseProtoNames: true, }.Marshal(r.inner) @@ -381,9 +384,9 @@ func (r *protoResource153ToLegacyAdapter) MarshalJSON() ([]byte, error) { // // Note that CheckAndSetDefaults is a noop for the returned resource and // SetSubKind is not implemented and panics on use. -func ProtoResource153ToLegacy(r ProtoResource153) Resource { - return &protoResource153ToLegacyAdapter{ +func ProtoResource153ToLegacy[T ProtoResource153](r T) Resource { + return &protoResource153ToLegacyAdapter[T]{ r, - resource153ToLegacyAdapter{r}, + resource153ToLegacyAdapter[T]{r}, } } diff --git a/api/types/resource_153_test.go b/api/types/resource_153_test.go index f6cbb14c9a6..a999e76e05a 100644 --- a/api/types/resource_153_test.go +++ b/api/types/resource_153_test.go @@ -87,6 +87,12 @@ func TestResource153ToLegacy(t *testing.T) { if diff := cmp.Diff(bot, unwrapped, protocmp.Transform()); diff != "" { t.Errorf("Unwrap mismatch (-want +got)\n%s", diff) } + + unwrapperT := legacyResource.(types.Resource153UnwrapperT[*machineidv1.Bot]) + unwrappedT := unwrapperT.UnwrapT() + if diff := cmp.Diff(bot, unwrappedT, protocmp.Transform()); diff != "" { + t.Errorf("Unwrap mismatch (-want +got)\n%s", diff) + } }) // Marshaling as JSON marshals the underlying resource. diff --git a/integrations/access/accessmonitoring/access_monitoring_rules.go b/integrations/access/accessmonitoring/access_monitoring_rules.go index e9f8e8e7b02..870ed75016e 100644 --- a/integrations/access/accessmonitoring/access_monitoring_rules.go +++ b/integrations/access/accessmonitoring/access_monitoring_rules.go @@ -116,15 +116,11 @@ func (amrh *RuleHandler) HandleAccessMonitoringRule(ctx context.Context, event t defer amrh.accessMonitoringRules.Unlock() switch op := event.Type; op { case types.OpPut: - e, ok := event.Resource.(types.Resource153Unwrapper) + e, ok := event.Resource.(types.Resource153UnwrapperT[*accessmonitoringrulesv1.AccessMonitoringRule]) if !ok { return trace.BadParameter("expected Resource153Unwrapper resource type, got %T", event.Resource) } - req, ok := e.Unwrap().(*accessmonitoringrulesv1.AccessMonitoringRule) - if !ok { - return trace.BadParameter("expected AccessMonitoringRule resource type, got %T", event.Resource) - } - + req := e.UnwrapT() // In the event an existing rule no longer applies we must remove it. if !amrh.ruleApplies(req) { delete(amrh.accessMonitoringRules.rules, event.Resource.GetName()) diff --git a/lib/auth/auth_with_roles.go b/lib/auth/auth_with_roles.go index d429a510848..aca104ce21b 100644 --- a/lib/auth/auth_with_roles.go +++ b/lib/auth/auth_with_roles.go @@ -1968,20 +1968,15 @@ func (r resourceChecker) CanAccess(resource types.Resource) error { } case types.SAMLIdPServiceProvider: return r.CheckAccess(rr, state) - - case types.Resource153Unwrapper: + case types.Resource153UnwrapperT[services.IdentityCenterAccount]: checkable, isCheckable := rr.(services.AccessCheckable) if isCheckable { - switch unwrapped := rr.Unwrap().(type) { - case services.IdentityCenterAccount: - return r.CheckAccess(checkable, state, services.NewIdentityCenterAccountMatcher(unwrapped)) - - case services.IdentityCenterAccountAssignment: - return r.CheckAccess(checkable, state, services.NewIdentityCenterAccountAssignmentMatcher(unwrapped)) - - default: - return r.CheckAccess(checkable, state) - } + return r.CheckAccess(checkable, state, services.NewIdentityCenterAccountMatcher(rr.UnwrapT())) + } + case types.Resource153UnwrapperT[services.IdentityCenterAccountAssignment]: + checkable, isCheckable := rr.(services.AccessCheckable) + if isCheckable { + return r.CheckAccess(checkable, state, services.NewIdentityCenterAccountAssignmentMatcher(rr.UnwrapT())) } } diff --git a/lib/auth/machineid/workloadidentityv1/revocation_service.go b/lib/auth/machineid/workloadidentityv1/revocation_service.go index a16e0836f68..525748aa74d 100644 --- a/lib/auth/machineid/workloadidentityv1/revocation_service.go +++ b/lib/auth/machineid/workloadidentityv1/revocation_service.go @@ -490,22 +490,14 @@ func (s *RevocationService) watchAndSign(ctx context.Context) error { handleEvent := func(e types.Event) (bool, error) { switch e.Type { case types.OpPut: - unwrapper, ok := e.Resource.(types.Resource153Unwrapper) + unwrapper, ok := e.Resource.(types.Resource153UnwrapperT[*workloadidentityv1pb.WorkloadIdentityX509Revocation]) if !ok { return false, trace.BadParameter( "expected event resource (%s) to implement Resource153Wrapper", e.Resource.GetName(), ) } - unwrapped := unwrapper.Unwrap() - revocation, ok := unwrapped.(*workloadidentityv1pb.WorkloadIdentityX509Revocation) - if !ok { - return false, trace.BadParameter( - "expected event resource (%s) to be a WorkloadIdentityX509Revocation, but it was %T", - e.Resource.GetName(), - unwrapped, - ) - } + revocation := unwrapper.UnwrapT() revocationsMap[revocation.Metadata.Name] = revocation return true, nil case types.OpDelete: diff --git a/lib/cache/collections.go b/lib/cache/collections.go index b662023e2fe..f49d6a84479 100644 --- a/lib/cache/collections.go +++ b/lib/cache/collections.go @@ -2428,18 +2428,16 @@ func (kubeWaitingContainerExecutor) deleteAll(ctx context.Context, cache *Cache) func (kubeWaitingContainerExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { switch r := resource.(type) { - case types.Resource153Unwrapper: - switch wc := r.Unwrap().(type) { - case *kubewaitingcontainerpb.KubernetesWaitingContainer: - err := cache.kubeWaitingContsCache.DeleteKubernetesWaitingContainer(ctx, &kubewaitingcontainerpb.DeleteKubernetesWaitingContainerRequest{ - Username: wc.Spec.Username, - Cluster: wc.Spec.Cluster, - Namespace: wc.Spec.Namespace, - PodName: wc.Spec.PodName, - ContainerName: wc.Spec.ContainerName, - }) - return trace.Wrap(err) - } + case types.Resource153UnwrapperT[*kubewaitingcontainerpb.KubernetesWaitingContainer]: + wc := r.UnwrapT() + err := cache.kubeWaitingContsCache.DeleteKubernetesWaitingContainer(ctx, &kubewaitingcontainerpb.DeleteKubernetesWaitingContainerRequest{ + Username: wc.Spec.Username, + Cluster: wc.Spec.Cluster, + Namespace: wc.Spec.Namespace, + PodName: wc.Spec.PodName, + ContainerName: wc.Spec.ContainerName, + }) + return trace.Wrap(err) } return trace.BadParameter("unknown KubeWaitingContainer type, expected *kubewaitingcontainerpb.KubernetesWaitingContainer, got %T", resource) @@ -3342,16 +3340,11 @@ func (userNotificationExecutor) deleteAll(ctx context.Context, cache *Cache) err } func (userNotificationExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { - r, ok := resource.(types.Resource153Unwrapper) + r, ok := resource.(types.Resource153UnwrapperT[*notificationsv1.Notification]) if !ok { return trace.BadParameter("unknown resource type, expected types.Resource153Unwrapper, got %T", resource) } - - notification, ok := r.Unwrap().(*notificationsv1.Notification) - if !ok { - return trace.BadParameter("unknown Notification type, expected *notificationsv1.Notification, got %T", resource) - } - + notification := r.UnwrapT() username := notification.GetSpec().GetUsername() notificationId := notification.GetMetadata().GetName() @@ -3405,17 +3398,11 @@ func (globalNotificationExecutor) deleteAll(ctx context.Context, cache *Cache) e } func (globalNotificationExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { - - r, ok := resource.(types.Resource153Unwrapper) + r, ok := resource.(types.Resource153UnwrapperT[*notificationsv1.GlobalNotification]) if !ok { return trace.BadParameter("unknown resource type, expected types.Resource153Unwrapper, got %T", resource) } - - globalNotification, ok := r.Unwrap().(*notificationsv1.GlobalNotification) - if !ok { - return trace.BadParameter("unknown Notification type, expected *notificationsv1.GlobalNotification, got %T", resource) - } - + globalNotification := r.UnwrapT() notificationId := globalNotification.GetMetadata().GetName() err := cache.notificationsCache.DeleteGlobalNotification(ctx, notificationId) diff --git a/lib/cache/provisioning.go b/lib/cache/provisioning.go index 883fb8cd69f..b078379da2d 100644 --- a/lib/cache/provisioning.go +++ b/lib/cache/provisioning.go @@ -70,16 +70,12 @@ func (provisioningStateExecutor) upsert(ctx context.Context, cache *Cache, resou } func (provisioningStateExecutor) delete(ctx context.Context, cache *Cache, resource types.Resource) error { - unwrapper, ok := resource.(types.Resource153Unwrapper) + unwrapper, ok := resource.(types.Resource153UnwrapperT[*provisioningv1.PrincipalState]) if !ok { return trace.BadParameter("resource must implement Resource153Unwrapper: %T", resource) } - principalState, ok := unwrapper.Unwrap().(*provisioningv1.PrincipalState) - if !ok { - return trace.BadParameter("wrapped resource must be a PrincipalState: %T", resource) - } - + principalState := unwrapper.UnwrapT() principalStateID := principalState.GetMetadata().GetName() downstreamID := principalState.GetSpec().GetDownstreamId() if principalStateID == "" || downstreamID == "" { diff --git a/lib/services/access_checker.go b/lib/services/access_checker.go index f9124b18d88..1662a4495cf 100644 --- a/lib/services/access_checker.go +++ b/lib/services/access_checker.go @@ -462,14 +462,10 @@ func (a *accessChecker) CheckAccess(r AccessCheckable, state AccessState, matche } switch rr := r.(type) { - case types.Resource153Unwrapper: - switch urr := rr.Unwrap().(type) { - case IdentityCenterAccount: - matchers = append(matchers, NewIdentityCenterAccountMatcher(urr)) - - case IdentityCenterAccountAssignment: - matchers = append(matchers, NewIdentityCenterAccountAssignmentMatcher(urr)) - } + case types.Resource153UnwrapperT[IdentityCenterAccount]: + matchers = append(matchers, NewIdentityCenterAccountMatcher(rr.UnwrapT())) + case types.Resource153UnwrapperT[IdentityCenterAccountAssignment]: + matchers = append(matchers, NewIdentityCenterAccountAssignmentMatcher(rr.UnwrapT())) } return trace.Wrap(a.RoleSet.checkAccess(r, a.info.Traits, state, matchers...)) diff --git a/lib/services/access_request.go b/lib/services/access_request.go index e3e164a921e..ab29a902243 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -2175,14 +2175,10 @@ func (m *RequestValidator) pruneResourceRequestRoles( } switch rr := resource.(type) { - case types.Resource153Unwrapper: - switch urr := rr.Unwrap().(type) { - case IdentityCenterAccount: - matchers = append(matchers, NewIdentityCenterAccountMatcher(urr)) - - case IdentityCenterAccountAssignment: - matchers = append(matchers, NewIdentityCenterAccountAssignmentMatcher(urr)) - } + case types.Resource153UnwrapperT[IdentityCenterAccount]: + matchers = append(matchers, NewIdentityCenterAccountMatcher(rr.UnwrapT())) + case types.Resource153UnwrapperT[IdentityCenterAccountAssignment]: + matchers = append(matchers, NewIdentityCenterAccountAssignmentMatcher(rr.UnwrapT())) } for _, role := range allRoles { diff --git a/lib/services/local/events_test.go b/lib/services/local/events_test.go index c4d7c91ed4e..7d3bc59229b 100644 --- a/lib/services/local/events_test.go +++ b/lib/services/local/events_test.go @@ -56,12 +56,11 @@ func newTestContext(t *testing.T) context.Context { return ctx } -func unwrapResource153[T any](t *testing.T, r types.Resource) T { - u, ok := r.(types.Resource153Unwrapper) +func unwrapResource153[T types.Resource153](t *testing.T, r types.Resource) T { + u, ok := r.(types.Resource153UnwrapperT[T]) require.True(t, ok, "expected event to implement Resource153Unwrapper") - dst, ok := u.Unwrap().(T) - require.True(t, ok, "expected event to cast to %T", dst) + dst := u.UnwrapT() return dst } diff --git a/lib/services/local/resource.go b/lib/services/local/resource.go index 5cdf374fd8c..755fcc162b2 100644 --- a/lib/services/local/resource.go +++ b/lib/services/local/resource.go @@ -73,14 +73,7 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) { var extItems []backend.Item var err error - // Unwrap "new style" resources. - // We always want to switch over the underlying type. - var res any = resource - if w, ok := res.(types.Resource153Unwrapper); ok { - res = w.Unwrap() - } - - switch r := res.(type) { + switch r := resource.(type) { case types.User: item, err = itemFromUser(r) if auth := r.GetLocalAuth(); err == nil && auth != nil { @@ -106,10 +99,10 @@ func itemsFromResource(resource types.Resource) ([]backend.Item, error) { item, err = itemFromClusterNetworkingConfig(r) case types.AuthPreference: item, err = itemFromAuthPreference(r) - case *autoupdatev1pb.AutoUpdateConfig: - item, err = itemFromAutoUpdateConfig(r) - case *autoupdatev1pb.AutoUpdateVersion: - item, err = itemFromAutoUpdateVersion(r) + case types.Resource153UnwrapperT[*autoupdatev1pb.AutoUpdateConfig]: + item, err = itemFromAutoUpdateConfig(r.UnwrapT()) + case types.Resource153UnwrapperT[*autoupdatev1pb.AutoUpdateVersion]: + item, err = itemFromAutoUpdateVersion(r.UnwrapT()) default: return nil, trace.NotImplemented("cannot itemFrom resource of type %T", resource) } diff --git a/lib/services/notifications_cache.go b/lib/services/notifications_cache.go index dce0be16599..9aa4a79ab89 100644 --- a/lib/services/notifications_cache.go +++ b/lib/services/notifications_cache.go @@ -462,18 +462,12 @@ func (c *UserNotificationCache) processEventsAndUpdateCurrent(ctx context.Contex case types.OpPut: // Since the EventsService watcher currently only supports legacy resources, we had to use types.Resource153ToLegacy() when parsing the event // to transform the notification into a legacy resource. We now have to use Unwrap() to get the original RFD153-style notification out and add it to the cache. - resource153, ok := event.Resource.(types.Resource153Unwrapper) + resource153, ok := event.Resource.(types.Resource153UnwrapperT[*notificationsv1.Notification]) if !ok { slog.WarnContext(ctx, "Unexpected resource type in event (expected types.Resource153Unwrapper)", "resource_type", logutils.TypeAttr(resource153)) continue } - resource := resource153.Unwrap() - - notification, ok := resource.(*notificationsv1.Notification) - if !ok { - slog.WarnContext(ctx, "Unexpected resource type in event (expected *notificationsv1.Notification)", "resource_type", logutils.TypeAttr(resource)) - continue - } + notification := resource153.UnwrapT() if evicted := cache.Put(notification); evicted > 1 { slog.WarnContext(ctx, "Processing of put event for notification resulted in multiple cache evictions (this is a bug).", "notification", notification.GetMetadata().GetName()) } @@ -493,18 +487,12 @@ func (c *GlobalNotificationCache) processEventsAndUpdateCurrent(ctx context.Cont for _, event := range events { switch event.Type { case types.OpPut: - resource153, ok := event.Resource.(types.Resource153Unwrapper) + resource153, ok := event.Resource.(types.Resource153UnwrapperT[*notificationsv1.GlobalNotification]) if !ok { slog.WarnContext(ctx, "Unexpected resource type in event (expected types.Resource153Unwrapper)", "resource_type", logutils.TypeAttr(resource153)) continue } - resource := resource153.Unwrap() - - globalNotification, ok := resource.(*notificationsv1.GlobalNotification) - if !ok { - slog.WarnContext(ctx, "Unexpected resource type in event (expected *notificationsv1.GlobalNotification)", "resource_type", logutils.TypeAttr(resource)) - continue - } + globalNotification := resource153.UnwrapT() if evicted := cache.Put(globalNotification); evicted > 1 { slog.WarnContext(ctx, "Processing of put event for notification resulted in multiple cache evictions (this is a bug).", "notification", globalNotification.GetMetadata().GetName()) } diff --git a/lib/services/unified_resource.go b/lib/services/unified_resource.go index 5be4a8e71ea..07bd81db33f 100644 --- a/lib/services/unified_resource.go +++ b/lib/services/unified_resource.go @@ -349,7 +349,7 @@ func (c *UnifiedResourceCache) SAMLIdPServiceProviders(ctx context.Context, para func (c *UnifiedResourceCache) IdentityCenterAccounts(ctx context.Context, params UnifiedResourcesIterateParams) iter.Seq2[*identitycenterv1.Account, error] { // cloning is performed on the concrete resource below instead of // on the wrapper type. - cloneFn := func(account IdentityCenterAccount) IdentityCenterAccount { + cloneFn := func(account types.Resource153UnwrapperT[IdentityCenterAccount]) types.Resource153UnwrapperT[IdentityCenterAccount] { return account } return func(yield func(*identitycenterv1.Account, error) bool) { @@ -359,7 +359,7 @@ func (c *UnifiedResourceCache) IdentityCenterAccounts(ctx context.Context, param return } - if !yield(apiutils.CloneProtoMsg(account.Account), nil) { + if !yield(apiutils.CloneProtoMsg(account.UnwrapT().Account), nil) { return } } @@ -370,7 +370,7 @@ func (c *UnifiedResourceCache) IdentityCenterAccounts(ctx context.Context, param func (c *UnifiedResourceCache) IdentityCenterAccountAssignments(ctx context.Context, params UnifiedResourcesIterateParams) iter.Seq2[*identitycenterv1.AccountAssignment, error] { // cloning is performed on the concrete resource below instead of // on the wrapper type. - cloneFn := func(account IdentityCenterAccountAssignment) IdentityCenterAccountAssignment { + cloneFn := func(account types.Resource153UnwrapperT[IdentityCenterAccountAssignment]) types.Resource153UnwrapperT[IdentityCenterAccountAssignment] { return account } return func(yield func(*identitycenterv1.AccountAssignment, error) bool) { @@ -380,7 +380,7 @@ func (c *UnifiedResourceCache) IdentityCenterAccountAssignments(ctx context.Cont return } - if !yield(apiutils.CloneProtoMsg(assignment.AccountAssignment), nil) { + if !yield(apiutils.CloneProtoMsg(assignment.UnwrapT().AccountAssignment), nil) { return } } @@ -397,20 +397,8 @@ func iterateUnifiedResourceCache[T any](ctx context.Context, c *UnifiedResourceC return } - switch r := i.resource.(type) { - case T: - if !yield(cloneFn(r), nil) { - return - } - case types.Resource153Unwrapper: - res, ok := r.Unwrap().(T) - if !ok { - continue - } - - if !yield(cloneFn(res), nil) { - return - } + if !yield(cloneFn(i.resource.(T)), nil) { + return } } } @@ -975,30 +963,13 @@ func (c *UnifiedResourceCache) processEventsAndUpdateCurrent(ctx context.Context switch r := event.Resource.(type) { case resource: c.putLocked(r) - - case types.Resource153Unwrapper: - // Raw RFD-153 style resources generally have very few methods - // defined on them by design. One way to add complex behavior to - // these resources is to wrap them inside another type that implements - // any methods or interfaces they need. Resources arriving here - // via the cache protocol will have those wrappers stripped away, - // so we unfortunately need to unwrap and re-wrap these values - // to restore them to a useful state. - switch unwrapped := r.Unwrap().(type) { - case IdentityCenterAccount: - c.putLocked(types.Resource153ToUnifiedResource(unwrapped)) - - case IdentityCenterAccountAssignment: - c.putLocked(types.Resource153ToUnifiedResource(unwrapped)) - - default: - c.logger.WarnContext(ctx, "unsupported Resource153 type", "resource_type", logutils.TypeAttr(unwrapped)) - } - + case types.Resource153UnwrapperT[IdentityCenterAccount]: + c.putLocked(types.Resource153ToUnifiedResource(r.UnwrapT())) + case types.Resource153UnwrapperT[IdentityCenterAccountAssignment]: + c.putLocked(types.Resource153ToUnifiedResource(r.UnwrapT())) default: c.logger.WarnContext(ctx, "unsupported Resource type", "resource_type", logutils.TypeAttr(r)) } - default: c.logger.WarnContext(ctx, "unsupported event type", "event_type", event.Type) continue @@ -1208,17 +1179,11 @@ func MakePaginatedResource(ctx context.Context, requestType string, r types.Reso } case types.KindIdentityCenterAccountAssignment: - unwrapper, ok := resource.(types.Resource153Unwrapper) + unwrapper, ok := resource.(types.Resource153UnwrapperT[IdentityCenterAccountAssignment]) if !ok { return nil, trace.BadParameter("%s has invalid type %T", resourceKind, resource) } - assignment, ok := unwrapper.Unwrap().(IdentityCenterAccountAssignment) - if !ok { - return nil, trace.BadParameter( - "Unexpected type for Identity Center Account Assignment: %T", - unwrapper) - } - + assignment := unwrapper.UnwrapT() protoResource = &proto.PaginatedResource{ Resource: proto.PackICAccountAssignment(assignment.AccountAssignment), RequiresRequest: requiresRequest, @@ -1247,14 +1212,11 @@ func MakePaginatedResource(ctx context.Context, requestType string, r types.Reso // makePaginatedIdentityCenterAccount returns a representation of the supplied // Identity Center account as an App. func makePaginatedIdentityCenterAccount(resourceKind string, resource types.ResourceWithLabels, requiresRequest bool) (*proto.PaginatedResource, error) { - unwrapper, ok := resource.(types.Resource153Unwrapper) + unwrapper, ok := resource.(types.Resource153UnwrapperT[IdentityCenterAccount]) if !ok { return nil, trace.BadParameter("%s has invalid type %T", resourceKind, resource) } - acct, ok := unwrapper.Unwrap().(IdentityCenterAccount) - if !ok { - return nil, trace.BadParameter("%s has invalid inner type %T", resourceKind, resource) - } + acct := unwrapper.UnwrapT() srcPSs := acct.GetSpec().GetPermissionSetInfo() pss := make([]*types.IdentityCenterPermissionSet, len(srcPSs)) for i, ps := range acct.GetSpec().GetPermissionSetInfo() { diff --git a/lib/srv/statichostusers.go b/lib/srv/statichostusers.go index 75d443de29a..3a4cf30b687 100644 --- a/lib/srv/statichostusers.go +++ b/lib/srv/statichostusers.go @@ -27,6 +27,7 @@ import ( "github.com/jonboulle/clockwork" userprovisioningpb "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" + userprovisioningv2 "github.com/gravitational/teleport/api/gen/proto/go/teleport/userprovisioning/v2" "github.com/gravitational/teleport/api/types" "github.com/gravitational/teleport/api/types/label" apiutils "github.com/gravitational/teleport/api/utils" @@ -184,16 +185,13 @@ func (s *StaticHostUserHandler) run(ctx context.Context) error { if event.Type != types.OpPut { continue } - r, ok := event.Resource.(types.Resource153Unwrapper) - if !ok { - slog.WarnContext(ctx, "Unexpected resource type.", "resource", event.Resource) - continue - } - hostUser, ok := r.Unwrap().(*userprovisioningpb.StaticHostUser) + r, ok := event.Resource.(types.Resource153UnwrapperT[*userprovisioningv2.StaticHostUser]) if !ok { slog.WarnContext(ctx, "Unexpected resource type.", "resource", event.Resource) continue } + hostUser := r.UnwrapT() + if err := s.handleNewHostUser(ctx, hostUser); err != nil { // Log the error so we don't stop the handler. slog.WarnContext(ctx, "Error handling static host user.", "error", err, "login", hostUser.GetMetadata().Name) diff --git a/lib/tbot/workloadidentity/trust_bundle_cache.go b/lib/tbot/workloadidentity/trust_bundle_cache.go index e86c0cc6e8b..962597c7980 100644 --- a/lib/tbot/workloadidentity/trust_bundle_cache.go +++ b/lib/tbot/workloadidentity/trust_bundle_cache.go @@ -470,7 +470,7 @@ func (m *TrustBundleCache) processEvent(ctx context.Context, event types.Event) bundleSet.Local = bundle m.setBundleSet(bundleSet) case types.KindSPIFFEFederation: - r153, ok := event.Resource.(types.Resource153Unwrapper) + r153, ok := event.Resource.(types.Resource153UnwrapperT[*machineidv1pb.SPIFFEFederation]) if !ok { log.WarnContext( ctx, @@ -479,15 +479,7 @@ func (m *TrustBundleCache) processEvent(ctx context.Context, event types.Event) ) return } - federation, ok := r153.Unwrap().(*machineidv1pb.SPIFFEFederation) - if !ok { - log.WarnContext( - ctx, - "Event did not contain expected type", - "got", reflect.TypeOf(event.Resource), - ) - return - } + federation := r153.UnwrapT() log.DebugContext( ctx, "Processing update for federated trust bundle",