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

Fix sort of Side Drawer Advance Filters (CRASM-967) #740

Draft
wants to merge 11 commits into
base: develop
Choose a base branch
from
4 changes: 3 additions & 1 deletion backend/src/api/search/buildRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,9 @@ export function buildRequest(
aggs: {
severity: {
terms: {
field: 'vulnerabilities.severity.keyword'
field: 'vulnerabilities.severity.keyword',
missing: 'null',
size: 50
}
},
cve: {
Expand Down
4 changes: 1 addition & 3 deletions backend/src/tasks/search-sync-domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import pRetry from 'p-retry';
export const DOMAIN_CHUNK_SIZE = typeof jest === 'undefined' ? 50 : 10;
export const ORGANIZATION_CHUNK_SIZE = typeof jest === 'undefined' ? 50 : 10;

export const handler = async (commandOptions: CommandOptions) => {
const { organizationId, domainId } = commandOptions;

export const handler = async (organizationId?: string) => {
console.log('Running searchSync');
await connectToDatabase();

Expand Down
11 changes: 1 addition & 10 deletions backend/src/tasks/syncdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,8 @@ export const handler: Handler = async (event) => {
}
}

console.log('Done. Running search sync...');
for (const organizationId of organizationIds) {
await searchSyncDomains({
organizationId,
scanId: 'scanId',
scanName: 'scanName',
organizationName: 'organizationName',
scanTaskId: 'scanTaskId'
});
}
console.log('Done.');
}
await searchSyncDomains();
await searchSyncOrgs();
};
71 changes: 9 additions & 62 deletions backend/src/tasks/test/search-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,7 @@ describe('search_sync', () => {
domain
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).not.toBeCalled();
});
Expand All @@ -71,13 +65,7 @@ describe('search_sync', () => {
updatedAt: new Date('9999-10-11')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).toBeCalled();
});
Expand All @@ -97,13 +85,7 @@ describe('search_sync', () => {
updatedAt: new Date('9999-9-11')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).not.toBeCalled();
});
Expand All @@ -122,13 +104,7 @@ describe('search_sync', () => {
updatedAt: new Date('9999-10-11')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).toBeCalled();
});
Expand All @@ -147,13 +123,7 @@ describe('search_sync', () => {
updatedAt: new Date('9999-9-11')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).not.toBeCalled();
});
Expand All @@ -174,13 +144,7 @@ describe('search_sync', () => {
syncedAt: new Date('9999-10-10')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).toBeCalled();
});
Expand All @@ -201,13 +165,7 @@ describe('search_sync', () => {
syncedAt: new Date('9999-10-10')
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).not.toBeCalled();
});
Expand All @@ -233,13 +191,7 @@ describe('search_sync', () => {
domain
}).save();

await searchSync({
organizationId: organization.id,
organizationName: 'organizationName',
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).toBeCalled();
expect(
Expand Down Expand Up @@ -272,12 +224,7 @@ describe('search_sync', () => {
)
);

await searchSync({
organizationId: organization.id,
scanId: 'scanId',
scanName: 'scanName',
scanTaskId: 'scanTaskId'
});
await searchSync(organization.id);

expect(updateDomains).toBeCalledTimes(2);
});
Expand Down
4 changes: 4 additions & 0 deletions backend/test/__snapshots__/search.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Object {
"severity": Object {
"terms": Object {
"field": "vulnerabilities.severity.keyword",
"missing": "null",
"size": 50,
},
},
},
Expand Down Expand Up @@ -195,6 +197,8 @@ Object {
"severity": Object {
"terms": Object {
"field": "vulnerabilities.severity.keyword",
"missing": "null",
"size": 50,
},
},
},
Expand Down
87 changes: 75 additions & 12 deletions frontend/src/components/DrawerInterior.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ interface Props {
initialFilters: any[];
}

interface SeverityData {
value: string;
count: number;
}

interface GroupedData {
[key: string]: number;
}

const FiltersApplied: React.FC = () => {
return (
<div className={classes.applied}>
Expand Down Expand Up @@ -151,26 +160,80 @@ export const DrawerInterior: React.FC<Props> = (props) => {
);

const portFacet: any[] = facets['services.port']
? facets['services.port'][0].data
? facets['services.port'][0].data.sort(
(a: { value: number }, b: { value: number }) => a.value - b.value
)
: [];

const fromDomainFacet: any[] = facets['fromRootDomain']
? facets['fromRootDomain'][0].data
? facets['fromRootDomain'][0].data.sort(
(a: { value: string }, b: { value: string }) =>
a.value.localeCompare(b.value)
)
: [];

const cveFacet: any[] = facets['vulnerabilities.cve']
? facets['vulnerabilities.cve'][0].data
? facets['vulnerabilities.cve'][0].data.sort(
(a: { value: string }, b: { value: string }) =>
a.value.localeCompare(b.value)
)
: [];

const severityFacet: any[] = facets['vulnerabilities.severity']
? facets['vulnerabilities.severity'][0].data
// To-Do: Create array(s) to handle permutations of null and N/A values
const titleCaseSeverityFacet = facets['vulnerabilities.severity']
? facets['vulnerabilities.severity'][0].data.map(
(d: { value: string; count: number }) => {
if (
d.value === null ||
d.value === 'null' ||
d.value === 'NULL' ||
d.value === undefined ||
d.value === '' ||
d.value === 'N/A'
) {
return { value: 'N/A', count: d.count };
} else {
return {
value:
d.value[0]?.toUpperCase() + d.value.slice(1)?.toLowerCase(),
count: d.count
};
}
}
)
: [];

// Always show all severities
for (const value of ['Critical', 'High', 'Medium', 'Low']) {
if (!severityFacet.find((severity) => value === severity.value))
severityFacet.push({ value, count: 0 });
}
const groupedData: GroupedData = titleCaseSeverityFacet
.map((d: SeverityData) => {
const severityLevels = [
'N/A',
'Low',
'Medium',
'High',
'Critical',
'Other'
];
if (severityLevels.includes(d.value)) {
return d;
} else {
return { value: 'Other', count: d.count };
}
})
.reduce((acc: GroupedData, curr: SeverityData) => {
if (acc[curr.value]) {
acc[curr.value] += curr.count;
} else {
acc[curr.value] = curr.count;
}
return acc;
}, {});

const sortedSeverityFacets = Object.entries(groupedData)
.map(([value, count]) => ({ value, count }))
.sort((a, b) => {
const order = ['N/A', 'Low', 'Medium', 'High', 'Critical', 'Other'];
return order.indexOf(a.value) - order.indexOf(b.value);
});

return (
<StyledWrapper style={{ overflowY: 'auto' }}>
Expand Down Expand Up @@ -360,7 +423,7 @@ export const DrawerInterior: React.FC<Props> = (props) => {
</AccordionDetails>
</Accordion>
)}
{severityFacet.length > 0 && (
{sortedSeverityFacets.length > 0 && (
<Accordion
elevation={0}
square
Expand All @@ -386,7 +449,7 @@ export const DrawerInterior: React.FC<Props> = (props) => {
</AccordionSummary>
<AccordionDetails classes={{ root: classes.details }}>
<FacetFilter
options={severityFacet}
options={sortedSeverityFacets}
selected={filtersByColumn['vulnerabilities.severity'] ?? []}
onSelect={(value) =>
addFilter('vulnerabilities.severity', value, 'any')
Expand Down
Loading