From b6452cf7b18f67cf391a0ad374bb03a4463fd9c8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 01:47:13 +0000 Subject: [PATCH 01/10] feat(deps): update dependencies --- .terraform-version | 2 +- bun.lockb | Bin 179261 -> 183500 bytes package.json | 12 ++++++------ versions.tf | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.terraform-version b/.terraform-version index 01b7568..80138e7 100644 --- a/.terraform-version +++ b/.terraform-version @@ -1 +1 @@ -1.13.3 +1.13.4 diff --git a/bun.lockb b/bun.lockb index dbec985bba2670a40f721a1ffddfc1b023bbe481..a908f3b642f1e4823dd7c7e9aa7828270d26fd3c 100755 GIT binary patch delta 24900 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 V)k3IR^v8aovT0G}BSL}j{{RBaf=U1Y diff --git a/package.json b/package.json index 93e841f..28c0a26 100644 --- a/package.json +++ b/package.json @@ -10,20 +10,20 @@ "test": "bun jest" }, "dependencies": { - "axios": "1.12.2", + "axios": "1.13.1", "lodash.mapkeys": "4.6.0", - "zod": "4.1.11" + "zod": "4.1.12" }, "devDependencies": { "@octokit/webhooks": "14.1.3", "@swc/jest": "0.2.39", - "@types/aws-lambda": "8.10.152", + "@types/aws-lambda": "8.10.157", "@types/jest": "30.0.0", "@types/lodash.mapkeys": "4.6.9", - "@types/micromatch": "4.0.9", - "jest": "30.1.3", + "@types/micromatch": "4.0.10", + "jest": "30.2.0", "prettier": "3.6.2", - "typescript": "5.9.2" + "typescript": "5.9.3" }, "jest": { "transform": { diff --git a/versions.tf b/versions.tf index fe8be7a..6e45378 100644 --- a/versions.tf +++ b/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = "1.13.3" + required_version = "1.13.4" required_providers { aws = { From bb55036af65be1a01e3def63461f2181ecf15bca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Nov 2025 01:47:31 +0000 Subject: [PATCH 02/10] terraform-docs: automated action --- USAGE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/USAGE.md b/USAGE.md index 1396a83..a709021 100644 --- a/USAGE.md +++ b/USAGE.md @@ -3,7 +3,7 @@ | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | 1.13.3 | +| [terraform](#requirement\_terraform) | 1.13.4 | ## Providers From a298d24b73d01c64d0a69695e36a96da8fdfa27a Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:22:59 -0600 Subject: [PATCH 03/10] migrate jest to bun test runner --- CONTRIBUTING.md | 2 +- bun.lock | 111 +++++++++++++++++++++++++++++++++++++++++++ bun.lockb | Bin 183500 -> 0 bytes lambda/proxy.test.ts | 80 ++++++++++++++++++------------- lambda/proxy.ts | 1 - package.json | 26 +--------- tsconfig.json | 1 - 7 files changed, 162 insertions(+), 59 deletions(-) create mode 100644 bun.lock delete mode 100755 bun.lockb diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72fc849..7c109b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ where "my-new-feature" describes what you're working on. ### 3. Add tests for any bug fixes or new functionality -All functions must be tested with a unit test. Please follow the existing convention of one exported function per file with a corresponding file to test it. Run tests using `yarn test`, or using the [Jest CLI](https://jestjs.io/docs/cli). +All functions must be tested with a unit test. Please follow the existing convention of one exported function per file with a corresponding file to test it. Run tests using `bun test`. There is also an integration test present in the [test workflow](./.github/workflows/test.yaml), which will actually run this Github Action using the code from this repository. This allows you to test your change to the Github Action right within the pull request you make. diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..e26621c --- /dev/null +++ b/bun.lock @@ -0,0 +1,111 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "github-webhook-proxy", + "dependencies": { + "axios": "1.13.1", + "lodash.mapkeys": "4.6.0", + "zod": "4.1.12", + }, + "devDependencies": { + "@octokit/webhooks": "14.1.3", + "@types/aws-lambda": "8.10.157", + "@types/bun": "1.3.1", + "@types/lodash.mapkeys": "4.6.9", + "@types/micromatch": "4.0.10", + "prettier": "3.6.2", + "typescript": "5.9.3", + }, + }, + }, + "packages": { + "@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="], + + "@octokit/openapi-webhooks-types": ["@octokit/openapi-webhooks-types@12.0.3", "", {}, "sha512-90MF5LVHjBedwoHyJsgmaFhEN1uzXyBDRLEBe7jlTYx/fEhPAk3P3DAJsfZwC54m8hAIryosJOL+UuZHB3K3yA=="], + + "@octokit/request-error": ["@octokit/request-error@7.0.2", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-U8piOROoQQUyExw5c6dTkU3GKxts5/ERRThIauNL7yaRoeXW0q/5bgHWT7JfWBw1UyrbK8ERId2wVkcB32n0uQ=="], + + "@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="], + + "@octokit/webhooks": ["@octokit/webhooks@14.1.3", "", { "dependencies": { "@octokit/openapi-webhooks-types": "12.0.3", "@octokit/request-error": "^7.0.0", "@octokit/webhooks-methods": "^6.0.0" } }, "sha512-gcK4FNaROM9NjA0mvyfXl0KPusk7a1BeA8ITlYEZVQCXF5gcETTd4yhAU0Kjzd8mXwYHppzJBWgdBVpIR9wUcQ=="], + + "@octokit/webhooks-methods": ["@octokit/webhooks-methods@6.0.0", "", {}, "sha512-MFlzzoDJVw/GcbfzVC1RLR36QqkTLUf79vLVO3D+xn7r0QgxnFoLZgtrzxiQErAjFUOdH6fas2KeQJ1yr/qaXQ=="], + + "@types/aws-lambda": ["@types/aws-lambda@8.10.157", "", {}, "sha512-ofjcRCO1N7tMZDSO11u5bFHPDfUFD3Q9YK9g4S4w8UDKuG3CNlw2lNK1sd3Itdo7JORygZmG4h9ZykS8dlXvMA=="], + + "@types/braces": ["@types/braces@3.0.5", "", {}, "sha512-SQFof9H+LXeWNz8wDe7oN5zu7ket0qwMu5vZubW4GCJ8Kkeh6nBWUz87+KTz/G3Kqsrp0j/W253XJb3KMEeg3w=="], + + "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], + + "@types/lodash": ["@types/lodash@4.17.20", "", {}, "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA=="], + + "@types/lodash.mapkeys": ["@types/lodash.mapkeys@4.6.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-6/ERBCabeDI656LsV+oopLjdnJ/x1PCAE6kkkssH8e4i0K7Pw307noxHCbUc6cAVfTo9vx0Z+k3QZwy1IrUZcA=="], + + "@types/micromatch": ["@types/micromatch@4.0.10", "", { "dependencies": { "@types/braces": "*" } }, "sha512-5jOhFDElqr4DKTrTEbnW8DZ4Hz5LRUEmyrGpCMrD/NphYv3nUnaF08xmSLx1rGGnyEs/kFnhiw6dCgcDqMr5PQ=="], + + "@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="], + + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "axios": ["axios@1.13.1", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw=="], + + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + + "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "^1.0.3" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "lodash.mapkeys": ["lodash.mapkeys@4.6.0", "", {}, "sha512-0Al+hxpYvONWtg+ZqHpa/GaVzxuN3V7Xeo2p+bY06EaK/n+Y9R7nBePPN2o1LxmL0TWQSwP8LYZ008/hc9JzhA=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="], + } +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index a908f3b642f1e4823dd7c7e9aa7828270d26fd3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183500 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
IeZT8*|N0?;X7! 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 diff --git a/lambda/proxy.test.ts b/lambda/proxy.test.ts index 8e912f0..2af72f4 100644 --- a/lambda/proxy.test.ts +++ b/lambda/proxy.test.ts @@ -12,20 +12,19 @@ limitations under the License. */ import { handler } from "./proxy"; -import axios, { AxiosRequestHeaders, AxiosResponse } from "axios"; +import type { AxiosRequestHeaders, AxiosResponse } from "axios"; import { readFileSync } from "fs"; import { Agent } from "https"; -import { readFileFromLayer } from "./file-readers"; import { APIGatewayProxyWithLambdaAuthorizerEvent } from "aws-lambda"; import { VALID_PING_EVENT } from "../fixtures/valid-ping-payload"; import { VALID_PUSH_PAYLOAD } from "../fixtures/valid-push-payload"; import { VALID_PUSH_PAYLOAD_USER_REPO } from "../fixtures/valid-push-payload-user-repo"; +import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test"; + const urlencodedPayload = readFileSync( "fixtures/invalid-payload-urlencoded.txt", ).toString(); -jest.mock("axios"); -jest.mock("./file-readers"); const axiosResponse: AxiosResponse = { status: 200, data: { @@ -39,7 +38,29 @@ const axiosResponse: AxiosResponse = { headers: {} as AxiosRequestHeaders, }, }; -(axios.post as jest.Mock).mockResolvedValue(axiosResponse); +const axiosPostMock = mock(() => axiosResponse); +mock.module("axios", () => ({ + default: { + post: axiosPostMock + } +})); + +const fileMap: Record = { + "allowed-destination-hosts.json": JSON.stringify([ + "approved.host", + "another.approved.host", + "a.wildcard.*.host", + ]), +}; +const readFileFromLayerMock = mock((fileName: string) => { + console.log('the file name', fileName); + return fileMap[fileName] +}); +mock.module("./file-readers", () => ({ + readFileFromLayer: readFileFromLayerMock, + getPublicCerts: mock() +})); + const expectedResponseObject = { statusCode: 200, body: '{"some":"data"}', @@ -66,16 +87,6 @@ const baseEvent: APIGatewayProxyWithLambdaAuthorizerEvent = { requestContext: {} as any, resource: "", }; -const fileMap: Record = { - "allowed-destination-hosts.json": JSON.stringify([ - "approved.host", - "another.approved.host", - "a.wildcard.*.host", - ]), -}; -(readFileFromLayer as jest.Mock).mockImplementation( - (fileName: string) => fileMap[fileName], -); describe("proxy", () => { beforeEach(() => { @@ -83,6 +94,10 @@ describe("proxy", () => { process.env.ENTERPRISE_MANAGED_USER_SUFFIX = ""; }); + afterEach(() => { + mock.clearAllMocks(); + }) + it("should reject a request with an invalid urlencoded payload", async () => { const event: APIGatewayProxyWithLambdaAuthorizerEvent = { ...baseEvent, @@ -94,7 +109,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual({ statusCode: 403, body: "Access denied" }); - expect(axios.post).not.toHaveBeenCalled(); + expect(axiosPostMock).not.toHaveBeenCalled(); }); it("should reject a request with an endpointId which is not an encoded URL", async () => { @@ -106,7 +121,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual({ statusCode: 403, body: "Access denied" }); - expect(axios.post).not.toHaveBeenCalled(); + expect(axiosPostMock).not.toHaveBeenCalled(); }); it("should allow a request from a managed user suffix when supplied", async () => { @@ -122,7 +137,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual(expectedResponseObject); - expect(axios.post).toHaveBeenCalled(); + expect(axiosPostMock).toHaveBeenCalled(); }); it("should forward a request when header is Content-Type", async () => { @@ -142,7 +157,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual(expectedResponseObject); - expect(axios.post).toHaveBeenCalled(); + expect(axiosPostMock).toHaveBeenCalled(); }); it("should not forward a request that does not come from an enterprise or managed user suffix", async () => { @@ -161,7 +176,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual({ statusCode: 403, body: "Access denied" }); - expect(axios.post).not.toHaveBeenCalled(); + expect(axiosPostMock).not.toHaveBeenCalled(); }); it("should not forward a request that does not have an approved host", async () => { @@ -175,7 +190,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual({ statusCode: 403, body: "Access denied" }); - expect(axios.post).not.toHaveBeenCalled(); + expect(axiosPostMock).not.toHaveBeenCalled(); }); it("should forward a request that has an approved host which matches a wildcard", async () => { @@ -201,7 +216,7 @@ describe("proxy", () => { }, }; const result = await handler(event); - expect(axios.post).toHaveBeenCalledWith( + expect(axiosPostMock).toHaveBeenCalledWith( destinationUrl, stringifiedPayload, { @@ -214,14 +229,17 @@ describe("proxy", () => { expect(result).toEqual(expectedResponseObject); }); - it("should forward a request from an enterprise and github org with supplied certs", async () => { + it.only("should forward a request from an enterprise and github org with supplied certs", async () => { const newFileMap: Record = { ...fileMap, "ca.pem": "some ca", "cert.pem": "some cert", }; - (readFileFromLayer as jest.Mock).mockImplementation( - (fileName: string) => newFileMap[fileName], + readFileFromLayerMock.mockImplementation( + (fileName: string) => { + console.log('the file name is', fileName); + return newFileMap[fileName] + }, ); const destinationUrl = "https://approved.host/github-webhook/"; const endpointId = encodeURIComponent(destinationUrl); @@ -232,7 +250,7 @@ describe("proxy", () => { }, }; const result = await handler(event); - expect(axios.post).toHaveBeenCalledWith( + expect(axiosPostMock).toHaveBeenCalledWith( destinationUrl, stringifiedPayload, { @@ -253,7 +271,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual({ statusCode: 404, body: "Not found" }); - expect(axios.post).not.toHaveBeenCalled(); + expect(axiosPostMock).not.toHaveBeenCalled(); }); it("should forward a ping event from a managed user suffix when supplied", async () => { @@ -269,7 +287,7 @@ describe("proxy", () => { }; const result = await handler(event); expect(result).toEqual(expectedResponseObject); - expect(axios.post).toHaveBeenCalled(); + expect(axiosPostMock).toHaveBeenCalled(); }); it("should return error response from axios", async () => { @@ -286,9 +304,7 @@ describe("proxy", () => { headers: {} as AxiosRequestHeaders, }, }; - (axios.post as jest.Mock).mockRejectedValue({ - response: axiosErrorResponse, - }); + axiosPostMock.mockImplementationOnce(() => axiosErrorResponse); process.env.ENTERPRISE_MANAGED_USER_SUFFIX = "suffix"; const destinationUrl = "https://approved.host/github-webhook/"; @@ -306,6 +322,6 @@ describe("proxy", () => { body: '{"some":"error"}', headers: { response: "headers" }, }); - expect(axios.post).toHaveBeenCalled(); + expect(axiosPostMock).toHaveBeenCalled(); }); }); diff --git a/lambda/proxy.ts b/lambda/proxy.ts index 00b3212..a60cb22 100644 --- a/lambda/proxy.ts +++ b/lambda/proxy.ts @@ -17,7 +17,6 @@ import { requestPayloadIsValid } from "./request-payload-is-valid"; import { destinationHostIsAllowed } from "./destination-host-is-allowed"; import { getHttpsAgent } from "./get-https-agent"; import { parseRequestBody } from "./parse-request-body"; -import { EnterpriseProxyEvent } from "./types"; import { urlIsValid } from "./url-is-valid"; import { axiosErrorSchema } from "./schema"; diff --git a/package.json b/package.json index 28c0a26..77f56b6 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "build": "bun build lambda/proxy.ts --outdir build/ --target node", "format": "prettier --write .", "format-check": "prettier --check", - "test": "bun jest" + "test": "bun test" }, "dependencies": { "axios": "1.13.1", @@ -16,33 +16,11 @@ }, "devDependencies": { "@octokit/webhooks": "14.1.3", - "@swc/jest": "0.2.39", "@types/aws-lambda": "8.10.157", - "@types/jest": "30.0.0", + "@types/bun": "1.3.1", "@types/lodash.mapkeys": "4.6.9", "@types/micromatch": "4.0.10", - "jest": "30.2.0", "prettier": "3.6.2", "typescript": "5.9.3" - }, - "jest": { - "transform": { - "^.+\\.(t|j)sx?$": [ - "@swc/jest", - { - "jsc": { - "target": "esnext" - } - } - ] - }, - "moduleNameMapper": { - "^(\\.{1,2}/.*)\\.js$": "$1" - }, - "extensionsToTreatAsEsm": [ - ".ts" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", - "clearMocks": true } } diff --git a/tsconfig.json b/tsconfig.json index 6e48cbc..8edd813 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,6 @@ "moduleResolution": "node", "module": "esnext", "target": "esnext", - "types": ["jest", "node"], "noEmit": true, "noImplicitAny": true, "noUncheckedIndexedAccess": true, From 2125d016d8297a86962a655d672db14fc8816aa5 Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:23:17 -0600 Subject: [PATCH 04/10] format --- USAGE.md | 120 ++++++++++++++++++++++--------------------- lambda/proxy.test.ts | 38 +++++++------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/USAGE.md b/USAGE.md index a709021..7f9e223 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,15 +1,16 @@ + ## Requirements -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | 1.13.4 | +| Name | Version | +| ------------------------------------------------------------------------ | ------- | +| [terraform](#requirement_terraform) | 1.13.4 | ## Providers -| Name | Version | -|------|---------| -| [aws](#provider\_aws) | n/a | +| Name | Version | +| ------------------------------------------------ | ------- | +| [aws](#provider_aws) | n/a | ## Modules @@ -17,63 +18,64 @@ No modules. ## Resources -| Name | Type | -|------|------| -| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | -| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | -| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | -| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | -| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | -| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | -| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | -| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | -| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | -| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | -| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | -| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | -| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | -| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | -| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | +| Name | Type | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | +| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | +| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | +| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | +| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | +| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | +| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | +| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | ## Inputs -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [api\_gateway\_domain\_name](#input\_api\_gateway\_domain\_name) | Domain name for API gateway domain mapping | `string` | `null` | no | -| [aws\_region](#input\_aws\_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | -| [certificate\_arn](#input\_certificate\_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | -| [custom\_tags](#input\_custom\_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | -| [enterprise\_managed\_user\_suffix](#input\_enterprise\_managed\_user\_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | -| [enterprise\_slug](#input\_enterprise\_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | -| [extra\_role\_policy](#input\_extra\_role\_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | -| [lambda\_bucket\_name](#input\_lambda\_bucket\_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | -| [lambda\_layer\_arn](#input\_lambda\_layer\_arn) | Lambda layer ARN for data store | `string` | n/a | yes | -| [lambda\_timeout\_seconds](#input\_lambda\_timeout\_seconds) | Number of seconds until lambda times out | `number` | `10` | no | -| [log\_retention\_days](#input\_log\_retention\_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | -| [resource\_prefix](#input\_resource\_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | -| [route\_53\_record\_name](#input\_route\_53\_record\_name) | Record name for Route 53 record creation | `string` | `null` | no | -| [subnet\_ids](#input\_subnet\_ids) | subnet\_ids for Lambda VPC config | `list(string)` | n/a | yes | -| [vpc\_id](#input\_vpc\_id) | VPC id for Lambda VPC config | `string` | n/a | yes | -| [zone\_id](#input\_zone\_id) | Zone id for Route53 record | `string` | `null` | no | +| Name | Description | Type | Default | Required | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------- | ------- | :------: | +| [api_gateway_domain_name](#input_api_gateway_domain_name) | Domain name for API gateway domain mapping | `string` | `null` | no | +| [aws_region](#input_aws_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | +| [certificate_arn](#input_certificate_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | +| [custom_tags](#input_custom_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | +| [enterprise_managed_user_suffix](#input_enterprise_managed_user_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | +| [enterprise_slug](#input_enterprise_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | +| [extra_role_policy](#input_extra_role_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | +| [lambda_bucket_name](#input_lambda_bucket_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | +| [lambda_layer_arn](#input_lambda_layer_arn) | Lambda layer ARN for data store | `string` | n/a | yes | +| [lambda_timeout_seconds](#input_lambda_timeout_seconds) | Number of seconds until lambda times out | `number` | `10` | no | +| [log_retention_days](#input_log_retention_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | +| [resource_prefix](#input_resource_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | +| [route_53_record_name](#input_route_53_record_name) | Record name for Route 53 record creation | `string` | `null` | no | +| [subnet_ids](#input_subnet_ids) | subnet_ids for Lambda VPC config | `list(string)` | n/a | yes | +| [vpc_id](#input_vpc_id) | VPC id for Lambda VPC config | `string` | n/a | yes | +| [zone_id](#input_zone_id) | Zone id for Route53 record | `string` | `null` | no | ## Outputs -| Name | Description | -|------|-------------| -| [apigateway\_ingress\_id](#output\_apigateway\_ingress\_id) | n/a | -| [apigateway\_invoke\_url](#output\_apigateway\_invoke\_url) | n/a | +| Name | Description | +| -------------------------------------------------------------------------------------------------- | ----------- | +| [apigateway_ingress_id](#output_apigateway_ingress_id) | n/a | +| [apigateway_invoke_url](#output_apigateway_invoke_url) | n/a | + diff --git a/lambda/proxy.test.ts b/lambda/proxy.test.ts index 2af72f4..41f2dc7 100644 --- a/lambda/proxy.test.ts +++ b/lambda/proxy.test.ts @@ -40,25 +40,25 @@ const axiosResponse: AxiosResponse = { }; const axiosPostMock = mock(() => axiosResponse); mock.module("axios", () => ({ - default: { - post: axiosPostMock - } + default: { + post: axiosPostMock, + }, })); const fileMap: Record = { - "allowed-destination-hosts.json": JSON.stringify([ - "approved.host", - "another.approved.host", - "a.wildcard.*.host", - ]), + "allowed-destination-hosts.json": JSON.stringify([ + "approved.host", + "another.approved.host", + "a.wildcard.*.host", + ]), }; const readFileFromLayerMock = mock((fileName: string) => { - console.log('the file name', fileName); - return fileMap[fileName] + console.log("the file name", fileName); + return fileMap[fileName]; }); mock.module("./file-readers", () => ({ - readFileFromLayer: readFileFromLayerMock, - getPublicCerts: mock() + readFileFromLayer: readFileFromLayerMock, + getPublicCerts: mock(), })); const expectedResponseObject = { @@ -95,8 +95,8 @@ describe("proxy", () => { }); afterEach(() => { - mock.clearAllMocks(); - }) + mock.clearAllMocks(); + }); it("should reject a request with an invalid urlencoded payload", async () => { const event: APIGatewayProxyWithLambdaAuthorizerEvent = { @@ -235,12 +235,10 @@ describe("proxy", () => { "ca.pem": "some ca", "cert.pem": "some cert", }; - readFileFromLayerMock.mockImplementation( - (fileName: string) => { - console.log('the file name is', fileName); - return newFileMap[fileName] - }, - ); + readFileFromLayerMock.mockImplementation((fileName: string) => { + console.log("the file name is", fileName); + return newFileMap[fileName]; + }); const destinationUrl = "https://approved.host/github-webhook/"; const endpointId = encodeURIComponent(destinationUrl); const event: APIGatewayProxyWithLambdaAuthorizerEvent = { From b771bc7f4908f510b6c1c2a982ff600fd4436516 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Nov 2025 15:23:37 +0000 Subject: [PATCH 05/10] terraform-docs: automated action --- USAGE.md | 120 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/USAGE.md b/USAGE.md index 7f9e223..a709021 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,16 +1,15 @@ - ## Requirements -| Name | Version | -| ------------------------------------------------------------------------ | ------- | -| [terraform](#requirement_terraform) | 1.13.4 | +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | 1.13.4 | ## Providers -| Name | Version | -| ------------------------------------------------ | ------- | -| [aws](#provider_aws) | n/a | +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | ## Modules @@ -18,64 +17,63 @@ No modules. ## Resources -| Name | Type | -| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | -| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | -| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | -| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | -| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | -| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | -| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | -| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | -| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | -| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | -| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | -| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | -| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | -| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | -| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | +| Name | Type | +|------|------| +| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | +| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | +| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | +| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | +| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | +| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | +| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | ## Inputs -| Name | Description | Type | Default | Required | -| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------- | ------- | :------: | -| [api_gateway_domain_name](#input_api_gateway_domain_name) | Domain name for API gateway domain mapping | `string` | `null` | no | -| [aws_region](#input_aws_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | -| [certificate_arn](#input_certificate_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | -| [custom_tags](#input_custom_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | -| [enterprise_managed_user_suffix](#input_enterprise_managed_user_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | -| [enterprise_slug](#input_enterprise_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | -| [extra_role_policy](#input_extra_role_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | -| [lambda_bucket_name](#input_lambda_bucket_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | -| [lambda_layer_arn](#input_lambda_layer_arn) | Lambda layer ARN for data store | `string` | n/a | yes | -| [lambda_timeout_seconds](#input_lambda_timeout_seconds) | Number of seconds until lambda times out | `number` | `10` | no | -| [log_retention_days](#input_log_retention_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | -| [resource_prefix](#input_resource_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | -| [route_53_record_name](#input_route_53_record_name) | Record name for Route 53 record creation | `string` | `null` | no | -| [subnet_ids](#input_subnet_ids) | subnet_ids for Lambda VPC config | `list(string)` | n/a | yes | -| [vpc_id](#input_vpc_id) | VPC id for Lambda VPC config | `string` | n/a | yes | -| [zone_id](#input_zone_id) | Zone id for Route53 record | `string` | `null` | no | +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_gateway\_domain\_name](#input\_api\_gateway\_domain\_name) | Domain name for API gateway domain mapping | `string` | `null` | no | +| [aws\_region](#input\_aws\_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | +| [certificate\_arn](#input\_certificate\_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | +| [custom\_tags](#input\_custom\_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | +| [enterprise\_managed\_user\_suffix](#input\_enterprise\_managed\_user\_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | +| [enterprise\_slug](#input\_enterprise\_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | +| [extra\_role\_policy](#input\_extra\_role\_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | +| [lambda\_bucket\_name](#input\_lambda\_bucket\_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | +| [lambda\_layer\_arn](#input\_lambda\_layer\_arn) | Lambda layer ARN for data store | `string` | n/a | yes | +| [lambda\_timeout\_seconds](#input\_lambda\_timeout\_seconds) | Number of seconds until lambda times out | `number` | `10` | no | +| [log\_retention\_days](#input\_log\_retention\_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | +| [resource\_prefix](#input\_resource\_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | +| [route\_53\_record\_name](#input\_route\_53\_record\_name) | Record name for Route 53 record creation | `string` | `null` | no | +| [subnet\_ids](#input\_subnet\_ids) | subnet\_ids for Lambda VPC config | `list(string)` | n/a | yes | +| [vpc\_id](#input\_vpc\_id) | VPC id for Lambda VPC config | `string` | n/a | yes | +| [zone\_id](#input\_zone\_id) | Zone id for Route53 record | `string` | `null` | no | ## Outputs -| Name | Description | -| -------------------------------------------------------------------------------------------------- | ----------- | -| [apigateway_ingress_id](#output_apigateway_ingress_id) | n/a | -| [apigateway_invoke_url](#output_apigateway_invoke_url) | n/a | - +| Name | Description | +|------|-------------| +| [apigateway\_ingress\_id](#output\_apigateway\_ingress\_id) | n/a | +| [apigateway\_invoke\_url](#output\_apigateway\_invoke\_url) | n/a | From 78ed850c48e21864e278e5f0ec9d2b3e4fda6acb Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:24:08 -0600 Subject: [PATCH 06/10] fix --- lambda/proxy.test.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lambda/proxy.test.ts b/lambda/proxy.test.ts index 41f2dc7..6bcd6d5 100644 --- a/lambda/proxy.test.ts +++ b/lambda/proxy.test.ts @@ -52,10 +52,7 @@ const fileMap: Record = { "a.wildcard.*.host", ]), }; -const readFileFromLayerMock = mock((fileName: string) => { - console.log("the file name", fileName); - return fileMap[fileName]; -}); +const readFileFromLayerMock = mock((fileName: string) => fileMap[fileName]); mock.module("./file-readers", () => ({ readFileFromLayer: readFileFromLayerMock, getPublicCerts: mock(), @@ -235,10 +232,9 @@ describe("proxy", () => { "ca.pem": "some ca", "cert.pem": "some cert", }; - readFileFromLayerMock.mockImplementation((fileName: string) => { - console.log("the file name is", fileName); - return newFileMap[fileName]; - }); + readFileFromLayerMock.mockImplementation( + (fileName: string) => newFileMap[fileName], + ); const destinationUrl = "https://approved.host/github-webhook/"; const endpointId = encodeURIComponent(destinationUrl); const event: APIGatewayProxyWithLambdaAuthorizerEvent = { From 697375ff35e00c5388b1a40240aaed438a5b874a Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:26:50 -0600 Subject: [PATCH 07/10] fix deps --- USAGE.md | 120 ++++++++++++++++++++++++++------------------------- bun.lock | 13 ++++++ package.json | 3 +- 3 files changed, 76 insertions(+), 60 deletions(-) diff --git a/USAGE.md b/USAGE.md index a709021..7f9e223 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,15 +1,16 @@ + ## Requirements -| Name | Version | -|------|---------| -| [terraform](#requirement\_terraform) | 1.13.4 | +| Name | Version | +| ------------------------------------------------------------------------ | ------- | +| [terraform](#requirement_terraform) | 1.13.4 | ## Providers -| Name | Version | -|------|---------| -| [aws](#provider\_aws) | n/a | +| Name | Version | +| ------------------------------------------------ | ------- | +| [aws](#provider_aws) | n/a | ## Modules @@ -17,63 +18,64 @@ No modules. ## Resources -| Name | Type | -|------|------| -| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | -| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | -| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | -| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | -| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | -| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | -| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | -| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | -| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | -| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | -| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | -| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | -| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | -| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | -| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | +| Name | Type | +| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | +| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | +| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | +| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | +| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | +| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | +| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | +| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | ## Inputs -| Name | Description | Type | Default | Required | -|------|-------------|------|---------|:--------:| -| [api\_gateway\_domain\_name](#input\_api\_gateway\_domain\_name) | Domain name for API gateway domain mapping | `string` | `null` | no | -| [aws\_region](#input\_aws\_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | -| [certificate\_arn](#input\_certificate\_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | -| [custom\_tags](#input\_custom\_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | -| [enterprise\_managed\_user\_suffix](#input\_enterprise\_managed\_user\_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | -| [enterprise\_slug](#input\_enterprise\_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | -| [extra\_role\_policy](#input\_extra\_role\_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | -| [lambda\_bucket\_name](#input\_lambda\_bucket\_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | -| [lambda\_layer\_arn](#input\_lambda\_layer\_arn) | Lambda layer ARN for data store | `string` | n/a | yes | -| [lambda\_timeout\_seconds](#input\_lambda\_timeout\_seconds) | Number of seconds until lambda times out | `number` | `10` | no | -| [log\_retention\_days](#input\_log\_retention\_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | -| [resource\_prefix](#input\_resource\_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | -| [route\_53\_record\_name](#input\_route\_53\_record\_name) | Record name for Route 53 record creation | `string` | `null` | no | -| [subnet\_ids](#input\_subnet\_ids) | subnet\_ids for Lambda VPC config | `list(string)` | n/a | yes | -| [vpc\_id](#input\_vpc\_id) | VPC id for Lambda VPC config | `string` | n/a | yes | -| [zone\_id](#input\_zone\_id) | Zone id for Route53 record | `string` | `null` | no | +| Name | Description | Type | Default | Required | +| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------- | ------- | :------: | +| [api_gateway_domain_name](#input_api_gateway_domain_name) | Domain name for API gateway domain mapping | `string` | `null` | no | +| [aws_region](#input_aws_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | +| [certificate_arn](#input_certificate_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | +| [custom_tags](#input_custom_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | +| [enterprise_managed_user_suffix](#input_enterprise_managed_user_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | +| [enterprise_slug](#input_enterprise_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | +| [extra_role_policy](#input_extra_role_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | +| [lambda_bucket_name](#input_lambda_bucket_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | +| [lambda_layer_arn](#input_lambda_layer_arn) | Lambda layer ARN for data store | `string` | n/a | yes | +| [lambda_timeout_seconds](#input_lambda_timeout_seconds) | Number of seconds until lambda times out | `number` | `10` | no | +| [log_retention_days](#input_log_retention_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | +| [resource_prefix](#input_resource_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | +| [route_53_record_name](#input_route_53_record_name) | Record name for Route 53 record creation | `string` | `null` | no | +| [subnet_ids](#input_subnet_ids) | subnet_ids for Lambda VPC config | `list(string)` | n/a | yes | +| [vpc_id](#input_vpc_id) | VPC id for Lambda VPC config | `string` | n/a | yes | +| [zone_id](#input_zone_id) | Zone id for Route53 record | `string` | `null` | no | ## Outputs -| Name | Description | -|------|-------------| -| [apigateway\_ingress\_id](#output\_apigateway\_ingress\_id) | n/a | -| [apigateway\_invoke\_url](#output\_apigateway\_invoke\_url) | n/a | +| Name | Description | +| -------------------------------------------------------------------------------------------------- | ----------- | +| [apigateway_ingress_id](#output_apigateway_ingress_id) | n/a | +| [apigateway_invoke_url](#output_apigateway_invoke_url) | n/a | + diff --git a/bun.lock b/bun.lock index e26621c..e6fc16b 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "axios": "1.13.1", "lodash.mapkeys": "4.6.0", + "micromatch": "4.0.8", "zod": "4.1.12", }, "devDependencies": { @@ -52,6 +53,8 @@ "axios": ["axios@1.13.1", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-hU4EGxxt+j7TQijx1oYdAjw4xuIp1wRQSsbMFwSthCWeBQur1eF+qJ5iQ5sN3Tw8YRzQNKb8jszgBdMDVqwJcw=="], + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -72,6 +75,8 @@ "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], "form-data": ["form-data@4.0.4", "", { "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow=="], @@ -90,18 +95,26 @@ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "lodash.mapkeys": ["lodash.mapkeys@4.6.0", "", {}, "sha512-0Al+hxpYvONWtg+ZqHpa/GaVzxuN3V7Xeo2p+bY06EaK/n+Y9R7nBePPN2o1LxmL0TWQSwP8LYZ008/hc9JzhA=="], "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], diff --git a/package.json b/package.json index 77f56b6..1dadefc 100644 --- a/package.json +++ b/package.json @@ -6,12 +6,13 @@ "scripts": { "build": "bun build lambda/proxy.ts --outdir build/ --target node", "format": "prettier --write .", - "format-check": "prettier --check", + "format-check": "prettier --check .", "test": "bun test" }, "dependencies": { "axios": "1.13.1", "lodash.mapkeys": "4.6.0", + "micromatch": "4.0.8", "zod": "4.1.12" }, "devDependencies": { From 7e865e0e14a3f145069aa6dae7ff8aea87f0cc5e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 3 Nov 2025 15:27:06 +0000 Subject: [PATCH 08/10] terraform-docs: automated action --- USAGE.md | 120 +++++++++++++++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/USAGE.md b/USAGE.md index 7f9e223..a709021 100644 --- a/USAGE.md +++ b/USAGE.md @@ -1,16 +1,15 @@ - ## Requirements -| Name | Version | -| ------------------------------------------------------------------------ | ------- | -| [terraform](#requirement_terraform) | 1.13.4 | +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | 1.13.4 | ## Providers -| Name | Version | -| ------------------------------------------------ | ------- | -| [aws](#provider_aws) | n/a | +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | n/a | ## Modules @@ -18,64 +17,63 @@ No modules. ## Resources -| Name | Type | -| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | -| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | -| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | -| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | -| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | -| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | -| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | -| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | -| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | -| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | -| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | -| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | -| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | -| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | -| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | -| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | -| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | -| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | -| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | -| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | +| Name | Type | +|------|------| +| [aws_api_gateway_base_path_mapping.dns_mapping](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_base_path_mapping) | resource | +| [aws_api_gateway_deployment.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_deployment) | resource | +| [aws_api_gateway_domain_name.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_domain_name) | resource | +| [aws_api_gateway_integration.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_integration) | resource | +| [aws_api_gateway_method.lambda_method](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method) | resource | +| [aws_api_gateway_method_settings.log_settings](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_method_settings) | resource | +| [aws_api_gateway_resource.lambda_endpoint](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_resource.webhook](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_resource) | resource | +| [aws_api_gateway_rest_api.ingress_api](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api) | resource | +| [aws_api_gateway_rest_api_policy.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_rest_api_policy) | resource | +| [aws_api_gateway_stage.ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/api_gateway_stage) | resource | +| [aws_cloudwatch_dashboard.metrics](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_dashboard) | resource | +| [aws_cloudwatch_log_group.apigw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | +| [aws_iam_role.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.extra_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource | +| [aws_iam_role_policy_attachment.basic_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.vpc_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_lambda_function.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource | +| [aws_lambda_permission.apigw_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource | +| [aws_route53_record.proxy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | +| [aws_security_group.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | +| [aws_iam_policy_document.allow_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.apigw_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.lambda_logging](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.proxy_service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_s3_object.proxy_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_object) | data source | ## Inputs -| Name | Description | Type | Default | Required | -| --------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | -------------- | ------- | :------: | -| [api_gateway_domain_name](#input_api_gateway_domain_name) | Domain name for API gateway domain mapping | `string` | `null` | no | -| [aws_region](#input_aws_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | -| [certificate_arn](#input_certificate_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | -| [custom_tags](#input_custom_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | -| [enterprise_managed_user_suffix](#input_enterprise_managed_user_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | -| [enterprise_slug](#input_enterprise_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | -| [extra_role_policy](#input_extra_role_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | -| [lambda_bucket_name](#input_lambda_bucket_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | -| [lambda_layer_arn](#input_lambda_layer_arn) | Lambda layer ARN for data store | `string` | n/a | yes | -| [lambda_timeout_seconds](#input_lambda_timeout_seconds) | Number of seconds until lambda times out | `number` | `10` | no | -| [log_retention_days](#input_log_retention_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | -| [resource_prefix](#input_resource_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | -| [route_53_record_name](#input_route_53_record_name) | Record name for Route 53 record creation | `string` | `null` | no | -| [subnet_ids](#input_subnet_ids) | subnet_ids for Lambda VPC config | `list(string)` | n/a | yes | -| [vpc_id](#input_vpc_id) | VPC id for Lambda VPC config | `string` | n/a | yes | -| [zone_id](#input_zone_id) | Zone id for Route53 record | `string` | `null` | no | +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [api\_gateway\_domain\_name](#input\_api\_gateway\_domain\_name) | Domain name for API gateway domain mapping | `string` | `null` | no | +| [aws\_region](#input\_aws\_region) | The AWS region to deploy to (e.g. us-east-1) | `string` | n/a | yes | +| [certificate\_arn](#input\_certificate\_arn) | Certificate ARN for API gateway domain name | `string` | `null` | no | +| [custom\_tags](#input\_custom\_tags) | Additional tags to be applied to all resources applied by this module. | `map(string)` | `{}` | no | +| [enterprise\_managed\_user\_suffix](#input\_enterprise\_managed\_user\_suffix) | Managed user suffix used for central identity management on GHEC | `string` | `""` | no | +| [enterprise\_slug](#input\_enterprise\_slug) | The name (slug) of the enterprise on GHEC | `string` | n/a | yes | +| [extra\_role\_policy](#input\_extra\_role\_policy) | jsonencoded string policy to include in the proxy lambda role | `string` | `null` | no | +| [lambda\_bucket\_name](#input\_lambda\_bucket\_name) | S3 bucket with lambda and layer archives | `string` | n/a | yes | +| [lambda\_layer\_arn](#input\_lambda\_layer\_arn) | Lambda layer ARN for data store | `string` | n/a | yes | +| [lambda\_timeout\_seconds](#input\_lambda\_timeout\_seconds) | Number of seconds until lambda times out | `number` | `10` | no | +| [log\_retention\_days](#input\_log\_retention\_days) | Number of days CloudWatch will retain logs | `number` | `7` | no | +| [resource\_prefix](#input\_resource\_prefix) | Prefix of webhook proxy resources | `string` | `"gwp"` | no | +| [route\_53\_record\_name](#input\_route\_53\_record\_name) | Record name for Route 53 record creation | `string` | `null` | no | +| [subnet\_ids](#input\_subnet\_ids) | subnet\_ids for Lambda VPC config | `list(string)` | n/a | yes | +| [vpc\_id](#input\_vpc\_id) | VPC id for Lambda VPC config | `string` | n/a | yes | +| [zone\_id](#input\_zone\_id) | Zone id for Route53 record | `string` | `null` | no | ## Outputs -| Name | Description | -| -------------------------------------------------------------------------------------------------- | ----------- | -| [apigateway_ingress_id](#output_apigateway_ingress_id) | n/a | -| [apigateway_invoke_url](#output_apigateway_invoke_url) | n/a | - +| Name | Description | +|------|-------------| +| [apigateway\_ingress\_id](#output\_apigateway\_ingress\_id) | n/a | +| [apigateway\_invoke\_url](#output\_apigateway\_invoke\_url) | n/a | From 0e453e5f47d4deac92e37119daef706cddae0648 Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:27:38 -0600 Subject: [PATCH 09/10] fix prettier --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 3e2e84b..ea20c0b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ build/ node_modules/ +USAGE.md From 589e76077ad743f161385cc92abb9e3c60b1b7f7 Mon Sep 17 00:00:00 2001 From: danadajian Date: Mon, 3 Nov 2025 09:28:54 -0600 Subject: [PATCH 10/10] fix only --- lambda/proxy.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda/proxy.test.ts b/lambda/proxy.test.ts index 6bcd6d5..52c7b0d 100644 --- a/lambda/proxy.test.ts +++ b/lambda/proxy.test.ts @@ -226,7 +226,7 @@ describe("proxy", () => { expect(result).toEqual(expectedResponseObject); }); - it.only("should forward a request from an enterprise and github org with supplied certs", async () => { + it("should forward a request from an enterprise and github org with supplied certs", async () => { const newFileMap: Record = { ...fileMap, "ca.pem": "some ca",