Skip to content

Commit

Permalink
🐛 Find variant checks by parent MRN (#1408)
Browse files Browse the repository at this point in the history
* 🐛 Find variant checks by parent MRN

Compliance only knows about parent MRNs and not variant MRNs.
To allow a mapping from compliance control to executed check, we need to store the check with it's parent MRN.


Signed-off-by: Christian Zunker <[email protected]>
  • Loading branch information
czunker authored Sep 9, 2024
1 parent 4be18f5 commit fe8d058
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 15 deletions.
5 changes: 5 additions & 0 deletions policy/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ func BundleExecutionChecksum(policy *Policy, framework *Framework) string {
if framework != nil {
res = res.Add(framework.GraphExecutionChecksum)
}
// So far the checksum only includes the policy and the framework
// It does not change if any of the jobs changes, only if the policy or the framework changes
// To update the resolved policy, when we change how it is generated, change the incoporated version of the resolver
res = res.Add(RESOLVER_VERSION)

return res.String()
}

Expand Down
1 change: 1 addition & 0 deletions policy/reportingjob.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,6 @@ func (r *ReportingJob) RefreshChecksum() {
checksum = checksum.Add(notify[i])
}
}

r.Checksum = checksum.String()
}
40 changes: 36 additions & 4 deletions policy/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/base64"
"encoding/binary"
"math/rand"
"slices"
"sort"
"time"

Expand All @@ -28,6 +29,10 @@ import (

const (
POLICY_SERVICE_NAME = "policy.api.mondoo.com"
// This is used to change the checksum of the resolved policy when we want it to be recalculated
// This can be updated, e.g., when we change how the report jobs are generated
// A change of this string will force an update of all the stored resolved policies
RESOLVER_VERSION = "v2024-08-29"
)

type AssetMutation struct {
Expand Down Expand Up @@ -1160,10 +1165,21 @@ func (cache *policyResolverCache) addCheckJob(ctx context.Context, check *explor
Type: ReportingJob_CHECK,
Mrns: []string{},
}
// We don't track the MRNs for variant queries through the cachem, since variant queries
// We don't track the MRNs for variant queries through the cache, since variant queries
// have no MQL, meaning they get the same code ID
if len(check.Variants) == 0 {
cache.global.codeIdToMrn[check.CodeId] = append(cache.global.codeIdToMrn[check.CodeId], check.Mrn)
// Because we have no variants, we might have to add the MRN of the parent job
if ownerJob != nil && ownerJob.Type == ReportingJob_CHECK && len(ownerJob.Mrns) > 0 {
// We might have variants, where multiple variant queries apply
// Don't save the same MRNs multiple times
for _, mrn := range ownerJob.Mrns {
if slices.Contains(cache.global.codeIdToMrn[check.CodeId], mrn) {
continue
}
cache.global.codeIdToMrn[check.CodeId] = append(cache.global.codeIdToMrn[check.CodeId], mrn)
}
}
}
cache.global.reportingJobsByUUID[uuid] = rj
cache.global.reportingJobsByMsum[check.Checksum] = append(cache.global.reportingJobsByMsum[check.Checksum], rj)
Expand All @@ -1183,12 +1199,14 @@ func (cache *policyResolverCache) addCheckJob(ctx context.Context, check *explor
rj.Notify = append(rj.Notify, ownerJob.Uuid)

if len(check.Variants) != 0 {
// Add parent MRN, so we can later also query the result by the variants parent MRN
// //.../queries/parent-check
// //.../queries/variant-1
rj.Mrns = []string{check.Mrn}
err := cache.addCheckJobVariants(ctx, check, rj)
if err != nil {
log.Error().Err(err).Str("checkMrn", check.Mrn).Msg("failed to add data query variants")
}
// If this is avariant query, its MRN is only the MRN of the check.
rj.Mrns = []string{check.Mrn}
} else {
// we set a placeholder for the execution query, just to indicate it will be added
cache.global.executionQueries[check.Checksum] = nil
Expand Down Expand Up @@ -1255,6 +1273,17 @@ func (cache *policyResolverCache) addDataQueryJob(ctx context.Context, query *ex
// have no MQL, meaning they get the same code ID
if len(query.Variants) == 0 {
cache.global.codeIdToMrn[query.CodeId] = append(cache.global.codeIdToMrn[query.CodeId], query.Mrn)
// Because we have no variants, we might have to add the MRN of the parent job
if ownerJob != nil && ownerJob.Type == ReportingJob_DATA_QUERY && len(ownerJob.Mrns) > 0 {
// We might have variants, where multiple variant queries apply
// Don't save the same MRNs multiple times
for _, mrn := range ownerJob.Mrns {
if slices.Contains(cache.global.codeIdToMrn[query.CodeId], mrn) {
continue
}
cache.global.codeIdToMrn[query.CodeId] = append(cache.global.codeIdToMrn[query.CodeId], mrn)
}
}
}
cache.global.reportingJobsByUUID[uuid] = rj
cache.global.reportingJobsByMsum[query.Checksum] = append(cache.global.reportingJobsByMsum[query.Checksum], rj)
Expand All @@ -1272,11 +1301,14 @@ func (cache *policyResolverCache) addDataQueryJob(ctx context.Context, query *ex
ownerJob.ChildJobs[rj.Uuid] = query.Impact
}
if len(query.Variants) != 0 {
// Add parent MRN, so we can later also query the result by the variants parent MRN
// //.../queries/parent-check
// //.../queries/variant-1
rj.Mrns = []string{query.Mrn}
err := cache.addDataQueryVariants(ctx, query, rj)
if err != nil {
log.Error().Err(err).Str("queryMrn", query.Mrn).Msg("failed to add data query variants")
}
rj.Mrns = []string{query.Mrn}
} else {
// we set a placeholder for the execution query, just to indicate it will be added
cache.global.executionQueries[query.Checksum] = nil
Expand Down
30 changes: 19 additions & 11 deletions policy/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ policies:
require.NoError(t, err)
require.NotNil(t, rp)
require.Len(t, rp.CollectorJob.ReportingJobs, 5)
ignoreJob := rp.CollectorJob.ReportingJobs["8Sis0SvMbtI="]
ignoreJob := rp.CollectorJob.ReportingJobs["q7gxFtwx4zg="]
require.NotNil(t, ignoreJob)
childJob := ignoreJob.ChildJobs["YCeU4NjbMe0="]
childJob := ignoreJob.ChildJobs["GhqR9OVIDVM="]
require.NotNil(t, childJob)
require.Equal(t, explorer.ScoringSystem_IGNORE_SCORE, childJob.Scoring)
})
Expand Down Expand Up @@ -291,12 +291,12 @@ policies:
require.NoError(t, err)
require.NotNil(t, rp)
require.Len(t, rp.CollectorJob.ReportingJobs, 5)
ignoreJob := rp.CollectorJob.ReportingJobs["WVDbd6CWW30="]
ignoreJob := rp.CollectorJob.ReportingJobs["gqNWe4GO+UA="]
require.NotNil(t, ignoreJob)
childJob := ignoreJob.ChildJobs["7Q8ymKH8W5c="]
childJob := ignoreJob.ChildJobs["LrvWHNnWZNQ="]
require.NotNil(t, childJob)
require.Equal(t, explorer.ScoringSystem_IGNORE_SCORE, childJob.Scoring)
activeJob := rp.CollectorJob.ReportingJobs["/w4u/z6FEsI="]
activeJob := rp.CollectorJob.ReportingJobs["+KeXN9zwDzA="]
require.NotNil(t, activeJob)
require.Equal(t, explorer.ScoringSystem_BANDED, activeJob.ScoringSystem)
})
Expand Down Expand Up @@ -1717,13 +1717,15 @@ queries:
}
// scoring queries report by code id
require.NotNil(t, qrIdToRj[b.Queries[1].CodeId])
require.Len(t, qrIdToRj[b.Queries[1].CodeId].Mrns, 2)
require.Len(t, qrIdToRj[b.Queries[1].CodeId].Mrns, 3)
require.Equal(t, queryMrn("variant1"), qrIdToRj[b.Queries[1].CodeId].Mrns[0])
require.Equal(t, queryMrn("variant2"), qrIdToRj[b.Queries[1].CodeId].Mrns[1])
require.Equal(t, queryMrn("check-variants"), qrIdToRj[b.Queries[1].CodeId].Mrns[1])
require.Equal(t, queryMrn("variant2"), qrIdToRj[b.Queries[1].CodeId].Mrns[2])

require.Len(t, qrIdToRj[b.Queries[2].CodeId].Mrns, 2)
require.Len(t, qrIdToRj[b.Queries[2].CodeId].Mrns, 3)
require.Equal(t, queryMrn("variant1"), qrIdToRj[b.Queries[2].CodeId].Mrns[0])
require.Equal(t, queryMrn("variant2"), qrIdToRj[b.Queries[2].CodeId].Mrns[1])
require.Equal(t, queryMrn("check-variants"), qrIdToRj[b.Queries[2].CodeId].Mrns[1])
require.Equal(t, queryMrn("variant2"), qrIdToRj[b.Queries[2].CodeId].Mrns[2])
})
}

Expand Down Expand Up @@ -1889,7 +1891,10 @@ queries:

rj = qrIdToRj["//test.sth/queries/windows-uname"]
require.NotNil(t, rj)
assert.ElementsMatch(t, []string{"//test.sth/queries/windows-uname"}, rj.Mrns)
assert.ElementsMatch(t, []string{
"//test.sth/queries/windows-uname",
"//test.sth/queries/uname",
}, rj.Mrns)
})

t.Run("resolve variant checks", func(t *testing.T) {
Expand All @@ -1899,6 +1904,9 @@ queries:

rj = qrIdToRj["eUdVwVDNIGA="]
require.NotNil(t, rj)
assert.ElementsMatch(t, []string{"//test.sth/queries/check-os-windows"}, rj.Mrns)
assert.ElementsMatch(t, []string{
"//test.sth/queries/check-os-windows",
"//test.sth/queries/check-os",
}, rj.Mrns)
})
}

0 comments on commit fe8d058

Please sign in to comment.