Skip to content

Commit 02840e2

Browse files
Support for LocalStack
1 parent d36fab9 commit 02840e2

File tree

10 files changed

+463
-2
lines changed

10 files changed

+463
-2
lines changed

.github/workflows/common-test.yml

Lines changed: 322 additions & 0 deletions
Large diffs are not rendered by default.

.github/workflows/pull-request.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,13 @@ jobs:
5353
with:
5454
mode: build
5555
testMonorepo: false
56+
useLocalStack: false
57+
58+
test-localstack:
59+
uses: ./.github/workflows/common-test.yml
60+
secrets: inherit
61+
needs: remove-old-layers
62+
with:
63+
mode: build
64+
testMonorepo: false
65+
useLocalStack: true

.github/workflows/test-with-real-npm-all.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ jobs:
1919
mode: global
2020
testMonorepo: false
2121
version: ${{ inputs.version }}
22+
useLocalStack: false
23+
secrets: inherit
24+
25+
test-global-not-monorepo-localstack:
26+
uses: ./.github/workflows/common-test.yml
27+
with:
28+
mode: global
29+
testMonorepo: false
30+
version: ${{ inputs.version }}
31+
useLocalStack: true
2232
secrets: inherit
2333

2434
test-local-not-monorepo:
@@ -28,6 +38,17 @@ jobs:
2838
mode: local
2939
testMonorepo: false
3040
version: ${{ inputs.version }}
41+
useLocalStack: false
42+
secrets: inherit
43+
44+
test-local-not-monorepo-localstack:
45+
needs: test-global-not-monorepo
46+
uses: ./.github/workflows/common-test.yml
47+
with:
48+
mode: local
49+
testMonorepo: false
50+
version: ${{ inputs.version }}
51+
useLocalStack: true
3152
secrets: inherit
3253

3354
test-global-monorepo:
@@ -37,6 +58,17 @@ jobs:
3758
mode: global
3859
testMonorepo: true
3960
version: ${{ inputs.version }}
61+
useLocalStack: false
62+
secrets: inherit
63+
64+
test-global-monorepo-localstack:
65+
needs: test-local-not-monorepo
66+
uses: ./.github/workflows/common-test.yml
67+
with:
68+
mode: global
69+
testMonorepo: true
70+
version: ${{ inputs.version }}
71+
useLocalStack: true
4072
secrets: inherit
4173

4274
test-local-monorepo:
@@ -46,4 +78,15 @@ jobs:
4678
mode: local
4779
testMonorepo: true
4880
version: ${{ inputs.version }}
81+
useLocalStack: false
82+
secrets: inherit
83+
84+
test-local-monorepo-localstack:
85+
needs: test-global-monorepo
86+
uses: ./.github/workflows/common-test.yml
87+
with:
88+
mode: local
89+
testMonorepo: true
90+
version: ${{ inputs.version }}
91+
useLocalStack: true
4992
secrets: inherit

.github/workflows/test-with-real-npm.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ on:
1616
description: 'Test monorepo by specifying folder in config'
1717
type: boolean
1818
default: false
19+
useLocalStack:
20+
description: 'Use LocalStack instead of AWS'
21+
type: boolean
22+
default: false
1923
version:
2024
description: 'Specify the version of the package'
2125
type: string
@@ -32,4 +36,5 @@ jobs:
3236
mode: ${{ inputs.mode }}
3337
testMonorepo: ${{ inputs.testMonorepo }}
3438
version: ${{ inputs.version }}
39+
useLocalStack: ${{ inputs.useLocalStack }}
3540
secrets: inherit

src/awsCredentials.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,50 @@ function getCredentialsProvider(
1717
});
1818
}
1919

20+
/**
21+
* Detects if LocalStack is being used by making a test request and checking for
22+
* the 'x-localstack' header in the response.
23+
* @see {@link https://github.com/localstack/localstack/pull/12769}
24+
* @param awsConfiguration - AWS configuration to use for the test request
25+
* @returns true if LocalStack is detected (x-localstack header present), false otherwise
26+
*/
27+
async function isLocalStackDetected(
28+
awsConfiguration: AwsConfiguration,
29+
): Promise<boolean> {
30+
// Enable LocalStack response header to detect LocalStack
31+
process.env.LOCALSTACK_RESPONSE_HEADER_ENABLED = 'true';
32+
33+
const { STSClient, GetCallerIdentityCommand } = await import(
34+
'@aws-sdk/client-sts'
35+
);
36+
37+
const client = new STSClient({
38+
region: awsConfiguration.region,
39+
credentials: fromNodeProviderChain({
40+
clientConfig: { region: awsConfiguration.region },
41+
profile: awsConfiguration.profile,
42+
roleArn: awsConfiguration.role,
43+
}),
44+
});
45+
46+
const command = new GetCallerIdentityCommand({});
47+
const response = await client.send(command);
48+
49+
// Check for x-localstack header in response metadata
50+
const headers = (response.$metadata as any)?.httpHeaders;
51+
if (
52+
headers &&
53+
('x-localstack' in headers ||
54+
'X-Localstack' in headers ||
55+
'X-LOCALSTACK' in headers)
56+
) {
57+
return true;
58+
}
59+
60+
return false;
61+
}
62+
2063
export const AwsCredentials = {
2164
getCredentialsProvider,
65+
isLocalStackDetected,
2266
};

src/configuration.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getConfigTsFromConfigFile } from './configuration/getConfigFromTsConfig
99
import { configFileDefaultName } from './constants.js';
1010
import { ResourceDiscovery } from './resourceDiscovery.js';
1111
import { Logger } from './logger.js';
12+
import { AwsCredentials } from './awsCredentials.js';
1213

1314
let config: LldConfig;
1415
const lambdas: Record<string, LambdaResource> = {};
@@ -41,9 +42,15 @@ async function readConfig() {
4142
});
4243

4344
const debuggerId = await generateDebuggerId(!!configFromWizard.observable);
45+
const localStack = await AwsCredentials.isLocalStackDetected({
46+
profile: configFromWizard.profile,
47+
region: configFromWizard.region,
48+
role: configFromWizard.role,
49+
});
4450
setConfig({
4551
...configFromWizard,
4652
debuggerId,
53+
localStack,
4754
start: false, // don't start the debugger after the wizard
4855
});
4956
} else {
@@ -63,9 +70,15 @@ async function readConfig() {
6370
: configFromConfigFile?.context,
6471
};
6572
const debuggerId = await generateDebuggerId(!!configMerged.observable);
73+
const localStack = await AwsCredentials.isLocalStackDetected({
74+
profile: configMerged.profile,
75+
region: configMerged.region,
76+
role: configMerged.role,
77+
});
6678
setConfig({
6779
...configMerged,
6880
debuggerId,
81+
localStack,
6982
start: true,
7083
});
7184
}

src/infraDeploy.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,6 +1061,11 @@ function getEnvironmentVariablesForDebugger({
10611061
env.LLD_VERBOSE = 'true';
10621062
}
10631063

1064+
// Disable TLS verification for LocalStack
1065+
if (Configuration.config.localStack) {
1066+
env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
1067+
}
1068+
10641069
return env;
10651070
}
10661071

src/ioTService.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,19 @@ async function connect(props?: {
122122
credentials,
123123
});
124124

125+
let region = props?.region;
126+
127+
if (!region && process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0') {
128+
// it is localstack
129+
region = process.env.AWS_REGION ?? 'us-east-1';
130+
}
131+
125132
device = new iot.device({
126133
protocol: 'wss',
127134
host: endpoint,
128135
reconnectPeriod: 1,
129136
keepalive: 60,
130-
region: props?.region,
137+
region,
131138
accessKeyId: credentials?.accessKeyId,
132139
secretKey: credentials?.secretAccessKey,
133140
sessionToken: credentials?.sessionToken,

src/lldebugger.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ async function run() {
5555
return;
5656
}
5757

58+
if (Configuration.config.localStack) {
59+
//https://github.com/localstack/localstack/issues/13308
60+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
61+
}
62+
5863
let message = `Starting the debugger ${
5964
Configuration.config.observable
6065
? 'in Observability mode'

src/types/lldConfig.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,11 @@ export type LldConfigCliArgs = {
9191

9292
export type LldConfigTs = Partial<LldConfigBase>;
9393

94-
export type LldConfig = LldConfigCliArgs & LldConfigTs & { debuggerId: string };
94+
export type LldConfig = LldConfigCliArgs &
95+
LldConfigTs & {
96+
debuggerId: string;
97+
/**
98+
* Indicates whether LocalStack is being used instead of real AWS services.
99+
*/
100+
localStack: boolean;
101+
};

0 commit comments

Comments
 (0)