Skip to content

Commit a490ce5

Browse files
Add test for Sdk instrumentation patch
1 parent 0640d9f commit a490ce5

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
"@aws-sdk/client-s3": "3.632.0",
7979
"@aws-sdk/client-secrets-manager": "3.632.0",
8080
"@aws-sdk/client-sfn": "3.632.0",
81+
"@aws-sdk/client-sts": "3.632.0",
8182
"@aws-sdk/client-sns": "3.632.0",
8283
"@opentelemetry/contrib-test-utils": "^0.45.0",
8384
"@smithy/protocol-http": "^5.0.1",

aws-distro-opentelemetry-node-autoinstrumentation/src/patches/instrumentation-patch.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ type V3PluginCommand = AwsV3Command<any, any, any, any, any> & {
370370
// (e.g., sts:AssumeRoleWithWebIdentity) which go through the same instrumented 'send' method.
371371
// Without this flag, each credential request would trigger another credential extraction attempt,
372372
// creating an infinite loop of nested AWS SDK calls.
373-
const SKIP_CREDENTIAL_CAPTURE_KEY = Symbol('skip-credential-capture');
373+
export const SKIP_CREDENTIAL_CAPTURE_KEY = Symbol('skip-credential-capture');
374374
function patchAwsSdkInstrumentation(instrumentation: Instrumentation): void {
375375
if (instrumentation) {
376376
(instrumentation as AwsInstrumentation)['_getV3SmithyClientSendPatch'] = function (

aws-distro-opentelemetry-node-autoinstrumentation/test/patches/instrumentation-patch.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Attributes,
66
diag,
77
Context as OtelContext,
8+
context as otelContext,
89
trace,
910
context,
1011
propagation,
@@ -27,6 +28,7 @@ import {
2728
AWSXRAY_TRACE_ID_HEADER_CAPITALIZED,
2829
customExtractor,
2930
headerGetter,
31+
SKIP_CREDENTIAL_CAPTURE_KEY,
3032
} from './../../src/patches/instrumentation-patch';
3133
import * as sinon from 'sinon';
3234
import { AWSXRAY_TRACE_ID_HEADER, AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
@@ -37,6 +39,7 @@ import * as nock from 'nock';
3739
import { ReadableSpan, Span as SDKSpan } from '@opentelemetry/sdk-trace-base';
3840
import { getTestSpans } from '@opentelemetry/contrib-test-utils';
3941
import { instrumentationConfigs } from '../../src/register';
42+
import { STS } from '@aws-sdk/client-sts';
4043

4144
// It is assumed that bedrock.test.ts has already registered the
4245
// necessary instrumentations for testing by calling:
@@ -692,6 +695,54 @@ describe('InstrumentationPatchTest', () => {
692695
});
693696
});
694697

698+
it('prevents recursion when credentials provider makes STS calls', async () => {
699+
let credentialsCallCount = 0;
700+
let skipCredentialCaptureValue = false;
701+
702+
// Create recursive credentials provider
703+
const recursiveCredentialsProvider = async (): Promise<any> => {
704+
credentialsCallCount++;
705+
if (otelContext.active().getValue(SKIP_CREDENTIAL_CAPTURE_KEY)) {
706+
skipCredentialCaptureValue = true;
707+
}
708+
709+
const credentialsStsClient = new STS({
710+
region: 'us-east-1',
711+
credentials: recursiveCredentialsProvider,
712+
});
713+
await credentialsStsClient
714+
.assumeRoleWithWebIdentity({
715+
RoleArn: 'arn:aws:iam::123456789012:role/test-role',
716+
RoleSessionName: 'test-session',
717+
WebIdentityToken: 'mock-token',
718+
})
719+
.catch((err: any) => {});
720+
return { accessKeyId: 'sts-access-key', secretAccessKey: 'secret' };
721+
};
722+
723+
// Create main client with recursive credentials provider
724+
const mainClient = new STS({
725+
region: 'us-east-1',
726+
credentials: recursiveCredentialsProvider,
727+
});
728+
729+
// Mock HTTP responses
730+
nock('https://sts.us-east-1.amazonaws.com')
731+
.post('/')
732+
.reply(200, '<GetCallerIdentityResponse></GetCallerIdentityResponse>');
733+
734+
// Make Lambda call - this triggers credential extraction which calls STS
735+
await mainClient.getCallerIdentity({}).catch((err: any) => {});
736+
737+
const testSpans = getTestSpans();
738+
const stsSpans = testSpans.filter(s => s.name.includes('GetCallerIdentity'));
739+
740+
expect(stsSpans.length).toBe(1);
741+
expect(credentialsCallCount).toBe(2); // 1. Main client needs credentials 2. Nested STS client needs credentials
742+
expect(skipCredentialCaptureValue).toBe(true); // Should detect skip key in context
743+
expect(stsSpans[0].attributes[AWS_ATTRIBUTE_KEYS.AWS_AUTH_ACCOUNT_ACCESS_KEY]).toBe('sts-access-key');
744+
});
745+
695746
it('injects trace context header into request via propagator', async () => {
696747
lambda = new Lambda({
697748
region: region,

0 commit comments

Comments
 (0)