Skip to content

Commit

Permalink
Move indicator path defaulting outside of helper functions
Browse files Browse the repository at this point in the history
This happens closer to where we pass data from the rule to our helpers,
and will prevent errors/bugs due to defaulting logic down the road.

It makes tests a little more verbose, but that's okay.
  • Loading branch information
rylnd committed Feb 12, 2021
1 parent 6b2d1d7 commit c33dc3a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries: [],
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toEqual([]);
Expand All @@ -102,6 +103,7 @@ describe('buildMatchedIndicator', () => {
const [indicator] = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(get(indicator, 'matched.atomic')).toEqual('domain_1');
Expand All @@ -111,6 +113,7 @@ describe('buildMatchedIndicator', () => {
const [indicator] = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(get(indicator, 'matched.field')).toEqual('event.field');
Expand All @@ -120,6 +123,7 @@ describe('buildMatchedIndicator', () => {
const [indicator] = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(get(indicator, 'matched.type')).toEqual('type_1');
Expand Down Expand Up @@ -148,6 +152,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toHaveLength(queries.length);
Expand All @@ -157,6 +162,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toEqual([
Expand Down Expand Up @@ -192,9 +198,9 @@ describe('buildMatchedIndicator', () => {
];

const indicators = buildMatchedIndicator({
indicatorPath: 'custom.indicator.path',
queries,
threats,
indicatorPath: 'custom.indicator.path',
});

expect(indicators).toEqual([
Expand All @@ -221,6 +227,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toEqual([
Expand All @@ -245,6 +252,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toEqual([
Expand Down Expand Up @@ -276,6 +284,7 @@ describe('buildMatchedIndicator', () => {
const indicators = buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
});

expect(indicators).toEqual([
Expand Down Expand Up @@ -307,6 +316,7 @@ describe('buildMatchedIndicator', () => {
buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
})
).toThrowError('Expected indicator field to be an object, but found: not an object');
});
Expand All @@ -327,6 +337,7 @@ describe('buildMatchedIndicator', () => {
buildMatchedIndicator({
queries,
threats,
indicatorPath: 'threat.indicator',
})
).toThrowError('Expected indicator field to be an object, but found: not an object');
});
Expand All @@ -352,7 +363,11 @@ describe('enrichSignalThreatMatches', () => {

it('performs no enrichment if there are no signals', async () => {
const signals = getSignalsResponseMock([]);
const enrichedSignals = await enrichSignalThreatMatches(signals, getMatchedThreats);
const enrichedSignals = await enrichSignalThreatMatches(
signals,
getMatchedThreats,
'threat.indicator'
);

expect(enrichedSignals.hits.hits).toEqual([]);
});
Expand All @@ -363,7 +378,11 @@ describe('enrichSignalThreatMatches', () => {
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
const enrichedSignals = await enrichSignalThreatMatches(signals, getMatchedThreats);
const enrichedSignals = await enrichSignalThreatMatches(
signals,
getMatchedThreats,
'threat.indicator'
);
const [enrichedHit] = enrichedSignals.hits.hits;
const indicators = get(enrichedHit._source, 'threat.indicator');

Expand All @@ -384,7 +403,11 @@ describe('enrichSignalThreatMatches', () => {
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
const enrichedSignals = await enrichSignalThreatMatches(signals, getMatchedThreats);
const enrichedSignals = await enrichSignalThreatMatches(
signals,
getMatchedThreats,
'threat.indicator'
);
const [enrichedHit] = enrichedSignals.hits.hits;
const indicators = get(enrichedHit._source, 'threat.indicator');

Expand All @@ -401,7 +424,11 @@ describe('enrichSignalThreatMatches', () => {
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
const enrichedSignals = await enrichSignalThreatMatches(signals, getMatchedThreats);
const enrichedSignals = await enrichSignalThreatMatches(
signals,
getMatchedThreats,
'threat.indicator'
);
const [enrichedHit] = enrichedSignals.hits.hits;
const indicators = get(enrichedHit._source, 'threat.indicator');

Expand All @@ -422,9 +449,9 @@ describe('enrichSignalThreatMatches', () => {
matched_queries: [matchedQuery],
});
const signals = getSignalsResponseMock([signalHit]);
await expect(() => enrichSignalThreatMatches(signals, getMatchedThreats)).rejects.toThrowError(
'Expected threat field to be an object, but found: whoops'
);
await expect(() =>
enrichSignalThreatMatches(signals, getMatchedThreats, 'threat.indicator')
).rejects.toThrowError('Expected threat field to be an object, but found: whoops');
});

it('enriches from a configured indicator path, if specified', async () => {
Expand Down Expand Up @@ -499,7 +526,11 @@ describe('enrichSignalThreatMatches', () => {
],
});
const signals = getSignalsResponseMock([signalHit, otherSignalHit]);
const enrichedSignals = await enrichSignalThreatMatches(signals, getMatchedThreats);
const enrichedSignals = await enrichSignalThreatMatches(
signals,
getMatchedThreats,
'threat.indicator'
);
expect(enrichedSignals.hits.total).toEqual(expect.objectContaining({ value: 1 }));
expect(enrichedSignals.hits.hits).toHaveLength(1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import type {
} from './types';
import { extractNamedQueries } from './utils';

const DEFAULT_INDICATOR_PATH = 'threat.indicator';
const getSignalId = (signal: SignalSourceHit): string => signal._id;

export const groupAndMergeSignalMatches = (signalHits: SignalSourceHit[]): SignalSourceHit[] => {
Expand All @@ -43,11 +42,11 @@ export const groupAndMergeSignalMatches = (signalHits: SignalSourceHit[]): Signa
export const buildMatchedIndicator = ({
queries,
threats,
indicatorPath = DEFAULT_INDICATOR_PATH,
indicatorPath,
}: {
queries: ThreatMatchNamedQuery[];
threats: ThreatListItem[];
indicatorPath?: string;
indicatorPath: string;
}): ThreatIndicator[] =>
queries.map((query) => {
const matchedThreat = threats.find((threat) => threat._id === query.id);
Expand All @@ -68,7 +67,7 @@ export const buildMatchedIndicator = ({
export const enrichSignalThreatMatches = async (
signals: SignalSearchResponse,
getMatchedThreats: GetMatchedThreats,
indicatorPath?: string
indicatorPath: string
): Promise<SignalSearchResponse> => {
const signalHits = signals.hits.hits;
if (signalHits.length === 0) {
Expand All @@ -79,10 +78,9 @@ export const enrichSignalThreatMatches = async (
const signalMatches = uniqueHits.map((signalHit) => extractNamedQueries(signalHit));
const matchedThreatIds = [...new Set(signalMatches.flat().map(({ id }) => id))];
const matchedThreats = await getMatchedThreats(matchedThreatIds);
const defaultedIndicatorPath = indicatorPath ? indicatorPath : DEFAULT_INDICATOR_PATH;
const matchedIndicators = signalMatches.map((queries) =>
buildMatchedIndicator({
indicatorPath: defaultedIndicatorPath,
indicatorPath,
queries,
threats: matchedThreats,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ export interface BuildThreatEnrichmentOptions {
services: AlertServices<AlertInstanceState, AlertInstanceContext, 'default'>;
threatFilters: PartialFilter[];
threatIndex: ThreatIndex;
threatIndicatorPath: ThreatIndicatorPathOrUndefined;
threatLanguage: ThreatLanguageOrUndefined;
threatQuery: ThreatQuery;
}

0 comments on commit c33dc3a

Please sign in to comment.