Compare commits

...

1 Commits

Author SHA1 Message Date
Karan Balani
1a5e60dcdd feat: control visibility of root user in list user api using flagger 2026-02-20 21:32:27 +05:30
7 changed files with 60 additions and 11 deletions

View File

@@ -3,8 +3,9 @@ package flagger
import "github.com/SigNoz/signoz/pkg/types/featuretypes"
var (
FeatureUseSpanMetrics = featuretypes.MustNewName("use_span_metrics")
FeatureKafkaSpanEval = featuretypes.MustNewName("kafka_span_eval")
FeatureUseSpanMetrics = featuretypes.MustNewName("use_span_metrics")
FeatureKafkaSpanEval = featuretypes.MustNewName("kafka_span_eval")
FeatureListUsersIncludeRoot = featuretypes.MustNewName("list_users_include_root")
)
func MustNewRegistry() featuretypes.Registry {
@@ -25,6 +26,14 @@ func MustNewRegistry() featuretypes.Registry {
DefaultVariant: featuretypes.MustNewName("disabled"),
Variants: featuretypes.NewBooleanVariants(),
},
&featuretypes.Feature{
Name: FeatureListUsersIncludeRoot,
Kind: featuretypes.KindBoolean,
Stage: featuretypes.StageStable,
Description: "Controls whether root admin users are shown in the list users API",
DefaultVariant: featuretypes.MustNewName("enabled"),
Variants: featuretypes.NewBooleanVariants(),
},
)
if err != nil {
panic(err)

View File

@@ -8,22 +8,25 @@ import (
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/http/binding"
"github.com/SigNoz/signoz/pkg/http/render"
root "github.com/SigNoz/signoz/pkg/modules/user"
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/authtypes"
"github.com/SigNoz/signoz/pkg/types/featuretypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/gorilla/mux"
)
type handler struct {
module root.Module
getter root.Getter
module root.Module
getter root.Getter
flagger flagger.Flagger
}
func NewHandler(module root.Module, getter root.Getter) root.Handler {
return &handler{module: module, getter: getter}
func NewHandler(module root.Module, getter root.Getter, flagger flagger.Flagger) root.Handler {
return &handler{module: module, getter: getter, flagger: flagger}
}
func (h *handler) AcceptInvite(w http.ResponseWriter, r *http.Request) {
@@ -211,12 +214,29 @@ func (h *handler) ListUsers(w http.ResponseWriter, r *http.Request) {
return
}
users, err := h.getter.ListByOrgID(ctx, valuer.MustNewUUID(claims.OrgID))
orgId := valuer.MustNewUUID(claims.OrgID)
users, err := h.getter.ListByOrgID(ctx, orgId)
if err != nil {
render.Error(w, err)
return
}
// filter root users if feature flag `list_users_include_root` is disabled
evalCtx := featuretypes.NewFlaggerEvaluationContext(orgId)
listUsersIncludeRoot := h.flagger.BooleanOrEmpty(r.Context(), flagger.FeatureListUsersIncludeRoot, evalCtx)
if !listUsersIncludeRoot {
filteredUsers := users[:0]
for _, u := range users {
if !u.IsRoot {
filteredUsers = append(filteredUsers, u)
}
}
render.Success(w, http.StatusOK, filteredUsers)
return
}
render.Success(w, http.StatusOK, users)
}

View File

@@ -11,6 +11,8 @@ import (
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
"github.com/SigNoz/signoz/pkg/factory/factorytest"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
"github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
"github.com/SigNoz/signoz/pkg/querier"
@@ -41,7 +43,13 @@ func TestNewHandlers(t *testing.T) {
queryParser := queryparser.New(providerSettings)
require.NoError(t, err)
dashboardModule := impldashboard.NewModule(impldashboard.NewStore(sqlstore), providerSettings, nil, orgGetter, queryParser)
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, nil, nil, nil, nil, nil, nil, nil, queryParser, Config{}, dashboardModule)
flagger, err := flagger.New(context.Background(), instrumentationtest.New().ToProviderSettings(), flagger.Config{}, flagger.MustNewRegistry())
if err != nil {
t.Fatalf("failed to create flagger: %v", err)
}
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, nil, nil, nil, nil, nil, nil, nil, queryParser, Config{}, dashboardModule, flagger)
querierHandler := querier.NewHandler(providerSettings, nil, nil)
handlers := NewHandlers(modules, providerSettings, nil, querierHandler, nil, nil, nil, nil, nil, nil, nil)

View File

@@ -8,6 +8,7 @@ import (
"github.com/SigNoz/signoz/pkg/cache"
"github.com/SigNoz/signoz/pkg/emailing"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/modules/apdex"
"github.com/SigNoz/signoz/pkg/modules/apdex/implapdex"
"github.com/SigNoz/signoz/pkg/modules/authdomain"
@@ -66,6 +67,7 @@ type Modules struct {
SpanPercentile spanpercentile.Module
MetricsExplorer metricsexplorer.Module
Promote promote.Module
Flagger flagger.Flagger
}
func NewModules(
@@ -85,6 +87,7 @@ func NewModules(
queryParser queryparser.QueryParser,
config Config,
dashboard dashboard.Module,
flagger flagger.Flagger,
) Modules {
quickfilter := implquickfilter.NewModule(implquickfilter.NewStore(sqlstore))
orgSetter := implorganization.NewSetter(implorganization.NewStore(sqlstore), alertmanager, quickfilter)
@@ -110,5 +113,6 @@ func NewModules(
Services: implservices.NewModule(querier, telemetryStore),
MetricsExplorer: implmetricsexplorer.NewModule(telemetryStore, telemetryMetadataStore, cache, ruleStore, dashboard, providerSettings, config.MetricsExplorer),
Promote: implpromote.NewModule(telemetryMetadataStore, telemetryStore),
Flagger: flagger,
}
}

View File

@@ -11,6 +11,8 @@ import (
"github.com/SigNoz/signoz/pkg/alertmanager/signozalertmanager"
"github.com/SigNoz/signoz/pkg/emailing/emailingtest"
"github.com/SigNoz/signoz/pkg/factory/factorytest"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
"github.com/SigNoz/signoz/pkg/modules/dashboard/impldashboard"
"github.com/SigNoz/signoz/pkg/modules/organization/implorganization"
"github.com/SigNoz/signoz/pkg/queryparser"
@@ -40,7 +42,13 @@ func TestNewModules(t *testing.T) {
queryParser := queryparser.New(providerSettings)
require.NoError(t, err)
dashboardModule := impldashboard.NewModule(impldashboard.NewStore(sqlstore), providerSettings, nil, orgGetter, queryParser)
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, nil, nil, nil, nil, nil, nil, nil, queryParser, Config{}, dashboardModule)
flagger, err := flagger.New(context.Background(), instrumentationtest.New().ToProviderSettings(), flagger.Config{}, flagger.MustNewRegistry())
if err != nil {
t.Fatalf("failed to create flagger: %v", err)
}
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, nil, nil, nil, nil, nil, nil, nil, queryParser, Config{}, dashboardModule, flagger)
reflectVal := reflect.ValueOf(modules)
for i := 0; i < reflectVal.NumField(); i++ {

View File

@@ -239,7 +239,7 @@ func NewAPIServerProviderFactories(orgGetter organization.Getter, authz authz.Au
orgGetter,
authz,
implorganization.NewHandler(modules.OrgGetter, modules.OrgSetter),
impluser.NewHandler(modules.User, modules.UserGetter),
impluser.NewHandler(modules.User, modules.UserGetter, modules.Flagger),
implsession.NewHandler(modules.Session),
implauthdomain.NewHandler(modules.AuthDomain),
implpreference.NewHandler(modules.Preference),

View File

@@ -388,7 +388,7 @@ func New(
}
// Initialize all modules
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, analytics, querier, telemetrystore, telemetryMetadataStore, authNs, authz, cache, queryParser, config, dashboard)
modules := NewModules(sqlstore, tokenizer, emailing, providerSettings, orgGetter, alertmanager, analytics, querier, telemetrystore, telemetryMetadataStore, authNs, authz, cache, queryParser, config, dashboard, flagger)
userService := impluser.NewService(providerSettings, impluser.NewStore(sqlstore, providerSettings), modules.User, orgGetter, authz, config.User.Root)