Skip to content

Commit

Permalink
fix: OIDC Parallel Requests error
Browse files Browse the repository at this point in the history
  • Loading branch information
paragbhingre committed Jan 12, 2022
1 parent 9b99800 commit 133757e
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 13 deletions.
55 changes: 43 additions & 12 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,29 @@ function getStsClient(region) {
});
}

let defaultSleep = function (ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
};
let sleep = defaultSleep;

// retryAndBackoff retries with exponential backoff the promise if the error isRetryable upto maxRetries time.
const retryAndBackoff = async (fn, isRetryable, retries = 0, maxRetries = 12, base = 50) => {
try {
return await fn();
} catch (err) {
if (!isRetryable) {
throw err;
}
// It's retryable, so sleep and retry.
await sleep(Math.random() * (Math.pow(2, retries) * base) );
retries += 1;
if (retries === maxRetries) {
throw err;
}
return await retryAndBackoff(fn, isRetryable, retries, maxRetries, base);
}
}

async function run() {
try {
// Get inputs
Expand Down Expand Up @@ -303,17 +326,18 @@ async function run() {

// Get role credentials if configured to do so
if (roleToAssume) {
const roleCredentials = await assumeRole({
sourceAccountId,
region,
roleToAssume,
roleExternalId,
roleDurationSeconds,
roleSessionName,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
});
const roleCredentials = await retryAndBackoff(
async () => { return await assumeRole({
sourceAccountId,
region,
roleToAssume,
roleExternalId,
roleDurationSeconds,
roleSessionName,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
}) }, true);
exportCredentials(roleCredentials);
// We need to validate the credentials in 2 of our use-cases
// First: self-hosted runners. If the GITHUB_ACTIONS environment variable
Expand All @@ -337,7 +361,14 @@ async function run() {
}
}

module.exports = run;
exports.withSleep = function (s) {
sleep = s;
};
exports.reset = function () {
sleep = defaultSleep;
};

exports.run = run

/* istanbul ignore next */
if (require.main === module) {
Expand Down
24 changes: 23 additions & 1 deletion index.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const core = require('@actions/core');
const assert = require('assert');
const aws = require('aws-sdk');
const run = require('./index.js');
const { run, withSleep, reset } = require('./index.js');

jest.mock('@actions/core');

Expand Down Expand Up @@ -156,10 +156,15 @@ describe('Configure AWS Credentials', () => {
}
}
});

withSleep(() => {
return Promise.resolve();
});
});

afterEach(() => {
process.env = OLD_ENV;
reset();
});

test('exports env vars', async () => {
Expand Down Expand Up @@ -612,6 +617,23 @@ describe('Configure AWS Credentials', () => {
expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN);
});

test('role assumption fails after maximun trials using OIDC Provider', async () => {
process.env.GITHUB_ACTIONS = 'true';
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token';

core.getInput = jest
.fn()
.mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}));

mockStsAssumeRoleWithWebIdentity.mockReset();
mockStsAssumeRoleWithWebIdentity.mockImplementation(() => {
throw new Error();
});

await assert.rejects(() => run());
expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledTimes(12)
});

test('role external ID provided', async () => {
core.getInput = jest
.fn()
Expand Down

0 comments on commit 133757e

Please sign in to comment.