Possible bug in FGA schema checks :thread:
# ask-a-descoper
m
Possible bug in FGA schema checks 🧵
d
Hi, I'm Descope's AI assistant. I've put together an initial response below based on your question. A member of the support team will take over and follow up shortly. Troubleshooting Information To help troubleshoot the issue you're experiencing with FGA schema checks, I need more details about the following: • The specific behavior you're seeing. • The schema definition you're using. • The relations and checks involved. • Any error messages you may have encountered. Immediate Assistance For immediate assistance with potential bugs, you can visit Support. Other Questions If you have questions about Descope's authentication, user management, or security features, I'd be happy to help with those.
m
Including a cut down of the relevant parts from the schema (this is cut down massively from the actual schema):
Copy code
type decision
  permission view: // big list of things that might allow view

type delegation
  permission view: // big list of things that might allow view

type document
  relation linked: decision | delegation
  permission view: linked.view
Users get linked to have a view permission through multiple sources. Documents can be linked to delegations OR decisions. However we have the following two scenarios: 1. User has view permissions on a decision with linked document = user can view document check passes. 2. User has view permissions on a delegation with linked document - user can view document check passes. However, if I go into the FGA schema and change to this:
Copy code
type document
  relation linked: delegation
So removing the OR on the relationship, then check 2 also passes. I am wondering if this has something to do with the permissions on both being set to view or something. We do use ORs throughout the schema but it is often with differnt relations or permissions on the related item. Obviously happy to provide more details, projects, sample IDs to test on it etc if required. Thanks! cc @Kenneth Knoll @Vivek Sharma @Reshma
n
Hey @Mike Hudson, thanks for reaching out. I'll look into this and let you know the recommended path as soon as possible.
Thanks for the detailed writeup and the schema snippet! There are a couple of things I would like to confirm on your end: • Can you confirm the schema change was saved and is active? If you load the current schema via API or check the FGA console, you should see only the
relation linked: delegation
. This makes sure we're not dealing with a cached or stale schema. • Are you using the FGA Cache service? If so, schema changes should trigger a cache purge, but we'd like to rule it out. You can test by pointing your check calls directly at the Descope API (not the cache proxy) and see if results change. • Does your
decision
type have any permissions that
delegation
does not? If so, try checking one of those decision-only permissions via
document -> linked.<decision-only-permission>
with the narrowed schema. If that check still passes, it would confirm that the engine is traversing the linked target based on stored tuples, ignoring the type constraint in the schema.
v
@Nick Rodriguez To answer your second question regarding whether we are using FGA cache: no, we are not currently using it. Other points can be addressed by @Mike Hudson
m
hi @Nick Rodriguez - thank you for you assistance Yes im modifying the schema and saving it in the descope console and then using a management key and going direct to the descope api for requests. Let me run over my current tests for clarity then I will move on to additional permissions. Test code example:
Copy code
console.log('CAN USER VIEW DELEGATION');
        const canUserViewDelegation = await descopeClient.management.fga.check([{
            resource: delegationId,
            resourceType: 'delegation',
            relation: 'view',
            target: userId,
            targetType: 'user'
        }]);
        console.log(canUserViewDelegation.data);

        console.log('IS DOCUMENT LINKED TO DELEGATION');
        const isDocumentLinkedToDelegation = await descopeClient.management.fga.check([{
            resource: documentId,
            resourceType: 'document',
            relation: 'linked',
            target: delegationId,
            targetType: 'delegation'
        }]);
        console.log(isDocumentLinkedToDelegation.data);

        console.log('CAN USER VIEW DOCUMENT');
        const canUserViewDocument = await descopeClient.management.fga.check([{
            resource: documentId,
            resourceType: 'document',
            relation: 'view',
            target: userId,
            targetType: 'user'
        }]);
        console.log(canUserViewDocument.data);
Schema says:
Copy code
type document
  relation linked: decision | delegation
  permission view: linked.view
Result is:
Copy code
CAN USER VIEW DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      resourceType: 'delegation',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
IS DOCUMENT LINKED TO DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'linked',
      target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
CAN USER VIEW DOCUMENT
[
  {
    allowed: false,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: false, path: null }
  }
]
Remove the decision from the relation:
Copy code
type document
  relation linked: delegation
Retest:
Copy code
CAN USER VIEW DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      resourceType: 'delegation',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
IS DOCUMENT LINKED TO DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'linked',
      target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
CAN USER VIEW DOCUMENT
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: false, path: null }
  }
]
Now the user can view the document! Change the relation so decision after the OR instead of before:
Copy code
type document
  relation linked: delegation | decision
Rerun test:
Copy code
CAN USER VIEW DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      resourceType: 'delegation',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
IS DOCUMENT LINKED TO DELEGATION
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'linked',
      target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
      targetType: 'none'
    },
    info: { direct: true, path: null }
  }
]
CAN USER VIEW DOCUMENT
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: false, path: null }
  }
]
User can still view document If i put it back to
Copy code
relation linked: decision | delegation
Then the CAN USER VIEW DOCUMENT check again returns false.
So onto testing something more aligned with your proposal i added the following:
Copy code
type delegation
  permission test_permission: view
Just copying the view permission to another name so it is unique And modifying the document schema to use this new unique permission name instead
Copy code
type document
  relation linked: decision | delegation
  permission view: linked.test_permission
And yes - using a unqiue permission name does return the right result (that the user can view the document)
Copy code
CAN USER VIEW DOCUMENT
[
  {
    allowed: true,
    tuple: {
      resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
      resourceType: 'document',
      relation: 'view',
      target: 'eeddfe9f-de27-47bc-b250-3233902f51ce',
      targetType: 'none'
    },
    info: { direct: false, path: null }
  }
]
So in final testing I played around with the permission check on document for other variations:
Copy code
permission view: linked.view | linked.test_permission
OR
Copy code
permission view: linked.test_permission
User can view document
Copy code
permission view: linked.view
User cannot view document So the assumption it is to do with a shared permission name between the two object types is correct.
Final mention just so this is also clear. Doing a relations dump on the document id shows this:
Copy code
RELATIONS DUMP 179de61c-aa60-46e5-aad2-5db826cc8633
[
  {
    resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
    relationDefinition: 'owner',
    namespace: 'document',
    target: 'aefead67-e89b-41c6-ab58-3ebe9efe6b59',
    targetNamespace: 'user',
    targetSetResource: '',
    targetSetRelationDefinition: '',
    targetSetRelationDefinitionNamespace: '',
    query: null
  },
  {
    resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
    relationDefinition: 'parent_tenant',
    namespace: 'document',
    target: '101e1754-969d-4d65-b42e-e02742243be2',
    targetNamespace: 'tenant',
    targetSetResource: '',
    targetSetRelationDefinition: '',
    targetSetRelationDefinitionNamespace: '',
    query: null
  },
  {
    resource: '179de61c-aa60-46e5-aad2-5db826cc8633',
    relationDefinition: 'linked',
    namespace: 'document',
    target: '8e0c637e-fc14-4a79-a4ba-5de9beef0acf',
    targetNamespace: 'delegation',
    targetSetResource: '',
    targetSetRelationDefinition: '',
    targetSetRelationDefinitionNamespace: '',
    query: null
  }
]
So at this point in time this document is not linked to any decisions, only delegations @Vivek Sharma - For your testing me messing with the schema may have removed document links you had to decisions. Apologies! With this information in hand I have changed the schema such that the permission checks should now pass in our use case by modifying the check on document to:
Copy code
permission view: linked.view | linked.view_parent_decision
So this should at least allow us to validate correct behaviour now on both object types
✅ 1
v
@Mike Hudson Great! 😃