Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions libs/shared/sentry-utils/src/lib/before-send.server.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

import { beforeSendServer } from './before-send.server';
import { filterSentryEvent } from './utils';

describe('beforeSendServer', () => {
const config = {
Expand All @@ -14,7 +13,7 @@ describe('beforeSendServer', () => {
clientName: 'fxa-shared-testing',
sampleRate: 0,
},
eventFilters: [filterSentryEvent],
eventFilters: [],
};

it('adjust event before send', () => {
Expand All @@ -28,6 +27,6 @@ describe('beforeSendServer', () => {
const hint = {};
const modified = beforeSendServer(config, data, hint);
expect(modified?.tags?.['fxa.name']).toEqual('unknown');
expect(modified?.extra?.['uid']).toEqual('[Filtered]');
expect(modified?.extra?.['uid']).toEqual('123');
});
});
298 changes: 2 additions & 296 deletions libs/shared/sentry-utils/src/lib/pii/filters.spec.ts
Original file line number Diff line number Diff line change
@@ -1,254 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import { ErrorEvent } from '@sentry/core';
import { Message } from '@aws-sdk/client-sqs';
import { IFilterAction, PiiData } from '../models/pii';
import {
CommonPiiActions,
FILTERED,
PiiRegexFilter,
TRUNCATED,
} from './filter-actions';
import { FilterBase, SentryPiiFilter, SqsMessageFilter } from './filters';
import { FILTERED, PiiRegexFilter } from './filter-actions';
import { FilterBase, SqsMessageFilter } from './filters';
import { Logger } from '../sentry.types';

describe('pii-filters', () => {
describe('SentryMessageFilter', () => {
const sentryFilter = new SentryPiiFilter([
CommonPiiActions.breadthFilter,
CommonPiiActions.depthFilter,
CommonPiiActions.urlUsernamePassword,
CommonPiiActions.emailValues,
CommonPiiActions.piiKeys,
CommonPiiActions.tokenValues,
CommonPiiActions.ipV4Values,
CommonPiiActions.ipV6Values,
new PiiRegexFilter(/foo/gi),
]);

it('filters empty event', () => {
let event: ErrorEvent = { type: undefined };
event = sentryFilter.filter(event);
expect(event).toEqual({ type: undefined });
});

it('filters event', () => {
let event: ErrorEvent = {
message: 'A foo message.',
contexts: {
ValidationError: {
_original: {
email: `foo@bar.com`,
},
details: [
{
context: {
key: 'email',
label: 'email',
name: '[undefined]',
regex: {},
value: 'none',
},
message: `foo@bar.com fails to match email pattern`,
path: ['email'],
type: 'string.pattern.base',
},
],
type: 'ValidationError',
},
},
breadcrumbs: [
{
message: 'A foo breadcrumb',
data: {
first_name: 'foo',
last_name: 'bar',
},
},
{
message: 'A fine message',
},
],
request: {
url: 'http://me:123@foo.bar/?email=foxkey@mozilla.com&uid=12345678123456781234567812345678',
query_string: {
email: 'foo',
uid: 'bar',
},
cookies: {
user: 'foo:bar',
},
env: {
key: '--foo',
},
headers: {
foo: 'a foo header',
bar: 'a foo bar bar header',
'oidc-claim': 'claim1',
},
data: {
info: {
email: 'foxkeh@mozilla.com',
uid: '12345678123456781234567812345678',
},
time: new Date(0).getTime(),
},
},
exception: {
values: [
{
value:
'Foo bar! A user with email foxkeh@mozilla.clom and ip 127.0.0.1 encountered an err.',
},
],
},
extra: {
meta: {
email: 'foo@bar.com',
},
foo: Array(51).fill('bar'),
l1: {
l2: {
l3: {
l4: {
l5: {
l6: {
l7: {
l8: {
l9: {
l10: 'bar',
},
},
},
},
},
},
},
},
},
},
user: {
meta: {
email: 'foo@bar.com',
},
id: 'foo123',
ip_address: '127.0.0.1',
email: 'foo@bar.com',
username: 'foo.bar',
},
type: undefined,
spans: undefined, // Not testing, let's be careful not put PII in spans,
measurements: undefined, // NA, just numbers
debug_meta: undefined, // NA, image data
sdkProcessingMetadata: undefined, // NA, not used
};

event = sentryFilter.filter(event);

expect(event).toEqual({
message: `A ${FILTERED} message.`,
contexts: {
ValidationError: {
_original: {
email: '[Filtered]',
},
details: [
{
context: {
key: 'email',
label: 'email',
name: '[undefined]',
regex: {},
value: 'none',
},
message: '[Filtered] fails to match email pattern',
path: ['email'],
type: 'string.pattern.base',
},
],
type: 'ValidationError',
},
},
breadcrumbs: [
{
message: `A ${FILTERED} breadcrumb`,
data: {
first_name: FILTERED,
last_name: 'bar',
},
},
{
message: 'A fine message',
},
],
request: {
url: `http://${FILTERED}:${FILTERED}@${FILTERED}.bar/?email=${FILTERED}&uid=${FILTERED}`,
query_string: {
email: FILTERED,
uid: FILTERED,
},
cookies: {
user: FILTERED,
},
env: {
key: `--${FILTERED}`,
},
headers: {
foo: `a ${FILTERED} header`,
bar: `a ${FILTERED} bar bar header`,
'oidc-claim': `${FILTERED}`,
},
data: {
info: {
email: `${FILTERED}`,
uid: `${FILTERED}`,
},
time: new Date(0).getTime(),
},
},
exception: {
values: [
{
value: `${FILTERED} bar! A user with email ${FILTERED} and ip ${FILTERED} encountered an err.`,
},
],
},
extra: {
meta: {
email: FILTERED,
},
foo: [...Array(50).fill('bar'), `${TRUNCATED}:1`],
l1: {
l2: {
l3: {
l4: {
l5: {
l6: TRUNCATED,
},
},
},
},
},
},
user: {
meta: {
email: FILTERED,
},
id: `${FILTERED}123`,
ip_address: FILTERED,
email: FILTERED,
username: FILTERED,
},
type: undefined,
spans: undefined, // Not testing, let's be careful not put PII in spans,
measurements: undefined, // NA, just numbers
debug_meta: undefined, // NA, image data
sdkProcessingMetadata: undefined, // NA, not used
});
});
});

describe('SqsMessageFilter', () => {
const sqsFilter = new SqsMessageFilter([new PiiRegexFilter(/foo/gi)]);

Expand Down Expand Up @@ -299,57 +58,4 @@ describe('pii-filters', () => {
expect(mockLogger.error).toBeCalled();
});
});

describe('Short Circuits', () => {
class ShortCircuit implements IFilterAction {
execute<T extends PiiData>(val: T, depth?: number) {
if (typeof val === 'string') {
val = FILTERED as T;
} else if (typeof val === 'object') {
for (const key in val) {
val[key] = FILTERED;
}
}
return { val, exitPipeline: true };
}
}

const shortCircuit = new ShortCircuit();
const noAction = {
execute: jest.fn(),
};

const sentryFilter = new SentryPiiFilter([
shortCircuit,
noAction as IFilterAction,
]);

afterEach(() => {
jest.restoreAllMocks();
});

it('shorts circuits', () => {
// The fact this runs with out error, indicates badAction was never invoked
const event = sentryFilter.filter({
type: undefined,
request: {
url: 'http://foo.bar',
query_string: {
foo: 'bar',
},
headers: {
foo: 'bar',
},
data: {
info: {
foo: 'bar',
},
time: new Date(0).getTime(),
},
},
});
expect(noAction.execute).toHaveBeenCalledTimes(0);
expect(event).toBeDefined();
});
});
});
Loading