mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 22:28:15 +00:00
feat(secret-sync): add Gitlab PR comments suggestions
This commit is contained in:
@@ -2232,7 +2232,8 @@ export const AppConnections = {
|
||||
GITLAB: {
|
||||
instanceUrl: "The GitLab instance URL to connect with.",
|
||||
accessToken: "The Access Token used to access GitLab.",
|
||||
code: "The OAuth code to use to connect with GitLab."
|
||||
code: "The OAuth code to use to connect with GitLab.",
|
||||
accessTokenType: "The type of token used to connect with GitLab."
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,3 +2,8 @@ export enum GitLabConnectionMethod {
|
||||
OAuth = "oauth",
|
||||
AccessToken = "access-token"
|
||||
}
|
||||
|
||||
export enum GitLabAccessTokenType {
|
||||
Project = "project",
|
||||
Personal = "personal"
|
||||
}
|
||||
|
||||
@@ -79,10 +79,13 @@ export const refreshGitLabToken = async (
|
||||
}
|
||||
});
|
||||
|
||||
const expiresAt = new Date(Date.now() + data.expires_in * 1000 - 60000);
|
||||
const expiresAt = new Date(Date.now() + data.expires_in * 1000 - 600000);
|
||||
|
||||
const encryptedCredentials = await encryptAppConnectionCredentials({
|
||||
credentials: {
|
||||
instanceUrl,
|
||||
tokenType: data.token_type,
|
||||
createdAt: new Date(data.created_at * 1000).toISOString(),
|
||||
refreshToken: data.refresh_token,
|
||||
accessToken: data.access_token,
|
||||
expiresAt
|
||||
@@ -174,7 +177,7 @@ export const validateGitLabConnectionCredentials = async (config: TGitLabConnect
|
||||
|
||||
try {
|
||||
const url = await getGitLabInstanceUrl(inputCredentials.instanceUrl);
|
||||
response = await request.get<TGitLabProject[]>(`${url}/api/v4/groups`, {
|
||||
response = await request.get<TGitLabProject[]>(`${url}/api/v4/user`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
Accept: "application/json"
|
||||
@@ -200,6 +203,7 @@ export const validateGitLabConnectionCredentials = async (config: TGitLabConnect
|
||||
if (method === GitLabConnectionMethod.OAuth && oauthData) {
|
||||
return {
|
||||
accessToken,
|
||||
instanceUrl: inputCredentials.instanceUrl,
|
||||
refreshToken: oauthData.refresh_token,
|
||||
expiresAt: new Date(Date.now() + oauthData.expires_in * 1000 - 60000),
|
||||
tokenType: oauthData.token_type,
|
||||
|
||||
@@ -8,9 +8,8 @@ import {
|
||||
GenericUpdateAppConnectionFieldsSchema
|
||||
} from "@app/services/app-connection/app-connection-schemas";
|
||||
|
||||
import { GitLabConnectionMethod } from "./gitlab-connection-enums";
|
||||
import { GitLabAccessTokenType, GitLabConnectionMethod } from "./gitlab-connection-enums";
|
||||
|
||||
// Fixed: Use consistent accessToken naming throughout
|
||||
export const GitLabConnectionAccessTokenCredentialsSchema = z.object({
|
||||
accessToken: z
|
||||
.string()
|
||||
@@ -22,7 +21,8 @@ export const GitLabConnectionAccessTokenCredentialsSchema = z.object({
|
||||
.trim()
|
||||
.url("Invalid Instance URL")
|
||||
.optional()
|
||||
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
|
||||
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl),
|
||||
accessTokenType: z.nativeEnum(GitLabAccessTokenType).describe(AppConnections.CREDENTIALS.GITLAB.accessTokenType)
|
||||
});
|
||||
|
||||
export const GitLabConnectionOAuthCredentialsSchema = z.object({
|
||||
@@ -35,7 +35,6 @@ export const GitLabConnectionOAuthCredentialsSchema = z.object({
|
||||
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
|
||||
});
|
||||
|
||||
// Fixed: Updated schema to match GitLab's actual OAuth response structure
|
||||
export const GitLabConnectionOAuthOutputCredentialsSchema = z.object({
|
||||
accessToken: z.string().trim(),
|
||||
refreshToken: z.string().trim(),
|
||||
@@ -50,7 +49,6 @@ export const GitLabConnectionOAuthOutputCredentialsSchema = z.object({
|
||||
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
|
||||
});
|
||||
|
||||
// Schema for refresh token input during initial setup
|
||||
export const GitLabConnectionRefreshTokenCredentialsSchema = z.object({
|
||||
refreshToken: z.string().trim().min(1, "Refresh token required"),
|
||||
instanceUrl: z
|
||||
@@ -83,8 +81,9 @@ export const SanitizedGitLabConnectionSchema = z.discriminatedUnion("method", [
|
||||
BaseGitLabConnectionSchema.extend({
|
||||
method: z.literal(GitLabConnectionMethod.AccessToken),
|
||||
credentials: GitLabConnectionAccessTokenCredentialsSchema.pick({
|
||||
instanceUrl: true
|
||||
}) // Don't expose sensitive data
|
||||
instanceUrl: true,
|
||||
accessTokenType: true
|
||||
})
|
||||
}),
|
||||
BaseGitLabConnectionSchema.extend({
|
||||
method: z.literal(GitLabConnectionMethod.OAuth),
|
||||
|
||||
@@ -271,67 +271,84 @@ export const GitLabSyncFns = {
|
||||
const currentVariableMap = new Map(currentVariables.map((v) => [v.key, v]));
|
||||
|
||||
for (const [key, { value }] of Object.entries(secretMap)) {
|
||||
const existingVariable = currentVariableMap.get(key);
|
||||
try {
|
||||
const existingVariable = currentVariableMap.get(key);
|
||||
|
||||
if (existingVariable) {
|
||||
if (existingVariable.value !== value) {
|
||||
await updateGitLabVariable({
|
||||
if (existingVariable) {
|
||||
if (existingVariable.value !== value) {
|
||||
await updateGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
projectId,
|
||||
key,
|
||||
variable: {
|
||||
value,
|
||||
variable_type: existingVariable.variable_type,
|
||||
environment_scope: targetEnvironment || existingVariable.environment_scope,
|
||||
protected: destinationConfig.shouldProtectSecrets ?? existingVariable.protected,
|
||||
...(!existingVariable.masked && destinationConfig.shouldMaskSecrets && { masked: value?.length > 8 }),
|
||||
...(!existingVariable.hidden &&
|
||||
destinationConfig.shouldHideSecrets && { masked_and_hidden: value?.length > 8 }),
|
||||
description: existingVariable.description ?? undefined
|
||||
},
|
||||
targetEnvironment
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await createGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
projectId,
|
||||
key,
|
||||
variable: {
|
||||
key,
|
||||
value,
|
||||
variable_type: existingVariable.variable_type,
|
||||
environment_scope: targetEnvironment || existingVariable.environment_scope,
|
||||
protected: destinationConfig.shouldProtectSecrets ?? existingVariable.protected,
|
||||
...(!existingVariable.masked && destinationConfig.shouldMaskSecrets && { masked: value?.length > 8 }),
|
||||
...(!existingVariable.hidden &&
|
||||
destinationConfig.shouldHideSecrets && { masked_and_hidden: value?.length > 8 }),
|
||||
description: existingVariable.description ?? undefined
|
||||
},
|
||||
targetEnvironment
|
||||
variable_type: "env_var",
|
||||
environment_scope: targetEnvironment || "*",
|
||||
protected: destinationConfig.shouldProtectSecrets || false,
|
||||
masked: value?.length > 8 ? destinationConfig.shouldMaskSecrets || false : false,
|
||||
masked_and_hidden: value?.length > 8 ? destinationConfig.shouldHideSecrets || false : false
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await createGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
projectId,
|
||||
variable: {
|
||||
key,
|
||||
value,
|
||||
variable_type: "env_var",
|
||||
environment_scope: targetEnvironment || "*",
|
||||
protected: destinationConfig.shouldProtectSecrets || false,
|
||||
masked: value?.length > 8 ? destinationConfig.shouldMaskSecrets || false : false,
|
||||
masked_and_hidden: value?.length > 8 ? destinationConfig.shouldHideSecrets || false : false
|
||||
}
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!secretSync.syncOptions.disableSecretDeletion) {
|
||||
for (const variable of currentVariables) {
|
||||
const shouldDelete =
|
||||
matchesSchema(variable.key, environment?.slug || "", secretSync.syncOptions.keySchema) &&
|
||||
!(variable.key in secretMap);
|
||||
try {
|
||||
const shouldDelete =
|
||||
matchesSchema(variable.key, environment?.slug || "", secretSync.syncOptions.keySchema) &&
|
||||
!(variable.key in secretMap);
|
||||
|
||||
if (shouldDelete) {
|
||||
await deleteGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
projectId,
|
||||
key: variable.key,
|
||||
targetEnvironment
|
||||
if (shouldDelete) {
|
||||
await deleteGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
projectId,
|
||||
key: variable.key,
|
||||
targetEnvironment
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: variable.key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof SecretSyncError) {
|
||||
throw error;
|
||||
}
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: "batch_sync"
|
||||
message: "Failed to sync secrets",
|
||||
error
|
||||
});
|
||||
}
|
||||
},
|
||||
@@ -347,8 +364,8 @@ export const GitLabSyncFns = {
|
||||
|
||||
const accessToken = await getValidAccessToken(connection, appConnectionDAL, kmsService);
|
||||
|
||||
try {
|
||||
for (const key of Object.keys(secretMap)) {
|
||||
for (const key of Object.keys(secretMap)) {
|
||||
try {
|
||||
await deleteGitLabVariable({
|
||||
accessToken,
|
||||
connection,
|
||||
@@ -356,12 +373,12 @@ export const GitLabSyncFns = {
|
||||
key,
|
||||
targetEnvironment
|
||||
});
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: key
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
throw new SecretSyncError({
|
||||
error,
|
||||
secretKey: "batch_remove"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ export type TGitLabSyncWithCredentials = TGitLabSync & {
|
||||
connection: TGitLabConnection;
|
||||
};
|
||||
|
||||
// GitLab CI/CD Variable structure based on API documentation
|
||||
export type TGitLabVariable = {
|
||||
key: string;
|
||||
value: string;
|
||||
@@ -25,7 +24,6 @@ export type TGitLabVariable = {
|
||||
description: string | null;
|
||||
};
|
||||
|
||||
// Type for creating a new variable
|
||||
export type TGitLabVariableCreate = {
|
||||
key: string;
|
||||
value: string;
|
||||
@@ -37,7 +35,6 @@ export type TGitLabVariableCreate = {
|
||||
description?: string;
|
||||
};
|
||||
|
||||
// Type for updating an existing variable
|
||||
export type TGitLabVariableUpdate = {
|
||||
value: string;
|
||||
variable_type?: "env_var" | "file";
|
||||
|
||||
Reference in New Issue
Block a user