mirror of
https://github.com/anchore/syft
synced 2024-11-13 23:57:07 +00:00
modifying ids requires augmenting relationships
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
4f0132a98c
commit
9d281d1d99
5 changed files with 164 additions and 99 deletions
|
@ -17,20 +17,16 @@ type Index struct {
|
||||||
|
|
||||||
// NewIndex returns a new relationship Index
|
// NewIndex returns a new relationship Index
|
||||||
func NewIndex(relationships ...artifact.Relationship) *Index {
|
func NewIndex(relationships ...artifact.Relationship) *Index {
|
||||||
out := Index{}
|
out := Index{
|
||||||
|
fromID: make(map[artifact.ID]*mappedRelationships),
|
||||||
|
toID: make(map[artifact.ID]*mappedRelationships),
|
||||||
|
}
|
||||||
out.Add(relationships...)
|
out.Add(relationships...)
|
||||||
return &out
|
return &out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds all the given relationships to the index, without adding duplicates
|
// Add adds all the given relationships to the index, without adding duplicates
|
||||||
func (i *Index) Add(relationships ...artifact.Relationship) {
|
func (i *Index) Add(relationships ...artifact.Relationship) {
|
||||||
if i.fromID == nil {
|
|
||||||
i.fromID = map[artifact.ID]*mappedRelationships{}
|
|
||||||
}
|
|
||||||
if i.toID == nil {
|
|
||||||
i.toID = map[artifact.ID]*mappedRelationships{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// store appropriate indexes for stable ordering to minimize ID() calls
|
// store appropriate indexes for stable ordering to minimize ID() calls
|
||||||
for _, r := range relationships {
|
for _, r := range relationships {
|
||||||
// prevent duplicates
|
// prevent duplicates
|
||||||
|
@ -71,6 +67,7 @@ func (i *Index) Add(relationships ...artifact.Relationship) {
|
||||||
func (i *Index) Remove(id artifact.ID) {
|
func (i *Index) Remove(id artifact.ID) {
|
||||||
delete(i.fromID, id)
|
delete(i.fromID, id)
|
||||||
delete(i.toID, id)
|
delete(i.toID, id)
|
||||||
|
|
||||||
for idx := 0; idx < len(i.all); {
|
for idx := 0; idx < len(i.all); {
|
||||||
if i.all[idx].from == id || i.all[idx].to == id {
|
if i.all[idx].from == id || i.all[idx].to == id {
|
||||||
i.all = append(i.all[:idx], i.all[idx+1:]...)
|
i.all = append(i.all[:idx], i.all[idx+1:]...)
|
||||||
|
@ -80,6 +77,26 @@ func (i *Index) Remove(id artifact.ID) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Index) Replace(ogID artifact.ID, replacement artifact.Identifiable) {
|
||||||
|
for _, mapped := range fromMappedByID(i.fromID, ogID) {
|
||||||
|
i.Add(artifact.Relationship{
|
||||||
|
From: replacement,
|
||||||
|
To: mapped.relationship.To,
|
||||||
|
Type: mapped.relationship.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, mapped := range fromMappedByID(i.toID, ogID) {
|
||||||
|
i.Add(artifact.Relationship{
|
||||||
|
From: mapped.relationship.From,
|
||||||
|
To: replacement,
|
||||||
|
Type: mapped.relationship.Type,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
i.Remove(ogID)
|
||||||
|
}
|
||||||
|
|
||||||
// From returns all relationships from the given identifiable, with specified types
|
// From returns all relationships from the given identifiable, with specified types
|
||||||
func (i *Index) From(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []artifact.Relationship {
|
func (i *Index) From(identifiable artifact.Identifiable, types ...artifact.RelationshipType) []artifact.Relationship {
|
||||||
return toSortedSlice(fromMapped(i.fromID, identifiable), types)
|
return toSortedSlice(fromMapped(i.fromID, identifiable), types)
|
||||||
|
@ -122,10 +139,17 @@ func (i *Index) All(types ...artifact.RelationshipType) []artifact.Relationship
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromMapped(idMap map[artifact.ID]*mappedRelationships, identifiable artifact.Identifiable) []*sortableRelationship {
|
func fromMapped(idMap map[artifact.ID]*mappedRelationships, identifiable artifact.Identifiable) []*sortableRelationship {
|
||||||
if identifiable == nil || idMap == nil {
|
if identifiable == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
mapped := idMap[identifiable.ID()]
|
return fromMappedByID(idMap, identifiable.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromMappedByID(idMap map[artifact.ID]*mappedRelationships, id artifact.ID) []*sortableRelationship {
|
||||||
|
if idMap == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mapped := idMap[id]
|
||||||
if mapped == nil {
|
if mapped == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -327,3 +327,84 @@ func TestRemove(t *testing.T) {
|
||||||
assert.Empty(t, index.From(c3))
|
assert.Empty(t, index.From(c3))
|
||||||
assert.Empty(t, index.To(c3))
|
assert.Empty(t, index.To(c3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReplace(t *testing.T) {
|
||||||
|
p1 := pkg.Package{Name: "pkg-1"}
|
||||||
|
p2 := pkg.Package{Name: "pkg-2"}
|
||||||
|
p3 := pkg.Package{Name: "pkg-3"}
|
||||||
|
p4 := pkg.Package{Name: "pkg-4"}
|
||||||
|
|
||||||
|
for _, p := range []*pkg.Package{&p1, &p2, &p3, &p4} {
|
||||||
|
p.SetID()
|
||||||
|
}
|
||||||
|
|
||||||
|
r1 := artifact.Relationship{
|
||||||
|
From: p1,
|
||||||
|
To: p2,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
}
|
||||||
|
r2 := artifact.Relationship{
|
||||||
|
From: p3,
|
||||||
|
To: p1,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
}
|
||||||
|
r3 := artifact.Relationship{
|
||||||
|
From: p2,
|
||||||
|
To: p3,
|
||||||
|
Type: artifact.ContainsRelationship,
|
||||||
|
}
|
||||||
|
|
||||||
|
index := NewIndex(r1, r2, r3)
|
||||||
|
|
||||||
|
// replace p1 with p4 in the relationships
|
||||||
|
index.Replace(p1.ID(), &p4)
|
||||||
|
|
||||||
|
expectedRels := []artifact.Relationship{
|
||||||
|
{
|
||||||
|
From: p4, // replaced
|
||||||
|
To: p2,
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: p3,
|
||||||
|
To: p4, // replaced
|
||||||
|
Type: artifact.DependencyOfRelationship,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
From: p2,
|
||||||
|
To: p3,
|
||||||
|
Type: artifact.ContainsRelationship,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
compareRelationships(t, expectedRels, index.All())
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareRelationships(t testing.TB, expected, actual []artifact.Relationship) {
|
||||||
|
assert.Equal(t, len(expected), len(actual), "number of relationships should match")
|
||||||
|
for _, e := range expected {
|
||||||
|
found := false
|
||||||
|
for _, a := range actual {
|
||||||
|
if a.From.ID() == e.From.ID() && a.To.ID() == e.To.ID() && a.Type == e.Type {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.True(t, found, "expected relationship not found: %+v", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReplace_NoExistingRelations(t *testing.T) {
|
||||||
|
p1 := pkg.Package{Name: "pkg-1"}
|
||||||
|
p2 := pkg.Package{Name: "pkg-2"}
|
||||||
|
|
||||||
|
p1.SetID()
|
||||||
|
p2.SetID()
|
||||||
|
|
||||||
|
index := NewIndex()
|
||||||
|
|
||||||
|
index.Replace(p1.ID(), &p2)
|
||||||
|
|
||||||
|
allRels := index.All()
|
||||||
|
assert.Len(t, allRels, 0)
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package task
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -112,10 +111,7 @@ func NewPackageTask(cfg CatalogingFactoryConfig, c pkg.Cataloger, tags ...string
|
||||||
|
|
||||||
pkgs, relationships = finalizePkgCatalogerResults(cfg, resolver, catalogerName, pkgs, relationships)
|
pkgs, relationships = finalizePkgCatalogerResults(cfg, resolver, catalogerName, pkgs, relationships)
|
||||||
|
|
||||||
pkgs, relationships, err = applyCompliance(cfg.ComplianceConfig, catalogerName, pkgs, relationships)
|
pkgs, relationships = applyCompliance(cfg.ComplianceConfig, pkgs, relationships)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
sbom.AddPackages(pkgs...)
|
sbom.AddPackages(pkgs...)
|
||||||
sbom.AddRelationships(relationships...)
|
sbom.AddRelationships(relationships...)
|
||||||
|
@ -171,45 +167,47 @@ func finalizePkgCatalogerResults(cfg CatalogingFactoryConfig, resolver file.Path
|
||||||
return pkgs, relationships
|
return pkgs, relationships
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCompliance(cfg cataloging.ComplianceConfig, catalogerName string, pkgs []pkg.Package, relationships []artifact.Relationship) ([]pkg.Package, []artifact.Relationship, error) {
|
type packageReplacement struct {
|
||||||
remainingPkgs, droppedPkgs, err := filterNonCompliantPackages(pkgs, cfg)
|
original artifact.ID
|
||||||
var nonCompliantErr cataloging.ErrNonCompliantPackages
|
pkg pkg.Package
|
||||||
if errors.As(err, &nonCompliantErr) {
|
|
||||||
log.WithFields("cataloger", catalogerName).Errorf(nonCompliantErr.Error())
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, fmt.Errorf("unable to filter non-compliant packages: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyCompliance(cfg cataloging.ComplianceConfig, pkgs []pkg.Package, relationships []artifact.Relationship) ([]pkg.Package, []artifact.Relationship) {
|
||||||
|
remainingPkgs, droppedPkgs, replacements := filterNonCompliantPackages(pkgs, cfg)
|
||||||
|
|
||||||
relIdx := relationship.NewIndex(relationships...)
|
relIdx := relationship.NewIndex(relationships...)
|
||||||
for _, p := range droppedPkgs {
|
for _, p := range droppedPkgs {
|
||||||
relIdx.Remove(p.ID())
|
relIdx.Remove(p.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
return remainingPkgs, relIdx.All(), nil
|
for _, replacement := range replacements {
|
||||||
|
relIdx.Replace(replacement.original, replacement.pkg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterNonCompliantPackages(pkgs []pkg.Package, cfg cataloging.ComplianceConfig) ([]pkg.Package, []pkg.Package, error) {
|
return remainingPkgs, relIdx.All()
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterNonCompliantPackages(pkgs []pkg.Package, cfg cataloging.ComplianceConfig) ([]pkg.Package, []pkg.Package, []packageReplacement) {
|
||||||
var remainingPkgs, droppedPkgs []pkg.Package
|
var remainingPkgs, droppedPkgs []pkg.Package
|
||||||
errNonCompliant := cataloging.NewErrNonCompliantPackages()
|
var replacements []packageReplacement
|
||||||
for _, p := range pkgs {
|
for _, p := range pkgs {
|
||||||
if applyComplianceRules(&p, cfg, errNonCompliant) {
|
keep, replacement := applyComplianceRules(&p, cfg)
|
||||||
|
if keep {
|
||||||
remainingPkgs = append(remainingPkgs, p)
|
remainingPkgs = append(remainingPkgs, p)
|
||||||
} else {
|
} else {
|
||||||
droppedPkgs = append(droppedPkgs, p)
|
droppedPkgs = append(droppedPkgs, p)
|
||||||
}
|
}
|
||||||
|
if replacement != nil {
|
||||||
|
replacements = append(replacements, *replacement)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(errNonCompliant.NonCompliantPackageLocations) > 0 {
|
return remainingPkgs, droppedPkgs, replacements
|
||||||
return nil, nil, errNonCompliant
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return remainingPkgs, droppedPkgs, nil
|
func applyComplianceRules(p *pkg.Package, cfg cataloging.ComplianceConfig) (bool, *packageReplacement) {
|
||||||
}
|
|
||||||
|
|
||||||
func applyComplianceRules(p *pkg.Package, cfg cataloging.ComplianceConfig, errNonCompliant *cataloging.ErrNonCompliantPackages) bool {
|
|
||||||
var drop bool
|
var drop bool
|
||||||
|
var replacement *packageReplacement
|
||||||
|
|
||||||
applyComplianceRule := func(value, fieldName string, action cataloging.ComplianceAction) bool {
|
applyComplianceRule := func(value, fieldName string, action cataloging.ComplianceAction) bool {
|
||||||
if strings.TrimSpace(value) != "" {
|
if strings.TrimSpace(value) != "" {
|
||||||
|
@ -225,11 +223,9 @@ func applyComplianceRules(p *pkg.Package, cfg cataloging.ComplianceConfig, errNo
|
||||||
case cataloging.ComplianceActionDrop:
|
case cataloging.ComplianceActionDrop:
|
||||||
log.WithFields("pkg", p.String(), "location", loc).Debugf("package with missing %s, dropping", fieldName)
|
log.WithFields("pkg", p.String(), "location", loc).Debugf("package with missing %s, dropping", fieldName)
|
||||||
drop = true
|
drop = true
|
||||||
case cataloging.ComplianceActionWarn:
|
|
||||||
log.WithFields("pkg", p.String(), "location", loc).Warnf("package with missing %s, failing", fieldName)
|
|
||||||
case cataloging.ComplianceActionFail:
|
|
||||||
errNonCompliant.AddInfo(loc, p.String(), fmt.Sprintf("missing %s", fieldName))
|
|
||||||
case cataloging.ComplianceActionStub:
|
case cataloging.ComplianceActionStub:
|
||||||
|
log.WithFields("pkg", p.String(), "location", loc).Debugf("package with missing %s, stubbing with default value", fieldName)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case cataloging.ComplianceActionKeep:
|
case cataloging.ComplianceActionKeep:
|
||||||
|
@ -238,6 +234,8 @@ func applyComplianceRules(p *pkg.Package, cfg cataloging.ComplianceConfig, errNo
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ogID := p.ID()
|
||||||
|
|
||||||
if applyComplianceRule(p.Name, "name", cfg.MissingName) {
|
if applyComplianceRule(p.Name, "name", cfg.MissingName) {
|
||||||
p.Name = cataloging.UnknownStubValue
|
p.Name = cataloging.UnknownStubValue
|
||||||
p.SetID()
|
p.SetID()
|
||||||
|
@ -248,7 +246,15 @@ func applyComplianceRules(p *pkg.Package, cfg cataloging.ComplianceConfig, errNo
|
||||||
p.SetID()
|
p.SetID()
|
||||||
}
|
}
|
||||||
|
|
||||||
return !drop && len(errNonCompliant.NonCompliantPackageLocations) == 0
|
newID := p.ID()
|
||||||
|
if newID != ogID {
|
||||||
|
replacement = &packageReplacement{
|
||||||
|
original: ogID,
|
||||||
|
pkg: *p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !drop, replacement
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasAuthoritativeCPE(cpes []cpe.CPE) bool {
|
func hasAuthoritativeCPE(cpes []cpe.CPE) bool {
|
||||||
|
|
|
@ -84,11 +84,10 @@ func TestApplyCompliance(t *testing.T) {
|
||||||
|
|
||||||
cfg := cataloging.ComplianceConfig{
|
cfg := cataloging.ComplianceConfig{
|
||||||
MissingName: cataloging.ComplianceActionDrop,
|
MissingName: cataloging.ComplianceActionDrop,
|
||||||
MissingVersion: cataloging.ComplianceActionWarn,
|
MissingVersion: cataloging.ComplianceActionStub,
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingPkgs, remainingRels, err := applyCompliance(cfg, "test-cataloger", []pkg.Package{p1, p2, p3, p4}, []artifact.Relationship{r1, r2})
|
remainingPkgs, remainingRels := applyCompliance(cfg, []pkg.Package{p1, p2, p3, p4}, []artifact.Relationship{r1, r2})
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// p2 should be dropped because it has a missing name, p3 and p4 should pass with a warning for the missing version
|
// p2 should be dropped because it has a missing name, p3 and p4 should pass with a warning for the missing version
|
||||||
assert.Len(t, remainingPkgs, 3) // p1, p3, p4 should remain
|
assert.Len(t, remainingPkgs, 3) // p1, p3, p4 should remain
|
||||||
|
@ -106,11 +105,11 @@ func TestFilterNonCompliantPackages(t *testing.T) {
|
||||||
|
|
||||||
cfg := cataloging.ComplianceConfig{
|
cfg := cataloging.ComplianceConfig{
|
||||||
MissingName: cataloging.ComplianceActionDrop,
|
MissingName: cataloging.ComplianceActionDrop,
|
||||||
MissingVersion: cataloging.ComplianceActionWarn,
|
MissingVersion: cataloging.ComplianceActionKeep,
|
||||||
}
|
}
|
||||||
|
|
||||||
remainingPkgs, droppedPkgs, err := filterNonCompliantPackages([]pkg.Package{p1, p2, p3}, cfg)
|
remainingPkgs, droppedPkgs, replacement := filterNonCompliantPackages([]pkg.Package{p1, p2, p3}, cfg)
|
||||||
require.NoError(t, err)
|
require.Nil(t, replacement)
|
||||||
|
|
||||||
// p2 should be dropped because it has a missing name
|
// p2 should be dropped because it has a missing name
|
||||||
assert.Len(t, remainingPkgs, 2)
|
assert.Len(t, remainingPkgs, 2)
|
||||||
|
@ -121,32 +120,21 @@ func TestFilterNonCompliantPackages(t *testing.T) {
|
||||||
func TestApplyComplianceRules_DropAndStub(t *testing.T) {
|
func TestApplyComplianceRules_DropAndStub(t *testing.T) {
|
||||||
p := pkg.Package{Name: "", Version: ""}
|
p := pkg.Package{Name: "", Version: ""}
|
||||||
p.SetID()
|
p.SetID()
|
||||||
|
ogID := p.ID()
|
||||||
|
|
||||||
cfg := cataloging.ComplianceConfig{
|
cfg := cataloging.ComplianceConfig{
|
||||||
MissingName: cataloging.ComplianceActionDrop,
|
MissingName: cataloging.ComplianceActionDrop,
|
||||||
MissingVersion: cataloging.ComplianceActionStub,
|
MissingVersion: cataloging.ComplianceActionStub,
|
||||||
}
|
}
|
||||||
|
|
||||||
errNonCompliant := cataloging.NewErrNonCompliantPackages()
|
isCompliant, replacement := applyComplianceRules(&p, cfg)
|
||||||
|
require.NotNil(t, replacement)
|
||||||
isCompliant := applyComplianceRules(&p, cfg, errNonCompliant)
|
assert.Equal(t, packageReplacement{
|
||||||
|
original: ogID,
|
||||||
|
pkg: p,
|
||||||
|
}, *replacement)
|
||||||
|
|
||||||
// the package should be dropped due to missing name (drop action) and its version should be stubbed
|
// the package should be dropped due to missing name (drop action) and its version should be stubbed
|
||||||
assert.False(t, isCompliant)
|
assert.False(t, isCompliant)
|
||||||
assert.Equal(t, cataloging.UnknownStubValue, p.Version)
|
assert.Equal(t, cataloging.UnknownStubValue, p.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyComplianceRules_Fail(t *testing.T) {
|
|
||||||
p1 := pkg.Package{Name: "", Version: "1.0"} // missing name
|
|
||||||
p1.SetID()
|
|
||||||
|
|
||||||
cfg := cataloging.ComplianceConfig{
|
|
||||||
MissingName: cataloging.ComplianceActionFail,
|
|
||||||
}
|
|
||||||
|
|
||||||
errNonCompliant := cataloging.NewErrNonCompliantPackages()
|
|
||||||
isCompliant := applyComplianceRules(&p1, cfg, errNonCompliant)
|
|
||||||
|
|
||||||
assert.False(t, isCompliant)
|
|
||||||
assert.Contains(t, errNonCompliant.NonCompliantPackageLocations, "unknown")
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,45 +1,15 @@
|
||||||
package cataloging
|
package cataloging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ComplianceActionKeep ComplianceAction = "keep"
|
ComplianceActionKeep ComplianceAction = "keep"
|
||||||
ComplianceActionWarn ComplianceAction = "warn"
|
|
||||||
ComplianceActionDrop ComplianceAction = "drop"
|
ComplianceActionDrop ComplianceAction = "drop"
|
||||||
ComplianceActionFail ComplianceAction = "fail"
|
|
||||||
ComplianceActionStub ComplianceAction = "stub"
|
ComplianceActionStub ComplianceAction = "stub"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrNonCompliantPackages struct {
|
|
||||||
NonCompliantPackageLocations map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewErrNonCompliantPackages() *ErrNonCompliantPackages {
|
|
||||||
return &ErrNonCompliantPackages{
|
|
||||||
NonCompliantPackageLocations: make(map[string][]string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ErrNonCompliantPackages) AddInfo(location, info, note string) {
|
|
||||||
e.NonCompliantPackageLocations[location] = append(e.NonCompliantPackageLocations[location], note+": "+info)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e ErrNonCompliantPackages) Error() string {
|
|
||||||
var reasons []string
|
|
||||||
for location, infos := range e.NonCompliantPackageLocations {
|
|
||||||
for _, info := range infos {
|
|
||||||
reasons = append(reasons, location+": "+info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(reasons)
|
|
||||||
|
|
||||||
return "non-compliant packages: " + strings.Join(reasons, "\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
const UnknownStubValue = "UNKNOWN"
|
const UnknownStubValue = "UNKNOWN"
|
||||||
|
|
||||||
type ComplianceAction string
|
type ComplianceAction string
|
||||||
|
@ -68,14 +38,10 @@ func (c ComplianceAction) Parse() ComplianceAction {
|
||||||
switch strings.ToLower(string(c)) {
|
switch strings.ToLower(string(c)) {
|
||||||
case string(ComplianceActionKeep), "include":
|
case string(ComplianceActionKeep), "include":
|
||||||
return ComplianceActionKeep
|
return ComplianceActionKeep
|
||||||
case string(ComplianceActionWarn), "warning":
|
|
||||||
return ComplianceActionWarn
|
|
||||||
case string(ComplianceActionDrop), "exclude":
|
case string(ComplianceActionDrop), "exclude":
|
||||||
return ComplianceActionDrop
|
return ComplianceActionDrop
|
||||||
case string(ComplianceActionFail), "error":
|
|
||||||
return ComplianceActionFail
|
|
||||||
case string(ComplianceActionStub), "replace":
|
case string(ComplianceActionStub), "replace":
|
||||||
return ComplianceActionStub
|
return ComplianceActionStub
|
||||||
}
|
}
|
||||||
return ComplianceActionWarn
|
return ComplianceActionKeep
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue