aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
673 lines • 100 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/* eslint-disable import/no-extraneous-dependencies */
/**
* THIS TEST SUITE DOES NOT USE aws-sdk-client-mock!
*
* We are asserting behavior of the STS Client used by SDKv3's credential provideres.
*
* In a recent SDKv3 change (between 3.699 and 3.730) the SDK team has bundled
* the STS client into the credential providers. That means that the publicly
* accessible (and hence mockable) STS Client is no longer the STS Client that
* is used by the credential providers.
*
* We therefore cannot mock the STS Client, but instead we intercept network
* calls and locally fake an STS Endpoint using the `FakeSts` class.
*/
const os = require("os");
const cdk_build_tools_1 = require("@aws-cdk/cdk-build-tools");
const cxapi = require("@aws-cdk/cx-api");
const fromEnv = require("@aws-sdk/credential-provider-env");
const promptly = require("promptly");
const uuid = require("uuid");
const fake_sts_1 = require("./fake-sts");
const aws_auth_1 = require("../../lib/api/aws-auth");
const awscli_compatible_1 = require("../../lib/api/aws-auth/awscli-compatible");
const user_agent_1 = require("../../lib/api/aws-auth/user-agent");
const plugin_1 = require("../../lib/api/plugin");
const mode_1 = require("../../lib/api/plugin/mode");
const cli_io_host_1 = require("../../lib/toolkit/cli-io-host");
const util_1 = require("../util");
const mock_sdk_1 = require("../util/mock-sdk");
// As part of the imports above we import `mock-sdk.ts` which automatically mocks
// all SDK clients. We don't want that for this test suite, so undo it.
(0, mock_sdk_1.undoAllSdkMocks)();
// Alloy mocking @aws-sdk/credential-provider-env
jest.mock('@aws-sdk/credential-provider-env', () => ({ __esModule: true, ...jest.requireActual('@aws-sdk/credential-provider-env') }));
let mockFetchMetadataToken = jest.fn();
let mockRequest = jest.fn();
jest.mock('@aws-sdk/ec2-metadata-service', () => {
return {
MetadataService: jest.fn().mockImplementation(() => {
return {
fetchMetadataToken: mockFetchMetadataToken,
request: mockRequest,
};
}),
};
});
let uid;
let pluginQueried;
beforeEach(() => {
// Cache busters!
// We prefix everything with UUIDs because:
//
// - We have a cache from account# -> credentials
// - We have a cache from access key -> account
uid = `(${uuid.v4()})`;
pluginQueried = false;
cli_io_host_1.CliIoHost.instance().logLevel = 'trace';
plugin_1.PluginHost.instance.credentialProviderSources.splice(0);
plugin_1.PluginHost.instance.credentialProviderSources.push({
isAvailable() {
return Promise.resolve(true);
},
canProvideCredentials(account) {
return Promise.resolve(account === uniq('99999'));
},
getProvider() {
pluginQueried = true;
return Promise.resolve({
accessKeyId: `${uid}plugin_key`,
secretAccessKey: 'plugin_secret',
sessionToken: 'plugin_token',
});
},
name: 'test plugin',
});
// Make sure these point to nonexistant files to start, if we don't call
// prepare() then we don't accidentally want to fall back to system config.
process.env.AWS_CONFIG_FILE = '/dev/null';
process.env.AWS_SHARED_CREDENTIALS_FILE = '/dev/null';
});
afterEach(() => {
cli_io_host_1.CliIoHost.instance().logLevel = 'info';
cdk_build_tools_1.bockfs.restore();
jest.restoreAllMocks();
});
function uniq(account) {
return `${uid}${account}`;
}
function env(account) {
return cxapi.EnvironmentUtils.make(account, 'def');
}
describe('with intercepted network calls', () => {
// Most tests will use intercepted network calls, except one test that tests
// that the right HTTP `Agent` is used.
let fakeSts;
beforeEach(() => {
fakeSts = new fake_sts_1.FakeSts();
fakeSts.begin();
// Make sure the KeyID returned by the plugin is recognized
fakeSts.registerUser(uniq('99999'), uniq('plugin_key'));
mockRequest = jest.fn().mockResolvedValue(JSON.stringify({ region: undefined }));
});
afterEach(() => {
fakeSts.restore();
});
// Set of tests where the CDK will not trigger assume-role
// (the INI file might still do assume-role)
describe('when CDK does not AssumeRole', () => {
test('uses default credentials by default', async () => {
// WHEN
const account = uniq('11111');
prepareCreds({
fakeSts,
credentials: {
default: { aws_access_key_id: 'access', $account: '11111', $fakeStsOptions: { partition: 'aws-here' } },
},
config: {
default: { region: 'eu-bla-5' },
},
});
const provider = await providerFromProfile(undefined);
// THEN
expect(provider.defaultRegion).toEqual('eu-bla-5');
await expect(provider.defaultAccount()).resolves.toEqual({ accountId: account, partition: 'aws-here' });
// Ask for a different region
const sdk = (await provider.forEnvironment({ ...env(account), region: 'rgn' }, mode_1.Mode.ForReading)).sdk;
expect((await sdkConfig(sdk).credentials()).accessKeyId).toEqual(uniq('access'));
expect(sdk.currentRegion).toEqual('rgn');
});
test('throws if no credentials could be found', async () => {
const account = uniq('11111');
const provider = await providerFromProfile(undefined);
await expect(exerciseCredentials(provider, { ...env(account), region: 'rgn' }))
.rejects
.toThrow(/Need to perform AWS calls for account .*, but no credentials have been configured, and none of these plugins found any/);
});
test('no base credentials partition if token is expired', async () => {
const account = uniq('11111');
const error = new Error('Expired Token');
error.name = 'ExpiredToken';
const identityProvider = () => Promise.reject(error);
const provider = new aws_auth_1.SdkProvider(identityProvider, 'rgn');
const creds = await provider.baseCredentialsPartition({ ...env(account), region: 'rgn' }, mode_1.Mode.ForReading);
expect(creds).toBeUndefined();
});
test('throws if profile credentials are not for the right account', async () => {
// WHEN
jest.spyOn(awscli_compatible_1.AwsCliCompatible, 'region').mockResolvedValue('us-east-123');
prepareCreds({
fakeSts,
config: {
'profile boo': { aws_access_key_id: 'access', $account: '11111' },
},
});
const provider = await providerFromProfile('boo');
await expect(exerciseCredentials(provider, env(uniq('some_account_#')))).rejects.toThrow('Need to perform AWS calls');
});
test('use profile acct/region if agnostic env requested', async () => {
// WHEN
prepareCreds({
fakeSts,
credentials: {
default: { aws_access_key_id: 'access', $account: '11111' },
},
config: {
default: { region: 'eu-bla-5' },
},
});
const provider = await providerFromProfile(undefined);
// THEN
const sdk = (await provider.forEnvironment(cxapi.EnvironmentUtils.make(cxapi.UNKNOWN_ACCOUNT, cxapi.UNKNOWN_REGION), mode_1.Mode.ForReading)).sdk;
expect((await sdkConfig(sdk).credentials()).accessKeyId).toEqual(uniq('access'));
expect((await sdk.currentAccount()).accountId).toEqual(uniq('11111'));
expect(sdk.currentRegion).toEqual('eu-bla-5');
});
test('passing profile skips EnvironmentCredentials', async () => {
// GIVEN
const fe = jest.spyOn(fromEnv, 'fromEnv');
prepareCreds({
fakeSts,
credentials: {
foo: { aws_access_key_id: 'access', $account: '11111' },
},
});
const provider = await providerFromProfile('foo');
await provider.defaultAccount();
expect(fe).not.toHaveBeenCalled();
});
test('supports profile spread over config_file and credentials_file', async () => {
// WHEN
prepareCreds({
fakeSts,
credentials: {
foo: { aws_access_key_id: 'fooccess', $account: '22222' },
},
config: {
'default': { region: 'eu-bla-5' },
'profile foo': { region: 'eu-west-1' },
},
});
const provider = await providerFromProfile('foo');
// THEN
expect(provider.defaultRegion).toEqual('eu-west-1');
await expect(provider.defaultAccount()).resolves.toEqual({ accountId: uniq('22222'), partition: 'aws' });
const sdk = (await provider.forEnvironment(env(uniq('22222')), mode_1.Mode.ForReading)).sdk;
expect((await sdkConfig(sdk).credentials()).accessKeyId).toEqual(uniq('fooccess'));
});
test('supports profile only in config_file', async () => {
// WHEN
prepareCreds({
fakeSts,
config: {
'default': { region: 'eu-bla-5' },
'profile foo': { aws_access_key_id: 'fooccess', $account: '22222' },
},
});
const provider = await providerFromProfile('foo');
// THEN
expect(provider.defaultRegion).toEqual('eu-bla-5'); // Fall back to default config
await expect(provider.defaultAccount()).resolves.toEqual({ accountId: uniq('22222'), partition: 'aws' });
const sdk = (await provider.forEnvironment(env(uniq('22222')), mode_1.Mode.ForReading)).sdk;
expect((await sdkConfig(sdk).credentials()).accessKeyId).toEqual(uniq('fooccess'));
});
test('can assume-role configured in config', async () => {
// GIVEN
jest.spyOn(console, 'debug');
prepareCreds({
fakeSts,
credentials: {
assumer: { aws_access_key_id: 'assumer', $account: '11111' },
},
config: {
'default': { region: 'eu-bla-5' },
'profile assumer': { region: 'us-east-2' },
'profile assumable': {
role_arn: 'arn:aws:iam::66666:role/Assumable',
source_profile: 'assumer',
$account: '66666',
$fakeStsOptions: { allowedAccounts: ['11111'] },
},
},
});
const provider = await providerFromProfile('assumable');
// WHEN
const sdk = (await provider.forEnvironment(env(uniq('66666')), mode_1.Mode.ForReading)).sdk;
// THEN
expect((await sdk.currentAccount()).accountId).toEqual(uniq('66666'));
});
test('can assume role even if [default] profile is missing', async () => {
// GIVEN
prepareCreds({
fakeSts,
credentials: {
assumer: { aws_access_key_id: 'assumer', $account: '22222' },
assumable: {
role_arn: 'arn:aws:iam::12356789012:role/Assumable',
source_profile: 'assumer',
$account: '22222',
},
},
config: {
'profile assumable': { region: 'eu-bla-5' },
},
});
// WHEN
const provider = await providerFromProfile('assumable');
// THEN
expect((await provider.defaultAccount())?.accountId).toEqual(uniq('22222'));
});
const providersForMfa = [
(() => providerFromProfile('mfa-role')),
(async () => {
// The profile is not passed explicitly. Should be picked from the environment variable
process.env.AWS_PROFILE = 'mfa-role';
// Awaiting to make sure the environment variable is only deleted after it's used
const provider = await aws_auth_1.SdkProvider.withAwsCliCompatibleDefaults({ logger: console });
delete process.env.AWS_PROFILE;
return Promise.resolve(provider);
}),
];
test.each(providersForMfa)('mfa_serial in profile will ask user for token', async (metaProvider) => {
// GIVEN
const mockPrompt = jest.spyOn(promptly, 'prompt').mockResolvedValue('1234');
prepareCreds({
fakeSts,
credentials: {
assumer: { aws_access_key_id: 'assumer', $account: '66666' },
},
config: {
'default': { region: 'eu-bla-5' },
'profile assumer': { region: 'us-east-2' },
'profile mfa-role': {
role_arn: 'arn:aws:iam::66666:role/Assumable',
source_profile: 'assumer',
mfa_serial: 'arn:aws:iam::account:mfa/user',
$account: '66666',
},
},
});
const provider = await metaProvider();
// THEN
const sdk = (await provider.forEnvironment(env(uniq('66666')), mode_1.Mode.ForReading)).sdk;
expect((await sdk.currentAccount()).accountId).toEqual(uniq('66666'));
// Make sure the MFA mock was called during this test, only once
// (Credentials need to remain cached)
expect(mockPrompt).toHaveBeenCalledTimes(1);
});
});
// For DefaultSynthesis we will do an assume-role after having gotten base credentials
describe('when CDK AssumeRoles', () => {
beforeEach(() => {
// All these tests share that 'arn:aws:role' is a role into account 88888 which can be assumed from 11111
fakeSts.registerRole(uniq('88888'), 'arn:aws:role', { allowedAccounts: [uniq('11111')] });
});
test('error we get from assuming a role is useful', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo' },
},
});
const provider = await providerFromProfile(undefined);
// WHEN
const promise = exerciseCredentials(provider, env(uniq('88888')), mode_1.Mode.ForReading, {
assumeRoleArn: 'doesnotexist.role.arn',
});
// THEN - error message contains both a helpful hint and the underlying AssumeRole message
await expect(promise).rejects.toThrow('(re)-bootstrap the environment');
await expect(promise).rejects.toThrow('doesnotexist.role.arn');
});
test('assuming a role sanitizes the username into the session name', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '11111' },
},
});
await (0, util_1.withMocked)(os, 'userInfo', async (userInfo) => {
userInfo.mockReturnValue({ username: 'skål', uid: 1, gid: 1, homedir: '/here', shell: '/bin/sh' });
// WHEN
const provider = await providerFromProfile(undefined);
const sdk = (await provider.forEnvironment(env(uniq('88888')), mode_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' })).sdk;
await sdk.currentAccount();
// THEN
expect(fakeSts.assumedRoles).toContainEqual(expect.objectContaining({
roleSessionName: 'aws-cdk-sk@l',
}));
});
});
test('session tags can be passed when assuming a role', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '11111' },
},
});
await (0, util_1.withMocked)(os, 'userInfo', async (userInfo) => {
userInfo.mockReturnValue({ username: 'skål', uid: 1, gid: 1, homedir: '/here', shell: '/bin/sh' });
// WHEN
const provider = await providerFromProfile(undefined);
const sdk = (await provider.forEnvironment(env(uniq('88888')), mode_1.Mode.ForReading, {
assumeRoleArn: 'arn:aws:role',
assumeRoleExternalId: 'bruh',
assumeRoleAdditionalOptions: {
Tags: [{ Key: 'Department', Value: 'Engineering' }],
},
})).sdk;
await sdk.currentAccount();
// THEN
expect(fakeSts.assumedRoles).toContainEqual(expect.objectContaining({
tags: [{ Key: 'Department', Value: 'Engineering' }],
transitiveTagKeys: ['Department'],
roleArn: 'arn:aws:role',
externalId: 'bruh',
roleSessionName: 'aws-cdk-sk@l',
}));
});
});
test('assuming a role does not fail when OS username cannot be read', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '11111' },
},
});
await (0, util_1.withMocked)(os, 'userInfo', async (userInfo) => {
userInfo.mockImplementation(() => {
// SystemError thrown as documented: https://nodejs.org/docs/latest-v16.x/api/os.html#osuserinfooptions
throw new Error('SystemError on Linux: uv_os_get_passwd returned ENOENT. See #19401 issue.');
});
// WHEN
const provider = await providerFromProfile(undefined);
await exerciseCredentials(provider, env(uniq('88888')), mode_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' });
// THEN
expect(fakeSts.assumedRoles).toContainEqual(expect.objectContaining({
roleArn: 'arn:aws:role',
roleSessionName: 'aws-cdk-noname',
}));
});
});
test('even if current credentials are for the wrong account, we will still use them to AssumeRole', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '11111' },
},
});
const provider = await providerFromProfile(undefined);
// WHEN
const sdk = (await provider.forEnvironment(env(uniq('88888')), mode_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' })).sdk;
// THEN
expect((await sdk.currentAccount()).accountId).toEqual(uniq('88888'));
});
test('if AssumeRole fails but current credentials are for the right account, we will still use them', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '88888' },
},
});
const provider = await providerFromProfile(undefined);
// WHEN - assumeRole fails because the role can only be assumed from account 11111
const sdk = (await provider.forEnvironment(env(uniq('88888')), mode_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' })).sdk;
// THEN
expect((await sdk.currentAccount()).accountId).toEqual(uniq('88888'));
});
test('if AssumeRole fails because of ExpiredToken, then fail completely', async () => {
// GIVEN
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '88888' },
},
});
const provider = await providerFromProfile(undefined);
// WHEN - assumeRole fails with a specific error
await expect(exerciseCredentials(provider, env(uniq('88888')), mode_1.Mode.ForReading, { assumeRoleArn: '<FAIL:ExpiredToken>' }))
.rejects.toThrow(/ExpiredToken/);
});
});
describe('Plugins', () => {
test('does not use plugins if current credentials are for expected account', async () => {
prepareCreds({
fakeSts,
config: {
default: { aws_access_key_id: 'foo', $account: '11111' },
},
});
const provider = await providerFromProfile(undefined);
await exerciseCredentials(provider, env(uniq('11111')));
expect(pluginQueried).toEqual(false);
});
test('uses plugin for account 99999', async () => {
const provider = await providerFromProfile(undefined);
await exerciseCredentials(provider, env(uniq('99999')));
expect(pluginQueried).toEqual(true);
});
test('can assume role with credentials from plugin', async () => {
fakeSts.registerRole(uniq('99999'), 'arn:aws:iam::99999:role/Assumable');
const provider = await providerFromProfile(undefined);
await exerciseCredentials(provider, env(uniq('99999')), mode_1.Mode.ForReading, {
assumeRoleArn: 'arn:aws:iam::99999:role/Assumable',
});
expect(pluginQueried).toEqual(true);
expect(fakeSts.assumedRoles).toContainEqual(expect.objectContaining({
roleArn: 'arn:aws:iam::99999:role/Assumable',
roleSessionName: expect.anything(),
}));
});
test('even if AssumeRole fails but current credentials are from a plugin, we will still use them', async () => {
const provider = await providerFromProfile(undefined);
const sdk = (await provider.forEnvironment(env(uniq('99999')), mode_1.Mode.ForReading, { assumeRoleArn: 'does:not:exist' })).sdk;
// THEN
expect((await sdk.currentAccount()).accountId).toEqual(uniq('99999'));
});
test('plugins are still queried even if current credentials are expired (or otherwise invalid)', async () => {
// GIVEN
prepareCreds({
credentials: {
default: { aws_access_key_id: `${uid}akid`, $account: '11111', $fakeStsOptions: { partition: 'aws-here' } },
},
config: {
default: { region: 'eu-bla-5' },
},
});
process.env.AWS_ACCESS_KEY_ID = `${uid}akid`;
process.env.AWS_SECRET_ACCESS_KEY = 'sekrit';
const provider = await providerFromProfile(undefined);
// WHEN
await exerciseCredentials(provider, env(uniq('99999')));
// THEN
expect(pluginQueried).toEqual(true);
});
});
describe('support for credential_source', () => {
test('can assume role with ecs credentials', async () => {
// GIVEN
const calls = jest.spyOn(console, 'debug');
prepareCreds({
config: {
'profile ecs': {
role_arn: 'arn:aws:iam::12356789012:role/Assumable',
credential_source: 'EcsContainer',
$account: '22222',
},
},
});
// WHEN
const provider = await providerFromProfile('ecs');
await provider.defaultAccount();
// THEN
expect(calls.mock.calls).toContainEqual([
'@aws-sdk/credential-provider-ini - finding credential resolver using profile=[ecs]',
]);
expect(calls.mock.calls).toContainEqual(['@aws-sdk/credential-provider-ini - credential_source is EcsContainer']);
});
test('can assume role with ec2 credentials', async () => {
// GIVEN
const calls = jest.spyOn(console, 'debug');
prepareCreds({
config: {
'profile ecs': {
role_arn: 'arn:aws:iam::12356789012:role/Assumable',
credential_source: 'Ec2InstanceMetadata',
$account: '22222',
},
},
});
// WHEN
const provider = await providerFromProfile('ecs');
await provider.defaultAccount();
// THEN
expect(calls.mock.calls).toContainEqual([
'@aws-sdk/credential-provider-ini - finding credential resolver using profile=[ecs]',
]);
expect(calls.mock.calls).toContainEqual([
'@aws-sdk/credential-provider-ini - credential_source is Ec2InstanceMetadata',
]);
});
test('can assume role with env credentials', async () => {
// GIVEN
const calls = jest.spyOn(console, 'debug');
prepareCreds({
config: {
'profile ecs': {
role_arn: 'arn:aws:iam::12356789012:role/Assumable',
credential_source: 'Environment',
$account: '22222',
},
},
});
// WHEN
const provider = await providerFromProfile('ecs');
await provider.defaultAccount();
// THEN
expect(calls.mock.calls).toContainEqual([
'@aws-sdk/credential-provider-ini - finding credential resolver using profile=[ecs]',
]);
expect(calls.mock.calls).toContainEqual(['@aws-sdk/credential-provider-ini - credential_source is Environment']);
});
test('assume fails with unsupported credential_source', async () => {
// GIVEN
prepareCreds({
config: {
'profile ecs': {
role_arn: 'arn:aws:iam::12356789012:role/Assumable',
credential_source: 'unsupported',
$account: '22222',
},
},
});
const provider = await providerFromProfile('ecs');
// WHEN
const account = await provider.defaultAccount();
// THEN
expect(account?.accountId).toEqual(undefined);
});
});
test('defaultAccount returns undefined if STS call fails', async () => {
// GIVEN
fakeSts.failAssumeRole = new Error('Oops, bad sekrit');
// WHEN
const provider = await providerFromProfile(undefined);
// THEN
await expect(provider.defaultAccount()).resolves.toBe(undefined);
});
test('defaultAccount returns undefined, event if STS call fails with ExpiredToken', async () => {
// GIVEN
const error = new Error('Too late');
error.name = 'ExpiredToken';
fakeSts.failAssumeRole = error;
// WHEN
const provider = await providerFromProfile(undefined);
// THEN
await expect(provider.defaultAccount()).resolves.toBe(undefined);
});
});
test('default useragent is reasonable', () => {
expect((0, user_agent_1.defaultCliUserAgent)()).toContain('aws-cdk/');
});
/**
* Use object hackery to get the credentials out of the SDK object
*/
function sdkConfig(sdk) {
return sdk.config;
}
/**
* Fixture for SDK auth for this test suite
*
* Has knowledge of the cache buster, will write proper fake config files and
* register users and roles in FakeSts at the same time.
*/
function prepareCreds(options) {
function convertSections(sections) {
const ret = [];
for (const [profile, user] of Object.entries(sections ?? {})) {
ret.push(`[${profile}]`);
if (isProfileRole(user)) {
ret.push(`role_arn=${user.role_arn}`);
if ('source_profile' in user) {
ret.push(`source_profile=${user.source_profile}`);
}
if ('credential_source' in user) {
ret.push(`credential_source=${user.credential_source}`);
}
if (user.mfa_serial) {
ret.push(`mfa_serial=${user.mfa_serial}`);
}
options.fakeSts?.registerRole(uniq(user.$account ?? '00000'), user.role_arn, {
...user.$fakeStsOptions,
allowedAccounts: user.$fakeStsOptions?.allowedAccounts?.map(uniq),
});
}
else {
if (user.aws_access_key_id) {
ret.push(`aws_access_key_id=${uniq(user.aws_access_key_id)}`);
ret.push('aws_secret_access_key=secret');
options.fakeSts?.registerUser(uniq(user.$account ?? '00000'), uniq(user.aws_access_key_id), user.$fakeStsOptions);
}
}
if (user.region) {
ret.push(`region=${user.region}`);
}
}
return ret.join('\n');
}
(0, cdk_build_tools_1.bockfs)({
'/home/me/.bxt/credentials': convertSections(options.credentials),
'/home/me/.bxt/config': convertSections(options.config),
});
// Set environment variables that we want
process.env.AWS_CONFIG_FILE = cdk_build_tools_1.bockfs.path('/home/me/.bxt/config');
process.env.AWS_SHARED_CREDENTIALS_FILE = cdk_build_tools_1.bockfs.path('/home/me/.bxt/credentials');
}
function isProfileRole(x) {
return 'role_arn' in x;
}
async function providerFromProfile(profile) {
return aws_auth_1.SdkProvider.withAwsCliCompatibleDefaults({ profile, logger: console });
}
async function exerciseCredentials(provider, e, mode = mode_1.Mode.ForReading, options) {
const sdk = await provider.forEnvironment(e, mode, options);
await sdk.sdk.currentAccount();
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2RrLXByb3ZpZGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZGstcHJvdmlkZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHNEQUFzRDtBQUN0RDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCx5QkFBeUI7QUFDekIsOERBQWtEO0FBQ2xELHlDQUF5QztBQUN6Qyw0REFBNEQ7QUFDNUQscUNBQXFDO0FBQ3JDLDZCQUE2QjtBQUM3Qix5Q0FBK0U7QUFDL0UscURBQW9HO0FBQ3BHLGdGQUE0RTtBQUM1RSxrRUFBd0U7QUFDeEUsaURBQWtEO0FBQ2xELG9EQUFpRDtBQUNqRCwrREFBMEQ7QUFDMUQsa0NBQXFDO0FBQ3JDLCtDQUFtRDtBQUVuRCxpRkFBaUY7QUFDakYsdUVBQXVFO0FBQ3ZFLElBQUEsMEJBQWUsR0FBRSxDQUFDO0FBRWxCLGlEQUFpRDtBQUNqRCxJQUFJLENBQUMsSUFBSSxDQUFDLGtDQUFrQyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxrQ0FBa0MsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRXZJLElBQUksc0JBQXNCLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0FBQ3ZDLElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUU1QixJQUFJLENBQUMsSUFBSSxDQUFDLCtCQUErQixFQUFFLEdBQUcsRUFBRTtJQUM5QyxPQUFPO1FBQ0wsZUFBZSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLEVBQUU7WUFDakQsT0FBTztnQkFDTCxrQkFBa0IsRUFBRSxzQkFBc0I7Z0JBQzFDLE9BQU8sRUFBRSxXQUFXO2FBQ3JCLENBQUM7UUFDSixDQUFDLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLEdBQVcsQ0FB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