Skip to content

Commit b859e5c

Browse files
authored
feat: support wildcards and improve error response logging (#158)
* improve logging * add wildcard matching support * update README.md
1 parent 835e84f commit b859e5c

File tree

8 files changed

+61
-8
lines changed

8 files changed

+61
-8
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ aws s3 cp "${file}" "${s3_destination}/${file}"
1717
```
1818

1919
Optionally, you may create a Lambda layer which optionally contains the following files:
20-
* `allowed-destination-hosts.json`: An array of destination hosts that the proxy can forward to. If omitted, all destinations will be allowed.
20+
* `allowed-destination-hosts.json`: An array of destination hosts that the proxy can forward to. If omitted, all destinations will be allowed. Wildcard matching is supported via [micromatch](https://github.com/micromatch/micromatch)
2121
* `ca.pem`: A root CA certificate for forwarding to internal destinations with self-signed certs
2222
* `cert.pem`: A chain certificate for forwarding to internal destinations with self-signed certs
2323

lambda/destination-host-is-allowed.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,18 @@ limitations under the License.
1212
*/
1313

1414
import { readFileFromLayer } from './file-readers';
15+
import { isMatch } from 'micromatch';
1516

1617
export function destinationHostIsAllowed(url: string) {
1718
const allowedDestinationHostsContents = readFileFromLayer('allowed-destination-hosts.json');
1819
if (!allowedDestinationHostsContents) {
1920
return true;
2021
}
2122
const allowedDestinationHosts: string[] = JSON.parse(allowedDestinationHostsContents);
22-
return allowedDestinationHosts.includes(new URL(url).host);
23+
const host = new URL(url).host;
24+
const destinationHostIsAllowed = allowedDestinationHosts.includes(host) || isMatch(host, allowedDestinationHosts);
25+
if (!destinationHostIsAllowed) {
26+
console.error(`Destination host ${host} does not match allowlist ${allowedDestinationHosts}`);
27+
}
28+
return destinationHostIsAllowed;
2329
}

lambda/proxy.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const baseEvent: APIGatewayProxyWithLambdaAuthorizerEvent<any> = {
6565
resource: ''
6666
};
6767
const fileMap: Record<string, string> = {
68-
'allowed-destination-hosts.json': JSON.stringify(['approved.host', 'another.approved.host'])
68+
'allowed-destination-hosts.json': JSON.stringify(['approved.host', 'another.approved.host', 'a.wildcard.*.host'])
6969
};
7070
(readFileFromLayer as jest.Mock).mockImplementation((fileName: string) => fileMap[fileName]);
7171

@@ -170,6 +170,19 @@ describe('proxy', () => {
170170
expect(axios.post).not.toHaveBeenCalled();
171171
});
172172

173+
it('should forward a request that has an approved host which matches a wildcard', async () => {
174+
const destinationUrl = 'https://a.wildcard.test.host/github-webhook/';
175+
const endpointId = encodeURIComponent(destinationUrl);
176+
const event: APIGatewayProxyWithLambdaAuthorizerEvent<any> = {
177+
...baseEvent,
178+
pathParameters: {
179+
endpointId
180+
}
181+
};
182+
const result = await handler(event);
183+
expect(result).toEqual(expectedResponseObject);
184+
});
185+
173186
it('should forward a request from an enterprise and github org without supplied certs', async () => {
174187
const destinationUrl = 'https://approved.host/github-webhook/';
175188
const endpointId = encodeURIComponent(destinationUrl);

lambda/proxy.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export async function handler(event: APIGatewayProxyWithLambdaAuthorizerEvent<an
2929
const endpointId = pathParameters?.endpointId;
3030

3131
if (!endpointId || !body) {
32+
console.error(`EndpointId or body is missing. endpointId: ${endpointId}, body: ${body}`);
3233
return { statusCode: 404, body: 'Not found' };
3334
}
3435

lambda/request-payload-is-valid.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,24 @@ export function requestPayloadIsValid({ sender, enterprise }: EnterpriseProxyEve
1818
}
1919

2020
function requestCameFromValidEnterprise(enterprise?: EnterpriseProxyEvent['enterprise']) {
21-
return process.env.ENTERPRISE_SLUG && enterprise?.slug === process.env.ENTERPRISE_SLUG;
21+
const requestCameFromValidEnterprise =
22+
process.env.ENTERPRISE_SLUG && enterprise?.slug === process.env.ENTERPRISE_SLUG;
23+
if (!requestCameFromValidEnterprise) {
24+
console.error(
25+
`ENTERPRISE_SLUG environment variable ${process.env.ENTERPRISE_SLUG} does not equal enterprise slug ${enterprise?.slug}`
26+
);
27+
}
28+
return requestCameFromValidEnterprise;
2229
}
2330

2431
function senderLoginEndsWithUserSuffix(senderLogin?: string) {
25-
return (
32+
const senderLoginEndsWithUserSuffix =
2633
process.env.ENTERPRISE_MANAGED_USER_SUFFIX &&
27-
senderLogin?.endsWith(`_${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`)
28-
);
34+
senderLogin?.endsWith(`_${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`);
35+
if (!senderLoginEndsWithUserSuffix) {
36+
console.error(
37+
`Sender login ${senderLogin} does not end with ENTERPRISE_MANAGED_USER_SUFFIX environment variable ${process.env.ENTERPRISE_MANAGED_USER_SUFFIX}`
38+
);
39+
}
40+
return senderLoginEndsWithUserSuffix;
2941
}

lambda/url-is-valid.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { urlSchema } from './schema';
22

33
export function urlIsValid(url: string) {
4-
return urlSchema.safeParse(url).success;
4+
const urlIsValid = urlSchema.safeParse(url).success;
5+
if (!urlIsValid) {
6+
console.error('Invalid URL:', url);
7+
}
8+
return urlIsValid;
59
}

package-lock.json

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"@types/aws-lambda": "8.10.107",
2222
"@types/jest": "29.5.12",
2323
"@types/lodash.mapkeys": "4.6.9",
24+
"@types/micromatch": "4.0.6",
2425
"jest": "29.7.0",
2526
"prettier": "3.2.5"
2627
},

0 commit comments

Comments
 (0)