-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
pkg: add 'sbom' package for working with SBOM documents
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 <thozza@redhat.com>
- Loading branch information
1 parent
15fa86a
commit 5a54d0a
Showing
2 changed files
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
}) | ||
} | ||
} |