// Copyright 2020-2026 Project Capsule Authors // SPDX-License-Identifier: Apache-2.0 package users import ( "context" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/authentication/serviceaccount" "sigs.k8s.io/controller-runtime/pkg/client" capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2" "github.com/projectcapsule/capsule/pkg/api/rbac" "github.com/projectcapsule/capsule/pkg/runtime/configuration" ) func IsCapsuleUser( ctx context.Context, c client.Client, cfg configuration.Configuration, user string, groups []string, ) bool { groupList := NewUserGroupList(groups) // if the user is a ServiceAccount belonging to the kube-system namespace, definitely, it's not a Capsule user // and we can skip the check in case of Capsule user group assigned to system:authenticated // (ref: https://github.com/projectcapsule/capsule/issues/234) if groupList.Find("system:serviceaccounts:kube-system") { return false } capsuleUsers := cfg.GetUsersByStatus() //nolint:nestif if sets.NewString(groups...).Has("system:serviceaccounts") { namespace, name, err := serviceaccount.SplitUsername(user) if err == nil { if configuration.IsControllerServiceAccount(name, namespace) { return false } serviceaccounts := capsuleUsers.GetByKinds([]rbac.OwnerKind{rbac.ServiceAccountOwner}) if len(serviceaccounts) > 0 && sets.New[string](serviceaccounts...).Has(user) { return true } var tl capsulev1beta2.TenantList if err := c.List(ctx, &tl, client.MatchingFields{".status.namespaces": namespace}); err != nil { return false } if len(tl.Items) == 1 { return true } } } //nolint:modernize for _, group := range capsuleUsers.GetByKinds([]rbac.OwnerKind{rbac.GroupOwner}) { if groupList.Find(group) { if len(cfg.IgnoreUserWithGroups()) > 0 { for _, ignoreGroup := range cfg.IgnoreUserWithGroups() { if groupList.Find(ignoreGroup) { return false } } } return true } } users := capsuleUsers.GetByKinds([]rbac.OwnerKind{rbac.UserOwner}) if len(users) > 0 && sets.New[string](users...).Has(user) { return true } return false }