Skip to content

Commit

Permalink
pkg: add 'sbom' package for working with SBOM documents
Browse files Browse the repository at this point in the history
Add a new `sbom` package for working with SBOM documents. It provides a
very simple wrapper struct, which currently supports only SPDX standard.
The SBOM document is for now stored in a raw JSON form, to not have to
convert the raw data from and to the specific in-memory representation
on the worker.

The idea is to provide a bit of an abstraction from the specific SBOM
implementation, so that in the future, it would be possible to create
`sbom.Document` from SBOM documents of various standards and also
serialize it back to various SBOM standards.

Signed-off-by: Tomáš Hozza <[email protected]>
  • Loading branch information
thozza committed Sep 13, 2024
1 parent d909018 commit 32fc171
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
70 changes: 70 additions & 0 deletions pkg/sbom/document.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package sbom

import (
"encoding/json"
"fmt"
)

type StandardType uint64

const (
StandardTypeNone StandardType = iota
StandardTypeSpdx
)

func (t StandardType) String() string {
switch t {
case StandardTypeNone:
return "none"
case StandardTypeSpdx:
return "spdx"
default:
panic("invalid standard type")
}
}

func (t StandardType) MarshalJSON() ([]byte, error) {
var s string

if t == StandardTypeNone {
s = ""
} else {
s = t.String()
}

return json.Marshal(s)
}

func (t *StandardType) UnmarshalJSON(data []byte) error {
switch string(data) {
case `""`:
*t = StandardTypeNone
case `"spdx"`:
*t = StandardTypeSpdx
default:
return fmt.Errorf("invalid SBOM standard type: %s", data)
}
return nil
}

type Document struct {
// type of the document standard
DocType StandardType

// document in a specific standard JSON raw format
Document json.RawMessage
}

func NewDocument(docType StandardType, doc json.RawMessage) (*Document, error) {
switch docType {
case StandardTypeSpdx:
docType = StandardTypeSpdx
default:
return nil, fmt.Errorf("unsupported SBOM document type: %s", docType)
}

return &Document{
DocType: docType,
Document: doc,
}, nil
}
86 changes: 86 additions & 0 deletions pkg/sbom/document_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package sbom

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/assert"
)

func TestStandardTypeJSONUnmarhsall(t *testing.T) {
type testStruct struct {
Type StandardType `json:"type"`
TypeOmit StandardType `json:"type_omit,omitempty"`
}

tests := []struct {
name string
data []byte
want testStruct
}{
{
name: "StandardTypeNone",
data: []byte(`{"type":""}`),
want: testStruct{
Type: StandardTypeNone,
TypeOmit: StandardTypeNone,
},
},
{
name: "StandardTypeSpdx",
data: []byte(`{"type":"spdx","type_omit":"spdx"}`),
want: testStruct{
Type: StandardTypeSpdx,
TypeOmit: StandardTypeSpdx,
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var ts testStruct
err := json.Unmarshal(tt.data, &ts)
assert.NoError(t, err)
assert.Equal(t, tt.want, ts)
})
}
}

func TestStandardTypeJSONMarhsall(t *testing.T) {
type TestStruct struct {
Type StandardType `json:"type"`
TypeOmit StandardType `json:"type_omit,omitempty"`
}

tests := []struct {
name string
want []byte
data TestStruct
}{
{
name: "StandardTypeNone",
want: []byte(`{"type":""}`),
data: TestStruct{
Type: StandardTypeNone,
TypeOmit: StandardTypeNone,
},
},
{
name: "StandardTypeSpdx",
want: []byte(`{"type":"spdx","type_omit":"spdx"}`),
data: TestStruct{
Type: StandardTypeSpdx,
TypeOmit: StandardTypeSpdx,
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var got []byte
got, err := json.Marshal(tt.data)
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}

0 comments on commit 32fc171

Please sign in to comment.