Skip to content

Commit

Permalink
feat: integrate scenario-specific relationships & attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
aazam-gh committed Jun 16, 2024
1 parent f7de7de commit 5641af6
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 11 deletions.
76 changes: 76 additions & 0 deletions pkg/cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,82 @@ func validate() func(cmd *cobra.Command, args []string) error {
for sn, scenario := range s.Scenarios {
color.Notice.Printf("%v.scenario: %s - %s\n", sn+1, scenario.Name, scenario.Description)

// Iterate over all scenario relationships in the subject
for _, t := range scenario.Relationships {
// Convert each scenario 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
}

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

// Iterate over all scenario attributes in the subject
for _, a := range scenario.Attributes {
// Convert each scnario 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 scenario 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
}

// If the attribute was successfully written to the database, log a success message
color.Success.Println(fmt.Sprintf(" success: %s ", a))
}

// Start log output for checks
color.Notice.Println(" checks:")

Expand Down
41 changes: 30 additions & 11 deletions pkg/development/coverage/coverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,6 @@ func Run(shape file.Shape) SchemaCoverageInfo {
}
}

entityCoverageInfo.CoverageRelationshipsPercent = calculateCoveragePercent(
ref.Relationships,
entityCoverageInfo.UncoveredRelationships,
)

// Calculate attributes coverage
at := attributes(ref.EntityName, shape.Attributes)

Expand All @@ -132,13 +127,37 @@ func Run(shape file.Shape) SchemaCoverageInfo {
}
}

entityCoverageInfo.CoverageAttributesPercent = calculateCoveragePercent(
ref.Attributes,
entityCoverageInfo.UncoveredAttributes,
)

// Calculate assertions coverage for each scenario
// Calculate relationships, attributes and assertions coverage for each scenario
for _, s := range shape.Scenarios {

// Calculate relationships coverage
er := relationships(ref.EntityName, shape.Relationships)

for _, relationship := range ref.Relationships {
if !slices.Contains(er, relationship) {
entityCoverageInfo.UncoveredRelationships = append(entityCoverageInfo.UncoveredRelationships, relationship)
}
}

entityCoverageInfo.CoverageRelationshipsPercent = calculateCoveragePercent(
ref.Relationships,
entityCoverageInfo.UncoveredRelationships,
)

// Calculate attributes coverage
at := attributes(ref.EntityName, s.Attributes)

for _, attr := range ref.Attributes {
if !slices.Contains(at, attr) {
entityCoverageInfo.UncoveredAttributes = append(entityCoverageInfo.UncoveredAttributes, attr)
}
}

entityCoverageInfo.CoverageAttributesPercent = calculateCoveragePercent(
ref.Attributes,
entityCoverageInfo.UncoveredAttributes,
)

ca := assertions(ref.EntityName, s.Checks, s.EntityFilters)

for _, assertion := range ref.Assertions {
Expand Down
94 changes: 94 additions & 0 deletions pkg/development/development.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,100 @@ 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 {

// Each item in the Scenario Relationships slice is processed individually
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 scenario 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 scenario 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 scenario 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
}
}

// Each item in the Scenario Attributes slice is processed individually
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 scenario 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 scenario 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
}
}

// Each Check in the current scenario is processed
for _, check := range scenario.Checks {
entity, err := tuple.E(check.Entity)
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
2 changes: 2 additions & 0 deletions playground/src/layout/components/Modals/newScenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ function NewScenario(props) {
assertions: {}
}
],
relationships: [],
attributes: [],
entity_filters: [],
subject_filters: []
};
Expand Down

0 comments on commit 5641af6

Please sign in to comment.