Skip to content

Commit 1a85539

Browse files
committed
update conversion logic
Signed-off-by: Vivek Kumar Sahu <vivekkumarsahu650@gmail.com>
1 parent 99d2d22 commit 1a85539

6 files changed

Lines changed: 92 additions & 38 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ require (
1919
github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect
2020
github.com/anchore/go-struct-converter v0.0.0-20250211213226-cce56d595160 // indirect
2121
github.com/blang/semver/v4 v4.0.0 // indirect
22-
github.com/google/go-cmp v0.6.0 // indirect
22+
github.com/google/go-cmp v0.7.0 // indirect
2323
github.com/sirupsen/logrus v1.9.3 // indirect
2424
github.com/spdx/tools-golang v0.5.5 // indirect
2525
golang.org/x/mod v0.23.0 // indirect

go.sum

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8
4343
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
4444
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
4545
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
46-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
4746
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
47+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
48+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
4849
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
4950
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
5051
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=

pkg/converter/converter.go

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/interlynk-io/sbommv/pkg/tcontext"
2626
"github.com/protobom/protobom/pkg/formats"
2727
"github.com/protobom/protobom/pkg/reader"
28+
"github.com/protobom/protobom/pkg/sbom"
2829
"github.com/protobom/protobom/pkg/writer"
2930
)
3031

@@ -51,39 +52,27 @@ func newBufferWriteCloser() *bufferWriteCloser {
5152
// ConvertSBOM converts SBOM data to the target format using protobom
5253
func ConvertSBOM(ctx tcontext.TransferMetadata, sbomData []byte, targetFormat FormatSpec) ([]byte, error) {
5354
// Detect source format
55+
logger.LogDebug(ctx.Context, "Iniatializing for SBOM conversion from spdx to cdx")
5456

5557
sourceFormat, err := detectFormat(sbomData)
5658
if err != nil {
5759
return nil, fmt.Errorf("detecting source format: %w", err)
5860
}
61+
5962
if sourceFormat == targetFormat {
6063
logger.LogDebug(ctx.Context, "No conversion needed", "format", sourceFormat)
6164
return sbomData, nil
6265
}
6366

64-
// Parse the input SBOM
65-
r := reader.New()
66-
67-
doc, err := r.ParseStream(bytes.NewReader(sbomData))
67+
doc, err := parseSBOM(sbomData)
6868
if err != nil {
69-
return nil, fmt.Errorf("parsing SBOM: %w", err)
69+
return nil, err
7070
}
7171

72-
// Serialize to target format (CycloneDX for DTrack)
72+
// Serialize to CycloneDX format from SPDX format
7373
if targetFormat == FormatCycloneDX {
74-
// Set serialNumber if missing or invalid
75-
if doc.Metadata.Id == "" || !isValidCycloneDXSerialNumber(doc.Metadata.Id) {
76-
doc.Metadata.Id = "urn:uuid:" + uuid.New().String()
77-
}
78-
doc.Metadata.Version = "1" // Default version
79-
80-
w := writer.New()
81-
buf := newBufferWriteCloser()
82-
if err := w.WriteStreamWithOptions(doc, buf, &writer.Options{Format: formats.CDX16JSON}); err != nil {
83-
return nil, fmt.Errorf("writing CycloneDX: %w", err)
84-
}
85-
logger.LogDebug(ctx.Context, "Converted SBOM", "from", sourceFormat, "to", targetFormat)
86-
return buf.Bytes(), nil
74+
enrichedDoc := enrichCycloneDXSBOM(doc)
75+
return serializeToCycloneDX(ctx, enrichedDoc)
8776
}
8877

8978
return nil, fmt.Errorf("unsupported conversion to %s", targetFormat)
@@ -111,3 +100,39 @@ func isValidCycloneDXSerialNumber(serial string) bool {
111100
matched, _ := regexp.MatchString(pattern, serial)
112101
return matched
113102
}
103+
104+
// protobom on converting from spdx to cdx, puts wp invalid serial number and version.
105+
// enrichCycloneDXSBOM() function will update the correct serial number and version
106+
func enrichCycloneDXSBOM(doc *sbom.Document) *sbom.Document {
107+
if doc.Metadata.Id == "" || !isValidCycloneDXSerialNumber(doc.Metadata.Id) {
108+
doc.Metadata.Id = "urn:uuid:" + uuid.New().String()
109+
}
110+
111+
doc.Metadata.Version = "1" // Default version
112+
113+
return doc
114+
}
115+
116+
func parseSBOM(sbomData []byte) (*sbom.Document, error) {
117+
// Parse the input SBOM
118+
r := reader.New()
119+
120+
// parse a sbom document from a sbom data using protobom
121+
doc, err := r.ParseStream(bytes.NewReader(sbomData))
122+
if err != nil {
123+
return nil, fmt.Errorf("parsing SBOM: %w", err)
124+
}
125+
return doc, nil
126+
}
127+
128+
func serializeToCycloneDX(ctx tcontext.TransferMetadata, doc *sbom.Document) ([]byte, error) {
129+
w := writer.New()
130+
buf := newBufferWriteCloser()
131+
132+
if err := w.WriteStreamWithOptions(doc, buf, &writer.Options{Format: formats.CDX15JSON}); err != nil {
133+
return nil, fmt.Errorf("writing CycloneDX: %w", err)
134+
}
135+
logger.LogDebug(ctx.Context, "Converted SPDX SBOM to CycloneDX")
136+
137+
return buf.Bytes(), nil
138+
}

pkg/engine/transfer.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"context"
2020
"fmt"
2121
"io"
22+
"strings"
2223

2324
adapter "github.com/interlynk-io/sbommv/pkg/adapter"
2425
"github.com/interlynk-io/sbommv/pkg/converter"
@@ -73,16 +74,7 @@ func TransferRun(ctx context.Context, cmd *cobra.Command, config types.Config) e
7374
}
7475

7576
var convertedIterator iterator.SBOMIterator
76-
77-
if types.AdapterType(config.DestinationType) == types.DtrackAdapterType {
78-
logger.LogDebug(transferCtx.Context, "SBOM conversion will take place")
79-
convertedSBOMs := sbomConversion(sbomIterator, *transferCtx)
80-
// Create a new iterator with converted SBOMs
81-
convertedIterator = iterator.NewMemoryIterator(convertedSBOMs)
82-
} else {
83-
logger.LogDebug(transferCtx.Context, "SBOM conversion will not take place")
84-
convertedIterator = sbomIterator
85-
}
77+
convertedIterator = checkAdapterForConversion(transferCtx, config, sbomIterator)
8678

8779
if config.DryRun {
8880
logger.LogDebug(transferCtx.Context, "Dry-run mode enabled: Displaying retrieved SBOMs", "values", config.DryRun)
@@ -154,9 +146,32 @@ func sbomConversion(sbomIterator iterator.SBOMIterator, transferCtx tcontext.Tra
154146

155147
// Update SBOM data with converted content
156148
sbom.Data = convertedData
149+
150+
if strings.HasSuffix(sbom.Path, ".spdx.json") {
151+
sbom.Path = strings.Replace(sbom.Path, ".spdx.json", ".conversion.cdx.json", 1)
152+
// transferCtx.FilePath = sbom.Path // Sync FilePath for logging
153+
}
157154
convertedSBOMs = append(convertedSBOMs, sbom)
158155
}
159156
logger.LogDebug(transferCtx.Context, "Successfully SBOM conversion")
160157

161158
return convertedSBOMs
162159
}
160+
161+
func checkAdapterForConversion(transferCtx *tcontext.TransferMetadata, config types.Config, sbomIterator iterator.SBOMIterator) iterator.SBOMIterator {
162+
logger.LogDebug(transferCtx.Context, "Checking adapter eligibility for undergoing conversion layer", "adapter type", config.DestinationType)
163+
164+
if types.AdapterType(config.DestinationType) == types.DtrackAdapterType {
165+
logger.LogDebug(transferCtx.Context, "Adapter eligible for conversion layer", "adapter type", config.DestinationType)
166+
167+
logger.LogDebug(transferCtx.Context, "SBOM conversion will take place")
168+
convertedSBOMs := sbomConversion(sbomIterator, *transferCtx)
169+
// Create a new iterator with converted SBOMs
170+
return iterator.NewMemoryIterator(convertedSBOMs)
171+
} else {
172+
173+
logger.LogDebug(transferCtx.Context, "Adapter not eligible for conversion layer", "adapter type", config.DestinationType)
174+
logger.LogDebug(transferCtx.Context, "SBOM conversion will not take place")
175+
return sbomIterator
176+
}
177+
}

pkg/target/dependencytrack/client.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ type Project struct {
5151
func (c *DependencyTrackClient) FindProject(ctx *tcontext.TransferMetadata, projectName, projectVersion string) (string, error) {
5252
logger.LogDebug(ctx.Context, "Finding Project", "project", projectName, "version", projectVersion)
5353

54+
// dtrack client, retrives all projects
5455
projects, err := c.Client.Project.GetAll(ctx.Context, dtrack.PageOptions{})
5556
if err != nil {
5657
return "", err
@@ -59,6 +60,7 @@ func (c *DependencyTrackClient) FindProject(ctx *tcontext.TransferMetadata, proj
5960
logger.LogDebug(ctx.Context, "Total Project Found", "count", projects.TotalCount)
6061

6162
for _, project := range projects.Items {
63+
// lookup for the our project name with version
6264
if project.Name == projectName && project.Version == projectVersion {
6365
logger.LogDebug(ctx.Context, "Project found", "project", projectName, "version", project.Version, "id", project.UUID)
6466
return project.UUID.String(), nil
@@ -71,14 +73,15 @@ func (c *DependencyTrackClient) FindProject(ctx *tcontext.TransferMetadata, proj
7173

7274
// UploadSBOM uploads an SBOM to a Dependency-Track project
7375
func (c *DependencyTrackClient) UploadSBOM(ctx *tcontext.TransferMetadata, projectName, projectVersion string, sbomData []byte) error {
74-
logger.LogDebug(ctx.Context, "Processing Uploading SBOMs to Dependency-Track sequentially", "project", projectName, "version", projectVersion)
76+
logger.LogDebug(ctx.Context, "Processing Uploading SBOMs", "project", projectName, "version", projectVersion)
7577

7678
bomReq := dtrack.BOMUploadRequest{
7779
ProjectName: projectName,
7880
ProjectVersion: projectVersion,
7981
BOM: base64.StdEncoding.EncodeToString(sbomData),
8082
}
8183

84+
// dtrack client will upload SBOM
8285
token, err := c.Client.BOM.Upload(ctx.Context, bomReq)
8386
if err != nil {
8487
return err
@@ -88,20 +91,22 @@ func (c *DependencyTrackClient) UploadSBOM(ctx *tcontext.TransferMetadata, proje
8891
return nil
8992
}
9093

91-
// FindOrCreateProject ensures a project exists, returning its UUID
94+
// FindOrCreateProject ensures a project exists, returning its UUID after finding or creating project
9295
func (c *DependencyTrackClient) FindOrCreateProject(ctx *tcontext.TransferMetadata, projectName, projectVersion string) (string, error) {
9396
logger.LogDebug(ctx.Context, "Finding Project", "project", projectName, "version", projectVersion)
9497

98+
// find project using project name and project version
9599
uuid, err := c.FindProject(ctx, projectName, projectVersion)
96100
if err != nil {
97101
return "", fmt.Errorf("finding project: %w", err)
98102
}
99103
if uuid != "" {
100-
logger.LogDebug(ctx.Context, "Project already exists", "project", projectName, "uuid", uuid)
104+
logger.LogDebug(ctx.Context, "Project already exists, therefor it wouldn't create a new", "project", projectName, "uuid", uuid)
101105
return uuid, nil
102106
}
103-
logger.LogDebug(ctx.Context, "Project doesn't exist", "project", projectName, "version", projectVersion)
107+
logger.LogDebug(ctx.Context, "New project will be created", "project", projectName, "version", projectVersion)
104108

109+
// create project using project name and project version
105110
return c.CreateProject(ctx, projectName, projectVersion)
106111
}
107112

@@ -114,6 +119,7 @@ func (c *DependencyTrackClient) CreateProject(ctx *tcontext.TransferMetadata, pr
114119
Version: projectVersion,
115120
}
116121

122+
// dtrack client will create a new project
117123
created, err := c.Client.Project.Create(ctx.Context, project)
118124
if err != nil {
119125
return "", err

pkg/target/dependencytrack/uploader.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,16 @@ func (u *SequentialUploader) Upload(ctx *tcontext.TransferMetadata, config *Depe
5959
projectName = sbom.Namespace
6060
}
6161

62+
projectVersion := config.ProjectVersion
63+
if projectVersion == "" {
64+
projectVersion = "latest"
65+
}
66+
6267
u.mu.Lock()
6368
if !u.createdProjects[projectName] {
64-
_, err = client.FindOrCreateProject(ctx, projectName, config.ProjectVersion)
69+
70+
// find or create project using project name and project version
71+
_, err = client.FindOrCreateProject(ctx, projectName, projectVersion)
6572
if err != nil {
6673
logger.LogInfo(ctx.Context, "Failed to find or create project", "project", projectName, "error", err)
6774
u.mu.Unlock()
@@ -73,14 +80,14 @@ func (u *SequentialUploader) Upload(ctx *tcontext.TransferMetadata, config *Depe
7380
u.mu.Unlock()
7481

7582
// Log SBOM filename before upload
76-
logger.LogDebug(ctx.Context, "Attempting to upload SBOM", "project", projectName, "file", sbom.Path)
83+
logger.LogDebug(ctx.Context, "Iniatializing uploading SBOM file", "file", sbom.Path)
7784

7885
err = client.UploadSBOM(ctx, projectName, config.ProjectVersion, sbom.Data)
7986
if err != nil {
8087
logger.LogInfo(ctx.Context, "Failed to upload SBOM", "project", projectName, "file", sbom.Path, "error", err)
8188
continue
8289
}
83-
logger.LogDebug(ctx.Context, "Successfully uploaded SBOM", "project", projectName, "file", sbom.Path)
90+
logger.LogDebug(ctx.Context, "Successfully uploaded SBOM file", "file", sbom.Path)
8491
}
8592
return nil
8693
}

0 commit comments

Comments
 (0)