mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Zanzana: Use modular schema (#92001)
* Zanzana: Use modular schema * Fix tests * Add module transform tests
This commit is contained in:
parent
dcdef1a02d
commit
87c4f2448c
@ -9,6 +9,7 @@ import (
|
||||
"google.golang.org/protobuf/types/known/wrapperspb"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
"github.com/openfga/language/pkg/go/transformer"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/schema"
|
||||
@ -28,16 +29,16 @@ func WithLogger(logger log.Logger) ClientOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithSchema(dsl string) ClientOption {
|
||||
func WithSchema(modules []transformer.ModuleFile) ClientOption {
|
||||
return func(c *Client) {
|
||||
c.dsl = dsl
|
||||
c.modules = modules
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
logger log.Logger
|
||||
client openfgav1.OpenFGAServiceClient
|
||||
dsl string
|
||||
modules []transformer.ModuleFile
|
||||
tenantID string
|
||||
storeID string
|
||||
modelID string
|
||||
@ -60,8 +61,8 @@ func New(ctx context.Context, cc grpc.ClientConnInterface, opts ...ClientOption)
|
||||
c.tenantID = "stack-default"
|
||||
}
|
||||
|
||||
if c.dsl == "" {
|
||||
c.dsl = schema.DSL
|
||||
if c.modules == nil || len(c.modules) == 0 {
|
||||
c.modules = schema.SchemaModules
|
||||
}
|
||||
|
||||
store, err := c.getOrCreateStore(ctx, c.tenantID)
|
||||
@ -71,7 +72,7 @@ func New(ctx context.Context, cc grpc.ClientConnInterface, opts ...ClientOption)
|
||||
|
||||
c.storeID = store.GetId()
|
||||
|
||||
modelID, err := c.loadModel(ctx, c.storeID, c.dsl)
|
||||
modelID, err := c.loadModel(ctx, c.storeID, c.modules)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -151,9 +152,14 @@ func (c *Client) getStore(ctx context.Context, name string) (*openfgav1.Store, e
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) loadModel(ctx context.Context, storeID string, dsl string) (string, error) {
|
||||
func (c *Client) loadModel(ctx context.Context, storeID string, modules []transformer.ModuleFile) (string, error) {
|
||||
var continuationToken string
|
||||
|
||||
model, err := schema.TransformModulesToModel(modules)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
// ReadAuthorizationModels returns authorization models for a store sorted in descending order of creation.
|
||||
// So with a pageSize of 1 we will get the latest model.
|
||||
@ -167,16 +173,10 @@ func (c *Client) loadModel(ctx context.Context, storeID string, dsl string) (str
|
||||
return "", fmt.Errorf("failed to load authorization model: %w", err)
|
||||
}
|
||||
|
||||
for _, model := range res.GetAuthorizationModels() {
|
||||
// We need to first convert stored model into dsl and compare it to provided dsl.
|
||||
storedDSL, err := schema.TransformToDSL(model)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, m := range res.GetAuthorizationModels() {
|
||||
// If provided dsl is equal to a stored dsl we use that as the authorization id
|
||||
if schema.EqualModels(dsl, storedDSL) {
|
||||
return model.GetId(), nil
|
||||
if schema.EqualModels(m, model) {
|
||||
return m.GetId(), nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,11 +188,6 @@ func (c *Client) loadModel(ctx context.Context, storeID string, dsl string) (str
|
||||
continuationToken = res.GetContinuationToken()
|
||||
}
|
||||
|
||||
model, err := schema.TransformToModel(dsl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
writeRes, err := c.client.WriteAuthorizationModel(ctx, &openfgav1.WriteAuthorizationModelRequest{
|
||||
StoreId: c.storeID,
|
||||
TypeDefinitions: model.GetTypeDefinitions(),
|
||||
|
@ -5,13 +5,15 @@ import (
|
||||
"testing"
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
"github.com/openfga/language/pkg/go/transformer"
|
||||
|
||||
"github.com/fullstorydev/grpchan/inprocgrpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/db"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
zserver "github.com/grafana/grafana/pkg/services/authz/zanzana/server"
|
||||
zstore "github.com/grafana/grafana/pkg/services/authz/zanzana/store"
|
||||
@ -63,12 +65,14 @@ func TestIntegrationClient(t *testing.T) {
|
||||
|
||||
t.Run("should update authorization model if it has new changes", func(t *testing.T) {
|
||||
dsl := `
|
||||
model
|
||||
schema 1.1
|
||||
module core
|
||||
|
||||
type user
|
||||
`
|
||||
c, err := New(context.Background(), conn, WithTenantID("new"), WithSchema(dsl))
|
||||
modules := []transformer.ModuleFile{
|
||||
{Name: "core.fga", Contents: dsl},
|
||||
}
|
||||
c, err := New(context.Background(), conn, WithTenantID("new"), WithSchema(modules))
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, prevStoreID, c.storeID)
|
||||
|
37
pkg/services/authz/zanzana/schema/core.fga
Normal file
37
pkg/services/authz/zanzana/schema/core.fga
Normal file
@ -0,0 +1,37 @@
|
||||
module core
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
|
||||
# team management
|
||||
define team_create: [role#assignee]
|
||||
define team_read: [role#assignee]
|
||||
define team_write: [role#assignee] or team_create
|
||||
define team_delete: [role#assignee] or team_write
|
||||
define team_permissions_write: [role#assignee]
|
||||
define team_permissions_read: [role#assignee] or team_permissions_write
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
|
||||
type team
|
||||
relations
|
||||
define org: [org]
|
||||
define admin: [user]
|
||||
define member: [user] or admin
|
||||
|
||||
define read: [role#assignee] or member or team_read from org
|
||||
define write: [role#assignee] or admin or team_write from org
|
||||
define delete: [role#assignee] or admin or team_delete from org
|
||||
define permissions_read: [role#assignee] or admin or team_permissions_read from org
|
||||
define permissions_write: [role#assignee] or admin or team_permissions_write from org
|
||||
|
34
pkg/services/authz/zanzana/schema/dashboard.fga
Normal file
34
pkg/services/authz/zanzana/schema/dashboard.fga
Normal file
@ -0,0 +1,34 @@
|
||||
module dashboard
|
||||
|
||||
extend type org
|
||||
relations
|
||||
define dashboard_annotations_create: [role#assignee]
|
||||
define dashboard_annotations_read: [role#assignee]
|
||||
define dashboard_annotations_write: [role#assignee]
|
||||
define dashboard_annotations_delete: [role#assignee]
|
||||
define dashboard_create: [role#assignee]
|
||||
define dashboard_delete: [role#assignee]
|
||||
define dashboard_permissions_read: [role#assignee]
|
||||
define dashboard_permissions_write: [role#assignee]
|
||||
define dashboard_public_write: [role#assignee] or dashboard_write
|
||||
define dashboard_read: [role#assignee]
|
||||
define dashboard_write: [role#assignee]
|
||||
|
||||
type dashboard
|
||||
relations
|
||||
define org: [org]
|
||||
define parent: [folder]
|
||||
|
||||
define read: [user, team#member, role#assignee] or dashboard_read from parent or dashboard_read from org
|
||||
define write: [user, team#member, role#assignee] or dashboard_write from parent or dashboard_write from org
|
||||
define delete: [user, team#member, role#assignee] or dashboard_delete from parent or dashboard_delete from org
|
||||
define create: [user, team#member, role#assignee] or dashboard_create from parent or dashboard_create from org
|
||||
define permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from parent or dashboard_permissions_read from org
|
||||
define permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from parent or dashboard_permissions_write from org
|
||||
|
||||
define public_write: [user, team#member, role#assignee] or dashboard_public_write from parent or dashboard_public_write from org or write
|
||||
define annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from parent or dashboard_annotations_create from org
|
||||
define annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from parent or dashboard_annotations_read from org
|
||||
define annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from parent or dashboard_annotations_write from org
|
||||
define annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from parent or dashboard_annotations_delete from org
|
||||
|
62
pkg/services/authz/zanzana/schema/folder.fga
Normal file
62
pkg/services/authz/zanzana/schema/folder.fga
Normal file
@ -0,0 +1,62 @@
|
||||
module folder
|
||||
|
||||
extend type org
|
||||
relations
|
||||
define folder_create: [role#assignee]
|
||||
define folder_read: [role#assignee] or folder_delete
|
||||
define folder_write: [role#assignee] or folder_create
|
||||
define folder_delete: [role#assignee] or folder_write
|
||||
define folder_permissions_write: [role#assignee]
|
||||
define folder_permissions_read: [role#assignee] or folder_permissions_write
|
||||
|
||||
define library_panel_create: [role#assignee]
|
||||
define library_panel_read: [role#assignee] or library_panel_write
|
||||
define library_panel_write: [role#assignee] or library_panel_create
|
||||
define library_panel_delete: [role#assignee] or library_panel_create
|
||||
|
||||
define alert_rule_create: [role#assignee]
|
||||
define alert_rule_read: [role#assignee] or alert_rule_write
|
||||
define alert_rule_write: [role#assignee] or alert_rule_create
|
||||
define alert_rule_delete: [role#assignee] or alert_rule_write
|
||||
define alert_silence_create: [role#assignee]
|
||||
define alert_silence_delete: [role#assignee] or alert_silence_write
|
||||
define alert_silence_read: [role#assignee] or alert_silence_write
|
||||
define alert_silence_write: [role#assignee] or alert_silence_create
|
||||
|
||||
type folder
|
||||
relations
|
||||
define parent: [folder]
|
||||
define org: [org]
|
||||
|
||||
define create: [user, team#member, role#assignee] or create from parent or folder_create from org
|
||||
define read: [user, team#member, role#assignee] or read from parent or folder_read from org
|
||||
define write: [user, team#member, role#assignee] or write from parent or folder_write from org
|
||||
define delete: [user, team#member, role#assignee] or delete from parent or folder_delete from org
|
||||
define permissions_read: [user, team#member, role#assignee] or permissions_read from parent or folder_permissions_read from org
|
||||
define permissions_write: [user, team#member, role#assignee] or permissions_write from parent or folder_permissions_write from org
|
||||
|
||||
define dashboard_create: [user, team#member, role#assignee] or dashboard_create from parent or dashboard_create from org
|
||||
define dashboard_read: [user, team#member, role#assignee] or dashboard_read from parent or dashboard_read from org
|
||||
define dashboard_write: [user, team#member, role#assignee] or dashboard_write from parent or dashboard_write from org
|
||||
define dashboard_delete: [user, team#member, role#assignee] or dashboard_delete from parent or dashboard_delete from org
|
||||
define dashboard_permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from parent or dashboard_permissions_read from org
|
||||
define dashboard_permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from parent or dashboard_permissions_write from org
|
||||
define dashboard_public_write: [user, team#member, role#assignee] or dashboard_public_write from parent or dashboard_public_write from org or dashboard_write
|
||||
define dashboard_annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from parent or dashboard_annotations_create from org
|
||||
define dashboard_annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from parent or dashboard_annotations_read from org
|
||||
define dashboard_annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from parent or dashboard_annotations_write from org
|
||||
define dashboard_annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from parent or dashboard_annotations_delete from org
|
||||
|
||||
define library_panel_create: [user, team#member, role#assignee] or library_panel_create from parent or library_panel_create from org
|
||||
define library_panel_read: [user, team#member, role#assignee] or library_panel_read from parent or library_panel_read from org or library_panel_write
|
||||
define library_panel_write: [user, team#member, role#assignee] or library_panel_write from parent or library_panel_write from org or library_panel_create
|
||||
define library_panel_delete: [user, team#member, role#assignee] or library_panel_delete from parent or library_panel_delete from org or library_panel_create
|
||||
|
||||
define alert_rule_create: [user, team#member, role#assignee] or alert_rule_create from parent or alert_rule_create from org
|
||||
define alert_rule_read: [user, team#member, role#assignee] or alert_rule_read from parent or alert_rule_read from org or alert_rule_write
|
||||
define alert_rule_write: [user, team#member, role#assignee] or alert_rule_write from parent or alert_rule_write from org or alert_rule_create
|
||||
define alert_rule_delete: [user, team#member, role#assignee] or alert_rule_delete from parent or alert_rule_delete from org or alert_rule_write
|
||||
define alert_silence_create: [user, team#member, role#assignee] or alert_silence_create from parent or alert_silence_create from org
|
||||
define alert_silence_read: [user, team#member, role#assignee] or alert_silence_read from parent or alert_silence_read from org or alert_silence_write
|
||||
define alert_silence_write: [user, team#member, role#assignee] or alert_silence_write from parent or alert_silence_write from org or alert_silence_create
|
||||
|
@ -1,126 +0,0 @@
|
||||
model
|
||||
schema 1.1
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
|
||||
# team management
|
||||
define team_create: [role#assignee]
|
||||
define team_read: [role#assignee]
|
||||
define team_write: [role#assignee] or team_create
|
||||
define team_delete: [role#assignee] or team_write
|
||||
define team_permissions_write: [role#assignee]
|
||||
define team_permissions_read: [role#assignee] or team_permissions_write
|
||||
|
||||
define folder_create: [role#assignee]
|
||||
define folder_read: [role#assignee] or folder_delete
|
||||
define folder_write: [role#assignee] or folder_create
|
||||
define folder_delete: [role#assignee] or folder_write
|
||||
define folder_permissions_write: [role#assignee]
|
||||
define folder_permissions_read: [role#assignee] or folder_permissions_write
|
||||
|
||||
define dashboard_annotations_create: [role#assignee]
|
||||
define dashboard_annotations_read: [role#assignee]
|
||||
define dashboard_annotations_write: [role#assignee]
|
||||
define dashboard_annotations_delete: [role#assignee]
|
||||
define dashboard_create: [role#assignee]
|
||||
define dashboard_delete: [role#assignee]
|
||||
define dashboard_permissions_read: [role#assignee]
|
||||
define dashboard_permissions_write: [role#assignee]
|
||||
define dashboard_public_write: [role#assignee] or dashboard_write
|
||||
define dashboard_read: [role#assignee]
|
||||
define dashboard_write: [role#assignee]
|
||||
|
||||
define library_panel_create: [role#assignee]
|
||||
define library_panel_read: [role#assignee] or library_panel_write
|
||||
define library_panel_write: [role#assignee] or library_panel_create
|
||||
define library_panel_delete: [role#assignee] or library_panel_create
|
||||
|
||||
define alert_rule_create: [role#assignee]
|
||||
define alert_rule_read: [role#assignee] or alert_rule_write
|
||||
define alert_rule_write: [role#assignee] or alert_rule_create
|
||||
define alert_rule_delete: [role#assignee] or alert_rule_write
|
||||
define alert_silence_create: [role#assignee]
|
||||
define alert_silence_delete: [role#assignee] or alert_silence_write
|
||||
define alert_silence_read: [role#assignee] or alert_silence_write
|
||||
define alert_silence_write: [role#assignee] or alert_silence_create
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
|
||||
type team
|
||||
relations
|
||||
define org: [org]
|
||||
define admin: [user]
|
||||
define member: [user] or admin
|
||||
|
||||
define read: [role#assignee] or member or team_read from org
|
||||
define write: [role#assignee] or admin or team_write from org
|
||||
define delete: [role#assignee] or admin or team_delete from org
|
||||
define permissions_read: [role#assignee] or admin or team_permissions_read from org
|
||||
define permissions_write: [role#assignee] or admin or team_permissions_write from org
|
||||
|
||||
type folder
|
||||
relations
|
||||
define parent: [folder]
|
||||
define org: [org]
|
||||
|
||||
define create: [user, team#member, role#assignee] or create from parent or folder_create from org
|
||||
define read: [user, team#member, role#assignee] or read from parent or folder_read from org
|
||||
define write: [user, team#member, role#assignee] or write from parent or folder_write from org
|
||||
define delete: [user, team#member, role#assignee] or delete from parent or folder_delete from org
|
||||
define permissions_read: [user, team#member, role#assignee] or permissions_read from parent or folder_permissions_read from org
|
||||
define permissions_write: [user, team#member, role#assignee] or permissions_write from parent or folder_permissions_write from org
|
||||
|
||||
define dashboard_create: [user, team#member, role#assignee] or dashboard_create from parent or dashboard_create from org
|
||||
define dashboard_read: [user, team#member, role#assignee] or dashboard_read from parent or dashboard_read from org
|
||||
define dashboard_write: [user, team#member, role#assignee] or dashboard_write from parent or dashboard_write from org
|
||||
define dashboard_delete: [user, team#member, role#assignee] or dashboard_delete from parent or dashboard_delete from org
|
||||
define dashboard_permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from parent or dashboard_permissions_read from org
|
||||
define dashboard_permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from parent or dashboard_permissions_write from org
|
||||
define dashboard_public_write: [user, team#member, role#assignee] or dashboard_public_write from parent or dashboard_public_write from org or dashboard_write
|
||||
define dashboard_annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from parent or dashboard_annotations_create from org
|
||||
define dashboard_annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from parent or dashboard_annotations_read from org
|
||||
define dashboard_annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from parent or dashboard_annotations_write from org
|
||||
define dashboard_annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from parent or dashboard_annotations_delete from org
|
||||
|
||||
define library_panel_create: [user, team#member, role#assignee] or library_panel_create from parent or library_panel_create from org
|
||||
define library_panel_read: [user, team#member, role#assignee] or library_panel_read from parent or library_panel_read from org or library_panel_write
|
||||
define library_panel_write: [user, team#member, role#assignee] or library_panel_write from parent or library_panel_write from org or library_panel_create
|
||||
define library_panel_delete: [user, team#member, role#assignee] or library_panel_delete from parent or library_panel_delete from org or library_panel_create
|
||||
|
||||
define alert_rule_create: [user, team#member, role#assignee] or alert_rule_create from parent or alert_rule_create from org
|
||||
define alert_rule_read: [user, team#member, role#assignee] or alert_rule_read from parent or alert_rule_read from org or alert_rule_write
|
||||
define alert_rule_write: [user, team#member, role#assignee] or alert_rule_write from parent or alert_rule_write from org or alert_rule_create
|
||||
define alert_rule_delete: [user, team#member, role#assignee] or alert_rule_delete from parent or alert_rule_delete from org or alert_rule_write
|
||||
define alert_silence_create: [user, team#member, role#assignee] or alert_silence_create from parent or alert_silence_create from org
|
||||
define alert_silence_read: [user, team#member, role#assignee] or alert_silence_read from parent or alert_silence_read from org or alert_silence_write
|
||||
define alert_silence_write: [user, team#member, role#assignee] or alert_silence_write from parent or alert_silence_write from org or alert_silence_create
|
||||
|
||||
# Dashboard
|
||||
type dashboard
|
||||
relations
|
||||
define org: [org]
|
||||
define parent: [folder]
|
||||
|
||||
define read: [user, team#member, role#assignee] or dashboard_read from parent or dashboard_read from org
|
||||
define write: [user, team#member, role#assignee] or dashboard_write from parent or dashboard_write from org
|
||||
define delete: [user, team#member, role#assignee] or dashboard_delete from parent or dashboard_delete from org
|
||||
define create: [user, team#member, role#assignee] or dashboard_create from parent or dashboard_create from org
|
||||
define permissions_read: [user, team#member, role#assignee] or dashboard_permissions_read from parent or dashboard_permissions_read from org
|
||||
define permissions_write: [user, team#member, role#assignee] or dashboard_permissions_write from parent or dashboard_permissions_write from org
|
||||
|
||||
define public_write: [user, team#member, role#assignee] or dashboard_public_write from parent or dashboard_public_write from org or write
|
||||
define annotations_create: [user, team#member, role#assignee] or dashboard_annotations_create from parent or dashboard_annotations_create from org
|
||||
define annotations_read: [user, team#member, role#assignee] or dashboard_annotations_read from parent or dashboard_annotations_read from org
|
||||
define annotations_write: [user, team#member, role#assignee] or dashboard_annotations_write from parent or dashboard_annotations_write from org
|
||||
define annotations_delete: [user, team#member, role#assignee] or dashboard_annotations_delete from parent or dashboard_annotations_delete from org
|
@ -2,7 +2,30 @@ package schema
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/openfga/language/pkg/go/transformer"
|
||||
)
|
||||
|
||||
//go:embed schema.fga
|
||||
var DSL string
|
||||
//go:embed core.fga
|
||||
var coreDSL string
|
||||
|
||||
//go:embed dashboard.fga
|
||||
var dashboardDSL string
|
||||
|
||||
//go:embed folder.fga
|
||||
var folderDSL string
|
||||
|
||||
var SchemaModules = []transformer.ModuleFile{
|
||||
{
|
||||
Name: "core.fga",
|
||||
Contents: coreDSL,
|
||||
},
|
||||
{
|
||||
Name: "dashboard.fga",
|
||||
Contents: dashboardDSL,
|
||||
},
|
||||
{
|
||||
Name: "folder.fga",
|
||||
Contents: folderDSL,
|
||||
},
|
||||
}
|
||||
|
@ -6,9 +6,19 @@ import (
|
||||
|
||||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
language "github.com/openfga/language/pkg/go/transformer"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
func TransformToModel(dsl string) (*openfgav1.AuthorizationModel, error) {
|
||||
func TransformModulesToModel(modules []language.ModuleFile) (*openfgav1.AuthorizationModel, error) {
|
||||
parsedAuthModel, err := language.TransformModuleFilesToModel(modules, "1.2")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to transform dsl to model: %w", err)
|
||||
}
|
||||
|
||||
return parsedAuthModel, nil
|
||||
}
|
||||
|
||||
func TransformDSLToModel(dsl string) (*openfgav1.AuthorizationModel, error) {
|
||||
parsedAuthModel, err := language.TransformDSLToProto(dsl)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to transform dsl to model: %w", err)
|
||||
@ -17,27 +27,32 @@ func TransformToModel(dsl string) (*openfgav1.AuthorizationModel, error) {
|
||||
return parsedAuthModel, nil
|
||||
}
|
||||
|
||||
func TransformToDSL(model *openfgav1.AuthorizationModel) (string, error) {
|
||||
return language.TransformJSONProtoToDSL(model)
|
||||
func TransformToDSL(model *openfgav1.AuthorizationModel, opts ...language.TransformOption) (string, error) {
|
||||
return language.TransformJSONProtoToDSL(model, opts...)
|
||||
}
|
||||
|
||||
// FIXME(kalleep): We need to figure out a better way to compare equality of two different
|
||||
// authorization model. For now the easiest way I found to comparing different schemas was
|
||||
// to convert them into their json representation but this requires us to first convert dsl into
|
||||
// openfgav1.AuthorizationModel and then later parse it as json.
|
||||
// Comparing parsed authorization model with authorization model from store directly by parsing them as
|
||||
// as json won't work because stored model will have some fields set such as id that are not present in a parsed
|
||||
// dsl from disk.
|
||||
func EqualModels(a, b string) bool {
|
||||
astr, err := language.TransformDSLToJSON(a)
|
||||
// EqualModels compares two authorization models.
|
||||
// Id is not comparing since model loaded from disk doesn't contain Id.
|
||||
func EqualModels(a, b *openfgav1.AuthorizationModel) bool {
|
||||
aCopy := openfgav1.AuthorizationModel{
|
||||
SchemaVersion: a.SchemaVersion,
|
||||
TypeDefinitions: a.TypeDefinitions,
|
||||
Conditions: a.Conditions,
|
||||
}
|
||||
aJSONBytes, err := protojson.Marshal(&aCopy)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
bstr, err := language.TransformDSLToJSON(b)
|
||||
bCopy := openfgav1.AuthorizationModel{
|
||||
SchemaVersion: b.SchemaVersion,
|
||||
TypeDefinitions: b.TypeDefinitions,
|
||||
Conditions: b.Conditions,
|
||||
}
|
||||
bJSONBytes, err := protojson.Marshal(&bCopy)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return astr == bstr
|
||||
return string(aJSONBytes) == string(bJSONBytes)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package schema
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/openfga/language/pkg/go/transformer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@ -125,7 +126,188 @@ type role
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, EqualModels(tt.a, tt.b))
|
||||
modelA, err := transformer.TransformDSLToProto(tt.a)
|
||||
assert.NoError(t, err)
|
||||
|
||||
modelB, err := transformer.TransformDSLToProto(tt.b)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.expected, EqualModels(modelA, modelB))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestModulesEqualModels(t *testing.T) {
|
||||
type testCase struct {
|
||||
desc string
|
||||
a []transformer.ModuleFile
|
||||
b []transformer.ModuleFile
|
||||
expected bool
|
||||
}
|
||||
|
||||
tests := []testCase{
|
||||
{
|
||||
desc: "should be equal",
|
||||
a: []transformer.ModuleFile{
|
||||
{
|
||||
Name: "core.fga",
|
||||
Contents: `
|
||||
module core
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
define viewer: [user]
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "team.fga",
|
||||
Contents: `
|
||||
module team
|
||||
|
||||
type team
|
||||
relations
|
||||
define org: [org]
|
||||
define admin: [user]
|
||||
define member: [user] or org
|
||||
`,
|
||||
},
|
||||
},
|
||||
b: []transformer.ModuleFile{
|
||||
{
|
||||
Name: "core.fga",
|
||||
Contents: `
|
||||
module core
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
define viewer: [user]
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "team.fga",
|
||||
Contents: `
|
||||
module team
|
||||
|
||||
type team
|
||||
relations
|
||||
define org: [org]
|
||||
define admin: [user]
|
||||
define member: [user] or org
|
||||
`,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
desc: "should not be equal",
|
||||
a: []transformer.ModuleFile{
|
||||
{
|
||||
Name: "core.fga",
|
||||
Contents: `
|
||||
module core
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
define viewer: [user]
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "team.fga",
|
||||
Contents: `
|
||||
module team
|
||||
|
||||
type team
|
||||
relations
|
||||
define org: [org]
|
||||
define admin: [user]
|
||||
define member: [user] or org
|
||||
`,
|
||||
},
|
||||
},
|
||||
b: []transformer.ModuleFile{
|
||||
{
|
||||
Name: "core.fga",
|
||||
Contents: `
|
||||
module core
|
||||
|
||||
type instance
|
||||
|
||||
type user
|
||||
|
||||
type org
|
||||
relations
|
||||
define instance: [instance]
|
||||
define member: [user]
|
||||
define viewer: [user]
|
||||
|
||||
type role
|
||||
relations
|
||||
define org: [org]
|
||||
define instance: [instance]
|
||||
define assignee: [user, team#member, role#assignee]
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "folder.fga",
|
||||
Contents: `
|
||||
module folder
|
||||
|
||||
type folder
|
||||
relations
|
||||
define parent: [folder]
|
||||
define org: [org]
|
||||
`,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.desc, func(t *testing.T) {
|
||||
modelA, err := TransformModulesToModel(tt.a)
|
||||
assert.NoError(t, err)
|
||||
|
||||
modelB, err := TransformModulesToModel(tt.b)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.expected, EqualModels(modelA, modelB))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user