Skip to content

Commit 921c943

Browse files
Merge pull request #120 from viveksahu26/feat/add_sbomasm_annotation
add sbomasm as a tool for spdx and cyclonedx
2 parents c4819f6 + 05ee179 commit 921c943

File tree

3 files changed

+301
-45
lines changed

3 files changed

+301
-45
lines changed

pkg/edit/cdx_edit.go

Lines changed: 217 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package edit
22

33
import (
44
"fmt"
5+
"strings"
56

67
cydx "github.com/CycloneDX/cyclonedx-go"
78
"github.com/interlynk-io/sbomasm/pkg/logger"
@@ -63,7 +64,6 @@ func (d *cdxEditDoc) update() {
6364
}
6465
}
6566
}
66-
6767
}
6868

6969
func (d *cdxEditDoc) timeStamp() error {
@@ -82,7 +82,6 @@ func (d *cdxEditDoc) timeStamp() error {
8282
} else {
8383
d.bom.Metadata.Timestamp = utcNowTime()
8484
}
85-
8685
return nil
8786
}
8887

@@ -269,31 +268,234 @@ func (d *cdxEditDoc) copyright() error {
269268
}
270269

271270
func (d *cdxEditDoc) tools() error {
272-
if !d.c.shouldTools() {
273-
return errNoConfiguration
271+
// default sbomasm tool for tools.tools
272+
sbomasmTool := cydx.Tool{
273+
Name: SBOMASM,
274+
Version: SBOMASM_VERSION,
274275
}
275276

276-
if d.c.search.subject != "document" {
277-
return errNotSupported
277+
// default sbomasm tool for tools.components
278+
sbomasmComponent := cydx.Component{
279+
Type: cydx.ComponentTypeApplication,
280+
Name: SBOMASM,
281+
Version: SBOMASM_VERSION,
278282
}
279283

280-
choice := cdxConstructTools(d.bom, d.c)
284+
// initialize the tool to cover case when tool section is not present
285+
// in that we still need to add sbomasm as a tool
286+
d.initializeMetadataTools()
287+
288+
// get all tools explicity specified by the user via flag `--tool`
289+
newTools := cdxConstructTools(d.bom, d.c)
290+
291+
// detect whether sbomasm is explicity specified by the user via flag `--tool` or not
292+
// if present then replace default sbomasm tool by provided sbomasm tool with version
293+
explicitSbomasm := d.detectExplicitTool(newTools.Tools, SBOMASM, &sbomasmTool)
294+
explicitSbomasmComponent := d.detectExplicitComponent(newTools.Components, SBOMASM, &sbomasmComponent)
295+
296+
if explicitSbomasm {
297+
d.bom.Metadata.Tools.Tools = removeTool(d.bom.Metadata.Tools.Tools, SBOMASM)
298+
}
299+
if explicitSbomasmComponent {
300+
d.bom.Metadata.Tools.Components = removeComponent(d.bom.Metadata.Tools.Components, SBOMASM)
301+
}
281302

282303
if d.c.onMissing() {
304+
d.addMissingToolsOrComponents(newTools, sbomasmTool, sbomasmComponent)
305+
return nil
306+
}
307+
308+
if d.c.onAppend() {
309+
d.appendToolsOrComponents(newTools, sbomasmTool, sbomasmComponent)
310+
return nil
311+
}
312+
313+
// neither missing nor append case
314+
d.mergeToolsOrComponents(newTools, sbomasmTool, sbomasmComponent)
315+
316+
return nil
317+
}
318+
319+
func (d *cdxEditDoc) initializeMetadataTools() {
320+
if d.bom.SpecVersion > cydx.SpecVersion1_4 {
283321
if d.bom.Metadata.Tools == nil {
284-
d.bom.Metadata.Tools = choice
322+
d.bom.Metadata.Tools = &cydx.ToolsChoice{
323+
Components: new([]cydx.Component),
324+
}
285325
}
286-
} else if d.c.onAppend() {
287-
if d.bom.Metadata.Tools != nil {
288-
d.bom.Metadata.Tools = cdxUniqTools(d.bom.Metadata.Tools, choice)
289-
} else {
290-
d.bom.Metadata.Tools = choice
326+
if d.bom.Metadata.Tools.Components == nil {
327+
d.bom.Metadata.Tools.Components = new([]cydx.Component)
291328
}
292329
} else {
293-
d.bom.Metadata.Tools = choice
330+
if d.bom.Metadata.Tools == nil {
331+
d.bom.Metadata.Tools = &cydx.ToolsChoice{
332+
Tools: new([]cydx.Tool),
333+
}
334+
}
335+
if d.bom.Metadata.Tools.Tools == nil {
336+
d.bom.Metadata.Tools.Tools = new([]cydx.Tool)
337+
}
294338
}
339+
}
295340

296-
return nil
341+
func (d *cdxEditDoc) detectExplicitTool(tools *[]cydx.Tool, sbomasmName string, sbomasmTool *cydx.Tool) bool {
342+
if tools != nil {
343+
for _, tool := range *tools {
344+
if tool.Name == sbomasmName {
345+
*sbomasmTool = tool
346+
return true
347+
}
348+
}
349+
}
350+
return false
351+
}
352+
353+
func (d *cdxEditDoc) detectExplicitComponent(components *[]cydx.Component, sbomasmName string, sbomasmComponent *cydx.Component) bool {
354+
if components != nil {
355+
for _, component := range *components {
356+
if component.Name == sbomasmName {
357+
*sbomasmComponent = component
358+
return true
359+
}
360+
}
361+
}
362+
return false
363+
}
364+
365+
// handle missing case for tools.tools and tools.components case
366+
func (d *cdxEditDoc) addMissingToolsOrComponents(newTools *cydx.ToolsChoice, sbomasmTool cydx.Tool, sbomasmComponent cydx.Component) {
367+
if d.bom.SpecVersion > cydx.SpecVersion1_4 {
368+
d.bom.Metadata.Tools.Components = cdxUniqueComponents(*d.bom.Metadata.Tools.Components, *newTools.Components)
369+
if !componentExists(d.bom.Metadata.Tools.Components, sbomasmComponent) {
370+
*d.bom.Metadata.Tools.Components = append(*d.bom.Metadata.Tools.Components, sbomasmComponent)
371+
}
372+
} else {
373+
d.bom.Metadata.Tools.Tools = cdxUniqueTools(*d.bom.Metadata.Tools.Tools, *newTools.Tools)
374+
if !toolExists(d.bom.Metadata.Tools.Tools, sbomasmTool) {
375+
*d.bom.Metadata.Tools.Tools = append(*d.bom.Metadata.Tools.Tools, sbomasmTool)
376+
}
377+
}
378+
}
379+
380+
// handle append case for tools.tools and tools.components case
381+
func (d *cdxEditDoc) appendToolsOrComponents(newTools *cydx.ToolsChoice, sbomasmTool cydx.Tool, sbomasmComponent cydx.Component) {
382+
if d.bom.SpecVersion > cydx.SpecVersion1_4 {
383+
d.bom.Metadata.Tools.Components = cdxUniqueComponents(*d.bom.Metadata.Tools.Components, *newTools.Components)
384+
if !componentExists(d.bom.Metadata.Tools.Components, sbomasmComponent) {
385+
*d.bom.Metadata.Tools.Components = append(*d.bom.Metadata.Tools.Components, sbomasmComponent)
386+
}
387+
} else {
388+
d.bom.Metadata.Tools.Tools = cdxUniqueTools(*d.bom.Metadata.Tools.Tools, *newTools.Tools)
389+
if !toolExists(d.bom.Metadata.Tools.Tools, sbomasmTool) {
390+
*d.bom.Metadata.Tools.Tools = append(*d.bom.Metadata.Tools.Tools, sbomasmTool)
391+
}
392+
}
393+
}
394+
395+
// handle default case for tools.tools and tools.components case
396+
func (d *cdxEditDoc) mergeToolsOrComponents(newTools *cydx.ToolsChoice, sbomasmTool cydx.Tool, sbomasmComponent cydx.Component) {
397+
if d.bom.SpecVersion > cydx.SpecVersion1_4 {
398+
d.bom.Metadata.Tools.Components = cdxUniqueComponents(*d.bom.Metadata.Tools.Components, *newTools.Components)
399+
if !componentExists(d.bom.Metadata.Tools.Components, sbomasmComponent) {
400+
*d.bom.Metadata.Tools.Components = append(*d.bom.Metadata.Tools.Components, sbomasmComponent)
401+
}
402+
} else {
403+
d.bom.Metadata.Tools.Tools = cdxUniqueTools(*d.bom.Metadata.Tools.Tools, *newTools.Tools)
404+
if !toolExists(d.bom.Metadata.Tools.Tools, sbomasmTool) {
405+
*d.bom.Metadata.Tools.Tools = append(*d.bom.Metadata.Tools.Tools, sbomasmTool)
406+
}
407+
}
408+
}
409+
410+
func toolExists(tools *[]cydx.Tool, tool cydx.Tool) bool {
411+
if tools == nil {
412+
return false
413+
}
414+
for _, t := range *tools {
415+
if t.Name == tool.Name && t.Version == tool.Version {
416+
return true
417+
}
418+
}
419+
return false
420+
}
421+
422+
// Check if a component exists
423+
func componentExists(components *[]cydx.Component, component cydx.Component) bool {
424+
if components == nil {
425+
return false
426+
}
427+
for _, c := range *components {
428+
if c.Name == component.Name && c.Version == component.Version {
429+
return true
430+
}
431+
}
432+
return false
433+
}
434+
435+
func cdxUniqueTools(existing, newTools []cydx.Tool) *[]cydx.Tool {
436+
toolSet := make(map[string]struct{})
437+
uniqueTools := []cydx.Tool{}
438+
439+
for _, t := range existing {
440+
key := fmt.Sprintf("%s-%s", strings.ToLower(t.Name), strings.ToLower(t.Version))
441+
toolSet[key] = struct{}{}
442+
uniqueTools = append(uniqueTools, t)
443+
}
444+
445+
for _, t := range newTools {
446+
key := fmt.Sprintf("%s-%s", strings.ToLower(t.Name), strings.ToLower(t.Version))
447+
if _, exists := toolSet[key]; !exists {
448+
uniqueTools = append(uniqueTools, t)
449+
}
450+
}
451+
452+
return &uniqueTools
453+
}
454+
455+
func cdxUniqueComponents(existing, newComponents []cydx.Component) *[]cydx.Component {
456+
componentSet := make(map[string]struct{})
457+
uniqueComponents := []cydx.Component{}
458+
459+
for _, c := range existing {
460+
key := fmt.Sprintf("%s-%s", strings.ToLower(c.Name), strings.ToLower(c.Version))
461+
componentSet[key] = struct{}{}
462+
uniqueComponents = append(uniqueComponents, c)
463+
}
464+
465+
for _, c := range newComponents {
466+
key := fmt.Sprintf("%s-%s", strings.ToLower(c.Name), strings.ToLower(c.Version))
467+
if _, exists := componentSet[key]; !exists {
468+
uniqueComponents = append(uniqueComponents, c)
469+
}
470+
}
471+
472+
return &uniqueComponents
473+
}
474+
475+
func removeTool(tools *[]cydx.Tool, name string) *[]cydx.Tool {
476+
if tools == nil {
477+
return nil
478+
}
479+
filtered := []cydx.Tool{}
480+
for _, t := range *tools {
481+
if t.Name != name {
482+
filtered = append(filtered, t)
483+
}
484+
}
485+
return &filtered
486+
}
487+
488+
func removeComponent(components *[]cydx.Component, name string) *[]cydx.Component {
489+
if components == nil {
490+
return nil
491+
}
492+
filtered := []cydx.Component{}
493+
for _, c := range *components {
494+
if c.Name != name {
495+
filtered = append(filtered, c)
496+
}
497+
}
498+
return &filtered
297499
}
298500

299501
func (d *cdxEditDoc) hashes() error {

pkg/edit/spdx.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ var spdx_strings_to_types = map[string]string{
5151
}
5252

5353
func spdxEdit(c *configParams) error {
54-
//log := logger.FromContext(*c.ctx)
54+
// log := logger.FromContext(*c.ctx)
5555

5656
bom, err := loadSpdxSbom(*c.ctx, c.inputFilePath)
5757
if err != nil {

0 commit comments

Comments
 (0)