Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cloud Security] Filters for Contextual Flyout Datagrid #201708

Merged
merged 12 commits into from
Dec 2, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,8 @@ export const VULNERABILITIES_SEVERITY: Record<VulnSeverity, VulnSeverity> = {
CRITICAL: 'CRITICAL',
UNKNOWN: 'UNKNOWN',
};

export const MISCONFIGURATION_STATUS: Record<string, string> = {
PASSED: 'passed',
FAILED: 'failed',
};
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ export * from './constants';
export {
extractErrorMessage,
buildMutedRulesFilter,
buildEntityFlyoutPreviewQuery,
buildGenericEntityFlyoutPreviewQuery,
buildMisconfigurationEntityFlyoutPreviewQuery,
buildVulnerabilityEntityFlyoutPreviewQuery,
} from './utils/helpers';
export { getAbbreviatedNumber } from './utils/get_abbreviated_number';
export { UiMetricService } from './utils/ui_metrics';
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
extractErrorMessage,
defaultErrorMessage,
buildMutedRulesFilter,
buildEntityFlyoutPreviewQuery,
buildEntityAlertsQuery,
buildGenericEntityFlyoutPreviewQuery,
buildMisconfigurationEntityFlyoutPreviewQuery,
buildVulnerabilityEntityFlyoutPreviewQuery,
} from './helpers';

const fallbackMessage = 'thisIsAFallBackMessage';
Expand Down Expand Up @@ -145,7 +147,7 @@ describe('test helper methods', () => {
});
});

describe('buildEntityFlyoutPreviewQueryTest', () => {
describe('buildGenericEntityFlyoutPreviewQuery', () => {
it('should return the correct query when given field and query', () => {
const field = 'host.name';
const query = 'exampleHost';
Expand All @@ -162,10 +164,10 @@ describe('test helper methods', () => {
},
};

expect(buildEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery);
expect(buildGenericEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery);
});

it('should return the correct query when given field and empty query', () => {
it('should return the correct query when given field and empty query and empty status', () => {
const field = 'host.name';
const expectedQuery = {
bool: {
Expand All @@ -180,12 +182,143 @@ describe('test helper methods', () => {
},
};

expect(buildEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery);
expect(buildGenericEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery);
});

it('should return the correct query when given field and queryValue and status but empty queryField', () => {
const field = 'host.name';
const query = 'exampleHost';
const status = 'pass';
const expectedQuery = {
bool: {
filter: [
{
bool: {
should: [{ term: { 'host.name': 'exampleHost' } }],
minimum_should_match: 1,
},
},
],
},
};

expect(buildGenericEntityFlyoutPreviewQuery(field, query, status)).toEqual(expectedQuery);
});

it('should return the correct query when given field and queryValue and queryField but empty status', () => {
const field = 'host.name';
const query = 'exampleHost';
const emptyStatus = undefined;
const queryField = 'some.field';
const expectedQuery = {
bool: {
filter: [
{
bool: {
should: [{ term: { 'host.name': 'exampleHost' } }],
minimum_should_match: 1,
},
},
],
},
};

expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual(
expectedQuery
);
});

it('should return the correct query when given all the parameters', () => {
const field = 'host.name';
const query = 'exampleHost';
const emptyStatus = 'some.status';
const queryField = 'some.field';
const expectedQuery = {
bool: {
filter: [
{
bool: {
should: [{ term: { 'host.name': 'exampleHost' } }],
minimum_should_match: 1,
},
},
{
bool: {
should: [{ term: { 'some.field': 'some.status' } }],
minimum_should_match: 1,
},
},
],
},
};

expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual(
expectedQuery
);
});
});

describe('buildMisconfigurationEntityFlyoutPreviewQuery', () => {
it('should return the correct query when given field, queryValue, status and queryType Misconfiguration', () => {
const field = 'host.name';
const queryValue = 'exampleHost';
const status = 'pass';
const expectedQuery = {
bool: {
filter: [
{
bool: {
should: [{ term: { 'host.name': 'exampleHost' } }],
minimum_should_match: 1,
},
},
{
bool: {
should: [{ term: { 'result.evaluation': 'pass' } }],
minimum_should_match: 1,
},
},
],
},
};

expect(buildMisconfigurationEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual(
expectedQuery
);
});
});
describe('buildVulnerabilityEntityFlyoutPreviewQuery', () => {
it('should return the correct query when given field, queryValue, status and queryType Vulnerability', () => {
const field = 'host.name';
const queryValue = 'exampleHost';
const status = 'low';
const expectedQuery = {
bool: {
filter: [
{
bool: {
should: [{ term: { 'host.name': 'exampleHost' } }],
minimum_should_match: 1,
},
},
{
bool: {
should: [{ term: { 'vulnerability.severity': 'low' } }],
minimum_should_match: 1,
},
},
],
},
};

expect(buildVulnerabilityEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual(
expectedQuery
);
});
});

describe('buildEntityAlertsQuery', () => {
const getExpectedAlertsQuery = (size?: number) => {
const getExpectedAlertsQuery = (size?: number, severity?: string) => {
return {
size: size || 0,
_source: false,
seanrathier marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -202,20 +335,30 @@ describe('test helper methods', () => {
filter: [
{
bool: {
must: [],
filter: [
should: [
{
match_phrase: {
'host.name': {
query: 'exampleHost',
},
term: {
'host.name': 'exampleHost',
},
},
],
should: [],
must_not: [],
minimum_should_match: 1,
},
},
severity
? {
bool: {
should: [
{
term: {
'kibana.alert.severity': 'low',
},
},
],
minimum_should_match: 1,
},
}
: undefined,
{
range: {
'@timestamp': {
Expand All @@ -229,7 +372,7 @@ describe('test helper methods', () => {
'kibana.alert.workflow_status': ['open', 'acknowledged'],
},
},
],
].filter(Boolean),
},
},
};
Expand All @@ -256,5 +399,18 @@ describe('test helper methods', () => {

expect(buildEntityAlertsQuery(field, to, from, query)).toEqual(getExpectedAlertsQuery(size));
});

it('should return the correct query when given severity query', () => {
const field = 'host.name';
const query = 'exampleHost';
const to = 'Tomorrow';
const from = 'Today';
const size = undefined;
const severity = 'low';

expect(buildEntityAlertsQuery(field, to, from, query, size, severity)).toEqual(
getExpectedAlertsQuery(size, 'low')
);
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:opinion

We should consider renaming this file to something like queries.ts because all exported functions are related to building queries.

This is a little pet peeve of mine when directories are called utils and files helpers. I've seen this in many cases over time files like this become a kitchen sink of common functions and it becomes hard to reorganize the structure later. This will be especially hard to reorganize if other plugins start to use our shared package.

x-pack/packages/kbn-cloud-security-posture/common/queries.ts

Since this is a shared package everything is by definition common so another suggestion is to remove comment altogether

x-pack/packages/kbn-cloud-security-posture/queries.ts

wdyt?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm you are right that almost all of the helpers functions here are query related and I can see the issue that this might have later in the future

I'm down to do this change but maybe in separate ticket/PR (as this PR is for Filters for the Datagrid, and this suggested change might touch other features thats not related at all with Contextual Flyout)

wdyt ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please and thank you! Can you open that issue as a tech debt?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the link to the tech debt issue here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#202242

Lemme know if i missed anything :)

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ export const buildMutedRulesFilter = (
return mutedRulesFilterQuery;
};

export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string) => {
export const buildGenericEntityFlyoutPreviewQuery = (
field: string,
queryValue?: string,
status?: string,
queryField?: string
) => {
return {
bool: {
filter: [
Expand All @@ -59,17 +64,52 @@ export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string
minimum_should_match: 1,
},
},
],
status && queryField
? {
bool: {
should: [
{
term: {
[queryField]: status,
},
},
],
minimum_should_match: 1,
},
}
: undefined,
].filter(Boolean),
},
};
};

// Higher-order function for Misconfiguration
export const buildMisconfigurationEntityFlyoutPreviewQuery = (
field: string,
queryValue?: string,
status?: string
) => {
const queryField = 'result.evaluation';
return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField);
};

// Higher-order function for Vulnerability
export const buildVulnerabilityEntityFlyoutPreviewQuery = (
field: string,
queryValue?: string,
status?: string
) => {
const queryField = 'vulnerability.severity';
return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField);
};

export const buildEntityAlertsQuery = (
field: string,
to: string,
from: string,
queryValue?: string,
size?: number
size?: number,
severity?: string
) => {
return {
size: size || 0,
Expand All @@ -87,20 +127,30 @@ export const buildEntityAlertsQuery = (
filter: [
{
bool: {
must: [],
filter: [
should: [
{
match_phrase: {
[field]: {
query: queryValue,
},
term: {
[field]: `${queryValue || ''}`,
},
},
],
should: [],
must_not: [],
minimum_should_match: 1,
},
},
severity
? {
bool: {
should: [
{
term: {
'kibana.alert.severity': severity,
},
},
],
minimum_should_match: 1,
},
}
: undefined,
{
range: {
'@timestamp': {
Expand All @@ -114,7 +164,7 @@ export const buildEntityAlertsQuery = (
'kibana.alert.workflow_status': ['open', 'acknowledged'],
},
},
],
].filter(Boolean),
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ export const statusColors = {
failed: euiThemeVars.euiColorVis9,
unknown: euiThemeVars.euiColorLightShade,
};

export const HOST_NAME = 'host.name';
export const USER_NAME = 'user.name';
Loading
Loading