Skip to content

Commit

Permalink
fix dependencies and compositions
Browse files Browse the repository at this point in the history
Signed-off-by: Vivek Kumar Sahu <[email protected]>
  • Loading branch information
viveksahu26 committed Sep 10, 2024
1 parent 0f8f22f commit 9e54452
Show file tree
Hide file tree
Showing 7 changed files with 243 additions and 116 deletions.
70 changes: 36 additions & 34 deletions pkg/compliance/bsi.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package compliance

import (
"context"
"fmt"
"strings"

"github.com/interlynk-io/sbomqs/pkg/logger"
Expand Down Expand Up @@ -161,31 +162,16 @@ func bsiBuildPhase(doc sbom.Document) *record {
}

func bsiSbomDepth(doc sbom.Document) *record {
if !doc.PrimaryComp().Present() {
return newRecordStmt(SBOM_DEPTH, "doc", "no-primary", 0.0)
}

if len(doc.Relations()) == 0 {
return newRecordStmt(SBOM_DEPTH, "doc", "no-relationships", 0.0)
}

primary, _ := lo.Find(doc.Components(), func(c sbom.GetComponent) bool {
return c.IsPrimaryComponent()
})

if !primary.HasRelationShips() {
return newRecordStmt(SBOM_DEPTH, "doc", "no-primary-relationships", 0.0)
}

if primary.RelationShipState() == "complete" {
return newRecordStmt(SBOM_DEPTH, "doc", "complete", 10.0)
}
result, score := "", 0.0
// for doc.Components()
totalDependencies := doc.PrimaryComp().Dependencies()

if primary.HasRelationShips() {
return newRecordStmt(SBOM_DEPTH, "doc", "unattested-has-relationships", 5.0)
if totalDependencies > 0 {
score = 10.0
}
result = fmt.Sprintf("doc has %d depedencies", totalDependencies)

return newRecordStmt(SBOM_DEPTH, "doc", "non-compliant", 0.0)
return newRecordStmt(SBOM_DEPTH, "doc", result, score)
}

func bsiCreator(doc sbom.Document) *record {
Expand Down Expand Up @@ -306,13 +292,17 @@ func bsiComponents(doc sbom.Document) []*record {
records := append(records, newRecordStmt(SBOM_COMPONENTS, "doc", "", 0.0))
return records
}
// map package ID to Package Name
for _, component := range doc.Components() {
CompIDWithName[component.GetID()] = component.GetName()
}

for _, component := range doc.Components() {
records = append(records, bsiComponentCreator(component))
records = append(records, bsiComponentName(component))
records = append(records, bsiComponentVersion(component))
records = append(records, bsiComponentLicense(component))
records = append(records, bsiComponentDepth(component))
records = append(records, bsiComponentDepth(doc, component))
records = append(records, bsiComponentHash(component))
records = append(records, bsiComponentSourceCodeURL(component))
records = append(records, bsiComponentDownloadURL(component))
Expand All @@ -325,28 +315,43 @@ func bsiComponents(doc sbom.Document) []*record {
return records
}

func bsiComponentDepth(component sbom.GetComponent) *record {
if !component.HasRelationShips() {
func bsiComponentDepth(doc sbom.Document, component sbom.GetComponent) *record {
result, score := "", 0.0
var fResults []string

dependencies := doc.GetRelationships(component.GetID())
if dependencies == nil {
return newRecordStmt(COMP_DEPTH, component.GetName(), "no-relationships", 0.0)
}

if component.RelationShipState() == "complete" {
return newRecordStmt(COMP_DEPTH, component.GetName(), "complete", 10.0)
for _, d := range dependencies {
state := component.GetComposition(d)
if state == "complete" {
componentName := extractName(d)
fResults = append(fResults, componentName)
score = 10.0
} else {
componentName := extractName(d)
// state := "(unattested-has-relationships)"
fResults = append(fResults, componentName)
score = 5.0
}
}

if component.HasRelationShips() {
return newRecordStmt(COMP_DEPTH, component.GetName(), "unattested-has-relationships", 5.0)
if fResults != nil {
result = strings.Join(fResults, ", ")
} else {
result += "no-relationships"
}

return newRecordStmt(COMP_DEPTH, component.GetName(), "non-compliant", 0.0)
return newRecordStmt(COMP_DEPTH, component.GetName(), result, score)
}

func bsiComponentLicense(component sbom.GetComponent) *record {
licenses := component.Licenses()
score := 0.0

if len(licenses) == 0 {
// fmt.Printf("component %s : %s has no licenses\n", component.Name(), component.Version())
return newRecordStmt(COMP_LICENSE, component.GetName(), "not-compliant", score)
}

Expand All @@ -373,9 +378,6 @@ func bsiComponentLicense(component sbom.GetComponent) *record {

total := spdx + aboutcode + custom

// fmt.Printf("component %s : %s has (total)%d = (all)%d licenses\n", component.Name(), component.Version(), total, len(licenses))
// fmt.Printf("%+v\n", licenses)

if total != len(licenses) {
score = 0.0
return newRecordStmt(COMP_LICENSE, component.GetName(), "not-compliant", score)
Expand Down
19 changes: 10 additions & 9 deletions pkg/compliance/ntia.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,19 +364,20 @@ func ntiaComponentDependencies(doc sbom.Document, component sbom.GetComponent) *
result, score := "", 0.0
var results []string

if relation := doc.Relations(); relation != nil {
for _, rel := range relation {
if strings.Contains(rel.GetFrom(), component.GetID()) {
componentName := extractName(rel.GetTo())
results = append(results, componentName)
score = 10.0
}
}
dependencies := doc.GetRelationships(component.GetID())
if dependencies == nil {
return newRecordStmt(COMP_DEPTH, component.GetName(), "no-relationships", 0.0)
}
for _, d := range dependencies {
componentName := extractName(d)
results = append(results, componentName)
score = 10.0
}

if results != nil {
result = strings.Join(results, ", ")
} else {
result += "No Dependencies"
result += "no-relationships"
}

return newRecordStmt(COMP_DEPTH, component.GetName(), result, score)
Expand Down
111 changes: 63 additions & 48 deletions pkg/sbom/cdx.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type CdxDoc struct {
manufacturer Manufacturer
compositions map[string]string
primaryComp primaryComp
dependencies map[string][]string
composition map[string]string
}

func newCDXDoc(ctx context.Context, f io.ReadSeeker, format FileFormat) (Document, error) {
Expand Down Expand Up @@ -129,6 +131,14 @@ func (c CdxDoc) Manufacturer() Manufacturer {
return c.manufacturer
}

func (c CdxDoc) GetRelationships(componentID string) []string {
return c.dependencies[componentID]
}

func (c CdxDoc) GetComposition(componentID string) string {
return c.composition[componentID]
}

func (c *CdxDoc) parse() {
c.parseDoc()
c.parseSpec()
Expand All @@ -137,7 +147,7 @@ func (c *CdxDoc) parse() {
c.parseManufacturer()
c.parseTool()
c.parseCompositions()
c.parseRelsAndPrimaryComp()
c.parsePrimaryCompAndRelationships()
c.parseComps()
}

Expand Down Expand Up @@ -287,49 +297,6 @@ func copyC(cdxc *cydx.Component, c *CdxDoc) *Component {
nc.isPrimary = true
}

fromRelsPresent := func(rels []GetRelation, compID string) bool {
for _, r := range rels {
if r.GetFrom() == compID {
return true
}
}
return false
}

compNormalise := func(compID string) string {
switch cydx.CompositionAggregate(compID) {
case cydx.CompositionAggregateComplete:
return "complete"
case cydx.CompositionAggregateIncomplete:
return "incomplete"
case cydx.CompositionAggregateIncompleteFirstPartyOnly:
return "incomplete-first-party-only"
case cydx.CompositionAggregateIncompleteFirstPartyOpenSourceOnly:
return "incomplete-first-party-open-source-only"
case cydx.CompositionAggregateIncompleteFirstPartyProprietaryOnly:
return "incomplete-first-party-proprietary-only"
case cydx.CompositionAggregateIncompleteThirdPartyOnly:
return "incomplete-third-party-only"
case cydx.CompositionAggregateIncompleteThirdPartyOpenSourceOnly:
return "incomplete-third-party-open-source-only"
case cydx.CompositionAggregateIncompleteThirdPartyProprietaryOnly:
return "incomplete-third-party-proprietary-only"
case cydx.CompositionAggregateNotSpecified:
return "not-specified"
case cydx.CompositionAggregateUnknown:
return "unknown"
}

return "not-specified"
}

nc.hasRelationships = fromRelsPresent(c.rels, cdxc.BOMRef)
if c.compositions != nil {
if comp, ok := c.compositions[cdxc.BOMRef]; ok {
nc.RelationshipState = compNormalise(comp)
}
}

nc.ID = cdxc.BOMRef
return nc
}
Expand Down Expand Up @@ -545,14 +512,16 @@ func (c *CdxDoc) parseManufacturer() {
c.manufacturer = m
}

func (c *CdxDoc) parseRelsAndPrimaryComp() {
func (c *CdxDoc) parsePrimaryCompAndRelationships() {
if c.doc.Metadata == nil {
return
}

if c.doc.Metadata.Component == nil {
return
}

c.dependencies = make(map[string][]string)

c.primaryComp.present = true
c.primaryComp.id = c.doc.Metadata.Component.BOMRef
var totalDependencies int
Expand All @@ -563,16 +532,62 @@ func (c *CdxDoc) parseRelsAndPrimaryComp() {
for _, d := range lo.FromPtr(r.Dependencies) {
nr := Relation{}
nr.From = r.Ref
nr.To = d
if r.Ref == c.primaryComp.id {
c.primaryComp.hasDependencies = true
totalDependencies++
c.rels = append(c.rels, nr)
c.dependencies[c.primaryComp.id] = append(c.dependencies[c.primaryComp.id], d)
} else {
c.rels = append(c.rels, nr)
c.dependencies[r.Ref] = append(c.dependencies[r.Ref], d)
}
nr.To = d
c.rels = append(c.rels, nr)
}
}
c.primaryComp.dependecies = totalDependencies
}

func (c *CdxDoc) parseComposition() {

Check failure on line 550 in pkg/sbom/cdx.go

View workflow job for this annotation

GitHub Actions / lint

func `(*CdxDoc).parseComposition` is unused (unused)
if c.doc.Metadata == nil {
return
}
if c.doc.Compositions == nil {
return
}
c.composition = make(map[string]string)

for _, cp := range lo.FromPtr(c.doc.Compositions) {
state := compNormalise(cp.BOMRef)
c.composition[cp.BOMRef] = state
}
}

func compNormalise(compID string) string {

Check failure on line 565 in pkg/sbom/cdx.go

View workflow job for this annotation

GitHub Actions / lint

func `compNormalise` is unused (unused)
switch cydx.CompositionAggregate(compID) {
case cydx.CompositionAggregateComplete:
return "complete"
case cydx.CompositionAggregateIncomplete:
return "incomplete"
case cydx.CompositionAggregateIncompleteFirstPartyOnly:
return "incomplete-first-party-only"
case cydx.CompositionAggregateIncompleteFirstPartyOpenSourceOnly:
return "incomplete-first-party-open-source-only"
case cydx.CompositionAggregateIncompleteFirstPartyProprietaryOnly:
return "incomplete-first-party-proprietary-only"
case cydx.CompositionAggregateIncompleteThirdPartyOnly:
return "incomplete-third-party-only"
case cydx.CompositionAggregateIncompleteThirdPartyOpenSourceOnly:
return "incomplete-third-party-open-source-only"
case cydx.CompositionAggregateIncompleteThirdPartyProprietaryOnly:
return "incomplete-third-party-proprietary-only"
case cydx.CompositionAggregateNotSpecified:
return "not-specified"
case cydx.CompositionAggregateUnknown:
return "unknown"
}
return "not-specified"
}

func (c *CdxDoc) assignSupplier(comp *cydx.Component) *Supplier {
if comp.Supplier == nil {
c.addToLogs(fmt.Sprintf("cdx doc comp %s no supplier found", comp.Name))
Expand Down
6 changes: 6 additions & 0 deletions pkg/sbom/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type GetComponent interface {
GetPackageLicenseDeclared() string
GetPackageLicenseConcluded() string
ExternalReferences() []GetExternalReference
GetComposition(string) string
}

type Component struct {
Expand Down Expand Up @@ -73,6 +74,7 @@ type Component struct {
PackageLicenseConcluded string
PackageLicenseDeclared string
ExternalRefs []GetExternalReference
composition map[string]string
}

func NewComponent() *Component {
Expand Down Expand Up @@ -174,3 +176,7 @@ func (c Component) GetPackageLicenseDeclared() string {
func (c Component) ExternalReferences() []GetExternalReference {
return c.ExternalRefs
}

func (c Component) GetComposition(componentID string) string {
return c.composition[componentID]
}
1 change: 1 addition & 0 deletions pkg/sbom/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ type Document interface {
Supplier() GetSupplier

PrimaryComp() PrimaryComp
GetRelationships(string) []string
}
11 changes: 8 additions & 3 deletions pkg/sbom/primarycomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ type PrimaryComp interface {
}

type primaryComp struct {
present bool
id string
dependecies int
present bool
id string
dependecies int
hasDependencies bool
}

func (pc *primaryComp) Present() bool {
Expand All @@ -37,3 +38,7 @@ func (pc *primaryComp) ID() string {
func (pc *primaryComp) Dependencies() int {
return pc.dependecies
}

func (pc *primaryComp) HasDependencies() bool {
return pc.hasDependencies
}
Loading

0 comments on commit 9e54452

Please sign in to comment.