From c4e92d4566b1150d1da97ec3417b6f1b5c1d9ea5 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Fri, 28 Nov 2025 15:19:30 +0000 Subject: [PATCH 1/2] fix(aws-serverless): Remove hyphens from AWS-lambda origins --- .../aws-serverless/tests/layer.test.ts | 12 ++++++------ .../aws-serverless/tests/npm.test.ts | 8 ++++---- packages/aws-serverless/src/integration/awslambda.ts | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts index bb7ae03a96e7..966ddf032218 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts @@ -23,7 +23,7 @@ test.describe('Lambda layer', () => { data: { 'sentry.sample_rate': 1, 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', + 'sentry.origin': 'auto.otel.aws_lambda', 'sentry.op': 'function.aws.lambda', 'cloud.account.id': '012345678912', 'faas.execution': expect.any(String), @@ -32,7 +32,7 @@ test.describe('Lambda layer', () => { 'otel.kind': 'SERVER', }, op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', + origin: 'auto.otel.aws_lambda', span_id: expect.stringMatching(/[a-f0-9]{16}/), status: 'ok', trace_id: expect.stringMatching(/[a-f0-9]{32}/), @@ -91,7 +91,7 @@ test.describe('Lambda layer', () => { data: { 'sentry.sample_rate': 1, 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', + 'sentry.origin': 'auto.otel.aws_lambda', 'sentry.op': 'function.aws.lambda', 'cloud.account.id': '012345678912', 'faas.execution': expect.any(String), @@ -100,7 +100,7 @@ test.describe('Lambda layer', () => { 'otel.kind': 'SERVER', }, op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', + origin: 'auto.otel.aws_lambda', span_id: expect.stringMatching(/[a-f0-9]{16}/), status: 'ok', trace_id: expect.stringMatching(/[a-f0-9]{32}/), @@ -214,7 +214,7 @@ test.describe('Lambda layer', () => { data: { 'sentry.sample_rate': 1, 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', + 'sentry.origin': 'auto.otel.aws_lambda', 'sentry.op': 'function.aws.lambda', 'cloud.account.id': '012345678912', 'faas.execution': expect.any(String), @@ -223,7 +223,7 @@ test.describe('Lambda layer', () => { 'otel.kind': 'SERVER', }, op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', + origin: 'auto.otel.aws_lambda', span_id: expect.stringMatching(/[a-f0-9]{16}/), status: 'ok', trace_id: expect.stringMatching(/[a-f0-9]{32}/), diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts index 9b4183425c95..e5b6ee1b9f32 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts @@ -23,7 +23,7 @@ test.describe('NPM package', () => { data: { 'sentry.sample_rate': 1, 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', + 'sentry.origin': 'auto.otel.aws_lambda', 'sentry.op': 'function.aws.lambda', 'cloud.account.id': '012345678912', 'faas.execution': expect.any(String), @@ -32,7 +32,7 @@ test.describe('NPM package', () => { 'otel.kind': 'SERVER', }, op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', + origin: 'auto.otel.aws_lambda', span_id: expect.stringMatching(/[a-f0-9]{16}/), status: 'ok', trace_id: expect.stringMatching(/[a-f0-9]{32}/), @@ -91,7 +91,7 @@ test.describe('NPM package', () => { data: { 'sentry.sample_rate': 1, 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', + 'sentry.origin': 'auto.otel.aws_lambda', 'sentry.op': 'function.aws.lambda', 'cloud.account.id': '012345678912', 'faas.execution': expect.any(String), @@ -100,7 +100,7 @@ test.describe('NPM package', () => { 'otel.kind': 'SERVER', }, op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', + origin: 'auto.otel.aws_lambda', span_id: expect.stringMatching(/[a-f0-9]{16}/), status: 'ok', trace_id: expect.stringMatching(/[a-f0-9]{32}/), diff --git a/packages/aws-serverless/src/integration/awslambda.ts b/packages/aws-serverless/src/integration/awslambda.ts index 2eaa1fd17354..0da2ea148a3f 100644 --- a/packages/aws-serverless/src/integration/awslambda.ts +++ b/packages/aws-serverless/src/integration/awslambda.ts @@ -24,7 +24,7 @@ export const instrumentAwsLambda = generateInstrumentOnce( ...options, eventContextExtractor, requestHook(span) { - span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.otel.aws-lambda'); + span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.otel.aws_lambda'); span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'function.aws.lambda'); }, responseHook(_span, { err }) { From d21ae3155ffb0406968d250a8e9d0d6a10672563 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Tue, 2 Dec 2025 02:02:33 +0000 Subject: [PATCH 2/2] Use locally built serverless package instead of pulling from npm in e2e tests --- .github/workflows/build.yml | 4 ++ dev-packages/e2e-tests/run.ts | 2 + .../aws-serverless/src/stack.ts | 53 +++++++++++++++++-- .../aws-serverless/tests/lambda-fixtures.ts | 28 +++++++++- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5575f81c9e4a..b351bdc647a0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -992,6 +992,8 @@ jobs: working-directory: ${{ runner.temp }}/test-application timeout-minutes: 7 run: ${{ matrix.build-command || 'pnpm test:build' }} + env: + SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Install Playwright uses: ./.github/actions/install-playwright @@ -1003,6 +1005,8 @@ jobs: working-directory: ${{ runner.temp }}/test-application timeout-minutes: 10 run: ${{ matrix.assert-command || 'pnpm test:assert' }} + env: + SENTRY_E2E_WORKSPACE_ROOT: ${{ github.workspace }} - name: Upload Playwright Traces uses: actions/upload-artifact@v5 diff --git a/dev-packages/e2e-tests/run.ts b/dev-packages/e2e-tests/run.ts index 5312dc664cee..e0331f0694f8 100644 --- a/dev-packages/e2e-tests/run.ts +++ b/dev-packages/e2e-tests/run.ts @@ -76,6 +76,8 @@ async function run(): Promise { REACT_APP_E2E_TEST_DSN: dsn, E2E_TEST_SENTRY_ORG_SLUG: process.env.E2E_TEST_SENTRY_ORG_SLUG || DEFAULT_SENTRY_ORG_SLUG, E2E_TEST_SENTRY_PROJECT: process.env.E2E_TEST_SENTRY_PROJECT || DEFAULT_SENTRY_PROJECT, + // Pass workspace root so tests copied to temp dirs can find local packages + SENTRY_E2E_WORKSPACE_ROOT: resolve(__dirname, '../..'), }; const env = { diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts index d23feae60811..f78d55bdaa53 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/src/stack.ts @@ -15,6 +15,17 @@ const LAYER_DIR = './node_modules/@sentry/aws-serverless/'; const DEFAULT_NODE_VERSION = '22'; export const SAM_PORT = 3001; +function resolvePackagesDir(): string { + // When running via the e2e test runner, tests are copied to a temp directory + // so we need the workspace root passed via env var + const workspaceRoot = process.env.SENTRY_E2E_WORKSPACE_ROOT; + if (workspaceRoot) { + return path.join(workspaceRoot, 'packages'); + } + // Fallback for local development when running from the original location + return path.resolve(__dirname, '../../../../../packages'); +} + export class LocalLambdaStack extends Stack { sentryLayer: CfnResource; @@ -67,10 +78,46 @@ export class LocalLambdaStack extends Stack { const functionName = `${addLayer ? 'Layer' : 'Npm'}${lambdaDir}`; if (!addLayer) { + const lambdaPath = path.resolve(functionsDir, lambdaDir); + const packageLockPath = path.join(lambdaPath, 'package-lock.json'); + const nodeModulesPath = path.join(lambdaPath, 'node_modules'); + + // Point the dependency at the locally built packages so tests use the current workspace bits + // We need to link all @sentry/* packages that are dependencies of aws-serverless + // because otherwise npm will try to install them from the registry, where the current version is not yet published + const packagesToLink = ['aws-serverless', 'node', 'core', 'node-core', 'opentelemetry']; + const dependencies: Record = {}; + + const packagesDir = resolvePackagesDir(); + for (const pkgName of packagesToLink) { + const pkgDir = path.join(packagesDir, pkgName); + if (!fs.existsSync(pkgDir)) { + throw new Error( + `[LocalLambdaStack] Workspace package ${pkgName} not found at ${pkgDir}. Did you run the build?`, + ); + } + const relativePath = path.relative(lambdaPath, pkgDir); + dependencies[`@sentry/${pkgName}`] = `file:${relativePath.replace(/\\/g, '/')}`; + } + console.log(`[LocalLambdaStack] Install dependencies for ${functionName}`); - const packageJson = { dependencies: { '@sentry/aws-serverless': '* || latest' } }; - fs.writeFileSync(path.join(functionsDir, lambdaDir, 'package.json'), JSON.stringify(packageJson, null, 2)); - execFileSync('npm', ['install', '--prefix', path.join(functionsDir, lambdaDir)], { stdio: 'inherit' }); + + if (fs.existsSync(packageLockPath)) { + // Prevent stale lock files from pinning the published package version + fs.rmSync(packageLockPath); + } + + if (fs.existsSync(nodeModulesPath)) { + // Ensure we reinstall from the workspace instead of reusing cached dependencies + fs.rmSync(nodeModulesPath, { recursive: true, force: true }); + } + + const packageJson = { + dependencies, + }; + + fs.writeFileSync(path.join(lambdaPath, 'package.json'), JSON.stringify(packageJson, null, 2)); + execFileSync('npm', ['install', '--prefix', lambdaPath], { stdio: 'inherit' }); } new CfnResource(this, functionName, { diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/lambda-fixtures.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/lambda-fixtures.ts index d6f331c7e96b..23aab3a7d683 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/lambda-fixtures.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/lambda-fixtures.ts @@ -17,7 +17,7 @@ export const test = base.extend<{ testEnvironment: LocalLambdaStack; lambdaClien console.log('[testEnvironment fixture] Setting up AWS Lambda test infrastructure'); execSync('docker network prune -f'); - execSync(`docker network create --driver bridge ${DOCKER_NETWORK_NAME}`); + createDockerNetwork(); const hostIp = await getHostIp(); const app = new App(); @@ -71,6 +71,8 @@ export const test = base.extend<{ testEnvironment: LocalLambdaStack; lambdaClien resolve(void 0); }, 5000); }); + + removeDockerNetwork(); } }, { scope: 'worker', auto: true }, @@ -88,3 +90,27 @@ export const test = base.extend<{ testEnvironment: LocalLambdaStack; lambdaClien await use(lambdaClient); }, }); + +function createDockerNetwork() { + try { + execSync(`docker network create --driver bridge ${DOCKER_NETWORK_NAME}`); + } catch (error) { + const stderr = (error as { stderr?: Buffer }).stderr?.toString() ?? ''; + if (stderr.includes('already exists')) { + console.log(`[testEnvironment fixture] Reusing existing docker network ${DOCKER_NETWORK_NAME}`); + return; + } + throw error; + } +} + +function removeDockerNetwork() { + try { + execSync(`docker network rm ${DOCKER_NETWORK_NAME}`); + } catch (error) { + const stderr = (error as { stderr?: Buffer }).stderr?.toString() ?? ''; + if (!stderr.includes('No such network')) { + console.warn(`[testEnvironment fixture] Failed to remove docker network ${DOCKER_NETWORK_NAME}: ${stderr}`); + } + } +}