From 362a4fc76d3f68052effbfdb34e3a7bcc5c55729 Mon Sep 17 00:00:00 2001 From: Steve Munene Date: Thu, 5 Mar 2026 13:42:51 +0300 Subject: [PATCH] MG-370 - Add fine grained access control to rules engine (#402) * update go mod file Signed-off-by: nyagamunene * fix rules endpoint tests Signed-off-by: nyagamunene * fix yaml file Signed-off-by: nyagamunene * fix build Signed-off-by: nyagamunene * address comments Signed-off-by: nyagamunene * remove roles from alarms Signed-off-by: nyagamunene * change approach for schema combaine Signed-off-by: Arvindh * change approach for schema combaine Signed-off-by: Arvindh * fix permissions for rules Signed-off-by: nyagamunene * fix authorization file Signed-off-by: nyagamunene * fix linter Signed-off-by: nyagamunene * fix linter Signed-off-by: nyagamunene --------- Signed-off-by: nyagamunene Signed-off-by: Arvindh Co-authored-by: Arvindh --- .github/workflows/tests.yaml | 2 +- cmd/re/main.go | 139 +- docker/.env | 5 +- docker/docker-compose.yaml | 18 + docker/permission.yaml | 71 + docker/spicedb/combined-schema.zed | 706 +++++++++ docker/spicedb/override-schema.zed | 187 +++ docker/supermq-docker-compose.override.yaml | 22 +- go.mod | 36 +- go.sum | 87 +- pkg/policies/evaluator.go | 6 + re/api/endpoints.go | 2 +- re/api/endpoints_test.go | 2 +- re/api/requests.go | 3 +- re/api/transport.go | 13 +- re/builtinroles.go | 8 + re/events/streams.go | 13 +- re/middleware/authorization.go | 59 +- re/middleware/callout.go | 53 +- re/middleware/logging.go | 12 +- re/middleware/metrics.go | 136 ++ re/middleware/tracing.go | 136 ++ re/mocks/repository.go | 1426 +++++++++++++++++ re/mocks/service.go | 1512 ++++++++++++++++++- re/operations.go | 68 - re/operations/operations.go | 64 + re/postgres/init.go | 22 +- re/postgres/repository.go | 166 +- re/postgres/rule.go | 11 + re/postgres/setup_test.go | 6 +- re/rule.go | 37 +- re/service.go | 71 +- re/service_test.go | 229 ++- scripts/combine-schema.sh | 350 +++++ scripts/supermq.sh | 5 +- 35 files changed, 5431 insertions(+), 252 deletions(-) create mode 100644 docker/permission.yaml create mode 100644 docker/spicedb/combined-schema.zed create mode 100644 docker/spicedb/override-schema.zed create mode 100644 pkg/policies/evaluator.go create mode 100644 re/builtinroles.go create mode 100644 re/middleware/metrics.go create mode 100644 re/middleware/tracing.go delete mode 100644 re/operations.go create mode 100644 re/operations/operations.go create mode 100755 scripts/combine-schema.sh diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 1b997c3f4..7314ca3ba 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -51,7 +51,7 @@ jobs: - name: Run linters uses: golangci/golangci-lint-action@v9 with: - version: v2.4.0 + version: latest args: --config ./tools/config/.golangci.yaml run-tests: diff --git a/cmd/re/main.go b/cmd/re/main.go index d857ce16a..966473507 100644 --- a/cmd/re/main.go +++ b/cmd/re/main.go @@ -20,33 +20,47 @@ import ( "github.com/absmach/magistrala/internal/email" "github.com/absmach/magistrala/pkg/emailer" pkglog "github.com/absmach/magistrala/pkg/logger" + "github.com/absmach/magistrala/pkg/prometheus" "github.com/absmach/magistrala/pkg/ticker" "github.com/absmach/magistrala/re" httpapi "github.com/absmach/magistrala/re/api" "github.com/absmach/magistrala/re/events" "github.com/absmach/magistrala/re/middleware" + "github.com/absmach/magistrala/re/operations" repg "github.com/absmach/magistrala/re/postgres" grpcClient "github.com/absmach/magistrala/readers/api/grpc" "github.com/absmach/supermq" + dpostgres "github.com/absmach/supermq/domains/postgres" smqlog "github.com/absmach/supermq/logger" smqauthn "github.com/absmach/supermq/pkg/authn" authnsvc "github.com/absmach/supermq/pkg/authn/authsvc" mgauthz "github.com/absmach/supermq/pkg/authz" authzsvc "github.com/absmach/supermq/pkg/authz/authsvc" "github.com/absmach/supermq/pkg/callout" + dconsumer "github.com/absmach/supermq/pkg/domains/events/consumer" domainsAuthz "github.com/absmach/supermq/pkg/domains/grpcclient" "github.com/absmach/supermq/pkg/grpcclient" jaegerclient "github.com/absmach/supermq/pkg/jaeger" "github.com/absmach/supermq/pkg/messaging" smqbrokers "github.com/absmach/supermq/pkg/messaging/brokers" brokerstracing "github.com/absmach/supermq/pkg/messaging/brokers/tracing" + "github.com/absmach/supermq/pkg/permissions" + "github.com/absmach/supermq/pkg/policies" + "github.com/absmach/supermq/pkg/policies/spicedb" pgclient "github.com/absmach/supermq/pkg/postgres" + "github.com/absmach/supermq/pkg/roles" "github.com/absmach/supermq/pkg/server" httpserver "github.com/absmach/supermq/pkg/server/http" + spicedbdecoder "github.com/absmach/supermq/pkg/spicedb" "github.com/absmach/supermq/pkg/uuid" + "github.com/authzed/authzed-go/v1" + "github.com/authzed/grpcutil" "github.com/caarlos0/env/v11" "github.com/go-chi/chi/v5" + "go.opentelemetry.io/otel/trace" "golang.org/x/sync/errgroup" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" ) const ( @@ -67,15 +81,21 @@ const ( const channBuffer = 256 type config struct { - LogLevel string `env:"MG_RE_LOG_LEVEL" envDefault:"info"` - InstanceID string `env:"MG_RE_INSTANCE_ID" envDefault:""` - JaegerURL url.URL `env:"SMQ_JAEGER_URL" envDefault:"http://localhost:4318/v1/traces"` - SendTelemetry bool `env:"SMQ_SEND_TELEMETRY" envDefault:"true"` - ESURL string `env:"SMQ_ES_URL" envDefault:"nats://localhost:4222"` - CacheURL string `env:"MG_RE_CACHE_URL" envDefault:"redis://localhost:6379/0"` - CacheKeyDuration time.Duration `env:"MG_RE_CACHE_KEY_DURATION" envDefault:"10m"` - TraceRatio float64 `env:"SMQ_JAEGER_TRACE_RATIO" envDefault:"1.0"` - BrokerURL string `env:"SMQ_MESSAGE_BROKER_URL" envDefault:"nats://localhost:4222"` + LogLevel string `env:"MG_RE_LOG_LEVEL" envDefault:"info"` + InstanceID string `env:"MG_RE_INSTANCE_ID" envDefault:""` + JaegerURL url.URL `env:"SMQ_JAEGER_URL" envDefault:"http://localhost:4318/v1/traces"` + SendTelemetry bool `env:"SMQ_SEND_TELEMETRY" envDefault:"true"` + ESURL string `env:"SMQ_ES_URL" envDefault:"nats://localhost:4222"` + ESConsumerName string `env:"MG_RE_EVENT_CONSUMER" envDefault:"rules_engine"` + CacheURL string `env:"MG_RE_CACHE_URL" envDefault:"redis://localhost:6379/0"` + CacheKeyDuration time.Duration `env:"MG_RE_CACHE_KEY_DURATION" envDefault:"10m"` + TraceRatio float64 `env:"SMQ_JAEGER_TRACE_RATIO" envDefault:"1.0"` + BrokerURL string `env:"SMQ_MESSAGE_BROKER_URL" envDefault:"nats://localhost:4222"` + SpicedbHost string `env:"SMQ_SPICEDB_HOST" envDefault:"localhost"` + SpicedbPort string `env:"SMQ_SPICEDB_PORT" envDefault:"50051"` + SpicedbPreSharedKey string `env:"SMQ_SPICEDB_PRE_SHARED_KEY" envDefault:"12345678"` + SpicedbSchemaFile string `env:"SMQ_SPICEDB_SCHEMA_FILE" envDefault:"schema.zed"` + PermissionsFile string `env:"SMQ_PERMISSIONS_FILE" envDefault:"permission.yaml"` } func main() { @@ -126,7 +146,14 @@ func main() { return } - db, err := pgclient.Setup(dbConfig, *repg.Migration()) + migration, err := repg.Migration() + if err != nil { + logger.Error(err.Error()) + exitCode = 1 + + return + } + db, err := pgclient.Setup(dbConfig, *migration) if err != nil { logger.Error(err.Error()) exitCode = 1 @@ -238,6 +265,16 @@ func main() { logger.Info("AuthZ successfully connected to auth gRPC server " + authnClient.Secure()) database := pgclient.NewDatabase(db, dbConfig, tracer) + + ddatabase := pgclient.NewDatabase(db, dbConfig, tracer) + drepo := dpostgres.NewRepository(ddatabase) + + if err := dconsumer.DomainsEventsSubscribe(ctx, drepo, cfg.ESURL, cfg.ESConsumerName, logger); err != nil { + logger.Error(fmt.Sprintf("failed to create domains event store : %s", err)) + exitCode = 1 + return + } + regrpcCfg := grpcclient.Config{} if err := env.ParseWithOptions(®rpcCfg, env.Options{Prefix: envPrefixGrpc}); err != nil { logger.Error(fmt.Sprintf("failed to load clients gRPC client configuration : %s", err)) @@ -255,7 +292,7 @@ func main() { readersClient := grpcClient.NewReadersClient(client.Connection(), regrpcCfg.Timeout) logger.Info("Readers gRPC client successfully connected to readers gRPC server " + client.Secure()) - svc, err := newService(ctx, database, runInfo, msgSub, writersPub, alarmsPub, authz, ec, logger, readersClient, callout, cfg) + svc, err := newService(ctx, cfg, database, runInfo, msgSub, writersPub, alarmsPub, authz, ec, logger, readersClient, callout, tracer) if err != nil { logger.Error(fmt.Sprintf("failed to create services: %s", err)) exitCode = 1 @@ -307,7 +344,7 @@ func main() { } } -func newService(ctx context.Context, db pgclient.Database, runInfo chan pkglog.RunInfo, rePubSub messaging.PubSub, writersPub, alarmsPub messaging.Publisher, authz mgauthz.Authorization, ec email.Config, logger *slog.Logger, readersClient grpcReadersV1.ReadersServiceClient, callout callout.Callout, cfg config) (re.Service, error) { +func newService(ctx context.Context, cfg config, db pgclient.Database, runInfo chan pkglog.RunInfo, rePubSub messaging.PubSub, writersPub, alarmsPub messaging.Publisher, authz mgauthz.Authorization, ec email.Config, logger *slog.Logger, readersClient grpcReadersV1.ReadersServiceClient, callout callout.Callout, tracer trace.Tracer) (re.Service, error) { repo := repg.NewRepository(db) idp := uuid.New() @@ -316,21 +353,93 @@ func newService(ctx context.Context, db pgclient.Database, runInfo chan pkglog.R logger.Error(fmt.Sprintf("failed to configure e-mailing util: %s", err.Error())) } - csvc := re.NewService(repo, runInfo, idp, rePubSub, writersPub, alarmsPub, ticker.NewTicker(time.Second*30), emailerClient, readersClient) + policyService, err := newSpiceDBPolicyServiceEvaluator(cfg, logger) + if err != nil { + return nil, err + } + logger.Info("Policy service successfully connected to SpiceDB gRPC server") + + availableActions, builtInRoles, err := availableActionsAndBuiltInRoles(cfg.SpicedbSchemaFile) + if err != nil { + return nil, fmt.Errorf("failed to get available actions and built-in roles: %w", err) + } + + csvc, err := re.NewService(repo, runInfo, policyService, idp, rePubSub, writersPub, alarmsPub, ticker.NewTicker(time.Second*30), emailerClient, readersClient, availableActions, builtInRoles) + if err != nil { + return nil, fmt.Errorf("failed to create RE service: %w", err) + } + csvc, err = events.NewEventStoreMiddleware(ctx, csvc, cfg.ESURL) if err != nil { return nil, fmt.Errorf("failed to init re event store middleware: %w", err) } - csvc, err = middleware.AuthorizationMiddleware(csvc, authz) + permConfig, err := permissions.ParsePermissionsFile(cfg.PermissionsFile) + if err != nil { + return nil, fmt.Errorf("failed to parse permissions file: %w", err) + } + + ruleOps, ruleRoleOps, err := permConfig.GetEntityPermissions(operations.EntityType) + if err != nil { + return nil, fmt.Errorf("failed to get rule permissions: %w", err) + } + + entitiesOps, err := permissions.NewEntitiesOperations( + permissions.EntitiesPermission{ + operations.EntityType: ruleOps, + }, + permissions.EntitiesOperationDetails[permissions.Operation]{ + operations.EntityType: operations.OperationDetails(), + }, + ) + if err != nil { + return nil, fmt.Errorf("failed to create entities operations: %w", err) + } + + roleOps, err := permissions.NewOperations(roles.Operations(), ruleRoleOps) + if err != nil { + return nil, fmt.Errorf("failed to create role operations: %w", err) + } + + csvc, err = middleware.AuthorizationMiddleware(csvc, authz, entitiesOps, roleOps) if err != nil { return nil, err } - csvc, err = middleware.NewCallout(csvc, callout) + csvc, err = middleware.NewCallout(csvc, callout, entitiesOps, roleOps) if err != nil { return nil, err } csvc = middleware.LoggingMiddleware(csvc, logger) + counter, latency := prometheus.MakeMetrics("re", "api") + csvc = middleware.NewMetricsMiddleware(counter, latency, csvc) + csvc = middleware.NewTracingMiddleware(tracer, csvc) return csvc, nil } + +func newSpiceDBPolicyServiceEvaluator(cfg config, logger *slog.Logger) (policies.Service, error) { + client, err := authzed.NewClientWithExperimentalAPIs( + fmt.Sprintf("%s:%s", cfg.SpicedbHost, cfg.SpicedbPort), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpcutil.WithInsecureBearerToken(cfg.SpicedbPreSharedKey), + ) + if err != nil { + return nil, err + } + ps := spicedb.NewPolicyService(client, logger) + + return ps, nil +} + +func availableActionsAndBuiltInRoles(spicedbSchemaFile string) ([]roles.Action, map[roles.BuiltInRoleName][]roles.Action, error) { + availableActions, err := spicedbdecoder.GetActionsFromSchema(spicedbSchemaFile, operations.EntityType) + if err != nil { + return []roles.Action{}, map[roles.BuiltInRoleName][]roles.Action{}, err + } + + builtInRoles := map[roles.BuiltInRoleName][]roles.Action{ + re.BuiltInRoleAdmin: availableActions, + } + + return availableActions, builtInRoles, err +} diff --git a/docker/.env b/docker/.env index 248eec4ad..2749337ef 100644 --- a/docker/.env +++ b/docker/.env @@ -85,11 +85,14 @@ SMQ_SPICEDB_DB_PORT=5432 ### SpiceDB config SMQ_SPICEDB_PRE_SHARED_KEY="12345678" -SMQ_SPICEDB_SCHEMA_FILE="/schema.zed" +SMQ_SPICEDB_SCHEMA_FILE="/schemas/combined-schema.zed" SMQ_SPICEDB_HOST=supermq-spicedb SMQ_SPICEDB_PORT=50051 SMQ_SPICEDB_DATASTORE_ENGINE=postgres +### Permissions +SMQ_PERMISSIONS_FILE=/schemas/permission.yaml + ### UI SMQ_UI_PATH_PREFIX=/ui diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 3cbcafb3c..93bdd32fb 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -253,6 +253,7 @@ services: container_name: magistrala-re depends_on: - re-db + - spicedb-migrate restart: on-failure environment: MG_RE_LOG_LEVEL: ${MG_RE_LOG_LEVEL} @@ -290,6 +291,8 @@ services: SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + SMQ_PERMISSIONS_FILE: ${SMQ_PERMISSIONS_FILE} MG_RE_INSTANCE_ID: ${MG_RE_INSTANCE_ID} MG_EMAIL_HOST: ${MG_EMAIL_HOST} MG_EMAIL_PORT: ${MG_EMAIL_PORT} @@ -314,6 +317,8 @@ services: networks: - magistrala-base-net volumes: + - ./permission.yaml:${SMQ_PERMISSIONS_FILE} + - ./spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - ./templates/${MG_RE_EMAIL_TEMPLATE}:/email.tmpl # Auth gRPC client certificates - type: bind @@ -353,6 +358,7 @@ services: container_name: magistrala-alarms depends_on: - alarms-db + - spicedb-migrate restart: on-failure environment: MG_ALARMS_LOG_LEVEL: ${MG_ALARMS_LOG_LEVEL} @@ -382,6 +388,11 @@ services: SMQ_DOMAINS_GRPC_CLIENT_CERT: ${SMQ_DOMAINS_GRPC_CLIENT_CERT:+/domains-grpc-client.crt} SMQ_DOMAINS_GRPC_CLIENT_KEY: ${SMQ_DOMAINS_GRPC_CLIENT_KEY:+/domains-grpc-client.key} SMQ_DOMAINS_GRPC_SERVER_CA_CERTS: ${SMQ_DOMAINS_GRPC_SERVER_CA_CERTS:+/domains-grpc-server-ca.crt} + SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} + SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} + SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + SMQ_PERMISSIONS_FILE: ${SMQ_PERMISSIONS_FILE} MG_ALARMS_INSTANCE_ID: ${MG_ALARMS_INSTANCE_ID} SMQ_ALLOW_UNVERIFIED_USER: ${SMQ_ALLOW_UNVERIFIED_USER} ports: @@ -389,6 +400,8 @@ services: networks: - magistrala-base-net volumes: + - ./permission.yaml:${SMQ_PERMISSIONS_FILE} + - ./spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} # Auth gRPC client certificates - type: bind source: ${SMQ_AUTH_GRPC_CLIENT_CERT:-ssl/certs/dummy/client_cert} @@ -442,6 +455,7 @@ services: container_name: magistrala-reports depends_on: - reports-db + - spicedb-migrate restart: on-failure environment: MG_REPORTS_LOG_LEVEL: ${MG_REPORTS_LOG_LEVEL} @@ -472,6 +486,8 @@ services: SMQ_SPICEDB_PRE_SHARED_KEY: ${SMQ_SPICEDB_PRE_SHARED_KEY} SMQ_SPICEDB_HOST: ${SMQ_SPICEDB_HOST} SMQ_SPICEDB_PORT: ${SMQ_SPICEDB_PORT} + SMQ_SPICEDB_SCHEMA_FILE: ${SMQ_SPICEDB_SCHEMA_FILE} + SMQ_PERMISSIONS_FILE: ${SMQ_PERMISSIONS_FILE} MG_REPORTS_INSTANCE_ID: ${MG_RE_INSTANCE_ID} MG_EMAIL_HOST: ${MG_EMAIL_HOST} MG_EMAIL_PORT: ${MG_EMAIL_PORT} @@ -496,6 +512,8 @@ services: networks: - magistrala-base-net volumes: + - ./permission.yaml:${SMQ_PERMISSIONS_FILE} + - ./spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} - ./templates/${MG_REPORTS_EMAIL_TEMPLATE}:/email.tmpl # Auth gRPC client certificates - type: bind diff --git a/docker/permission.yaml b/docker/permission.yaml new file mode 100644 index 000000000..a33754c88 --- /dev/null +++ b/docker/permission.yaml @@ -0,0 +1,71 @@ +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +alarm: + operations: + - add: alarm_create_permission + - list: alarm_read_permission + - view: read_permission + - update: update_permission + - enable: update_permission + - disable: update_permission + - delete: delete_permission + +rule: + operations: + - add: rule_create_permission + - list: rule_read_permission + - view: read_permission + - update: update_permission + - update_tags: update_permission + - update_schedule: update_permission + - enable: update_permission + - disable: update_permission + - delete: delete_permission + roles_operations: + - add: manage_role_permission + - remove: manage_role_permission + - update: manage_role_permission + - retrieve: view_role_users_permission + - retrieve_all: view_role_users_permission + - add_actions: manage_role_permission + - list_actions: view_role_users_permission + - check_actions_exists: view_role_users_permission + - remove_actions: manage_role_permission + - remove_all_actions: manage_role_permission + - add_members: add_role_users_permission + - list_members: view_role_users_permission + - check_members_exists: view_role_users_permission + - remove_members: remove_role_users_permission + - remove_all_members: remove_role_users_permission + +report: + operations: + - add: report_create_permission + - list: report_read_permission + - generate: report_create_permission + - view: read_permission + - update: update_permission + - update_schedule: update_permission + - enable: update_permission + - disable: update_permission + - delete: delete_permission + - update_template: update_permission + - view_template: read_permission + - delete_template: delete_permission + roles_operations: + - add: manage_role_permission + - remove: manage_role_permission + - update: manage_role_permission + - retrieve: view_role_users_permission + - retrieve_all: view_role_users_permission + - add_actions: manage_role_permission + - list_actions: view_role_users_permission + - check_actions_exists: view_role_users_permission + - remove_actions: manage_role_permission + - remove_all_actions: manage_role_permission + - add_members: add_role_users_permission + - list_members: view_role_users_permission + - check_members_exists: view_role_users_permission + - remove_members: remove_role_users_permission + - remove_all_members: remove_role_users_permission diff --git a/docker/spicedb/combined-schema.zed b/docker/spicedb/combined-schema.zed new file mode 100644 index 000000000..931b79543 --- /dev/null +++ b/docker/spicedb/combined-schema.zed @@ -0,0 +1,706 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 +// Code generated by scripts/combine-schema.sh. DO NOT EDIT. +// +// Combined from: +// - docker/supermq-docker/spicedb/schema.zed +// - docker/spicedb/override-schema.zed + +definition user {} + + +definition role { + relation entity: domain | group | channel | client + relation member: user + relation built_in_role: domain | group | channel | client + + permission delete = entity->manage_role_permission - built_in_role->manage_role_permission + permission update = entity->manage_role_permission - built_in_role->manage_role_permission + permission read = entity->manage_role_permission - built_in_role->manage_role_permission + + permission add_user = entity->add_role_users_permission + permission remove_user = entity->remove_role_users_permission + permission view_user = entity->view_role_users_permission +} + +definition client { + relation domain: domain // This can't be clubbed with parent_group, but if parent_group is unassigned then we could not track belongs to which domain, so it safe to add domain + relation parent_group: group + + relation update: role#member + relation read: role#member + relation delete: role#member + relation set_parent_group: role#member + relation connect_to_channel: role#member + + relation manage_role: role#member + relation add_role_users: role#member + relation remove_role_users: role#member + relation view_role_users: role#member + + permission update_permission = update + parent_group->client_update_permission + domain->client_update_permission + permission read_permission = read + parent_group->client_read_permission + domain->client_read_permission + permission delete_permission = delete + parent_group->client_delete_permission + domain->client_delete_permission + permission set_parent_group_permission = set_parent_group + parent_group->client_set_parent_group_permission + domain->client_set_parent_group_permission + permission connect_to_channel_permission = connect_to_channel + parent_group->client_connect_to_channel_permission + domain->client_connect_to_channel_permission + + permission manage_role_permission = manage_role + parent_group->client_manage_role_permission + domain->client_manage_role_permission + permission add_role_users_permission = add_role_users + parent_group->client_add_role_users_permission + domain->client_add_role_users_permission + permission remove_role_users_permission = remove_role_users + parent_group->client_remove_role_users_permission + domain->client_remove_role_users_permission + permission view_role_users_permission = view_role_users + parent_group->client_view_role_users_permission + domain->client_view_role_users_permission +} + +definition channel { + relation domain: domain // This can't be clubbed with parent_group, but if parent_group is unassigned then we could not track belongs to which domain, so it safe to add domain + relation parent_group: group + + relation update: role#member + relation read: role#member + relation delete: role#member + relation set_parent_group: role#member + relation connect_to_client: role#member + relation publish: role#member | client + relation subscribe: role#member | client + + relation manage_role: role#member + relation add_role_users: role#member + relation remove_role_users: role#member + relation view_role_users: role#member + + permission update_permission = update + parent_group->channel_update_permission + domain->channel_update_permission + permission read_permission = read + parent_group->channel_read_permission + domain->channel_read_permission + permission delete_permission = delete + parent_group->channel_delete_permission + domain->channel_delete_permission + permission set_parent_group_permission = set_parent_group + parent_group->channel_set_parent_group_permission + domain->channel_set_parent_group_permission + permission connect_to_client_permission = connect_to_client + parent_group->channel_connect_to_client_permission + domain->channel_connect_to_client_permission + permission publish_permission = publish + parent_group->channel_publish_permission + domain->channel_publish_permission + permission subscribe_permission = subscribe + parent_group->channel_subscribe_permission + domain->channel_subscribe_permission + + permission manage_role_permission = manage_role + parent_group->channel_manage_role_permission + domain->channel_manage_role_permission + permission add_role_users_permission = add_role_users + parent_group->channel_add_role_users_permission + domain->channel_add_role_users_permission + permission remove_role_users_permission = remove_role_users + parent_group->channel_remove_role_users_permission + domain->channel_remove_role_users_permission + permission view_role_users_permission = view_role_users + parent_group->channel_view_role_users_permission + domain->channel_view_role_users_permission +} + +definition group { + relation domain: domain // This can't be clubbed with parent_group, but if parent_group is unassigned then we could not track belongs to which domain, so it is safe to add domain + relation parent_group: group + + relation update: role#member + relation read: role#member + relation membership: role#member + relation delete: role#member + relation set_child: role#member + relation set_parent: role#member + + relation manage_role: role#member + relation add_role_users: role#member + relation remove_role_users: role#member + relation view_role_users: role#member + + relation client_create: role#member + relation channel_create: role#member + // this allows to add parent for group during the new group creation + relation subgroup_create: role#member + relation subgroup_client_create: role#member + relation subgroup_channel_create: role#member + + relation client_update: role#member + relation client_read: role#member + relation client_delete: role#member + relation client_set_parent_group: role#member + relation client_connect_to_channel: role#member + + relation client_manage_role: role#member + relation client_add_role_users: role#member + relation client_remove_role_users: role#member + relation client_view_role_users: role#member + + relation channel_update: role#member + relation channel_read: role#member + relation channel_delete: role#member + relation channel_set_parent_group: role#member + relation channel_connect_to_client: role#member + relation channel_publish: role#member + relation channel_subscribe: role#member + + relation channel_manage_role: role#member + relation channel_add_role_users: role#member + relation channel_remove_role_users: role#member + relation channel_view_role_users: role#member + + relation subgroup_update: role#member + relation subgroup_read: role#member + relation subgroup_membership: role#member + relation subgroup_delete: role#member + relation subgroup_set_child: role#member + relation subgroup_set_parent: role#member + + relation subgroup_manage_role: role#member + relation subgroup_add_role_users: role#member + relation subgroup_remove_role_users: role#member + relation subgroup_view_role_users: role#member + + relation subgroup_client_update: role#member + relation subgroup_client_read: role#member + relation subgroup_client_delete: role#member + relation subgroup_client_set_parent_group: role#member + relation subgroup_client_connect_to_channel: role#member + + relation subgroup_client_manage_role: role#member + relation subgroup_client_add_role_users: role#member + relation subgroup_client_remove_role_users: role#member + relation subgroup_client_view_role_users: role#member + + relation subgroup_channel_update: role#member + relation subgroup_channel_read: role#member + relation subgroup_channel_delete: role#member + relation subgroup_channel_set_parent_group: role#member + relation subgroup_channel_connect_to_client: role#member + relation subgroup_channel_publish: role#member + relation subgroup_channel_subscribe: role#member + + relation subgroup_channel_manage_role: role#member + relation subgroup_channel_add_role_users: role#member + relation subgroup_channel_remove_role_users: role#member + relation subgroup_channel_view_role_users: role#member + + // Subgroup permission + permission subgroup_create_permission = subgroup_create + parent_group->subgroup_create_permission + permission subgroup_client_create_permission = subgroup_client_create + parent_group->subgroup_client_create_permission + permission subgroup_channel_create_permission = subgroup_channel_create + parent_group->subgroup_channel_create_permission + + permission subgroup_update_permission = subgroup_update + parent_group->subgroup_update_permission + permission subgroup_membership_permission = subgroup_membership + parent_group->subgroup_membership_permission + permission subgroup_read_permission = subgroup_read + parent_group->subgroup_read_permission + permission subgroup_delete_permission = subgroup_delete + parent_group->subgroup_delete_permission + permission subgroup_set_child_permission = subgroup_set_child + parent_group->subgroup_set_child_permission + permission subgroup_set_parent_permission = subgroup_set_parent + parent_group->subgroup_set_parent_permission + + permission subgroup_manage_role_permission = subgroup_manage_role + parent_group->subgroup_manage_role_permission + permission subgroup_add_role_users_permission = subgroup_add_role_users + parent_group->subgroup_add_role_users_permission + permission subgroup_remove_role_users_permission = subgroup_remove_role_users + parent_group->subgroup_remove_role_users_permission + permission subgroup_view_role_users_permission = subgroup_view_role_users + parent_group->subgroup_view_role_users_permission + + // Group permission + permission update_permission = update + parent_group->subgroup_create_permission + domain->group_update_permission + permission membership_permission = membership + parent_group->subgroup_membership_permission + domain->group_membership_permission + permission read_permission = read + parent_group->subgroup_read_permission + domain->group_read_permission + permission delete_permission = delete + parent_group->subgroup_delete_permission + domain->group_delete_permission + permission set_child_permission = set_child + parent_group->subgroup_set_child_permission + domain->group_set_child_permission + permission set_parent_permission = set_parent + parent_group->subgroup_set_parent_permission + domain->group_set_parent_permission + + permission manage_role_permission = manage_role + parent_group->subgroup_manage_role_permission + domain->group_manage_role_permission + permission add_role_users_permission = add_role_users + parent_group->subgroup_add_role_users_permission + domain->group_add_role_users_permission + permission remove_role_users_permission = remove_role_users + parent_group->subgroup_remove_role_users_permission + domain->group_remove_role_users_permission + permission view_role_users_permission = view_role_users + parent_group->subgroup_view_role_users_permission + domain->group_view_role_users_permission + + // Subgroup clients permission + permission subgroup_client_update_permission = subgroup_client_update + parent_group->subgroup_client_update_permission + permission subgroup_client_read_permission = subgroup_client_read + parent_group->subgroup_client_read_permission + permission subgroup_client_delete_permission = subgroup_client_delete + parent_group->subgroup_client_delete_permission + permission subgroup_client_set_parent_group_permission = subgroup_client_set_parent_group + parent_group->subgroup_client_set_parent_group_permission + permission subgroup_client_connect_to_channel_permission = subgroup_client_connect_to_channel + parent_group->subgroup_client_connect_to_channel_permission + + permission subgroup_client_manage_role_permission = subgroup_client_manage_role + parent_group->subgroup_client_manage_role_permission + permission subgroup_client_add_role_users_permission = subgroup_client_add_role_users + parent_group->subgroup_client_add_role_users_permission + permission subgroup_client_remove_role_users_permission = subgroup_client_remove_role_users + parent_group->subgroup_client_remove_role_users_permission + permission subgroup_client_view_role_users_permission = subgroup_client_view_role_users + parent_group->subgroup_client_view_role_users_permission + + // Group clients permission + permission client_create_permission = client_create + parent_group->subgroup_client_create_permission + domain->client_create_permission + permission client_update_permission = client_update + parent_group->subgroup_client_update_permission + domain->client_update_permission + permission client_read_permission = client_read + parent_group->subgroup_client_read_permission + domain->client_read_permission + permission client_delete_permission = client_delete + parent_group->subgroup_client_delete_permission + domain->client_delete_permission + permission client_set_parent_group_permission = client_set_parent_group + parent_group->subgroup_client_set_parent_group_permission + domain->client_set_parent_group_permission + permission client_connect_to_channel_permission = client_connect_to_channel + parent_group->subgroup_client_connect_to_channel_permission + domain->client_connect_to_channel_permission + + permission client_manage_role_permission = client_manage_role + parent_group->subgroup_client_manage_role_permission + domain->client_manage_role_permission + permission client_add_role_users_permission = client_add_role_users + parent_group->subgroup_client_add_role_users_permission + domain->client_add_role_users_permission + permission client_remove_role_users_permission = client_remove_role_users + parent_group->subgroup_client_remove_role_users_permission + domain->client_remove_role_users_permission + permission client_view_role_users_permission = client_view_role_users + parent_group->subgroup_client_view_role_users_permission + domain->client_view_role_users_permission + + // Subgroup channels permission + permission subgroup_channel_update_permission = subgroup_channel_update + parent_group->subgroup_channel_update_permission + permission subgroup_channel_read_permission = subgroup_channel_read + parent_group->subgroup_channel_read_permission + permission subgroup_channel_delete_permission = subgroup_channel_delete + parent_group->subgroup_channel_delete_permission + permission subgroup_channel_set_parent_group_permission = subgroup_channel_set_parent_group + parent_group->subgroup_channel_set_parent_group_permission + permission subgroup_channel_connect_to_client_permission = subgroup_channel_connect_to_client + parent_group->subgroup_channel_connect_to_client_permission + permission subgroup_channel_publish_permission = subgroup_channel_publish + parent_group->subgroup_channel_publish_permission + permission subgroup_channel_subscribe_permission = subgroup_channel_subscribe + parent_group->subgroup_channel_subscribe_permission + + permission subgroup_channel_manage_role_permission = subgroup_channel_manage_role + parent_group->subgroup_channel_manage_role_permission + permission subgroup_channel_add_role_users_permission = subgroup_channel_add_role_users + parent_group->subgroup_channel_add_role_users_permission + permission subgroup_channel_remove_role_users_permission = subgroup_channel_remove_role_users + parent_group->subgroup_channel_remove_role_users_permission + permission subgroup_channel_view_role_users_permission = subgroup_channel_view_role_users + parent_group->subgroup_channel_view_role_users_permission + + // Group channels permission + permission channel_create_permission = channel_create + parent_group->subgroup_channel_create_permission + domain->channel_create_permission + permission channel_update_permission = channel_update + parent_group->subgroup_channel_update_permission + domain->channel_update_permission + permission channel_read_permission = channel_read + parent_group->subgroup_channel_read_permission + domain->channel_read_permission + permission channel_delete_permission = channel_delete + parent_group->subgroup_channel_delete_permission + domain->channel_delete_permission + permission channel_set_parent_group_permission = channel_set_parent_group + parent_group->subgroup_channel_set_parent_group_permission + domain->channel_set_parent_group_permission + permission channel_connect_to_client_permission = channel_connect_to_client + parent_group->subgroup_channel_connect_to_client_permission + domain->channel_connect_to_client_permission + permission channel_publish_permission = channel_publish + parent_group->subgroup_channel_publish_permission + domain->channel_publish_permission + permission channel_subscribe_permission = channel_subscribe + parent_group->subgroup_channel_subscribe_permission + domain->channel_subscribe_permission + + permission channel_manage_role_permission = channel_manage_role + parent_group->channel_manage_role_permission + domain->channel_manage_role_permission + permission channel_add_role_users_permission = channel_add_role_users + parent_group->channel_add_role_users_permission + domain->channel_add_role_users_permission + permission channel_remove_role_users_permission = channel_remove_role_users + parent_group->channel_remove_role_users_permission + domain->channel_remove_role_users_permission + permission channel_view_role_users_permission = channel_view_role_users + parent_group->channel_view_role_users_permission + domain->channel_view_role_users_permission + + +} + +definition domain { + //Replace platform with organization in future + relation organization: platform + relation team: team + + relation update: role#member | team#member + relation enable: role#member | team#member + relation disable: role#member | team#member + relation read: role#member | team#member + relation delete: role#member | team#member + + relation manage_role: role#member | team#member + relation add_role_users: role#member | team#member + relation remove_role_users: role#member | team#member + relation view_role_users: role#member | team#member + + relation client_create: role#member | team#member + relation channel_create: role#member | team#member + relation group_create: role#member | team#member + + relation client_update: role#member | team#member + relation client_read: role#member | team#member + relation client_delete: role#member | team#member + relation client_set_parent_group: role#member | team#member + relation client_connect_to_channel: role#member | team#member + + relation client_manage_role: role#member | team#member + relation client_add_role_users: role#member | team#member + relation client_remove_role_users: role#member | team#member + relation client_view_role_users: role#member | team#member + + relation channel_update: role#member | team#member + relation channel_read: role#member | team#member + relation channel_delete: role#member | team#member + relation channel_set_parent_group: role#member | team#member + relation channel_connect_to_client: role#member | team#member + relation channel_publish: role#member | team#member + relation channel_subscribe: role#member | team#member + + relation channel_manage_role: role#member | team#member + relation channel_add_role_users: role#member | team#member + relation channel_remove_role_users: role#member | team#member + relation channel_view_role_users: role#member | team#member + + relation group_update: role#member | team#member + relation group_membership: role#member | team#member + relation group_read: role#member | team#member + relation group_delete: role#member | team#member + relation group_set_child: role#member | team#member + relation group_set_parent: role#member | team#member + + relation group_manage_role: role#member | team#member + relation group_add_role_users: role#member | team#member + relation group_remove_role_users: role#member | team#member + relation group_view_role_users: role#member | team#member + + // Magistrala-specific relations + relation alarm_create: role#member | team#member + relation alarm_update: role#member | team#member + relation alarm_read: role#member | team#member + relation alarm_delete: role#member | team#member + relation alarm_manage_role: role#member | team#member + relation alarm_add_role_users: role#member | team#member + relation alarm_remove_role_users: role#member | team#member + relation alarm_view_role_users: role#member | team#member + relation rule_create: role#member | team#member + relation rule_update: role#member | team#member + relation rule_read: role#member | team#member + relation rule_delete: role#member | team#member + relation rule_manage_role: role#member | team#member + relation rule_add_role_users: role#member | team#member + relation rule_remove_role_users: role#member | team#member + relation rule_view_role_users: role#member | team#member + relation report_create: role#member | team#member + relation report_update: role#member | team#member + relation report_read: role#member | team#member + relation report_delete: role#member | team#member + relation report_manage_role: role#member | team#member + relation report_add_role_users: role#member | team#member + relation report_remove_role_users: role#member | team#member + relation report_view_role_users: role#member | team#member + + permission update_permission = update + team->domain_update + organization->admin + permission read_permission = read + team->domain_read + organization->admin + permission enable_permission = enable + team->domain_update + organization->admin + permission disable_permission = disable + team->domain_update + organization->admin + permission delete_permission = delete + team->domain_delete + organization->admin + + permission manage_role_permission = manage_role + team->domain_manage_role + organization->admin + permission add_role_users_permission = add_role_users + team->domain_add_role_users + organization->admin + permission remove_role_users_permission = remove_role_users + team->domain_remove_role_users + organization->admin + permission view_role_users_permission = view_role_users + team->domain_view_role_users + organization->admin + + permission membership = read + update + enable + disable + delete + + manage_role + add_role_users + remove_role_users + view_role_users + + client_create + channel_create + group_create + + client_update + client_read + client_delete + client_set_parent_group + client_connect_to_channel + + client_manage_role + client_add_role_users + client_remove_role_users + client_view_role_users + + channel_update + channel_read + channel_delete + channel_set_parent_group + channel_connect_to_client + channel_publish + channel_subscribe + + channel_manage_role + channel_add_role_users + channel_remove_role_users + channel_view_role_users + + group_update + group_membership + group_read + group_delete + group_set_child + group_set_parent + + group_manage_role + group_add_role_users + group_remove_role_users + group_view_role_users + + alarm_create + alarm_update + alarm_read + alarm_delete + alarm_manage_role + alarm_add_role_users + alarm_remove_role_users + alarm_view_role_users + rule_create + rule_update + rule_read + rule_delete + rule_manage_role + rule_add_role_users + rule_remove_role_users + rule_view_role_users + report_create + report_update + report_read + report_delete + report_manage_role + report_add_role_users + report_remove_role_users + report_view_role_users + + organization->admin + + permission admin = (read & update & enable & disable & delete & manage_role & add_role_users & remove_role_users & view_role_users) + organization->admin + + permission client_create_permission = client_create + team->client_create + organization->admin + permission channel_create_permission = channel_create + team->channel_create + organization->admin + permission group_create_permission = group_create + team->group_create + organization->admin + + permission client_update_permission = client_update + team->client_update + organization->admin + permission client_read_permission = client_read + team->client_read + organization->admin + permission client_delete_permission = client_delete + team->client_delete + organization->admin + permission client_set_parent_group_permission = client_set_parent_group + team->client_set_parent_group + organization->admin + permission client_connect_to_channel_permission = client_connect_to_channel + team->client_connect_to_channel + organization->admin + + permission client_manage_role_permission = client_manage_role + team->client_manage_role + organization->admin + permission client_add_role_users_permission = client_add_role_users + team->client_add_role_users + organization->admin + permission client_remove_role_users_permission = client_remove_role_users + team->client_remove_role_users + organization->admin + permission client_view_role_users_permission = client_view_role_users + team->client_view_role_users + organization->admin + + permission channel_update_permission = channel_update + team->channel_update + organization->admin + permission channel_read_permission = channel_read + team->channel_read + organization->admin + permission channel_delete_permission = channel_delete + team->channel_delete + organization->admin + permission channel_set_parent_group_permission = channel_set_parent_group + team->channel_set_parent_group + organization->admin + permission channel_connect_to_client_permission = channel_connect_to_client + team->channel_connect_to_client + organization->admin + permission channel_publish_permission = channel_publish + team->channel_publish + organization->admin + permission channel_subscribe_permission = channel_subscribe + team->channel_subscribe + organization->admin + + permission channel_manage_role_permission = channel_manage_role + team->channel_manage_role + organization->admin + permission channel_add_role_users_permission = channel_add_role_users + team->channel_add_role_users + organization->admin + permission channel_remove_role_users_permission = channel_remove_role_users + team->channel_remove_role_users + organization->admin + permission channel_view_role_users_permission = channel_view_role_users + team->channel_view_role_users + organization->admin + + permission group_update_permission = group_update + team->group_update + organization->admin + permission group_membership_permission = group_membership + team->group_membership + organization->admin + permission group_read_permission = group_read + team->group_read + organization->admin + permission group_delete_permission = group_delete + team->group_delete + organization->admin + permission group_set_child_permission = group_set_child + team->group_set_child + organization->admin + permission group_set_parent_permission = group_set_parent + team->group_set_parent + organization->admin + + permission group_manage_role_permission = group_manage_role + team->group_manage_role + organization->admin + permission group_add_role_users_permission = group_add_role_users + team->group_add_role_users + organization->admin + permission group_remove_role_users_permission = group_remove_role_users + team->group_remove_role_users + organization->admin + permission group_view_role_users_permission = group_view_role_users + team->group_view_role_users + organization->admin + + // Magistrala-specific permissions + permission alarm_create_permission = alarm_create + team->alarm_create + organization->admin + permission alarm_update_permission = alarm_update + team->alarm_update + organization->admin + permission alarm_read_permission = alarm_read + team->alarm_read + organization->admin + permission alarm_delete_permission = alarm_delete + team->alarm_delete + organization->admin + permission alarm_manage_role_permission = alarm_manage_role + team->alarm_manage_role + organization->admin + permission alarm_add_role_users_permission = alarm_add_role_users + team->alarm_add_role_users + organization->admin + permission alarm_remove_role_users_permission = alarm_remove_role_users + team->alarm_remove_role_users + organization->admin + permission alarm_view_role_users_permission = alarm_view_role_users + team->alarm_view_role_users + organization->admin + permission rule_create_permission = rule_create + team->rule_create + organization->admin + permission rule_update_permission = rule_update + team->rule_update + organization->admin + permission rule_read_permission = rule_read + team->rule_read + organization->admin + permission rule_delete_permission = rule_delete + team->rule_delete + organization->admin + permission rule_manage_role_permission = rule_manage_role + team->rule_manage_role + organization->admin + permission rule_add_role_users_permission = rule_add_role_users + team->rule_add_role_users + organization->admin + permission rule_remove_role_users_permission = rule_remove_role_users + team->rule_remove_role_users + organization->admin + permission rule_view_role_users_permission = rule_view_role_users + team->rule_view_role_users + organization->admin + permission report_create_permission = report_create + team->report_create + organization->admin + permission report_update_permission = report_update + team->report_update + organization->admin + permission report_read_permission = report_read + team->report_read + organization->admin + permission report_delete_permission = report_delete + team->report_delete + organization->admin + permission report_manage_role_permission = report_manage_role + team->report_manage_role + organization->admin + permission report_add_role_users_permission = report_add_role_users + team->report_add_role_users + organization->admin + permission report_remove_role_users_permission = report_remove_role_users + team->report_remove_role_users + organization->admin + permission report_view_role_users_permission = report_view_role_users + team->report_view_role_users + organization->admin + +} + +// Add this relation and permission in future while adding organization +definition team { + relation organization: organization + relation parent_team: team + + relation delete: role#member + relation enable: role#member | team#member + relation disable: role#member | team#member + relation update: role#member + relation read: role#member + + relation set_parent: role#member + relation set_child: role#member + + relation member: role#member + + relation manage_role: role#member + relation add_role_users: role#member + relation remove_role_users: role#member + relation view_role_users: role#member + + relation subteam_delete: role#member + relation subteam_update: role#member + relation subteam_read: role#member + + relation subteam_member: role#member + + relation subteam_set_child: role#member + relation subteam_set_parent: role#member + + relation subteam_manage_role: role#member + relation subteam_add_role_users: role#member + relation subteam_remove_role_users: role#member + relation subteam_view_role_users: role#member + + // Domain related permission + + relation domain_update: role#member | team#member + relation domain_read: role#member | team#member + relation domain_membership: role#member | team#member + relation domain_delete: role#member | team#member + + relation domain_manage_role: role#member | team#member + relation domain_add_role_users: role#member | team#member + relation domain_remove_role_users: role#member | team#member + relation domain_view_role_users: role#member | team#member + + relation client_create: role#member | team#member + relation channel_create: role#member | team#member + relation group_create: role#member | team#member + + relation client_update: role#member | team#member + relation client_read: role#member | team#member + relation client_delete: role#member | team#member + relation client_set_parent_group: role#member | team#member + relation client_connect_to_channel: role#member | team#member + + relation client_manage_role: role#member | team#member + relation client_add_role_users: role#member | team#member + relation client_remove_role_users: role#member | team#member + relation client_view_role_users: role#member | team#member + + relation channel_update: role#member | team#member + relation channel_read: role#member | team#member + relation channel_delete: role#member | team#member + relation channel_set_parent_group: role#member | team#member + relation channel_connect_to_client: role#member | team#member + relation channel_publish: role#member | team#member + relation channel_subscribe: role#member | team#member + + relation channel_manage_role: role#member | team#member + relation channel_add_role_users: role#member | team#member + relation channel_remove_role_users: role#member | team#member + relation channel_view_role_users: role#member | team#member + + relation group_update: role#member | team#member + relation group_membership: role#member | team#member + relation group_read: role#member | team#member + relation group_delete: role#member | team#member + relation group_set_child: role#member | team#member + relation group_set_parent: role#member | team#member + + relation group_manage_role: role#member | team#member + relation group_add_role_users: role#member | team#member + relation group_remove_role_users: role#member | team#member + relation group_view_role_users: role#member | team#member + + // Magistrala-specific relations + relation alarm_create: role#member | team#member + relation alarm_update: role#member | team#member + relation alarm_read: role#member | team#member + relation alarm_delete: role#member | team#member + relation alarm_manage_role: role#member | team#member + relation alarm_add_role_users: role#member | team#member + relation alarm_remove_role_users: role#member | team#member + relation alarm_view_role_users: role#member | team#member + relation rule_create: role#member | team#member + relation rule_update: role#member | team#member + relation rule_read: role#member | team#member + relation rule_delete: role#member | team#member + relation rule_manage_role: role#member | team#member + relation rule_add_role_users: role#member | team#member + relation rule_remove_role_users: role#member | team#member + relation rule_view_role_users: role#member | team#member + relation report_create: role#member | team#member + relation report_update: role#member | team#member + relation report_read: role#member | team#member + relation report_delete: role#member | team#member + relation report_manage_role: role#member | team#member + relation report_add_role_users: role#member | team#member + relation report_remove_role_users: role#member | team#member + relation report_view_role_users: role#member | team#member + + permission delete_permission = delete + organization->team_delete + parent_team->subteam_delete + organization->admin + permission update_permission = update + organization->team_update + parent_team->subteam_update + organization->admin + permission read_permission = read + organization->team_read + parent_team->subteam_read + organization->admin + + permission set_parent_permission = set_parent + organization->team_set_parent + parent_team->subteam_set_parent + organization->admin + permission set_child_permisssion = set_child + organization->team_set_child + parent_team->subteam_set_child + organization->admin + + permission membership = member + organization->team_member + parent_team->subteam_member + organization->admin + + permission manage_role_permission = manage_role + organization->team_manage_role + parent_team->subteam_manage_role + organization->admin + permission add_role_users_permission = add_role_users + organization->team_add_role_users + parent_team->subteam_add_role_users + organization->admin + permission remove_role_users_permission = remove_role_users + organization->team_remove_role_users + parent_team->subteam_remove_role_users + organization->admin + permission view_role_users_permission = view_role_users + organization->team_view_role_users + parent_team->subteam_view_role_users + organization->admin +} + + +definition organization { + relation platform: platform + relation administrator: user + + relation delete: role#member + relation update: role#member + relation read: role#member + + relation member: role#member + + relation manage_role: role#member + relation add_role_users: role#member + relation remove_role_users: role#member + relation view_role_users: role#member + + relation team_create: role#member + + relation team_delete: role#member + relation team_update: role#member + relation team_read: role#member + + relation team_member: role#member // Will be member of all the teams in the organization + + relation team_set_child: role#member + relation team_set_parent: role#member + + relation team_manage_role: role#member + relation team_add_role_users: role#member + relation team_remove_role_users: role#member + relation team_view_role_users: role#member + + permission admin = administrator + platform->administrator + permission delete_permission = admin + delete->member + permission update_permission = admin + update->member + permission read_permission = admin + read->member + + permission membership = admin + member->member + + permission team_create_permission = admin + team_create->member + + permission manage_role_permission = admin + manage_role + permission add_role_users_permisson = admin + add_role_users + permission remove_role_users_permission = admin + remove_role_users + permission view_role_users_permission = admin + view_role_users +} + + +definition platform { + relation administrator: user + relation member: user + + permission admin = administrator + permission membership = administrator + member +} +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +// Merge documentation +// - Source A (base): docker/supermq-docker/spicedb/schema.zed (SuperMQ upstream schema) +// - Source B (overlay): docker/spicedb/override-schema.zed (Magistrala schema extensions) +// - Merge script: scripts/combined-schema.sh +// - Output: docker/spicedb/combined-schema.zed +// +// How merge works: +// 1. The first `definition domain { ... }` block is treated as explicit domain overlay. +// 2. The first `definition team { ... }` block is treated as explicit team overlay. +// 3. Domain overlay relations/permissions are injected into SuperMQ `definition domain`. +// 4. Team overlay relations are injected into SuperMQ `definition team`. +// 5. `permission membership_extension = ...` from the domain overlay is injected into +// SuperMQ `domain.permission membership` before `organization->admin`. +// 6. Overlay `definition domain` and `definition team` blocks are removed before append, +// so only merged SuperMQ domain/team definitions remain. +// 7. Remaining definitions in this file (for example `alarm`, `rule`, `report`) are appended. +// +// Maintenance notes: +// - Keep all custom domain/team merge lines inside the two overlay blocks below. +// - Update `permission membership_extension` whenever domain membership additions change. +// - Regenerate combined schema with: `sh scripts/combine-schema.sh` +// - `scripts/supermq.sh` also regenerates combined schema after refreshing SuperMQ docker files. + +// Overlay domain block consumed by scripts/combine-schema.sh during merge. + +// Overlay team block consumed by scripts/combine-schema.sh during merge. + +definition alarm { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->alarm_update_permission +permission read_permission = read + domain->alarm_read_permission +permission delete_permission = delete + domain->alarm_delete_permission + +permission manage_role_permission = manage_role + domain->alarm_manage_role_permission +permission add_role_users_permission = add_role_users + domain->alarm_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->alarm_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->alarm_view_role_users_permission +} + +definition rule { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->rule_update_permission +permission read_permission = read + domain->rule_read_permission +permission delete_permission = delete + domain->rule_delete_permission + +permission manage_role_permission = manage_role + domain->rule_manage_role_permission +permission add_role_users_permission = add_role_users + domain->rule_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->rule_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->rule_view_role_users_permission +} + +definition report { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->report_update_permission +permission read_permission = read + domain->report_read_permission +permission delete_permission = delete + domain->report_delete_permission + +permission manage_role_permission = manage_role + domain->report_manage_role_permission +permission add_role_users_permission = add_role_users + domain->report_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->report_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->report_view_role_users_permission +} diff --git a/docker/spicedb/override-schema.zed b/docker/spicedb/override-schema.zed new file mode 100644 index 000000000..04201e318 --- /dev/null +++ b/docker/spicedb/override-schema.zed @@ -0,0 +1,187 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +// Merge documentation +// - Source A (base): docker/supermq-docker/spicedb/schema.zed (SuperMQ upstream schema) +// - Source B (overlay): docker/spicedb/override-schema.zed (Magistrala schema extensions) +// - Merge script: scripts/combined-schema.sh +// - Output: docker/spicedb/combined-schema.zed +// +// How merge works: +// 1. The first `definition domain { ... }` block is treated as explicit domain overlay. +// 2. The first `definition team { ... }` block is treated as explicit team overlay. +// 3. Domain overlay relations/permissions are injected into SuperMQ `definition domain`. +// 4. Team overlay relations are injected into SuperMQ `definition team`. +// 5. `permission membership_extension = ...` from the domain overlay is injected into +// SuperMQ `domain.permission membership` before `organization->admin`. +// 6. Overlay `definition domain` and `definition team` blocks are removed before append, +// so only merged SuperMQ domain/team definitions remain. +// 7. Remaining definitions in this file (for example `alarm`, `rule`, `report`) are appended. +// +// Maintenance notes: +// - Keep all custom domain/team merge lines inside the two overlay blocks below. +// - Update `permission membership_extension` whenever domain membership additions change. +// - Regenerate combined schema with: `sh scripts/combine-schema.sh` +// - `scripts/supermq.sh` also regenerates combined schema after refreshing SuperMQ docker files. + +// Overlay domain block consumed by scripts/combine-schema.sh during merge. +definition domain { + + // Magistrala-specific relations + relation alarm_create: role#member | team#member + relation alarm_update: role#member | team#member + relation alarm_read: role#member | team#member + relation alarm_delete: role#member | team#member + relation alarm_manage_role: role#member | team#member + relation alarm_add_role_users: role#member | team#member + relation alarm_remove_role_users: role#member | team#member + relation alarm_view_role_users: role#member | team#member + + relation rule_create: role#member | team#member + relation rule_update: role#member | team#member + relation rule_read: role#member | team#member + relation rule_delete: role#member | team#member + relation rule_manage_role: role#member | team#member + relation rule_add_role_users: role#member | team#member + relation rule_remove_role_users: role#member | team#member + relation rule_view_role_users: role#member | team#member + + relation report_create: role#member | team#member + relation report_update: role#member | team#member + relation report_read: role#member | team#member + relation report_delete: role#member | team#member + relation report_manage_role: role#member | team#member + relation report_add_role_users: role#member | team#member + relation report_remove_role_users: role#member | team#member + relation report_view_role_users: role#member | team#member + + // Magistrala-specific permissions + permission alarm_create_permission = alarm_create + team->alarm_create + organization->admin + permission alarm_update_permission = alarm_update + team->alarm_update + organization->admin + permission alarm_read_permission = alarm_read + team->alarm_read + organization->admin + permission alarm_delete_permission = alarm_delete + team->alarm_delete + organization->admin + permission alarm_manage_role_permission = alarm_manage_role + team->alarm_manage_role + organization->admin + permission alarm_add_role_users_permission = alarm_add_role_users + team->alarm_add_role_users + organization->admin + permission alarm_remove_role_users_permission = alarm_remove_role_users + team->alarm_remove_role_users + organization->admin + permission alarm_view_role_users_permission = alarm_view_role_users + team->alarm_view_role_users + organization->admin + + permission rule_create_permission = rule_create + team->rule_create + organization->admin + permission rule_update_permission = rule_update + team->rule_update + organization->admin + permission rule_read_permission = rule_read + team->rule_read + organization->admin + permission rule_delete_permission = rule_delete + team->rule_delete + organization->admin + permission rule_manage_role_permission = rule_manage_role + team->rule_manage_role + organization->admin + permission rule_add_role_users_permission = rule_add_role_users + team->rule_add_role_users + organization->admin + permission rule_remove_role_users_permission = rule_remove_role_users + team->rule_remove_role_users + organization->admin + permission rule_view_role_users_permission = rule_view_role_users + team->rule_view_role_users + organization->admin + + permission report_create_permission = report_create + team->report_create + organization->admin + permission report_update_permission = report_update + team->report_update + organization->admin + permission report_read_permission = report_read + team->report_read + organization->admin + permission report_delete_permission = report_delete + team->report_delete + organization->admin + permission report_manage_role_permission = report_manage_role + team->report_manage_role + organization->admin + permission report_add_role_users_permission = report_add_role_users + team->report_add_role_users + organization->admin + permission report_remove_role_users_permission = report_remove_role_users + team->report_remove_role_users + organization->admin + permission report_view_role_users_permission = report_view_role_users + team->report_view_role_users + organization->admin + + // Explicit extension injected into SuperMQ domain `permission membership`. + permission membership_extension = alarm_create + alarm_update + alarm_read + alarm_delete + alarm_manage_role + alarm_add_role_users + alarm_remove_role_users + alarm_view_role_users + rule_create + rule_update + rule_read + rule_delete + rule_manage_role + rule_add_role_users + rule_remove_role_users + rule_view_role_users + report_create + report_update + report_read + report_delete + report_manage_role + report_add_role_users + report_remove_role_users + report_view_role_users + +} + +// Overlay team block consumed by scripts/combine-schema.sh during merge. +definition team { + + relation alarm_create: role#member | team#member + relation alarm_update: role#member | team#member + relation alarm_read: role#member | team#member + relation alarm_delete: role#member | team#member + relation alarm_manage_role: role#member | team#member + relation alarm_add_role_users: role#member | team#member + relation alarm_remove_role_users: role#member | team#member + relation alarm_view_role_users: role#member | team#member + + relation rule_create: role#member | team#member + relation rule_update: role#member | team#member + relation rule_read: role#member | team#member + relation rule_delete: role#member | team#member + relation rule_manage_role: role#member | team#member + relation rule_add_role_users: role#member | team#member + relation rule_remove_role_users: role#member | team#member + relation rule_view_role_users: role#member | team#member + + relation report_create: role#member | team#member + relation report_update: role#member | team#member + relation report_read: role#member | team#member + relation report_delete: role#member | team#member + relation report_manage_role: role#member | team#member + relation report_add_role_users: role#member | team#member + relation report_remove_role_users: role#member | team#member + relation report_view_role_users: role#member | team#member + +} + +definition alarm { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->alarm_update_permission +permission read_permission = read + domain->alarm_read_permission +permission delete_permission = delete + domain->alarm_delete_permission + +permission manage_role_permission = manage_role + domain->alarm_manage_role_permission +permission add_role_users_permission = add_role_users + domain->alarm_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->alarm_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->alarm_view_role_users_permission +} + +definition rule { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->rule_update_permission +permission read_permission = read + domain->rule_read_permission +permission delete_permission = delete + domain->rule_delete_permission + +permission manage_role_permission = manage_role + domain->rule_manage_role_permission +permission add_role_users_permission = add_role_users + domain->rule_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->rule_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->rule_view_role_users_permission +} + +definition report { +relation domain: domain + +relation update: role#member +relation read: role#member +relation delete: role#member + +relation manage_role: role#member +relation add_role_users: role#member +relation remove_role_users: role#member +relation view_role_users: role#member + +permission update_permission = update + domain->report_update_permission +permission read_permission = read + domain->report_read_permission +permission delete_permission = delete + domain->report_delete_permission + +permission manage_role_permission = manage_role + domain->report_manage_role_permission +permission add_role_users_permission = add_role_users + domain->report_add_role_users_permission +permission remove_role_users_permission = remove_role_users + domain->report_remove_role_users_permission +permission view_role_users_permission = view_role_users + domain->report_view_role_users_permission +} diff --git a/docker/supermq-docker-compose.override.yaml b/docker/supermq-docker-compose.override.yaml index 8b7aef5c3..1a72818a9 100644 --- a/docker/supermq-docker-compose.override.yaml +++ b/docker/supermq-docker-compose.override.yaml @@ -2,9 +2,12 @@ # SPDX-License-Identifier: Apache-2.0 services: + spicedb: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} spicedb-migrate: networks: !override @@ -17,7 +20,8 @@ services: auth-db: networks: !override - magistrala-base-net - + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} auth-redis: networks: !override - magistrala-base-net @@ -25,6 +29,8 @@ services: auth: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} domains-db: networks: !override @@ -37,6 +43,8 @@ services: domains: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} clients-db: networks: !override @@ -49,6 +57,8 @@ services: clients: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} channels-redis: networks: !override @@ -61,6 +71,8 @@ services: channels: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} users-db: networks: !override @@ -77,6 +89,8 @@ services: groups: networks: !override - magistrala-base-net + volumes: + - ../spicedb/combined-schema.zed:${SMQ_SPICEDB_SCHEMA_FILE} jaeger: networks: !override @@ -170,10 +184,10 @@ services: AM_CERTS_OPENBAO_UNSEAL_KEY_2: ${AM_CERTS_OPENBAO_UNSEAL_KEY_2} AM_CERTS_OPENBAO_UNSEAL_KEY_3: ${AM_CERTS_OPENBAO_UNSEAL_KEY_3} AM_CERTS_OPENBAO_ROOT_TOKEN: ${AM_CERTS_OPENBAO_ROOT_TOKEN} - + AM_JAEGER_URL: ${AM_JAEGER_URL} AM_JAEGER_TRACE_RATIO: ${AM_JAEGER_TRACE_RATIO} - + AM_AUTH_GRPC_URL: ${AM_AUTH_GRPC_URL} AM_AUTH_GRPC_TIMEOUT: ${AM_AUTH_GRPC_TIMEOUT} AM_AUTH_GRPC_CLIENT_CERT: ${AM_AUTH_GRPC_CLIENT_CERT} @@ -209,3 +223,5 @@ services: env_file: !override - ./.env - ../../docker/.env + + diff --git a/go.mod b/go.mod index e4b55b5de..a00cf30d7 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,12 @@ module github.com/absmach/magistrala -go 1.25.7 +go 1.26.0 require ( github.com/0x6flab/namegenerator v1.4.0 github.com/absmach/callhome v0.18.2 github.com/absmach/certs v0.18.5 - github.com/absmach/supermq v0.18.6-0.20260226153547-15a6c026e943 + github.com/absmach/supermq v0.19.0 github.com/authzed/authzed-go v1.8.0 github.com/authzed/grpcutil v0.0.0-20250221190651-1985b19b35b8 github.com/caarlos0/env/v11 v11.4.0 @@ -36,9 +36,9 @@ require ( github.com/traefik/yaegi v0.16.1 github.com/vadv/gopher-lua-libs v0.8.0 github.com/yuin/gopher-lua v1.1.1 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 - go.opentelemetry.io/otel v1.40.0 - go.opentelemetry.io/otel/trace v1.40.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0 + go.opentelemetry.io/otel v1.41.0 + go.opentelemetry.io/otel/trace v1.41.0 golang.org/x/sync v0.19.0 gonum.org/v1/gonum v0.17.0 google.golang.org/grpc v1.79.1 @@ -47,13 +47,25 @@ require ( moul.io/http2curl v1.0.0 ) -require go.uber.org/atomic v1.11.0 // indirect +require ( + github.com/antlr4-go/antlr/v4 v4.13.1 // indirect + github.com/authzed/cel-go v0.20.2 // indirect + github.com/authzed/spicedb v1.49.2 // indirect + github.com/ccoveille/go-safecast/v2 v2.0.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/go-errors/errors v1.5.1 // indirect + github.com/go-logr/zerologr v1.2.3 // indirect + github.com/rs/zerolog v1.34.0 // indirect + github.com/stoewer/go-strcase v1.3.1 // indirect + go.uber.org/atomic v1.11.0 // indirect + golang.org/x/exp v0.0.0-20251017212417-90e834f514db // indirect + sigs.k8s.io/controller-runtime v0.22.4 // indirect +) require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1 // indirect - cloud.google.com/go/compute/metadata v0.9.0 // indirect dario.cat/mergo v1.0.2 // indirect - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.1.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect @@ -115,7 +127,7 @@ require ( github.com/planetscale/vtprotobuf v0.6.1-0.20240917153116-6f2963f01587 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.67.4 // indirect + github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.19.2 // indirect github.com/rabbitmq/amqp091-go v1.10.0 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect @@ -132,10 +144,10 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/metric v1.41.0 // indirect + go.opentelemetry.io/otel/sdk v1.41.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect diff --git a/go.sum b/go.sum index 658834347..7a610a043 100644 --- a/go.sum +++ b/go.sum @@ -3,18 +3,23 @@ buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-202512091757 buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20251209175733-2a1774d88802.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.122.0 h1:0JTLGrcSIs3HIGsgVPvTx3cfyFSP/k9CI8vLPHTd6Wc= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= +filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/0x6flab/namegenerator v1.4.0 h1:QnkI813SZsI/hYnKD9pg3mkIlcYzCx0N4hnzb0YYME4= github.com/0x6flab/namegenerator v1.4.0/go.mod h1:2sQzXuS6dX/KEwWtB6GJU729O3m4gBdD5oAU8hd0SyY= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= +github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= @@ -30,17 +35,23 @@ github.com/absmach/mgate v0.5.0 h1:RV2Aalra3xIm+XTs13TM7iE7v4WTL2SKhKcPbKr22Ac= github.com/absmach/mgate v0.5.0/go.mod h1:0KVq7mxM0wayosmyXPPxp1EL0c2d9kRp5V8NZCKdetA= github.com/absmach/senml v1.0.8 h1:+opem/r4g6c6eA/JLyCIuksyEhj7eBdysY3pEmy1mqo= github.com/absmach/senml v1.0.8/go.mod h1:DRhzHLgvQoIUHroBgpFrSWso+bJZO9E96RlHAHy+VRI= -github.com/absmach/supermq v0.18.6-0.20260226153547-15a6c026e943 h1:DbQ0t46WNqMVHcks8D4XcMIYU3m5lZ6hmbhr2Wcln+Y= -github.com/absmach/supermq v0.18.6-0.20260226153547-15a6c026e943/go.mod h1:VLInclhsnLm/mo1qng3ac7T0bJnteqH/y2mPxML6H+4= +github.com/absmach/supermq v0.19.0 h1:sbqfzmSiMp9GEaCWgpREiLC0tFsSntgLIyAaZs7SnRY= +github.com/absmach/supermq v0.19.0/go.mod h1:SG2yIzlJmc26ZjDVSkoapc6HZ6W13SUsaN3sAErfgC4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ= +github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/authzed/authzed-go v1.8.0 h1:cRka8J8QXGl+nyNrhsiPSFJUluIG1tuTXnG8ad2LZ1Y= github.com/authzed/authzed-go v1.8.0/go.mod h1:WC3x/SuVvclBlDYMg9V7e5c/J/KGGwG+cSw2WQBbodk= +github.com/authzed/cel-go v0.20.2 h1:GlmLecGry7Z8HU0k+hmaHHUV05ZHrsFxduXHtIePvck= +github.com/authzed/cel-go v0.20.2/go.mod h1:pJHVFWbqUHV1J+klQoZubdKswlbxcsbojda3mye9kiU= github.com/authzed/grpcutil v0.0.0-20250221190651-1985b19b35b8 h1:y17oq4U8n+k1OcIGGDsjYdIdp4QywGcE7ZphIvtfEbo= github.com/authzed/grpcutil v0.0.0-20250221190651-1985b19b35b8/go.mod h1:Pf1ZSi41EePvx1GC1DeEJw5dn35iUcxZHqpHuG1Rpic= +github.com/authzed/spicedb v1.49.2 h1:6LKOxiNN7K18x4xs2NB0dhnDNDypbpuOP7s06AwjCH8= +github.com/authzed/spicedb v1.49.2/go.mod h1:I9t8PtFBxUHsSZKfrkK6bxbMy8La7LYjkpgw6UpNHQs= github.com/aws/aws-sdk-go v1.34.0/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.40.45 h1:QN1nsY27ssD/JmW4s83qmSb+uL6DG4GmCDzjmJB4xUI= github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= @@ -57,6 +68,8 @@ github.com/caarlos0/env/v11 v11.4.0 h1:Kcb6t5kIIr4XkoQC9AF2j+8E1Jsrl3Wz/hhm1LtoG github.com/caarlos0/env/v11 v11.4.0/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U= github.com/cbroglie/mustache v1.0.1 h1:ivMg8MguXq/rrz2eu3tw6g3b16+PQhoTn6EZAhst2mw= github.com/cbroglie/mustache v1.0.1/go.mod h1:R/RUa+SobQ14qkP4jtx5Vke5sDytONDQXNLPY/PO69g= +github.com/ccoveille/go-safecast/v2 v2.0.0 h1:+5eyITXAUj3wMjad6cRVJKGnC7vDS55zk0INzJagub0= +github.com/ccoveille/go-safecast/v2 v2.0.0/go.mod h1:JIYA4CAR33blIDuE6fSwCp2sz1oOBahXnvmdBhOAABs= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -78,6 +91,7 @@ github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -109,6 +123,8 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eclipse/paho.mqtt.golang v1.5.1 h1:/VSOv3oDLlpqR2Epjn1Q7b2bSTplJIeV2ISgCl2W7nE= github.com/eclipse/paho.mqtt.golang v1.5.1/go.mod h1:1/yJCneuyOoCOzKSsOTUc0AJfpsItBGWvYpBLimhArU= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -131,6 +147,8 @@ github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sa github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug= github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs= github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -150,17 +168,22 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zerologr v1.2.3 h1:up5N9vcH9Xck3jJkXzgyOxozT14R47IyDODz8LM1KSs= +github.com/go-logr/zerologr v1.2.3/go.mod h1:BxwGo7y5zgSHYR1BjbnHPyF/5ZjVKfKxAZANVu6E8Ho= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= @@ -191,6 +214,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= +github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -291,8 +316,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= -github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -330,6 +355,7 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -337,6 +363,8 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= @@ -371,6 +399,10 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/oklog/ulid/v2 v2.1.1 h1:suPZ4ARWLOJLegGFiZZ1dFAkqzhMjL3J1TzI+5wHz8s= github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ= +github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= +github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= +github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= +github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -417,8 +449,8 @@ github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvM github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.67.4 h1:yR3NqWO1/UyO1w2PhUvXlGQs/PtFmoveVO0KZ4+Lvsc= -github.com/prometheus/common v0.67.4/go.mod h1:gP0fq6YjjNCLssJCQp0yk4M8W6ikLURwkdd/YKtTbyI= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -433,8 +465,11 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/rubenv/sql-migrate v1.8.1 h1:EPNwCvjAowHI3TnZ+4fQu3a915OpnQoPAjTXCGOy2U0= github.com/rubenv/sql-migrate v1.8.1/go.mod h1:BTIKBORjzyxZDS6dzoiw6eAFYJ1iNlGAtjn4LGeVjS8= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -474,6 +509,8 @@ github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/sqids/sqids-go v0.4.1 h1:eQKYzmAZbLlRwHeHYPF35QhgxwZHLnlmVj9AkIj/rrw= github.com/sqids/sqids-go v0.4.1/go.mod h1:EMwHuPQgSNFS0A49jESTfIQS+066XQTVhukrzEPScl8= +github.com/stoewer/go-strcase v1.3.1 h1:iS0MdW+kVTxgMoE1LAZyMiYJFKlOzLooE4MxjirtkAs= +github.com/stoewer/go-strcase v1.3.1/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -526,22 +563,22 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0 h1:XmiuHzgJt067+a6kwyAzkhXooYVv3/TOw9cM2VfJgUM= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.65.0/go.mod h1:KDgtbWKTQs4bM+VPUr6WlL9m/WXcmkCcBlIzqxPGzmI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0 h1:7iP2uCb7sGddAr30RRS6xjKy7AZ2JtTOPA3oolgVSw8= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.65.0/go.mod h1:c7hN3ddxs/z6q9xwvfLPk+UHlWRQyaeR1LdgfL/66l0= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0 h1:PnV4kVnw0zOmwwFkAzCN5O07fw1YOIQor120zrh0AVo= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.66.0/go.mod h1:ofAwF4uinaf8SXdVzzbL4OsxJ3VfeEg3f/F6CeF49/Y= +go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= +go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0 h1:ao6Oe+wSebTlQ1OEht7jlYTzQKE+pnx/iNywFvTbuuI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.41.0/go.mod h1:u3T6vz0gh/NVzgDgiwkgLxpsSF6PaPmo2il0apGJbls= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ= +go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps= +go.opentelemetry.io/otel/sdk v1.41.0 h1:YPIEXKmiAwkGl3Gu1huk1aYWwtpRLeskpV+wPisxBp8= +go.opentelemetry.io/otel/sdk v1.41.0/go.mod h1:ahFdU0G5y8IxglBf0QBJXgSe7agzjE4GiTJ6HT9ud90= +go.opentelemetry.io/otel/sdk/metric v1.41.0 h1:siZQIYBAUd1rlIWQT2uCxWJxcCO7q3TriaMlf08rXw8= +go.opentelemetry.io/otel/sdk/metric v1.41.0/go.mod h1:HNBuSvT7ROaGtGI50ArdRLUnvRTRGniSUZbxiWxSO8Y= +go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= +go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -595,6 +632,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -660,9 +699,11 @@ golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -703,6 +744,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -769,3 +812,5 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= moul.io/http2curl v1.0.0 h1:6XwpyZOYsgZJrU8exnG87ncVkU1FVCcTRpwzOkTDUi8= moul.io/http2curl v1.0.0/go.mod h1:f6cULg+e4Md/oW1cYmwW4IWQOVl2lGbmCNGOHvzX2kE= +sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A= +sigs.k8s.io/controller-runtime v0.22.4/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= diff --git a/pkg/policies/evaluator.go b/pkg/policies/evaluator.go new file mode 100644 index 000000000..edc21342e --- /dev/null +++ b/pkg/policies/evaluator.go @@ -0,0 +1,6 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package policies + +const RulesType = "rules" diff --git a/re/api/endpoints.go b/re/api/endpoints.go index af74680e4..6401495fb 100644 --- a/re/api/endpoints.go +++ b/re/api/endpoints.go @@ -44,7 +44,7 @@ func viewRuleEndpoint(s re.Service) endpoint.Endpoint { if err := req.validate(); err != nil { return viewRuleRes{}, err } - rule, err := s.ViewRule(ctx, session, req.id) + rule, err := s.ViewRule(ctx, session, req.id, req.withRoles) if err != nil { return viewRuleRes{}, err } diff --git a/re/api/endpoints_test.go b/re/api/endpoints_test.go index 4d5a1d26f..30b289f94 100644 --- a/re/api/endpoints_test.go +++ b/re/api/endpoints_test.go @@ -334,7 +334,7 @@ func TestViewRuleEndpoint(t *testing.T) { } authCall := authn.On("Authenticate", mock.Anything, tc.token).Return(tc.authnRes, tc.authnErr) - svcCall := svc.On("ViewRule", mock.Anything, tc.authnRes, tc.id).Return(tc.svcRes, tc.svcErr) + svcCall := svc.On("ViewRule", mock.Anything, tc.authnRes, tc.id, false).Return(tc.svcRes, tc.svcErr) res, err := req.make() assert.Nil(t, err, fmt.Sprintf("%s: unexpected error %s", tc.desc, err)) diff --git a/re/api/requests.go b/re/api/requests.go index cb3c9356f..ca508355b 100644 --- a/re/api/requests.go +++ b/re/api/requests.go @@ -33,7 +33,8 @@ func (req addRuleReq) validate() error { } type viewRuleReq struct { - id string + id string + withRoles bool } func (req viewRuleReq) validate() error { diff --git a/re/api/transport.go b/re/api/transport.go index d5e830cee..b251ec3b6 100644 --- a/re/api/transport.go +++ b/re/api/transport.go @@ -16,6 +16,7 @@ import ( apiutil "github.com/absmach/supermq/api/http/util" smqauthn "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/errors" + roleManagerHttp "github.com/absmach/supermq/pkg/roles/rolemanager/api" "github.com/go-chi/chi/v5" kithttp "github.com/go-kit/kit/transport/http" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -36,6 +37,8 @@ func MakeHandler(svc re.Service, authn smqauthn.AuthNMiddleware, mux *chi.Mux, l r.Use(authn.WithOptions(smqauthn.WithDomainCheck(true)).Middleware()) r.Route("/{domainID}", func(r chi.Router) { r.Route("/rules", func(r chi.Router) { + d := roleManagerHttp.NewDecoder("ruleID") + r.Post("/", otelhttp.NewHandler(kithttp.NewServer( addRuleEndpoint(svc), decodeAddRuleRequest, @@ -50,6 +53,8 @@ func MakeHandler(svc re.Service, authn smqauthn.AuthNMiddleware, mux *chi.Mux, l opts..., ), "list_rules").ServeHTTP) + r = roleManagerHttp.EntityAvailableActionsRouter(svc, d, r, opts) + r.Route("/{ruleID}", func(r chi.Router) { r.Get("/", otelhttp.NewHandler(kithttp.NewServer( viewRuleEndpoint(svc), @@ -99,6 +104,8 @@ func MakeHandler(svc re.Service, authn smqauthn.AuthNMiddleware, mux *chi.Mux, l api.EncodeResponse, opts..., ), "disable_rule").ServeHTTP) + + roleManagerHttp.EntityRoleMangerRouter(svc, d, r, opts) }) }) }) @@ -123,7 +130,11 @@ func decodeAddRuleRequest(_ context.Context, r *http.Request) (any, error) { func decodeViewRuleRequest(_ context.Context, r *http.Request) (any, error) { id := chi.URLParam(r, ruleIdKey) - return viewRuleReq{id: id}, nil + withRoles, err := apiutil.ReadBoolQuery(r, api.RolesKey, false) + if err != nil { + return nil, errors.Wrap(apiutil.ErrValidation, err) + } + return viewRuleReq{id: id, withRoles: withRoles}, nil } func decodeUpdateRuleRequest(_ context.Context, r *http.Request) (any, error) { diff --git a/re/builtinroles.go b/re/builtinroles.go new file mode 100644 index 000000000..3b242c116 --- /dev/null +++ b/re/builtinroles.go @@ -0,0 +1,8 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package re + +import "github.com/absmach/supermq/pkg/roles" + +const BuiltInRoleAdmin roles.BuiltInRoleName = "admin" diff --git a/re/events/streams.go b/re/events/streams.go index dfeece402..46d5b07e8 100644 --- a/re/events/streams.go +++ b/re/events/streams.go @@ -11,6 +11,7 @@ import ( "github.com/absmach/supermq/pkg/events" "github.com/absmach/supermq/pkg/events/store" "github.com/absmach/supermq/pkg/messaging" + rmEvents "github.com/absmach/supermq/pkg/roles/rolemanager/events" "github.com/go-chi/chi/v5/middleware" ) @@ -32,6 +33,7 @@ var _ re.Service = (*eventStore)(nil) type eventStore struct { events.Publisher svc re.Service + rmEvents.RoleManagerEventStore } // NewEventStoreMiddleware returns wrapper around rules service that sends @@ -42,9 +44,12 @@ func NewEventStoreMiddleware(ctx context.Context, svc re.Service, url string) (r return nil, err } + res := rmEvents.NewRoleManagerEventStore("alarms", supermqPrefix, svc, publisher) + return &eventStore{ - svc: svc, - Publisher: publisher, + svc: svc, + Publisher: publisher, + RoleManagerEventStore: res, }, nil } @@ -78,8 +83,8 @@ func (es *eventStore) ListRules(ctx context.Context, session authn.Session, pm r return page, nil } -func (es *eventStore) ViewRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { - rule, err := es.svc.ViewRule(ctx, session, id) +func (es *eventStore) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { + rule, err := es.svc.ViewRule(ctx, session, id, withRoles) if err != nil { return rule, err } diff --git a/re/middleware/authorization.go b/re/middleware/authorization.go index bdebdd35f..2fc51ee9d 100644 --- a/re/middleware/authorization.go +++ b/re/middleware/authorization.go @@ -7,12 +7,14 @@ import ( "context" "github.com/absmach/magistrala/re" + "github.com/absmach/magistrala/re/operations" "github.com/absmach/supermq/pkg/authn" smqauthz "github.com/absmach/supermq/pkg/authz" "github.com/absmach/supermq/pkg/errors" "github.com/absmach/supermq/pkg/messaging" "github.com/absmach/supermq/pkg/permissions" "github.com/absmach/supermq/pkg/policies" + rolemgr "github.com/absmach/supermq/pkg/roles/rolemanager/middleware" ) var ( @@ -23,36 +25,47 @@ var ( ) type authorizationMiddleware struct { - svc re.Service - authz smqauthz.Authorization + svc re.Service + authz smqauthz.Authorization + entitiesOps permissions.EntitiesOperations[permissions.Operation] + rolemgr.RoleManagerAuthorizationMiddleware } // AuthorizationMiddleware adds authorization to the re service. -func AuthorizationMiddleware(svc re.Service, authz smqauthz.Authorization) (re.Service, error) { +func AuthorizationMiddleware(svc re.Service, authz smqauthz.Authorization, entitiesOps permissions.EntitiesOperations[permissions.Operation], roleOps permissions.Operations[permissions.RoleOperation]) (re.Service, error) { + if err := entitiesOps.Validate(); err != nil { + return nil, err + } + ram, err := rolemgr.NewAuthorization(operations.EntityType, svc, authz, roleOps) + if err != nil { + return nil, err + } return &authorizationMiddleware{ - svc: svc, - authz: authz, + svc: svc, + authz: authz, + entitiesOps: entitiesOps, + RoleManagerAuthorizationMiddleware: ram, }, nil } func (am *authorizationMiddleware) AddRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { - if err := am.authorize(ctx, re.OpAddRule, session); err != nil { + if err := am.authorize(ctx, operations.OpAddRule, session, policies.DomainType, session.DomainID); err != nil { return re.Rule{}, errors.Wrap(errDomainCreateRules, err) } return am.svc.AddRule(ctx, session, r) } -func (am *authorizationMiddleware) ViewRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { - if err := am.authorize(ctx, re.OpViewRule, session); err != nil { +func (am *authorizationMiddleware) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { + if err := am.authorize(ctx, operations.OpViewRule, session, operations.EntityType, id); err != nil { return re.Rule{}, errors.Wrap(errDomainViewRules, err) } - return am.svc.ViewRule(ctx, session, id) + return am.svc.ViewRule(ctx, session, id, withRoles) } func (am *authorizationMiddleware) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { - if err := am.authorize(ctx, re.OpUpdateRule, session); err != nil { + if err := am.authorize(ctx, operations.OpUpdateRule, session, operations.EntityType, r.ID); err != nil { return re.Rule{}, errors.Wrap(errDomainUpdateRules, err) } @@ -60,7 +73,7 @@ func (am *authorizationMiddleware) UpdateRule(ctx context.Context, session authn } func (am *authorizationMiddleware) UpdateRuleTags(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { - if err := am.authorize(ctx, re.OpUpdateRuleTags, session); err != nil { + if err := am.authorize(ctx, operations.OpUpdateRuleTags, session, operations.EntityType, r.ID); err != nil { return re.Rule{}, errors.Wrap(errDomainUpdateRules, err) } @@ -68,7 +81,7 @@ func (am *authorizationMiddleware) UpdateRuleTags(ctx context.Context, session a } func (am *authorizationMiddleware) UpdateRuleSchedule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { - if err := am.authorize(ctx, re.OpUpdateRuleSchedule, session); err != nil { + if err := am.authorize(ctx, operations.OpUpdateRuleSchedule, session, operations.EntityType, r.ID); err != nil { return re.Rule{}, errors.Wrap(errDomainUpdateRules, err) } @@ -76,7 +89,7 @@ func (am *authorizationMiddleware) UpdateRuleSchedule(ctx context.Context, sessi } func (am *authorizationMiddleware) ListRules(ctx context.Context, session authn.Session, pm re.PageMeta) (re.Page, error) { - if err := am.authorize(ctx, re.OpListRules, session); err != nil { + if err := am.authorize(ctx, operations.OpListRules, session, policies.DomainType, session.DomainID); err != nil { return re.Page{}, errors.Wrap(errDomainViewRules, err) } @@ -84,7 +97,7 @@ func (am *authorizationMiddleware) ListRules(ctx context.Context, session authn. } func (am *authorizationMiddleware) RemoveRule(ctx context.Context, session authn.Session, id string) error { - if err := am.authorize(ctx, re.OpRemoveRule, session); err != nil { + if err := am.authorize(ctx, operations.OpRemoveRule, session, operations.EntityType, id); err != nil { return errors.Wrap(errDomainDeleteRules, err) } @@ -92,7 +105,7 @@ func (am *authorizationMiddleware) RemoveRule(ctx context.Context, session authn } func (am *authorizationMiddleware) EnableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { - if err := am.authorize(ctx, re.OpEnableRule, session); err != nil { + if err := am.authorize(ctx, operations.OpEnableRule, session, operations.EntityType, id); err != nil { return re.Rule{}, errors.Wrap(errDomainUpdateRules, err) } @@ -100,7 +113,7 @@ func (am *authorizationMiddleware) EnableRule(ctx context.Context, session authn } func (am *authorizationMiddleware) DisableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { - if err := am.authorize(ctx, re.OpDisableRule, session); err != nil { + if err := am.authorize(ctx, operations.OpDisableRule, session, operations.EntityType, id); err != nil { return re.Rule{}, errors.Wrap(errDomainUpdateRules, err) } @@ -119,8 +132,8 @@ func (am *authorizationMiddleware) Cancel() error { return am.svc.Cancel() } -func (am *authorizationMiddleware) authorize(ctx context.Context, op permissions.Operation, session authn.Session) error { - perm, err := re.GetPermission(op) +func (am *authorizationMiddleware) authorize(ctx context.Context, op permissions.Operation, session authn.Session, objType, obj string) error { + perm, err := am.entitiesOps.GetPermission(operations.EntityType, op) if err != nil { return err } @@ -130,19 +143,19 @@ func (am *authorizationMiddleware) authorize(ctx context.Context, op permissions SubjectType: policies.UserType, SubjectKind: policies.UsersKind, Subject: session.DomainUserID, - Object: session.DomainID, - ObjectType: policies.DomainType, - Permission: perm, + Object: obj, + ObjectType: objType, + Permission: perm.String(), } var pat *smqauthz.PATReq if session.PatID != "" { - opName := re.OperationName(op) + opName := am.entitiesOps.OperationName(operations.EntityType, op) pat = &smqauthz.PATReq{ UserID: session.UserID, PatID: session.PatID, EntityID: session.DomainID, - EntityType: re.EntityType, + EntityType: operations.EntityType, Operation: opName, Domain: session.DomainID, } diff --git a/re/middleware/callout.go b/re/middleware/callout.go index 27e838301..26d0caf94 100644 --- a/re/middleware/callout.go +++ b/re/middleware/callout.go @@ -7,26 +7,43 @@ import ( "context" "time" + mgPolicies "github.com/absmach/magistrala/pkg/policies" "github.com/absmach/magistrala/re" + "github.com/absmach/magistrala/re/operations" "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/callout" "github.com/absmach/supermq/pkg/messaging" + "github.com/absmach/supermq/pkg/permissions" "github.com/absmach/supermq/pkg/policies" + rolemw "github.com/absmach/supermq/pkg/roles/rolemanager/middleware" ) var _ re.Service = (*calloutMiddleware)(nil) type calloutMiddleware struct { - svc re.Service - callout callout.Callout + svc re.Service + callout callout.Callout + entitiesOps permissions.EntitiesOperations[permissions.Operation] + rolemw.RoleManagerCalloutMiddleware } const entityType = "rule" -func NewCallout(svc re.Service, callout callout.Callout) (re.Service, error) { +func NewCallout(svc re.Service, callout callout.Callout, entitiesOps permissions.EntitiesOperations[permissions.Operation], roleOps permissions.Operations[permissions.RoleOperation]) (re.Service, error) { + call, err := rolemw.NewCallout(mgPolicies.RulesType, svc, callout, roleOps) + if err != nil { + return nil, err + } + + if err := entitiesOps.Validate(); err != nil { + return nil, err + } + return &calloutMiddleware{ - svc: svc, - callout: callout, + svc: svc, + callout: callout, + entitiesOps: entitiesOps, + RoleManagerCalloutMiddleware: call, }, nil } @@ -36,23 +53,23 @@ func (cm *calloutMiddleware) AddRule(ctx context.Context, session authn.Session, "count": 1, } - if err := cm.callOut(ctx, session, re.OpAddRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpAddRule, params); err != nil { return re.Rule{}, err } return cm.svc.AddRule(ctx, session, r) } -func (cm *calloutMiddleware) ViewRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { +func (cm *calloutMiddleware) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { params := map[string]any{ "entity_id": id, } - if err := cm.callOut(ctx, session, re.OpViewRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpViewRule, params); err != nil { return re.Rule{}, err } - return cm.svc.ViewRule(ctx, session, id) + return cm.svc.ViewRule(ctx, session, id, withRoles) } func (cm *calloutMiddleware) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { @@ -60,7 +77,7 @@ func (cm *calloutMiddleware) UpdateRule(ctx context.Context, session authn.Sessi "entity_id": r.ID, } - if err := cm.callOut(ctx, session, re.OpUpdateRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpUpdateRule, params); err != nil { return re.Rule{}, err } @@ -72,7 +89,7 @@ func (cm *calloutMiddleware) UpdateRuleTags(ctx context.Context, session authn.S "entity_id": r.ID, } - if err := cm.callOut(ctx, session, re.OpUpdateRuleTagsStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpUpdateRuleTags, params); err != nil { return re.Rule{}, err } @@ -84,7 +101,7 @@ func (cm *calloutMiddleware) UpdateRuleSchedule(ctx context.Context, session aut "entity_id": r.ID, } - if err := cm.callOut(ctx, session, re.OpUpdateRuleScheduleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpUpdateRuleSchedule, params); err != nil { return re.Rule{}, err } @@ -96,7 +113,7 @@ func (cm *calloutMiddleware) ListRules(ctx context.Context, session authn.Sessio "pagemeta": pm, } - if err := cm.callOut(ctx, session, re.OpListRulesStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpListRules, params); err != nil { return re.Page{}, err } @@ -108,7 +125,7 @@ func (cm *calloutMiddleware) RemoveRule(ctx context.Context, session authn.Sessi "entity_id": id, } - if err := cm.callOut(ctx, session, re.OpRemoveRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpRemoveRule, params); err != nil { return err } @@ -120,7 +137,7 @@ func (cm *calloutMiddleware) EnableRule(ctx context.Context, session authn.Sessi "entity_id": id, } - if err := cm.callOut(ctx, session, re.OpEnableRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpEnableRule, params); err != nil { return re.Rule{}, err } @@ -132,7 +149,7 @@ func (cm *calloutMiddleware) DisableRule(ctx context.Context, session authn.Sess "entity_id": id, } - if err := cm.callOut(ctx, session, re.OpDisableRuleStr, params); err != nil { + if err := cm.callOut(ctx, session, operations.OpDisableRule, params); err != nil { return re.Rule{}, err } @@ -151,7 +168,7 @@ func (cm *calloutMiddleware) Cancel() error { return cm.svc.Cancel() } -func (cm *calloutMiddleware) callOut(ctx context.Context, session authn.Session, op string, pld map[string]any) error { +func (cm *calloutMiddleware) callOut(ctx context.Context, session authn.Session, op permissions.Operation, pld map[string]any) error { var entityID string if id, ok := pld["entity_id"].(string); ok { entityID = id @@ -159,7 +176,7 @@ func (cm *calloutMiddleware) callOut(ctx context.Context, session authn.Session, req := callout.Request{ BaseRequest: callout.BaseRequest{ - Operation: op, + Operation: cm.entitiesOps.OperationName(entityType, op), EntityType: entityType, EntityID: entityID, CallerID: session.UserID, diff --git a/re/middleware/logging.go b/re/middleware/logging.go index c7afb8236..3b5abd55b 100644 --- a/re/middleware/logging.go +++ b/re/middleware/logging.go @@ -12,6 +12,7 @@ import ( "github.com/absmach/magistrala/re" "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/messaging" + rolemw "github.com/absmach/supermq/pkg/roles/rolemanager/middleware" ) var _ re.Service = (*loggingMiddleware)(nil) @@ -19,10 +20,15 @@ var _ re.Service = (*loggingMiddleware)(nil) type loggingMiddleware struct { logger *slog.Logger svc re.Service + rolemw.RoleManagerLoggingMiddleware } func LoggingMiddleware(svc re.Service, logger *slog.Logger) re.Service { - return &loggingMiddleware{logger, svc} + return &loggingMiddleware{ + logger: logger, + svc: svc, + RoleManagerLoggingMiddleware: rolemw.NewLogging("re", svc, logger), + } } func (lm *loggingMiddleware) AddRule(ctx context.Context, session authn.Session, r re.Rule) (res re.Rule, err error) { @@ -42,7 +48,7 @@ func (lm *loggingMiddleware) AddRule(ctx context.Context, session authn.Session, return lm.svc.AddRule(ctx, session, r) } -func (lm *loggingMiddleware) ViewRule(ctx context.Context, session authn.Session, id string) (res re.Rule, err error) { +func (lm *loggingMiddleware) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (res re.Rule, err error) { defer func(begin time.Time) { args := []any{ slog.String("duration", time.Since(begin).String()), @@ -59,7 +65,7 @@ func (lm *loggingMiddleware) ViewRule(ctx context.Context, session authn.Session } lm.logger.Info("View rule completed successfully", args...) }(time.Now()) - return lm.svc.ViewRule(ctx, session, id) + return lm.svc.ViewRule(ctx, session, id, withRoles) } func (lm *loggingMiddleware) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (res re.Rule, err error) { diff --git a/re/middleware/metrics.go b/re/middleware/metrics.go new file mode 100644 index 000000000..b929dfb86 --- /dev/null +++ b/re/middleware/metrics.go @@ -0,0 +1,136 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package middleware + +import ( + "context" + "time" + + "github.com/absmach/magistrala/re" + "github.com/absmach/supermq/pkg/authn" + "github.com/absmach/supermq/pkg/messaging" + rolemw "github.com/absmach/supermq/pkg/roles/rolemanager/middleware" + "github.com/go-kit/kit/metrics" +) + +type metricsMiddleware struct { + counter metrics.Counter + latency metrics.Histogram + service re.Service + rolemw.RoleManagerMetricsMiddleware +} + +var _ re.Service = (*metricsMiddleware)(nil) + +func NewMetricsMiddleware(counter metrics.Counter, latency metrics.Histogram, service re.Service) re.Service { + return &metricsMiddleware{ + counter: counter, + latency: latency, + service: service, + RoleManagerMetricsMiddleware: rolemw.NewMetrics("re", service, counter, latency), + } +} + +func (mm *metricsMiddleware) AddRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "add_rule").Add(1) + mm.latency.With("method", "add_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.AddRule(ctx, session, r) +} + +func (mm *metricsMiddleware) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "view_rule").Add(1) + mm.latency.With("method", "view_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.ViewRule(ctx, session, id, withRoles) +} + +func (mm *metricsMiddleware) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "update_rule").Add(1) + mm.latency.With("method", "update_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.UpdateRule(ctx, session, r) +} + +func (mm *metricsMiddleware) UpdateRuleTags(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "update_rule_tags").Add(1) + mm.latency.With("method", "update_rule_tags").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.UpdateRuleTags(ctx, session, r) +} + +func (mm *metricsMiddleware) UpdateRuleSchedule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "update_rule_schedule").Add(1) + mm.latency.With("method", "update_rule_schedule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.UpdateRuleSchedule(ctx, session, r) +} + +func (mm *metricsMiddleware) ListRules(ctx context.Context, session authn.Session, pm re.PageMeta) (re.Page, error) { + defer func(begin time.Time) { + mm.counter.With("method", "list_rules").Add(1) + mm.latency.With("method", "list_rules").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.ListRules(ctx, session, pm) +} + +func (mm *metricsMiddleware) RemoveRule(ctx context.Context, session authn.Session, id string) error { + defer func(begin time.Time) { + mm.counter.With("method", "remove_rule").Add(1) + mm.latency.With("method", "remove_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.RemoveRule(ctx, session, id) +} + +func (mm *metricsMiddleware) EnableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "enable_rule").Add(1) + mm.latency.With("method", "enable_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.EnableRule(ctx, session, id) +} + +func (mm *metricsMiddleware) DisableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { + defer func(begin time.Time) { + mm.counter.With("method", "disable_rule").Add(1) + mm.latency.With("method", "disable_rule").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.DisableRule(ctx, session, id) +} + +func (mm *metricsMiddleware) Handle(msg *messaging.Message) error { + defer func(begin time.Time) { + mm.counter.With("method", "handle").Add(1) + mm.latency.With("method", "handle").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.Handle(msg) +} + +func (mm *metricsMiddleware) StartScheduler(ctx context.Context) error { + defer func(begin time.Time) { + mm.counter.With("method", "start_scheduler").Add(1) + mm.latency.With("method", "start_scheduler").Observe(time.Since(begin).Seconds()) + }(time.Now()) + + return mm.service.StartScheduler(ctx) +} + +func (mm *metricsMiddleware) Cancel() error { + return mm.service.Cancel() +} diff --git a/re/middleware/tracing.go b/re/middleware/tracing.go new file mode 100644 index 000000000..d0ead6a60 --- /dev/null +++ b/re/middleware/tracing.go @@ -0,0 +1,136 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package middleware + +import ( + "context" + + "github.com/absmach/magistrala/re" + "github.com/absmach/supermq/pkg/authn" + "github.com/absmach/supermq/pkg/messaging" + rolemw "github.com/absmach/supermq/pkg/roles/rolemanager/middleware" + smqTracing "github.com/absmach/supermq/pkg/tracing" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" +) + +type tracingMiddleware struct { + tracer trace.Tracer + svc re.Service + rolemw.RoleManagerTracing +} + +var _ re.Service = (*tracingMiddleware)(nil) + +func NewTracingMiddleware(tracer trace.Tracer, svc re.Service) re.Service { + return &tracingMiddleware{ + tracer: tracer, + svc: svc, + RoleManagerTracing: rolemw.NewTracing("re", svc, tracer), + } +} + +func (tm *tracingMiddleware) AddRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "add_rule", trace.WithAttributes( + attribute.String("name", r.Name), + attribute.String("domain_id", r.DomainID), + )) + defer span.End() + + return tm.svc.AddRule(ctx, session, r) +} + +func (tm *tracingMiddleware) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "view_rule", trace.WithAttributes( + attribute.String("id", id), + )) + defer span.End() + + return tm.svc.ViewRule(ctx, session, id, withRoles) +} + +func (tm *tracingMiddleware) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "update_rule", trace.WithAttributes( + attribute.String("id", r.ID), + )) + defer span.End() + + return tm.svc.UpdateRule(ctx, session, r) +} + +func (tm *tracingMiddleware) UpdateRuleTags(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "update_rule_tags", trace.WithAttributes( + attribute.String("id", r.ID), + )) + defer span.End() + + return tm.svc.UpdateRuleTags(ctx, session, r) +} + +func (tm *tracingMiddleware) UpdateRuleSchedule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "update_rule_schedule", trace.WithAttributes( + attribute.String("id", r.ID), + )) + defer span.End() + + return tm.svc.UpdateRuleSchedule(ctx, session, r) +} + +func (tm *tracingMiddleware) ListRules(ctx context.Context, session authn.Session, pm re.PageMeta) (re.Page, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "list_rules", trace.WithAttributes( + attribute.Int("offset", int(pm.Offset)), + attribute.Int("limit", int(pm.Limit)), + )) + defer span.End() + + return tm.svc.ListRules(ctx, session, pm) +} + +func (tm *tracingMiddleware) RemoveRule(ctx context.Context, session authn.Session, id string) error { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "remove_rule", trace.WithAttributes( + attribute.String("id", id), + )) + defer span.End() + + return tm.svc.RemoveRule(ctx, session, id) +} + +func (tm *tracingMiddleware) EnableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "enable_rule", trace.WithAttributes( + attribute.String("id", id), + )) + defer span.End() + + return tm.svc.EnableRule(ctx, session, id) +} + +func (tm *tracingMiddleware) DisableRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "disable_rule", trace.WithAttributes( + attribute.String("id", id), + )) + defer span.End() + + return tm.svc.DisableRule(ctx, session, id) +} + +func (tm *tracingMiddleware) Handle(msg *messaging.Message) error { + _, span := smqTracing.StartSpan(context.Background(), tm.tracer, "handle", trace.WithAttributes( + attribute.String("channel", msg.Channel), + attribute.String("subtopic", msg.Subtopic), + )) + defer span.End() + + return tm.svc.Handle(msg) +} + +func (tm *tracingMiddleware) StartScheduler(ctx context.Context) error { + ctx, span := smqTracing.StartSpan(ctx, tm.tracer, "start_scheduler") + defer span.End() + + return tm.svc.StartScheduler(ctx) +} + +func (tm *tracingMiddleware) Cancel() error { + return tm.svc.Cancel() +} diff --git a/re/mocks/repository.go b/re/mocks/repository.go index 6997b2727..730351ab4 100644 --- a/re/mocks/repository.go +++ b/re/mocks/repository.go @@ -13,6 +13,7 @@ import ( "time" "github.com/absmach/magistrala/re" + "github.com/absmach/supermq/pkg/roles" mock "github.com/stretchr/testify/mock" ) @@ -43,6 +44,74 @@ func (_m *Repository) EXPECT() *Repository_Expecter { return &Repository_Expecter{mock: &_m.Mock} } +// AddRoles provides a mock function for the type Repository +func (_mock *Repository) AddRoles(ctx context.Context, rps []roles.RoleProvision) ([]roles.RoleProvision, error) { + ret := _mock.Called(ctx, rps) + + if len(ret) == 0 { + panic("no return value specified for AddRoles") + } + + var r0 []roles.RoleProvision + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, []roles.RoleProvision) ([]roles.RoleProvision, error)); ok { + return returnFunc(ctx, rps) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, []roles.RoleProvision) []roles.RoleProvision); ok { + r0 = returnFunc(ctx, rps) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]roles.RoleProvision) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, []roles.RoleProvision) error); ok { + r1 = returnFunc(ctx, rps) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_AddRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddRoles' +type Repository_AddRoles_Call struct { + *mock.Call +} + +// AddRoles is a helper method to define mock.On call +// - ctx context.Context +// - rps []roles.RoleProvision +func (_e *Repository_Expecter) AddRoles(ctx interface{}, rps interface{}) *Repository_AddRoles_Call { + return &Repository_AddRoles_Call{Call: _e.mock.On("AddRoles", ctx, rps)} +} + +func (_c *Repository_AddRoles_Call) Run(run func(ctx context.Context, rps []roles.RoleProvision)) *Repository_AddRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 []roles.RoleProvision + if args[1] != nil { + arg1 = args[1].([]roles.RoleProvision) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_AddRoles_Call) Return(roleProvisions []roles.RoleProvision, err error) *Repository_AddRoles_Call { + _c.Call.Return(roleProvisions, err) + return _c +} + +func (_c *Repository_AddRoles_Call) RunAndReturn(run func(ctx context.Context, rps []roles.RoleProvision) ([]roles.RoleProvision, error)) *Repository_AddRoles_Call { + _c.Call.Return(run) + return _c +} + // AddRule provides a mock function for the type Repository func (_mock *Repository) AddRule(ctx context.Context, r re.Rule) (re.Rule, error) { ret := _mock.Called(ctx, r) @@ -109,6 +178,78 @@ func (_c *Repository_AddRule_Call) RunAndReturn(run func(ctx context.Context, r return _c } +// ListEntityMembers provides a mock function for the type Repository +func (_mock *Repository) ListEntityMembers(ctx context.Context, entityID string, pageQuery roles.MembersRolePageQuery) (roles.MembersRolePage, error) { + ret := _mock.Called(ctx, entityID, pageQuery) + + if len(ret) == 0 { + panic("no return value specified for ListEntityMembers") + } + + var r0 roles.MembersRolePage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, roles.MembersRolePageQuery) (roles.MembersRolePage, error)); ok { + return returnFunc(ctx, entityID, pageQuery) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, roles.MembersRolePageQuery) roles.MembersRolePage); ok { + r0 = returnFunc(ctx, entityID, pageQuery) + } else { + r0 = ret.Get(0).(roles.MembersRolePage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, roles.MembersRolePageQuery) error); ok { + r1 = returnFunc(ctx, entityID, pageQuery) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_ListEntityMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListEntityMembers' +type Repository_ListEntityMembers_Call struct { + *mock.Call +} + +// ListEntityMembers is a helper method to define mock.On call +// - ctx context.Context +// - entityID string +// - pageQuery roles.MembersRolePageQuery +func (_e *Repository_Expecter) ListEntityMembers(ctx interface{}, entityID interface{}, pageQuery interface{}) *Repository_ListEntityMembers_Call { + return &Repository_ListEntityMembers_Call{Call: _e.mock.On("ListEntityMembers", ctx, entityID, pageQuery)} +} + +func (_c *Repository_ListEntityMembers_Call) Run(run func(ctx context.Context, entityID string, pageQuery roles.MembersRolePageQuery)) *Repository_ListEntityMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 roles.MembersRolePageQuery + if args[2] != nil { + arg2 = args[2].(roles.MembersRolePageQuery) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_ListEntityMembers_Call) Return(membersRolePage roles.MembersRolePage, err error) *Repository_ListEntityMembers_Call { + _c.Call.Return(membersRolePage, err) + return _c +} + +func (_c *Repository_ListEntityMembers_Call) RunAndReturn(run func(ctx context.Context, entityID string, pageQuery roles.MembersRolePageQuery) (roles.MembersRolePage, error)) *Repository_ListEntityMembers_Call { + _c.Call.Return(run) + return _c +} + // ListRules provides a mock function for the type Repository func (_mock *Repository) ListRules(ctx context.Context, pm re.PageMeta) (re.Page, error) { ret := _mock.Called(ctx, pm) @@ -175,6 +316,183 @@ func (_c *Repository_ListRules_Call) RunAndReturn(run func(ctx context.Context, return _c } +// RemoveEntityMembers provides a mock function for the type Repository +func (_mock *Repository) RemoveEntityMembers(ctx context.Context, entityID string, members []string) error { + ret := _mock.Called(ctx, entityID, members) + + if len(ret) == 0 { + panic("no return value specified for RemoveEntityMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, []string) error); ok { + r0 = returnFunc(ctx, entityID, members) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RemoveEntityMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveEntityMembers' +type Repository_RemoveEntityMembers_Call struct { + *mock.Call +} + +// RemoveEntityMembers is a helper method to define mock.On call +// - ctx context.Context +// - entityID string +// - members []string +func (_e *Repository_Expecter) RemoveEntityMembers(ctx interface{}, entityID interface{}, members interface{}) *Repository_RemoveEntityMembers_Call { + return &Repository_RemoveEntityMembers_Call{Call: _e.mock.On("RemoveEntityMembers", ctx, entityID, members)} +} + +func (_c *Repository_RemoveEntityMembers_Call) Run(run func(ctx context.Context, entityID string, members []string)) *Repository_RemoveEntityMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RemoveEntityMembers_Call) Return(err error) *Repository_RemoveEntityMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RemoveEntityMembers_Call) RunAndReturn(run func(ctx context.Context, entityID string, members []string) error) *Repository_RemoveEntityMembers_Call { + _c.Call.Return(run) + return _c +} + +// RemoveMemberFromAllRoles provides a mock function for the type Repository +func (_mock *Repository) RemoveMemberFromAllRoles(ctx context.Context, memberID string) error { + ret := _mock.Called(ctx, memberID) + + if len(ret) == 0 { + panic("no return value specified for RemoveMemberFromAllRoles") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) error); ok { + r0 = returnFunc(ctx, memberID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RemoveMemberFromAllRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveMemberFromAllRoles' +type Repository_RemoveMemberFromAllRoles_Call struct { + *mock.Call +} + +// RemoveMemberFromAllRoles is a helper method to define mock.On call +// - ctx context.Context +// - memberID string +func (_e *Repository_Expecter) RemoveMemberFromAllRoles(ctx interface{}, memberID interface{}) *Repository_RemoveMemberFromAllRoles_Call { + return &Repository_RemoveMemberFromAllRoles_Call{Call: _e.mock.On("RemoveMemberFromAllRoles", ctx, memberID)} +} + +func (_c *Repository_RemoveMemberFromAllRoles_Call) Run(run func(ctx context.Context, memberID string)) *Repository_RemoveMemberFromAllRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RemoveMemberFromAllRoles_Call) Return(err error) *Repository_RemoveMemberFromAllRoles_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RemoveMemberFromAllRoles_Call) RunAndReturn(run func(ctx context.Context, memberID string) error) *Repository_RemoveMemberFromAllRoles_Call { + _c.Call.Return(run) + return _c +} + +// RemoveRoles provides a mock function for the type Repository +func (_mock *Repository) RemoveRoles(ctx context.Context, roleIDs []string) error { + ret := _mock.Called(ctx, roleIDs) + + if len(ret) == 0 { + panic("no return value specified for RemoveRoles") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, []string) error); ok { + r0 = returnFunc(ctx, roleIDs) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RemoveRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveRoles' +type Repository_RemoveRoles_Call struct { + *mock.Call +} + +// RemoveRoles is a helper method to define mock.On call +// - ctx context.Context +// - roleIDs []string +func (_e *Repository_Expecter) RemoveRoles(ctx interface{}, roleIDs interface{}) *Repository_RemoveRoles_Call { + return &Repository_RemoveRoles_Call{Call: _e.mock.On("RemoveRoles", ctx, roleIDs)} +} + +func (_c *Repository_RemoveRoles_Call) Run(run func(ctx context.Context, roleIDs []string)) *Repository_RemoveRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 []string + if args[1] != nil { + arg1 = args[1].([]string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RemoveRoles_Call) Return(err error) *Repository_RemoveRoles_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RemoveRoles_Call) RunAndReturn(run func(ctx context.Context, roleIDs []string) error) *Repository_RemoveRoles_Call { + _c.Call.Return(run) + return _c +} + // RemoveRule provides a mock function for the type Repository func (_mock *Repository) RemoveRule(ctx context.Context, id string) error { ret := _mock.Called(ctx, id) @@ -232,6 +550,1114 @@ func (_c *Repository_RemoveRule_Call) RunAndReturn(run func(ctx context.Context, return _c } +// RetrieveAllRoles provides a mock function for the type Repository +func (_mock *Repository) RetrieveAllRoles(ctx context.Context, entityID string, limit uint64, offset uint64) (roles.RolePage, error) { + ret := _mock.Called(ctx, entityID, limit, offset) + + if len(ret) == 0 { + panic("no return value specified for RetrieveAllRoles") + } + + var r0 roles.RolePage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, uint64, uint64) (roles.RolePage, error)); ok { + return returnFunc(ctx, entityID, limit, offset) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, uint64, uint64) roles.RolePage); ok { + r0 = returnFunc(ctx, entityID, limit, offset) + } else { + r0 = ret.Get(0).(roles.RolePage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, uint64, uint64) error); ok { + r1 = returnFunc(ctx, entityID, limit, offset) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RetrieveAllRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveAllRoles' +type Repository_RetrieveAllRoles_Call struct { + *mock.Call +} + +// RetrieveAllRoles is a helper method to define mock.On call +// - ctx context.Context +// - entityID string +// - limit uint64 +// - offset uint64 +func (_e *Repository_Expecter) RetrieveAllRoles(ctx interface{}, entityID interface{}, limit interface{}, offset interface{}) *Repository_RetrieveAllRoles_Call { + return &Repository_RetrieveAllRoles_Call{Call: _e.mock.On("RetrieveAllRoles", ctx, entityID, limit, offset)} +} + +func (_c *Repository_RetrieveAllRoles_Call) Run(run func(ctx context.Context, entityID string, limit uint64, offset uint64)) *Repository_RetrieveAllRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 uint64 + if args[2] != nil { + arg2 = args[2].(uint64) + } + var arg3 uint64 + if args[3] != nil { + arg3 = args[3].(uint64) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Repository_RetrieveAllRoles_Call) Return(rolePage roles.RolePage, err error) *Repository_RetrieveAllRoles_Call { + _c.Call.Return(rolePage, err) + return _c +} + +func (_c *Repository_RetrieveAllRoles_Call) RunAndReturn(run func(ctx context.Context, entityID string, limit uint64, offset uint64) (roles.RolePage, error)) *Repository_RetrieveAllRoles_Call { + _c.Call.Return(run) + return _c +} + +// RetrieveByIDWithRoles provides a mock function for the type Repository +func (_mock *Repository) RetrieveByIDWithRoles(ctx context.Context, id string, memberID string) (re.Rule, error) { + ret := _mock.Called(ctx, id, memberID) + + if len(ret) == 0 { + panic("no return value specified for RetrieveByIDWithRoles") + } + + var r0 re.Rule + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) (re.Rule, error)); ok { + return returnFunc(ctx, id, memberID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) re.Rule); ok { + r0 = returnFunc(ctx, id, memberID) + } else { + r0 = ret.Get(0).(re.Rule) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = returnFunc(ctx, id, memberID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RetrieveByIDWithRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveByIDWithRoles' +type Repository_RetrieveByIDWithRoles_Call struct { + *mock.Call +} + +// RetrieveByIDWithRoles is a helper method to define mock.On call +// - ctx context.Context +// - id string +// - memberID string +func (_e *Repository_Expecter) RetrieveByIDWithRoles(ctx interface{}, id interface{}, memberID interface{}) *Repository_RetrieveByIDWithRoles_Call { + return &Repository_RetrieveByIDWithRoles_Call{Call: _e.mock.On("RetrieveByIDWithRoles", ctx, id, memberID)} +} + +func (_c *Repository_RetrieveByIDWithRoles_Call) Run(run func(ctx context.Context, id string, memberID string)) *Repository_RetrieveByIDWithRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RetrieveByIDWithRoles_Call) Return(rule re.Rule, err error) *Repository_RetrieveByIDWithRoles_Call { + _c.Call.Return(rule, err) + return _c +} + +func (_c *Repository_RetrieveByIDWithRoles_Call) RunAndReturn(run func(ctx context.Context, id string, memberID string) (re.Rule, error)) *Repository_RetrieveByIDWithRoles_Call { + _c.Call.Return(run) + return _c +} + +// RetrieveEntitiesRolesActionsMembers provides a mock function for the type Repository +func (_mock *Repository) RetrieveEntitiesRolesActionsMembers(ctx context.Context, entityIDs []string) ([]roles.EntityActionRole, []roles.EntityMemberRole, error) { + ret := _mock.Called(ctx, entityIDs) + + if len(ret) == 0 { + panic("no return value specified for RetrieveEntitiesRolesActionsMembers") + } + + var r0 []roles.EntityActionRole + var r1 []roles.EntityMemberRole + var r2 error + if returnFunc, ok := ret.Get(0).(func(context.Context, []string) ([]roles.EntityActionRole, []roles.EntityMemberRole, error)); ok { + return returnFunc(ctx, entityIDs) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, []string) []roles.EntityActionRole); ok { + r0 = returnFunc(ctx, entityIDs) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]roles.EntityActionRole) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, []string) []roles.EntityMemberRole); ok { + r1 = returnFunc(ctx, entityIDs) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).([]roles.EntityMemberRole) + } + } + if returnFunc, ok := ret.Get(2).(func(context.Context, []string) error); ok { + r2 = returnFunc(ctx, entityIDs) + } else { + r2 = ret.Error(2) + } + return r0, r1, r2 +} + +// Repository_RetrieveEntitiesRolesActionsMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveEntitiesRolesActionsMembers' +type Repository_RetrieveEntitiesRolesActionsMembers_Call struct { + *mock.Call +} + +// RetrieveEntitiesRolesActionsMembers is a helper method to define mock.On call +// - ctx context.Context +// - entityIDs []string +func (_e *Repository_Expecter) RetrieveEntitiesRolesActionsMembers(ctx interface{}, entityIDs interface{}) *Repository_RetrieveEntitiesRolesActionsMembers_Call { + return &Repository_RetrieveEntitiesRolesActionsMembers_Call{Call: _e.mock.On("RetrieveEntitiesRolesActionsMembers", ctx, entityIDs)} +} + +func (_c *Repository_RetrieveEntitiesRolesActionsMembers_Call) Run(run func(ctx context.Context, entityIDs []string)) *Repository_RetrieveEntitiesRolesActionsMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 []string + if args[1] != nil { + arg1 = args[1].([]string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RetrieveEntitiesRolesActionsMembers_Call) Return(entityActionRoles []roles.EntityActionRole, entityMemberRoles []roles.EntityMemberRole, err error) *Repository_RetrieveEntitiesRolesActionsMembers_Call { + _c.Call.Return(entityActionRoles, entityMemberRoles, err) + return _c +} + +func (_c *Repository_RetrieveEntitiesRolesActionsMembers_Call) RunAndReturn(run func(ctx context.Context, entityIDs []string) ([]roles.EntityActionRole, []roles.EntityMemberRole, error)) *Repository_RetrieveEntitiesRolesActionsMembers_Call { + _c.Call.Return(run) + return _c +} + +// RetrieveEntityRole provides a mock function for the type Repository +func (_mock *Repository) RetrieveEntityRole(ctx context.Context, entityID string, roleID string) (roles.Role, error) { + ret := _mock.Called(ctx, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RetrieveEntityRole") + } + + var r0 roles.Role + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) (roles.Role, error)); ok { + return returnFunc(ctx, entityID, roleID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, string) roles.Role); ok { + r0 = returnFunc(ctx, entityID, roleID) + } else { + r0 = ret.Get(0).(roles.Role) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = returnFunc(ctx, entityID, roleID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RetrieveEntityRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveEntityRole' +type Repository_RetrieveEntityRole_Call struct { + *mock.Call +} + +// RetrieveEntityRole is a helper method to define mock.On call +// - ctx context.Context +// - entityID string +// - roleID string +func (_e *Repository_Expecter) RetrieveEntityRole(ctx interface{}, entityID interface{}, roleID interface{}) *Repository_RetrieveEntityRole_Call { + return &Repository_RetrieveEntityRole_Call{Call: _e.mock.On("RetrieveEntityRole", ctx, entityID, roleID)} +} + +func (_c *Repository_RetrieveEntityRole_Call) Run(run func(ctx context.Context, entityID string, roleID string)) *Repository_RetrieveEntityRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RetrieveEntityRole_Call) Return(role roles.Role, err error) *Repository_RetrieveEntityRole_Call { + _c.Call.Return(role, err) + return _c +} + +func (_c *Repository_RetrieveEntityRole_Call) RunAndReturn(run func(ctx context.Context, entityID string, roleID string) (roles.Role, error)) *Repository_RetrieveEntityRole_Call { + _c.Call.Return(run) + return _c +} + +// RetrieveRole provides a mock function for the type Repository +func (_mock *Repository) RetrieveRole(ctx context.Context, roleID string) (roles.Role, error) { + ret := _mock.Called(ctx, roleID) + + if len(ret) == 0 { + panic("no return value specified for RetrieveRole") + } + + var r0 roles.Role + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) (roles.Role, error)); ok { + return returnFunc(ctx, roleID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string) roles.Role); ok { + r0 = returnFunc(ctx, roleID) + } else { + r0 = ret.Get(0).(roles.Role) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = returnFunc(ctx, roleID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RetrieveRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveRole' +type Repository_RetrieveRole_Call struct { + *mock.Call +} + +// RetrieveRole is a helper method to define mock.On call +// - ctx context.Context +// - roleID string +func (_e *Repository_Expecter) RetrieveRole(ctx interface{}, roleID interface{}) *Repository_RetrieveRole_Call { + return &Repository_RetrieveRole_Call{Call: _e.mock.On("RetrieveRole", ctx, roleID)} +} + +func (_c *Repository_RetrieveRole_Call) Run(run func(ctx context.Context, roleID string)) *Repository_RetrieveRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RetrieveRole_Call) Return(role roles.Role, err error) *Repository_RetrieveRole_Call { + _c.Call.Return(role, err) + return _c +} + +func (_c *Repository_RetrieveRole_Call) RunAndReturn(run func(ctx context.Context, roleID string) (roles.Role, error)) *Repository_RetrieveRole_Call { + _c.Call.Return(run) + return _c +} + +// RoleAddActions provides a mock function for the type Repository +func (_mock *Repository) RoleAddActions(ctx context.Context, role roles.Role, actions []string) ([]string, error) { + ret := _mock.Called(ctx, role, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleAddActions") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) ([]string, error)); ok { + return returnFunc(ctx, role, actions) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) []string); ok { + r0 = returnFunc(ctx, role, actions) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, roles.Role, []string) error); ok { + r1 = returnFunc(ctx, role, actions) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleAddActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleAddActions' +type Repository_RoleAddActions_Call struct { + *mock.Call +} + +// RoleAddActions is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +// - actions []string +func (_e *Repository_Expecter) RoleAddActions(ctx interface{}, role interface{}, actions interface{}) *Repository_RoleAddActions_Call { + return &Repository_RoleAddActions_Call{Call: _e.mock.On("RoleAddActions", ctx, role, actions)} +} + +func (_c *Repository_RoleAddActions_Call) Run(run func(ctx context.Context, role roles.Role, actions []string)) *Repository_RoleAddActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleAddActions_Call) Return(ops []string, err error) *Repository_RoleAddActions_Call { + _c.Call.Return(ops, err) + return _c +} + +func (_c *Repository_RoleAddActions_Call) RunAndReturn(run func(ctx context.Context, role roles.Role, actions []string) ([]string, error)) *Repository_RoleAddActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleAddMembers provides a mock function for the type Repository +func (_mock *Repository) RoleAddMembers(ctx context.Context, role roles.Role, members []string) ([]string, error) { + ret := _mock.Called(ctx, role, members) + + if len(ret) == 0 { + panic("no return value specified for RoleAddMembers") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) ([]string, error)); ok { + return returnFunc(ctx, role, members) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) []string); ok { + r0 = returnFunc(ctx, role, members) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, roles.Role, []string) error); ok { + r1 = returnFunc(ctx, role, members) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleAddMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleAddMembers' +type Repository_RoleAddMembers_Call struct { + *mock.Call +} + +// RoleAddMembers is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +// - members []string +func (_e *Repository_Expecter) RoleAddMembers(ctx interface{}, role interface{}, members interface{}) *Repository_RoleAddMembers_Call { + return &Repository_RoleAddMembers_Call{Call: _e.mock.On("RoleAddMembers", ctx, role, members)} +} + +func (_c *Repository_RoleAddMembers_Call) Run(run func(ctx context.Context, role roles.Role, members []string)) *Repository_RoleAddMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleAddMembers_Call) Return(strings []string, err error) *Repository_RoleAddMembers_Call { + _c.Call.Return(strings, err) + return _c +} + +func (_c *Repository_RoleAddMembers_Call) RunAndReturn(run func(ctx context.Context, role roles.Role, members []string) ([]string, error)) *Repository_RoleAddMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleCheckActionsExists provides a mock function for the type Repository +func (_mock *Repository) RoleCheckActionsExists(ctx context.Context, roleID string, actions []string) (bool, error) { + ret := _mock.Called(ctx, roleID, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleCheckActionsExists") + } + + var r0 bool + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, []string) (bool, error)); ok { + return returnFunc(ctx, roleID, actions) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, []string) bool); ok { + r0 = returnFunc(ctx, roleID, actions) + } else { + r0 = ret.Get(0).(bool) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, []string) error); ok { + r1 = returnFunc(ctx, roleID, actions) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleCheckActionsExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleCheckActionsExists' +type Repository_RoleCheckActionsExists_Call struct { + *mock.Call +} + +// RoleCheckActionsExists is a helper method to define mock.On call +// - ctx context.Context +// - roleID string +// - actions []string +func (_e *Repository_Expecter) RoleCheckActionsExists(ctx interface{}, roleID interface{}, actions interface{}) *Repository_RoleCheckActionsExists_Call { + return &Repository_RoleCheckActionsExists_Call{Call: _e.mock.On("RoleCheckActionsExists", ctx, roleID, actions)} +} + +func (_c *Repository_RoleCheckActionsExists_Call) Run(run func(ctx context.Context, roleID string, actions []string)) *Repository_RoleCheckActionsExists_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleCheckActionsExists_Call) Return(b bool, err error) *Repository_RoleCheckActionsExists_Call { + _c.Call.Return(b, err) + return _c +} + +func (_c *Repository_RoleCheckActionsExists_Call) RunAndReturn(run func(ctx context.Context, roleID string, actions []string) (bool, error)) *Repository_RoleCheckActionsExists_Call { + _c.Call.Return(run) + return _c +} + +// RoleCheckMembersExists provides a mock function for the type Repository +func (_mock *Repository) RoleCheckMembersExists(ctx context.Context, roleID string, members []string) (bool, error) { + ret := _mock.Called(ctx, roleID, members) + + if len(ret) == 0 { + panic("no return value specified for RoleCheckMembersExists") + } + + var r0 bool + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, []string) (bool, error)); ok { + return returnFunc(ctx, roleID, members) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, []string) bool); ok { + r0 = returnFunc(ctx, roleID, members) + } else { + r0 = ret.Get(0).(bool) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, []string) error); ok { + r1 = returnFunc(ctx, roleID, members) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleCheckMembersExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleCheckMembersExists' +type Repository_RoleCheckMembersExists_Call struct { + *mock.Call +} + +// RoleCheckMembersExists is a helper method to define mock.On call +// - ctx context.Context +// - roleID string +// - members []string +func (_e *Repository_Expecter) RoleCheckMembersExists(ctx interface{}, roleID interface{}, members interface{}) *Repository_RoleCheckMembersExists_Call { + return &Repository_RoleCheckMembersExists_Call{Call: _e.mock.On("RoleCheckMembersExists", ctx, roleID, members)} +} + +func (_c *Repository_RoleCheckMembersExists_Call) Run(run func(ctx context.Context, roleID string, members []string)) *Repository_RoleCheckMembersExists_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleCheckMembersExists_Call) Return(b bool, err error) *Repository_RoleCheckMembersExists_Call { + _c.Call.Return(b, err) + return _c +} + +func (_c *Repository_RoleCheckMembersExists_Call) RunAndReturn(run func(ctx context.Context, roleID string, members []string) (bool, error)) *Repository_RoleCheckMembersExists_Call { + _c.Call.Return(run) + return _c +} + +// RoleListActions provides a mock function for the type Repository +func (_mock *Repository) RoleListActions(ctx context.Context, roleID string) ([]string, error) { + ret := _mock.Called(ctx, roleID) + + if len(ret) == 0 { + panic("no return value specified for RoleListActions") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string) ([]string, error)); ok { + return returnFunc(ctx, roleID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string) []string); ok { + r0 = returnFunc(ctx, roleID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = returnFunc(ctx, roleID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleListActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleListActions' +type Repository_RoleListActions_Call struct { + *mock.Call +} + +// RoleListActions is a helper method to define mock.On call +// - ctx context.Context +// - roleID string +func (_e *Repository_Expecter) RoleListActions(ctx interface{}, roleID interface{}) *Repository_RoleListActions_Call { + return &Repository_RoleListActions_Call{Call: _e.mock.On("RoleListActions", ctx, roleID)} +} + +func (_c *Repository_RoleListActions_Call) Run(run func(ctx context.Context, roleID string)) *Repository_RoleListActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RoleListActions_Call) Return(strings []string, err error) *Repository_RoleListActions_Call { + _c.Call.Return(strings, err) + return _c +} + +func (_c *Repository_RoleListActions_Call) RunAndReturn(run func(ctx context.Context, roleID string) ([]string, error)) *Repository_RoleListActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleListMembers provides a mock function for the type Repository +func (_mock *Repository) RoleListMembers(ctx context.Context, roleID string, limit uint64, offset uint64) (roles.MembersPage, error) { + ret := _mock.Called(ctx, roleID, limit, offset) + + if len(ret) == 0 { + panic("no return value specified for RoleListMembers") + } + + var r0 roles.MembersPage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, string, uint64, uint64) (roles.MembersPage, error)); ok { + return returnFunc(ctx, roleID, limit, offset) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, string, uint64, uint64) roles.MembersPage); ok { + r0 = returnFunc(ctx, roleID, limit, offset) + } else { + r0 = ret.Get(0).(roles.MembersPage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, string, uint64, uint64) error); ok { + r1 = returnFunc(ctx, roleID, limit, offset) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_RoleListMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleListMembers' +type Repository_RoleListMembers_Call struct { + *mock.Call +} + +// RoleListMembers is a helper method to define mock.On call +// - ctx context.Context +// - roleID string +// - limit uint64 +// - offset uint64 +func (_e *Repository_Expecter) RoleListMembers(ctx interface{}, roleID interface{}, limit interface{}, offset interface{}) *Repository_RoleListMembers_Call { + return &Repository_RoleListMembers_Call{Call: _e.mock.On("RoleListMembers", ctx, roleID, limit, offset)} +} + +func (_c *Repository_RoleListMembers_Call) Run(run func(ctx context.Context, roleID string, limit uint64, offset uint64)) *Repository_RoleListMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 string + if args[1] != nil { + arg1 = args[1].(string) + } + var arg2 uint64 + if args[2] != nil { + arg2 = args[2].(uint64) + } + var arg3 uint64 + if args[3] != nil { + arg3 = args[3].(uint64) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Repository_RoleListMembers_Call) Return(membersPage roles.MembersPage, err error) *Repository_RoleListMembers_Call { + _c.Call.Return(membersPage, err) + return _c +} + +func (_c *Repository_RoleListMembers_Call) RunAndReturn(run func(ctx context.Context, roleID string, limit uint64, offset uint64) (roles.MembersPage, error)) *Repository_RoleListMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveActions provides a mock function for the type Repository +func (_mock *Repository) RoleRemoveActions(ctx context.Context, role roles.Role, actions []string) error { + ret := _mock.Called(ctx, role, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveActions") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) error); ok { + r0 = returnFunc(ctx, role, actions) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RoleRemoveActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveActions' +type Repository_RoleRemoveActions_Call struct { + *mock.Call +} + +// RoleRemoveActions is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +// - actions []string +func (_e *Repository_Expecter) RoleRemoveActions(ctx interface{}, role interface{}, actions interface{}) *Repository_RoleRemoveActions_Call { + return &Repository_RoleRemoveActions_Call{Call: _e.mock.On("RoleRemoveActions", ctx, role, actions)} +} + +func (_c *Repository_RoleRemoveActions_Call) Run(run func(ctx context.Context, role roles.Role, actions []string)) *Repository_RoleRemoveActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleRemoveActions_Call) Return(err error) *Repository_RoleRemoveActions_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RoleRemoveActions_Call) RunAndReturn(run func(ctx context.Context, role roles.Role, actions []string) error) *Repository_RoleRemoveActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveAllActions provides a mock function for the type Repository +func (_mock *Repository) RoleRemoveAllActions(ctx context.Context, role roles.Role) error { + ret := _mock.Called(ctx, role) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveAllActions") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role) error); ok { + r0 = returnFunc(ctx, role) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RoleRemoveAllActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveAllActions' +type Repository_RoleRemoveAllActions_Call struct { + *mock.Call +} + +// RoleRemoveAllActions is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +func (_e *Repository_Expecter) RoleRemoveAllActions(ctx interface{}, role interface{}) *Repository_RoleRemoveAllActions_Call { + return &Repository_RoleRemoveAllActions_Call{Call: _e.mock.On("RoleRemoveAllActions", ctx, role)} +} + +func (_c *Repository_RoleRemoveAllActions_Call) Run(run func(ctx context.Context, role roles.Role)) *Repository_RoleRemoveAllActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RoleRemoveAllActions_Call) Return(err error) *Repository_RoleRemoveAllActions_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RoleRemoveAllActions_Call) RunAndReturn(run func(ctx context.Context, role roles.Role) error) *Repository_RoleRemoveAllActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveAllMembers provides a mock function for the type Repository +func (_mock *Repository) RoleRemoveAllMembers(ctx context.Context, role roles.Role) error { + ret := _mock.Called(ctx, role) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveAllMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role) error); ok { + r0 = returnFunc(ctx, role) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RoleRemoveAllMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveAllMembers' +type Repository_RoleRemoveAllMembers_Call struct { + *mock.Call +} + +// RoleRemoveAllMembers is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +func (_e *Repository_Expecter) RoleRemoveAllMembers(ctx interface{}, role interface{}) *Repository_RoleRemoveAllMembers_Call { + return &Repository_RoleRemoveAllMembers_Call{Call: _e.mock.On("RoleRemoveAllMembers", ctx, role)} +} + +func (_c *Repository_RoleRemoveAllMembers_Call) Run(run func(ctx context.Context, role roles.Role)) *Repository_RoleRemoveAllMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_RoleRemoveAllMembers_Call) Return(err error) *Repository_RoleRemoveAllMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RoleRemoveAllMembers_Call) RunAndReturn(run func(ctx context.Context, role roles.Role) error) *Repository_RoleRemoveAllMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveMembers provides a mock function for the type Repository +func (_mock *Repository) RoleRemoveMembers(ctx context.Context, role roles.Role, members []string) error { + ret := _mock.Called(ctx, role, members) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role, []string) error); ok { + r0 = returnFunc(ctx, role, members) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Repository_RoleRemoveMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveMembers' +type Repository_RoleRemoveMembers_Call struct { + *mock.Call +} + +// RoleRemoveMembers is a helper method to define mock.On call +// - ctx context.Context +// - role roles.Role +// - members []string +func (_e *Repository_Expecter) RoleRemoveMembers(ctx interface{}, role interface{}, members interface{}) *Repository_RoleRemoveMembers_Call { + return &Repository_RoleRemoveMembers_Call{Call: _e.mock.On("RoleRemoveMembers", ctx, role, members)} +} + +func (_c *Repository_RoleRemoveMembers_Call) Run(run func(ctx context.Context, role roles.Role, members []string)) *Repository_RoleRemoveMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + var arg2 []string + if args[2] != nil { + arg2 = args[2].([]string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Repository_RoleRemoveMembers_Call) Return(err error) *Repository_RoleRemoveMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Repository_RoleRemoveMembers_Call) RunAndReturn(run func(ctx context.Context, role roles.Role, members []string) error) *Repository_RoleRemoveMembers_Call { + _c.Call.Return(run) + return _c +} + +// UpdateRole provides a mock function for the type Repository +func (_mock *Repository) UpdateRole(ctx context.Context, ro roles.Role) (roles.Role, error) { + ret := _mock.Called(ctx, ro) + + if len(ret) == 0 { + panic("no return value specified for UpdateRole") + } + + var r0 roles.Role + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role) (roles.Role, error)); ok { + return returnFunc(ctx, ro) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, roles.Role) roles.Role); ok { + r0 = returnFunc(ctx, ro) + } else { + r0 = ret.Get(0).(roles.Role) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, roles.Role) error); ok { + r1 = returnFunc(ctx, ro) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Repository_UpdateRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateRole' +type Repository_UpdateRole_Call struct { + *mock.Call +} + +// UpdateRole is a helper method to define mock.On call +// - ctx context.Context +// - ro roles.Role +func (_e *Repository_Expecter) UpdateRole(ctx interface{}, ro interface{}) *Repository_UpdateRole_Call { + return &Repository_UpdateRole_Call{Call: _e.mock.On("UpdateRole", ctx, ro)} +} + +func (_c *Repository_UpdateRole_Call) Run(run func(ctx context.Context, ro roles.Role)) *Repository_UpdateRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 roles.Role + if args[1] != nil { + arg1 = args[1].(roles.Role) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Repository_UpdateRole_Call) Return(role roles.Role, err error) *Repository_UpdateRole_Call { + _c.Call.Return(role, err) + return _c +} + +func (_c *Repository_UpdateRole_Call) RunAndReturn(run func(ctx context.Context, ro roles.Role) (roles.Role, error)) *Repository_UpdateRole_Call { + _c.Call.Return(run) + return _c +} + // UpdateRule provides a mock function for the type Repository func (_mock *Repository) UpdateRule(ctx context.Context, r re.Rule) (re.Rule, error) { ret := _mock.Called(ctx, r) diff --git a/re/mocks/service.go b/re/mocks/service.go index dc41c45f1..809ed88a3 100644 --- a/re/mocks/service.go +++ b/re/mocks/service.go @@ -14,6 +14,7 @@ import ( "github.com/absmach/magistrala/re" "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/messaging" + "github.com/absmach/supermq/pkg/roles" mock "github.com/stretchr/testify/mock" ) @@ -44,6 +45,96 @@ func (_m *Service) EXPECT() *Service_Expecter { return &Service_Expecter{mock: &_m.Mock} } +// AddRole provides a mock function for the type Service +func (_mock *Service) AddRole(ctx context.Context, session authn.Session, entityID string, roleName string, optionalActions []string, optionalMembers []string) (roles.RoleProvision, error) { + ret := _mock.Called(ctx, session, entityID, roleName, optionalActions, optionalMembers) + + if len(ret) == 0 { + panic("no return value specified for AddRole") + } + + var r0 roles.RoleProvision + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string, []string) (roles.RoleProvision, error)); ok { + return returnFunc(ctx, session, entityID, roleName, optionalActions, optionalMembers) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string, []string) roles.RoleProvision); ok { + r0 = returnFunc(ctx, session, entityID, roleName, optionalActions, optionalMembers) + } else { + r0 = ret.Get(0).(roles.RoleProvision) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, []string, []string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleName, optionalActions, optionalMembers) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_AddRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddRole' +type Service_AddRole_Call struct { + *mock.Call +} + +// AddRole is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleName string +// - optionalActions []string +// - optionalMembers []string +func (_e *Service_Expecter) AddRole(ctx interface{}, session interface{}, entityID interface{}, roleName interface{}, optionalActions interface{}, optionalMembers interface{}) *Service_AddRole_Call { + return &Service_AddRole_Call{Call: _e.mock.On("AddRole", ctx, session, entityID, roleName, optionalActions, optionalMembers)} +} + +func (_c *Service_AddRole_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleName string, optionalActions []string, optionalMembers []string)) *Service_AddRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + var arg5 []string + if args[5] != nil { + arg5 = args[5].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + ) + }) + return _c +} + +func (_c *Service_AddRole_Call) Return(roleProvision roles.RoleProvision, err error) *Service_AddRole_Call { + _c.Call.Return(roleProvision, err) + return _c +} + +func (_c *Service_AddRole_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleName string, optionalActions []string, optionalMembers []string) (roles.RoleProvision, error)) *Service_AddRole_Call { + _c.Call.Return(run) + return _c +} + // AddRule provides a mock function for the type Service func (_mock *Service) AddRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { ret := _mock.Called(ctx, session, r) @@ -355,6 +446,152 @@ func (_c *Service_Handle_Call) RunAndReturn(run func(msg *messaging.Message) err return _c } +// ListAvailableActions provides a mock function for the type Service +func (_mock *Service) ListAvailableActions(ctx context.Context, session authn.Session) ([]string, error) { + ret := _mock.Called(ctx, session) + + if len(ret) == 0 { + panic("no return value specified for ListAvailableActions") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session) ([]string, error)); ok { + return returnFunc(ctx, session) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session) []string); ok { + r0 = returnFunc(ctx, session) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session) error); ok { + r1 = returnFunc(ctx, session) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_ListAvailableActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListAvailableActions' +type Service_ListAvailableActions_Call struct { + *mock.Call +} + +// ListAvailableActions is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +func (_e *Service_Expecter) ListAvailableActions(ctx interface{}, session interface{}) *Service_ListAvailableActions_Call { + return &Service_ListAvailableActions_Call{Call: _e.mock.On("ListAvailableActions", ctx, session)} +} + +func (_c *Service_ListAvailableActions_Call) Run(run func(ctx context.Context, session authn.Session)) *Service_ListAvailableActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + run( + arg0, + arg1, + ) + }) + return _c +} + +func (_c *Service_ListAvailableActions_Call) Return(strings []string, err error) *Service_ListAvailableActions_Call { + _c.Call.Return(strings, err) + return _c +} + +func (_c *Service_ListAvailableActions_Call) RunAndReturn(run func(ctx context.Context, session authn.Session) ([]string, error)) *Service_ListAvailableActions_Call { + _c.Call.Return(run) + return _c +} + +// ListEntityMembers provides a mock function for the type Service +func (_mock *Service) ListEntityMembers(ctx context.Context, session authn.Session, entityID string, pq roles.MembersRolePageQuery) (roles.MembersRolePage, error) { + ret := _mock.Called(ctx, session, entityID, pq) + + if len(ret) == 0 { + panic("no return value specified for ListEntityMembers") + } + + var r0 roles.MembersRolePage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, roles.MembersRolePageQuery) (roles.MembersRolePage, error)); ok { + return returnFunc(ctx, session, entityID, pq) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, roles.MembersRolePageQuery) roles.MembersRolePage); ok { + r0 = returnFunc(ctx, session, entityID, pq) + } else { + r0 = ret.Get(0).(roles.MembersRolePage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, roles.MembersRolePageQuery) error); ok { + r1 = returnFunc(ctx, session, entityID, pq) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_ListEntityMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListEntityMembers' +type Service_ListEntityMembers_Call struct { + *mock.Call +} + +// ListEntityMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - pq roles.MembersRolePageQuery +func (_e *Service_Expecter) ListEntityMembers(ctx interface{}, session interface{}, entityID interface{}, pq interface{}) *Service_ListEntityMembers_Call { + return &Service_ListEntityMembers_Call{Call: _e.mock.On("ListEntityMembers", ctx, session, entityID, pq)} +} + +func (_c *Service_ListEntityMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, pq roles.MembersRolePageQuery)) *Service_ListEntityMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 roles.MembersRolePageQuery + if args[3] != nil { + arg3 = args[3].(roles.MembersRolePageQuery) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_ListEntityMembers_Call) Return(membersRolePage roles.MembersRolePage, err error) *Service_ListEntityMembers_Call { + _c.Call.Return(membersRolePage, err) + return _c +} + +func (_c *Service_ListEntityMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, pq roles.MembersRolePageQuery) (roles.MembersRolePage, error)) *Service_ListEntityMembers_Call { + _c.Call.Return(run) + return _c +} + // ListRules provides a mock function for the type Service func (_mock *Service) ListRules(ctx context.Context, session authn.Session, pm re.PageMeta) (re.Page, error) { ret := _mock.Called(ctx, session, pm) @@ -427,6 +664,207 @@ func (_c *Service_ListRules_Call) RunAndReturn(run func(ctx context.Context, ses return _c } +// RemoveEntityMembers provides a mock function for the type Service +func (_mock *Service) RemoveEntityMembers(ctx context.Context, session authn.Session, entityID string, members []string) error { + ret := _mock.Called(ctx, session, entityID, members) + + if len(ret) == 0 { + panic("no return value specified for RemoveEntityMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, []string) error); ok { + r0 = returnFunc(ctx, session, entityID, members) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RemoveEntityMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveEntityMembers' +type Service_RemoveEntityMembers_Call struct { + *mock.Call +} + +// RemoveEntityMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - members []string +func (_e *Service_Expecter) RemoveEntityMembers(ctx interface{}, session interface{}, entityID interface{}, members interface{}) *Service_RemoveEntityMembers_Call { + return &Service_RemoveEntityMembers_Call{Call: _e.mock.On("RemoveEntityMembers", ctx, session, entityID, members)} +} + +func (_c *Service_RemoveEntityMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, members []string)) *Service_RemoveEntityMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 []string + if args[3] != nil { + arg3 = args[3].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RemoveEntityMembers_Call) Return(err error) *Service_RemoveEntityMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RemoveEntityMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, members []string) error) *Service_RemoveEntityMembers_Call { + _c.Call.Return(run) + return _c +} + +// RemoveMemberFromAllRoles provides a mock function for the type Service +func (_mock *Service) RemoveMemberFromAllRoles(ctx context.Context, session authn.Session, memberID string) error { + ret := _mock.Called(ctx, session, memberID) + + if len(ret) == 0 { + panic("no return value specified for RemoveMemberFromAllRoles") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string) error); ok { + r0 = returnFunc(ctx, session, memberID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RemoveMemberFromAllRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveMemberFromAllRoles' +type Service_RemoveMemberFromAllRoles_Call struct { + *mock.Call +} + +// RemoveMemberFromAllRoles is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - memberID string +func (_e *Service_Expecter) RemoveMemberFromAllRoles(ctx interface{}, session interface{}, memberID interface{}) *Service_RemoveMemberFromAllRoles_Call { + return &Service_RemoveMemberFromAllRoles_Call{Call: _e.mock.On("RemoveMemberFromAllRoles", ctx, session, memberID)} +} + +func (_c *Service_RemoveMemberFromAllRoles_Call) Run(run func(ctx context.Context, session authn.Session, memberID string)) *Service_RemoveMemberFromAllRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + run( + arg0, + arg1, + arg2, + ) + }) + return _c +} + +func (_c *Service_RemoveMemberFromAllRoles_Call) Return(err error) *Service_RemoveMemberFromAllRoles_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RemoveMemberFromAllRoles_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, memberID string) error) *Service_RemoveMemberFromAllRoles_Call { + _c.Call.Return(run) + return _c +} + +// RemoveRole provides a mock function for the type Service +func (_mock *Service) RemoveRole(ctx context.Context, session authn.Session, entityID string, roleID string) error { + ret := _mock.Called(ctx, session, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RemoveRole") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) error); ok { + r0 = returnFunc(ctx, session, entityID, roleID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RemoveRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveRole' +type Service_RemoveRole_Call struct { + *mock.Call +} + +// RemoveRole is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +func (_e *Service_Expecter) RemoveRole(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}) *Service_RemoveRole_Call { + return &Service_RemoveRole_Call{Call: _e.mock.On("RemoveRole", ctx, session, entityID, roleID)} +} + +func (_c *Service_RemoveRole_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string)) *Service_RemoveRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RemoveRole_Call) Return(err error) *Service_RemoveRole_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RemoveRole_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string) error) *Service_RemoveRole_Call { + _c.Call.Return(run) + return _c +} + // RemoveRule provides a mock function for the type Service func (_mock *Service) RemoveRule(ctx context.Context, session authn.Session, id string) error { ret := _mock.Called(ctx, session, id) @@ -490,6 +928,966 @@ func (_c *Service_RemoveRule_Call) RunAndReturn(run func(ctx context.Context, se return _c } +// RetrieveAllRoles provides a mock function for the type Service +func (_mock *Service) RetrieveAllRoles(ctx context.Context, session authn.Session, entityID string, limit uint64, offset uint64) (roles.RolePage, error) { + ret := _mock.Called(ctx, session, entityID, limit, offset) + + if len(ret) == 0 { + panic("no return value specified for RetrieveAllRoles") + } + + var r0 roles.RolePage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, uint64, uint64) (roles.RolePage, error)); ok { + return returnFunc(ctx, session, entityID, limit, offset) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, uint64, uint64) roles.RolePage); ok { + r0 = returnFunc(ctx, session, entityID, limit, offset) + } else { + r0 = ret.Get(0).(roles.RolePage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, uint64, uint64) error); ok { + r1 = returnFunc(ctx, session, entityID, limit, offset) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RetrieveAllRoles_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveAllRoles' +type Service_RetrieveAllRoles_Call struct { + *mock.Call +} + +// RetrieveAllRoles is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - limit uint64 +// - offset uint64 +func (_e *Service_Expecter) RetrieveAllRoles(ctx interface{}, session interface{}, entityID interface{}, limit interface{}, offset interface{}) *Service_RetrieveAllRoles_Call { + return &Service_RetrieveAllRoles_Call{Call: _e.mock.On("RetrieveAllRoles", ctx, session, entityID, limit, offset)} +} + +func (_c *Service_RetrieveAllRoles_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, limit uint64, offset uint64)) *Service_RetrieveAllRoles_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 uint64 + if args[3] != nil { + arg3 = args[3].(uint64) + } + var arg4 uint64 + if args[4] != nil { + arg4 = args[4].(uint64) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RetrieveAllRoles_Call) Return(rolePage roles.RolePage, err error) *Service_RetrieveAllRoles_Call { + _c.Call.Return(rolePage, err) + return _c +} + +func (_c *Service_RetrieveAllRoles_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, limit uint64, offset uint64) (roles.RolePage, error)) *Service_RetrieveAllRoles_Call { + _c.Call.Return(run) + return _c +} + +// RetrieveRole provides a mock function for the type Service +func (_mock *Service) RetrieveRole(ctx context.Context, session authn.Session, entityID string, roleID string) (roles.Role, error) { + ret := _mock.Called(ctx, session, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RetrieveRole") + } + + var r0 roles.Role + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) (roles.Role, error)); ok { + return returnFunc(ctx, session, entityID, roleID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) roles.Role); ok { + r0 = returnFunc(ctx, session, entityID, roleID) + } else { + r0 = ret.Get(0).(roles.Role) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RetrieveRole_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RetrieveRole' +type Service_RetrieveRole_Call struct { + *mock.Call +} + +// RetrieveRole is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +func (_e *Service_Expecter) RetrieveRole(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}) *Service_RetrieveRole_Call { + return &Service_RetrieveRole_Call{Call: _e.mock.On("RetrieveRole", ctx, session, entityID, roleID)} +} + +func (_c *Service_RetrieveRole_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string)) *Service_RetrieveRole_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RetrieveRole_Call) Return(role roles.Role, err error) *Service_RetrieveRole_Call { + _c.Call.Return(role, err) + return _c +} + +func (_c *Service_RetrieveRole_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string) (roles.Role, error)) *Service_RetrieveRole_Call { + _c.Call.Return(run) + return _c +} + +// RoleAddActions provides a mock function for the type Service +func (_mock *Service) RoleAddActions(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) ([]string, error) { + ret := _mock.Called(ctx, session, entityID, roleID, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleAddActions") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) ([]string, error)); ok { + return returnFunc(ctx, session, entityID, roleID, actions) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) []string); ok { + r0 = returnFunc(ctx, session, entityID, roleID, actions) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, []string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, actions) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleAddActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleAddActions' +type Service_RoleAddActions_Call struct { + *mock.Call +} + +// RoleAddActions is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - actions []string +func (_e *Service_Expecter) RoleAddActions(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, actions interface{}) *Service_RoleAddActions_Call { + return &Service_RoleAddActions_Call{Call: _e.mock.On("RoleAddActions", ctx, session, entityID, roleID, actions)} +} + +func (_c *Service_RoleAddActions_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string)) *Service_RoleAddActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleAddActions_Call) Return(ops []string, err error) *Service_RoleAddActions_Call { + _c.Call.Return(ops, err) + return _c +} + +func (_c *Service_RoleAddActions_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) ([]string, error)) *Service_RoleAddActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleAddMembers provides a mock function for the type Service +func (_mock *Service) RoleAddMembers(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) ([]string, error) { + ret := _mock.Called(ctx, session, entityID, roleID, members) + + if len(ret) == 0 { + panic("no return value specified for RoleAddMembers") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) ([]string, error)); ok { + return returnFunc(ctx, session, entityID, roleID, members) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) []string); ok { + r0 = returnFunc(ctx, session, entityID, roleID, members) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, []string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, members) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleAddMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleAddMembers' +type Service_RoleAddMembers_Call struct { + *mock.Call +} + +// RoleAddMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - members []string +func (_e *Service_Expecter) RoleAddMembers(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, members interface{}) *Service_RoleAddMembers_Call { + return &Service_RoleAddMembers_Call{Call: _e.mock.On("RoleAddMembers", ctx, session, entityID, roleID, members)} +} + +func (_c *Service_RoleAddMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string)) *Service_RoleAddMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleAddMembers_Call) Return(strings []string, err error) *Service_RoleAddMembers_Call { + _c.Call.Return(strings, err) + return _c +} + +func (_c *Service_RoleAddMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) ([]string, error)) *Service_RoleAddMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleCheckActionsExists provides a mock function for the type Service +func (_mock *Service) RoleCheckActionsExists(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) (bool, error) { + ret := _mock.Called(ctx, session, entityID, roleID, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleCheckActionsExists") + } + + var r0 bool + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) (bool, error)); ok { + return returnFunc(ctx, session, entityID, roleID, actions) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) bool); ok { + r0 = returnFunc(ctx, session, entityID, roleID, actions) + } else { + r0 = ret.Get(0).(bool) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, []string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, actions) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleCheckActionsExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleCheckActionsExists' +type Service_RoleCheckActionsExists_Call struct { + *mock.Call +} + +// RoleCheckActionsExists is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - actions []string +func (_e *Service_Expecter) RoleCheckActionsExists(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, actions interface{}) *Service_RoleCheckActionsExists_Call { + return &Service_RoleCheckActionsExists_Call{Call: _e.mock.On("RoleCheckActionsExists", ctx, session, entityID, roleID, actions)} +} + +func (_c *Service_RoleCheckActionsExists_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string)) *Service_RoleCheckActionsExists_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleCheckActionsExists_Call) Return(b bool, err error) *Service_RoleCheckActionsExists_Call { + _c.Call.Return(b, err) + return _c +} + +func (_c *Service_RoleCheckActionsExists_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) (bool, error)) *Service_RoleCheckActionsExists_Call { + _c.Call.Return(run) + return _c +} + +// RoleCheckMembersExists provides a mock function for the type Service +func (_mock *Service) RoleCheckMembersExists(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) (bool, error) { + ret := _mock.Called(ctx, session, entityID, roleID, members) + + if len(ret) == 0 { + panic("no return value specified for RoleCheckMembersExists") + } + + var r0 bool + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) (bool, error)); ok { + return returnFunc(ctx, session, entityID, roleID, members) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) bool); ok { + r0 = returnFunc(ctx, session, entityID, roleID, members) + } else { + r0 = ret.Get(0).(bool) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, []string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, members) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleCheckMembersExists_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleCheckMembersExists' +type Service_RoleCheckMembersExists_Call struct { + *mock.Call +} + +// RoleCheckMembersExists is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - members []string +func (_e *Service_Expecter) RoleCheckMembersExists(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, members interface{}) *Service_RoleCheckMembersExists_Call { + return &Service_RoleCheckMembersExists_Call{Call: _e.mock.On("RoleCheckMembersExists", ctx, session, entityID, roleID, members)} +} + +func (_c *Service_RoleCheckMembersExists_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string)) *Service_RoleCheckMembersExists_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleCheckMembersExists_Call) Return(b bool, err error) *Service_RoleCheckMembersExists_Call { + _c.Call.Return(b, err) + return _c +} + +func (_c *Service_RoleCheckMembersExists_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) (bool, error)) *Service_RoleCheckMembersExists_Call { + _c.Call.Return(run) + return _c +} + +// RoleListActions provides a mock function for the type Service +func (_mock *Service) RoleListActions(ctx context.Context, session authn.Session, entityID string, roleID string) ([]string, error) { + ret := _mock.Called(ctx, session, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RoleListActions") + } + + var r0 []string + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) ([]string, error)); ok { + return returnFunc(ctx, session, entityID, roleID) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) []string); ok { + r0 = returnFunc(ctx, session, entityID, roleID) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleListActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleListActions' +type Service_RoleListActions_Call struct { + *mock.Call +} + +// RoleListActions is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +func (_e *Service_Expecter) RoleListActions(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}) *Service_RoleListActions_Call { + return &Service_RoleListActions_Call{Call: _e.mock.On("RoleListActions", ctx, session, entityID, roleID)} +} + +func (_c *Service_RoleListActions_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string)) *Service_RoleListActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RoleListActions_Call) Return(strings []string, err error) *Service_RoleListActions_Call { + _c.Call.Return(strings, err) + return _c +} + +func (_c *Service_RoleListActions_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string) ([]string, error)) *Service_RoleListActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleListMembers provides a mock function for the type Service +func (_mock *Service) RoleListMembers(ctx context.Context, session authn.Session, entityID string, roleID string, limit uint64, offset uint64) (roles.MembersPage, error) { + ret := _mock.Called(ctx, session, entityID, roleID, limit, offset) + + if len(ret) == 0 { + panic("no return value specified for RoleListMembers") + } + + var r0 roles.MembersPage + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, uint64, uint64) (roles.MembersPage, error)); ok { + return returnFunc(ctx, session, entityID, roleID, limit, offset) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, uint64, uint64) roles.MembersPage); ok { + r0 = returnFunc(ctx, session, entityID, roleID, limit, offset) + } else { + r0 = ret.Get(0).(roles.MembersPage) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, uint64, uint64) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, limit, offset) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_RoleListMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleListMembers' +type Service_RoleListMembers_Call struct { + *mock.Call +} + +// RoleListMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - limit uint64 +// - offset uint64 +func (_e *Service_Expecter) RoleListMembers(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, limit interface{}, offset interface{}) *Service_RoleListMembers_Call { + return &Service_RoleListMembers_Call{Call: _e.mock.On("RoleListMembers", ctx, session, entityID, roleID, limit, offset)} +} + +func (_c *Service_RoleListMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, limit uint64, offset uint64)) *Service_RoleListMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 uint64 + if args[4] != nil { + arg4 = args[4].(uint64) + } + var arg5 uint64 + if args[5] != nil { + arg5 = args[5].(uint64) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + arg5, + ) + }) + return _c +} + +func (_c *Service_RoleListMembers_Call) Return(membersPage roles.MembersPage, err error) *Service_RoleListMembers_Call { + _c.Call.Return(membersPage, err) + return _c +} + +func (_c *Service_RoleListMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, limit uint64, offset uint64) (roles.MembersPage, error)) *Service_RoleListMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveActions provides a mock function for the type Service +func (_mock *Service) RoleRemoveActions(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) error { + ret := _mock.Called(ctx, session, entityID, roleID, actions) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveActions") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) error); ok { + r0 = returnFunc(ctx, session, entityID, roleID, actions) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RoleRemoveActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveActions' +type Service_RoleRemoveActions_Call struct { + *mock.Call +} + +// RoleRemoveActions is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - actions []string +func (_e *Service_Expecter) RoleRemoveActions(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, actions interface{}) *Service_RoleRemoveActions_Call { + return &Service_RoleRemoveActions_Call{Call: _e.mock.On("RoleRemoveActions", ctx, session, entityID, roleID, actions)} +} + +func (_c *Service_RoleRemoveActions_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string)) *Service_RoleRemoveActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleRemoveActions_Call) Return(err error) *Service_RoleRemoveActions_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RoleRemoveActions_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, actions []string) error) *Service_RoleRemoveActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveAllActions provides a mock function for the type Service +func (_mock *Service) RoleRemoveAllActions(ctx context.Context, session authn.Session, entityID string, roleID string) error { + ret := _mock.Called(ctx, session, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveAllActions") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) error); ok { + r0 = returnFunc(ctx, session, entityID, roleID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RoleRemoveAllActions_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveAllActions' +type Service_RoleRemoveAllActions_Call struct { + *mock.Call +} + +// RoleRemoveAllActions is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +func (_e *Service_Expecter) RoleRemoveAllActions(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}) *Service_RoleRemoveAllActions_Call { + return &Service_RoleRemoveAllActions_Call{Call: _e.mock.On("RoleRemoveAllActions", ctx, session, entityID, roleID)} +} + +func (_c *Service_RoleRemoveAllActions_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string)) *Service_RoleRemoveAllActions_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RoleRemoveAllActions_Call) Return(err error) *Service_RoleRemoveAllActions_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RoleRemoveAllActions_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string) error) *Service_RoleRemoveAllActions_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveAllMembers provides a mock function for the type Service +func (_mock *Service) RoleRemoveAllMembers(ctx context.Context, session authn.Session, entityID string, roleID string) error { + ret := _mock.Called(ctx, session, entityID, roleID) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveAllMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string) error); ok { + r0 = returnFunc(ctx, session, entityID, roleID) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RoleRemoveAllMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveAllMembers' +type Service_RoleRemoveAllMembers_Call struct { + *mock.Call +} + +// RoleRemoveAllMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +func (_e *Service_Expecter) RoleRemoveAllMembers(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}) *Service_RoleRemoveAllMembers_Call { + return &Service_RoleRemoveAllMembers_Call{Call: _e.mock.On("RoleRemoveAllMembers", ctx, session, entityID, roleID)} +} + +func (_c *Service_RoleRemoveAllMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string)) *Service_RoleRemoveAllMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + ) + }) + return _c +} + +func (_c *Service_RoleRemoveAllMembers_Call) Return(err error) *Service_RoleRemoveAllMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RoleRemoveAllMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string) error) *Service_RoleRemoveAllMembers_Call { + _c.Call.Return(run) + return _c +} + +// RoleRemoveMembers provides a mock function for the type Service +func (_mock *Service) RoleRemoveMembers(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) error { + ret := _mock.Called(ctx, session, entityID, roleID, members) + + if len(ret) == 0 { + panic("no return value specified for RoleRemoveMembers") + } + + var r0 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, []string) error); ok { + r0 = returnFunc(ctx, session, entityID, roleID, members) + } else { + r0 = ret.Error(0) + } + return r0 +} + +// Service_RoleRemoveMembers_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RoleRemoveMembers' +type Service_RoleRemoveMembers_Call struct { + *mock.Call +} + +// RoleRemoveMembers is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - members []string +func (_e *Service_Expecter) RoleRemoveMembers(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, members interface{}) *Service_RoleRemoveMembers_Call { + return &Service_RoleRemoveMembers_Call{Call: _e.mock.On("RoleRemoveMembers", ctx, session, entityID, roleID, members)} +} + +func (_c *Service_RoleRemoveMembers_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string)) *Service_RoleRemoveMembers_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 []string + if args[4] != nil { + arg4 = args[4].([]string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_RoleRemoveMembers_Call) Return(err error) *Service_RoleRemoveMembers_Call { + _c.Call.Return(err) + return _c +} + +func (_c *Service_RoleRemoveMembers_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, members []string) error) *Service_RoleRemoveMembers_Call { + _c.Call.Return(run) + return _c +} + // StartScheduler provides a mock function for the type Service func (_mock *Service) StartScheduler(ctx context.Context) error { ret := _mock.Called(ctx) @@ -541,6 +1939,90 @@ func (_c *Service_StartScheduler_Call) RunAndReturn(run func(ctx context.Context return _c } +// UpdateRoleName provides a mock function for the type Service +func (_mock *Service) UpdateRoleName(ctx context.Context, session authn.Session, entityID string, roleID string, newRoleName string) (roles.Role, error) { + ret := _mock.Called(ctx, session, entityID, roleID, newRoleName) + + if len(ret) == 0 { + panic("no return value specified for UpdateRoleName") + } + + var r0 roles.Role + var r1 error + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, string) (roles.Role, error)); ok { + return returnFunc(ctx, session, entityID, roleID, newRoleName) + } + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, string, string) roles.Role); ok { + r0 = returnFunc(ctx, session, entityID, roleID, newRoleName) + } else { + r0 = ret.Get(0).(roles.Role) + } + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, string, string) error); ok { + r1 = returnFunc(ctx, session, entityID, roleID, newRoleName) + } else { + r1 = ret.Error(1) + } + return r0, r1 +} + +// Service_UpdateRoleName_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdateRoleName' +type Service_UpdateRoleName_Call struct { + *mock.Call +} + +// UpdateRoleName is a helper method to define mock.On call +// - ctx context.Context +// - session authn.Session +// - entityID string +// - roleID string +// - newRoleName string +func (_e *Service_Expecter) UpdateRoleName(ctx interface{}, session interface{}, entityID interface{}, roleID interface{}, newRoleName interface{}) *Service_UpdateRoleName_Call { + return &Service_UpdateRoleName_Call{Call: _e.mock.On("UpdateRoleName", ctx, session, entityID, roleID, newRoleName)} +} + +func (_c *Service_UpdateRoleName_Call) Run(run func(ctx context.Context, session authn.Session, entityID string, roleID string, newRoleName string)) *Service_UpdateRoleName_Call { + _c.Call.Run(func(args mock.Arguments) { + var arg0 context.Context + if args[0] != nil { + arg0 = args[0].(context.Context) + } + var arg1 authn.Session + if args[1] != nil { + arg1 = args[1].(authn.Session) + } + var arg2 string + if args[2] != nil { + arg2 = args[2].(string) + } + var arg3 string + if args[3] != nil { + arg3 = args[3].(string) + } + var arg4 string + if args[4] != nil { + arg4 = args[4].(string) + } + run( + arg0, + arg1, + arg2, + arg3, + arg4, + ) + }) + return _c +} + +func (_c *Service_UpdateRoleName_Call) Return(role roles.Role, err error) *Service_UpdateRoleName_Call { + _c.Call.Return(role, err) + return _c +} + +func (_c *Service_UpdateRoleName_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, entityID string, roleID string, newRoleName string) (roles.Role, error)) *Service_UpdateRoleName_Call { + _c.Call.Return(run) + return _c +} + // UpdateRule provides a mock function for the type Service func (_mock *Service) UpdateRule(ctx context.Context, session authn.Session, r re.Rule) (re.Rule, error) { ret := _mock.Called(ctx, session, r) @@ -758,8 +2240,8 @@ func (_c *Service_UpdateRuleTags_Call) RunAndReturn(run func(ctx context.Context } // ViewRule provides a mock function for the type Service -func (_mock *Service) ViewRule(ctx context.Context, session authn.Session, id string) (re.Rule, error) { - ret := _mock.Called(ctx, session, id) +func (_mock *Service) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error) { + ret := _mock.Called(ctx, session, id, withRoles) if len(ret) == 0 { panic("no return value specified for ViewRule") @@ -767,16 +2249,16 @@ func (_mock *Service) ViewRule(ctx context.Context, session authn.Session, id st var r0 re.Rule var r1 error - if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string) (re.Rule, error)); ok { - return returnFunc(ctx, session, id) + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, bool) (re.Rule, error)); ok { + return returnFunc(ctx, session, id, withRoles) } - if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string) re.Rule); ok { - r0 = returnFunc(ctx, session, id) + if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, string, bool) re.Rule); ok { + r0 = returnFunc(ctx, session, id, withRoles) } else { r0 = ret.Get(0).(re.Rule) } - if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string) error); ok { - r1 = returnFunc(ctx, session, id) + if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, string, bool) error); ok { + r1 = returnFunc(ctx, session, id, withRoles) } else { r1 = ret.Error(1) } @@ -792,11 +2274,12 @@ type Service_ViewRule_Call struct { // - ctx context.Context // - session authn.Session // - id string -func (_e *Service_Expecter) ViewRule(ctx interface{}, session interface{}, id interface{}) *Service_ViewRule_Call { - return &Service_ViewRule_Call{Call: _e.mock.On("ViewRule", ctx, session, id)} +// - withRoles bool +func (_e *Service_Expecter) ViewRule(ctx interface{}, session interface{}, id interface{}, withRoles interface{}) *Service_ViewRule_Call { + return &Service_ViewRule_Call{Call: _e.mock.On("ViewRule", ctx, session, id, withRoles)} } -func (_c *Service_ViewRule_Call) Run(run func(ctx context.Context, session authn.Session, id string)) *Service_ViewRule_Call { +func (_c *Service_ViewRule_Call) Run(run func(ctx context.Context, session authn.Session, id string, withRoles bool)) *Service_ViewRule_Call { _c.Call.Run(func(args mock.Arguments) { var arg0 context.Context if args[0] != nil { @@ -810,10 +2293,15 @@ func (_c *Service_ViewRule_Call) Run(run func(ctx context.Context, session authn if args[2] != nil { arg2 = args[2].(string) } + var arg3 bool + if args[3] != nil { + arg3 = args[3].(bool) + } run( arg0, arg1, arg2, + arg3, ) }) return _c @@ -824,7 +2312,7 @@ func (_c *Service_ViewRule_Call) Return(rule re.Rule, err error) *Service_ViewRu return _c } -func (_c *Service_ViewRule_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, id string) (re.Rule, error)) *Service_ViewRule_Call { +func (_c *Service_ViewRule_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, id string, withRoles bool) (re.Rule, error)) *Service_ViewRule_Call { _c.Call.Return(run) return _c } diff --git a/re/operations.go b/re/operations.go deleted file mode 100644 index 8ca795a54..000000000 --- a/re/operations.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Abstract Machines -// SPDX-License-Identifier: Apache-2.0 - -package re - -import ( - "github.com/absmach/supermq/pkg/errors" - "github.com/absmach/supermq/pkg/permissions" - "github.com/absmach/supermq/pkg/policies" -) - -const EntityType = "rules" - -const ( - OpAddRule permissions.Operation = iota - OpViewRule - OpUpdateRule - OpUpdateRuleTags - OpUpdateRuleSchedule - OpListRules - OpRemoveRule - OpEnableRule - OpDisableRule -) - -const ( - OpAddRuleStr = "OpAddRule" - OpViewRuleStr = "OpViewRule" - OpUpdateRuleStr = "OpUpdateRule" - OpUpdateRuleTagsStr = "OpUpdateRuleTags" - OpUpdateRuleScheduleStr = "OpUpdateRuleSchedule" - OpListRulesStr = "OpListRules" - OpRemoveRuleStr = "OpRemoveRule" - OpEnableRuleStr = "OpEnableRule" - OpDisableRuleStr = "OpDisableRule" -) - -func GetPermission(op permissions.Operation) (string, error) { - if op < OpAddRule || op > OpDisableRule { - return "", errors.New("invalid operation") - } - return policies.MembershipPermission, nil -} - -func OperationName(op permissions.Operation) string { - switch op { - case OpAddRule: - return OpAddRuleStr - case OpViewRule: - return OpViewRuleStr - case OpUpdateRule: - return OpUpdateRuleStr - case OpUpdateRuleTags: - return OpUpdateRuleTagsStr - case OpUpdateRuleSchedule: - return OpUpdateRuleScheduleStr - case OpListRules: - return OpListRulesStr - case OpRemoveRule: - return OpRemoveRuleStr - case OpEnableRule: - return OpEnableRuleStr - case OpDisableRule: - return OpDisableRuleStr - default: - return "unknown" - } -} diff --git a/re/operations/operations.go b/re/operations/operations.go new file mode 100644 index 000000000..85e4baf21 --- /dev/null +++ b/re/operations/operations.go @@ -0,0 +1,64 @@ +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 + +package operations + +import ( + "github.com/absmach/supermq/pkg/permissions" +) + +const EntityType = "rule" + +// Rule Operations. +const ( + OpAddRule permissions.Operation = iota + OpViewRule + OpUpdateRule + OpUpdateRuleTags + OpUpdateRuleSchedule + OpRemoveRule + OpListRules + OpEnableRule + OpDisableRule +) + +func OperationDetails() map[permissions.Operation]permissions.OperationDetails { + return map[permissions.Operation]permissions.OperationDetails{ + OpAddRule: { + Name: "add", + PermissionRequired: true, + }, + OpViewRule: { + Name: "view", + PermissionRequired: true, + }, + OpUpdateRule: { + Name: "update", + PermissionRequired: true, + }, + OpUpdateRuleTags: { + Name: "update_tags", + PermissionRequired: true, + }, + OpUpdateRuleSchedule: { + Name: "update_schedule", + PermissionRequired: true, + }, + OpRemoveRule: { + Name: "delete", + PermissionRequired: true, + }, + OpListRules: { + Name: "list", + PermissionRequired: true, + }, + OpEnableRule: { + Name: "enable", + PermissionRequired: true, + }, + OpDisableRule: { + Name: "disable", + PermissionRequired: true, + }, + } +} diff --git a/re/postgres/init.go b/re/postgres/init.go index 2420b8956..f7ad8191d 100644 --- a/re/postgres/init.go +++ b/re/postgres/init.go @@ -4,12 +4,20 @@ package postgres import ( + dpostgres "github.com/absmach/supermq/domains/postgres" + "github.com/absmach/supermq/pkg/errors" + repoerr "github.com/absmach/supermq/pkg/errors/repository" + rolesPostgres "github.com/absmach/supermq/pkg/roles/repo/postgres" _ "github.com/jackc/pgx/v5/stdlib" // required for SQL access migrate "github.com/rubenv/sql-migrate" ) -func Migration() *migrate.MemoryMigrationSource { - return &migrate.MemoryMigrationSource{ +func Migration() (*migrate.MemoryMigrationSource, error) { + rolesMigration, err := rolesPostgres.Migration(rolesTableNamePrefix, entityTableName, entityIDColumnName) + if err != nil { + return &migrate.MemoryMigrationSource{}, errors.Wrap(repoerr.ErrRoleMigration, err) + } + rulesMigration := &migrate.MemoryMigrationSource{ Migrations: []*migrate.Migration{ { Id: "rules_01", @@ -65,4 +73,14 @@ func Migration() *migrate.MemoryMigrationSource { }, }, } + + rulesMigration.Migrations = append(rulesMigration.Migrations, rolesMigration.Migrations...) + + domainsMigration, err := dpostgres.Migration() + if err != nil { + return &migrate.MemoryMigrationSource{}, errors.Wrap(repoerr.ErrRoleMigration, err) + } + rulesMigration.Migrations = append(rulesMigration.Migrations, domainsMigration.Migrations...) + + return rulesMigration, nil } diff --git a/re/postgres/repository.go b/re/postgres/repository.go index 3596a9f7d..a64b8ba67 100644 --- a/re/postgres/repository.go +++ b/re/postgres/repository.go @@ -10,19 +10,32 @@ import ( "strings" "time" + mgPolicies "github.com/absmach/magistrala/pkg/policies" "github.com/absmach/magistrala/re" api "github.com/absmach/supermq/api/http" "github.com/absmach/supermq/pkg/errors" repoerr "github.com/absmach/supermq/pkg/errors/repository" "github.com/absmach/supermq/pkg/postgres" + rolesPostgres "github.com/absmach/supermq/pkg/roles/repo/postgres" +) + +const ( + rolesTableNamePrefix = "rules" + entityTableName = "rules" + entityIDColumnName = "id" ) type PostgresRepository struct { DB postgres.Database + rolesPostgres.Repository } func NewRepository(db postgres.Database) re.Repository { - return &PostgresRepository{DB: db} + rolesRepo := rolesPostgres.NewRepository(db, mgPolicies.RulesType, rolesTableNamePrefix, entityTableName, entityIDColumnName) + return &PostgresRepository{ + DB: db, + Repository: rolesRepo, + } } func (repo *PostgresRepository) AddRule(ctx context.Context, r re.Rule) (re.Rule, error) { @@ -82,6 +95,157 @@ func (repo *PostgresRepository) ViewRule(ctx context.Context, id string) (re.Rul return ret, nil } +func (repo *PostgresRepository) RetrieveByIDWithRoles(ctx context.Context, id, memberID string) (re.Rule, error) { + query := ` + WITH selected_rule AS ( + SELECT + r.id, + r.domain_id + FROM + rules r + WHERE + r.id = :id + LIMIT 1 + ), + selected_rule_roles AS ( + SELECT + rr.entity_id AS rule_id, + rrm.member_id AS member_id, + rr.id AS role_id, + rr."name" AS role_name, + jsonb_agg(DISTINCT rra."action") AS actions, + 'direct' AS access_type, + '' AS access_provider_id + FROM + rules_roles rr + JOIN + rules_role_members rrm ON rr.id = rrm.role_id + JOIN + rules_role_actions rra ON rr.id = rra.role_id + JOIN + selected_rule sr ON sr.id = rr.entity_id + AND rrm.member_id = :member_id + GROUP BY + rr.entity_id, rr.id, rr.name, rrm.member_id + ), + selected_domain_roles AS ( + SELECT + sr.id AS rule_id, + drm.member_id AS member_id, + dr.id AS role_id, + dr."name" AS role_name, + jsonb_agg(DISTINCT all_actions."action") AS actions, + 'domain' AS access_type, + dr.entity_id AS access_provider_id + FROM + domains d + JOIN + selected_rule sr ON sr.domain_id = d.id + JOIN + domains_roles dr ON dr.entity_id = d.id + JOIN + domains_role_members drm ON dr.id = drm.role_id + JOIN + domains_role_actions dra ON dr.id = dra.role_id + JOIN + domains_role_actions all_actions ON dr.id = all_actions.role_id + WHERE + drm.member_id = :member_id + AND dra."action" LIKE 'rule%' + GROUP BY + sr.id, dr.entity_id, dr.id, dr."name", drm.member_id + ), + all_roles AS ( + SELECT + srr.rule_id, + srr.member_id, + srr.role_id, + srr.role_name, + srr.actions, + srr.access_type, + srr.access_provider_id + FROM + selected_rule_roles srr + UNION + SELECT + sdr.rule_id, + sdr.member_id, + sdr.role_id, + sdr.role_name, + sdr.actions, + sdr.access_type, + sdr.access_provider_id + FROM + selected_domain_roles sdr + ), + final_roles AS ( + SELECT + ar.rule_id, + ar.member_id, + jsonb_agg( + jsonb_build_object( + 'role_id', ar.role_id, + 'role_name', ar.role_name, + 'actions', ar.actions, + 'access_type', ar.access_type, + 'access_provider_id', ar.access_provider_id + ) + ) AS roles + FROM all_roles ar + GROUP BY + ar.rule_id, ar.member_id + ) + SELECT + r2.id, + r2."name", + r2.domain_id, + r2.tags, + r2.metadata, + r2.input_channel, + r2.input_topic, + r2.outputs, + r2.status, + r2.logic_type, + r2.logic_value, + r2.time, + r2.recurring, + r2.recurring_period, + r2.start_datetime, + r2.created_at, + r2.created_by, + r2.updated_at, + r2.updated_by, + fr.member_id, + fr.roles + FROM rules r2 + JOIN final_roles fr ON fr.rule_id = r2.id + ` + parameters := map[string]any{ + "id": id, + "member_id": memberID, + } + row, err := repo.DB.NamedQueryContext(ctx, query, parameters) + if err != nil { + return re.Rule{}, errors.Wrap(repoerr.ErrViewEntity, err) + } + defer row.Close() + + dbrule := dbRule{} + if !row.Next() { + return re.Rule{}, repoerr.ErrNotFound + } + + if err := row.StructScan(&dbrule); err != nil { + return re.Rule{}, errors.Wrap(repoerr.ErrViewEntity, err) + } + + r, err := dbToRule(dbrule) + if err != nil { + return re.Rule{}, errors.Wrap(repoerr.ErrViewEntity, err) + } + return r, nil +} + func (repo *PostgresRepository) UpdateRuleStatus(ctx context.Context, r re.Rule) (re.Rule, error) { q := `UPDATE rules SET status = :status, updated_at = :updated_at, updated_by = :updated_by diff --git a/re/postgres/rule.go b/re/postgres/rule.go index 3027e3d66..43fac2314 100644 --- a/re/postgres/rule.go +++ b/re/postgres/rule.go @@ -11,6 +11,7 @@ import ( "github.com/absmach/magistrala/pkg/schedule" "github.com/absmach/magistrala/re" "github.com/absmach/supermq/pkg/errors" + "github.com/absmach/supermq/pkg/roles" "github.com/jackc/pgtype" ) @@ -35,6 +36,8 @@ type dbRule struct { CreatedBy string `db:"created_by"` UpdatedAt time.Time `db:"updated_at"` UpdatedBy string `db:"updated_by"` + MemberID string `db:"member_id,omitempty"` + Roles json.RawMessage `db:"roles,omitempty"` } func ruleToDb(r re.Rule) (dbRule, error) { @@ -108,6 +111,13 @@ func dbToRule(dto dbRule) (re.Rule, error) { } } + var roles []roles.MemberRoleActions + if dto.Roles != nil { + if err := json.Unmarshal(dto.Roles, &roles); err != nil { + return re.Rule{}, errors.Wrap(errors.ErrMalformedEntity, err) + } + } + return re.Rule{ ID: dto.ID, Name: dto.Name, @@ -132,6 +142,7 @@ func dbToRule(dto dbRule) (re.Rule, error) { CreatedBy: dto.CreatedBy, UpdatedAt: dto.UpdatedAt, UpdatedBy: dto.UpdatedBy, + Roles: roles, }, nil } diff --git a/re/postgres/setup_test.go b/re/postgres/setup_test.go index 0ee52b2a1..29b67862f 100644 --- a/re/postgres/setup_test.go +++ b/re/postgres/setup_test.go @@ -75,7 +75,11 @@ func TestMain(m *testing.M) { SSLRootCert: "", } - if db, err = postgres.Setup(dbConfig, *repostgres.Migration()); err != nil { + migration, err := repostgres.Migration() + if err != nil { + log.Fatalf("Could not get migration: %s", err) + } + if db, err = postgres.Setup(dbConfig, *migration); err != nil { log.Fatalf("Could not setup test DB connection: %s", err) } diff --git a/re/rule.go b/re/rule.go index f689d28f4..10d28756a 100644 --- a/re/rule.go +++ b/re/rule.go @@ -13,6 +13,7 @@ import ( "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/errors" "github.com/absmach/supermq/pkg/messaging" + "github.com/absmach/supermq/pkg/roles" ) const ( @@ -42,21 +43,22 @@ var outputRegistry = map[outputs.OutputType]func() Runnable{ } type Rule struct { - ID string `json:"id"` - Name string `json:"name"` - DomainID string `json:"domain"` - Metadata Metadata `json:"metadata,omitempty"` - Tags []string `json:"tags,omitempty"` - InputChannel string `json:"input_channel"` - InputTopic string `json:"input_topic"` - Logic Script `json:"logic"` - Outputs Outputs `json:"outputs,omitempty"` - Schedule schedule.Schedule `json:"schedule,omitempty"` - Status Status `json:"status"` - CreatedAt time.Time `json:"created_at"` - CreatedBy string `json:"created_by"` - UpdatedAt time.Time `json:"updated_at"` - UpdatedBy string `json:"updated_by"` + ID string `json:"id"` + Name string `json:"name"` + DomainID string `json:"domain"` + Metadata Metadata `json:"metadata,omitempty"` + Tags []string `json:"tags,omitempty"` + InputChannel string `json:"input_channel"` + InputTopic string `json:"input_topic"` + Logic Script `json:"logic"` + Outputs Outputs `json:"outputs,omitempty"` + Schedule schedule.Schedule `json:"schedule,omitempty"` + Status Status `json:"status"` + CreatedAt time.Time `json:"created_at"` + CreatedBy string `json:"created_by"` + UpdatedAt time.Time `json:"updated_at"` + UpdatedBy string `json:"updated_by"` + Roles []roles.MemberRoleActions `json:"roles,omitempty"` } // EventEncode converts a Rule struct to map[string]any at event producer. @@ -224,7 +226,7 @@ type Page struct { type Service interface { messaging.MessageHandler AddRule(ctx context.Context, session authn.Session, r Rule) (Rule, error) - ViewRule(ctx context.Context, session authn.Session, id string) (Rule, error) + ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (Rule, error) UpdateRule(ctx context.Context, session authn.Session, r Rule) (Rule, error) UpdateRuleTags(ctx context.Context, session authn.Session, r Rule) (Rule, error) UpdateRuleSchedule(ctx context.Context, session authn.Session, r Rule) (Rule, error) @@ -234,11 +236,13 @@ type Service interface { DisableRule(ctx context.Context, session authn.Session, id string) (Rule, error) StartScheduler(ctx context.Context) error + roles.RoleManager } type Repository interface { AddRule(ctx context.Context, r Rule) (Rule, error) ViewRule(ctx context.Context, id string) (Rule, error) + RetrieveByIDWithRoles(ctx context.Context, id, memberID string) (Rule, error) UpdateRule(ctx context.Context, r Rule) (Rule, error) UpdateRuleTags(ctx context.Context, r Rule) (Rule, error) UpdateRuleSchedule(ctx context.Context, r Rule) (Rule, error) @@ -246,4 +250,5 @@ type Repository interface { UpdateRuleStatus(ctx context.Context, r Rule) (Rule, error) ListRules(ctx context.Context, pm PageMeta) (Page, error) UpdateRuleDue(ctx context.Context, id string, due time.Time) (Rule, error) + roles.Repository } diff --git a/re/service.go b/re/service.go index e041d901c..09d5e9c62 100644 --- a/re/service.go +++ b/re/service.go @@ -11,11 +11,14 @@ import ( "github.com/absmach/magistrala/pkg/emailer" pkglog "github.com/absmach/magistrala/pkg/logger" "github.com/absmach/magistrala/pkg/ticker" + "github.com/absmach/magistrala/re/operations" "github.com/absmach/supermq" "github.com/absmach/supermq/pkg/authn" "github.com/absmach/supermq/pkg/errors" svcerr "github.com/absmach/supermq/pkg/errors/service" "github.com/absmach/supermq/pkg/messaging" + "github.com/absmach/supermq/pkg/policies" + "github.com/absmach/supermq/pkg/roles" ) var ErrGoroutinesNotAllowed = errors.New("goroutines are not allowed in Go scripts") @@ -30,23 +33,29 @@ type re struct { ticker ticker.Ticker email emailer.Emailer readers grpcReadersV1.ReadersServiceClient + roles.ProvisionManageService } -func NewService(repo Repository, runInfo chan pkglog.RunInfo, idp supermq.IDProvider, rePubSub messaging.PubSub, writersPub, alarmsPub messaging.Publisher, tck ticker.Ticker, emailer emailer.Emailer, readers grpcReadersV1.ReadersServiceClient) Service { - return &re{ - repo: repo, - idp: idp, - runInfo: runInfo, - rePubSub: rePubSub, - writersPub: writersPub, - alarmsPub: alarmsPub, - ticker: tck, - email: emailer, - readers: readers, +func NewService(repo Repository, runInfo chan pkglog.RunInfo, policy policies.Service, idp supermq.IDProvider, rePubSub messaging.PubSub, writersPub, alarmsPub messaging.Publisher, tck ticker.Ticker, emailer emailer.Emailer, readers grpcReadersV1.ReadersServiceClient, availableActions []roles.Action, builtInRoles map[roles.BuiltInRoleName][]roles.Action) (Service, error) { + rpms, err := roles.NewProvisionManageService(operations.EntityType, repo, policy, idp, availableActions, builtInRoles) + if err != nil { + return nil, err } + return &re{ + repo: repo, + idp: idp, + runInfo: runInfo, + rePubSub: rePubSub, + writersPub: writersPub, + alarmsPub: alarmsPub, + ticker: tck, + email: emailer, + readers: readers, + ProvisionManageService: rpms, + }, nil } -func (re *re) AddRule(ctx context.Context, session authn.Session, r Rule) (Rule, error) { +func (re *re) AddRule(ctx context.Context, session authn.Session, r Rule) (retRule Rule, retErr error) { if r.Logic.Type == GoType && goKeywordRegex.MatchString(r.Logic.Value) { return Rule{}, errors.Wrap(svcerr.ErrMalformedEntity, ErrGoroutinesNotAllowed) } @@ -72,11 +81,45 @@ func (re *re) AddRule(ctx context.Context, session authn.Session, r Rule) (Rule, return Rule{}, errors.Wrap(svcerr.ErrCreateEntity, err) } + defer func() { + if retErr != nil { + if errRollBack := re.repo.RemoveRule(ctx, rule.ID); errRollBack != nil { + retErr = errors.Wrap(retErr, errors.Wrap(svcerr.ErrRollbackRepo, errRollBack)) + } + } + }() + + newBuiltInRoleMembers := map[roles.BuiltInRoleName][]roles.Member{ + BuiltInRoleAdmin: {roles.Member(session.UserID)}, + } + + optionalPolicies := []policies.Policy{ + { + SubjectType: policies.DomainType, + Subject: session.DomainID, + Relation: policies.DomainRelation, + ObjectType: operations.EntityType, + Object: rule.ID, + }, + } + + _, err = re.AddNewEntitiesRoles(ctx, session.DomainID, session.UserID, []string{rule.ID}, optionalPolicies, newBuiltInRoleMembers) + if err != nil { + return Rule{}, errors.Wrap(svcerr.ErrAddPolicies, err) + } + return rule, nil } -func (re *re) ViewRule(ctx context.Context, session authn.Session, id string) (Rule, error) { - rule, err := re.repo.ViewRule(ctx, id) +func (re *re) ViewRule(ctx context.Context, session authn.Session, id string, withRoles bool) (Rule, error) { + var rule Rule + var err error + switch withRoles { + case true: + rule, err = re.repo.RetrieveByIDWithRoles(ctx, id, session.UserID) + default: + rule, err = re.repo.ViewRule(ctx, id) + } if err != nil { return Rule{}, errors.Wrap(svcerr.ErrViewEntity, err) } diff --git a/re/service_test.go b/re/service_test.go index 7cc8285a7..f33add753 100644 --- a/re/service_test.go +++ b/re/service_test.go @@ -26,6 +26,8 @@ import ( svcerr "github.com/absmach/supermq/pkg/errors/service" "github.com/absmach/supermq/pkg/messaging" pubsubmocks "github.com/absmach/supermq/pkg/messaging/mocks" + policymocks "github.com/absmach/supermq/pkg/policies/mocks" + "github.com/absmach/supermq/pkg/roles" "github.com/absmach/supermq/pkg/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -59,27 +61,40 @@ var ( } ) -func newService(t *testing.T, runInfo chan pkglog.RunInfo) (re.Service, *mocks.Repository, *pubsubmocks.PubSub, *tmocks.Ticker, *emocks.Emailer) { +func newService(t *testing.T, runInfo chan pkglog.RunInfo) (re.Service, *mocks.Repository, *pubsubmocks.PubSub, *tmocks.Ticker, *emocks.Emailer, *policymocks.Service) { repo := new(mocks.Repository) mockTicker := new(tmocks.Ticker) idProvider := uuid.NewMock() pubsub := pubsubmocks.NewPubSub(t) readersSvc := new(readmocks.ReadersServiceClient) e := new(emocks.Emailer) - return re.NewService(repo, runInfo, idProvider, pubsub, pubsub, pubsub, mockTicker, e, readersSvc), repo, pubsub, mockTicker, e + policy := new(policymocks.Service) + availableActions := []roles.Action{} + builtInRoles := map[roles.BuiltInRoleName][]roles.Action{ + "admin": availableActions, + } + svc, err := re.NewService(repo, runInfo, policy, idProvider, pubsub, pubsub, pubsub, mockTicker, e, readersSvc, availableActions, builtInRoles) + if err != nil { + t.Fatalf("Failed to create service: %v", err) + } + return svc, repo, pubsub, mockTicker, e, policy } func TestAddRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, policies := newService(t, make(chan pkglog.RunInfo)) ruleName := namegen.Generate() now := time.Now().Add(time.Hour) cases := []struct { - desc string - session authn.Session - rule re.Rule - res re.Rule - err error + desc string + session authn.Session + rule re.Rule + res re.Rule + err error + addPoliciesErr error + deletePolicies error + addRoleErr error + deleteErr error }{ { desc: "Add rule successfully", @@ -109,7 +124,10 @@ func TestAddRule(t *testing.T) { CreatedBy: userID, DomainID: domainID, }, - err: nil, + err: nil, + addPoliciesErr: nil, + addRoleErr: nil, + deleteErr: nil, }, { desc: "Add rule with failed repo", @@ -126,7 +144,11 @@ func TestAddRule(t *testing.T) { Time: now, }, }, - err: repoerr.ErrCreateEntity, + err: repoerr.ErrCreateEntity, + addPoliciesErr: nil, + deletePolicies: nil, + addRoleErr: nil, + deleteErr: nil, }, { desc: "Add rule with non-zero StartDateTime", @@ -158,7 +180,136 @@ func TestAddRule(t *testing.T) { CreatedBy: userID, DomainID: domainID, }, - err: nil, + err: nil, + addPoliciesErr: nil, + addRoleErr: nil, + deleteErr: nil, + }, + { + desc: "Add rule with failed to add roles and failed to delete policies", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + }, + res: re.Rule{ + Name: ruleName, + ID: ruleID, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + Status: re.EnabledStatus, + CreatedBy: userID, + DomainID: domainID, + }, + addRoleErr: svcerr.ErrCreateEntity, + deletePolicies: svcerr.ErrRemoveEntity, + err: svcerr.ErrRemoveEntity, + }, + { + desc: "Add rule with failed to add policies", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + }, + res: re.Rule{ + Name: ruleName, + ID: ruleID, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + Status: re.EnabledStatus, + CreatedBy: userID, + DomainID: domainID, + }, + addPoliciesErr: svcerr.ErrAuthorization, + err: svcerr.ErrAddPolicies, + }, + { + desc: "Add rule with failed to add policies and failed rollback", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + }, + res: re.Rule{ + Name: ruleName, + ID: ruleID, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + Status: re.EnabledStatus, + CreatedBy: userID, + DomainID: domainID, + }, + addPoliciesErr: svcerr.ErrAuthorization, + deleteErr: svcerr.ErrRemoveEntity, + err: svcerr.ErrRollbackRepo, + }, + { + desc: "Add rule with failed to add roles", + session: authn.Session{ + UserID: userID, + DomainID: domainID, + }, + rule: re.Rule{ + Name: ruleName, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + }, + res: re.Rule{ + Name: ruleName, + ID: ruleID, + InputChannel: inputChannel, + Schedule: pkgSch.Schedule{ + Recurring: pkgSch.Daily, + RecurringPeriod: 1, + Time: now, + }, + Status: re.EnabledStatus, + CreatedBy: userID, + DomainID: domainID, + }, + addRoleErr: svcerr.ErrCreateEntity, + err: svcerr.ErrAddPolicies, }, { desc: "Add rule with Go script containing goroutines", @@ -186,6 +337,10 @@ func TestAddRule(t *testing.T) { for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { repoCall := repo.On("AddRule", mock.Anything, mock.Anything).Return(tc.res, tc.err) + policyCall := policies.On("AddPolicies", context.Background(), mock.Anything).Return(tc.addPoliciesErr) + policyCall2 := policies.On("DeletePolicies", context.Background(), mock.Anything).Return(tc.deletePolicies).Maybe() + repoCall1 := repo.On("AddRoles", context.Background(), mock.Anything).Return([]roles.RoleProvision{}, tc.addRoleErr) + repoCall2 := repo.On("Remove", context.Background(), mock.Anything).Return(tc.deleteErr).Maybe() res, err := svc.AddRule(context.Background(), tc.session, tc.rule) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) if err == nil { @@ -193,14 +348,18 @@ func TestAddRule(t *testing.T) { assert.Equal(t, tc.rule.Name, res.Name) assert.Equal(t, tc.rule.Schedule, res.Schedule) } - defer repoCall.Unset() + policyCall.Unset() + policyCall2.Unset() + repoCall.Unset() + repoCall1.Unset() + repoCall2.Unset() }) } } func TestViewRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) now := time.Now().Add(time.Hour) cases := []struct { @@ -246,7 +405,7 @@ func TestViewRule(t *testing.T) { for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { repoCall := repo.On("ViewRule", mock.Anything, mock.Anything).Return(tc.res, tc.err) - res, err := svc.ViewRule(context.Background(), tc.session, tc.id) + res, err := svc.ViewRule(context.Background(), tc.session, tc.id, false) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) if err == nil { @@ -259,7 +418,7 @@ func TestViewRule(t *testing.T) { func TestUpdateRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) newName := namegen.Generate() now := time.Now().Add(time.Hour) @@ -370,7 +529,7 @@ func TestUpdateRule(t *testing.T) { func TestUpdateRuleTags(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) cases := []struct { desc string @@ -427,7 +586,7 @@ func TestUpdateRuleTags(t *testing.T) { func TestUpdateRuleSchedule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) now := time.Now().UTC() future := now.Add(2 * time.Hour) @@ -495,7 +654,7 @@ func TestUpdateRuleSchedule(t *testing.T) { func TestListRules(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) numRules := 50 now := time.Now().Add(time.Hour) var rules []re.Rule @@ -629,13 +788,14 @@ func TestListRules(t *testing.T) { func TestRemoveRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, policies := newService(t, make(chan pkglog.RunInfo)) cases := []struct { - desc string - session authn.Session - id string - err error + desc string + session authn.Session + id string + err error + deletePoliciesErr error }{ { desc: "remove rule successfully", @@ -643,8 +803,9 @@ func TestRemoveRule(t *testing.T) { UserID: userID, DomainID: domainID, }, - id: ruleID, - err: nil, + id: ruleID, + err: nil, + deletePoliciesErr: nil, }, { desc: "remove rule with failed repo", @@ -652,25 +813,28 @@ func TestRemoveRule(t *testing.T) { UserID: userID, DomainID: domainID, }, - id: ruleID, - err: svcerr.ErrRemoveEntity, + id: ruleID, + err: svcerr.ErrRemoveEntity, + deletePoliciesErr: nil, }, } for _, tc := range cases { t.Run(tc.desc, func(t *testing.T) { repoCall := repo.On("RemoveRule", mock.Anything, mock.Anything).Return(tc.err) + policyCall := policies.On("DeletePolicies", context.Background(), mock.Anything).Return(tc.deletePoliciesErr) err := svc.RemoveRule(context.Background(), tc.session, tc.id) assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err)) - defer repoCall.Unset() + policyCall.Unset() + repoCall.Unset() }) } } func TestEnableRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) now := time.Now() @@ -730,7 +894,7 @@ func TestEnableRule(t *testing.T) { func TestDisableRule(t *testing.T) { // nolint:dogsled - svc, repo, _, _, _ := newService(t, make(chan pkglog.RunInfo)) + svc, repo, _, _, _, _ := newService(t, make(chan pkglog.RunInfo)) now := time.Now() @@ -789,7 +953,7 @@ func TestDisableRule(t *testing.T) { } func TestHandle(t *testing.T) { - svc, repo, pubmocks, _, emailer := newService(t, make(chan pkglog.RunInfo)) + svc, repo, pubmocks, _, emailer, _ := newService(t, make(chan pkglog.RunInfo)) now := time.Now() scheduled := false @@ -1461,7 +1625,8 @@ func TestHandle(t *testing.T) { func TestStartScheduler(t *testing.T) { now := time.Now().Truncate(time.Minute) ri := make(chan pkglog.RunInfo) - svc, repo, _, ticker, _ := newService(t, ri) + // nolint:dogsled + svc, repo, _, ticker, _, _ := newService(t, ri) ctxCases := []struct { desc string diff --git a/scripts/combine-schema.sh b/scripts/combine-schema.sh new file mode 100755 index 000000000..76053ad6b --- /dev/null +++ b/scripts/combine-schema.sh @@ -0,0 +1,350 @@ +#!/bin/sh +# Copyright (c) Abstract Machines +# SPDX-License-Identifier: Apache-2.0 + +set -eu + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +REPO_ROOT=$(CDPATH= cd -- "$SCRIPT_DIR/.." && pwd) + +SUPERMQ_SCHEMA="$REPO_ROOT/docker/supermq-docker/spicedb/schema.zed" +OVERRIDE_SCHEMA="$REPO_ROOT/docker/spicedb/override-schema.zed" +OUTPUT_SCHEMA="$REPO_ROOT/docker/spicedb/combined-schema.zed" + +if [ ! -f "$SUPERMQ_SCHEMA" ]; then + echo "ERROR: $SUPERMQ_SCHEMA not found" >&2 + exit 1 +fi + +if [ ! -f "$OVERRIDE_SCHEMA" ]; then + echo "ERROR: $OVERRIDE_SCHEMA not found" >&2 + exit 1 +fi + +mkdir -p "$(dirname "$OUTPUT_SCHEMA")" + +tmp_supermq_schema=$(mktemp) +tmp_supermq_merged=$(mktemp) +tmp_override_remaining=$(mktemp) +tmp_overlay_domain=$(mktemp) +tmp_overlay_team=$(mktemp) +tmp_overlay_domain_relations=$(mktemp) +tmp_overlay_team_relations=$(mktemp) +tmp_overlay_domain_permissions=$(mktemp) +tmp_overlay_membership_extension=$(mktemp) + +cleanup() { + rm -f "$tmp_supermq_schema" + rm -f "$tmp_supermq_merged" + rm -f "$tmp_override_remaining" + rm -f "$tmp_overlay_domain" + rm -f "$tmp_overlay_team" + rm -f "$tmp_overlay_domain_relations" + rm -f "$tmp_overlay_team_relations" + rm -f "$tmp_overlay_domain_permissions" + rm -f "$tmp_overlay_membership_extension" +} +trap cleanup EXIT INT TERM + +cp "$SUPERMQ_SCHEMA" "$tmp_supermq_schema" + +# Extract the first domain overlay block from override schema. +if ! awk ' + BEGIN { + in_domain = 0 + found = 0 + } + !found && /^definition domain[[:space:]]*{/ { + in_domain = 1 + found = 1 + next + } + in_domain { + if ($0 ~ /^}/) { + in_domain = 0 + next + } + print + } + END { + if (!found) { + exit 1 + } + } +' "$OVERRIDE_SCHEMA" > "$tmp_overlay_domain"; then + echo "ERROR: definition domain block not found in $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +# Extract the first team overlay block from override schema. +if ! awk ' + BEGIN { + in_team = 0 + found = 0 + } + !found && /^definition team[[:space:]]*{/ { + in_team = 1 + found = 1 + next + } + in_team { + if ($0 ~ /^}/) { + in_team = 0 + next + } + print + } + END { + if (!found) { + exit 1 + } + } +' "$OVERRIDE_SCHEMA" > "$tmp_overlay_team"; then + echo "ERROR: definition team block not found in $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +# Read explicit domain overlay relations from override domain block. +awk ' + /^[[:space:]]*relation[[:space:]]+[A-Za-z0-9_]+:[[:space:]]*role#member[[:space:]]*\|[[:space:]]*team#member[[:space:]]*$/ { + line = $0 + sub(/^[[:space:]]*/, "\t", line) + print line + } +' "$tmp_overlay_domain" > "$tmp_overlay_domain_relations" + +# Read explicit team overlay relations from override team block. +awk ' + /^[[:space:]]*relation[[:space:]]+[A-Za-z0-9_]+:[[:space:]]*role#member[[:space:]]*\|[[:space:]]*team#member[[:space:]]*$/ { + line = $0 + sub(/^[[:space:]]*/, "\t", line) + print line + } +' "$tmp_overlay_team" > "$tmp_overlay_team_relations" + +# Read explicit domain overlay permissions from override domain block. +awk ' + /^[[:space:]]*permission[[:space:]]+[A-Za-z0-9_]+_permission[[:space:]]*=/ { + line = $0 + sub(/^[[:space:]]*/, "\t", line) + print line + } +' "$tmp_overlay_domain" > "$tmp_overlay_domain_permissions" + +# Read explicit domain membership extension expression from override domain block. +awk ' + /^[[:space:]]*permission[[:space:]]+membership_extension[[:space:]]*=/ { + line = $0 + sub(/^[[:space:]]*permission[[:space:]]+membership_extension[[:space:]]*=[[:space:]]*/, "", line) + print line + exit + } +' "$tmp_overlay_domain" > "$tmp_overlay_membership_extension" + +if [ ! -s "$tmp_overlay_domain_relations" ]; then + echo "ERROR: no domain relation overlay lines found in definition domain block of $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +if [ ! -s "$tmp_overlay_team_relations" ]; then + echo "ERROR: no team relation overlay lines found in definition team block of $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +if [ ! -s "$tmp_overlay_domain_permissions" ]; then + echo "ERROR: no domain permission overlay lines found in definition domain block of $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +if [ ! -s "$tmp_overlay_membership_extension" ]; then + echo "ERROR: permission membership_extension not found in definition domain block of $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +# Remove the first domain and first team overlay blocks from override schema before appending. +if ! awk ' + BEGIN { + skip_domain = 0 + skip_team = 0 + removed_domain = 0 + removed_team = 0 + } + !removed_domain && /^definition domain[[:space:]]*{/ { + skip_domain = 1 + removed_domain = 1 + next + } + skip_domain { + if ($0 ~ /^}/) { + skip_domain = 0 + } + next + } + !removed_team && /^definition team[[:space:]]*{/ { + skip_team = 1 + removed_team = 1 + next + } + skip_team { + if ($0 ~ /^}/) { + skip_team = 0 + } + next + } + { print } + END { + if (!removed_domain || !removed_team) { + exit 1 + } + } +' "$OVERRIDE_SCHEMA" > "$tmp_override_remaining"; then + echo "ERROR: failed to strip definition domain/team blocks from $OVERRIDE_SCHEMA" >&2 + exit 1 +fi + +# Inject explicit override lines into SuperMQ domain and team definitions. +awk \ + -v domain_relations_file="$tmp_overlay_domain_relations" \ + -v team_relations_file="$tmp_overlay_team_relations" \ + -v domain_permissions_file="$tmp_overlay_domain_permissions" \ + -v membership_extension_file="$tmp_overlay_membership_extension" ' + BEGIN { + while ((getline line < domain_relations_file) > 0) { + domain_relations = domain_relations line ORS + } + close(domain_relations_file) + + while ((getline line < team_relations_file) > 0) { + team_relations = team_relations line ORS + } + close(team_relations_file) + + while ((getline line < domain_permissions_file) > 0) { + domain_permissions = domain_permissions line ORS + } + close(domain_permissions_file) + + membership_extension = "" + if ((getline line < membership_extension_file) > 0) { + membership_extension = line + } + close(membership_extension_file) + + in_domain = 0 + in_team = 0 + in_domain_membership = 0 + inserted_domain_relations = 0 + inserted_team_relations = 0 + inserted_domain_permissions = 0 + inserted_domain_membership = 0 + } + { + if ($0 ~ /^definition domain[[:space:]]*{/) { + in_domain = 1 + } else if ($0 ~ /^definition team[[:space:]]*{/) { + in_team = 1 + } + + if (in_domain && $0 ~ /^[[:space:]]*permission membership[[:space:]]*=/) { + in_domain_membership = 1 + } + + if (in_domain && in_domain_membership && $0 ~ /organization->admin[[:space:]]*$/) { + membership_tail = $0 + sub(/[[:space:]]*\+[[:space:]]*organization->admin[[:space:]]*$/, " +", membership_tail) + print membership_tail + print "\t" membership_extension " +" + print "\torganization->admin" + in_domain_membership = 0 + inserted_domain_membership = 1 + next + } + + print $0 + + if (in_domain && $0 ~ /^[[:space:]]*relation group_view_role_users: role#member \| team#member[[:space:]]*$/) { + print "" + print "\t// Magistrala-specific relations" + printf "%s", domain_relations + inserted_domain_relations = 1 + } + + if (in_team && $0 ~ /^[[:space:]]*relation group_view_role_users: role#member \| team#member[[:space:]]*$/) { + print "" + print "\t// Magistrala-specific relations" + printf "%s", team_relations + inserted_team_relations = 1 + } + + if (in_domain && $0 ~ /^[[:space:]]*permission group_view_role_users_permission = group_view_role_users \+ team->group_view_role_users \+ organization->admin[[:space:]]*$/) { + print "" + print "\t// Magistrala-specific permissions" + printf "%s", domain_permissions + inserted_domain_permissions = 1 + } + + if (in_domain && $0 ~ /^}/) { + in_domain = 0 + in_domain_membership = 0 + } else if (in_team && $0 ~ /^}/) { + in_team = 0 + } + } + END { + if (!inserted_domain_relations || !inserted_team_relations || !inserted_domain_permissions || !inserted_domain_membership) { + exit 1 + } + } +' "$tmp_supermq_schema" > "$tmp_supermq_merged" || { + echo "ERROR: failed to merge override schema into SuperMQ schema" >&2 + exit 1 +} + +first_domain_relation=$(awk 'NR == 1 {print $2}' "$tmp_overlay_domain_relations") +first_team_relation=$(awk 'NR == 1 {print $2}' "$tmp_overlay_team_relations") +first_domain_permission=$(awk 'NR == 1 {print $2}' "$tmp_overlay_domain_permissions") + +if [ -z "$first_domain_relation" ] || [ -z "$first_team_relation" ] || [ -z "$first_domain_permission" ]; then + echo "ERROR: failed to verify merged overlay lines" >&2 + exit 1 +fi + +sub_first_domain_relation=${first_domain_relation%%:*} +sub_first_team_relation=${first_team_relation%%:*} + +if ! grep -Fq "relation $sub_first_domain_relation: role#member | team#member" "$tmp_supermq_merged"; then + echo "ERROR: merged schema is missing domain relation $sub_first_domain_relation" >&2 + exit 1 +fi + +if ! grep -Fq "relation $sub_first_team_relation: role#member | team#member" "$tmp_supermq_merged"; then + echo "ERROR: merged schema is missing team relation $sub_first_team_relation" >&2 + exit 1 +fi + +if ! grep -Fq "permission $first_domain_permission" "$tmp_supermq_merged"; then + echo "ERROR: merged schema is missing domain permission $first_domain_permission" >&2 + exit 1 +fi + +membership_extension_value=$(cat "$tmp_overlay_membership_extension") +if ! grep -Fq "$membership_extension_value +" "$tmp_supermq_merged"; then + echo "ERROR: merged schema is missing domain membership_extension values" >&2 + exit 1 +fi + +{ + cat <<'EOF' +// Copyright (c) Abstract Machines +// SPDX-License-Identifier: Apache-2.0 +// Code generated by scripts/combine-schema.sh. DO NOT EDIT. +// +// Combined from: +// - docker/supermq-docker/spicedb/schema.zed +// - docker/spicedb/override-schema.zed + +EOF + cat "$tmp_supermq_merged" "$tmp_override_remaining" +} > "$OUTPUT_SCHEMA" + +echo "Combined schema generated at: $OUTPUT_SCHEMA" diff --git a/scripts/supermq.sh b/scripts/supermq.sh index 36aae47fa..9dcb01a0e 100755 --- a/scripts/supermq.sh +++ b/scripts/supermq.sh @@ -13,7 +13,8 @@ REPO_URL=https://github.com/absmach/supermq TEMP_DIR="supermq" DOCKER_DIR="docker" DOCKER_DST_DIR="../docker" -DEST_DIR="../../docker/supermq-docker" +DEST_DIR="../docker/supermq-docker" +COMBINE_SCHEMA_SCRIPT="./combine-schema.sh" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" || exit 1 @@ -40,3 +41,5 @@ mkdir -p "$DEST_DIR" mv -f "$DOCKER_DIR"/.??* "$DOCKER_DIR"/* "$DEST_DIR"/ cd .. rm -rf "$TEMP_DIR" + +sh "$COMBINE_SCHEMA_SCRIPT"