Skip to content

Commit

Permalink
Add schema convert and schema apply to FGA module
Browse files Browse the repository at this point in the history
  • Loading branch information
atainter committed Aug 28, 2024
1 parent 5d61376 commit 4f156c9
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/workos/workos-go/v4 v4.16.0
github.com/workos/workos-go/v4 v4.21.0
)

require (
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/workos/workos-go/v4 v4.16.0 h1:7BPvVKHI8qhOY/lH4EbBY2CtQs1CDJxXDbfTnYNma3g=
github.com/workos/workos-go/v4 v4.16.0/go.mod h1:CwpXdAWhIE3SxV49qBVeYqWV8ojv0A0L9nM1xnho4/c=
github.com/workos/workos-go/v4 v4.21.0 h1:pEoAJzCsBPU46dL6/PwwwS5BrBV8LWOZQp0mERrRPCc=
github.com/workos/workos-go/v4 v4.21.0/go.mod h1:CwpXdAWhIE3SxV49qBVeYqWV8ojv0A0L9nM1xnho4/c=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
Expand Down
154 changes: 154 additions & 0 deletions internal/cmd/fga.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/spf13/cobra"
"github.com/workos/workos-cli/internal/printer"
"github.com/workos/workos-go/v4/pkg/fga"
"github.com/workos/workos-go/v4/pkg/workos_errors"
)

var resourceTypesFile string
Expand Down Expand Up @@ -65,6 +66,14 @@ func init() {
queryCmd.Flags().String("order", "", "order in which a list of results should be returned (asc or desc)")
fgaCmd.AddCommand(queryCmd)

// schema
convertSchemaCMD.Flags().StringP("output", "o", "json", "output format (schema or json)")
schemaCmd.AddCommand(convertSchemaCMD)
applySchemaCmd.Flags().BoolP("verbose", "v", false, "print extra details about the request")
applySchemaCmd.Flags().Bool("fail-on-warnings", false, "fail if there are warnings")
schemaCmd.AddCommand(applySchemaCmd)
fgaCmd.AddCommand(schemaCmd)

rootCmd.AddCommand(fgaCmd)
}

Expand Down Expand Up @@ -606,6 +615,151 @@ var queryCmd = &cobra.Command{
},
}

var schemaCmd = &cobra.Command{
Use: "schema",
Short: "Manage your schema",
Long: "A schema is a set of resource types and relations that define the structure of your application. Use this command to manage your schema.",
}

var convertSchemaCMD = &cobra.Command{
Use: "convert <input_file>",
Short: "Convert a schema to a JSON representation (or JSON to schema)",
Long: "Convert a schema to a JSON representation (or JSON to schema) that can be used to apply resource types.",
Example: `workos fga schema convert schema.txt -o json`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
output, err := cmd.Flags().GetString("output")
if err != nil {
return errors.Wrap(err, "invalid output flag")
}

bytes, err := os.ReadFile(args[0])
if err != nil {
return errors.Errorf("error reading input file: %v", err)
}

var response fga.ConvertSchemaResponse
switch output {
case "json":
schemaString := string(bytes)
response, err = fga.ConvertSchemaToResourceTypes(context.Background(), fga.ConvertSchemaToResourceTypesOpts{
Schema: schemaString,
})
if err != nil {
return convertSchemaError(err)
}
case "schema":
var resourceTypesWithVersion fga.ConvertResourceTypesToSchemaOpts
err = json.Unmarshal(bytes, &resourceTypesWithVersion)
if err != nil {
return errors.Errorf("error unmarshalling resource types: %v", err)
}
response, err = fga.ConvertResourceTypesToSchema(context.Background(), resourceTypesWithVersion)
if err != nil {
return convertSchemaError(err)
}
default:
return errors.Errorf("invalid output format: %s", output)
}

printer.PrintMsg("Version:")
printer.PrintMsg(fmt.Sprintf("%s\n", response.Version))

if response.Warnings != nil {
printer.PrintMsg("Warnings:")
for _, warning := range response.Warnings {
printer.PrintMsg(fmt.Sprintf("%s", warning.Message))

Check failure on line 671 in internal/cmd/fga.go

View workflow job for this annotation

GitHub Actions / Lint (golangci)

S1025: the argument is already a string, there's no need to use fmt.Sprintf (gosimple)
}
printer.PrintMsg("\n")
}

if response.Schema != nil {
printer.PrintMsg("Schema:")
printer.PrintMsg(fmt.Sprintf("%s", *response.Schema))

Check failure on line 678 in internal/cmd/fga.go

View workflow job for this annotation

GitHub Actions / Lint (golangci)

S1025: the argument is already a string, there's no need to use fmt.Sprintf (gosimple)
}

if response.ResourceTypes != nil {
printer.PrintMsg("Resource Types:")
printer.PrintJson(response.ResourceTypes)
}

return nil
},
}

var applySchemaCmd = &cobra.Command{
Use: "apply <input_file>",
Short: "Apply a schema",
Long: "Apply a schema to create or update resource types.",
Example: `workos fga schema apply schema.txt`,
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
verbose, err := cmd.Flags().GetBool("verbose")
if err != nil {
return errors.Wrap(err, "invalid verbose flag")
}
failOnWarnings, err := cmd.Flags().GetBool("fail-on-warnings")
if err != nil {
return errors.Wrap(err, "invalid fail-on-warnings flag")
}

bytes, err := os.ReadFile(args[0])
if err != nil {
return errors.Errorf("error reading input file: %v", err)
}
// Convert schema to resource types
response, err := fga.ConvertSchemaToResourceTypes(context.Background(), fga.ConvertSchemaToResourceTypesOpts{
Schema: string(bytes),
})
if err != nil {
return convertSchemaError(err)
}

if response.Warnings != nil {
printer.PrintMsg("Warnings:")
for _, warning := range response.Warnings {
printer.PrintMsg(fmt.Sprintf("%s", warning.Message))

Check failure on line 721 in internal/cmd/fga.go

View workflow job for this annotation

GitHub Actions / Lint (golangci)

S1025: the argument is already a string, there's no need to use fmt.Sprintf (gosimple)
}
printer.PrintMsg("\n")
if failOnWarnings {
return errors.New("error applying schema: warnings found (omit --fail-on-warnings to ignore)")
}
}

printer.PrintMsg("applying schema...")

if verbose {
printer.PrintJson(response.ResourceTypes)
}

ops := make([]fga.UpdateResourceTypeOpts, 0)
for _, rt := range response.ResourceTypes {
ops = append(ops, fga.UpdateResourceTypeOpts{

Check failure on line 737 in internal/cmd/fga.go

View workflow job for this annotation

GitHub Actions / Lint (golangci)

S1016: should convert rt (type github.com/workos/workos-go/v4/pkg/fga.ResourceType) to github.com/workos/workos-go/v4/pkg/fga.UpdateResourceTypeOpts instead of using struct literal (gosimple)
Type: rt.Type,
Relations: rt.Relations,
})
}

_, err = fga.BatchUpdateResourceTypes(context.Background(), ops)
if err != nil {
return errors.Errorf("error applying schema: %v", err)
}

printer.PrintMsg("Schema applied")
return nil
},
}

func convertSchemaError(err error) error {
var target workos_errors.HTTPError
if errors.As(err, &target) {
if len(target.Errors) > 0 {
return errors.Errorf("error converting schema: %s\n\t%s", target.Message, strings.Join(target.Errors, "\n\t"))
}
}
return errors.Errorf("error converting schema: %v", err)
}

func warrantCheckAsString(w fga.WarrantCheck) (string, error) {
s := fmt.Sprintf(
"%s:%s %s %s:%s",
Expand Down

0 comments on commit 4f156c9

Please sign in to comment.