Skip to content

Commit

Permalink
✨ Add dependency relationship to RuleSets (#427)
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Lucidi <slucidi@redhat.com>
  • Loading branch information
mansam committed Jun 30, 2023
1 parent ea0cd11 commit acf3c06
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 2 deletions.
21 changes: 21 additions & 0 deletions api/ruleset.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,11 @@ func (h RuleSetHandler) Update(ctx *gin.Context) {
_ = ctx.Error(result.Error)
return
}
err = h.DB(ctx).Model(m).Association("DependsOn").Replace(m.DependsOn)
if err != nil {
_ = ctx.Error(err)
return
}
err = h.DB(ctx).Model(m).Association("Rules").Replace(m.Rules)
if err != nil {
_ = ctx.Error(err)
Expand Down Expand Up @@ -225,6 +230,7 @@ type RuleSet struct {
Custom bool `json:"custom,omitempty"`
Repository *Repository `json:"repository,omitempty"`
Identity *Ref `json:"identity,omitempty"`
DependsOn []Ref `json:"dependsOn"`
}

//
Expand All @@ -250,6 +256,12 @@ func (r *RuleSet) With(m *model.RuleSet) {
r.Rules,
rule)
}
r.DependsOn = []Ref{}
for i := range m.DependsOn {
dep := Ref{}
dep.With(m.DependsOn[i].ID, m.DependsOn[i].Name)
r.DependsOn = append(r.DependsOn, dep)
}
}

//
Expand All @@ -271,6 +283,15 @@ func (r *RuleSet) Model() (m *model.RuleSet) {
if r.Repository != nil {
m.Repository, _ = json.Marshal(r.Repository)
}
for _, ref := range r.DependsOn {
m.DependsOn = append(
m.DependsOn,
model.RuleSet{
Model: model.Model{
ID: ref.ID,
},
})
}
return
}

Expand Down
2 changes: 0 additions & 2 deletions migration/v6/model/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ type MigrationWave = model.MigrationWave
type Proxy = model.Proxy
type Review = model.Review
type Setting = model.Setting
type RuleSet = model.RuleSet
type Rule = model.Rule
type Stakeholder = model.Stakeholder
type StakeholderGroup = model.StakeholderGroup
type Tag = model.Tag
Expand Down
67 changes: 67 additions & 0 deletions migration/v6/model/ruleset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package model

import "gorm.io/gorm"

//
// RuleSet - Analysis ruleset.
type RuleSet struct {
Model
Kind string
Name string `gorm:"uniqueIndex;not null"`
Description string
Custom bool
Repository JSON `gorm:"type:json"`
ImageID uint `gorm:"index" ref:"file"`
Image *File
IdentityID *uint `gorm:"index"`
Identity *Identity
Rules []Rule `gorm:"constraint:OnDelete:CASCADE"`
DependsOn []RuleSet `gorm:"many2many:RuleSetDependencies;constraint:OnDelete:CASCADE"`
}

//
// BeforeUpdate hook to avoid cyclic dependencies.
func (r *RuleSet) BeforeUpdate(db *gorm.DB) (err error) {
seen := make(map[uint]bool)
var nextDeps []RuleSet
var nextRuleSetIDs []uint
for _, dep := range r.DependsOn {
nextRuleSetIDs = append(nextRuleSetIDs, dep.ID)
}
for len(nextRuleSetIDs) != 0 {
result := db.Preload("DependsOn").Where("ID IN ?", nextRuleSetIDs).Find(&nextDeps)
if result.Error != nil {
err = result.Error
return
}
nextRuleSetIDs = nextRuleSetIDs[:0]
for _, nextDep := range nextDeps {
for _, dep := range nextDep.DependsOn {
if seen[dep.ID] {
continue
}
if dep.ID == r.ID {
err = DependencyCyclicError{}
return
}
seen[dep.ID] = true
nextRuleSetIDs = append(nextRuleSetIDs, dep.ID)
}
}
}

return
}

//
// Rule - Analysis rule.
type Rule struct {
Model
Name string
Description string
Labels JSON `gorm:"type:json"`
RuleSetID uint `gorm:"uniqueIndex:RuleA;not null"`
RuleSet *RuleSet
FileID *uint `gorm:"uniqueIndex:RuleA" ref:"file"`
File *File
}

0 comments on commit acf3c06

Please sign in to comment.