Skip to content

Commit

Permalink
Merge pull request #1290 from guardian/nt/cb-digest
Browse files Browse the repository at this point in the history
Eliminate race condition
  • Loading branch information
NovemberTang authored Oct 7, 2024
2 parents 8b3abaa + f6b7b1f commit 38e4423
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 15 deletions.
64 changes: 64 additions & 0 deletions packages/cloudbuster/src/digests.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { cloudbuster_fsbp_vulnerabilities } from '@prisma/client';
import type { SecurityHubSeverity } from 'common/types';
import { createDigestsFromFindings } from './digests';

function mockFinding(
aws_account_id: string,
severity: SecurityHubSeverity,
): cloudbuster_fsbp_vulnerabilities {
return {
aws_account_id,
title: 'mock title',
aws_account_name: 'mock-account',
arn: 'arn::mock::123',
remediation: 'https://mock.url/mock',
severity,
within_sla: true,
first_observed_at: new Date('2020-01-01'),
control_id: 'MOCK.1',
aws_region: 'eu-mock-1',
repo: null,
stack: null,
stage: null,
app: null,
};
}

describe('createDigestsFromFindings', () => {
it('should filter findings by severity', () => {
const findings = [
mockFinding('1', 'CRITICAL'),
mockFinding('2', 'HIGH'),
mockFinding('3', 'CRITICAL'),
];
const criticalDigests = createDigestsFromFindings(findings, 'CRITICAL');
expect(criticalDigests.length).toBe(2);

const highDigests = createDigestsFromFindings(findings, 'HIGH');
expect(highDigests.length).toBe(1);
});
it('should create one digest per account', () => {
const findingsFromTwoAccounts = [
mockFinding('1', 'CRITICAL'),
mockFinding('2', 'CRITICAL'),
mockFinding('3', 'CRITICAL'),
];
const result = createDigestsFromFindings(
findingsFromTwoAccounts,
'CRITICAL',
);
expect(result.length).toBe(3);
});
it('should combine findings of the same account and severity into one digest', () => {
const findingsFromOneAccount = [
mockFinding('1', 'CRITICAL'),
mockFinding('1', 'CRITICAL'),
mockFinding('1', 'CRITICAL'),
];
const result = createDigestsFromFindings(
findingsFromOneAccount,
'CRITICAL',
);
expect(result.length).toBe(1);
});
});
6 changes: 5 additions & 1 deletion packages/cloudbuster/src/digests.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { RequestedChannel } from '@guardian/anghammarad';
import type { Anghammarad, NotifyParams } from '@guardian/anghammarad';
import type { cloudbuster_fsbp_vulnerabilities } from '@prisma/client';
import type { SecurityHubSeverity } from 'common/src/types';
import { type Config } from './config';
import { groupFindingsByAccount } from './findings';
import type { Digest } from './types';
Expand All @@ -10,8 +11,11 @@ import type { Digest } from './types';
*/
export function createDigestsFromFindings(
findings: cloudbuster_fsbp_vulnerabilities[],
severity: SecurityHubSeverity,
): Digest[] {
const groupedFindings = groupFindingsByAccount(findings);
const filteredFindings = findings.filter((f) => f.severity === severity);

const groupedFindings = groupFindingsByAccount(filteredFindings);

return Object.keys(groupedFindings)
.map((awsAccountId) =>
Expand Down
17 changes: 7 additions & 10 deletions packages/cloudbuster/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,8 @@ import { getConfig } from './config';
import { createDigestsFromFindings, sendDigest } from './digests';
import { findingsToGuardianFormat } from './findings';

type LambdaHandlerProps = {
severities?: SecurityHubSeverity[];
};

export async function main(input: LambdaHandlerProps) {
// When manually invoking the function in AWS for testing,
// it can be cumbersome to manually type this object as an input.
// Therefore, fall back to default values.
const { severities = ['CRITICAL', 'HIGH'] } = input;
export async function main() {
const severities: SecurityHubSeverity[] = ['CRITICAL', 'HIGH'];

// *** SETUP ***
const config = await getConfig();
Expand All @@ -38,8 +31,12 @@ export async function main(input: LambdaHandlerProps) {
data: tableContents,
});

const digests = createDigestsFromFindings(tableContents);
const digests = createDigestsFromFindings(tableContents, 'CRITICAL');

const isTuesday = new Date().getDay() === 2;
if (isTuesday) {
digests.push(...createDigestsFromFindings(tableContents, 'HIGH'));
}
// *** NOTIFICATION SENDING ***
const anghammaradClient = new Anghammarad();

Expand Down
5 changes: 1 addition & 4 deletions packages/cloudbuster/src/run-locally.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { main } from './index';

if (require.main === module) {
void main({
// Using all severities in DEV for more data.
severities: ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'INFORMATION'],
});
void main();
}

0 comments on commit 38e4423

Please sign in to comment.