Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config-resolver): use real region in configuration #2986

Merged
merged 8 commits into from
Nov 4, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,4 @@ export const resolveCustomEndpointsConfig = <T>(
endpoint: normalizeEndpoint(input),
isCustomEndpoint: true,
useDualstackEndpoint: normalizeBoolean(input.useDualstackEndpoint!),
useFipsEndpoint: normalizeBoolean(input.useFipsEndpoint!),
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,13 @@ export interface EndpointsInputConfig {
* Enables IPv6/IPv4 dualstack endpoint.
*/
useDualstackEndpoint?: boolean | Provider<boolean>;

/**
* Enables FIPS compatible endpoints.
*/
useFipsEndpoint?: boolean | Provider<boolean>;
}

interface PreviouslyResolved {
regionInfoProvider: RegionInfoProvider;
urlParser: UrlParser;
region: Provider<string>;
useFipsEndpoint: Provider<boolean>;
}

export interface EndpointsResolvedConfig extends Required<EndpointsInputConfig> {
Expand All @@ -48,26 +44,20 @@ export interface EndpointsResolvedConfig extends Required<EndpointsInputConfig>
* Resolved value for input {@link EndpointsInputConfig.useDualstackEndpoint}
*/
useDualstackEndpoint: Provider<boolean>;

/**
* Resolved value for input {@link EndpointsInputConfig.useFipsEndpoint}
*/
useFipsEndpoint: Provider<boolean>;
}

export const resolveEndpointsConfig = <T>(
input: T & EndpointsInputConfig & PreviouslyResolved
): T & EndpointsResolvedConfig => {
const useDualstackEndpoint = normalizeBoolean(input.useDualstackEndpoint!);
const useFipsEndpoint = normalizeBoolean(input.useFipsEndpoint!);
const { endpoint, useFipsEndpoint } = input;
return {
...input,
tls: input.tls ?? true,
endpoint: input.endpoint
? normalizeEndpoint({ ...input, endpoint: input.endpoint })
endpoint: endpoint
? normalizeEndpoint({ ...input, endpoint })
: () => getEndpointFromRegion({ ...input, useDualstackEndpoint, useFipsEndpoint }),
isCustomEndpoint: input.endpoint ? true : false,
isCustomEndpoint: endpoint ? true : false,
useDualstackEndpoint,
useFipsEndpoint,
};
};
36 changes: 36 additions & 0 deletions packages/config-resolver/src/regionConfig/getRealRegion.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getRealRegion } from "./getRealRegion";
import { isFipsRegion } from "./isFipsRegion";

jest.mock("./isFipsRegion");

describe(getRealRegion.name, () => {
beforeEach(() => {
(isFipsRegion as jest.Mock).mockReturnValue(true);
});

afterEach(() => {
expect(isFipsRegion).toHaveBeenCalledTimes(1);
jest.clearAllMocks();
});

it("returns provided region if it's not FIPS", () => {
const mockRegion = "mockRegion";
(isFipsRegion as jest.Mock).mockReturnValue(false);
expect(getRealRegion(mockRegion)).toStrictEqual(mockRegion);
});

describe("FIPS regions", () => {
it.each(["fips-aws-global", "aws-fips"])(`returns "us-east-1" for "%s"`, (input) => {
expect(getRealRegion(input)).toStrictEqual("us-east-1");
});

it.each([
["us-west-1", "us-west-1-fips"],
["us-west-1", "fips-us-west-1"],
["us-west-1", "fips-dkr-us-west-1"],
["us-west-1", "fips-prod-us-west-1"],
])(`returns "%s" for "%s"`, (output, input) => {
expect(getRealRegion(input)).toStrictEqual(output);
});
});
});
8 changes: 8 additions & 0 deletions packages/config-resolver/src/regionConfig/getRealRegion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { isFipsRegion } from "./isFipsRegion";

export const getRealRegion = (region: string) =>
isFipsRegion(region)
? ["fips-aws-global", "aws-fips"].includes(region)
? "us-east-1"
: region.replace(/fips-(dkr-|prod-)?|-fips/, "")
: region;

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,28 +1,85 @@
import { normalizeRegion } from "./normalizeRegion";
import { getRealRegion } from "./getRealRegion";
import { isFipsRegion } from "./isFipsRegion";
import { resolveRegionConfig } from "./resolveRegionConfig";

jest.mock("./normalizeRegion");
jest.mock("./getRealRegion");
jest.mock("./isFipsRegion");

describe("RegionConfig", () => {
const mockRegionProvider = () => Promise.resolve("mockRegion");
const mockRegion = "mockRegion";
const mockRealRegion = "mockRealRegion";
const mockUseFipsEndpoint = () => Promise.resolve(false);

beforeEach(() => {
(normalizeRegion as jest.Mock).mockReturnValue(mockRegionProvider);
(getRealRegion as jest.Mock).mockReturnValue(mockRealRegion);
(isFipsRegion as jest.Mock).mockReturnValue(false);
});

afterEach(() => {
jest.clearAllMocks();
});

it("assigns value returned by normalizeRegion to region", async () => {
const region = "mockRegion";
expect(resolveRegionConfig({ region }).region).toBe(mockRegionProvider);
expect(normalizeRegion).toHaveBeenCalledTimes(1);
expect(normalizeRegion).toHaveBeenCalledWith(region);
describe("region", () => {
it("return normalized value with real region if passed as a string", async () => {
const resolvedRegionConfig = resolveRegionConfig({ region: mockRegion, useFipsEndpoint: mockUseFipsEndpoint });
const resolvedRegion = await resolvedRegionConfig.region();
expect(resolvedRegion).toBe(mockRealRegion);
expect(getRealRegion).toHaveBeenCalledTimes(1);
expect(getRealRegion).toHaveBeenCalledWith(mockRegion);
});

it("return provider with real region if passed as a Provider", async () => {
const resolvedRegionConfig = resolveRegionConfig({
region: () => Promise.resolve(mockRegion),
useFipsEndpoint: mockUseFipsEndpoint,
});
const resolvedRegion = await resolvedRegionConfig.region();
expect(resolvedRegion).toBe(mockRealRegion);
expect(getRealRegion).toHaveBeenCalledTimes(1);
expect(getRealRegion).toHaveBeenCalledWith(mockRegion);
});

it("throw if region is not supplied", () => {
expect(() => resolveRegionConfig({ useFipsEndpoint: mockUseFipsEndpoint })).toThrow();
});
});

it("throw if region is not supplied", () => {
expect(() => resolveRegionConfig({})).toThrow();
expect(normalizeRegion).not.toHaveBeenCalled();
describe("useFipsEndpoint", () => {
let mockRegionProvider;
let mockUseFipsEndpoint;

beforeEach(() => {
mockRegionProvider = jest.fn().mockResolvedValueOnce(Promise.resolve(mockRegion));
mockUseFipsEndpoint = jest.fn().mockResolvedValueOnce(Promise.resolve(false));
});

afterEach(() => {
expect(isFipsRegion).toHaveBeenCalledTimes(1);
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
expect(mockRegionProvider).toHaveBeenCalledTimes(1);
});

it("returns Provider which returns true for FIPS endpoints", async () => {
(isFipsRegion as jest.Mock).mockReturnValue(true);
const resolvedRegionConfig = resolveRegionConfig({
region: mockRegionProvider,
useFipsEndpoint: mockUseFipsEndpoint,
});

const useFipsEndpoint = await resolvedRegionConfig.useFipsEndpoint();
expect(useFipsEndpoint).toStrictEqual(true);
expect(mockUseFipsEndpoint).not.toHaveBeenCalled();
});

it("returns passed Provider if endpoint is not FIPS", async () => {
const resolvedRegionConfig = resolveRegionConfig({
region: mockRegionProvider,
useFipsEndpoint: mockUseFipsEndpoint,
});

const useFipsEndpoint = await resolvedRegionConfig.useFipsEndpoint();
expect(useFipsEndpoint).toStrictEqual(false);
expect(mockUseFipsEndpoint).toHaveBeenCalledTimes(1);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { Provider } from "@aws-sdk/types";

import { normalizeRegion } from "./normalizeRegion";
import { getRealRegion } from "./getRealRegion";
import { isFipsRegion } from "./isFipsRegion";

export interface RegionInputConfig {
/**
* The AWS region to which this client will send requests
*/
region?: string | Provider<string>;

/**
* Enables FIPS compatible endpoints.
*/
useFipsEndpoint?: boolean | Provider<boolean>;
}

interface PreviouslyResolved {}
Expand All @@ -16,14 +22,34 @@ export interface RegionResolvedConfig {
* Resolved value for input config {@link RegionInputConfig.region}
*/
region: Provider<string>;

/**
* Resolved value for input {@link RegionInputConfig.useFipsEndpoint}
*/
useFipsEndpoint: Provider<boolean>;
}

export const resolveRegionConfig = <T>(input: T & RegionInputConfig & PreviouslyResolved): T & RegionResolvedConfig => {
if (!input.region) {
const { region, useFipsEndpoint } = input;
if (!region) {
throw new Error("Region is missing");
}

return {
...input,
region: normalizeRegion(input.region!),
region: async () => {
if (typeof region === "string") {
return getRealRegion(region);
}
const providedRegion = await region();
return getRealRegion(providedRegion);
},
useFipsEndpoint: async () => {
const providedRegion = typeof region === "string" ? region : await region();
if (isFipsRegion(providedRegion)) {
return true;
}
return typeof useFipsEndpoint === "boolean" ? Promise.resolve(useFipsEndpoint) : useFipsEndpoint!();
},
};
};
12 changes: 6 additions & 6 deletions packages/config-resolver/src/regionInfo/getRegionInfo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ describe(getRegionInfo.name, () => {
partitionHostname: mockPartitionHostname,
});
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
hostname: mockHostname,
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
regionRegex: mockRegionRegex,
useFipsEndpoint: false,
});
});
});
Expand Down Expand Up @@ -169,10 +169,10 @@ describe(getRegionInfo.name, () => {
partitionHostname: mockPartitionHostname,
});
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
hostname: mockHostname,
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
signingRegion: mockSigningRegion,
regionRegex: mockRegionRegex,
useFipsEndpoint: false,
});
});
});
Expand Down Expand Up @@ -232,9 +232,9 @@ describe(getRegionInfo.name, () => {
partitionHostname: mockPartitionHostname,
});
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
hostname: mockHostname,
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
regionRegex: mockRegionRegex,
useFipsEndpoint: false,
});
});
});
Expand Down
4 changes: 2 additions & 2 deletions packages/config-resolver/src/regionInfo/getRegionInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ export const getRegionInfo = (
throw new Error(`Endpoint resolution failed for: ${{ resolvedRegion, useFipsEndpoint, useDualstackEndpoint }}`);
}

const signingRegion = getResolvedSigningRegion(region, {
hostname,
const signingRegion = getResolvedSigningRegion(hostname, {
signingRegion: regionHash[resolvedRegion]?.signingRegion,
regionRegex: partitionHash[partition].regionRegex,
useFipsEndpoint,
});

return {
Expand Down
Loading