diff --git a/pkg/sbom/document.go b/pkg/sbom/document.go new file mode 100644 index 000000000..8d4dd2c96 --- /dev/null +++ b/pkg/sbom/document.go @@ -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 +} diff --git a/pkg/sbom/document_test.go b/pkg/sbom/document_test.go new file mode 100644 index 000000000..b60fe4384 --- /dev/null +++ b/pkg/sbom/document_test.go @@ -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) + }) + } +}