Skip to content

Commit f856daa

Browse files
committed
feat(spec1-5): add support for formulation
Signed-off-by: nscuro <[email protected]>
1 parent 2fbde0e commit f856daa

10 files changed

+1615
-41
lines changed

convert.go

+5
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func (b *BOM) convert(specVersion SpecVersion) {
5050
}
5151
if specVersion < SpecVersion1_5 {
5252
b.Annotations = nil
53+
b.Formulation = nil
5354
}
5455

5556
if b.Metadata != nil {
@@ -389,9 +390,13 @@ func (sv SpecVersion) supportsExternalReferenceType(ert ExternalReferenceType) b
389390
ERTypeCertificationReport,
390391
ERTypeCodifiedInfrastructure,
391392
ERTypeComponentAnalysisReport,
393+
ERTypeConfiguration,
392394
ERTypeDistributionIntake,
393395
ERTypeDynamicAnalysisReport,
396+
ERTypeEvidence,
394397
ERTypeExploitabilityStatement,
398+
ERTypeFormulation,
399+
ERTypeLog,
395400
ERTypeMaturityReport,
396401
ERTypeModelCard,
397402
ERTypePentestReport,

cyclonedx.go

+214
Large diffs are not rendered by default.

cyclonedx_json.go

+39
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,47 @@ package cyclonedx
1919

2020
import (
2121
"encoding/json"
22+
"errors"
2223
)
2324

25+
func (ev EnvironmentVariableChoice) MarshalJSON() ([]byte, error) {
26+
if ev.Property != nil && *ev.Property != (Property{}) {
27+
return json.Marshal(ev.Property)
28+
} else if ev.Value != "" {
29+
return json.Marshal(ev.Value)
30+
}
31+
32+
return []byte("{}"), nil
33+
}
34+
35+
func (ev *EnvironmentVariableChoice) UnmarshalJSON(bytes []byte) error {
36+
var property Property
37+
err := json.Unmarshal(bytes, &property)
38+
if err != nil {
39+
var ute *json.UnmarshalTypeError
40+
if !errors.As(err, &ute) || ute.Value != "string" {
41+
return err
42+
}
43+
}
44+
45+
if property != (Property{}) {
46+
ev.Property = &property
47+
return nil
48+
}
49+
50+
var value string
51+
err = json.Unmarshal(bytes, &value)
52+
if err != nil {
53+
var ute *json.UnmarshalTypeError
54+
if !errors.As(err, &ute) || ute.Value != "object" {
55+
return err
56+
}
57+
}
58+
59+
ev.Value = value
60+
return nil
61+
}
62+
2463
type mlDatasetChoiceRefJSON struct {
2564
Ref string `json:"ref" xml:"-"`
2665
}

cyclonedx_json_test.go

+68
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,74 @@ import (
2323
"testing"
2424
)
2525

26+
func TestEnvironmentVariableChoice_MarshalJSON(t *testing.T) {
27+
t.Run("Empty", func(t *testing.T) {
28+
choice := EnvironmentVariableChoice{}
29+
jsonBytes, err := json.Marshal(choice)
30+
require.NoError(t, err)
31+
require.Equal(t, "{}", string(jsonBytes))
32+
})
33+
34+
t.Run("WithProperty", func(t *testing.T) {
35+
choice := EnvironmentVariableChoice{
36+
Property: &Property{
37+
Name: "foo",
38+
Value: "bar",
39+
},
40+
}
41+
jsonBytes, err := json.Marshal(choice)
42+
require.NoError(t, err)
43+
require.Equal(t, `{"name":"foo","value":"bar"}`, string(jsonBytes))
44+
})
45+
46+
t.Run("WithValue", func(t *testing.T) {
47+
choice := EnvironmentVariableChoice{Value: "foo"}
48+
jsonBytes, err := json.Marshal(choice)
49+
require.NoError(t, err)
50+
require.Equal(t, `"foo"`, string(jsonBytes))
51+
})
52+
53+
t.Run("WithPropertyAndValue", func(t *testing.T) {
54+
choice := EnvironmentVariableChoice{
55+
Property: &Property{
56+
Name: "foo",
57+
Value: "bar",
58+
},
59+
Value: "baz",
60+
}
61+
jsonBytes, err := json.Marshal(choice)
62+
require.NoError(t, err)
63+
require.Equal(t, `{"name":"foo","value":"bar"}`, string(jsonBytes))
64+
})
65+
}
66+
67+
func TestEnvironmentVariableChoice_UnmarshalJSON(t *testing.T) {
68+
t.Run("Empty", func(t *testing.T) {
69+
var choice EnvironmentVariableChoice
70+
err := json.Unmarshal([]byte(`{}`), &choice)
71+
require.NoError(t, err)
72+
require.Equal(t, EnvironmentVariableChoice{}, choice)
73+
})
74+
75+
t.Run("WithProperty", func(t *testing.T) {
76+
var choice EnvironmentVariableChoice
77+
err := json.Unmarshal([]byte(`{"name":"foo","value":"bar"}`), &choice)
78+
require.NoError(t, err)
79+
require.NotNil(t, choice.Property)
80+
require.Equal(t, "foo", choice.Property.Name)
81+
require.Equal(t, "bar", choice.Property.Value)
82+
require.Empty(t, choice.Value)
83+
})
84+
85+
t.Run("WithValue", func(t *testing.T) {
86+
var choice EnvironmentVariableChoice
87+
err := json.Unmarshal([]byte(`"foo"`), &choice)
88+
require.NoError(t, err)
89+
require.Nil(t, choice.Property)
90+
require.Equal(t, "foo", choice.Value)
91+
})
92+
}
93+
2694
func TestMLDatasetChoice_MarshalJSON(t *testing.T) {
2795
t.Run("Empty", func(t *testing.T) {
2896
choice := MLDatasetChoice{}

cyclonedx_xml.go

+69
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,75 @@ func (d *Dependency) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) erro
9797
return nil
9898
}
9999

100+
func (ev EnvironmentVariables) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
101+
if len(ev) == 0 {
102+
return nil
103+
}
104+
105+
err := e.EncodeToken(start)
106+
if err != nil {
107+
return err
108+
}
109+
110+
for _, choice := range ev {
111+
if choice.Property != nil && choice.Value != "" {
112+
return fmt.Errorf("either property or value must be set, but not both")
113+
}
114+
115+
if choice.Property != nil {
116+
err = e.EncodeElement(choice.Property, xml.StartElement{Name: xml.Name{Local: "environmentVar"}})
117+
if err != nil {
118+
return err
119+
}
120+
} else if choice.Value != "" {
121+
err = e.EncodeElement(choice.Value, xml.StartElement{Name: xml.Name{Local: "value"}})
122+
if err != nil {
123+
return err
124+
}
125+
}
126+
}
127+
128+
return e.EncodeToken(start.End())
129+
}
130+
131+
func (ev *EnvironmentVariables) UnmarshalXML(d *xml.Decoder, _ xml.StartElement) error {
132+
envVars := make([]EnvironmentVariableChoice, 0)
133+
134+
for {
135+
token, err := d.Token()
136+
if err != nil {
137+
if errors.Is(err, io.EOF) {
138+
break
139+
}
140+
return err
141+
}
142+
143+
switch tokenType := token.(type) {
144+
case xml.StartElement:
145+
if tokenType.Name.Local == "value" {
146+
var value string
147+
err = d.DecodeElement(&value, &tokenType)
148+
if err != nil {
149+
return err
150+
}
151+
envVars = append(envVars, EnvironmentVariableChoice{Value: value})
152+
} else if tokenType.Name.Local == "environmentVar" {
153+
var property Property
154+
err = d.DecodeElement(&property, &tokenType)
155+
if err != nil {
156+
return err
157+
}
158+
envVars = append(envVars, EnvironmentVariableChoice{Property: &property})
159+
} else {
160+
return fmt.Errorf("unknown element: %s", tokenType.Name.Local)
161+
}
162+
}
163+
}
164+
165+
*ev = envVars
166+
return nil
167+
}
168+
100169
func (l Licenses) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
101170
if len(l) == 0 {
102171
return nil

0 commit comments

Comments
 (0)