diff --git a/fgax/checks.go b/fgax/checks.go index 6ea39cb..c26fa70 100644 --- a/fgax/checks.go +++ b/fgax/checks.go @@ -74,9 +74,18 @@ func (c *Client) BatchCheckObjectAccess(ctx context.Context, checks []AccessChec return nil, err } + if check == nil { + continue + } + ctxTuples := getContextualTuples(opts...) if len(ctxTuples) > 0 { check.ContextualTuples = append(check.ContextualTuples, ctxTuples...) + } else if !hasParentContextualTuple(*check) { + parentContextualTuple := c.getParentContextualTuple(ctx, check.Object) + if parentContextualTuple != nil { + check.ContextualTuples = append(check.ContextualTuples, *parentContextualTuple) + } } checkRequests = append(checkRequests, *check) @@ -329,7 +338,7 @@ func hasParentContextualTuple[T ofgaclient.ClientBatchCheckItem | ofgaclient.Cli // getParentContextualTuple returns a parent context tuple if the organization ID is available in the context. User in the check will always be the `organization:ulid-of-organization` func (c *Client) getParentContextualTuple(ctx context.Context, object string) *ofgaclient.ClientTupleKey { - if c.DisableParentContext { + if !c.EnableParentContext { return nil } diff --git a/fgax/checks_test.go b/fgax/checks_test.go index a2a04a8..df542d1 100644 --- a/fgax/checks_test.go +++ b/fgax/checks_test.go @@ -718,6 +718,7 @@ func TestGetParentContextualTuple(t *testing.T) { "user": {}, "system": {}, }, + EnableParentContext: true, } for _, tc := range tests { diff --git a/fgax/fga.go b/fgax/fga.go index f51ec02..ff276e6 100644 --- a/fgax/fga.go +++ b/fgax/fga.go @@ -22,8 +22,8 @@ type Client struct { ParentContextConditions map[string]openfga.RelationshipCondition // ParentContextSkipKinds is an additional set of entity kind names that should not have parent context tuples added ParentContextSkipKinds map[string]struct{} - // DisableParentContext disables the automatic addition of parent context tuples entirely - DisableParentContext bool + // EnableParentContext disables the automatic addition of parent context tuples entirely + EnableParentContext bool } // Config configures the openFGA setup @@ -48,8 +48,8 @@ type Config struct { Credentials Credentials `json:"credentials" koanf:"credentials" jsonschema:"description=credentials for the openFGA client"` // MaxBatchWriteSize is the maximum number of writes per batch in a transaction, default 100 MaxBatchWriteSize int `json:"maxbatchwritesize" koanf:"maxbatchwritesize" jsonschema:"description=maximum number of writes per batch in a transaction, defaults to 100" default:"100"` - // DisableParentContext disables the automatic addition of parent context tuples entirely - DisableParentContext bool `json:"disableparentcontext" koanf:"disableparentcontext" jsonschema:"description=disables the automatic addition of parent context tuples" default:"false"` + // EnabledParentContext disables the automatic addition of parent context tuples entirely + EnabledParentContext bool `json:"enableparentcontext" koanf:"enableparentcontext" jsonschema:"description=disables the automatic addition of parent context tuples"` // ParentContextSkipKinds is a list of entity kind names that should not have parent context tuples added ParentContextSkipKinds []string `json:"parentcontextskipkinds" koanf:"parentcontextskipkinds" jsonschema:"description=entity kind names that should not have parent context tuples added"` // ParentContextConditions defines relationship conditions to apply on parent context tuples per entity kind @@ -159,10 +159,10 @@ func WithClientCredentials(clientID, clientSecret, aud, issuer, scopes string) O } } -// WithDisableParentContext disables the automatic addition of parent context tuples for all checks -func WithDisableParentContext() Option { +// WithParentContext enables the automatic addition of parent context tuples for all checks +func WithParentContext() Option { return func(c *Client) { - c.DisableParentContext = true + c.EnableParentContext = true } } @@ -272,8 +272,8 @@ func CreateFGAClientWithStore(ctx context.Context, c Config) (*Client, error) { WithAuthorizationModelID(c.ModelID), ) - if c.DisableParentContext { - opts = append(opts, WithDisableParentContext()) + if c.EnabledParentContext { + opts = append(opts, WithParentContext()) } if len(c.ParentContextSkipKinds) > 0 { diff --git a/fgax/testutils/container.go b/fgax/testutils/container.go index b2457dc..0a48aec 100644 --- a/fgax/testutils/container.go +++ b/fgax/testutils/container.go @@ -37,8 +37,8 @@ type OpenFGATestFixture struct { cpu int64 // envVars is a map of environment variables to set in the container envVars map[string]string - // disableParentContext will disable adding the parent context to fga checks - disableParentContext bool + // enableParentContext will disable adding the parent context to fga checks + enableParentContext bool // parentSkipKinds are the entity kinds that should skip adding the parent context tuple parentSkipKinds []string // parentContextConditions are entity kinds and and conditions to set on the parent context tuple @@ -108,10 +108,10 @@ func WithEnvVars(envVars map[string]string) Option { } } -// WithDisableParentContext disable the parent context entirely -func WithDisableParentContext() Option { +// WithParentContext enables the parent context entirely +func WithParentContext() Option { return func(c *OpenFGATestFixture) { - c.disableParentContext = true + c.enableParentContext = true } } @@ -179,8 +179,8 @@ func (o *OpenFGATestFixture) NewFgaClient(ctx context.Context) (*fgax.Client, er HostURL: host, ModelFile: o.modelFile, ModuleFile: o.moduleFile, - DisableParentContext: o.disableParentContext, - ParentContextSkipKinds: o.parentSkipKinds, + EnabledParentContext: o.enableParentContext, + ParentContextSkipKinds: o.parentSkipKinds, ParentContextConditions: o.parentContextConditions, } diff --git a/fgax/tuples.go b/fgax/tuples.go index a044c94..6d8042d 100644 --- a/fgax/tuples.go +++ b/fgax/tuples.go @@ -29,6 +29,8 @@ const ( AuditorRelation = "auditor" // CollaboratorRelation is the relation for collaborators of an entity CollaboratorRelation = "collaborator" + // FullAccessRelation is the relation for owners and super_admins that have access to everything by default + FullAccessRelation = "full_access" // Wildcard allows for public access (any subject) // see: https://openfga.dev/docs/modeling/public-access @@ -45,7 +47,7 @@ const ( BlockedRelation = "blocked" // ViewerRelation is the relation to assign viewers to an entity ViewerRelation = "viewer" - // ParentContextRelation is the relation for parents of an entity that are only used for contextual checks, this is used for organization context + // ParentContextRelation is the relation for parents of an entity that are only used for parent organization context ParentContextRelation = "parent_context" // AssigneeRelation is the relation for assignee of an entity