Skip to content

Commit

Permalink
feat: support modular models (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
ewanharris committed Mar 28, 2024
2 parents 9598153 + 520d2c8 commit 7e4603b
Show file tree
Hide file tree
Showing 27 changed files with 217 additions and 101 deletions.
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ linters-settings:
- google.golang.org/protobuf/encoding/protojson
- google.golang.org/protobuf/types/known/structpb
- gopkg.in/yaml.v3
- github.com/hashicorp/go-multierror
- github.com/gocarina/gocsv
test:
files:
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# Changelog

## v0.3.0-beta.1

### [0.3.0-beta.1](https://github.com/openfga/cli/compare/v0.2.6...v0.3.0-beta.1) (2024-03-13)

Added:
- Support for [modular models](https://github.com/openfga/rfcs/blob/main/20231212-modular-models.md) ([#262](https://github.com/openfga/cli/issues/262))

## v0.2.7

### [0.2.7](https://github.com/openfga/cli/compare/v0.2.6...v0.2.7) (2024-04-27)
### [0.2.7](https://github.com/openfga/cli/compare/v0.2.6...v0.2.7) (2024-03-13)

Added:
- Support for exporting tuples as CSV (#250) - thanks @edwin-Marrima
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ fga store **create**

###### Parameters
* `--name`: Name of the store to be created. If the `model` parameter is specified, the model file name will be used as the default store name.
* `--model`: File with the authorization model. Can be in JSON or OpenFGA format (optional).
* `--format` : Authorization model input format. Can be "fga" or "json" (optional, defaults to the model file extension if present).
* `--model`: File with the authorization model. Can be in JSON, OpenFGA format, or fga.mod file (optional).
* `--format` : Authorization model input format. Can be "fga", "json", or "modular" (optional, defaults to the model file extension if present).

###### Example
`fga store create --name "FGA Demo Store"`
Expand Down Expand Up @@ -352,7 +352,7 @@ fga model **write**
###### Parameters
* `--store-id`: Specifies the store id
* `--file`: File containing the authorization model.
* `--format`: Authorization model input format. Can be "fga" or "json". Defaults to the file extension if provided (optional)
* `--format`: Authorization model input format. Can be "fga", "json", or "modular". Defaults to the file extension if provided (optional)
###### Example
* `fga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 --file model.fga`
Expand Down Expand Up @@ -423,7 +423,7 @@ fga model **validate**
###### Parameters
* `--file`: File containing the authorization model.
* `--format`: Authorization model input format. Can be "fga" or "json". Defaults to the file extension if provided (optional)
* `--format`: Authorization model input format. Can be "fga", "json", or "modular". Defaults to the file extension if provided (optional)
###### Example
`fga model validate --file model.json`
Expand Down Expand Up @@ -555,7 +555,7 @@ fga model **transform**
###### Parameters
* `--file`: File containing the authorization model
* `--input-format`: Authorization model input format. Can be "fga" or "json". Defaults to the file extension if provided (optional)
* `--input-format`: Authorization model input format. Can be "fga", "json", or "modular". Defaults to the file extension if provided (optional)
###### Example
`fga model transform --file model.json`
Expand Down
2 changes: 1 addition & 1 deletion cmd/model/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ var getCmd = &cobra.Command{
}

if getOutputFormat == authorizationmodel.ModelFormatJSON {
return output.Display(authModel.DisplayAsJSON(fields)) //nolint:wrapcheck
return output.Display(authModel.DisplayAsJSON(fields))
}

dslModel, err := authModel.DisplayAsDSL(fields)
Expand Down
2 changes: 1 addition & 1 deletion cmd/model/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ var listCmd = &cobra.Command{
models.AuthorizationModels = append(models.AuthorizationModels, authModel.DisplayAsJSON(fields))
}

return output.Display(models) //nolint:wrapcheck
return output.Display(models)
},
}

Expand Down
12 changes: 7 additions & 5 deletions cmd/model/transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ var transformCmd = &cobra.Command{
Short: "Transforms an authorization model",
Example: `fga model transform --file=model.json
fga model transform --file=model.fga
fga model transform '{ "schema_version": "1.1", "type_definitions":[{"type":"user"}] }' --input-format json`,
fga model transform '{ "schema_version": "1.1", "type_definitions":[{"type":"user"}] }' --input-format json
fga model transform --file=fga.mod`,

Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -53,7 +54,8 @@ fga model transform '{ "schema_version": "1.1", "type_definitions":[{"type":"use
return err //nolint:wrapcheck
}

if transformInputFormat == authorizationmodel.ModelFormatJSON {
if transformInputFormat == authorizationmodel.ModelFormatJSON ||
transformInputFormat == authorizationmodel.ModelFormatModular {
dslModel, err := authModel.DisplayAsDSL([]string{"model"})
if err != nil {
return fmt.Errorf("failed to transform model due to %w", err)
Expand All @@ -67,13 +69,13 @@ fga model transform '{ "schema_version": "1.1", "type_definitions":[{"type":"use
return err //nolint:wrapcheck
}

return output.Display(authModel.DisplayAsJSON([]string{"model"})) //nolint:wrapcheck
return output.Display(authModel.DisplayAsJSON([]string{"model"}))
},
}

var transformInputFormat = authorizationmodel.ModelFormatDefault

func init() {
transformCmd.Flags().String("file", "", "File Name. The file should have the model in the JSON or DSL format")
transformCmd.Flags().Var(&transformInputFormat, "input-format", `Authorization model input format. Can be "fga" or "json"`) //nolint:lll
transformCmd.Flags().String("file", "", "File Name. The file should have the model in the JSON or DSL format or be an `fga.mod` format") //nolint:lll
transformCmd.Flags().Var(&transformInputFormat, "input-format", `Authorization model input format. Can be "fga", "json", or "modular"`) //nolint:lll
}
14 changes: 4 additions & 10 deletions cmd/model/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,21 @@ var validateCmd = &cobra.Command{
}

authModel := authorizationmodel.AuthzModel{}
var err error

if validateInputFormat == authorizationmodel.ModelFormatJSON {
err = authModel.ReadFromJSONString(inputModel)
} else {
err = authModel.ReadFromDSLString(inputModel)
}

err := authModel.ReadModelFromString(inputModel, validateInputFormat)
if err != nil {
return err //nolint:wrapcheck
}

response := validate(authModel)

return output.Display(response) //nolint:wrapcheck
return output.Display(response)
},
}

var validateInputFormat = authorizationmodel.ModelFormatDefault

func init() {
validateCmd.Flags().String("file", "", "File Name. The file should have the model in the JSON or DSL format")
validateCmd.Flags().Var(&validateInputFormat, "format", `Authorization model input format. Can be "fga" or "json"`)
validateCmd.Flags().String("file", "", "File Name. The file should have the model in the JSON or DSL format or be an fga.mod file") //nolint:lll
validateCmd.Flags().Var(&validateInputFormat, "format", `Authorization model input format. Can be "fga", "json", or "modular"`) //nolint:lll
}
9 changes: 2 additions & 7 deletions cmd/model/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,7 @@ fga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 '{"type_definitions":[{"ty

authModel := authorizationmodel.AuthzModel{}

if writeInputFormat == authorizationmodel.ModelFormatJSON {
err = authModel.ReadFromJSONString(inputModel)
} else {
err = authModel.ReadFromDSLString(inputModel)
}

err = authModel.ReadModelFromString(inputModel, writeInputFormat)
if err != nil {
return err //nolint:wrapcheck
}
Expand All @@ -93,7 +88,7 @@ fga model write --store-id=01H0H015178Y2V4CX10C2KGHF4 '{"type_definitions":[{"ty
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/query/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ var checkCmd = &cobra.Command{
return fmt.Errorf("failed to check due to %w", err)
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/query/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ var expandCmd = &cobra.Command{
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/query/list-objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ var listObjectsCmd = &cobra.Command{
return fmt.Errorf("failed to list objects due to %w", err)
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/query/list-relations.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ var listRelationsCmd = &cobra.Command{
return fmt.Errorf("failed to list relations due to %w", err)
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
10 changes: 3 additions & 7 deletions cmd/store/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,8 @@ func CreateStoreWithModel(

if inputModel != "" {
authModel := authorizationmodel.AuthzModel{}
if inputFormat == authorizationmodel.ModelFormatJSON {
err = authModel.ReadFromJSONString(inputModel)
} else {
err = authModel.ReadFromDSLString(inputModel)
}

err = authModel.ReadModelFromString(inputModel, inputFormat)
if err != nil {
return nil, err //nolint:wrapcheck
}
Expand Down Expand Up @@ -127,7 +123,7 @@ export FGA_STORE_ID=$(fga store create --model Model.fga | jq -r .store.id)
return err
}

return output.Display(response) //nolint:wrapcheck
return output.Display(response)
},
}

Expand All @@ -136,5 +132,5 @@ var createModelInputFormat = authorizationmodel.ModelFormatDefault
func init() {
createCmd.Flags().String("name", "", "Store Name")
createCmd.Flags().String("model", "", "Authorization Model File Name")
createCmd.Flags().Var(&createModelInputFormat, "format", `Authorization model input format. Can be "fga" or "json"`)
createCmd.Flags().Var(&createModelInputFormat, "format", `Authorization model input format. Can be "fga", "json" or "modular`) //nolint:lll
}
4 changes: 2 additions & 2 deletions cmd/store/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var deleteCmd = &cobra.Command{
Message string
}

return output.Display(returnMessage{Message: "Delete store cancelled"}) //nolint:wrapcheck
return output.Display(returnMessage{Message: "Delete store cancelled"})
}
}

Expand All @@ -64,7 +64,7 @@ var deleteCmd = &cobra.Command{
return fmt.Errorf("failed to delete store %v due to %w", clientConfig.StoreID, err)
}

return output.Display(output.EmptyStruct{}) //nolint:wrapcheck
return output.Display(output.EmptyStruct{})
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/store/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var getCmd = &cobra.Command{
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
11 changes: 3 additions & 8 deletions cmd/store/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func importStore(
maxParallelRequests int,
) error {
var err error
if storeID == "" { //nolint:nestif
if storeID == "" {
createStoreAndModelResponse, err := CreateStoreWithModel(clientConfig, storeData.Name, storeData.Model, format)
if err != nil {
return err
Expand All @@ -53,12 +53,7 @@ func importStore(
authModel := authorizationmodel.AuthzModel{}
clientConfig.StoreID = storeID

if format == authorizationmodel.ModelFormatJSON {
err = authModel.ReadFromJSONString(storeData.Model)
} else {
err = authModel.ReadFromDSLString(storeData.Model)
}

err = authModel.ReadModelFromString(storeData.Model, format)
if err != nil {
return err //nolint:wrapcheck
}
Expand Down Expand Up @@ -130,7 +125,7 @@ var importCmd = &cobra.Command{
return err
}

return output.Display(output.EmptyStruct{}) //nolint:wrapcheck
return output.Display(output.EmptyStruct{})
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/store/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ var listCmd = &cobra.Command{
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/tuple/changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ var changesCmd = &cobra.Command{
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
},
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/tuple/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ var deleteCmd = &cobra.Command{
return err
}

return output.Display(*response) //nolint:wrapcheck
return output.Display(*response)
}
body := &client.ClientDeleteTuplesBody{
client.ClientTupleKeyWithoutCondition{
Expand All @@ -92,7 +92,7 @@ var deleteCmd = &cobra.Command{
return fmt.Errorf("failed to delete tuples due to %w", err)
}

return output.Display(output.EmptyStruct{}) //nolint:wrapcheck
return output.Display(output.EmptyStruct{})
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/tuple/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ var importCmd = &cobra.Command{
return err
}

return output.Display(*result) //nolint:wrapcheck
return output.Display(*result)
},
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/tuple/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ var readCmd = &cobra.Command{
data = response.simple
}

return dataPrinter.Display(data) //nolint:wrapcheck
return dataPrinter.Display(data)
},
}

Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ go 1.21.8
require (
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
github.com/golang/mock v1.6.0
github.com/hashicorp/go-multierror v1.1.1
github.com/mattn/go-isatty v0.0.20
github.com/muesli/mango-cobra v1.2.0
github.com/muesli/roff v0.1.0
github.com/nwidger/jsoncolor v0.3.2
github.com/oklog/ulid/v2 v2.1.0
github.com/openfga/api/proto v0.0.0-20240201160513-05de9d8be3ee
github.com/openfga/go-sdk v0.3.5
github.com/openfga/language/pkg/go v0.0.0-20240311093347-a2bba7a149ff
github.com/openfga/openfga v1.5.0
github.com/openfga/api/proto v0.0.0-20240318145204-66b9e5cb403c
github.com/openfga/go-sdk v0.3.6-0.20240313140700-3de2c059df44
github.com/openfga/language/pkg/go v0.0.0-20240327204426-18b0254b2be1
github.com/openfga/openfga v1.5.1
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.18.2
Expand All @@ -36,10 +37,9 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/karlseguin/ccache/v3 v3.0.5 // indirect
Expand Down
Loading

0 comments on commit 7e4603b

Please sign in to comment.