Skip to content

Commit af5b00e

Browse files
authored
feat(config-resolver): use real region in configuration (#2986)
1 parent 41d3762 commit af5b00e

17 files changed

+166
-4280
lines changed

packages/config-resolver/src/endpointsConfig/resolveCustomEndpointsConfig.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,4 @@ export const resolveCustomEndpointsConfig = <T>(
3131
endpoint: normalizeEndpoint(input),
3232
isCustomEndpoint: true,
3333
useDualstackEndpoint: normalizeBoolean(input.useDualstackEndpoint!),
34-
useFipsEndpoint: normalizeBoolean(input.useFipsEndpoint!),
3534
});

packages/config-resolver/src/endpointsConfig/resolveEndpointsConfig.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,13 @@ export interface EndpointsInputConfig {
1919
* Enables IPv6/IPv4 dualstack endpoint.
2020
*/
2121
useDualstackEndpoint?: boolean | Provider<boolean>;
22-
23-
/**
24-
* Enables FIPS compatible endpoints.
25-
*/
26-
useFipsEndpoint?: boolean | Provider<boolean>;
2722
}
2823

2924
interface PreviouslyResolved {
3025
regionInfoProvider: RegionInfoProvider;
3126
urlParser: UrlParser;
3227
region: Provider<string>;
28+
useFipsEndpoint: Provider<boolean>;
3329
}
3430

3531
export interface EndpointsResolvedConfig extends Required<EndpointsInputConfig> {
@@ -48,26 +44,20 @@ export interface EndpointsResolvedConfig extends Required<EndpointsInputConfig>
4844
* Resolved value for input {@link EndpointsInputConfig.useDualstackEndpoint}
4945
*/
5046
useDualstackEndpoint: Provider<boolean>;
51-
52-
/**
53-
* Resolved value for input {@link EndpointsInputConfig.useFipsEndpoint}
54-
*/
55-
useFipsEndpoint: Provider<boolean>;
5647
}
5748

5849
export const resolveEndpointsConfig = <T>(
5950
input: T & EndpointsInputConfig & PreviouslyResolved
6051
): T & EndpointsResolvedConfig => {
6152
const useDualstackEndpoint = normalizeBoolean(input.useDualstackEndpoint!);
62-
const useFipsEndpoint = normalizeBoolean(input.useFipsEndpoint!);
53+
const { endpoint, useFipsEndpoint } = input;
6354
return {
6455
...input,
6556
tls: input.tls ?? true,
66-
endpoint: input.endpoint
67-
? normalizeEndpoint({ ...input, endpoint: input.endpoint })
57+
endpoint: endpoint
58+
? normalizeEndpoint({ ...input, endpoint })
6859
: () => getEndpointFromRegion({ ...input, useDualstackEndpoint, useFipsEndpoint }),
69-
isCustomEndpoint: input.endpoint ? true : false,
60+
isCustomEndpoint: endpoint ? true : false,
7061
useDualstackEndpoint,
71-
useFipsEndpoint,
7262
};
7363
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { getRealRegion } from "./getRealRegion";
2+
import { isFipsRegion } from "./isFipsRegion";
3+
4+
jest.mock("./isFipsRegion");
5+
6+
describe(getRealRegion.name, () => {
7+
beforeEach(() => {
8+
(isFipsRegion as jest.Mock).mockReturnValue(true);
9+
});
10+
11+
afterEach(() => {
12+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
13+
jest.clearAllMocks();
14+
});
15+
16+
it("returns provided region if it's not FIPS", () => {
17+
const mockRegion = "mockRegion";
18+
(isFipsRegion as jest.Mock).mockReturnValue(false);
19+
expect(getRealRegion(mockRegion)).toStrictEqual(mockRegion);
20+
});
21+
22+
describe("FIPS regions", () => {
23+
it.each(["fips-aws-global", "aws-fips"])(`returns "us-east-1" for "%s"`, (input) => {
24+
expect(getRealRegion(input)).toStrictEqual("us-east-1");
25+
});
26+
27+
it.each([
28+
["us-west-1", "us-west-1-fips"],
29+
["us-west-1", "fips-us-west-1"],
30+
["us-west-1", "fips-dkr-us-west-1"],
31+
["us-west-1", "fips-prod-us-west-1"],
32+
])(`returns "%s" for "%s"`, (output, input) => {
33+
expect(getRealRegion(input)).toStrictEqual(output);
34+
});
35+
});
36+
});
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { isFipsRegion } from "./isFipsRegion";
2+
3+
export const getRealRegion = (region: string) =>
4+
isFipsRegion(region)
5+
? ["fips-aws-global", "aws-fips"].includes(region)
6+
? "us-east-1"
7+
: region.replace(/fips-(dkr-|prod-)?|-fips/, "")
8+
: region;

packages/config-resolver/src/regionConfig/normalizeRegion.spec.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

packages/config-resolver/src/regionConfig/normalizeRegion.ts

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,85 @@
1-
import { normalizeRegion } from "./normalizeRegion";
1+
import { getRealRegion } from "./getRealRegion";
2+
import { isFipsRegion } from "./isFipsRegion";
23
import { resolveRegionConfig } from "./resolveRegionConfig";
34

4-
jest.mock("./normalizeRegion");
5+
jest.mock("./getRealRegion");
6+
jest.mock("./isFipsRegion");
57

68
describe("RegionConfig", () => {
7-
const mockRegionProvider = () => Promise.resolve("mockRegion");
9+
const mockRegion = "mockRegion";
10+
const mockRealRegion = "mockRealRegion";
11+
const mockUseFipsEndpoint = () => Promise.resolve(false);
812

913
beforeEach(() => {
10-
(normalizeRegion as jest.Mock).mockReturnValue(mockRegionProvider);
14+
(getRealRegion as jest.Mock).mockReturnValue(mockRealRegion);
15+
(isFipsRegion as jest.Mock).mockReturnValue(false);
1116
});
1217

1318
afterEach(() => {
1419
jest.clearAllMocks();
1520
});
1621

17-
it("assigns value returned by normalizeRegion to region", async () => {
18-
const region = "mockRegion";
19-
expect(resolveRegionConfig({ region }).region).toBe(mockRegionProvider);
20-
expect(normalizeRegion).toHaveBeenCalledTimes(1);
21-
expect(normalizeRegion).toHaveBeenCalledWith(region);
22+
describe("region", () => {
23+
it("return normalized value with real region if passed as a string", async () => {
24+
const resolvedRegionConfig = resolveRegionConfig({ region: mockRegion, useFipsEndpoint: mockUseFipsEndpoint });
25+
const resolvedRegion = await resolvedRegionConfig.region();
26+
expect(resolvedRegion).toBe(mockRealRegion);
27+
expect(getRealRegion).toHaveBeenCalledTimes(1);
28+
expect(getRealRegion).toHaveBeenCalledWith(mockRegion);
29+
});
30+
31+
it("return provider with real region if passed as a Provider", async () => {
32+
const resolvedRegionConfig = resolveRegionConfig({
33+
region: () => Promise.resolve(mockRegion),
34+
useFipsEndpoint: mockUseFipsEndpoint,
35+
});
36+
const resolvedRegion = await resolvedRegionConfig.region();
37+
expect(resolvedRegion).toBe(mockRealRegion);
38+
expect(getRealRegion).toHaveBeenCalledTimes(1);
39+
expect(getRealRegion).toHaveBeenCalledWith(mockRegion);
40+
});
41+
42+
it("throw if region is not supplied", () => {
43+
expect(() => resolveRegionConfig({ useFipsEndpoint: mockUseFipsEndpoint })).toThrow();
44+
});
2245
});
2346

24-
it("throw if region is not supplied", () => {
25-
expect(() => resolveRegionConfig({})).toThrow();
26-
expect(normalizeRegion).not.toHaveBeenCalled();
47+
describe("useFipsEndpoint", () => {
48+
let mockRegionProvider;
49+
let mockUseFipsEndpoint;
50+
51+
beforeEach(() => {
52+
mockRegionProvider = jest.fn().mockResolvedValueOnce(Promise.resolve(mockRegion));
53+
mockUseFipsEndpoint = jest.fn().mockResolvedValueOnce(Promise.resolve(false));
54+
});
55+
56+
afterEach(() => {
57+
expect(isFipsRegion).toHaveBeenCalledTimes(1);
58+
expect(isFipsRegion).toHaveBeenCalledWith(mockRegion);
59+
expect(mockRegionProvider).toHaveBeenCalledTimes(1);
60+
});
61+
62+
it("returns Provider which returns true for FIPS endpoints", async () => {
63+
(isFipsRegion as jest.Mock).mockReturnValue(true);
64+
const resolvedRegionConfig = resolveRegionConfig({
65+
region: mockRegionProvider,
66+
useFipsEndpoint: mockUseFipsEndpoint,
67+
});
68+
69+
const useFipsEndpoint = await resolvedRegionConfig.useFipsEndpoint();
70+
expect(useFipsEndpoint).toStrictEqual(true);
71+
expect(mockUseFipsEndpoint).not.toHaveBeenCalled();
72+
});
73+
74+
it("returns passed Provider if endpoint is not FIPS", async () => {
75+
const resolvedRegionConfig = resolveRegionConfig({
76+
region: mockRegionProvider,
77+
useFipsEndpoint: mockUseFipsEndpoint,
78+
});
79+
80+
const useFipsEndpoint = await resolvedRegionConfig.useFipsEndpoint();
81+
expect(useFipsEndpoint).toStrictEqual(false);
82+
expect(mockUseFipsEndpoint).toHaveBeenCalledTimes(1);
83+
});
2784
});
2885
});
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import { Provider } from "@aws-sdk/types";
22

3-
import { normalizeRegion } from "./normalizeRegion";
3+
import { getRealRegion } from "./getRealRegion";
4+
import { isFipsRegion } from "./isFipsRegion";
45

56
export interface RegionInputConfig {
67
/**
78
* The AWS region to which this client will send requests
89
*/
910
region?: string | Provider<string>;
11+
12+
/**
13+
* Enables FIPS compatible endpoints.
14+
*/
15+
useFipsEndpoint?: boolean | Provider<boolean>;
1016
}
1117

1218
interface PreviouslyResolved {}
@@ -16,14 +22,34 @@ export interface RegionResolvedConfig {
1622
* Resolved value for input config {@link RegionInputConfig.region}
1723
*/
1824
region: Provider<string>;
25+
26+
/**
27+
* Resolved value for input {@link RegionInputConfig.useFipsEndpoint}
28+
*/
29+
useFipsEndpoint: Provider<boolean>;
1930
}
2031

2132
export const resolveRegionConfig = <T>(input: T & RegionInputConfig & PreviouslyResolved): T & RegionResolvedConfig => {
22-
if (!input.region) {
33+
const { region, useFipsEndpoint } = input;
34+
if (!region) {
2335
throw new Error("Region is missing");
2436
}
37+
2538
return {
2639
...input,
27-
region: normalizeRegion(input.region!),
40+
region: async () => {
41+
if (typeof region === "string") {
42+
return getRealRegion(region);
43+
}
44+
const providedRegion = await region();
45+
return getRealRegion(providedRegion);
46+
},
47+
useFipsEndpoint: async () => {
48+
const providedRegion = typeof region === "string" ? region : await region();
49+
if (isFipsRegion(providedRegion)) {
50+
return true;
51+
}
52+
return typeof useFipsEndpoint === "boolean" ? Promise.resolve(useFipsEndpoint) : useFipsEndpoint!();
53+
},
2854
};
2955
};

packages/config-resolver/src/regionInfo/getRegionInfo.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ describe(getRegionInfo.name, () => {
105105
partitionHostname: mockPartitionHostname,
106106
});
107107
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
108-
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
109-
hostname: mockHostname,
108+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
110109
regionRegex: mockRegionRegex,
110+
useFipsEndpoint: false,
111111
});
112112
});
113113
});
@@ -169,10 +169,10 @@ describe(getRegionInfo.name, () => {
169169
partitionHostname: mockPartitionHostname,
170170
});
171171
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
172-
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
173-
hostname: mockHostname,
172+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
174173
signingRegion: mockSigningRegion,
175174
regionRegex: mockRegionRegex,
175+
useFipsEndpoint: false,
176176
});
177177
});
178178
});
@@ -232,9 +232,9 @@ describe(getRegionInfo.name, () => {
232232
partitionHostname: mockPartitionHostname,
233233
});
234234
expect(getResolvedPartition).toHaveBeenCalledWith(mockRegion, mockGetResolvedPartitionOptions);
235-
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockRegion, {
236-
hostname: mockHostname,
235+
expect(getResolvedSigningRegion).toHaveBeenCalledWith(mockHostname, {
237236
regionRegex: mockRegionRegex,
237+
useFipsEndpoint: false,
238238
});
239239
});
240240
});

packages/config-resolver/src/regionInfo/getRegionInfo.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ export const getRegionInfo = (
3737
throw new Error(`Endpoint resolution failed for: ${{ resolvedRegion, useFipsEndpoint, useDualstackEndpoint }}`);
3838
}
3939

40-
const signingRegion = getResolvedSigningRegion(region, {
41-
hostname,
40+
const signingRegion = getResolvedSigningRegion(hostname, {
4241
signingRegion: regionHash[resolvedRegion]?.signingRegion,
4342
regionRegex: partitionHash[partition].regionRegex,
43+
useFipsEndpoint,
4444
});
4545

4646
return {

0 commit comments

Comments
 (0)