diff --git a/lib/aws.ts b/lib/aws.ts index 1e3610e..c6d3d2c 100644 --- a/lib/aws.ts +++ b/lib/aws.ts @@ -162,7 +162,7 @@ export class DefaultAwsClient implements IAws { * * @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters */ -export function safeUsername() { +function safeUsername() { try { return os.userInfo().username.replace(/[^\w+=,.@-]/g, '@'); } catch { diff --git a/test/aws.test.ts b/test/aws.test.ts index 7e9e7a5..3a9f8f3 100644 --- a/test/aws.test.ts +++ b/test/aws.test.ts @@ -1,4 +1,5 @@ -import { DefaultAwsClient, safeUsername } from '../lib'; +import * as os from 'os'; +import { DefaultAwsClient } from '../lib'; afterEach(() => { jest.requireActual('aws-sdk'); @@ -26,31 +27,37 @@ describe('discoverTargetAccount', () => { ChainableTemporaryCredentials: jest.fn(), }; }); - const aws = new DefaultAwsClient(); - - await aws.discoverTargetAccount({ - region: 'us-east-1', - assumeRoleArn: 'arn:aws:iam::123456789012:role/my-role', - assumeRoleExternalId: 'external-id', - }); - - expect(AWS.ChainableTemporaryCredentials).toHaveBeenCalledWith({ - params: { - ExternalId: 'external-id', - RoleArn: 'arn:aws:iam::123456789012:role/my-role', - RoleSessionName: `cdk-assets-${safeUsername()}`, - }, - stsConfig: { - customUserAgent: 'cdk-assets', + await withMocked(os, 'userInfo', async (userInfo) => { + userInfo.mockReturnValue({ + username: 'foo', + uid: 1, + gid: 1, + homedir: '/here', + shell: '/bin/sh', + }); + await aws.discoverTargetAccount({ region: 'us-east-1', - }, + assumeRoleArn: 'arn:aws:iam::123456789012:role/my-role', + assumeRoleExternalId: 'external-id', + }); + expect(AWS.ChainableTemporaryCredentials).toHaveBeenCalledWith({ + params: { + ExternalId: 'external-id', + RoleArn: 'arn:aws:iam::123456789012:role/my-role', + RoleSessionName: `cdk-assets-foo`, + }, + stsConfig: { + customUserAgent: 'cdk-assets', + region: 'us-east-1', + }, + }); }); }); test('returns account information', async () => { // eslint-disable-next-line @typescript-eslint/no-require-imports - const AWS = require('aws-sdk'); + require('aws-sdk'); jest.mock('aws-sdk', () => { return { @@ -75,3 +82,34 @@ describe('discoverTargetAccount', () => { }); }); }); + +export function withMocked( + obj: A, + key: K, + block: (fn: jest.Mocked[K]) => B +): B { + const original = obj[key]; + const mockFn = jest.fn(); + (obj as any)[key] = mockFn; + + let asyncFinally: boolean = false; + try { + const ret = block(mockFn as any); + if (!isPromise(ret)) { + return ret; + } + + asyncFinally = true; + return ret.finally(() => { + obj[key] = original; + }) as any; + } finally { + if (!asyncFinally) { + obj[key] = original; + } + } +} + +function isPromise(object: any): object is Promise { + return Promise.resolve(object) === object; +}