Skip to content

Commit 33bba82

Browse files
committed
add tests
1 parent f5ce600 commit 33bba82

4 files changed

Lines changed: 158 additions & 2 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function makeHex(length) {
2+
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('');
3+
}
4+
5+
exports.handler = async event => {
6+
const dsn = event?.dsn ?? process.env.SENTRY_DSN ?? process.env.TUNNEL_TEST_DSN;
7+
8+
const envelopeHeader = event?.omitDsn
9+
? {}
10+
: {
11+
dsn,
12+
};
13+
const envelopeItemHeader = { type: 'event' };
14+
const envelopeItemPayload = {
15+
event_id: makeHex(32),
16+
message: event?.marker ?? 'lambda-extension-tunnel-test',
17+
level: 'info',
18+
};
19+
const envelope = `${JSON.stringify(envelopeHeader)}\n${JSON.stringify(envelopeItemHeader)}\n${JSON.stringify(
20+
envelopeItemPayload,
21+
)}\n`;
22+
23+
const response = await fetch('http://localhost:9000/envelope', {
24+
method: 'POST',
25+
headers: {
26+
'Content-Type': 'application/x-sentry-envelope',
27+
},
28+
body: envelope,
29+
});
30+
31+
const responseBody = await response.text();
32+
33+
return {
34+
attemptedDsn: dsn,
35+
status: response.status,
36+
responseBody,
37+
};
38+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
function makeHex(length) {
2+
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('');
3+
}
4+
5+
exports.handler = async event => {
6+
const dsn = event?.dsn ?? process.env.TUNNEL_TEST_DSN;
7+
8+
const envelopeHeader = event?.omitDsn
9+
? {}
10+
: {
11+
dsn,
12+
};
13+
const envelopeItemHeader = { type: 'event' };
14+
const envelopeItemPayload = {
15+
event_id: makeHex(32),
16+
message: event?.marker ?? 'lambda-extension-tunnel-no-dsn-test',
17+
level: 'info',
18+
};
19+
const envelope = `${JSON.stringify(envelopeHeader)}\n${JSON.stringify(envelopeItemHeader)}\n${JSON.stringify(
20+
envelopeItemPayload,
21+
)}\n`;
22+
23+
const response = await fetch('http://localhost:9000/envelope', {
24+
method: 'POST',
25+
headers: {
26+
'Content-Type': 'application/x-sentry-envelope',
27+
},
28+
body: envelope,
29+
});
30+
31+
const responseBody = await response.text();
32+
33+
return {
34+
attemptedDsn: dsn,
35+
status: response.status,
36+
responseBody,
37+
};
38+
};

dev-packages/e2e-tests/test-applications/aws-serverless-layer/src/stack.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,13 @@ export class LocalLambdaStack extends Stack {
7575
Layers: [{ Ref: this.sentryLayer.logicalId }],
7676
Environment: {
7777
Variables: {
78-
SENTRY_DSN: dsn,
7978
SENTRY_TRACES_SAMPLE_RATE: 1.0,
8079
SENTRY_DEBUG: true,
8180
NODE_OPTIONS: `--import=@sentry/aws-serverless/awslambda-auto`,
81+
// We only set SENTRY_DSN if not running TunnelNoDsn, because there
82+
// we want to test that the extension tunnel forwards requests when SENTRY_DSN is missing.
83+
TUNNEL_TEST_DSN: dsn,
84+
...(lambdaDir !== 'TunnelNoDsn' ? { SENTRY_DSN: dsn } : {}),
8285
},
8386
},
8487
},

dev-packages/e2e-tests/test-applications/aws-serverless-layer/tests/layer.test.ts

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1-
import { waitForTransaction, waitForError } from '@sentry-internal/test-utils';
1+
import { waitForTransaction, waitForError, waitForRequest } from '@sentry-internal/test-utils';
22
import { InvokeCommand } from '@aws-sdk/client-lambda';
33
import { test, expect } from './lambda-fixtures';
44

5+
interface TunnelInvokeResult {
6+
attemptedDsn?: string;
7+
status: number;
8+
responseBody: string;
9+
}
10+
11+
function parseLambdaPayload(payload: Uint8Array | undefined): TunnelInvokeResult {
12+
if (!payload) {
13+
throw new Error('Missing Lambda payload');
14+
}
15+
16+
return JSON.parse(Buffer.from(payload).toString('utf8')) as TunnelInvokeResult;
17+
}
18+
519
test.describe('Lambda layer', () => {
620
test('tracing in CJS works', async ({ lambdaClient }) => {
721
const transactionEventPromise = waitForTransaction('aws-serverless-layer', transactionEvent => {
@@ -242,4 +256,67 @@ test.describe('Lambda layer', () => {
242256
}),
243257
);
244258
});
259+
260+
test('extension tunnel validates DSN allowlist and rejects invalid envelopes', async ({ lambdaClient }) => {
261+
const matchingMarker = `extension-tunnel-matching-${Date.now()}`;
262+
const matchingRequestPromise = waitForRequest('aws-serverless-layer', requestData => {
263+
return requestData.rawProxyRequestBody.includes(matchingMarker);
264+
});
265+
266+
const matchingResponse = await lambdaClient.send(
267+
new InvokeCommand({
268+
FunctionName: 'LayerTunnel',
269+
Payload: JSON.stringify({
270+
marker: matchingMarker,
271+
}),
272+
}),
273+
);
274+
const matchingResult = parseLambdaPayload(matchingResponse.Payload);
275+
expect(matchingResult.status).toBe(200);
276+
await matchingRequestPromise;
277+
278+
const mismatchedResponse = await lambdaClient.send(
279+
new InvokeCommand({
280+
FunctionName: 'LayerTunnel',
281+
Payload: JSON.stringify({
282+
// Keep host/project/port valid but change public key, so DSN stays valid and fails allowlist match.
283+
dsn: String(matchingResult.attemptedDsn).replace('://public@', '://unauthorized@'),
284+
}),
285+
}),
286+
);
287+
const mismatchedResult = parseLambdaPayload(mismatchedResponse.Payload);
288+
expect(mismatchedResult.status).toBe(403);
289+
expect(mismatchedResult.responseBody).toContain('DSN not allowed');
290+
291+
const missingDsnResponse = await lambdaClient.send(
292+
new InvokeCommand({
293+
FunctionName: 'LayerTunnel',
294+
Payload: JSON.stringify({
295+
omitDsn: true,
296+
}),
297+
}),
298+
);
299+
const missingDsnResult = parseLambdaPayload(missingDsnResponse.Payload);
300+
expect(missingDsnResult.status).toBe(400);
301+
expect(missingDsnResult.responseBody).toContain('missing DSN');
302+
});
303+
304+
test('extension tunnel forwards requests when SENTRY_DSN is missing', async ({ lambdaClient }) => {
305+
const marker = `extension-tunnel-no-sentry-dsn-${Date.now()}`;
306+
const noDsnRequestPromise = waitForRequest('aws-serverless-layer', requestData => {
307+
return requestData.rawProxyRequestBody.includes(marker);
308+
});
309+
310+
const noDsnResponse = await lambdaClient.send(
311+
new InvokeCommand({
312+
FunctionName: 'LayerTunnelNoDsn',
313+
Payload: JSON.stringify({
314+
marker,
315+
}),
316+
}),
317+
);
318+
const noDsnResult = parseLambdaPayload(noDsnResponse.Payload);
319+
expect(noDsnResult.status).toBe(200);
320+
await noDsnRequestPromise;
321+
});
245322
});

0 commit comments

Comments
 (0)