Skip to content

Commit

Permalink
🐛 make sure reporting job mrns work correctly for variants (#1398)
Browse files Browse the repository at this point in the history
Signed-off-by: Ivan Milchev <ivan@mondoo.com>
  • Loading branch information
imilchev authored Aug 8, 2024
1 parent 99a4fa1 commit 56ca809
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 17 deletions.
43 changes: 26 additions & 17 deletions policy/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,6 @@ func (s *LocalServices) mergeRisk(cache *resolverCache, riskFactor *RiskFactor)

if riskFactor.Action != explorer.Action_UNSPECIFIED {
existing.Action = riskFactor.Action

}
} else {
cache.riskFactors[riskFactor.Mrn] = riskFactor
Expand Down Expand Up @@ -1161,7 +1160,11 @@ func (cache *policyResolverCache) addCheckJob(ctx context.Context, check *explor
Type: ReportingJob_CHECK,
Mrns: []string{},
}
cache.global.codeIdToMrn[check.CodeId] = append(cache.global.codeIdToMrn[check.CodeId], check.Mrn)
// We don't track the MRNs for variant queries through the cachem, 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)
}
cache.global.reportingJobsByUUID[uuid] = rj
cache.global.reportingJobsByMsum[check.Checksum] = append(cache.global.reportingJobsByMsum[check.Checksum], rj)
cache.childJobsByMrn[check.Mrn] = append(cache.childJobsByMrn[check.Mrn], rj)
Expand All @@ -1172,13 +1175,6 @@ func (cache *policyResolverCache) addCheckJob(ctx context.Context, check *explor
}
cache.global.reportingJobsByCodeId[check.CodeId] = append(cache.global.reportingJobsByCodeId[check.CodeId], rj)

// Add the MRN to all the reporting jobs with the same codeID
// This is used to track all the MRNs
for _, job := range cache.global.reportingJobsByCodeId[check.CodeId] {
// Set the MRNs to all the MRNs we collected so far
job.Mrns = cache.global.codeIdToMrn[check.CodeId]
}

if ownerJob.ChildJobs[rj.Uuid] == nil {
ownerJob.ChildJobs[rj.Uuid] = impact
}
Expand All @@ -1191,10 +1187,19 @@ func (cache *policyResolverCache) addCheckJob(ctx context.Context, check *explor
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
cache.global.queriesByMsum[check.Checksum] = check

// Add the MRN to all the reporting jobs with the same codeID
// This is used to track all the MRNs
for _, job := range cache.global.reportingJobsByCodeId[check.CodeId] {
// Set the MRNs to all the MRNs we collected so far
job.Mrns = cache.global.codeIdToMrn[check.CodeId]
}
}
}

Expand Down Expand Up @@ -1246,7 +1251,11 @@ func (cache *policyResolverCache) addDataQueryJob(ctx context.Context, query *ex
// FIXME: DEPRECATED, remove in v10.0 vv
DeprecatedV8IsData: true,
}
cache.global.codeIdToMrn[query.CodeId] = append(cache.global.codeIdToMrn[query.CodeId], query.Mrn)
// We don't track the MRNs for variant queries through the cachem, since variant queries
// 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)
}
cache.global.reportingJobsByUUID[uuid] = rj
cache.global.reportingJobsByMsum[query.Checksum] = append(cache.global.reportingJobsByMsum[query.Checksum], rj)
cache.childJobsByMrn[query.Mrn] = append(cache.childJobsByMrn[query.Mrn], rj)
Expand All @@ -1257,13 +1266,6 @@ func (cache *policyResolverCache) addDataQueryJob(ctx context.Context, query *ex
}
cache.global.reportingJobsByCodeId[query.CodeId] = append(cache.global.reportingJobsByCodeId[query.CodeId], rj)

// Add the MRN to all the reporting jobs with the same codeID
// This is used to track all the MRNs
for _, job := range cache.global.reportingJobsByCodeId[query.CodeId] {
// Set the MRNs to all the MRNs we collected so far
job.Mrns = cache.global.codeIdToMrn[query.CodeId]
}

// local aspects for the resolved policy
rj.Notify = append(rj.Notify, ownerJob.Uuid)
if ownerJob.ChildJobs[rj.Uuid] == nil {
Expand All @@ -1274,11 +1276,18 @@ func (cache *policyResolverCache) addDataQueryJob(ctx context.Context, query *ex
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
cache.global.dataQueries[query.Checksum] = struct{}{}
cache.global.queriesByMsum[query.Checksum] = query
// Add the MRN to all the reporting jobs with the same codeID
// This is used to track all the MRNs
for _, job := range cache.global.reportingJobsByCodeId[query.CodeId] {
// Set the MRNs to all the MRNs we collected so far
job.Mrns = cache.global.codeIdToMrn[query.CodeId]
}
}
}

Expand Down
89 changes: 89 additions & 0 deletions policy/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1805,3 +1805,92 @@ policies:

require.Equal(t, float32(0.9), rp.CollectorJob.RiskFactors["//test.sth/risks/sshd-service"].Magnitude.GetValue())
}

func TestResolve_Variants(t *testing.T) {
b := parseBundle(t, `
owner_mrn: //test.sth
policies:
- uid: example2
name: Another policy
version: "1.0.0"
groups:
# Additionally it defines some queries of its own
- type: chapter
title: Some uname infos
queries:
# In this case, we are using a shared query that is defined below
- uid: uname
checks:
- uid: check-os
variants:
- uid: check-os-unix
- uid: check-os-windows
queries:
# This is a composed query which has two variants: one for unix type systems
# and one for windows, where we don't run the additional argument.
# If you run the "uname" query, it will pick matching sub-queries for you.
- uid: uname
title: Collect uname info
variants:
- uid: unix-uname
- uid: windows-uname
- uid: unix-uname
mql: command("uname -a").stdout
filters: asset.family.contains("unix")
- uid: windows-uname
mql: command("uname").stdout
filters: asset.family.contains("windows")
- uid: check-os-unix
filters: asset.family.contains("unix")
title: A check only run on Linux/macOS
mql: users.contains(name == "root")
- uid: check-os-windows
filters: asset.family.contains("windows")
title: A check only run on Windows
mql: users.contains(name == "Administrator")`)

srv := initResolver(t, []*testAsset{
{asset: "asset1", policies: []string{policyMrn("example2")}},
}, []*policy.Bundle{b})

ctx := context.Background()
_, err := srv.SetBundle(ctx, b)
require.NoError(t, err)

_, err = b.Compile(context.Background(), conf.Schema, nil)
require.NoError(t, err)

rp, err := srv.Resolve(context.Background(), &policy.ResolveReq{
PolicyMrn: policyMrn("example2"),
AssetFilters: []*explorer.Mquery{{Mql: "asset.family.contains(\"windows\")"}},
})

require.NoError(t, err)
require.NotNil(t, rp)
qrIdToRj := map[string]*policy.ReportingJob{}
for _, rj := range rp.CollectorJob.ReportingJobs {
qrIdToRj[rj.QrId] = rj
}

t.Run("resolve variant data queries", func(t *testing.T) {
rj := qrIdToRj["//test.sth/queries/uname"]
require.NotNil(t, rj)
assert.ElementsMatch(t, []string{"//test.sth/queries/uname"}, rj.Mrns)

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

t.Run("resolve variant checks", func(t *testing.T) {
rj := qrIdToRj["//test.sth/queries/check-os"]
require.NotNil(t, rj)
assert.ElementsMatch(t, []string{"//test.sth/queries/check-os"}, rj.Mrns)

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

0 comments on commit 56ca809

Please sign in to comment.