<@U04UQ68083H> I believe it isn't possible to use ...
# ory-copilot
b
@chilly-king-10285 I believe it isn't possible to use a boolean in the
related
section of a permission model. How can I accomplish something similar to this?
Copy code
class Feature implements Namespace {
  related: {
	// Feature requires entitlement
	entitled: boolean;
    // Users or customer entitled for this Feature
    subscribers: (User | SubjectSet<Customer, "members">)[];
	// Feature requires flag
	flagged: boolean;
	// Feature flag is enabled for these users
	enabled_for: (User | SubjectSet<Customer, "members">)[];
  }
  permits = {
    subscribe: (ctx: Context): boolean => !this.related.entitled || this.related.subscribers.includes(ctx.subject),
	enabled_for: (ctx: Context): boolean => !this.related.flagged || this.related.enabled_for.includes(ctx.subject),
	// Feature flag is enabled AND feature is entitled
	activated_for: (ctx: Context): boolean => this.permits.enabled_for(ctx) && this.permits.subscribe(ctx)
  };
}
b
A message from kapa.ai
You are correct: in Ory Permission Language (OPL), the
related
section can only declare relationships to other namespaces (i.e., arrays of subjects or subject sets), not primitive types like
boolean
. The OPL is designed around expressing relationships between entities, and all relations must be many-to-many and reference other namespaces or subject sets, not simple values or flags [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). To achieve similar logic to a boolean flag, you should model the "entitled" or "flagged" state as a relationship. For example, instead of a boolean
entitled
, you could have a relation like
entitled_for: (User | SubjectSet<Customer, "members">)[]
, and then check if the subject is in that relation. If you want to represent a "global" flag, you could use a special subject (e.g., a "system" user or group) to indicate that the feature is globally enabled. Here’s how you might refactor your model:
Copy code
typescript class Feature implements Namespace {   related: {     // Users or customers entitled for this Feature     entitled_for: (User | SubjectSet<Customer, "members">)[];     // Users or customers for whom the feature flag is enabled     enabled_for: (User | SubjectSet<Customer, "members">)[];   }   permits = {     subscribe: (ctx: Context): boolean =>       this.related.entitled_for.includes(ctx.subject),     enabled_for: (ctx: Context): boolean =>       this.related.enabled_for.includes(ctx.subject),     // Feature flag is enabled AND feature is entitled     activated_for: (ctx: Context): boolean =>       this.permits.enabled_for(ctx) && this.permits.subscribe(ctx),   }; }
If you want to support a "default allow" (i.e., if no one is entitled, then everyone is), you could model this by adding a special subject (like a "public" group) to the relation, or by handling the "empty" case in your application logic, since OPL itself does not support conditional logic based on the presence or absence of relationships [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). In summary: - You cannot use booleans in
related
. - Model flags as relationships to special subjects or groups. - All permission logic must be expressed in terms of relationships and set membership. For more details, see the Ory Permission Language specification and examples [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements) [OPL Examples](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples).
b
@chilly-king-10285 explain what the traverse function does in OPL
b
A message from kapa.ai
In the Ory Permission Language (OPL), the
traverse
function is used to iterate over an array of related objects (such as parents, folders, or other namespaces) and evaluate a permission or condition for each element. It returns
true
if at least one of the elements in the array satisfies the provided condition (i.e., the callback function returns
true
for that element). For example, in the following OPL snippet:
Copy code
typescript class Document implements Namespace {   related: {     parents: Folder[];   };    permits = {     view: (ctx: Context): boolean =>       this.related.parents.traverse((parent) => parent.permits.view(ctx)),   }; }
Here,
this.related.parents.traverse((parent) => parent.permits.view(ctx))
checks if any parent folder grants the
view
permission to the subject in the context. If at least one parent folder allows viewing, the function returns
true
 [OPL Examples](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples). This is similar to the
Array.prototype.some()
method in JavaScript/TypeScript, where the function returns
true
if the callback returns
true
for any element in the array. Summary: -
traverse
iterates over related entities. - Returns
true
if the callback returns
true
for any element. - Commonly used to check permissions up a hierarchy or across related objects [OPL Examples](https://www.ory.sh/docs/keto/reference/ory-permission-language#examples).
b
@chilly-king-10285 the opl documentation says : The
related
section of type declarations defines relations. Unlike regular TypeScript,
RelationName
must be a unique identifier used as the relation strings in the tuples. Does that mean unique to the namespace or unique globally?
b
A message from kapa.ai
In Ory Permission Language (OPL), the requirement that
RelationName
must be a unique identifier refers to uniqueness within the namespace, not globally. Each namespace (represented as a class) defines its own set of relations, and the relation names must be unique within that class. This is supported by the documentation, which states: > The
related
section of type declarations defines relations. Unlike regular TypeScript,
RelationName
must be a unique identifier used as the relation strings in the tuples. The
TypeName
must be the name of another
type
that is defined above or below (in TypeScript: a class that implements
Namespace
) [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language#statements). There is no indication in the documentation that relation names must be unique across all namespaces—only within the context of each namespace's definition.
m
(deleted -wrong thread)
b
A message from kapa.ai
To configure the minimum tuple with the
/admin/relation-tuples
endpoint, you need to provide at least the following fields in the request body:
namespace
,
object
, and
relation
. Additionally, you must specify either
subject_id
or a
subject_set
. This is the minimum required to define a relationship tuple in Ory Keto. Here is an example of the minimal JSON payload for the
/admin/relation-tuples
endpoint:
Copy code
json {   "namespace": "feature",   "object": "my-feature",   "relation": "entitled_for",   "subject_id": "user-alice" }
This tuple states that the subject with ID
user-alice
is entitled for the feature
my-feature
in the
feature
namespace. You can also use a
subject_set
instead of
subject_id
if you want to refer to a group or another set of subjects:
Copy code
json {   "namespace": "feature",   "object": "my-feature",   "relation": "entitled_for",   "subject_set": {     "namespace": "customer",     "object": "customer-123",     "relation": "members"   } }
This tuple states that all members of
customer-123
are entitled for the feature
my-feature
. These examples follow the requirements described in the API reference for the
/admin/relation-tuples
endpoint [Ory Keto API - createRelationship](https://www.ory.sh/docs/keto/reference/rest-api#createrelationship).