Skip to content

Commit cdc6226

Browse files
author
Marco Franceschi
committed
feat: Reused data for Automated Rules and created policyPackPlugin unit test
1 parent 538824d commit cdc6226

File tree

7 files changed

+119
-226
lines changed

7 files changed

+119
-226
lines changed
Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
import groupBy from 'lodash/groupBy'
2-
import isEmpty from 'lodash/isEmpty'
3-
import { Entity } from '../../types'
41
import {
52
JsRule,
63
ResourceData,
@@ -12,17 +9,6 @@ import {
129
import { RuleEvaluator } from './rule-evaluator'
1310

1411
export default class JsEvaluator implements RuleEvaluator<JsRule> {
15-
private readonly findings: RuleFinding[] = []
16-
17-
private readonly providerName
18-
19-
private readonly entityName
20-
21-
constructor(providerName: string, entityName: string) {
22-
this.entityName = entityName
23-
this.providerName = providerName
24-
}
25-
2612
canEvaluate(rule: Rule | JsRule): boolean {
2713
return 'check' in rule
2814
}
@@ -43,56 +29,6 @@ export default class JsEvaluator implements RuleEvaluator<JsRule> {
4329
typename: data.resource?.__typename, // eslint-disable-line no-underscore-dangle
4430
rule: ruleMetadata,
4531
} as RuleFinding
46-
this.findings.push(finding)
4732
return finding
4833
}
49-
50-
// TODO: Share logic with the JSON evaluator
51-
prepareMutations(): Entity[] {
52-
const mutations = []
53-
54-
// Group Findings by schema type
55-
const findingsByType = groupBy(this.findings, 'typename')
56-
57-
for (const findingType in findingsByType) {
58-
if (!isEmpty(findingType)) {
59-
// Group Findings by resource
60-
const findingsByResource = groupBy(
61-
findingsByType[findingType],
62-
'resourceId'
63-
)
64-
65-
for (const resource in findingsByResource) {
66-
if (resource) {
67-
const data = (
68-
(findingsByResource[resource] as RuleFinding[]) || []
69-
).map(({ typename, ...properties }) => properties)
70-
71-
// Create dynamically update mutations by resource
72-
const updateMutation = {
73-
name: `${this.providerName}${this.entityName}Findings`,
74-
mutation: `mutation update${findingType}($input: Update${findingType}Input!) {
75-
update${findingType}(input: $input) {
76-
numUids
77-
}
78-
}
79-
`,
80-
data: {
81-
filter: {
82-
id: { eq: resource },
83-
},
84-
set: {
85-
[`${this.entityName}Findings`]: data,
86-
},
87-
},
88-
}
89-
90-
mutations.push(updateMutation)
91-
}
92-
}
93-
}
94-
}
95-
96-
return mutations
97-
}
9834
}

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

Lines changed: 9 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import lodash, { groupBy, isEmpty } from 'lodash'
1+
import lodash from 'lodash'
22
import * as jqNode from 'node-jq'
33
import {
44
Condition,
@@ -10,23 +10,11 @@ import {
1010
RuleResult,
1111
_ResourceData,
1212
} from '../types'
13-
import { RuleEvaluator } from './rule-evaluator'
1413
import AdditionalOperators from '../operators'
1514
import ComparisonOperators from '../operators/comparison'
16-
import { Entity } from '../../types'
15+
import { RuleEvaluator } from './rule-evaluator'
1716

1817
export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
19-
private readonly findings: RuleFinding[] = []
20-
21-
private readonly providerName
22-
23-
private readonly entityName
24-
25-
constructor(providerName: string, entityName: string) {
26-
this.entityName = entityName
27-
this.providerName = providerName
28-
}
29-
3018
canEvaluate(rule: JsonRule): boolean {
3119
return 'conditions' in rule
3220
}
@@ -47,7 +35,6 @@ export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
4735
typename: data.resource?.__typename, // eslint-disable-line no-underscore-dangle
4836
rule: ruleMetadata,
4937
} as RuleFinding
50-
this.findings.push(finding)
5138
return finding
5239
}
5340

@@ -91,6 +78,13 @@ export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
9178
}
9279
return true
9380
},
81+
compare: async (_, conditions: Condition[], data) => {
82+
for (let i = 0; i < conditions.length; i++) {
83+
// if 1 is false, it's false
84+
if (!(await this.evaluateCondition(conditions[i], data))) return false
85+
}
86+
return true
87+
},
9488
array_all: async (array = [], conditions: Condition, data) => {
9589
// an AND, but with every resource item
9690
const baseElementPath = data.elementPath
@@ -186,52 +180,4 @@ export default class JsonEvaluator implements RuleEvaluator<JsonRule> {
186180
return data
187181
}
188182
}
189-
190-
prepareMutations(): Entity[] {
191-
const mutations = []
192-
193-
// Group Findings by schema type
194-
const findingsByType = groupBy(this.findings, 'typename')
195-
196-
for (const findingType in findingsByType) {
197-
if (!isEmpty(findingType)) {
198-
// Group Findings by resource
199-
const findingsByResource = groupBy(
200-
findingsByType[findingType],
201-
'resourceId'
202-
)
203-
204-
for (const resource in findingsByResource) {
205-
if (resource) {
206-
const data = (
207-
(findingsByResource[resource] as RuleFinding[]) || []
208-
).map(({ typename, ...properties }) => properties)
209-
210-
// Create dynamically update mutations by resource
211-
const updateMutation = {
212-
name: `${this.providerName}${this.entityName}Findings`,
213-
mutation: `mutation update${findingType}($input: Update${findingType}Input!) {
214-
update${findingType}(input: $input) {
215-
numUids
216-
}
217-
}
218-
`,
219-
data: {
220-
filter: {
221-
id: { eq: resource },
222-
},
223-
set: {
224-
[`${this.entityName}Findings`]: data,
225-
},
226-
},
227-
}
228-
229-
mutations.push(updateMutation)
230-
}
231-
}
232-
}
233-
}
234-
235-
return mutations
236-
}
237183
}
Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
1-
import { Entity } from '../../types'
21
import { JsonRule, Result, Rule, RuleFinding } from '../types'
32
import { RuleEvaluator } from './rule-evaluator'
43

54
export default class ManualEvaluator implements RuleEvaluator<JsonRule> {
6-
private readonly findings: RuleFinding[] = []
7-
8-
private readonly providerName
9-
10-
private readonly entityName
11-
12-
constructor(providerName: string, entityName: string) {
13-
this.entityName = entityName
14-
this.providerName = providerName
15-
}
16-
175
canEvaluate(rule: Rule): boolean {
186
return !('gql' in rule) && !('conditions' in rule) && !('resource' in rule)
197
}
@@ -25,26 +13,6 @@ export default class ManualEvaluator implements RuleEvaluator<JsonRule> {
2513
typename: 'manual',
2614
rule,
2715
} as RuleFinding
28-
this.findings.push(finding)
2916
return finding
3017
}
31-
32-
prepareMutations(): Entity[] {
33-
const manualFindings = this.findings.map(({ typename, ...finding }) => ({
34-
...finding,
35-
}))
36-
return [
37-
{
38-
name: `${this.providerName}${this.entityName}Findings`,
39-
mutation: `
40-
mutation($input: [Add${this.providerName}${this.entityName}FindingsInput!]!) {
41-
add${this.providerName}${this.entityName}Findings(input: $input, upsert: true) {
42-
numUids
43-
}
44-
}
45-
`,
46-
data: manualFindings,
47-
},
48-
]
49-
}
5018
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { Entity } from '../../types'
21
import { ResourceData, Rule, RuleFinding } from '../types'
32

43
export interface RuleEvaluator<K extends Rule> {
54
canEvaluate: (rule: K) => boolean
65
evaluateSingleResource: (rule: K, data?: ResourceData) => Promise<RuleFinding>
7-
prepareMutations: () => Entity[]
86
}

src/rules-engine/index.ts

Lines changed: 3 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ export default class RulesProvider implements Engine {
3535
this.entityName = entityName
3636
this.providerName = providerName
3737
this.evaluators = [
38-
new JsonEvaluator(providerName, entityName),
39-
new JsEvaluator(providerName, entityName),
40-
new ManualEvaluator(providerName, entityName),
38+
new JsonEvaluator(),
39+
new JsEvaluator(),
40+
new ManualEvaluator(),
4141
]
4242
}
4343

@@ -101,51 +101,6 @@ export default class RulesProvider implements Engine {
101101
return data
102102
}
103103

104-
/**
105-
* Prepare the mutations for overall provider findings
106-
* @param findings RuleFinding array
107-
* @returns A formatted Entity array
108-
*/
109-
private prepareProviderMutations = (
110-
findings: RuleFinding[] = []
111-
): Entity[] => {
112-
// Prepare provider schema connections
113-
return [
114-
{
115-
name: `${this.providerName}Findings`,
116-
mutation: `
117-
mutation($input: [Add${this.providerName}FindingsInput!]!) {
118-
add${this.providerName}Findings(input: $input, upsert: true) {
119-
numUids
120-
}
121-
}
122-
`,
123-
data: {
124-
id: `${this.providerName}-provider`,
125-
},
126-
},
127-
{
128-
name: `${this.providerName}Findings`,
129-
mutation: `mutation update${this.providerName}Findings($input: Update${this.providerName}FindingsInput!) {
130-
update${this.providerName}Findings(input: $input) {
131-
numUids
132-
}
133-
}
134-
`,
135-
data: {
136-
filter: {
137-
id: { eq: `${this.providerName}-provider` },
138-
},
139-
set: {
140-
[`${this.entityName}Findings`]: findings.map(
141-
({ typename, ...rest }) => ({ ...rest })
142-
),
143-
},
144-
},
145-
},
146-
]
147-
}
148-
149104
getSchema = (): string[] => {
150105
const mainType = `
151106
enum FindingsResult {
@@ -212,19 +167,6 @@ export default class RulesProvider implements Engine {
212167
return [mainType, extensions]
213168
}
214169

215-
prepareMutations = (findings: RuleFinding[] = []): Entity[] => {
216-
// Prepare entities mutations
217-
const entitiesData = []
218-
for (const evaluator of this.evaluators) {
219-
entitiesData.push(...evaluator.prepareMutations())
220-
}
221-
222-
// Prepare provider mutations
223-
const providerData = this.prepareProviderMutations(findings)
224-
225-
return [...entitiesData, ...providerData]
226-
}
227-
228170
processRule = async (rule: Rule, data: unknown): Promise<RuleFinding[]> => {
229171
const res: any[] = []
230172
const dedupeIds = {}

src/rules-engine/types.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ export interface RuleFinding extends Finding {
6363
rule?: Rule
6464
}
6565

66-
export interface ProcessedFindings {
67-
automatedFindings: RuleFinding[]
68-
manualFindings: Omit<RuleFinding, 'typename'>[]
69-
}
7066
export interface JsonRule extends Rule {
7167
conditions: Condition
7268
}

0 commit comments

Comments
 (0)