-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
…FGA" This reverts commit fb25b96.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/* | ||
Copyright © 2023 OpenFGA | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package model | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
pb "buf.build/gen/go/openfga/api/protocolbuffers/go/openfga/v1" | ||
"github.com/oklog/ulid/v2" | ||
"github.com/openfga/cli/internal/authorizationmodel" | ||
"github.com/openfga/cli/internal/output" | ||
openfga "github.com/openfga/go-sdk" | ||
"github.com/openfga/openfga/pkg/typesystem" | ||
"github.com/spf13/cobra" | ||
"google.golang.org/protobuf/encoding/protojson" | ||
) | ||
|
||
type validationResult struct { | ||
ID string `json:"id,omitempty"` | ||
CreatedAt *time.Time `json:"created_at,omitempty"` | ||
IsValid bool `json:"is_valid"` | ||
Error *string `json:"error,omitempty"` | ||
} | ||
|
||
func validate(inputModel authorizationmodel.AuthzModel) validationResult { | ||
model := &pb.AuthorizationModel{} | ||
output := validationResult{ | ||
IsValid: true, | ||
} | ||
|
||
modelJSONString, err := inputModel.GetAsJSONString() | ||
if err != nil { | ||
output.IsValid = false | ||
errorString := "unable to parse json input" | ||
output.Error = &errorString | ||
|
||
return output | ||
} | ||
|
||
err = protojson.Unmarshal([]byte(*modelJSONString), model) | ||
if err != nil { | ||
output.IsValid = false | ||
errorString := "unable to parse json input" | ||
output.Error = &errorString | ||
|
||
return output | ||
} | ||
|
||
if model.Id != "" { | ||
output.ID = model.Id | ||
|
||
modelID, err := ulid.Parse(model.Id) | ||
if err != nil { | ||
output.IsValid = false | ||
errorString := "unable to parse id: invalid ulid format" | ||
output.Error = &errorString | ||
|
||
return output | ||
} | ||
|
||
createdAt := time.Unix(int64(modelID.Time()/1_000), 0).UTC() //nolint:gomnd | ||
output.CreatedAt = &createdAt | ||
} | ||
|
||
if _, err = typesystem.NewAndValidate(context.Background(), model); err != nil { | ||
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Security Audits
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Tests
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Test Release Process
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Tests
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Security Audits
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Lints
Check failure on line 80 in cmd/model/validate.go GitHub Actions / Test Release Process
|
||
errString := err.Error() | ||
output.IsValid = false | ||
output.Error = &errString | ||
} | ||
|
||
return output | ||
} | ||
|
||
// validateCmd represents the validate command. | ||
var validateCmd = &cobra.Command{ | ||
Use: "validate", | ||
Short: "Validate Authorization Model", | ||
Long: "Validates that an authorization model is valid.", | ||
Example: `fga model validate --file model.json`, | ||
Args: cobra.MaximumNArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
var inputModel string | ||
if err := authorizationmodel.ReadFromInputFileOrArg( | ||
cmd, | ||
args, | ||
"file", | ||
false, | ||
&inputModel, | ||
openfga.PtrString(""), | ||
&validateInputFormat); err != nil { | ||
return err //nolint:wrapcheck | ||
} | ||
|
||
authModel := authorizationmodel.AuthzModel{} | ||
var err error | ||
|
||
if validateInputFormat == authorizationmodel.ModelFormatJSON { | ||
err = authModel.ReadFromJSONString(inputModel) | ||
} else { | ||
err = authModel.ReadFromDSLString(inputModel) | ||
} | ||
|
||
if err != nil { | ||
return err //nolint:wrapcheck | ||
} | ||
|
||
response := validate(authModel) | ||
|
||
return output.Display(response) //nolint:wrapcheck | ||
}, | ||
} | ||
|
||
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"`) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package model | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/openfga/cli/internal/authorizationmodel" | ||
openfga "github.com/openfga/go-sdk" | ||
) | ||
|
||
func TestValidateCmdWithArgs(t *testing.T) { | ||
t.Parallel() | ||
validateCmd.SetArgs([]string{`{"schema_version":"1.1"}`}) | ||
|
||
if err := validateCmd.Execute(); err != nil { | ||
t.Errorf("failed to execute validateCmd") | ||
} | ||
} | ||
|
||
func TestValidate(t *testing.T) { | ||
t.Parallel() | ||
|
||
type validationTest struct { | ||
Name string | ||
Input string | ||
IsValid bool | ||
ExpectedOutput validationResult | ||
} | ||
|
||
tests := []validationTest{ | ||
{ | ||
Name: "missing schema version", | ||
Input: "{", | ||
IsValid: false, | ||
ExpectedOutput: validationResult{ | ||
IsValid: false, | ||
Error: openfga.PtrString("unable to parse json input"), | ||
}, | ||
}, | ||
{ | ||
Name: "missing schema version", | ||
Input: `{"id":"abcde","schema_version":"1.1"}`, | ||
IsValid: false, | ||
ExpectedOutput: validationResult{ | ||
ID: "abcde", | ||
IsValid: false, | ||
Error: openfga.PtrString("unable to parse id: invalid ulid format"), | ||
}, | ||
}, | ||
{ | ||
Name: "missing schema version", | ||
Input: "{}", | ||
IsValid: false, | ||
ExpectedOutput: validationResult{ | ||
IsValid: false, | ||
Error: openfga.PtrString("invalid schema version"), | ||
}, | ||
}, | ||
{ | ||
Name: "invalid schema version", | ||
Input: `{"schema_version":"1.0"}`, | ||
IsValid: false, | ||
ExpectedOutput: validationResult{ | ||
IsValid: false, | ||
Error: openfga.PtrString("invalid schema version"), | ||
}, | ||
}, | ||
{ | ||
Name: "only schema", | ||
Input: `{"schema_version":"1.1"}`, | ||
IsValid: true, | ||
ExpectedOutput: validationResult{ | ||
IsValid: true, | ||
}, | ||
}, | ||
} | ||
|
||
for index := 0; index < len(tests); index++ { | ||
test := tests[index] | ||
|
||
t.Run(test.Name, func(t *testing.T) { | ||
t.Parallel() | ||
|
||
model := authorizationmodel.AuthzModel{} | ||
err := model.ReadFromJSONString(test.Input) | ||
if err != nil { | ||
return | ||
} | ||
output := validate(model) | ||
|
||
if !reflect.DeepEqual(output, test.ExpectedOutput) { | ||
t.Fatalf("Expect output %v actual %v", test.ExpectedOutput, output) | ||
} | ||
}) | ||
} | ||
} |