Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: added scenario specific relationship and attributes #862

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions pkg/cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,85 @@ func validate() func(cmd *cobra.Command, args []string) error {
// Start log output for checks
color.Notice.Println(" checks:")

//Iterate over all the scenarios specific relationships
var createdLocalRelationshipsTups []*base.Tuple
for _, t := range scenario.Relationships {
// Convert each relationship to a Tuple
var tup *base.Tuple
tup, err = tuple.Tuple(t)
// If an error occurs during the conversion, add the error message to the list and continue to the next iteration
if err != nil {
list.Add(err.Error())
continue
}

// Retrieve the entity definition associated with the tuple's entity type
definition, _, err := dev.Container.SR.ReadEntityDefinition(ctx, "t1", tup.GetEntity().GetType(), version)
// If an error occurs while reading the entity definition, return the error
if err != nil {
return err
}

// Validate the tuple using the entity definition
err = serverValidation.ValidateTuple(definition, tup)
// If an error occurs during validation, return the error
if err != nil {
return err
}

// Write the validated tuple to the database
_, err = dev.Container.DW.Write(ctx, "t1", database.NewTupleCollection(tup), database.NewAttributeCollection())
// If an error occurs while writing to the database, add an error message to the list, log the error and continue to the next iteration
if err != nil {
list.Add(fmt.Sprintf("%s failed %s", t, err.Error()))
color.Danger.Println(fmt.Sprintf("fail: %s failed %s", t, validationError(err.Error())))
continue
}

createdLocalRelationshipsTups = append(createdLocalRelationshipsTups, tup)
// If the tuple was successfully written to the database, log a success message
color.Success.Println(fmt.Sprintf(" scenario relationship success: %s ", t))
}

//Iterate over all the scenarios specific relationship
var createdScenarioAttributes []*base.Attribute
for _, a := range s.Attributes {
// Convert each attribute to an Attribute
var attr *base.Attribute
attr, err = attribute.Attribute(a)
// If an error occurs during the conversion, add the error message to the list and continue to the next iteration
if err != nil {
list.Add(err.Error())
continue
}

// Retrieve the entity definition associated with the attribute's entity type
definition, _, err := dev.Container.SR.ReadEntityDefinition(ctx, "t1", attr.GetEntity().GetType(), version)
// If an error occurs while reading the entity definition, return the error
if err != nil {
return err
}

// Validate the attribute using the entity definition
err = serverValidation.ValidateAttribute(definition, attr)
// If an error occurs during validation, return the error
if err != nil {
return err
}

// Write the validated attribute to the database
_, err = dev.Container.DW.Write(ctx, "t1", database.NewTupleCollection(), database.NewAttributeCollection(attr))
// If an error occurs while writing to the database, add an error message to the list, log the error and continue to the next iteration
if err != nil {
list.Add(fmt.Sprintf("%s failed %s", a, err.Error()))
color.Danger.Println(fmt.Sprintf("fail: %s failed %s", a, validationError(err.Error())))
continue
}

createdScenarioAttributes = append(createdScenarioAttributes, attr)
// If the attribute was successfully written to the database, log a success message
color.Success.Println(fmt.Sprintf(" scenario attribute success: %s ", a))
}
// Iterate over all checks in the scenario
for _, check := range scenario.Checks {
// Extract entity from the check
Expand Down Expand Up @@ -439,6 +518,46 @@ func validate() func(cmd *cobra.Command, args []string) error {
}
}
}

// Once scenarios are tested delete created local scenario specific relationships
for _, t := range createdLocalRelationshipsTups {
// Write the relationship to the database
_, err = dev.Container.DW.Delete(ctx, "t1", &base.TupleFilter{
Entity: &base.EntityFilter{
Type: t.GetEntity().Type,
Ids: []string{t.Entity.Id},
},
Relation: t.GetRelation(),
},
&base.AttributeFilter{},
)
// Continue to the next relationship if an error occurred
if err != nil {
// If an error occurs, add it to the list and continue to the next filter.
list.Add(err.Error())
continue
}
}

// Once scenarios are tested delete created local scenario specific attributes
for _, a := range createdScenarioAttributes {
// Write the relationship to the database
_, err = dev.Container.DW.Delete(ctx, "t1", &base.TupleFilter{},
&base.AttributeFilter{
Entity: &base.EntityFilter{
Type: a.GetEntity().Type,
Ids: []string{a.Entity.Id},
},
Attributes: []string{a.GetAttribute()},
},
)
// Continue to the next relationship if an error occurred
if err != nil {
// If an error occurs, add it to the list and continue to the next filter.
list.Add(err.Error())
continue
}
}
}

// If the error list is not empty, there were some errors during processing.
Expand Down
145 changes: 145 additions & 0 deletions pkg/development/development.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,103 @@ func (c *Development) Run(ctx context.Context, shape map[string]interface{}) (er
// Each item in the Scenarios slice is processed individually
for i, scenario := range s.Scenarios {

var createdScenarioRelationshipsTups []*v1.Tuple
// Add scenario specific local relationships
for _, t := range scenario.Relationships {
tup, err := tuple.Tuple(t)
if err != nil {
errors = append(errors, Error{
Type: "relationships",
Key: t,
Message: err.Error(),
})
continue
}

// Read the schema definition for this relationship
definition, _, err := c.Container.SR.ReadEntityDefinition(ctx, "t1", tup.GetEntity().GetType(), version)
if err != nil {
errors = append(errors, Error{
Type: "relationships",
Key: t,
Message: err.Error(),
})
continue
}

// Validate the relationship tuple against the schema definition
err = validation.ValidateTuple(definition, tup)
if err != nil {
errors = append(errors, Error{
Type: "relationships",
Key: t,
Message: err.Error(),
})
continue
}

// Write the relationship to the database
_, err = c.Container.DW.Write(ctx, "t1", database.NewTupleCollection(tup), database.NewAttributeCollection())
// Continue to the next relationship if an error occurred
if err != nil {
errors = append(errors, Error{
Type: "relationships",
Key: t,
Message: err.Error(),
})
continue
}
createdScenarioRelationshipsTups = append(createdScenarioRelationshipsTups, tup)
}

// Add scenario specific attributes
var createdScenarioAttributes []*v1.Attribute
for _, a := range scenario.Attributes {
attr, err := attribute.Attribute(a)
if err != nil {
errors = append(errors, Error{
Type: "attributes",
Key: a,
Message: err.Error(),
})
continue
}

// Read the schema definition for this attribute
definition, _, err := c.Container.SR.ReadEntityDefinition(ctx, "t1", attr.GetEntity().GetType(), version)
if err != nil {
errors = append(errors, Error{
Type: "attributes",
Key: a,
Message: err.Error(),
})
continue
}

// Validate the attribute against the schema definition
err = validation.ValidateAttribute(definition, attr)
if err != nil {
errors = append(errors, Error{
Type: "attributes",
Key: a,
Message: err.Error(),
})
continue
}

// Write the attribute to the database
_, err = c.Container.DW.Write(ctx, "t1", database.NewTupleCollection(), database.NewAttributeCollection(attr))
// Continue to the next attribute if an error occurred
if err != nil {
errors = append(errors, Error{
Type: "attributes",
Key: a,
Message: err.Error(),
})
continue
}
createdScenarioAttributes = append(createdScenarioAttributes, attr)
}
// Each Check in the current scenario is processed
for _, check := range scenario.Checks {
entity, err := tuple.E(check.Entity)
Expand Down Expand Up @@ -519,6 +616,54 @@ func (c *Development) Run(ctx context.Context, shape map[string]interface{}) (er
}
}
}

// Once the scenarios are tested, delete created scenario specific relationships.
for _, t := range createdScenarioRelationshipsTups {
// Write the relationship to the database
_, err = c.Container.DW.Delete(ctx, "t1", &v1.TupleFilter{
Entity: &v1.EntityFilter{
Type: t.GetEntity().Type,
Ids: []string{t.Entity.Id},
},
Relation: t.GetRelation(),
},
&v1.AttributeFilter{},
)
// Continue to the next relationship if an error occurred
if err != nil {
// If an error occurs, add it to the list and continue to the next filter.
errors = append(errors, Error{
Type: "scenarios",
Key: i,
Message: err.Error(),
})
continue
}
}

// Once the scenarios are tested, delete created scenario specific attributes.
for _, a := range createdScenarioAttributes {
// Write the relationship to the database
_, err = c.Container.DW.Delete(ctx, "t1", &v1.TupleFilter{},
&v1.AttributeFilter{
Entity: &v1.EntityFilter{
Type: a.GetEntity().Type,
Ids: []string{a.Entity.Id},
},
Attributes: []string{a.GetAttribute()},
},
)
// Continue to the next relationship if an error occurred
if err != nil {
// If an error occurs, add it to the list and continue to the next filter.
errors = append(errors, Error{
Type: "scenarios",
Key: i,
Message: err.Error(),
})
continue
}
}
}

return
Expand Down
6 changes: 6 additions & 0 deletions pkg/development/file/shape.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ type Scenario struct {
// Description is a string that provides a brief explanation of the scenario.
Description string `yaml:"description"`

// Scenario specific local Relationships is slice of strings that represent the authorization relationships.
Relationships []string `yaml:"relationships"`

// Scenario specific local attributes is a slice of strings that represent the authorization attributes.
Attributes []string `yaml:"attributes"`

// Checks is a slice of Check structs that represent the authorization checks to be performed.
Checks []Check `yaml:"checks"`

Expand Down