fix: enforce allowed-account-ids on the use-existing-credentials path

The early return for valid pre-existing credentials skipped the
allowed-account-ids check, now included.
This commit is contained in:
Tom Keller
2026-08-31 11:59:08 -07:00
parent ed5da29eb9
commit 1f2d3ed486
3 changed files with 40 additions and 19 deletions
-14
View File
@@ -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<T>(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.
*
+13 -5
View File
@@ -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;
+27
View File
@@ -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', {}, () => {