Giter Club home page Giter Club logo

language's Introduction

OpenFGA

Go Reference GitHub release (latest SemVer) Docker Pulls Codecov Go Report CII Best Practices Join our community Twitter FOSSA Status Artifact HUB OpenSSF Scorecard SLSA 3

A high-performance and flexible authorization/permission engine built for developers and inspired by Google Zanzibar.

OpenFGA is designed to make it easy for developers to model their application permissions and add and integrate fine-grained authorization into their applications.

It allows in-memory data storage for quick development, as well as pluggable database modules. It currently supports PostgreSQL 14 and MySQL 8.

It offers an HTTP API and a gRPC API. It has SDKs for Java, Node.js/JavaScript, GoLang, Python and .NET. Look in our Community section for third-party SDKs and tools. It can also be used as a library (see example).

Getting Started

The following section aims to help you get started quickly. Please look at our official documentation for in-depth information.

Setup and Installation

ℹī¸ The following sections setup an OpenFGA server using the default configuration values. These are for rapid development and not for a production environment. Data written to an OpenFGA instance using the default configuration with the memory storage engine will not persist after the service is stopped.

For more information on how to configure the OpenFGA server, please take a look at our official documentation on Running in Production.

Docker

OpenFGA is available on Dockerhub, so you can quickly start it using the in-memory datastore by running the following commands:

docker pull openfga/openfga
docker run -p 8080:8080 -p 3000:3000 openfga/openfga run

Tip

The OPENFGA_HTTP_ADDR environment variable can used to configure the address at which the playground expects the OpenFGA server to be. For example, docker run -e OPENFGA_PLAYGROUND_ENABLED=true -e OPENFGA_HTTP_ADDR=0.0.0.0:4000 -p 4000:4000 -p 3000:3000 openfga/openfga run will start the OpenFGA server on port 4000, and configure the playground too.

Docker Compose

docker-compose.yaml provides an example of how to launch OpenFGA with Postgres using docker compose.

  1. First, either clone this repo or curl the docker-compose.yaml file with the following command:

    curl -LO https://openfga.dev/docker-compose.yaml
  2. Then, run the following command:

    docker compose up

Package Managers

If you are a Homebrew user, you can install OpenFGA with the following command:

brew install openfga

Pre-compiled Binaries

Download your platform's latest release and extract it. Then run the binary with the command:

./openfga run

Building from Source

There are two recommended options for building OpenFGA from source code:

Building from source with go install

Make sure you have Go 1.20 or later installed. See the Go downloads page.

You can install from source using Go modules:

  1. First, make sure $GOBIN is on your shell $PATH:

    export PATH=$PATH:$(go env GOBIN)
  2. Then use the install command:

    go install github.com/openfga/openfga/cmd/openfga
  3. Run the server with:

    ./openfga run

Building from source with go build

Alternatively you can build OpenFGA by cloning the project from this Github repo, and then building it with the go build command:

  1. Clone the repo to a local directory, and navigate to that directory:

    git clone https://github.com/openfga/openfga.git && cd openfga
  2. Then use the build command:

    go build -o ./openfga ./cmd/openfga
  3. Run the server with:

    ./openfga run

Verifying the Installation

Now that you have Set up and Installed OpenFGA, you can test your installation by creating an OpenFGA Store.

curl -X POST 'localhost:8080/stores' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "openfga-demo"
}'

If everything is running correctly, you should get a response with information about the newly created store, for example:

{
  "id": "01G3EMTKQRKJ93PFVDA1SJHWD2",
  "name": "openfga-demo",
  "created_at": "2022-05-19T17:11:12.888680Z",
  "updated_at": "2022-05-19T17:11:12.888680Z"
}

Playground

The Playground facilitates rapid development by allowing you to visualize and model your application's authorization model(s) and manage relationship tuples with a locally running OpenFGA instance.

To run OpenFGA with the Playground disabled, provide the --playground-enabled=false flag.

./openfga run --playground-enabled=false

Once OpenFGA is running, by default, the Playground can be accessed at http://localhost:3000/playground.

In the event that a port other than the default port is required, the --playground-port flag can be set to change it. For example,

./openfga run --playground-enabled --playground-port 3001

Profiler (pprof)

Profiling through pprof can be enabled on the OpenFGA server by providing the --profiler-enabled flag.

./openfga run --profiler-enabled

This will start serving profiling data on port 3001. You can see that data by visiting http://localhost:3001/debug/pprof.

If you need to serve the profiler on a different address, you can do so by specifying the --profiler-addr flag. For example,

./openfga run --profiler-enabled --profiler-addr :3002

Once the OpenFGA server is running, in another window you can run the following command to generate a compressed CPU profile:

go tool pprof -proto -seconds 60 http://localhost:3001/debug/pprof/profile
# will collect data for 60 seconds and generate a file like pprof.samples.cpu.001.pb.gz

That file can be analyzed visually by running the following command and then visiting http://localhost:8084:

go tool pprof -http=localhost:8084 pprof.samples.cpu.001.pb.gz

Next Steps

Take a look at examples of how to:

Don't hesitate to browse the official Documentation, API Reference.

Limitations

MySQL Storage engine

The MySQL storage engine has a lower length limit for some properties of a tuple compared with other storage backends. For more information see the docs.

OpenFGA's MySQL Storage Adapter was contributed to OpenFGA by @twintag. Thanks!

Production Readiness

The core OpenFGA service has been in use by Okta FGA in production since December 2021.

OpenFGA's Memory Storage Adapter was built for development purposes only and is not recommended for a production environment, because it is not designed for scalable queries and has no support for persistence.

You can learn about more organizations using OpenFGA in production here. If your organization is using OpenFGA in production please consider adding it to the list.

The OpenFGA team will do its best to address all production issues with high priority.

Contributing

See CONTRIBUTING.

Community Meetings

We hold a monthly meeting to interact with the community, collaborate and receive/provide feedback. You can find more details, including the time, our agenda, and the meeting minutes here.

language's People

Contributors

aaguiarz avatar adriantam avatar d-jeffery avatar dependabot[bot] avatar evansims avatar ewanharris avatar jimmyjames avatar jpadilla avatar le-yams avatar miparnisari avatar rhamzeh avatar siddhant-k-code avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

language's Issues

Allow using keywords as relation, type and condition names

An example test that would need to work:

For now, we'll keep the following as reserved:

and
or
from
relations
define

as reserved, but allow

model
schema
type
relation
condition
# dsl-syntax-validation-cases.yaml
- name: a valid model with type names doesn't conflict with built-in keywords
  dsl: |
    model
      schema 1.1
    type user
    type model
      relations
        define model: [user]
        define schema: [user]
        define type: [user]
        define relation: [user]
        define condition: [user] or model or schema or type or relation
    type schema
      relations
        define model: [user]
        define schema: [user]
        define type: [user]
        define relation: [user]
        define condition: [user] or model or schema or type or relation
    type type
      relations
        define model: [user]
        define schema: [user]
        define type: [user]
        define relation: [user]
        define condition: [user] or model or schema or type or relation
    type relation
      relations
        define model: [user]
        define schema: [user]
        define type: [user]
        define relation: [user]
        define condition: [user] or model or schema or type or relation
    type condition
      relations
        define model: [user]
        define schema: [user]
        define type: [user]
        define relation: [user]
        define condition: [user] or model or schema or type or relation

DSL Condition Support: Known Issues

The following are the known issues for the current WIP support for conditions in language:

Validation in JS

(Note language does not yet do validations in Go)

  • Condition CEL Expression is not validated
  • Condition Parameters are not validated to be used and usable in the expression
  • Condition CEL Expression is not validated to be not using undefined parameters

Parsing

  • Some valid CEL expressions are not parsed properly
  • } cannot occur in the expression
  • Relation, parameter or type names that conflict with parameter type keywords (map, list, string, etc..) are parsed incorrectly

Expose errors and metadata types

The frontend-utils package currently imports all errors via the dist folder. We don't really want that as we shouldn't encourage importing through dist.

Instead make this exported fully and also ensure that the types are fully up to date (e.g. typeName and relation here)

Unhelpful error message when using rewrites as the base (tupleset) of a `from`

model
  schema 1.1
type user
type org
  relations
    define owner: [user]
    define member: [user]
    define can_add_member: owner
type team
  relations
    define parent: [org]
    define member: [user]
    define can_add_member: can_add_member from parent
type group
  relations
    define parent: [team]
    define org: parent from parent
    define member: [user]
    define can_add_member: can_add_member from org

The language server shows an unhelpful ModelValidationError:

`can_add_member` is an impossible relation for `group` (no entrypoint).

The actual error should inform the user the because group -> org has a rewrite (in this case tuple to userset, but computed usersets or a type restriction with a userset should also fail), it cannot be used as the source of a from (cannot be used as a tupleset).

The actual error message should be discussed.

The API shows a much more helpful message in similar situations:

the 'group#org' relation is referenced in at least one tupleset and thus must be a direct relation
Screenshot 2023-09-20 at 6 40 51 PM

Allow comments to come before the model

On the CLI, we want to allow an output such as:

# Model ID: 01H6BP03XGV3CMJ9VZQBG4NS1C
# Created At: 2023-07-27 12:43:22 +0000 UTC
model
  schema 1.1

type report
  relations
    define approver: can_manage from submitter
    define submitter: [employee]

type employee
  relations
    define can_manage: manager or can_manage from manager
    define manager: [employee]

Right now passing it back to the transformer fails because the grammar does not allow comments to come first

Add Java bindings for the transformer and validator

We currently have bindings to support JS and Golang, with the following features supported in each.

Feature Go JS
Transformer from the DSL to JSON and from JSON to DSL ✅ ✅
Syntactic Model Validations ✅ ✅
Semantic Model Validations ❌ (planned) ✅
Graphing & Utility Methods ❌ (planned) ❌ (planned)

In order to progress in our support for a Jetbrains Plugin, we will need to add Java bindings that handle the same features.

The Java bindings should run against the same set of checks as the other implementations (JS tests, Test Definitions)

The exposed methods should match the ones for JS and Go

  • transformer
    • transformJSONToDSL
    • transformDSLToJSON
  • validator
    • validateDSL
    • validateJSON

Comments interrupting / affecting Model Validation

Example:

model
  schema 1.1
type user
type group
  relations
    define member: [user]
type folder
  relations
    define parent: [folder]
    define viewer: [user,user:*,group#member] or viewer from parent
type document
  relations
# documents live within folders
    define parent: [folder]
    define viewer: [    user,user:*,group#member] or viewer from parent
image

Restructure tests to provide a test suite other parsers can use

We would like to provide a test suite that both us and community parsers can use to validate their parsers.

A proposed solution would look like:

/tests/data/
- v1.0/
  - parser/
    - {case name}.model.json
    - {case name}.model.openfga
  - checker/
    - dsl/ 
      - {case name}.results.json
      - {case name}.model.openfga
    - json/ 
      - {case name}.results.json
      - {case name}.model.json
  - formatter/
    - {case name}.input.json
    - {case name}.output.openfga
- v1.1/
  - parser/
  - checker/
  - formatter/

See Related Discussion

Circular dependency between OpenFGAParser.ts and OpenFGAParserListener.ts

There is a circular dependency between

import OpenFGAParserListener from "./OpenFGAParserListener.js";
and
import { TypeDefsContext } from "./OpenFGAParser";

As a result, using the syntax transformer will result in

OpenFGAParserListener.js:9 Uncaught TypeError: Class extends value undefined is not a constructor or null
    at ./node_modules/@openfga/syntax-transformer/dist/gen/OpenFGAParserListener.js (OpenFGAParserListener.js:9:1)
    at options.factory (react refresh:6:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@openfga/syntax-transformer/dist/transformer/dsltojson.js (dsltojson.js:30:1)
    at options.factory (react refresh:6:1)
    at __webpack_require__ (bootstrap:24:1)
    at fn (hot module replacement:62:1)
    at ./node_modules/@openfga/syntax-transformer/dist/transformer/index.js (index.js:17:1)
    at options.factory (react refresh:6:1)

Add a JSON Schema for what the JSON model should look like and validate against invalid JSON input

See: openfga/openfga#1164

The below model is invalid because the intersection definition in the document#viewer relation is malformed. It’s missing a child: [â€Ļ] nested block.

{
  "schema_version": "1.1",
  "type_definitions": [
    {
        "type": "user"
    },
    {
        "type": "folder",
        "relations": {
            "viewer": {"this": {}},
            "parent": {"this": {}}
        },
        "metadata": {
            "relations": {
                "viewer": {
                    "directly_related_user_types": [{"type": "user"}]
                },
                "parent": {
                    "directly_related_user_types": [{"type": "folder"}]
                }
            }
        }
    },
    {
        "type": "document",
        "relations": {
            "parent": {"this": {}},
            "viewer": {
                "union": {
                    "child": [
                        {
                            "intersection": {
                                "tupleToUserset": {
                                    "tupleset": {
                                        "relation": "parent"
                                    },
                                    "computedUserset": {
                                        "relation": "viewer"
                                    }
                                }
                            }
                        },
                        {"this": {}}
                    ]
                }
            }
        },
        "metadata": {
            "relations": {
                "parent": {
                    "directly_related_user_types": [{"type": "folder", "relation": "parent"}]
                },
                "viewer": {
                    "directly_related_user_types": [{"type": "user"}]
                }
            }
        }
    }
  ]
}

Syntax error on last line reporting empty range from `checkDSL`

One error I'm encountering;

image

If I make an error here like in the attached screenshot (removing a closing bracket on the last line), it reports an invalid range. I get the following error contents;

{
  severity: 8,
  startColumn: 0,
  endColumn: 0,
  startLineNumber: 21,
  endLineNumber: 21,
  message: "Invalid syntax",
  source: "linter",
}

Right line, but 0s on the start & end cols.

Language incorrectly transforms JSON syntax that is not supported in the DSL

For example, the below currently cannot be represented in JSON

{
  "schema_version": "1.1",
  "type_definitions": [
    {
      "type": "user",
      "relations": {}
    },
    {
      "type": "folder",
      "relations": {
        "admin": {
          "this": {}
        },
        "viewer": {
          "this": {}
        },
        "blocked": {
          "this": {}
        },
        "can_view": {
          "union": {
            "child": [
              {
                "computedUserset": {
                  "object": "",
                  "relation": "admin"
                }
              },
              {
                "difference": {
                  "base": {
                    "computedUserset": {
                      "object": "",
                      "relation": "viewer"
                    }
                  },
                  "subtract": {
                    "computedUserset": {
                      "object": "",
                      "relation": "blocked"
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "metadata": {
        "relations": {
          "admin": {
            "directly_related_user_types": [
              {
                "type": "user"
              }
            ]
          },
          "viewer": {
            "directly_related_user_types": [
              {
                "type": "user"
              }
            ]
          },
          "blocked": {
            "directly_related_user_types": [
              {
                "type": "user"
              }
            ]
          },
          "can_view": {
            "directly_related_user_types": []
          }
        }
      }
    }
  ]
}

and the language transforms it to:

model
  schema 1.1

type user

type folder
  relations
    define admin: [user]
    define blocked: [user]
    define can_view: admin or
    define viewer: [user]

Playground authorization model fails

Summary

I used docker compose to spin a container for openfga. In the playground, I copied the example found at https://openfga.dev/docs/modeling/user-groups.

The playground give me this error :

image

By debugging, at discovered that the real error is:

TypeError: Cannot read properties of undefined (reading 'member')
    at b (_app-3f8777cf4f50374e.js:1:559716)
    at _app-3f8777cf4f50374e.js:1:566200
    at Array.forEach (<anonymous>)
    at _app-3f8777cf4f50374e.js:1:566115
    at O (_app-3f8777cf4f50374e.js:1:566418)
    at t.validateDSL (_app-3f8777cf4f50374e.js:1:566784)
    at t.validateDSL (_app-3f8777cf4f50374e.js:1:407940)
    at onChange (_app-3f8777cf4f50374e.js:1:867140)
    at 727.3d4089e0c45544c8.js:1:3895891
    at e.value (727.3d4089e0c45544c8.js:1:943659)

Did I do something wrong when I paste the Authorization Model copied from you documentation ?

Store data

model_file: |
model
  schema 1.1
type user
type document
  relations
    define editor: [team#member]
type team
  relations
    define member: [user]

Other data

Docker compose file : https://openfga.dev/docker-compose.yaml

Issues in validation of fga.mod fields

Schema could alternatively be a number.

} else if (schema !== "1.2") {

Also realized since this is just JSON, i have no range to use for marking which contents in fga.mod when generating errors. The structure is missing line and character values, such that i'd also need to parse the YAML as well to get line numbers.

return yamlDoc.toJSON();

Grammar seems sensitive to characters in comments

The following model will fail to parse in fga model test --tests testfile.yaml

model.fga:

# I can't believe it's not yaml
model
  schema 1.1

type user

testfile.yaml:

model_file: ./model.fga

Error:

Error: error running tests due to failed to transform due to 2 errors occurred:
	* syntax error at line=1, column=7: token recognition error at: '''
	* syntax error at line=1, column=20: token recognition error at: '''

If you remove the comment on model.fga, the test passes.

When transforming a modular model back to DSL, specify module in comments

For example, for the modular model specified here, this will be the combined DSL:

model
  schema 1.2

## module = core; filename = ./core.fga
type user

type organization
  relations
    define member: [user]
    define admin: [user]
    ## extended by: module = confluence; filename = ./confluence.fga
    define can_create_page: member
    ## extended by: module = jira; filename = ./jira/projects.fga
    define can_create_project: member

type group
  relations
    define member: [user]

## module = confluence; filename = ./confluence.fga
type space
  relations
    define organization: [organization] 

type page
  relations
    define space: [space]
    define owner: [user]

## module = jira; filename = ./jira/projects.fga
type project
  relations
    define organization: [organization]

## module = jira; filename = ./jira/tickets.fga
type ticket
  relations
    define project: [project]
    define owner: [user]

Note that ideally the extended relations will be sorted last and by module/filename

Support mixed operators with various direct assignments

We had split supporting the following JSON from #16 to reduce scope as this still needed discussion.

As a suggestion, consider the following three cases:

I-

"relation": {
  "union": {
    "child": [
      {
        "computedUserset": {
          "relation": "rel3"
        }
      },
      {
        "difference": {
          "base": {
            "intersection": {
              "child": [
                {
                  "computedUserset": {
                    "relation": "rel1"
                  }
                },
                {
                  "computedUserset": {
                    "relation": "rel2"
                  }
                }
              ]
            }
          },
          "subtract": {
            "this": {}
          }
        }
      }
    ]
  }
}

II-

"relation": {
  "union": {
    "child": [
      {
        "intersection": {
          "child": [
            {
              "this": {}
            },
            {
              "computedUserset": {
                "relation": "allowed"
              }
            }
          ]
        }
      },
      {
        "difference": {
          "base": {
            "this": {}
          },
          "subtract": {
            "computedUserset": {
              "relation": "blocked"
            }
          }
        }
      }
    ]
  }
}

III-

"relation": {
  "difference": {
    "computedUserset": {
      "relation": "rel1"
    },
    "subtract": {
      "this": {}
    }
  }
}

Note: We should consider rejecting this case (define relation: rel1 but not [user]) as it is nonsensical

Some potential solutions:
A. Allow restating the full type restrictions:
e.g.

  • define relation: rel3 or ((rel1 and rel2) but not [user])
  • define relation: ([user] and allowed) or ([user] but not blocked)
  • define relation: rel1 but not [user]

B. Allow using self
e.g.

  • define relation: [user] | rel3 or ((rel1 and rel2) but not self)
  • define relation: [user] | (self and allowed) or (self but not blocked)
  • define relation: [user] | rel1 but not self

C. Allow using self but require defining it for clarity (we can also have the define as optional)
e.g.

  • define relation: [user] as self | rel3 or ((rel1 and rel2) but not self)
  • define relation: [user] as self | (self and allowed) or (self but not blocked)
  • define relation: [user] as self | rel1 but not self

D. Allow defining an using an arbitrary name in lieu of self (needs an extension to the json to support it)
e.g.

  • define relation: [user] as some_name | rel3 or ((rel1 and rel2) but not some_name)
  • define relation: [user] as some_name | (some_name and allowed) or (some_name but not blocked)
  • define relation: [user] as some_name | rel1 but not some_name

Other questions to consider, does | as a separator make sense?

For other ideas, please post in the comments

Ref: Follow-up on #16

Panic on validating model with comments

[11/09/23 6:36:38] ~/GitHub/cli (main) $ cat /Users/mparnisari/Desktop/demo/model.fga
model
  schema 1.1
type user
type group
  relations
    # groups have users
    define member: [user]
type folder
  relations
    # folders can be nested
    define parent: [folder]
    # if you can view the parent folder, you can view the folder
    define viewer: [user,user:*,group#member] or viewer from parent
type document
  relations
    # documents live within folders
    define parent: [folder]
    # if you can view the parent folder, you can view the document
    define viewer: [user,user:*,group#member] or viewer from parent%
[11/09/23 6:36:40] ~/GitHub/cli (main) $ cat /Users/mparnisari/Desktop/demo/model.json
{
    "type_definitions": [
      {
        "type": "user",
        "relations": {}
      },
      {
        "type": "group",
        "relations": {
          "member": {
            "this": {}
          }
        },
        "metadata": {
          "relations": {
            "member": {
              "directly_related_user_types": [
                {
                  "type": "user"
                }
              ]
            }
          }
        }
      },
      {
        "type": "folder",
        "relations": {
          "parent": {
            "this": {}
          },
          "viewer": {
            "union": {
              "child": [
                {
                  "this": {}
                },
                {
                  "tupleToUserset": {
                    "tupleset": {
                      "object": "",
                      "relation": "parent"
                    },
                    "computedUserset": {
                      "object": "",
                      "relation": "viewer"
                    }
                  }
                }
              ]
            }
          }
        },
        "metadata": {
          "relations": {
            "parent": {
              "directly_related_user_types": [
                {
                  "type": "folder"
                }
              ]
            },
            "viewer": {
              "directly_related_user_types": [
                {
                  "type": "user"
                },
                {
                  "type": "user",
                  "wildcard": {}
                },
                {
                  "type": "group",
                  "relation": "member"
                }
              ]
            }
          }
        }
      },
      {
        "type": "document",
        "relations": {
          "parent": {
            "this": {}
          },
          "viewer": {
            "union": {
              "child": [
                {
                  "this": {}
                },
                {
                  "tupleToUserset": {
                    "tupleset": {
                      "object": "",
                      "relation": "parent"
                    },
                    "computedUserset": {
                      "object": "",
                      "relation": "viewer"
                    }
                  }
                }
              ]
            }
          }
        },
        "metadata": {
          "relations": {
            "parent": {
              "directly_related_user_types": [
                {
                  "type": "folder"
                }
              ]
            },
            "viewer": {
              "directly_related_user_types": [
                {
                  "type": "user"
                },
                {
                  "type": "user",
                  "wildcard": {}
                },
                {
                  "type": "group",
                  "relation": "member"
                }
              ]
            }
          }
        }
      }
    ],
    "schema_version": "1.1"
  }%
[11/09/23 6:36:42] ~/GitHub/cli (main) $ ./dist/fga model validate --file /Users/mparnisari/Desktop/demo/model.json
{
  "is_valid":true
}
[11/09/23 6:36:45] ~/GitHub/cli (main) $ ./dist/fga model validate --file /Users/mparnisari/Desktop/demo/model.fga
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0xb0 pc=0x15ef378]

goroutine 1 [running]:
github.com/openfga/language/pkg/go/transformer.(*openFgaDslListener).ExitRelationDeclaration(0xc00011c680, 0x1aab0e0?)
	/Users/mparnisari/go/pkg/mod/github.com/openfga/language/pkg/[email protected]/transformer/dsltojson.go:77 +0xd8
github.com/openfga/language/pkg/go/gen.(*RelationDeclarationContext).ExitRule(0xc0005e39d0?, {0x1aab0e0?, 0xc00011c680?})
	/Users/mparnisari/go/pkg/mod/github.com/openfga/language/pkg/[email protected]/gen/openfga_parser.go:1705 +0x3f
github.com/antlr4-go/antlr/v4.(*ParseTreeWalker).ExitRule(0xc000420200?, {0x1aab0e0, 0xc00011c680}, {0x4a53b148?, 0xc000420580?})
	/Users/mparnisari/go/pkg/mod/github.com/antlr4-go/antlr/[email protected]/tree.go:241 +0x62
github.com/antlr4-go/antlr/v4.(*ParseTreeWalker).Walk(0xc00011cb80?, {0x1aab0e0, 0xc00011c680}, {0x1aae9a0?, 0xc000420580})
	/Users/mparnisari/go/pkg/mod/github.com/antlr4-go/antlr/[email protected]/tree.go:225 +0x179
github.com/antlr4-go/antlr/v4.(*ParseTreeWalker).Walk(0xc00011c700?, {0x1aab0e0, 0xc00011c680}, {0x1aae9e8?, 0xc000420200})
	/Users/mparnisari/go/pkg/mod/github.com/antlr4-go/antlr/[email protected]/tree.go:223 +0x125
github.com/antlr4-go/antlr/v4.(*ParseTreeWalker).Walk(0x20e6ae0?, {0x1aab0e0, 0xc00011c680}, {0x1aaea30?, 0xc00011cb80})
	/Users/mparnisari/go/pkg/mod/github.com/antlr4-go/antlr/[email protected]/tree.go:223 +0x125
github.com/antlr4-go/antlr/v4.(*ParseTreeWalker).Walk(0xc000078590?, {0x1aab0e0, 0xc00011c680}, {0x1aaeb08?, 0xc00011c700})
	/Users/mparnisari/go/pkg/mod/github.com/antlr4-go/antlr/[email protected]/tree.go:223 +0x125
github.com/openfga/language/pkg/go/transformer.TransformDslToJSON({0xc0002e46c0?, 0x15f5279?})
	/Users/mparnisari/go/pkg/mod/github.com/openfga/language/pkg/[email protected]/transformer/dsltojson.go:236 +0x37e
github.com/openfga/cli/internal/authorizationmodel.(*AuthzModel).ReadFromDSLString(0xc0005e3ca8, {0xc0002e46c0?, 0xc0001443c0?})
	/Users/mparnisari/GitHub/cli/internal/authorizationmodel/model.go:145 +0x27
github.com/openfga/cli/cmd/model.glob..func5(0xc00057e500?, {0xc0001443c0?, 0x4?, 0x197028c?})
	/Users/mparnisari/GitHub/cli/cmd/model/validate.go:115 +0xbb
github.com/spf13/cobra.(*Command).execute(0x20d5760, {0xc0001443a0, 0x2, 0x2})
	/Users/mparnisari/go/pkg/mod/github.com/spf13/[email protected]/command.go:940 +0x87c
github.com/spf13/cobra.(*Command).ExecuteC(0x20d4060)
	/Users/mparnisari/go/pkg/mod/github.com/spf13/[email protected]/command.go:1068 +0x3a5
github.com/spf13/cobra.(*Command).Execute(...)
	/Users/mparnisari/go/pkg/mod/github.com/spf13/[email protected]/command.go:992
github.com/openfga/cli/cmd.Execute()
	/Users/mparnisari/GitHub/cli/cmd/root.go:47 +0x1a
main.main()
	/Users/mparnisari/GitHub/cli/main.go:21 +0xf
[11/09/23 6:36:48] ~/GitHub/cli (main) $

Language is validating against valid cases where `this` is not in first place

In the below case, Language should not treat it as unsupported by DSL, and should allow it

- name: relation def where this is not in first place
  json: >-2
    {
      "schema_version": "1.1",
      "type_definitions": [
        {
          "type": "user",
          "relations": {
            "rel1": {
              "this": {}
            },
            "rel2": {
              "union": {
                "child": [
                  {
                    "computedUserset": {
                      "relation": "rel1"
                    }
                  },
                  {
                    "this": {}
                  }
                ]
              }
            }
          },
          "metadata": {
            "relations": {
              "rel1": {
                "directly_related_user_types": [
                  {
                    "type": "user"
                  }
                ]
              },
              "rel2": {
                "directly_related_user_types": [
                  {
                    "type": "user"
                  }
                ]
              }
            }
          }
        }
      ]
    }
  valid: true

feat: support nested userset rewrite operands in the DSL

The DSL today does not support nested userset rewrite operands and/or compound expressions delineated by parenthetical expressions. The DSL language should be extended to support compound expressions with parenthetical expressions so that it supports the same expressiveness of the JSON support existing today.

Below are some examples of the unsupported functionality.

# sample1
type document
  relations
    define restricted as self
    define editor as self
    define viewer as editor or (self but not restricted)
# sample2
type document
  relations
    define restricted as self
    define parent as self
    define editor as self
    define (viewer but not restricted) or (editor and viewer from parent)

These same models are supported in the JSON structure today, for example:

# sample 1
{
  "type_definitions": [
    {
      "type": "document",
      "relations": {
        "restricted": { "this": {} },
        "editor": { "this": {} },
        "viewer": {
          "union": {
            "child": [
              { "computedUserset": { "object": "", "relation": "editor" } },
              {
                "union": {
                    "child": [
                        { "this": {} },
                        {
                            "difference": {
                                "base": {
                                    "this": {} 
                                },
                                "subtract": {
                                    "object": "",
                                    "relation": "restricted"
                                }
                            }
                        }
                    ]
                }
              }
            ]
          }
        }
      }
    }
  ]
}
# sample2
{
  "type_definitions": [
    {
      "type": "document",
      "relations": {
        "parent": { "this": {} },
        "restricted": { "this": {} },
        "editor": { "this": {} },
        "viewer": {
          "union": {
            "child": [
              {
                "difference": {
                    "base": {
                        "this": {} 
                    },
                    "subtract": {
                        "object": "",
                        "relation": "restricted"
                    }
                }
              },
              {
                "intersection": {
                    "child": [
                        {
                            "computedUserset": {
                                "object": "",
                                "relation": "editor"
                            }
                        },
                        {
                            "tupleToUserset": {
                                "tupleset": {
                                    "object": "",
                                    "relation": "parent"
                                },
                                "computedUserset": {
                                    "object": "",
                                    "relation": "viewer"
                                }
                            }
                        }
                    ]
                }
              }
            ]
          }
        }
      }
    }
  ]
}

Map errors raised by `validateJSON` back to their original source files

When we run the fully combined model through validateJSON currently the errors have no metadata associated with them that would allow us to (or at least easily) look up the line and column information associated with the error.

When we raise a validation error we should include the new file and module metadata fields so that we can improve the error reporting for these errors. Then in the catch for validateJSON we can lookup the file contents and get line/column data to improve these errors.

Support nested userset rewrite operands in the DSL in the Go bindings

Related to #16

Currently the Go bindings do not properly support mixed operators. Work has happened in #107 to add the bindings to JS

The following will result in incorrect JSON

Tests for these cases are already in place and the Go implementation fails on them

 define relation: (rel1 and rel2) but not rel3
 define relation: ((rel1 and rel2) but not rel3) # transformation back to DSL will not keep the extraneous surrounding brackets
 define relation: rel1 and (rel2 but not rel3)
 define relation: rel1 and ((rel2 but not rel3) or (rel4 and (rel5 but not rel6 from rel7)))
 define relation: [user, user:*, user#follower with condition] or ((rel1 and rel2) but not rel3)
 define relation: ([user] or ((rel1 and rel2)) but not rel3 

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤ī¸ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.