diff --git a/packages/credential-provider-env/src/fromEnv.spec.ts b/packages/credential-provider-env/src/fromEnv.spec.ts new file mode 100644 index 0000000000000..231dcb6a72bc0 --- /dev/null +++ b/packages/credential-provider-env/src/fromEnv.spec.ts @@ -0,0 +1,56 @@ +import { CredentialsProviderError } from "@aws-sdk/property-provider"; + +import { ENV_EXPIRATION, ENV_KEY, ENV_SECRET, ENV_SESSION, fromEnv } from "./fromEnv"; + +describe(fromEnv.name, () => { + const ORIGINAL_ENV = process.env; + const mockAccessKeyId = "mockAccessKeyId"; + const mockSecretAccessKey = "mockSecretAccessKey"; + const mockSessionToken = "mockSessionToken"; + const mockExpiration = new Date().toISOString(); + + beforeEach(() => { + process.env = { + ...ORIGINAL_ENV, + [ENV_KEY]: mockAccessKeyId, + [ENV_SECRET]: mockSecretAccessKey, + [ENV_SESSION]: mockSessionToken, + [ENV_EXPIRATION]: mockExpiration, + }; + }); + + afterEach(() => { + process.env = ORIGINAL_ENV; + }); + + it("should read credentials from known environment variables", async () => { + const receivedCreds = await fromEnv()(); + expect(receivedCreds).toStrictEqual({ + accessKeyId: mockAccessKeyId, + secretAccessKey: mockSecretAccessKey, + sessionToken: mockSessionToken, + expiration: new Date(mockExpiration), + }); + }); + + it("can create credentials without a session token or expiration", async () => { + delete process.env[ENV_SESSION]; + delete process.env[ENV_EXPIRATION]; + const receivedCreds = await fromEnv()(); + expect(receivedCreds).toStrictEqual({ + accessKeyId: mockAccessKeyId, + secretAccessKey: mockSecretAccessKey, + }); + }); + + it.each([ENV_KEY, ENV_SECRET])("throws if env['%s'] is not found", async (key) => { + delete process.env[key]; + const expectedError = new CredentialsProviderError("Unable to find environment variable credentials."); + try { + await fromEnv()(); + fail(`expected ${expectedError}`); + } catch (error) { + expect(error).toStrictEqual(expectedError); + } + }); +}); diff --git a/packages/credential-provider-env/src/fromEnv.ts b/packages/credential-provider-env/src/fromEnv.ts new file mode 100644 index 0000000000000..9df8fbde3fbd3 --- /dev/null +++ b/packages/credential-provider-env/src/fromEnv.ts @@ -0,0 +1,30 @@ +import { CredentialsProviderError } from "@aws-sdk/property-provider"; +import { CredentialProvider } from "@aws-sdk/types"; + +export const ENV_KEY = "AWS_ACCESS_KEY_ID"; +export const ENV_SECRET = "AWS_SECRET_ACCESS_KEY"; +export const ENV_SESSION = "AWS_SESSION_TOKEN"; +export const ENV_EXPIRATION = "AWS_CREDENTIAL_EXPIRATION"; + +/** + * Source AWS credentials from known environment variables. If either the + * `AWS_ACCESS_KEY_ID` or `AWS_SECRET_ACCESS_KEY` environment variable is not + * set in this process, the provider will return a rejected promise. + */ +export const fromEnv = (): CredentialProvider => async () => { + const accessKeyId: string | undefined = process.env[ENV_KEY]; + const secretAccessKey: string | undefined = process.env[ENV_SECRET]; + const sessionToken: string | undefined = process.env[ENV_SESSION]; + const expiry: string | undefined = process.env[ENV_EXPIRATION]; + + if (accessKeyId && secretAccessKey) { + return { + accessKeyId, + secretAccessKey, + ...(sessionToken && { sessionToken }), + ...(expiry && { expiration: new Date(expiry) }), + }; + } + + throw new CredentialsProviderError("Unable to find environment variable credentials."); +}; diff --git a/packages/credential-provider-env/src/index.spec.ts b/packages/credential-provider-env/src/index.spec.ts deleted file mode 100644 index b389ed73be586..0000000000000 --- a/packages/credential-provider-env/src/index.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { CredentialsProviderError } from "@aws-sdk/property-provider"; - -import { ENV_EXPIRATION, ENV_KEY, ENV_SECRET, ENV_SESSION, fromEnv } from "./"; - -const akid = process.env[ENV_KEY]; -const secret = process.env[ENV_SECRET]; -const token = process.env[ENV_SESSION]; -const expiry = process.env[ENV_EXPIRATION]; - -beforeEach(() => { - delete process.env[ENV_KEY]; - delete process.env[ENV_SECRET]; - delete process.env[ENV_SESSION]; - delete process.env[ENV_EXPIRATION]; -}); - -afterAll(() => { - process.env[ENV_KEY] = akid; - process.env[ENV_SECRET] = secret; - process.env[ENV_SESSION] = token; - process.env[ENV_EXPIRATION] = expiry; -}); - -describe("fromEnv", () => { - it("should read credentials from known environment variables", async () => { - const dateString = "1970-01-01T07:00:00Z"; - process.env[ENV_KEY] = "foo"; - process.env[ENV_SECRET] = "bar"; - process.env[ENV_SESSION] = "baz"; - process.env[ENV_EXPIRATION] = dateString; - - expect(await fromEnv()()).toEqual({ - accessKeyId: "foo", - secretAccessKey: "bar", - sessionToken: "baz", - expiration: new Date(dateString), - }); - }); - - it("can create credentials without a session token or expiration", async () => { - process.env[ENV_KEY] = "foo"; - process.env[ENV_SECRET] = "bar"; - - expect(await fromEnv()()).toEqual({ - accessKeyId: "foo", - secretAccessKey: "bar", - }); - }); - - it("should reject the promise if no environmental credentials can be found", async () => { - await expect(fromEnv()()).rejects.toMatchObject( - new CredentialsProviderError("Unable to find environment variable credentials.") - ); - }); - - it("should flag a lack of credentials as a non-terminal error", async () => { - await fromEnv()().then( - () => { - throw new Error("The promise should have been rejected."); - }, - (err) => { - expect((err as CredentialsProviderError).tryNextLink).toBe(true); - } - ); - }); -}); diff --git a/packages/credential-provider-env/src/index.ts b/packages/credential-provider-env/src/index.ts index 878c71c8987b6..17bf6daa67e0e 100755 --- a/packages/credential-provider-env/src/index.ts +++ b/packages/credential-provider-env/src/index.ts @@ -1,30 +1 @@ -import { CredentialsProviderError } from "@aws-sdk/property-provider"; -import { CredentialProvider } from "@aws-sdk/types"; - -export const ENV_KEY = "AWS_ACCESS_KEY_ID"; -export const ENV_SECRET = "AWS_SECRET_ACCESS_KEY"; -export const ENV_SESSION = "AWS_SESSION_TOKEN"; -export const ENV_EXPIRATION = "AWS_CREDENTIAL_EXPIRATION"; - -/** - * Source AWS credentials from known environment variables. If either the - * `AWS_ACCESS_KEY_ID` or `AWS_SECRET_ACCESS_KEY` environment variable is not - * set in this process, the provider will return a rejected promise. - */ -export function fromEnv(): CredentialProvider { - return () => { - const accessKeyId: string | undefined = process.env[ENV_KEY]; - const secretAccessKey: string | undefined = process.env[ENV_SECRET]; - const expiry: string | undefined = process.env[ENV_EXPIRATION]; - if (accessKeyId && secretAccessKey) { - return Promise.resolve({ - accessKeyId, - secretAccessKey, - sessionToken: process.env[ENV_SESSION], - expiration: expiry ? new Date(expiry) : undefined, - }); - } - - return Promise.reject(new CredentialsProviderError("Unable to find environment variable credentials.")); - }; -} +export * from "./fromEnv";