Skip to content

Commit

Permalink
⭐️ Add evidence to compliance controls. (#1246)
Browse files Browse the repository at this point in the history
Signed-off-by: Preslav <[email protected]>
  • Loading branch information
preslavgerchev authored Apr 15, 2024
1 parent 78c55ea commit cb2aa30
Show file tree
Hide file tree
Showing 12 changed files with 1,980 additions and 1,373 deletions.
3 changes: 2 additions & 1 deletion apps/cnspec/cmd/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ func (c *scanConfig) loadPolicies(ctx context.Context) error {
return err
}

bundle.ConvertQuerypacks()
// prepare the bundle for compilation
bundle.Prepare()
conf := mqlc.NewConfig(c.runtime.Schema(), cnquery.DefaultFeatures)

_, err = bundle.CompileExt(ctx, policy.BundleCompileConf{
Expand Down
1 change: 1 addition & 0 deletions cli/reporter/print_compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ func (r *defaultReporter) printAssetControls(resolved *policy.ResolvedPolicy, re
control, ok := controls[score.QrId]
if !ok {
r.out("Couldn't find any controls for " + score.QrId)
r.out(NewLineCharacter)
continue
}

Expand Down
55 changes: 55 additions & 0 deletions internal/bundle/bundle.yac.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions policy/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ func (p *Bundle) ToYAML() ([]byte, error) {
return yaml.Marshal(p)
}

// Prepares the bundle for compilation
func (b *Bundle) Prepare() {
b.ConvertEvidence()
b.ConvertQuerypacks()
}

// ConvertQuerypacks takes any existing querypacks in the bundle
// and turns them into policies for execution by cnspec.
func (p *Bundle) ConvertQuerypacks() {
Expand Down Expand Up @@ -175,6 +181,32 @@ func (p *Bundle) ConvertQuerypacks() {
}
}

func (b *Bundle) ConvertEvidence() {
for _, f := range b.Frameworks {
policies := []*Policy{}
cmaps := []*ControlMap{}
for _, g := range f.Groups {
for _, c := range g.Controls {
evidencePolicies := c.GenerateEvidencePolicies(f.Uid)
policies = append(policies, evidencePolicies...)
controlMap := c.GenerateEvidenceControlMap()
// if the control has evidence, we add the control map
if controlMap != nil {
cmaps = append(cmaps, controlMap)
}
}
}
// we only want a new framework map if there's at least one control map
if len(cmaps) > 0 {
frameworkMap := GenerateFrameworkMap(cmaps, f, policies)
b.FrameworkMaps = append(b.FrameworkMaps, frameworkMap)
}
if len(policies) > 0 {
b.Policies = append(b.Policies, policies...)
}
}
}

func convertQueryPackDocs(q *explorer.QueryPackDocs) *PolicyDocs {
if q == nil {
return nil
Expand Down
21 changes: 21 additions & 0 deletions policy/bundle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,27 @@ func TestBundleCompile_ConvertQueryPacks(t *testing.T) {
require.Equal(t, expectedGrpFilters, bundle.Policies[0].Groups[1].Filters)
}

func TestBundle_ConvertEvidence(t *testing.T) {
bundleLoader := policy.DefaultBundleLoader()
bundle, err := bundleLoader.BundleFromPaths("testdata/evidence.mql.yaml")
require.NotNil(t, bundle)
require.NoError(t, err)

require.Equal(t, 0, len(bundle.Policies))
require.Equal(t, 0, len(bundle.FrameworkMaps))
require.Equal(t, 1, len(bundle.Frameworks))

// the framework in this bundle contains 2 controls with 2 evidences per control
bundle.ConvertEvidence()

// assert that we now have a policy per evidence and one frameworkmap to tie them together
require.Equal(t, 4, len(bundle.Policies))
require.Equal(t, 1, len(bundle.FrameworkMaps))
require.Equal(t, 2, len(bundle.FrameworkMaps[0].Controls))
require.Equal(t, 4, len(bundle.FrameworkMaps[0].PolicyDependencies))
require.Equal(t, 1, len(bundle.Frameworks))
}

func TestBundleCompile_FromQueryPackBundle(t *testing.T) {
// this bundle has both built-in queries and group queries
qBundleStr := `
Expand Down
Loading

0 comments on commit cb2aa30

Please sign in to comment.