diff --git a/src/helpers.ts b/src/helpers.ts index f0b2b5c..27524ec 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -5,7 +5,6 @@ import type { Credentials, STSClient } from '@aws-sdk/client-sts'; import { GetCallerIdentityCommand } from '@aws-sdk/client-sts'; import type { AwsCredentialIdentity } from '@aws-sdk/types'; import type { UserAgent } from '@smithy/types'; -import type { CredentialsClient } from './CredentialsClient'; const MAX_TAG_VALUE_LENGTH = 256; const SANITIZATION_CHARACTER = '_'; @@ -282,19 +281,6 @@ export function isDefined(i: T | undefined | null): i is T { } /* c8 ignore stop */ -export async function areCredentialsValid(credentialsClient: CredentialsClient) { - const client = credentialsClient.stsClient; - try { - const identity = await client.send(new GetCallerIdentityCommand({})); - if (identity.Account) { - return true; - } - return false; - } catch (_) { - return false; - } -} - /** * Like core.getBooleanInput, but respects the required option. * diff --git a/src/index.ts b/src/index.ts index 9d77a52..340f44c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,12 +3,12 @@ import type { AssumeRoleCommandOutput } from '@aws-sdk/client-sts'; import { assumeRole } from './assumeRole'; import { CredentialsClient } from './CredentialsClient'; import { - areCredentialsValid, errorMessage, exportAccountId, exportCredentials, exportRegion, getBooleanInput, + getCallerIdentity, retryAndBackoff, toCredentialIdentity, translateEnvVariables, @@ -53,8 +53,8 @@ export async function run() { }); const roleChaining = getBooleanInput('role-chaining', { required: false }); const outputCredentials = getBooleanInput('output-credentials', { required: false }); - // Default to always outputting environment credentials unless profile is specified. If profile is specified, default - // to no environment credentials (but still output them if the user specifically requests it). + // Default to always outputting environment credentials unless profile is specified. If profile is specified, + // default to no environment credentials (but still output them if the user specifically requests it). const outputEnvCredentials = getBooleanInput('output-env-credentials', { required: false, default: !awsProfile }); const unsetCurrentCredentials = getBooleanInput('unset-current-credentials', { required: false }); let disableRetry = getBooleanInput('disable-retry', { required: false }); @@ -165,8 +165,16 @@ export async function run() { //if the user wants to attempt to use existing credentials, check if we have some already if (useExistingCredentials) { - const validCredentials = await areCredentialsValid(credentialsClient); - if (validCredentials) { + const identity = await (async () => { + try { + return await getCallerIdentity(credentialsClient.stsClient); + } catch { + return null; + } + })(); + if (identity) { + // The allowed-account-ids guardrail applies to reused credentials too. + validateAccountId(expectedAccountIds, identity.Account); core.notice('Pre-existing credentials are valid. No need to generate new ones.'); if (timeoutId) clearTimeout(timeoutId); return; diff --git a/test/index.test.ts b/test/index.test.ts index 24583b3..bc7d4f4 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1015,6 +1015,33 @@ describe('Configure AWS Credentials', {}, () => { await run(); expect(core.setFailed).not.toHaveBeenCalled(); }); + + it('fails on the use-existing-credentials path when the account is not allowed', async () => { + vi.mocked(core.getInput).mockImplementation( + mocks.getInput({ + ...mocks.USE_EXISTING_CREDENTIALS_INPUTS, + 'allowed-account-ids': '999999999999', + }), + ); + mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); + + await run(); + expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining('does not match')); + }); + + it('reuses existing credentials when their account is allowed', async () => { + vi.mocked(core.getInput).mockImplementation( + mocks.getInput({ + ...mocks.USE_EXISTING_CREDENTIALS_INPUTS, + 'allowed-account-ids': '111111111111', + }), + ); + mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); + + await run(); + expect(core.notice).toHaveBeenCalledWith('Pre-existing credentials are valid. No need to generate new ones.'); + expect(core.setFailed).not.toHaveBeenCalled(); + }); }); describe('Global Timeout Configuration', {}, () => {