diff --git a/backend/package-lock.json b/backend/package-lock.json index db116bc48..7534ac1bd 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -38,6 +38,7 @@ "@octokit/core": "^5.2.1", "@octokit/plugin-paginate-graphql": "^4.0.1", "@octokit/plugin-retry": "^5.0.5", + "@octokit/request": "8.4.1", "@octokit/rest": "^20.0.2", "@octokit/webhooks-types": "^7.3.1", "@octopusdeploy/api-client": "^3.4.1", @@ -9777,18 +9778,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/auth-app/node_modules/@octokit/endpoint": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", - "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", - "dependencies": { - "@octokit/types": "^13.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/auth-app/node_modules/@octokit/openapi-types": { "version": "22.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", @@ -9835,11 +9824,6 @@ "node": "14 || >=16.14" } }, - "node_modules/@octokit/auth-app/node_modules/universal-user-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" - }, "node_modules/@octokit/auth-oauth-app": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-app/-/auth-oauth-app-8.1.1.tgz", @@ -9855,18 +9839,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/endpoint": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", - "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", - "dependencies": { - "@octokit/types": "^13.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/auth-oauth-app/node_modules/@octokit/openapi-types": { "version": "22.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", @@ -9905,11 +9877,6 @@ "@octokit/openapi-types": "^22.2.0" } }, - "node_modules/@octokit/auth-oauth-app/node_modules/universal-user-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" - }, "node_modules/@octokit/auth-oauth-device": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-device/-/auth-oauth-device-7.1.1.tgz", @@ -9924,18 +9891,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/endpoint": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", - "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", - "dependencies": { - "@octokit/types": "^13.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/auth-oauth-device/node_modules/@octokit/openapi-types": { "version": "22.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", @@ -9974,11 +9929,6 @@ "@octokit/openapi-types": "^22.2.0" } }, - "node_modules/@octokit/auth-oauth-device/node_modules/universal-user-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" - }, "node_modules/@octokit/auth-oauth-user": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@octokit/auth-oauth-user/-/auth-oauth-user-5.1.1.tgz", @@ -9994,18 +9944,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/endpoint": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", - "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", - "dependencies": { - "@octokit/types": "^13.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/auth-oauth-user/node_modules/@octokit/openapi-types": { "version": "22.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", @@ -10044,11 +9982,6 @@ "@octokit/openapi-types": "^22.2.0" } }, - "node_modules/@octokit/auth-oauth-user/node_modules/universal-user-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" - }, "node_modules/@octokit/auth-token": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", @@ -10102,32 +10035,38 @@ "@octokit/openapi-types": "^24.2.0" } }, + "node_modules/@octokit/core/node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, "node_modules/@octokit/endpoint": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", - "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.4.tgz", + "integrity": "sha512-OlYOlZIsfEVZm5HCSR8aSg02T2lbUWOsCQoPKfTXJwDzcHQBrVBGdGXb89dv2Kw2ToZaRtudp8O3ZIYoaOjKlA==", "license": "MIT", "dependencies": { - "@octokit/types": "^13.1.0", - "universal-user-agent": "^6.0.0" + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" }, "engines": { "node": ">= 18" } }, "node_modules/@octokit/endpoint/node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", "license": "MIT" }, "node_modules/@octokit/endpoint/node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^24.2.0" + "@octokit/openapi-types": "^25.1.0" } }, "node_modules/@octokit/graphql": { @@ -10159,6 +10098,12 @@ "@octokit/openapi-types": "^24.2.0" } }, + "node_modules/@octokit/graphql/node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, "node_modules/@octokit/oauth-authorization-url": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@octokit/oauth-authorization-url/-/oauth-authorization-url-7.1.1.tgz", @@ -10181,18 +10126,6 @@ "node": ">= 18" } }, - "node_modules/@octokit/oauth-methods/node_modules/@octokit/endpoint": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.1.tgz", - "integrity": "sha512-JYjh5rMOwXMJyUpj028cu0Gbp7qe/ihxfJMLc8VZBMMqSwLgOxDI1911gV4Enl1QSavAQNJcwmwBF9M0VvLh6Q==", - "dependencies": { - "@octokit/types": "^13.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/@octokit/oauth-methods/node_modules/@octokit/openapi-types": { "version": "22.2.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", @@ -10231,11 +10164,6 @@ "@octokit/openapi-types": "^22.2.0" } }, - "node_modules/@octokit/oauth-methods/node_modules/universal-user-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" - }, "node_modules/@octokit/openapi-types": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", @@ -10376,31 +10304,54 @@ } }, "node_modules/@octokit/request-error/node_modules/@octokit/openapi-types": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", - "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==" + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" }, "node_modules/@octokit/request-error/node_modules/@octokit/types": { - "version": "13.6.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz", - "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==", + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^22.2.0" + "@octokit/openapi-types": "^24.2.0" + } + }, + "node_modules/@octokit/request/node_modules/@octokit/endpoint": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz", + "integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==", + "license": "MIT", + "dependencies": { + "@octokit/types": "^13.1.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" } }, "node_modules/@octokit/request/node_modules/@octokit/openapi-types": { - "version": "22.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-22.2.0.tgz", - "integrity": "sha512-QBhVjcUa9W7Wwhm6DBFu6ZZ+1/t/oYxqc2tp81Pi41YNuJinbFRx8B133qVOrAaBbF7D/m0Et6f9/pZt9Rc+tg==" + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", + "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", + "license": "MIT" }, "node_modules/@octokit/request/node_modules/@octokit/types": { - "version": "13.6.1", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.6.1.tgz", - "integrity": "sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==", + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", + "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", + "license": "MIT", "dependencies": { - "@octokit/openapi-types": "^22.2.0" + "@octokit/openapi-types": "^24.2.0" } }, + "node_modules/@octokit/request/node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, "node_modules/@octokit/rest": { "version": "20.0.2", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz", @@ -18288,7 +18239,8 @@ "node_modules/fast-content-type-parse": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-1.1.0.tgz", - "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==" + "integrity": "sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==", + "license": "MIT" }, "node_modules/fast-copy": { "version": "3.0.1", @@ -24776,6 +24728,12 @@ "jsonwebtoken": "^9.0.2" } }, + "node_modules/octokit-auth-probot/node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==", + "license": "ISC" + }, "node_modules/odbc": { "version": "2.4.9", "resolved": "https://registry.npmjs.org/odbc/-/odbc-2.4.9.tgz", @@ -30705,9 +30663,10 @@ "integrity": "sha512-G5o6f95b5BggDGuUfKDApKaCgNYy2x7OdHY0zSMF081O0EJobw+1130VONhrA7ezGSV2FNOGyM+KQpQZAr9bIQ==" }, "node_modules/universal-user-agent": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", - "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "license": "ISC" }, "node_modules/universalify": { "version": "2.0.1", diff --git a/backend/package.json b/backend/package.json index ff8b832bc..f84db13fc 100644 --- a/backend/package.json +++ b/backend/package.json @@ -158,6 +158,7 @@ "@octokit/core": "^5.2.1", "@octokit/plugin-paginate-graphql": "^4.0.1", "@octokit/plugin-retry": "^5.0.5", + "@octokit/request": "8.4.1", "@octokit/rest": "^20.0.2", "@octokit/webhooks-types": "^7.3.1", "@octopusdeploy/api-client": "^3.4.1", diff --git a/backend/src/ee/services/secret-scanning-v2/secret-scanning-v2-dal.ts b/backend/src/ee/services/secret-scanning-v2/secret-scanning-v2-dal.ts index 447ffc22a..c6ca50c5e 100644 --- a/backend/src/ee/services/secret-scanning-v2/secret-scanning-v2-dal.ts +++ b/backend/src/ee/services/secret-scanning-v2/secret-scanning-v2-dal.ts @@ -49,6 +49,7 @@ const baseSecretScanningDataSourceQuery = ({ db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"), db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"), db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"), + db.ref("gatewayId").withSchema(TableName.AppConnection).as("connectionGatewayId"), db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"), db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"), db @@ -82,6 +83,7 @@ const expandSecretScanningDataSource = < connectionUpdatedAt, connectionVersion, connectionIsPlatformManagedCredentials, + connectionGatewayId, ...el } = dataSource; @@ -100,7 +102,8 @@ const expandSecretScanningDataSource = < createdAt: connectionCreatedAt, updatedAt: connectionUpdatedAt, version: connectionVersion, - isPlatformManagedCredentials: connectionIsPlatformManagedCredentials + isPlatformManagedCredentials: connectionIsPlatformManagedCredentials, + gatewayId: connectionGatewayId } : undefined }; diff --git a/backend/src/services/app-connection/github/github-connection-fns.ts b/backend/src/services/app-connection/github/github-connection-fns.ts index 57d01be29..c1542bbd9 100644 --- a/backend/src/services/app-connection/github/github-connection-fns.ts +++ b/backend/src/services/app-connection/github/github-connection-fns.ts @@ -1,4 +1,5 @@ import { createAppAuth } from "@octokit/auth-app"; +import { request } from "@octokit/request"; import { AxiosError, AxiosRequestConfig, AxiosResponse } from "axios"; import https from "https"; import RE2 from "re2"; @@ -12,7 +13,6 @@ import { GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway"; import { logger } from "@app/lib/logger"; import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; import { getAppConnectionMethodName } from "@app/services/app-connection/app-connection-fns"; -import { IntegrationUrls } from "@app/services/integration-auth/integration-list"; import { AppConnection } from "../app-connection-enums"; import { GitHubConnectionMethod } from "./github-connection-enums"; @@ -30,6 +30,23 @@ export const getGitHubConnectionListItem = () => { }; }; +export const getGitHubInstanceApiUrl = async (config: { + credentials: Pick; +}) => { + const host = config.credentials.host || "github.com"; + + await blockLocalAndPrivateIpAddresses(host); + + let apiBase: string; + if (config.credentials.instanceType === "server") { + apiBase = `${host}/api/v3`; + } else { + apiBase = `api.${host}`; + } + + return apiBase; +}; + export const requestWithGitHubGateway = async ( appConnection: { gatewayId?: string | null }, gatewayService: Pick, @@ -73,7 +90,10 @@ export const requestWithGitHubGateway = async ( return await httpRequest.request(finalRequestConfig); } catch (error) { const axiosError = error as AxiosError; - logger.error("Error during GitHub gateway request:", axiosError.message, axiosError.response?.data); + logger.error( + { message: axiosError.message, data: axiosError.response?.data }, + "Error during GitHub gateway request:" + ); throw error; } }, @@ -112,7 +132,10 @@ export const getGitHubAppAuthToken = async (appConnection: TGitHubConnection) => const appAuth = createAppAuth({ appId, privateKey: appPrivateKey, - installationId: appConnection.credentials.installationId + installationId: appConnection.credentials.installationId, + request: request.defaults({ + baseUrl: `https://${await getGitHubInstanceApiUrl(appConnection)}` + }) }); const { token } = await appAuth({ type: "installation" }); @@ -141,7 +164,7 @@ export const makePaginatedGitHubRequest = async ( const token = method === GitHubConnectionMethod.OAuth ? credentials.accessToken : await getGitHubAppAuthToken(appConnection); - let url: string | null = `https://api.${credentials.host || "github.com"}${path}`; + let url: string | null = `https://${await getGitHubInstanceApiUrl(appConnection)}${path}`; let results: T[] = []; let i = 0; @@ -355,7 +378,7 @@ export const validateGitHubConnectionCredentials = async ( }; }[]; }>(config, gatewayService, { - url: IntegrationUrls.GITHUB_USER_INSTALLATIONS.replace("api.github.com", `api.${host}`), + url: `https://${await getGitHubInstanceApiUrl(config)}/user/installations`, headers: { Accept: "application/json", Authorization: `Bearer ${tokenResp.data.access_token}`, @@ -377,11 +400,15 @@ export const validateGitHubConnectionCredentials = async ( switch (method) { case GitHubConnectionMethod.App: return { - installationId: credentials.installationId + installationId: credentials.installationId, + instanceType: credentials.instanceType, + host: credentials.host }; case GitHubConnectionMethod.OAuth: return { - accessToken: tokenResp.data.access_token + accessToken: tokenResp.data.access_token, + instanceType: credentials.instanceType, + host: credentials.host }; default: throw new InternalServerError({ diff --git a/backend/src/services/app-connection/github/github-connection-schemas.ts b/backend/src/services/app-connection/github/github-connection-schemas.ts index bf92ec155..1b8aa9c3f 100644 --- a/backend/src/services/app-connection/github/github-connection-schemas.ts +++ b/backend/src/services/app-connection/github/github-connection-schemas.ts @@ -10,26 +10,59 @@ import { import { GitHubConnectionMethod } from "./github-connection-enums"; -export const GitHubConnectionOAuthInputCredentialsSchema = z.object({ - code: z.string().trim().min(1, "OAuth code required"), - host: z.string().trim().optional() -}); +export const GitHubConnectionOAuthInputCredentialsSchema = z.union([ + z.object({ + code: z.string().trim().min(1, "OAuth code required"), + instanceType: z.literal("server"), + host: z.string().trim().min(1, "Host is required for server instance type") + }), + z.object({ + code: z.string().trim().min(1, "OAuth code required"), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); -export const GitHubConnectionAppInputCredentialsSchema = z.object({ - code: z.string().trim().min(1, "GitHub App code required"), - installationId: z.string().min(1, "GitHub App Installation ID required"), - host: z.string().trim().optional() -}); +export const GitHubConnectionAppInputCredentialsSchema = z.union([ + z.object({ + code: z.string().trim().min(1, "GitHub App code required"), + installationId: z.string().min(1, "GitHub App Installation ID required"), + instanceType: z.literal("server"), + host: z.string().trim().min(1, "Host is required for server instance type") + }), + z.object({ + code: z.string().trim().min(1, "GitHub App code required"), + installationId: z.string().min(1, "GitHub App Installation ID required"), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); -export const GitHubConnectionOAuthOutputCredentialsSchema = z.object({ - accessToken: z.string(), - host: z.string().trim().optional() -}); +export const GitHubConnectionOAuthOutputCredentialsSchema = z.union([ + z.object({ + accessToken: z.string(), + instanceType: z.literal("server"), + host: z.string().trim().min(1) + }), + z.object({ + accessToken: z.string(), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); -export const GitHubConnectionAppOutputCredentialsSchema = z.object({ - installationId: z.string(), - host: z.string().trim().optional() -}); +export const GitHubConnectionAppOutputCredentialsSchema = z.union([ + z.object({ + installationId: z.string(), + instanceType: z.literal("server"), + host: z.string().trim().min(1) + }), + z.object({ + installationId: z.string(), + instanceType: z.literal("cloud").optional(), + host: z.string().trim().optional() + }) +]); export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("method", [ z.object({ @@ -84,11 +117,17 @@ export const GitHubConnectionSchema = z.intersection( export const SanitizedGitHubConnectionSchema = z.discriminatedUnion("method", [ BaseGitHubConnectionSchema.extend({ method: z.literal(GitHubConnectionMethod.App), - credentials: GitHubConnectionAppOutputCredentialsSchema.pick({}) + credentials: z.object({ + instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(), + host: z.string().optional() + }) }), BaseGitHubConnectionSchema.extend({ method: z.literal(GitHubConnectionMethod.OAuth), - credentials: GitHubConnectionOAuthOutputCredentialsSchema.pick({}) + credentials: z.object({ + instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(), + host: z.string().optional() + }) }) ]); diff --git a/backend/src/services/secret-sync/github/github-sync-fns.ts b/backend/src/services/secret-sync/github/github-sync-fns.ts index b37d5e90e..e2cf8f6e8 100644 --- a/backend/src/services/secret-sync/github/github-sync-fns.ts +++ b/backend/src/services/secret-sync/github/github-sync-fns.ts @@ -3,6 +3,7 @@ import sodium from "libsodium-wrappers"; import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service"; import { getGitHubAppAuthToken, + getGitHubInstanceApiUrl, GitHubConnectionMethod, makePaginatedGitHubRequest, requestWithGitHubGateway @@ -73,7 +74,7 @@ const getPublicKey = async ( } const response = await requestWithGitHubGateway(connection, gatewayService, { - url: `https://api.${connection.credentials.host || "github.com"}${path}`, + url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, method: "GET", headers: { Accept: "application/vnd.github+json", @@ -111,7 +112,7 @@ const deleteSecret = async ( } await requestWithGitHubGateway(connection, gatewayService, { - url: `https://api.${connection.credentials.host || "github.com"}${path}`, + url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, method: "DELETE", headers: { Accept: "application/vnd.github+json", @@ -157,7 +158,7 @@ const putSecret = async ( } await requestWithGitHubGateway(connection, gatewayService, { - url: `https://api.${connection.credentials.host || "github.com"}${path}`, + url: `https://${await getGitHubInstanceApiUrl(connection)}${path}`, method: "PUT", headers: { Accept: "application/vnd.github+json", diff --git a/backend/src/services/secret-sync/secret-sync-dal.ts b/backend/src/services/secret-sync/secret-sync-dal.ts index 617393668..e50593f10 100644 --- a/backend/src/services/secret-sync/secret-sync-dal.ts +++ b/backend/src/services/secret-sync/secret-sync-dal.ts @@ -30,6 +30,7 @@ const baseSecretSyncQuery = ({ filter, db, tx }: { db: TDbClient; filter?: Secre db.ref("encryptedCredentials").withSchema(TableName.AppConnection).as("connectionEncryptedCredentials"), db.ref("description").withSchema(TableName.AppConnection).as("connectionDescription"), db.ref("version").withSchema(TableName.AppConnection).as("connectionVersion"), + db.ref("gatewayId").withSchema(TableName.AppConnection).as("connectionGatewayId"), db.ref("createdAt").withSchema(TableName.AppConnection).as("connectionCreatedAt"), db.ref("updatedAt").withSchema(TableName.AppConnection).as("connectionUpdatedAt"), db @@ -65,6 +66,7 @@ const expandSecretSync = ( connectionUpdatedAt, connectionVersion, connectionIsPlatformManagedCredentials, + connectionGatewayId, ...el } = secretSync; @@ -83,7 +85,8 @@ const expandSecretSync = ( createdAt: connectionCreatedAt, updatedAt: connectionUpdatedAt, version: connectionVersion, - isPlatformManagedCredentials: connectionIsPlatformManagedCredentials + isPlatformManagedCredentials: connectionIsPlatformManagedCredentials, + gatewayId: connectionGatewayId }, folder: folder ? { diff --git a/frontend/src/hooks/api/appConnections/types/github-connection.ts b/frontend/src/hooks/api/appConnections/types/github-connection.ts index a8b734aa9..27bed2dcb 100644 --- a/frontend/src/hooks/api/appConnections/types/github-connection.ts +++ b/frontend/src/hooks/api/appConnections/types/github-connection.ts @@ -11,6 +11,7 @@ export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub method: GitHubConnectionMethod.OAuth; credentials: { code: string; + instanceType?: "cloud" | "server"; host?: string; }; } @@ -19,6 +20,7 @@ export type TGitHubConnection = TRootAppConnection & { app: AppConnection.GitHub credentials: { code: string; installationId: string; + instanceType?: "cloud" | "server"; host?: string; }; } diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx index eb93993af..5c9a5bcd3 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/GitHubConnectionForm.tsx @@ -48,9 +48,16 @@ const formSchema = genericAppConnectionFieldsSchema.extend({ app: z.literal(AppConnection.GitHub), method: z.nativeEnum(GitHubConnectionMethod), credentials: z - .object({ - host: z.string().optional() - }) + .union([ + z.object({ + instanceType: z.literal("cloud").optional(), + host: z.string().optional() + }), + z.object({ + instanceType: z.literal("server"), + host: z.string().min(1, "Required") + }) + ]) .optional() }); @@ -70,7 +77,10 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => { defaultValues: appConnection ?? { app: AppConnection.GitHub, method: GitHubConnectionMethod.App, - gatewayId: null + gatewayId: null, + credentials: { + instanceType: "cloud" + } } }); @@ -78,6 +88,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => { handleSubmit, control, watch, + setValue, formState: { isSubmitting, isDirty } } = form; @@ -85,6 +96,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => { const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list()); const selectedMethod = watch("method"); + const instanceType = watch("credentials.instanceType"); const onSubmit = (formData: FormData) => { setIsRedirecting(true); @@ -103,7 +115,7 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => { switch (formData.method) { case GitHubConnectionMethod.App: window.location.assign( - `${githubHost}/apps/${appClientSlug}/installations/new?state=${state}` + `${githubHost}/${formData.credentials?.instanceType === "server" ? "github-apps" : "apps"}/${appClientSlug}/installations/new?state=${state}` ); break; case GitHubConnectionMethod.OAuth: @@ -175,13 +187,54 @@ export const GitHubConnectionForm = ({ appConnection }: Props) => { )} /> - {subscription.gateway && ( - - - -
GitHub Enterprise Options
-
- + + + +
GitHub Enterprise Options
+
+ + ( + + + + )} + /> + + ( + + + + )} + /> + {subscription.gateway && instanceType === "server" && ( { ( {
- - )} - /> - - - - )} + )} + + +