Skip to content
Open
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
59 changes: 59 additions & 0 deletions src/__tests__/credentials.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as given from './given';

jest.mock('@aws-sdk/credential-providers', () => ({
fromNodeProviderChain: () => async () => ({
accessKeyId: 'DEFAULT_CHAIN',
secretAccessKey: 'default-chain',
}),
}));

type CredentialProvider = () => Promise<Record<string, unknown>>;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const resolveCredentials = (plugin: any): Promise<Record<string, unknown>> =>
(plugin.clientFactory.credentials as CredentialProvider)();

describe('AWS credentials', () => {
// osls 4 removed provider.getCredentials(); calling it throws
// AWS_SDK_V2_SURFACE_REMOVED. Falling back to the default chain would ignore
// provider.profile and --aws-profile, so the osls-resolved config must win.
it('uses the credentials osls 4 resolves via getAwsSdkV3Config()', async () => {
const plugin = given.plugin();
const identity = { accessKeyId: 'OSLS', secretAccessKey: 'osls' };
Object.assign(plugin['provider'], {
getAwsSdkV3Config: jest.fn().mockResolvedValue({
region: 'eu-west-1',
credentials: async () => identity,
}),
getCredentials: () => {
throw new Error('AWS_SDK_V2_SURFACE_REMOVED');
},
});

await expect(resolveCredentials(plugin)).resolves.toEqual(identity);
});

it('accepts static credentials from getAwsSdkV3Config()', async () => {
const plugin = given.plugin();
const identity = { accessKeyId: 'STATIC', secretAccessKey: 'static' };
Object.assign(plugin['provider'], {
getAwsSdkV3Config: jest.fn().mockResolvedValue({ credentials: identity }),
});

await expect(resolveCredentials(plugin)).resolves.toEqual(identity);
});

it('uses getCredentials() on Serverless 3 / osls 3', async () => {
const plugin = given.plugin();
Object.assign(plugin['provider'], {
getCredentials: () => ({
credentials: { accessKeyId: 'SLS3', secretAccessKey: 'sls3' },
}),
});

await expect(resolveCredentials(plugin)).resolves.toMatchObject({
accessKeyId: 'SLS3',
secretAccessKey: 'sls3',
});
});
});
11 changes: 11 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ const CONSOLE_BASE_URL = 'https://console.aws.amazon.com';
*/
const resolveCredentials = (provider: Provider): AwsCredentials => {
return async () => {
// osls 4 removed `getCredentials()` (it throws AWS_SDK_V2_SURFACE_REMOVED)
// and exposes its resolved SDK v3 client config instead.
if (typeof provider.getAwsSdkV3Config === 'function') {
const { credentials: v3Credentials } = await provider.getAwsSdkV3Config();
Comment thread
jimmyn marked this conversation as resolved.
if (!v3Credentials) {
return fromNodeProviderChain()();
}
return typeof v3Credentials === 'function'
? v3Credentials()
: v3Credentials;
}
let credentials;
try {
({ credentials } = provider.getCredentials());
Expand Down
8 changes: 8 additions & 0 deletions src/types/serverless.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,14 @@ declare module 'serverless/lib/plugins/aws/provider.js' {
region?: string;
signatureVersion?: string;
};
// osls 4 only: client config (region, credentials, retries, proxy) for
// plugin-built SDK v3 clients. Replaces request() and getCredentials().
getAwsSdkV3Config?: () => Promise<{
region?: string;
credentials?:
| import('@aws-sdk/types').AwsCredentialIdentity
| import('@aws-sdk/types').AwsCredentialIdentityProvider;
}>;
}

export default Provider;
Expand Down