github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/internal/sbomsync/builder.go (about) 1 package sbomsync 2 3 import ( 4 "sync" 5 6 "github.com/anchore/syft/syft/artifact" 7 "github.com/anchore/syft/syft/linux" 8 "github.com/anchore/syft/syft/pkg" 9 "github.com/anchore/syft/syft/sbom" 10 ) 11 12 var _ interface { 13 Accessor 14 Builder 15 } = (*sbomBuilder)(nil) // integrity check 16 17 // Builder provides a simple facade for simple additions to the SBOM 18 type Builder interface { 19 // nodes 20 21 AddPackages(...pkg.Package) 22 23 DeletePackages(...artifact.ID) 24 25 // edges 26 27 AddRelationships(...artifact.Relationship) 28 29 // other 30 31 SetLinuxDistribution(linux.Release) 32 } 33 34 // Accessor allows for low-level access to the SBOM 35 type Accessor interface { 36 WriteToSBOM(func(*sbom.SBOM)) 37 ReadFromSBOM(func(*sbom.SBOM)) 38 } 39 40 type sbomBuilder struct { 41 sbom *sbom.SBOM 42 lock *sync.RWMutex 43 onWrite []func(*sbom.SBOM) 44 } 45 46 func NewBuilder(s *sbom.SBOM, onWrite ...func(*sbom.SBOM)) Builder { 47 return &sbomBuilder{ 48 sbom: s, 49 lock: &sync.RWMutex{}, 50 onWrite: onWrite, 51 } 52 } 53 54 func (b sbomBuilder) onWriteEvent() { 55 for _, fn := range b.onWrite { 56 fn(b.sbom) 57 } 58 } 59 60 func (b sbomBuilder) WriteToSBOM(fn func(*sbom.SBOM)) { 61 b.lock.Lock() 62 defer b.lock.Unlock() 63 64 fn(b.sbom) 65 b.onWriteEvent() 66 } 67 68 func (b sbomBuilder) ReadFromSBOM(fn func(*sbom.SBOM)) { 69 b.lock.RLock() 70 defer b.lock.RUnlock() 71 72 fn(b.sbom) 73 } 74 75 func (b sbomBuilder) AddPackages(p ...pkg.Package) { 76 b.lock.Lock() 77 defer b.lock.Unlock() 78 79 b.sbom.Artifacts.Packages.Add(p...) 80 b.onWriteEvent() 81 } 82 83 func (b sbomBuilder) DeletePackages(ids ...artifact.ID) { 84 b.lock.Lock() 85 defer b.lock.Unlock() 86 87 deleted := make(map[artifact.ID]struct{}) 88 for _, id := range ids { 89 b.sbom.Artifacts.Packages.Delete(id) 90 deleted[id] = struct{}{} 91 } 92 93 // remove any relationships that reference the deleted packages 94 var relationships []artifact.Relationship 95 for _, rel := range b.sbom.Relationships { 96 if _, ok := deleted[rel.From.ID()]; ok { 97 continue 98 } 99 if _, ok := deleted[rel.To.ID()]; ok { 100 continue 101 } 102 103 // only keep relationships that don't reference the deleted packages 104 relationships = append(relationships, rel) 105 } 106 107 b.sbom.Relationships = relationships 108 b.onWriteEvent() 109 } 110 111 func (b sbomBuilder) AddRelationships(relationship ...artifact.Relationship) { 112 b.lock.Lock() 113 defer b.lock.Unlock() 114 115 b.sbom.Relationships = append(b.sbom.Relationships, relationship...) 116 b.onWriteEvent() 117 } 118 119 func (b sbomBuilder) SetLinuxDistribution(release linux.Release) { 120 b.lock.Lock() 121 defer b.lock.Unlock() 122 123 b.sbom.Artifacts.LinuxDistribution = &release 124 b.onWriteEvent() 125 }