Skip to content

Commit ac0ca9d

Browse files
Add test for Sdk instrumentation patch
1 parent 0bb5933 commit ac0ca9d

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
@@ -423,7 +423,7 @@ type V3PluginCommand = AwsV3Command<any, any, any, any, any> & {
423423
// (e.g., sts:AssumeRoleWithWebIdentity) which go through the same instrumented 'send' method.
424424
// Without this flag, each credential request would trigger another credential extraction attempt,
425425
// creating an infinite loop of nested AWS SDK calls.
426-
const SKIP_CREDENTIAL_CAPTURE_KEY = Symbol('skip-credential-capture');
426+
export const SKIP_CREDENTIAL_CAPTURE_KEY = Symbol('skip-credential-capture');
427427
function patchAwsSdkInstrumentation(instrumentation: Instrumentation): void {
428428
if (instrumentation) {
429429
(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,
@@ -28,6 +29,7 @@ import {
2829
customExtractor,
2930
ExtendedAwsLambdaInstrumentation,
3031
headerGetter,
32+
SKIP_CREDENTIAL_CAPTURE_KEY,
3133
} from './../../src/patches/instrumentation-patch';
3234
import * as sinon from 'sinon';
3335
import { AWSXRAY_TRACE_ID_HEADER, AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
@@ -39,6 +41,7 @@ import { ReadableSpan, Span as SDKSpan } from '@opentelemetry/sdk-trace-base';
3941
import { getTestSpans } from '@opentelemetry/contrib-test-utils';
4042
import { instrumentationConfigs } from '../../src/register';
4143
import { LoggerProvider } from '@opentelemetry/api-logs';
44+
import { STS } from '@aws-sdk/client-sts';
4245

4346
// It is assumed that bedrock.test.ts has already registered the
4447
// necessary instrumentations for testing by calling:
@@ -694,6 +697,54 @@ describe('InstrumentationPatchTest', () => {
694697
});
695698
});
696699

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

0 commit comments

Comments
 (0)