Skip to content

Commit d35bb1d

Browse files
authored
Merge branch 'main' into dependabot/go_modules/github.com/stretchr/testify-1.10.0
2 parents 179cca2 + cb3a443 commit d35bb1d

21 files changed

+1140
-114
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Use LF line endings
2+
* text eol=lf

.github/workflows/openssf.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
with:
3333
persist-credentials: false
3434
- name: "Run analysis"
35-
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
35+
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
3636
with:
3737
results_file: results.sarif
3838
results_format: sarif

extensions/props.go

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
Copyright 2024 The OSCAL Compass Authors
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package extensions
7+
8+
import (
9+
"strings"
10+
11+
oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"
12+
)
13+
14+
// TrestleNameSpace is the generic namespace for trestle-defined property extensions.
15+
const TrestleNameSpace = "https://oscal-compass.github.io/compliance-trestle/schemas/oscal"
16+
17+
// Below are defined oscal.Property names for compass-based extensions.
18+
const (
19+
// RuleIdProp represents the property name for Rule ids.
20+
RuleIdProp = "Rule_Id"
21+
// RuleDescriptionProp represents the property name for Rule descriptions.
22+
RuleDescriptionProp = "Rule_Description"
23+
// CheckIdProp represents the property name for Check ids.
24+
CheckIdProp = "Check_Id"
25+
// CheckDescriptionProp represents the property name for Check descriptions.
26+
CheckDescriptionProp = "Check_Description"
27+
// ParameterIdProp represents the property name for Parameter ids.
28+
ParameterIdProp = "Parameter_Id"
29+
// ParameterDescriptionProp represents the property name for Parameter descriptions.
30+
ParameterDescriptionProp = "Parameter_Description"
31+
// ParameterDefaultProp represents the property name for Parameter default selected values.
32+
ParameterDefaultProp = "Parameter_Value_Default"
33+
// FrameworkProp represents the property name for the control source short name.
34+
FrameworkProp = "Framework_Short_Name"
35+
)
36+
37+
// FindAllProps returns all properties with the given name. If no properties match, nil is returned.
38+
// This function also implicitly checks that the property is a trestle-defined property in the namespace.
39+
func FindAllProps(name string, props []oscalTypes.Property) []oscalTypes.Property {
40+
var matchingProps []oscalTypes.Property
41+
for _, prop := range props {
42+
if prop.Name == name && strings.Contains(prop.Ns, TrestleNameSpace) {
43+
matchingProps = append(matchingProps, prop)
44+
}
45+
}
46+
return matchingProps
47+
}
48+
49+
// GetTrestleProp returned the first property matching the given name and a match is found.
50+
// This function also implicitly checks that the property is a trestle-defined property in the namespace.
51+
func GetTrestleProp(name string, props []oscalTypes.Property) (oscalTypes.Property, bool) {
52+
for _, prop := range props {
53+
if prop.Name == name && strings.Contains(prop.Ns, TrestleNameSpace) {
54+
return prop, true
55+
}
56+
}
57+
return oscalTypes.Property{}, false
58+
}

extensions/props_test.go

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/*
2+
Copyright 2024 The OSCAL Compass Authors
3+
SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package extensions
7+
8+
import (
9+
"testing"
10+
11+
oscalTypes "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func TestGetTrestleProp(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
inputProps []oscalTypes.Property
19+
inputName string
20+
wantProp oscalTypes.Property
21+
wantFound bool
22+
}{
23+
{
24+
name: "Valid/PropFound",
25+
inputName: "testProp1",
26+
inputProps: []oscalTypes.Property{
27+
{
28+
Name: "testProp1",
29+
Value: "testValue",
30+
},
31+
{
32+
Name: "testProp1",
33+
Value: "testValue",
34+
Ns: TrestleNameSpace,
35+
},
36+
},
37+
wantProp: oscalTypes.Property{
38+
Name: "testProp1",
39+
Value: "testValue",
40+
Ns: TrestleNameSpace,
41+
Group: "",
42+
Class: "",
43+
Remarks: "",
44+
},
45+
wantFound: true,
46+
},
47+
{
48+
name: "Valid/PropNotFound",
49+
inputName: "testProp",
50+
inputProps: []oscalTypes.Property{
51+
{
52+
Name: "testProp1",
53+
Value: "testValue",
54+
},
55+
{
56+
Name: "testProp2",
57+
Value: "testValue",
58+
Ns: TrestleNameSpace,
59+
},
60+
},
61+
wantProp: oscalTypes.Property{},
62+
wantFound: false,
63+
},
64+
{
65+
name: "Valid/PropNotFoundNs",
66+
inputName: "testProp1",
67+
inputProps: []oscalTypes.Property{
68+
{
69+
Name: "testProp1",
70+
Value: "testValue",
71+
},
72+
{
73+
Name: "testProp2",
74+
Value: "testValue",
75+
},
76+
},
77+
wantProp: oscalTypes.Property{},
78+
wantFound: false,
79+
},
80+
}
81+
82+
for _, c := range tests {
83+
t.Run(c.name, func(t *testing.T) {
84+
foundProp, found := GetTrestleProp(c.inputName, c.inputProps)
85+
require.Equal(t, c.wantProp, foundProp)
86+
require.Equal(t, c.wantFound, found)
87+
})
88+
}
89+
}
90+
91+
func TestFindAllProps(t *testing.T) {
92+
tests := []struct {
93+
name string
94+
inputName string
95+
inputProps []oscalTypes.Property
96+
wantProps []oscalTypes.Property
97+
}{
98+
{
99+
name: "Valid/PropsFound",
100+
inputName: "testProp1",
101+
inputProps: []oscalTypes.Property{
102+
{
103+
Name: "testProp1",
104+
Value: "testValue1",
105+
Ns: TrestleNameSpace,
106+
},
107+
{
108+
Name: "testProp1",
109+
Value: "testValue2",
110+
Ns: TrestleNameSpace,
111+
},
112+
{
113+
Name: "testProp1",
114+
Value: "testValue3",
115+
},
116+
},
117+
wantProps: []oscalTypes.Property{
118+
{
119+
Name: "testProp1",
120+
Value: "testValue1",
121+
Ns: TrestleNameSpace,
122+
Group: "",
123+
Class: "",
124+
Remarks: "",
125+
},
126+
{
127+
Name: "testProp1",
128+
Value: "testValue2",
129+
Ns: TrestleNameSpace,
130+
Group: "",
131+
Class: "",
132+
Remarks: "",
133+
},
134+
},
135+
},
136+
{
137+
name: "Valid/NoPropsFound",
138+
inputName: "testProp3",
139+
inputProps: []oscalTypes.Property{
140+
{
141+
Name: "testProp1",
142+
Value: "testValue1",
143+
Ns: TrestleNameSpace,
144+
},
145+
{
146+
Name: "testProp1",
147+
Value: "testValue2",
148+
Ns: TrestleNameSpace,
149+
},
150+
{
151+
Name: "testProp1",
152+
Value: "testValue3",
153+
Ns: TrestleNameSpace,
154+
},
155+
},
156+
wantProps: []oscalTypes.Property(nil),
157+
},
158+
}
159+
160+
for _, c := range tests {
161+
t.Run(c.name, func(t *testing.T) {
162+
foundProps := FindAllProps(c.inputName, c.inputProps)
163+
require.Equal(t, c.wantProps, foundProps)
164+
})
165+
}
166+
}

extensions/rules.go

-11
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,6 @@
55

66
package extensions
77

8-
// Below are defined oscal.Property names for compass-based extensions.
9-
const (
10-
RuleIdProp = "Rule_Id"
11-
RuleDescriptionProp = "Rule_Description"
12-
CheckIdProp = "Check_Id"
13-
CheckDescriptionProp = "Check_Description"
14-
ParameterIdProp = "Parameter_Id"
15-
ParameterDescriptionProp = "Parameter_Description"
16-
ParameterDefaultProp = "Parameter_Value_Default"
17-
)
18-
198
// RuleSet defines a Rule instance with associated
209
// Check implementation data.
2110
type RuleSet struct {

rules/internal/set.go internal/set/set.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package internal
6+
package set
77

88
// Set represents a set data structure.
99
type Set[T comparable] map[T]struct{}
1010

11-
// NewSet returns an initialized set.
12-
func NewSet[T comparable]() Set[T] {
11+
// New NewSet returns an initialized set.
12+
func New[T comparable]() Set[T] {
1313
return make(Set[T])
1414
}
1515

@@ -23,3 +23,15 @@ func (s Set[T]) Has(item T) bool {
2323
_, ok := s[item]
2424
return ok
2525
}
26+
27+
// Intersect returns a new Set representing the intersection
28+
// between two sets.
29+
func (s Set[T]) Intersect(other Set[T]) Set[T] {
30+
newSet := New[T]()
31+
for elem := range s {
32+
if _, ok := other[elem]; ok {
33+
newSet.Add(elem)
34+
}
35+
}
36+
return newSet
37+
}

rules/memory.go

+23-31
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
oscal112 "github.com/defenseunicorns/go-oscal/src/types/oscal-1-1-2"
1414

1515
"github.com/oscal-compass/oscal-sdk-go/extensions"
16-
. "github.com/oscal-compass/oscal-sdk-go/rules/internal"
16+
"github.com/oscal-compass/oscal-sdk-go/internal/set"
1717
)
1818

1919
var (
@@ -27,10 +27,8 @@ var (
2727
ErrComponentsNotFound = errors.New("no components not found")
2828
)
2929

30-
/*
31-
MemoryStore provides implementation of a memory-based rule.Store.
32-
WARNING: This implementation is not thread safe.
33-
*/
30+
// MemoryStore implements the Store interface using an in-memory map-based data structure.
31+
// WARNING: This implementation is not thread safe.
3432
type MemoryStore struct {
3533
// nodes saves the rule ID map keys, which are used with
3634
// the other fields.
@@ -44,48 +42,50 @@ type MemoryStore struct {
4442

4543
// rulesByComponent stores the component title of any component
4644
// mapped to any relevant rules.
47-
rulesByComponent map[string]Set[string]
45+
rulesByComponent map[string]set.Set[string]
4846
// checksByValidationComponent store checkId mapped to validation
4947
// component title to filter check information on rules.
50-
checksByValidationComponent map[string]Set[string]
48+
checksByValidationComponent map[string]set.Set[string]
5149
}
5250

53-
// NewMemoryStoreFromComponents creates a new memory-based rule finder.
54-
func NewMemoryStoreFromComponents(components []oscal112.DefinedComponent) (*MemoryStore, error) {
55-
if len(components) == 0 {
56-
return nil, fmt.Errorf("failed to create memory store from components: %w", ErrComponentsNotFound)
57-
}
58-
store := &MemoryStore{
51+
// NewMemoryStore creates a new memory-based Store.
52+
func NewMemoryStore() *MemoryStore {
53+
return &MemoryStore{
5954
nodes: make(map[string]extensions.RuleSet),
6055
byCheck: make(map[string]string),
61-
rulesByComponent: make(map[string]Set[string]),
62-
checksByValidationComponent: make(map[string]Set[string]),
56+
rulesByComponent: make(map[string]set.Set[string]),
57+
checksByValidationComponent: make(map[string]set.Set[string]),
6358
}
59+
}
6460

61+
// IndexAll indexes rule information from OSCAL Components.
62+
func (m *MemoryStore) IndexAll(components []oscal112.DefinedComponent) error {
63+
if len(components) == 0 {
64+
return fmt.Errorf("failed to index components: %w", ErrComponentsNotFound)
65+
}
6566
for _, component := range components {
66-
extractedRules := store.indexComponent(component)
67+
extractedRules := m.indexComponent(component)
6768
if len(extractedRules) != 0 {
68-
store.rulesByComponent[component.Title] = extractedRules
69+
m.rulesByComponent[component.Title] = extractedRules
6970
}
7071
}
71-
72-
return store, nil
72+
return nil
7373
}
7474

75-
func (m *MemoryStore) indexComponent(component oscal112.DefinedComponent) Set[string] {
76-
rules := NewSet[string]()
75+
func (m *MemoryStore) indexComponent(component oscal112.DefinedComponent) set.Set[string] {
76+
rules := set.New[string]()
7777
if component.Props == nil {
7878
return rules
7979
}
8080

8181
// Catalog all registered check implementations by validation component for filtering in
8282
// `rules.FindByComponent`.
83-
checkIds := NewSet[string]()
83+
checkIds := set.New[string]()
8484

8585
// Each rule set is linked by a group id in the property remarks
8686
byRemarks := groupPropsByRemarks(*component.Props)
8787
for _, propSet := range byRemarks {
88-
ruleIdProp, ok := findProp(extensions.RuleIdProp, propSet)
88+
ruleIdProp, ok := getProp(extensions.RuleIdProp, propSet)
8989
if !ok {
9090
continue
9191
}
@@ -193,11 +193,3 @@ func (m *MemoryStore) FindByComponent(ctx context.Context, componentId string) (
193193

194194
return ruleSets, nil
195195
}
196-
197-
func (m *MemoryStore) All(ctx context.Context) ([]extensions.RuleSet, error) {
198-
var ruleSets []extensions.RuleSet
199-
for _, rule := range m.nodes {
200-
ruleSets = append(ruleSets, rule)
201-
}
202-
return ruleSets, nil
203-
}

0 commit comments

Comments
 (0)