Skip to content

Commit f931f91

Browse files
committed
feat: Reduced mutations payload
1 parent 55dd5e7 commit f931f91

File tree

9 files changed

+78
-26
lines changed

9 files changed

+78
-26
lines changed

src/plugins/policyPack/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ export default class PolicyPackPlugin extends Plugin {
321321
})
322322

323323
// Prepare mutations
324-
const mutations = engine.prepareMutations(findings)
324+
const mutations = engine.prepareMutations(findings, rules)
325325

326326
// Save connections
327327
processConnectionsBetweenEntities({

src/rules-engine/data-processors/data-processor.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Entity } from '../../types'
2-
import { RuleFinding } from '../types'
2+
import { Rule, RuleFinding } from '../types'
33

44
export default interface DataProcessor {
55
readonly typenameToFieldMap: { [typeName: string]: string }
@@ -17,5 +17,12 @@ export default interface DataProcessor {
1717
* @param findings resulted findings during rules execution
1818
* @returns {Entity[]} Array of generated mutations
1919
*/
20-
prepareMutations: (findings: RuleFinding[]) => Entity[]
20+
prepareFindingsMutations: (findings: RuleFinding[]) => Entity[]
21+
22+
/**
23+
* Transforms Rules array into a mutation array for GraphQL
24+
* @param rules rules metadata
25+
* @returns {Entity[]} Array of generated mutations
26+
*/
27+
prepareRulesMetadataMutations: (rules: Rule[]) => Entity[]
2128
}

src/rules-engine/data-processors/dgraph-data-processor.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import groupBy from 'lodash/groupBy'
22
import isEmpty from 'lodash/isEmpty'
33
import { Entity } from '../../types'
4-
import { RuleFinding } from '../types'
4+
import { Rule, RuleFinding } from '../types'
55
import DataProcessor from './data-processor'
66

77
export default class DgraphDataProcessor implements DataProcessor {
@@ -48,7 +48,7 @@ export default class DgraphDataProcessor implements DataProcessor {
4848
4949
type ruleMetadata @key(fields: "id") {
5050
id: String! @id @search(by: [hash, regexp])
51-
severity: String! @search(by: [hash, regexp])
51+
severity: String @search(by: [hash, regexp])
5252
description: String! @search(by: [hash, regexp])
5353
title: String @search(by: [hash, regexp])
5454
audit: String @search(by: [hash, regexp])
@@ -185,7 +185,44 @@ export default class DgraphDataProcessor implements DataProcessor {
185185
return mutations
186186
}
187187

188-
prepareMutations = (findings: RuleFinding[] = []): Entity[] => {
188+
prepareRulesMetadataMutations = (rules: Rule[] = []): Entity[] => {
189+
return [
190+
{
191+
name: 'ruleMetadata',
192+
mutation: `
193+
mutation($input: [AddruleMetadataInput!]!) {
194+
addruleMetadata(input: $input, upsert: true) {
195+
numUids
196+
}
197+
}
198+
199+
`,
200+
data: rules.map(
201+
({
202+
id,
203+
title,
204+
description,
205+
references,
206+
rationale,
207+
audit,
208+
remediation,
209+
severity,
210+
}) => ({
211+
id,
212+
title,
213+
description,
214+
references,
215+
rationale,
216+
audit,
217+
remediation,
218+
severity,
219+
})
220+
),
221+
},
222+
]
223+
}
224+
225+
prepareFindingsMutations = (findings: RuleFinding[] = []): Entity[] => {
189226
// Return an empty array if there are no findings
190227
if (isEmpty(findings)) {
191228
return []

src/rules-engine/evaluators/js-evaluator.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@ export default class JsEvaluator implements RuleEvaluator<JsRule> {
1414
}
1515

1616
async evaluateSingleResource(
17-
rule: JsRule,
17+
{ id, check, severity }: JsRule,
1818
data: ResourceData
1919
): Promise<RuleFinding> {
20-
const { gql, check, resource, ...ruleMetadata } = rule
21-
const result = rule.check!(data)
22-
? RuleResult.MATCHES
23-
: RuleResult.DOESNT_MATCH
20+
const result = check!(data) ? RuleResult.MATCHES : RuleResult.DOESNT_MATCH
2421

2522
const finding = {
26-
id: `${rule.id}/${data.resource?.id}`,
23+
id: `${id}/${data.resource?.id}`,
2724
resourceId: data.resource?.id,
2825
result: result !== RuleResult.MATCHES ? Result.FAIL : Result.PASS,
2926
typename: data.resource?.__typename, // eslint-disable-line no-underscore-dangle
30-
rule: ruleMetadata,
27+
rule: {
28+
id,
29+
severity,
30+
},
3131
} as RuleFinding
3232
return finding
3333
}

src/rules-engine/evaluators/json-evaluator.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,22 @@ export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
2020
}
2121

2222
async evaluateSingleResource(
23-
rule: JsonRule,
23+
{ id, conditions, severity }: JsonRule,
2424
data: ResourceData
2525
): Promise<RuleFinding> {
26-
const { gql, conditions, resource, ...ruleMetadata } = rule
27-
const result = (await this.evaluateCondition(rule.conditions, data))
26+
const result = (await this.evaluateCondition(conditions, data))
2827
? RuleResult.MATCHES
2928
: RuleResult.DOESNT_MATCH
3029

3130
const finding = {
32-
id: `${rule.id}/${data.resource?.id}`,
31+
id: `${id}/${data.resource?.id}`,
3332
resourceId: data.resource?.id,
3433
result: result !== RuleResult.MATCHES ? Result.FAIL : Result.PASS,
3534
typename: data.resource?.__typename, // eslint-disable-line no-underscore-dangle
36-
rule: ruleMetadata,
35+
rule: {
36+
id,
37+
severity,
38+
},
3739
} as RuleFinding
3840
return finding
3941
}

src/rules-engine/evaluators/manual-evaluator.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ export default class ManualEvaluator implements RuleEvaluator<JsonRule> {
66
return !('gql' in rule) && !('conditions' in rule) && !('resource' in rule)
77
}
88

9-
async evaluateSingleResource(rule: Rule): Promise<RuleFinding> {
9+
async evaluateSingleResource({ id, severity }: Rule): Promise<RuleFinding> {
1010
return {
11-
id: `${rule.id}/manual`,
11+
id: `${id}/manual`,
1212
result: Result.SKIPPED,
1313
typename: 'manual',
14-
rule,
14+
rule: {
15+
id,
16+
severity,
17+
},
1518
} as RuleFinding
1619
}
1720
}

src/rules-engine/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ export default class RulesProvider implements Engine {
135135
return res
136136
}
137137

138-
prepareMutations = (findings: RuleFinding[]): Entity[] =>
139-
this.dataProcessor.prepareMutations(findings)
138+
prepareMutations = (findings: RuleFinding[], rules: Rule[]): Entity[] => [
139+
...this.dataProcessor.prepareRulesMetadataMutations(rules),
140+
...this.dataProcessor.prepareFindingsMutations(findings),
141+
]
140142
}

src/rules-engine/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ export interface Engine {
8989
/**
9090
* Transforms RuleFinding array into a mutation array for GraphQL
9191
* @param findings resulted findings during rules execution
92+
* @param rules rules metadata
9293
* @returns {Entity[]} Array of generated mutations
9394
*/
94-
prepareMutations: (findings: RuleFinding[]) => Entity[]
95+
prepareMutations: (findings: RuleFinding[], rules: Rule[]) => Entity[]
9596
}

tests/rules-engine.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('RulesEngine', () => {
3838
ManualEvaluatorMock.manualRule as Rule,
3939
undefined
4040
)
41-
const [mutations] = rulesEngine.prepareMutations(findings)
41+
const [mutations] = rulesEngine.prepareMutations(findings, [])
4242

4343
expect(findings.length).toBe(1)
4444
expect(mutations).toBeDefined()
@@ -66,7 +66,7 @@ describe('RulesEngine', () => {
6666
it('Should return empty mutations array given an empty findings array', () => {
6767
const data = []
6868

69-
const entities = rulesEngine.prepareMutations(data)
69+
const entities = rulesEngine.prepareMutations(data, [])
7070

7171
expect(entities).toBeDefined()
7272
expect(entities.length).toBe(0)

0 commit comments

Comments
 (0)