Merge pull request #4743 from Infisical/feat/adds-PAT-to-github-integration

feat: adds PAT to GitHub integration
This commit is contained in:
Piyush Gupta
2025-10-25 02:37:10 +05:30
committed by GitHub
15 changed files with 288 additions and 36 deletions
@@ -345,6 +345,8 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
case GitHubConnectionMethod.App:
case GitHubRadarConnectionMethod.App:
return "GitHub App";
case GitHubConnectionMethod.Pat:
return "Personal Access Token";
case AzureKeyVaultConnectionMethod.OAuth:
case AzureAppConfigurationConnectionMethod.OAuth:
case AzureClientSecretsConnectionMethod.OAuth:
@@ -1,4 +1,5 @@
export enum GitHubConnectionMethod {
OAuth = "oauth",
App = "github-app"
App = "github-app",
Pat = "pat"
}
@@ -248,10 +248,18 @@ export const makePaginatedGitHubRequest = async <T, R = T[]>(
): Promise<T[]> => {
const { credentials, method } = appConnection;
const token =
method === GitHubConnectionMethod.OAuth
? credentials.accessToken
: await getGitHubAppAuthToken(appConnection, gatewayService, gatewayV2Service);
let token: string;
switch (method) {
case GitHubConnectionMethod.OAuth:
token = credentials.accessToken;
break;
case GitHubConnectionMethod.Pat:
token = credentials.personalAccessToken;
break;
default:
token = await getGitHubAppAuthToken(appConnection, gatewayService, gatewayV2Service);
}
const baseUrl = `https://${await getGitHubInstanceApiUrl(appConnection)}${path}`;
const initialUrlObj = new URL(baseUrl);
@@ -460,6 +468,35 @@ export const validateGitHubConnectionCredentials = async (
gatewayV2Service: Pick<TGatewayV2ServiceFactory, "getPlatformConnectionDetailsByGatewayId">
) => {
const { credentials, method } = config;
// PAT validation
if (method === GitHubConnectionMethod.Pat) {
try {
const apiUrl = await getGitHubInstanceApiUrl(config);
await requestWithGitHubGateway(config, gatewayService, gatewayV2Service, {
url: `https://${apiUrl}/user`,
method: "GET",
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${credentials.personalAccessToken}`,
"X-GitHub-Api-Version": "2022-11-28"
}
});
return {
personalAccessToken: credentials.personalAccessToken,
instanceType: credentials.instanceType,
host: credentials.host
};
} catch (e: unknown) {
logger.error(e, "Unable to verify GitHub PAT connection");
throw new BadRequestError({
message: "Unable to validate Personal Access Token: verify token has proper permissions"
});
}
}
const {
INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_ID,
INF_APP_CONNECTION_GITHUB_OAUTH_CLIENT_SECRET,
@@ -38,6 +38,19 @@ export const GitHubConnectionAppInputCredentialsSchema = z.union([
})
]);
export const GitHubConnectionPatInputCredentialsSchema = z.union([
z.object({
personalAccessToken: z.string().trim().min(1, "Personal Access Token required"),
instanceType: z.literal("server"),
host: z.string().trim().min(1, "Host is required for server instance type")
}),
z.object({
personalAccessToken: z.string().trim().min(1, "Personal Access Token required"),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional()
})
]);
export const GitHubConnectionOAuthOutputCredentialsSchema = z.union([
z.object({
accessToken: z.string(),
@@ -64,6 +77,19 @@ export const GitHubConnectionAppOutputCredentialsSchema = z.union([
})
]);
export const GitHubConnectionPatOutputCredentialsSchema = z.union([
z.object({
personalAccessToken: z.string(),
instanceType: z.literal("server"),
host: z.string().trim().min(1)
}),
z.object({
personalAccessToken: z.string(),
instanceType: z.literal("cloud").optional(),
host: z.string().trim().optional()
})
]);
export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("method", [
z.object({
method: z.literal(GitHubConnectionMethod.App).describe(AppConnections.CREATE(AppConnection.GitHub).method),
@@ -76,6 +102,12 @@ export const ValidateGitHubConnectionCredentialsSchema = z.discriminatedUnion("m
credentials: GitHubConnectionOAuthInputCredentialsSchema.describe(
AppConnections.CREATE(AppConnection.GitHub).credentials
)
}),
z.object({
method: z.literal(GitHubConnectionMethod.Pat).describe(AppConnections.CREATE(AppConnection.GitHub).method),
credentials: GitHubConnectionPatInputCredentialsSchema.describe(
AppConnections.CREATE(AppConnection.GitHub).credentials
)
})
]);
@@ -88,7 +120,11 @@ export const CreateGitHubConnectionSchema = ValidateGitHubConnectionCredentialsS
export const UpdateGitHubConnectionSchema = z
.object({
credentials: z
.union([GitHubConnectionAppInputCredentialsSchema, GitHubConnectionOAuthInputCredentialsSchema])
.union([
GitHubConnectionAppInputCredentialsSchema,
GitHubConnectionOAuthInputCredentialsSchema,
GitHubConnectionPatInputCredentialsSchema
])
.optional()
.describe(AppConnections.UPDATE(AppConnection.GitHub).credentials)
})
@@ -110,6 +146,10 @@ export const GitHubConnectionSchema = z.intersection(
z.object({
method: z.literal(GitHubConnectionMethod.OAuth),
credentials: GitHubConnectionOAuthOutputCredentialsSchema
}),
z.object({
method: z.literal(GitHubConnectionMethod.Pat),
credentials: GitHubConnectionPatOutputCredentialsSchema
})
])
);
@@ -128,6 +168,13 @@ export const SanitizedGitHubConnectionSchema = z.discriminatedUnion("method", [
instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(),
host: z.string().optional()
})
}),
BaseGitHubConnectionSchema.extend({
method: z.literal(GitHubConnectionMethod.Pat),
credentials: z.object({
instanceType: z.union([z.literal("server"), z.literal("cloud")]).optional(),
host: z.string().optional()
})
})
]);
@@ -211,10 +211,18 @@ export const GithubSyncFns = {
}
const { connection } = secretSync;
const token =
connection.method === GitHubConnectionMethod.OAuth
? connection.credentials.accessToken
: await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service);
let token: string;
switch (connection.method) {
case GitHubConnectionMethod.OAuth:
token = connection.credentials.accessToken;
break;
case GitHubConnectionMethod.Pat:
token = connection.credentials.personalAccessToken;
break;
default:
token = await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service);
}
const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService, gatewayV2Service);
const publicKey = await getPublicKey(secretSync, gatewayService, gatewayV2Service, token);
@@ -269,10 +277,18 @@ export const GithubSyncFns = {
const secretMap = Object.fromEntries(Object.entries(ogSecretMap).map(([i, v]) => [i.toUpperCase(), v]));
const { connection } = secretSync;
const token =
connection.method === GitHubConnectionMethod.OAuth
? connection.credentials.accessToken
: await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service);
let token: string;
switch (connection.method) {
case GitHubConnectionMethod.OAuth:
token = connection.credentials.accessToken;
break;
case GitHubConnectionMethod.Pat:
token = connection.credentials.personalAccessToken;
break;
default:
token = await getGitHubAppAuthToken(connection, gatewayService, gatewayV2Service);
}
const encryptedSecrets = await getEncryptedSecrets(secretSync, gatewayService, gatewayV2Service);