diff --git a/.prettierignore b/.prettierignore index 3e2e84b..ea20c0b 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,2 +1,3 @@ build/ node_modules/ +USAGE.md 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/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/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 diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..e6fc16b --- /dev/null +++ b/bun.lock @@ -0,0 +1,124 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "github-webhook-proxy", + "dependencies": { + "axios": "1.13.1", + "lodash.mapkeys": "4.6.0", + "micromatch": "4.0.8", + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "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=="], + + "zod": ["zod@4.1.12", "", {}, "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ=="], + } +} diff --git a/bun.lockb b/bun.lockb deleted file mode 100755 index dbec985..0000000 Binary files a/bun.lockb and /dev/null differ diff --git a/lambda/proxy.test.ts b/lambda/proxy.test.ts index 8e912f0..52c7b0d 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,26 @@ 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) => fileMap[fileName]); +mock.module("./file-readers", () => ({ + readFileFromLayer: readFileFromLayerMock, + getPublicCerts: mock(), +})); + const expectedResponseObject = { statusCode: 200, body: '{"some":"data"}', @@ -66,16 +84,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 +91,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 +106,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 +118,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 +134,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 +154,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 +173,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 +187,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 +213,7 @@ describe("proxy", () => { }, }; const result = await handler(event); - expect(axios.post).toHaveBeenCalledWith( + expect(axiosPostMock).toHaveBeenCalledWith( destinationUrl, stringifiedPayload, { @@ -220,7 +232,7 @@ describe("proxy", () => { "ca.pem": "some ca", "cert.pem": "some cert", }; - (readFileFromLayer as jest.Mock).mockImplementation( + readFileFromLayerMock.mockImplementation( (fileName: string) => newFileMap[fileName], ); const destinationUrl = "https://approved.host/github-webhook/"; @@ -232,7 +244,7 @@ describe("proxy", () => { }, }; const result = await handler(event); - expect(axios.post).toHaveBeenCalledWith( + expect(axiosPostMock).toHaveBeenCalledWith( destinationUrl, stringifiedPayload, { @@ -253,7 +265,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 +281,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 +298,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 +316,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 93e841f..1dadefc 100644 --- a/package.json +++ b/package.json @@ -6,43 +6,22 @@ "scripts": { "build": "bun build lambda/proxy.ts --outdir build/ --target node", "format": "prettier --write .", - "format-check": "prettier --check", - "test": "bun jest" + "format-check": "prettier --check .", + "test": "bun test" }, "dependencies": { - "axios": "1.12.2", + "axios": "1.13.1", "lodash.mapkeys": "4.6.0", - "zod": "4.1.11" + "micromatch": "4.0.8", + "zod": "4.1.12" }, "devDependencies": { "@octokit/webhooks": "14.1.3", - "@swc/jest": "0.2.39", - "@types/aws-lambda": "8.10.152", - "@types/jest": "30.0.0", + "@types/aws-lambda": "8.10.157", + "@types/bun": "1.3.1", "@types/lodash.mapkeys": "4.6.9", - "@types/micromatch": "4.0.9", - "jest": "30.1.3", + "@types/micromatch": "4.0.10", "prettier": "3.6.2", - "typescript": "5.9.2" - }, - "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 + "typescript": "5.9.3" } } 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, 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 = {