Skip to content

Commit

Permalink
Add support for multiple policy in on block event (#857)
Browse files Browse the repository at this point in the history
  • Loading branch information
asafambar authored Jul 11, 2023
1 parent af26f09 commit 491202d
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 37 deletions.
34 changes: 33 additions & 1 deletion utils/coreutils/tableutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var DefaultMaxColWidth = 25
// In case the struct you want to print contains a field that is a slice of other structs,
// you can print it in the table too with the 'embed-table' tag which can be set on slices of structs only.
// Fields with the 'extended' tag will be printed iff the 'printExtended' bool input is true.
// You can merge cells horizontally with the 'auto-merge' tag, it will merge cells with the same value.
//
// Example:
// These are the structs Customer and Product:
Expand Down Expand Up @@ -91,6 +92,36 @@ var DefaultMaxColWidth = 25
// ┌─────────────────────────┐
// │ No customers were found │
// └─────────────────────────┘
//
// Example(auto-merge):
// These are the structs Customer:
//
// type Customer struct {
// name string `col-name:"Name" auto-merge:"true"`
// age string `col-name:"Age" auto-merge:"true"`
// title string `col-name:"Product Title" auto-merge:"true"`
// CatNumber string `col-name:"Product\nCatalog #" auto-merge:"true"`
// Color string `col-name:"Color" extended:"true" auto-merge:"true"`
// }
//
// customersSlice := []Customer{
// {name: "Gai", age: "350", title: "SpiderFrog Shirt - Medium", CatNumber: "123456", Color: "Green"},
// {name: "Gai", age: "350", title: "Floral Bottle", CatNumber: "147585", Color: "Blue"},
// {name: "Noah", age: "21", title: "Pouch", CatNumber: "456789", Color: "Red"},
// }
//
// Customers
// ┌──────┬─────┬───────────────────────────┬───────────┐
// │ NAME │ AGE │ PRODUCT TITLE │ PRODUCT │
// │ │ │ │ CATALOG # │
// ├──────┼─────┼───────────────────────────┼───────────┤
// │ Gai │ 350 │ SpiderFrog Shirt - Medium │ 123456 │
// │ │ ├───────────────────────────┼───────────┤
// │ │ │ Floral Bottle │ 147585 │
// ├──────┼─────┼───────────────────────────┼───────────┤
// │ Noah │ 21 │ Pouch │ 456789 │
// └──────┴─────┴───────────────────────────┴───────────┘

func PrintTable(rows interface{}, title string, emptyTableMessage string, printExtended bool) (err error) {
tableWriter, err := PrepareTable(rows, emptyTableMessage, printExtended)
if err != nil || tableWriter == nil {
Expand Down Expand Up @@ -140,6 +171,7 @@ func PrepareTable(rows interface{}, emptyTableMessage string, printExtended bool
columnName, columnNameExist := field.Tag.Lookup("col-name")
embedTable, embedTableExist := field.Tag.Lookup("embed-table")
extended, extendedExist := field.Tag.Lookup("extended")
_, autoMerge := field.Tag.Lookup("auto-merge")
_, omitEmptyColumn := field.Tag.Lookup("omitempty")
if !printExtended && extendedExist && extended == "true" {
continue
Expand All @@ -161,7 +193,7 @@ func PrepareTable(rows interface{}, emptyTableMessage string, printExtended bool
} else {
columnsNames = append(columnsNames, columnName)
fieldsProperties = append(fieldsProperties, fieldProperties{index: i})
columnConfigs = append(columnConfigs, table.ColumnConfig{Name: columnName})
columnConfigs = append(columnConfigs, table.ColumnConfig{Name: columnName, AutoMerge: autoMerge})
}
}
tableWriter.AppendHeader(columnsNames)
Expand Down
88 changes: 55 additions & 33 deletions xray/commands/curation/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,33 @@ type PackageStatus struct {
Action string `json:"action"`
ParentName string `json:"direct_dependency_package_name"`
ParentVersion string `json:"direct_dependency_package_version"`
BlockedPackageUrl string `json:"blocked_package_url"`
BlockedPackageUrl string `json:"blocked_package_url,omitempty"`
PackageName string `json:"blocked_package_name"`
PackageVersion string `json:"blocked_package_version"`
BlockingReason string `json:"blocking_reason"`
DepRelation string `json:"dependency_relation"`
PkgType string `json:"type"`
Policy []Policy `json:"policies"`
Policy []Policy `json:"policies,omitempty"`
}

type Policy struct {
Policy string `json:"policy"`
Condition string `json:"condition"`
Policy string `json:"policy"`
Condition string `json:"condition"`
Explanation string `json:"explanation"`
Recommendation string `json:"recommendation"`
}

type PackageStatusTable struct {
Status string `col-name:"Action"`
ParentName string `col-name:"Direct Dependency\nPackage Name"`
ParentVersion string `col-name:"Direct Dependency\nPackage Version"`
BlockedPackageUrl string `col-name:"Blocked Package URL"`
PackageName string `col-name:"Blocked Package\nName"`
PackageVersion string `col-name:"Blocked Package\nVersion"`
BlockingReason string `col-name:"Blocking Reason"`
PkgType string `col-name:"Package Type"`
Policy []policyTable `embed-table:"true"`
}

type policyTable struct {
Policy string `col-name:"Violated Policy\nName"`
Condition string `col-name:"Violated Condition\nName"`
ParentName string `col-name:"Direct\nDependency\nPackage\nName" auto-merge:"true"`
ParentVersion string `col-name:"Direct\nDependency\nPackage\nVersion" auto-merge:"true"`
PackageName string `col-name:"Blocked\nPackage\nName" auto-merge:"true"`
PackageVersion string `col-name:"Blocked\nPackage\nVersion" auto-merge:"true"`
BlockingReason string `col-name:"Blocking Reason" auto-merge:"true"`
PkgType string `col-name:"Package\nType" auto-merge:"true"`
Policy string `col-name:"Violated\nPolicy\nName"`
Condition string `col-name:"Violated Condition\nName"`
Explanation string `col-name:"Explanation Name"`
Recommendation string `col-name:"Recommendation Name"`
}

type treeAnalyzer struct {
Expand Down Expand Up @@ -279,24 +277,34 @@ func printResult(format utils.OutputFormat, projectPath string, packagesStatus [

func convertToPackageStatusTable(packagesStatus []*PackageStatus) []PackageStatusTable {
var pkgStatusTable []PackageStatusTable
for _, pkgStatus := range packagesStatus {
for index, pkgStatus := range packagesStatus {
// We use auto-merge supported by the 'go-pretty' library. It doesn't have an option to merge lines by a group of unique fields.
// In order to so, we make each group merge only with itself by adding or not adding space. This way, it won't be merged with the next group.
uniqLineSep := ""
if index%2 == 0 {
uniqLineSep = " "
}
pkgTable := PackageStatusTable{
Status: pkgStatus.Action,
ParentName: pkgStatus.ParentName,
ParentVersion: pkgStatus.ParentVersion,
BlockedPackageUrl: pkgStatus.BlockedPackageUrl,
PackageName: pkgStatus.PackageName,
PackageVersion: pkgStatus.PackageVersion,
BlockingReason: pkgStatus.BlockingReason,
PkgType: pkgStatus.PkgType,
ParentName: pkgStatus.ParentName + uniqLineSep,
ParentVersion: pkgStatus.ParentVersion + uniqLineSep,
PackageName: pkgStatus.PackageName + uniqLineSep,
PackageVersion: pkgStatus.PackageVersion + uniqLineSep,
BlockingReason: pkgStatus.BlockingReason + uniqLineSep,
PkgType: pkgStatus.PkgType + uniqLineSep,
}
if len(pkgStatus.Policy) == 0 {
pkgStatusTable = append(pkgStatusTable, pkgTable)
continue
}
var policiesCondTable []policyTable
for _, policyCond := range pkgStatus.Policy {
policiesCondTable = append(policiesCondTable, policyTable(policyCond))
pkgTable.Policy = policyCond.Policy
pkgTable.Explanation = policyCond.Explanation
pkgTable.Recommendation = policyCond.Recommendation
pkgTable.Condition = policyCond.Condition
pkgStatusTable = append(pkgStatusTable, pkgTable)
}
pkgTable.Policy = policiesCondTable
pkgStatusTable = append(pkgStatusTable, pkgTable)
}

return pkgStatusTable
}

Expand Down Expand Up @@ -450,23 +458,37 @@ func (nc *treeAnalyzer) getBlockedPackageDetails(packageUrl string, name string,
}

// Return policies and conditions names from the FORBIDDEN HTTP error message.
// Message structure: Package %s:%s download was blocked by JFrog Packages Curation service due to the following policies violated {%s, %s},{%s, %s}.
// Message structure: Package %s:%s download was blocked by JFrog Packages Curation service due to the following policies violated {%s, %s, %s, %s},{%s, %s, %s, %s}.
func (nc *treeAnalyzer) extractPoliciesFromMsg(respError *ErrorsResp) []Policy {
var policies []Policy
msg := respError.Errors[0].Message
allMatches := nc.extractPoliciesRegex.FindAllString(msg, -1)
for _, match := range allMatches {
match = strings.TrimSuffix(strings.TrimPrefix(match, "{"), "}")
polCond := strings.Split(match, ",")
if len(polCond) == 2 {
if len(polCond) >= 2 {
pol := polCond[0]
cond := polCond[1]

if len(polCond) == 4 {
exp, rec := makeLegiblePolicyDetails(polCond[2], polCond[3])
policies = append(policies, Policy{Policy: strings.TrimSpace(pol),
Condition: strings.TrimSpace(cond), Explanation: strings.TrimSpace(exp), Recommendation: strings.TrimSpace(rec)})
continue
}
policies = append(policies, Policy{Policy: strings.TrimSpace(pol), Condition: strings.TrimSpace(cond)})
}
}
return policies
}

// Adding a new line after the headline and replace every "|" with a new line.
func makeLegiblePolicyDetails(explanation, recommendation string) (string, string) {
explanation = strings.ReplaceAll(strings.Replace(explanation, ": ", ":\n", 1), " | ", "\n")
recommendation = strings.ReplaceAll(strings.Replace(recommendation, ": ", ":\n", 1), " | ", "\n")
return explanation, recommendation
}

func getUrlNameAndVersionByTech(tech coreutils.Technology, nodeId, artiUrl, repo string) (downloadUrl string, name string, version string) {
if tech == coreutils.Npm {
return getNameScopeAndVersion(nodeId, artiUrl, repo, coreutils.Npm.ToString())
Expand Down
8 changes: 5 additions & 3 deletions xray/commands/curation/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,16 @@ func getTestCasesForExtractPoliciesFromMsg() []struct {
Errors: []ErrorResp{
{
Status: 403,
Message: "Package test:1.0.0 download was blocked by JFrog Packages Curation service due to the following policies violated {policy1, condition1}.",
Message: "Package test:1.0.0 download was blocked by JFrog Packages Curation service due to the following policies violated {policy1, condition1, Package is 3339 days old, Upgrade to version 0.2.4 (latest)}.",
},
},
},
expect: []Policy{
{
Policy: "policy1",
Condition: "condition1",
Policy: "policy1",
Condition: "condition1",
Explanation: "Package is 3339 days old",
Recommendation: "Upgrade to version 0.2.4 (latest)",
},
},
},
Expand Down

0 comments on commit 491202d

Please sign in to comment.