Skip to content

Commit 8e2c62e

Browse files
committed
Extract configureEnvironment and update implementation
* sanitise environment * handle endpoint url configuration misconfiguration * add testing
1 parent 4273be3 commit 8e2c62e

File tree

3 files changed

+130
-16
lines changed

3 files changed

+130
-16
lines changed

__tests__/index.test.js

+57-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,59 @@
1-
describe("Simple test", () => {
2-
test("it passes", () => {
3-
expect(true).toEqual(true);
1+
const { configureEnvironment, EnvironmentMisconfigurationError } = require("../src");
2+
3+
describe("configureEnvironment", () => {
4+
test("empty environment", () => {
5+
const env = {};
6+
const allowListStr = "";
7+
configureEnvironment(env, allowListStr);
8+
expect(env).toEqual({
9+
AWS_ENDPOINT_URL: "http://localhost.localstack.cloud:4566",
10+
AWS_ENDPOINT_URL_S3: "http://s3.localhost.localstack.cloud:4566",
11+
});
12+
});
13+
14+
test("custom endpoint url", () => {
15+
const env = {
16+
AWS_ENDPOINT_URL: "http://foo.bar:4567",
17+
AWS_ENDPOINT_URL_S3: "http://foo.bar:4567",
18+
};
19+
const allowListStr = "";
20+
configureEnvironment(env, allowListStr);
21+
expect(env).toEqual({
22+
AWS_ENDPOINT_URL: "http://foo.bar:4567",
23+
AWS_ENDPOINT_URL_S3: "http://foo.bar:4567",
24+
});
25+
});
26+
27+
test("custom endpoint url without specifying s3 url", () => {
28+
const env = {
29+
AWS_ENDPOINT_URL: "http://foo.bar:4567",
30+
};
31+
const allowListStr = "";
32+
expect(() => configureEnvironment(env, allowListStr)).toThrow(EnvironmentMisconfigurationError);
33+
});
34+
35+
test("strip extra configuration envars", () => {
36+
const env = {
37+
AWS_PROFILE: "my-profile",
38+
};
39+
const allowListStr = "";
40+
configureEnvironment(env, allowListStr);
41+
expect(env).toEqual({
42+
AWS_ENDPOINT_URL: "http://localhost.localstack.cloud:4566",
43+
AWS_ENDPOINT_URL_S3: "http://s3.localhost.localstack.cloud:4566",
44+
});
45+
});
46+
47+
test("allowlist of profile", () => {
48+
const env = {
49+
AWS_PROFILE: "my-profile",
50+
};
51+
const allowListStr = "AWS_PROFILE";
52+
configureEnvironment(env, allowListStr);
53+
expect(env).toEqual({
54+
AWS_PROFILE: "my-profile",
55+
AWS_ENDPOINT_URL: "http://localhost.localstack.cloud:4566",
56+
AWS_ENDPOINT_URL_S3: "http://s3.localhost.localstack.cloud:4566",
57+
});
458
});
559
});

bin/cdklocal

+4-13
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ const https = require("https");
99
const crypto = require("crypto");
1010
const net = require('net');
1111

12-
// constants and custom config values
12+
const { isEnvTrue, EDGE_PORT, PROTOCOL, configureEnvironment } = require("../src");
1313

14-
const isEnvTrue = (envName) => ["1", "true"].includes(process.env[envName]);
14+
// constants and custom config values
1515

16-
const DEFAULT_EDGE_PORT = 4566;
17-
const EDGE_PORT = process.env.EDGE_PORT || DEFAULT_EDGE_PORT;
1816
const DEFAULT_HOSTNAME = "localhost";
1917
const LAMBDA_MOUNT_CODE = isEnvTrue("LAMBDA_MOUNT_CODE");
20-
const PROTOCOL = isEnvTrue("USE_SSL") ? "https" : "http";
18+
const AWS_ENVAR_ALLOWLIST = process.env.AWS_ENVAR_ALLOWLIST || "";
2119

2220

2321
//----------------
@@ -451,13 +449,6 @@ const patchPre_2_14 = () => {
451449
applyPatches(provider, CdkToolkit, SDK, ToolkitInfo);
452450
};
453451

454-
const configureEnvironment = () => {
455-
// This _must_ use localhost.localstack.cloud as we require valid subdomains of these paths to
456-
// resolve. Unfortunately though `curl` seems to support subdomains of localhost, the CDK does not.
457-
process.env.AWS_ENDPOINT_URL_S3 = process.env.AWS_ENDPOINT_URL_S3 || `${PROTOCOL}://s3.localhost.localstack.cloud:${EDGE_PORT}`;
458-
process.env.AWS_ENDPOINT_URL = process.env.AWS_ENDPOINT_URL || `${PROTOCOL}://localhost.localstack.cloud:${EDGE_PORT}`;
459-
};
460-
461452
const patchPost_2_14 = () => {
462453
var lib = null;
463454
try {
@@ -484,7 +475,7 @@ const patchPost_2_14 = () => {
484475
break;
485476
case "ERR_PACKAGE_PATH_NOT_EXPORTED":
486477
// post 2.177
487-
configureEnvironment();
478+
configureEnvironment(process.env, AWS_ENVAR_ALLOWLIST);
488479
break;
489480
default:
490481
// a different error

src/index.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
const isEnvTrue = (envName) => ["1", "true"].includes(process.env[envName]);
2+
3+
const DEFAULT_EDGE_PORT = 4566;
4+
const EDGE_PORT = process.env.EDGE_PORT || DEFAULT_EDGE_PORT;
5+
const PROTOCOL = isEnvTrue("USE_SSL") ? "https" : "http";
6+
7+
class EnvironmentMisconfigurationError extends Error {
8+
constructor(message) {
9+
super(message);
10+
}
11+
}
12+
13+
const configureEnvironment = (env, allowListStr) => {
14+
// If the user has set `AWS_ENDPOINT_URL` but _NOT_ `AWS_ENDPOINT_URL_S3` then we cannot continue
15+
// as we do not know if the users endpoint can support subdomains, and we cannot simply use the
16+
// same version as S3 requests will be parsed incorrectly.
17+
if (Object.hasOwn(env, "AWS_ENDPOINT_URL") && !Object.hasOwn(env, "AWS_ENDPOINT_URL_S3")) {
18+
throw new EnvironmentMisconfigurationError("If specifying 'AWS_ENDPOINT_URL' then 'AWS_ENDPOINT_URL_S3' must be specified");
19+
}
20+
21+
// Strip out any variables that may configure the environment
22+
//
23+
// 1. parse AWS_ENVAR_ALLOWLIST to extract the keys we should allow
24+
const allowList = allowListStr.split(",").map((item) => item.trim());
25+
26+
// 2. build array of keys to remove
27+
const keysToRemove = Object.keys(env).filter((key) => {
28+
// don't filter out any keys which are not AWS configuration keys
29+
if (!key.startsWith("AWS_")) {
30+
return false;
31+
}
32+
33+
// always allow AWS_ENDPOINT_URL*
34+
if (key.startsWith("AWS_ENDPOINT_URL")) {
35+
return false;
36+
}
37+
38+
// if the key has been explicitly allowlisted, don't exclude the key
39+
if (allowList.includes(key)) {
40+
return false;
41+
}
42+
43+
// otherwise we should remove the key
44+
return true;
45+
});
46+
47+
// 3. remove the keys from the environment
48+
49+
Object.keys(env).forEach((key) => {
50+
if (keysToRemove.includes(key)) {
51+
delete env[key];
52+
}
53+
});
54+
55+
// Explicitly set AWS_ENDPOINT_URL* to configure network access to LocalStack
56+
// This _must_ use localhost.localstack.cloud as we require valid subdomains of these paths to
57+
// resolve. Unfortunately though `curl` seems to support subdomains of localhost, the CDK does not.
58+
env.AWS_ENDPOINT_URL_S3 = env.AWS_ENDPOINT_URL_S3 || `${PROTOCOL}://s3.localhost.localstack.cloud:${EDGE_PORT}`;
59+
env.AWS_ENDPOINT_URL = env.AWS_ENDPOINT_URL || `${PROTOCOL}://localhost.localstack.cloud:${EDGE_PORT}`;
60+
};
61+
62+
63+
module.exports = {
64+
isEnvTrue,
65+
EDGE_PORT,
66+
PROTOCOL,
67+
configureEnvironment,
68+
EnvironmentMisconfigurationError,
69+
};

0 commit comments

Comments
 (0)