Compare commits

..

3 Commits

114 changed files with 259 additions and 5390 deletions

View File

@@ -107,10 +107,6 @@ INF_APP_CONNECTION_GITHUB_APP_PRIVATE_KEY=
INF_APP_CONNECTION_GITHUB_APP_SLUG= INF_APP_CONNECTION_GITHUB_APP_SLUG=
INF_APP_CONNECTION_GITHUB_APP_ID= INF_APP_CONNECTION_GITHUB_APP_ID=
#gitlab app connection
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID=
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET=
#github radar app connection #github radar app connection
INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_ID= INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_ID=
INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_SECRET= INF_APP_CONNECTION_GITHUB_RADAR_APP_CLIENT_SECRET=

View File

@@ -30,7 +30,6 @@
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",
"@fastify/swagger": "^8.14.0", "@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^2.1.0", "@fastify/swagger-ui": "^2.1.0",
"@gitbeaker/rest": "^42.5.0",
"@google-cloud/kms": "^4.5.0", "@google-cloud/kms": "^4.5.0",
"@infisical/quic": "^1.0.8", "@infisical/quic": "^1.0.8",
"@node-saml/passport-saml": "^5.0.1", "@node-saml/passport-saml": "^5.0.1",
@@ -7808,48 +7807,6 @@
"p-limit": "^3.1.0" "p-limit": "^3.1.0"
} }
}, },
"node_modules/@gitbeaker/core": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-42.5.0.tgz",
"integrity": "sha512-rMWpOPaZi1iLiifnOIoVO57p2EmQQdfIwP4txqNyMvG4WjYP5Ez0U7jRD9Nra41x6K5kTPBZkuQcAdxVWRJcEQ==",
"license": "MIT",
"dependencies": {
"@gitbeaker/requester-utils": "^42.5.0",
"qs": "^6.12.2",
"xcase": "^2.0.1"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@gitbeaker/requester-utils": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-42.5.0.tgz",
"integrity": "sha512-HLdLS9LPBMVQumvroQg/4qkphLDtwDB+ygEsrD2u4oYCMUtXV4V1xaVqU4yTXjbTJ5sItOtdB43vYRkBcgueBw==",
"license": "MIT",
"dependencies": {
"picomatch-browser": "^2.2.6",
"qs": "^6.12.2",
"rate-limiter-flexible": "^4.0.1",
"xcase": "^2.0.1"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@gitbeaker/rest": {
"version": "42.5.0",
"resolved": "https://registry.npmjs.org/@gitbeaker/rest/-/rest-42.5.0.tgz",
"integrity": "sha512-oC5cM6jS7aFOp0luTw5mWSRuMgdxwHRLZQ/aWkI+ETMfsprR/HyxsXfljlMY/XJ/fRxTbRJiodR5Axf66WjO3w==",
"license": "MIT",
"dependencies": {
"@gitbeaker/core": "^42.5.0",
"@gitbeaker/requester-utils": "^42.5.0"
},
"engines": {
"node": ">=18.20.0"
}
},
"node_modules/@google-cloud/kms": { "node_modules/@google-cloud/kms": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/@google-cloud/kms/-/kms-4.5.0.tgz", "resolved": "https://registry.npmjs.org/@google-cloud/kms/-/kms-4.5.0.tgz",
@@ -24671,18 +24628,6 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/picomatch-browser": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/picomatch-browser/-/picomatch-browser-2.2.6.tgz",
"integrity": "sha512-0ypsOQt9D4e3hziV8O4elD9uN0z/jtUEfxVRtNaAAtXIyUx9m/SzlO020i8YNL2aL/E6blOvvHQcin6HZlFy/w==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pify": { "node_modules/pify": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
@@ -25617,12 +25562,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/rate-limiter-flexible": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.1.tgz",
"integrity": "sha512-2/dGHpDFpeA0+755oUkW+EKyklqLS9lu0go9pDsbhqQjZcxfRyJ6LA4JI0+HAdZ2bemD/oOjUeZQB2lCZqXQfQ==",
"license": "ISC"
},
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "2.5.2", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
@@ -31100,12 +31039,6 @@
} }
} }
}, },
"node_modules/xcase": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz",
"integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==",
"license": "MIT"
},
"node_modules/xml-crypto": { "node_modules/xml-crypto": {
"version": "6.0.1", "version": "6.0.1",
"resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.0.1.tgz", "resolved": "https://registry.npmjs.org/xml-crypto/-/xml-crypto-6.0.1.tgz",

View File

@@ -149,7 +149,6 @@
"@fastify/static": "^7.0.4", "@fastify/static": "^7.0.4",
"@fastify/swagger": "^8.14.0", "@fastify/swagger": "^8.14.0",
"@fastify/swagger-ui": "^2.1.0", "@fastify/swagger-ui": "^2.1.0",
"@gitbeaker/rest": "^42.5.0",
"@google-cloud/kms": "^4.5.0", "@google-cloud/kms": "^4.5.0",
"@infisical/quic": "^1.0.8", "@infisical/quic": "^1.0.8",
"@node-saml/passport-saml": "^5.0.1", "@node-saml/passport-saml": "^5.0.1",

View File

@@ -2228,12 +2228,6 @@ export const AppConnections = {
}, },
FLYIO: { FLYIO: {
accessToken: "The Access Token used to access fly.io." accessToken: "The Access Token used to access fly.io."
},
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.",
accessTokenType: "The type of token used to connect with GitLab."
} }
} }
}; };
@@ -2408,17 +2402,6 @@ export const SecretSyncs = {
FLYIO: { FLYIO: {
appId: "The ID of the Fly.io app to sync secrets to." appId: "The ID of the Fly.io app to sync secrets to."
}, },
GITLAB: {
projectId: "The GitLab Project ID to sync secrets to.",
projectName: "The GitLab Project Name to sync secrets to.",
groupId: "The GitLab Group ID to sync secrets to.",
groupName: "The GitLab Group Name to sync secrets to.",
scope: "The GitLab scope that secrets should be synced to. (default: project)",
targetEnvironment: "The GitLab environment scope that secrets should be synced to. (default: *)",
shouldProtectSecrets: "Whether variables should be protected",
shouldMaskSecrets: "Whether variables should be masked in logs",
shouldHideSecrets: "Whether variables should be hidden"
},
CLOUDFLARE_PAGES: { CLOUDFLARE_PAGES: {
projectName: "The name of the Cloudflare Pages project to sync secrets to.", projectName: "The name of the Cloudflare Pages project to sync secrets to.",
environment: "The environment of the Cloudflare Pages project to sync secrets to." environment: "The environment of the Cloudflare Pages project to sync secrets to."

View File

@@ -247,10 +247,6 @@ const envSchema = z
INF_APP_CONNECTION_GITHUB_RADAR_APP_ID: zpStr(z.string().optional()), INF_APP_CONNECTION_GITHUB_RADAR_APP_ID: zpStr(z.string().optional()),
INF_APP_CONNECTION_GITHUB_RADAR_APP_WEBHOOK_SECRET: zpStr(z.string().optional()), INF_APP_CONNECTION_GITHUB_RADAR_APP_WEBHOOK_SECRET: zpStr(z.string().optional()),
// gitlab oauth
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID: zpStr(z.string().optional()),
INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET: zpStr(z.string().optional()),
// gcp app // gcp app
INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL: zpStr(z.string().optional()), INF_APP_CONNECTION_GCP_SERVICE_ACCOUNT_CREDENTIAL: zpStr(z.string().optional()),

View File

@@ -35,10 +35,6 @@ import {
CamundaConnectionListItemSchema, CamundaConnectionListItemSchema,
SanitizedCamundaConnectionSchema SanitizedCamundaConnectionSchema
} from "@app/services/app-connection/camunda"; } from "@app/services/app-connection/camunda";
import {
CloudflareConnectionListItemSchema,
SanitizedCloudflareConnectionSchema
} from "@app/services/app-connection/cloudflare/cloudflare-connection-schema";
import { import {
DatabricksConnectionListItemSchema, DatabricksConnectionListItemSchema,
SanitizedDatabricksConnectionSchema SanitizedDatabricksConnectionSchema
@@ -50,7 +46,6 @@ import {
GitHubRadarConnectionListItemSchema, GitHubRadarConnectionListItemSchema,
SanitizedGitHubRadarConnectionSchema SanitizedGitHubRadarConnectionSchema
} from "@app/services/app-connection/github-radar"; } from "@app/services/app-connection/github-radar";
import { GitLabConnectionListItemSchema, SanitizedGitLabConnectionSchema } from "@app/services/app-connection/gitlab";
import { import {
HCVaultConnectionListItemSchema, HCVaultConnectionListItemSchema,
SanitizedHCVaultConnectionSchema SanitizedHCVaultConnectionSchema
@@ -85,6 +80,10 @@ import {
WindmillConnectionListItemSchema WindmillConnectionListItemSchema
} from "@app/services/app-connection/windmill"; } from "@app/services/app-connection/windmill";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
import {
CloudflareConnectionListItemSchema,
SanitizedCloudflareConnectionSchema
} from "@app/services/app-connection/cloudflare/cloudflare-connection-schema";
// can't use discriminated due to multiple schemas for certain apps // can't use discriminated due to multiple schemas for certain apps
const SanitizedAppConnectionSchema = z.union([ const SanitizedAppConnectionSchema = z.union([
@@ -115,7 +114,6 @@ const SanitizedAppConnectionSchema = z.union([
...SanitizedHerokuConnectionSchema.options, ...SanitizedHerokuConnectionSchema.options,
...SanitizedRenderConnectionSchema.options, ...SanitizedRenderConnectionSchema.options,
...SanitizedFlyioConnectionSchema.options, ...SanitizedFlyioConnectionSchema.options,
...SanitizedGitLabConnectionSchema.options,
...SanitizedCloudflareConnectionSchema.options ...SanitizedCloudflareConnectionSchema.options
]); ]);
@@ -147,7 +145,6 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
HerokuConnectionListItemSchema, HerokuConnectionListItemSchema,
RenderConnectionListItemSchema, RenderConnectionListItemSchema,
FlyioConnectionListItemSchema, FlyioConnectionListItemSchema,
GitLabConnectionListItemSchema,
CloudflareConnectionListItemSchema CloudflareConnectionListItemSchema
]); ]);

View File

@@ -1,90 +0,0 @@
import z from "zod";
import { readLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
CreateGitLabConnectionSchema,
SanitizedGitLabConnectionSchema,
TGitLabGroup,
TGitLabProject,
UpdateGitLabConnectionSchema
} from "@app/services/app-connection/gitlab";
import { AuthMode } from "@app/services/auth/auth-type";
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
export const registerGitLabConnectionRouter = async (server: FastifyZodProvider) => {
registerAppConnectionEndpoints({
app: AppConnection.GitLab,
server,
sanitizedResponseSchema: SanitizedGitLabConnectionSchema,
createSchema: CreateGitLabConnectionSchema,
updateSchema: UpdateGitLabConnectionSchema
});
// The below endpoints are not exposed and for Infisical App use
server.route({
method: "GET",
url: `/:connectionId/projects`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const projects: TGitLabProject[] = await server.services.appConnection.gitlab.listProjects(
connectionId,
req.permission
);
return projects;
}
});
server.route({
method: "GET",
url: `/:connectionId/groups`,
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
connectionId: z.string().uuid()
}),
response: {
200: z
.object({
id: z.string(),
name: z.string()
})
.array()
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { connectionId } = req.params;
const groups: TGitLabGroup[] = await server.services.appConnection.gitlab.listGroups(
connectionId,
req.permission
);
return groups;
}
});
};

View File

@@ -10,13 +10,11 @@ import { registerAzureClientSecretsConnectionRouter } from "./azure-client-secre
import { registerAzureDevOpsConnectionRouter } from "./azure-devops-connection-router"; import { registerAzureDevOpsConnectionRouter } from "./azure-devops-connection-router";
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router"; import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
import { registerCamundaConnectionRouter } from "./camunda-connection-router"; import { registerCamundaConnectionRouter } from "./camunda-connection-router";
import { registerCloudflareConnectionRouter } from "./cloudflare-connection-router";
import { registerDatabricksConnectionRouter } from "./databricks-connection-router"; import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
import { registerFlyioConnectionRouter } from "./flyio-connection-router"; import { registerFlyioConnectionRouter } from "./flyio-connection-router";
import { registerGcpConnectionRouter } from "./gcp-connection-router"; import { registerGcpConnectionRouter } from "./gcp-connection-router";
import { registerGitHubConnectionRouter } from "./github-connection-router"; import { registerGitHubConnectionRouter } from "./github-connection-router";
import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router"; import { registerGitHubRadarConnectionRouter } from "./github-radar-connection-router";
import { registerGitLabConnectionRouter } from "./gitlab-connection-router";
import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router"; import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router";
import { registerHerokuConnectionRouter } from "./heroku-connection-router"; import { registerHerokuConnectionRouter } from "./heroku-connection-router";
import { registerHumanitecConnectionRouter } from "./humanitec-connection-router"; import { registerHumanitecConnectionRouter } from "./humanitec-connection-router";
@@ -29,6 +27,7 @@ import { registerTeamCityConnectionRouter } from "./teamcity-connection-router";
import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router"; import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router";
import { registerVercelConnectionRouter } from "./vercel-connection-router"; import { registerVercelConnectionRouter } from "./vercel-connection-router";
import { registerWindmillConnectionRouter } from "./windmill-connection-router"; import { registerWindmillConnectionRouter } from "./windmill-connection-router";
import { registerCloudflareConnectionRouter } from "./cloudflare-connection-router";
export * from "./app-connection-router"; export * from "./app-connection-router";
@@ -61,6 +60,5 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
[AppConnection.Heroku]: registerHerokuConnectionRouter, [AppConnection.Heroku]: registerHerokuConnectionRouter,
[AppConnection.Render]: registerRenderConnectionRouter, [AppConnection.Render]: registerRenderConnectionRouter,
[AppConnection.Flyio]: registerFlyioConnectionRouter, [AppConnection.Flyio]: registerFlyioConnectionRouter,
[AppConnection.GitLab]: registerGitLabConnectionRouter,
[AppConnection.Cloudflare]: registerCloudflareConnectionRouter [AppConnection.Cloudflare]: registerCloudflareConnectionRouter
}; };

View File

@@ -1,13 +0,0 @@
import { CreateGitLabSyncSchema, GitLabSyncSchema, UpdateGitLabSyncSchema } from "@app/services/secret-sync/gitlab";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
export const registerGitLabSyncRouter = async (server: FastifyZodProvider) =>
registerSyncSecretsEndpoints({
destination: SecretSync.GitLab,
server,
responseSchema: GitLabSyncSchema,
createSchema: CreateGitLabSyncSchema,
updateSchema: UpdateGitLabSyncSchema
});

View File

@@ -13,7 +13,6 @@ import { registerDatabricksSyncRouter } from "./databricks-sync-router";
import { registerFlyioSyncRouter } from "./flyio-sync-router"; import { registerFlyioSyncRouter } from "./flyio-sync-router";
import { registerGcpSyncRouter } from "./gcp-sync-router"; import { registerGcpSyncRouter } from "./gcp-sync-router";
import { registerGitHubSyncRouter } from "./github-sync-router"; import { registerGitHubSyncRouter } from "./github-sync-router";
import { registerGitLabSyncRouter } from "./gitlab-sync-router";
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router"; import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
import { registerHerokuSyncRouter } from "./heroku-sync-router"; import { registerHerokuSyncRouter } from "./heroku-sync-router";
import { registerHumanitecSyncRouter } from "./humanitec-sync-router"; import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
@@ -46,6 +45,5 @@ export const SECRET_SYNC_REGISTER_ROUTER_MAP: Record<SecretSync, (server: Fastif
[SecretSync.Heroku]: registerHerokuSyncRouter, [SecretSync.Heroku]: registerHerokuSyncRouter,
[SecretSync.Render]: registerRenderSyncRouter, [SecretSync.Render]: registerRenderSyncRouter,
[SecretSync.Flyio]: registerFlyioSyncRouter, [SecretSync.Flyio]: registerFlyioSyncRouter,
[SecretSync.GitLab]: registerGitLabSyncRouter,
[SecretSync.CloudflarePages]: registerCloudflarePagesSyncRouter [SecretSync.CloudflarePages]: registerCloudflarePagesSyncRouter
}; };

View File

@@ -22,15 +22,10 @@ import {
import { AzureDevOpsSyncListItemSchema, AzureDevOpsSyncSchema } from "@app/services/secret-sync/azure-devops"; import { AzureDevOpsSyncListItemSchema, AzureDevOpsSyncSchema } from "@app/services/secret-sync/azure-devops";
import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/services/secret-sync/azure-key-vault"; import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/services/secret-sync/azure-key-vault";
import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda"; import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda";
import {
CloudflarePagesSyncListItemSchema,
CloudflarePagesSyncSchema
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks"; import { DatabricksSyncListItemSchema, DatabricksSyncSchema } from "@app/services/secret-sync/databricks";
import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio"; import { FlyioSyncListItemSchema, FlyioSyncSchema } from "@app/services/secret-sync/flyio";
import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp"; import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/gcp";
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github"; import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
import { GitLabSyncListItemSchema, GitLabSyncSchema } from "@app/services/secret-sync/gitlab";
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault"; import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
import { HerokuSyncListItemSchema, HerokuSyncSchema } from "@app/services/secret-sync/heroku"; import { HerokuSyncListItemSchema, HerokuSyncSchema } from "@app/services/secret-sync/heroku";
import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec"; import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec";
@@ -39,6 +34,10 @@ import { TeamCitySyncListItemSchema, TeamCitySyncSchema } from "@app/services/se
import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud"; import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud";
import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel"; import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel";
import { WindmillSyncListItemSchema, WindmillSyncSchema } from "@app/services/secret-sync/windmill"; import { WindmillSyncListItemSchema, WindmillSyncSchema } from "@app/services/secret-sync/windmill";
import {
CloudflarePagesSyncListItemSchema,
CloudflarePagesSyncSchema
} from "@app/services/secret-sync/cloudflare-pages/cloudflare-pages-schema";
const SecretSyncSchema = z.discriminatedUnion("destination", [ const SecretSyncSchema = z.discriminatedUnion("destination", [
AwsParameterStoreSyncSchema, AwsParameterStoreSyncSchema,
@@ -61,7 +60,6 @@ const SecretSyncSchema = z.discriminatedUnion("destination", [
HerokuSyncSchema, HerokuSyncSchema,
RenderSyncSchema, RenderSyncSchema,
FlyioSyncSchema, FlyioSyncSchema,
GitLabSyncSchema,
CloudflarePagesSyncSchema CloudflarePagesSyncSchema
]); ]);
@@ -86,7 +84,6 @@ const SecretSyncOptionsSchema = z.discriminatedUnion("destination", [
HerokuSyncListItemSchema, HerokuSyncListItemSchema,
RenderSyncListItemSchema, RenderSyncListItemSchema,
FlyioSyncListItemSchema, FlyioSyncListItemSchema,
GitLabSyncListItemSchema,
CloudflarePagesSyncListItemSchema CloudflarePagesSyncListItemSchema
]); ]);

View File

@@ -26,7 +26,6 @@ export enum AppConnection {
Heroku = "heroku", Heroku = "heroku",
Render = "render", Render = "render",
Flyio = "flyio", Flyio = "flyio",
GitLab = "gitlab",
Cloudflare = "cloudflare" Cloudflare = "cloudflare"
} }

View File

@@ -51,11 +51,6 @@ import {
validateAzureKeyVaultConnectionCredentials validateAzureKeyVaultConnectionCredentials
} from "./azure-key-vault"; } from "./azure-key-vault";
import { CamundaConnectionMethod, getCamundaConnectionListItem, validateCamundaConnectionCredentials } from "./camunda"; import { CamundaConnectionMethod, getCamundaConnectionListItem, validateCamundaConnectionCredentials } from "./camunda";
import { CloudflareConnectionMethod } from "./cloudflare/cloudflare-connection-enum";
import {
getCloudflareConnectionListItem,
validateCloudflareConnectionCredentials
} from "./cloudflare/cloudflare-connection-fns";
import { import {
DatabricksConnectionMethod, DatabricksConnectionMethod,
getDatabricksConnectionListItem, getDatabricksConnectionListItem,
@@ -69,7 +64,6 @@ import {
GitHubRadarConnectionMethod, GitHubRadarConnectionMethod,
validateGitHubRadarConnectionCredentials validateGitHubRadarConnectionCredentials
} from "./github-radar"; } from "./github-radar";
import { getGitLabConnectionListItem, GitLabConnectionMethod, validateGitLabConnectionCredentials } from "./gitlab";
import { import {
getHCVaultConnectionListItem, getHCVaultConnectionListItem,
HCVaultConnectionMethod, HCVaultConnectionMethod,
@@ -105,6 +99,11 @@ import {
validateWindmillConnectionCredentials, validateWindmillConnectionCredentials,
WindmillConnectionMethod WindmillConnectionMethod
} from "./windmill"; } from "./windmill";
import {
getCloudflareConnectionListItem,
validateCloudflareConnectionCredentials
} from "./cloudflare/cloudflare-connection-fns";
import { CloudflareConnectionMethod } from "./cloudflare/cloudflare-connection-enum";
export const listAppConnectionOptions = () => { export const listAppConnectionOptions = () => {
return [ return [
@@ -135,7 +134,6 @@ export const listAppConnectionOptions = () => {
getHerokuConnectionListItem(), getHerokuConnectionListItem(),
getRenderConnectionListItem(), getRenderConnectionListItem(),
getFlyioConnectionListItem(), getFlyioConnectionListItem(),
getGitLabConnectionListItem(),
getCloudflareConnectionListItem() getCloudflareConnectionListItem()
].sort((a, b) => a.name.localeCompare(b.name)); ].sort((a, b) => a.name.localeCompare(b.name));
}; };
@@ -215,7 +213,6 @@ export const validateAppConnectionCredentials = async (
[AppConnection.Heroku]: validateHerokuConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Heroku]: validateHerokuConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Render]: validateRenderConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Render]: validateRenderConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Flyio]: validateFlyioConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Flyio]: validateFlyioConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.GitLab]: validateGitLabConnectionCredentials as TAppConnectionCredentialsValidator,
[AppConnection.Cloudflare]: validateCloudflareConnectionCredentials as TAppConnectionCredentialsValidator [AppConnection.Cloudflare]: validateCloudflareConnectionCredentials as TAppConnectionCredentialsValidator
}; };
@@ -233,7 +230,6 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
case GitHubConnectionMethod.OAuth: case GitHubConnectionMethod.OAuth:
case AzureDevOpsConnectionMethod.OAuth: case AzureDevOpsConnectionMethod.OAuth:
case HerokuConnectionMethod.OAuth: case HerokuConnectionMethod.OAuth:
case GitLabConnectionMethod.OAuth:
return "OAuth"; return "OAuth";
case HerokuConnectionMethod.AuthToken: case HerokuConnectionMethod.AuthToken:
return "Auth Token"; return "Auth Token";
@@ -331,7 +327,6 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
[AppConnection.Heroku]: platformManagedCredentialsNotSupported, [AppConnection.Heroku]: platformManagedCredentialsNotSupported,
[AppConnection.Render]: platformManagedCredentialsNotSupported, [AppConnection.Render]: platformManagedCredentialsNotSupported,
[AppConnection.Flyio]: platformManagedCredentialsNotSupported, [AppConnection.Flyio]: platformManagedCredentialsNotSupported,
[AppConnection.GitLab]: platformManagedCredentialsNotSupported,
[AppConnection.Cloudflare]: platformManagedCredentialsNotSupported [AppConnection.Cloudflare]: platformManagedCredentialsNotSupported
}; };

View File

@@ -28,7 +28,6 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
[AppConnection.Heroku]: "Heroku", [AppConnection.Heroku]: "Heroku",
[AppConnection.Render]: "Render", [AppConnection.Render]: "Render",
[AppConnection.Flyio]: "Fly.io", [AppConnection.Flyio]: "Fly.io",
[AppConnection.GitLab]: "GitLab",
[AppConnection.Cloudflare]: "Cloudflare" [AppConnection.Cloudflare]: "Cloudflare"
}; };
@@ -60,6 +59,5 @@ export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanTyp
[AppConnection.Heroku]: AppConnectionPlanType.Regular, [AppConnection.Heroku]: AppConnectionPlanType.Regular,
[AppConnection.Render]: AppConnectionPlanType.Regular, [AppConnection.Render]: AppConnectionPlanType.Regular,
[AppConnection.Flyio]: AppConnectionPlanType.Regular, [AppConnection.Flyio]: AppConnectionPlanType.Regular,
[AppConnection.GitLab]: AppConnectionPlanType.Regular,
[AppConnection.Cloudflare]: AppConnectionPlanType.Regular [AppConnection.Cloudflare]: AppConnectionPlanType.Regular
}; };

View File

@@ -58,8 +58,6 @@ import { gcpConnectionService } from "./gcp/gcp-connection-service";
import { ValidateGitHubConnectionCredentialsSchema } from "./github"; import { ValidateGitHubConnectionCredentialsSchema } from "./github";
import { githubConnectionService } from "./github/github-connection-service"; import { githubConnectionService } from "./github/github-connection-service";
import { ValidateGitHubRadarConnectionCredentialsSchema } from "./github-radar"; import { ValidateGitHubRadarConnectionCredentialsSchema } from "./github-radar";
import { ValidateGitLabConnectionCredentialsSchema } from "./gitlab";
import { gitlabConnectionService } from "./gitlab/gitlab-connection-service";
import { ValidateHCVaultConnectionCredentialsSchema } from "./hc-vault"; import { ValidateHCVaultConnectionCredentialsSchema } from "./hc-vault";
import { hcVaultConnectionService } from "./hc-vault/hc-vault-connection-service"; import { hcVaultConnectionService } from "./hc-vault/hc-vault-connection-service";
import { ValidateHerokuConnectionCredentialsSchema } from "./heroku"; import { ValidateHerokuConnectionCredentialsSchema } from "./heroku";
@@ -118,7 +116,6 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
[AppConnection.Heroku]: ValidateHerokuConnectionCredentialsSchema, [AppConnection.Heroku]: ValidateHerokuConnectionCredentialsSchema,
[AppConnection.Render]: ValidateRenderConnectionCredentialsSchema, [AppConnection.Render]: ValidateRenderConnectionCredentialsSchema,
[AppConnection.Flyio]: ValidateFlyioConnectionCredentialsSchema, [AppConnection.Flyio]: ValidateFlyioConnectionCredentialsSchema,
[AppConnection.GitLab]: ValidateGitLabConnectionCredentialsSchema,
[AppConnection.Cloudflare]: ValidateCloudflareConnectionCredentialsSchema [AppConnection.Cloudflare]: ValidateCloudflareConnectionCredentialsSchema
}; };
@@ -527,8 +524,7 @@ export const appConnectionServiceFactory = ({
onepass: onePassConnectionService(connectAppConnectionById), onepass: onePassConnectionService(connectAppConnectionById),
heroku: herokuConnectionService(connectAppConnectionById, appConnectionDAL, kmsService), heroku: herokuConnectionService(connectAppConnectionById, appConnectionDAL, kmsService),
render: renderConnectionService(connectAppConnectionById), render: renderConnectionService(connectAppConnectionById),
flyio: flyioConnectionService(connectAppConnectionById), cloudflare: cloudflareConnectionService(connectAppConnectionById),
gitlab: gitlabConnectionService(connectAppConnectionById, appConnectionDAL, kmsService), flyio: flyioConnectionService(connectAppConnectionById)
cloudflare: cloudflareConnectionService(connectAppConnectionById)
}; };
}; };

View File

@@ -62,12 +62,6 @@ import {
TCamundaConnectionInput, TCamundaConnectionInput,
TValidateCamundaConnectionCredentialsSchema TValidateCamundaConnectionCredentialsSchema
} from "./camunda"; } from "./camunda";
import {
TCloudflareConnection,
TCloudflareConnectionConfig,
TCloudflareConnectionInput,
TValidateCloudflareConnectionCredentialsSchema
} from "./cloudflare/cloudflare-connection-types";
import { import {
TDatabricksConnection, TDatabricksConnection,
TDatabricksConnectionConfig, TDatabricksConnectionConfig,
@@ -98,12 +92,6 @@ import {
TGitHubRadarConnectionInput, TGitHubRadarConnectionInput,
TValidateGitHubRadarConnectionCredentialsSchema TValidateGitHubRadarConnectionCredentialsSchema
} from "./github-radar"; } from "./github-radar";
import {
TGitLabConnection,
TGitLabConnectionConfig,
TGitLabConnectionInput,
TValidateGitLabConnectionCredentialsSchema
} from "./gitlab";
import { import {
THCVaultConnection, THCVaultConnection,
THCVaultConnectionConfig, THCVaultConnectionConfig,
@@ -165,6 +153,12 @@ import {
TWindmillConnectionConfig, TWindmillConnectionConfig,
TWindmillConnectionInput TWindmillConnectionInput
} from "./windmill"; } from "./windmill";
import {
TCloudflareConnection,
TCloudflareConnectionConfig,
TCloudflareConnectionInput,
TValidateCloudflareConnectionCredentialsSchema
} from "./cloudflare/cloudflare-connection-types";
export type TAppConnection = { id: string } & ( export type TAppConnection = { id: string } & (
| TAwsConnection | TAwsConnection
@@ -194,7 +188,6 @@ export type TAppConnection = { id: string } & (
| THerokuConnection | THerokuConnection
| TRenderConnection | TRenderConnection
| TFlyioConnection | TFlyioConnection
| TGitLabConnection
| TCloudflareConnection | TCloudflareConnection
); );
@@ -230,7 +223,6 @@ export type TAppConnectionInput = { id: string } & (
| THerokuConnectionInput | THerokuConnectionInput
| TRenderConnectionInput | TRenderConnectionInput
| TFlyioConnectionInput | TFlyioConnectionInput
| TGitLabConnectionInput
| TCloudflareConnectionInput | TCloudflareConnectionInput
); );
@@ -274,7 +266,6 @@ export type TAppConnectionConfig =
| THerokuConnectionConfig | THerokuConnectionConfig
| TRenderConnectionConfig | TRenderConnectionConfig
| TFlyioConnectionConfig | TFlyioConnectionConfig
| TGitLabConnectionConfig
| TCloudflareConnectionConfig; | TCloudflareConnectionConfig;
export type TValidateAppConnectionCredentialsSchema = export type TValidateAppConnectionCredentialsSchema =
@@ -305,7 +296,6 @@ export type TValidateAppConnectionCredentialsSchema =
| TValidateHerokuConnectionCredentialsSchema | TValidateHerokuConnectionCredentialsSchema
| TValidateRenderConnectionCredentialsSchema | TValidateRenderConnectionCredentialsSchema
| TValidateFlyioConnectionCredentialsSchema | TValidateFlyioConnectionCredentialsSchema
| TValidateGitLabConnectionCredentialsSchema
| TValidateCloudflareConnectionCredentialsSchema; | TValidateCloudflareConnectionCredentialsSchema;
export type TListAwsConnectionKmsKeys = { export type TListAwsConnectionKmsKeys = {

View File

@@ -1,9 +0,0 @@
export enum GitLabConnectionMethod {
OAuth = "oauth",
AccessToken = "access-token"
}
export enum GitLabAccessTokenType {
Project = "project",
Personal = "personal"
}

View File

@@ -1,351 +0,0 @@
/* eslint-disable no-await-in-loop */
import { GitbeakerRequestError, Gitlab } from "@gitbeaker/rest";
import { AxiosError } from "axios";
import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { BadRequestError, InternalServerError } from "@app/lib/errors";
import { removeTrailingSlash } from "@app/lib/fn";
import { logger } from "@app/lib/logger";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { encryptAppConnectionCredentials } from "@app/services/app-connection/app-connection-fns";
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TAppConnectionDALFactory } from "../app-connection-dal";
import { GitLabAccessTokenType, GitLabConnectionMethod } from "./gitlab-connection-enums";
import { TGitLabConnection, TGitLabConnectionConfig, TGitLabGroup, TGitLabProject } from "./gitlab-connection-types";
interface GitLabOAuthTokenResponse {
access_token: string;
token_type: string;
expires_in: number;
refresh_token: string;
created_at: number;
scope?: string;
}
export const getGitLabConnectionListItem = () => {
const { INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID } = getConfig();
return {
name: "GitLab" as const,
app: AppConnection.GitLab as const,
methods: Object.values(GitLabConnectionMethod) as [
GitLabConnectionMethod.AccessToken,
GitLabConnectionMethod.OAuth
],
oauthClientId: INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID
};
};
export const getGitLabInstanceUrl = async (instanceUrl?: string) => {
const gitLabInstanceUrl = instanceUrl ? removeTrailingSlash(instanceUrl) : IntegrationUrls.GITLAB_URL;
await blockLocalAndPrivateIpAddresses(gitLabInstanceUrl);
return gitLabInstanceUrl;
};
export const getGitLabClient = async (accessToken: string, instanceUrl?: string, isOAuth = false) => {
const host = await getGitLabInstanceUrl(instanceUrl);
const client = new Gitlab<true>({
host,
...(isOAuth ? { oauthToken: accessToken } : { token: accessToken }),
camelize: true
});
return client;
};
export const refreshGitLabToken = async (
refreshToken: string,
appId: string,
orgId: string,
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">,
instanceUrl?: string
): Promise<string> => {
const { INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID, INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET, SITE_URL } =
getConfig();
if (!INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET || !INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID || !SITE_URL) {
throw new InternalServerError({
message: `GitLab environment variables have not been configured`
});
}
const payload = new URLSearchParams({
grant_type: "refresh_token",
refresh_token: refreshToken,
client_id: INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID,
client_secret: INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET,
redirect_uri: `${SITE_URL}/organization/app-connections/gitlab/oauth/callback`
});
try {
const url = await getGitLabInstanceUrl(instanceUrl);
const { data } = await request.post<GitLabOAuthTokenResponse>(`${url}/oauth/token`, payload.toString(), {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json"
}
});
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
},
orgId,
kmsService
});
await appConnectionDAL.updateById(appId, { encryptedCredentials });
return data.access_token;
} catch (error: unknown) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to refresh GitLab token: ${error.message}`
});
}
throw new BadRequestError({
message: "Unable to refresh GitLab token"
});
}
};
export const exchangeGitLabOAuthCode = async (
code: string,
instanceUrl?: string
): Promise<GitLabOAuthTokenResponse> => {
const { INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID, INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET, SITE_URL } =
getConfig();
if (!INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET || !INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID || !SITE_URL) {
throw new InternalServerError({
message: `GitLab environment variables have not been configured`
});
}
try {
const payload = new URLSearchParams({
grant_type: "authorization_code",
code,
client_id: INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID,
client_secret: INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET,
redirect_uri: `${SITE_URL}/organization/app-connections/gitlab/oauth/callback`
});
const url = await getGitLabInstanceUrl(instanceUrl);
const response = await request.post<GitLabOAuthTokenResponse>(`${url}/oauth/token`, payload.toString(), {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json"
}
});
if (!response.data) {
throw new InternalServerError({
message: "Failed to exchange OAuth code: Empty response"
});
}
return response.data;
} catch (error: unknown) {
if (error instanceof AxiosError) {
throw new BadRequestError({
message: `Failed to exchange OAuth code: ${error.message}`
});
}
throw new BadRequestError({
message: "Unable to exchange OAuth code"
});
}
};
export const validateGitLabConnectionCredentials = async (config: TGitLabConnectionConfig) => {
const { credentials: inputCredentials, method } = config;
let accessToken: string;
let oauthData: GitLabOAuthTokenResponse | null = null;
if (method === GitLabConnectionMethod.OAuth && "code" in inputCredentials) {
oauthData = await exchangeGitLabOAuthCode(inputCredentials.code, inputCredentials.instanceUrl);
accessToken = oauthData.access_token;
} else if (method === GitLabConnectionMethod.AccessToken && "accessToken" in inputCredentials) {
accessToken = inputCredentials.accessToken;
} else {
throw new BadRequestError({
message: "Invalid credentials for the selected connection method"
});
}
try {
const client = await getGitLabClient(
accessToken,
inputCredentials.instanceUrl,
method === GitLabConnectionMethod.OAuth
);
await client.Users.showCurrentUser();
} catch (error: unknown) {
logger.error(error, "Error validating GitLab connection credentials");
if (error instanceof GitbeakerRequestError) {
throw new BadRequestError({
message: `Failed to validate credentials: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
});
}
throw new BadRequestError({
message: `Failed to validate credentials: ${(error as Error)?.message || "verify credentials"}`
});
}
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,
createdAt: new Date(oauthData.created_at * 1000)
};
}
return inputCredentials;
};
export const listGitLabProjects = async ({
appConnection,
appConnectionDAL,
kmsService
}: {
appConnection: TGitLabConnection;
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
}): Promise<TGitLabProject[]> => {
let { accessToken } = appConnection.credentials;
if (
appConnection.method === GitLabConnectionMethod.OAuth &&
appConnection.credentials.refreshToken &&
new Date(appConnection.credentials.expiresAt) < new Date()
) {
accessToken = await refreshGitLabToken(
appConnection.credentials.refreshToken,
appConnection.id,
appConnection.orgId,
appConnectionDAL,
kmsService,
appConnection.credentials.instanceUrl
);
}
try {
const client = await getGitLabClient(
accessToken,
appConnection.credentials.instanceUrl,
appConnection.method === GitLabConnectionMethod.OAuth
);
const projects = await client.Projects.all({
archived: false,
includePendingDelete: false,
membership: true,
includeHidden: false,
imported: false
});
return projects.map((project) => ({
name: project.pathWithNamespace,
id: project.id.toString()
}));
} catch (error: unknown) {
if (error instanceof GitbeakerRequestError) {
throw new BadRequestError({
message: `Failed to fetch GitLab projects: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
});
}
if (error instanceof InternalServerError) {
throw error;
}
throw new InternalServerError({
message: "Unable to fetch GitLab projects"
});
}
};
export const listGitLabGroups = async ({
appConnection,
appConnectionDAL,
kmsService
}: {
appConnection: TGitLabConnection;
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
}): Promise<TGitLabGroup[]> => {
let { accessToken } = appConnection.credentials;
if (
appConnection.method === GitLabConnectionMethod.AccessToken &&
appConnection.credentials.accessTokenType === GitLabAccessTokenType.Project
) {
return [];
}
if (
appConnection.method === GitLabConnectionMethod.OAuth &&
appConnection.credentials.refreshToken &&
new Date(appConnection.credentials.expiresAt) < new Date()
) {
accessToken = await refreshGitLabToken(
appConnection.credentials.refreshToken,
appConnection.id,
appConnection.orgId,
appConnectionDAL,
kmsService,
appConnection.credentials.instanceUrl
);
}
try {
const client = await getGitLabClient(
accessToken,
appConnection.credentials.instanceUrl,
appConnection.method === GitLabConnectionMethod.OAuth
);
const groups = await client.Groups.all({
orderBy: "name",
sort: "asc",
minAccessLevel: 50
});
return groups.map((group) => ({
id: group.id.toString(),
name: group.name
}));
} catch (error: unknown) {
if (error instanceof GitbeakerRequestError) {
throw new BadRequestError({
message: `Failed to fetch GitLab groups: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
});
}
if (error instanceof InternalServerError) {
throw error;
}
throw new InternalServerError({
message: "Unable to fetch GitLab groups"
});
}
};

View File

@@ -1,138 +0,0 @@
import z from "zod";
import { AppConnections } from "@app/lib/api-docs";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import {
BaseAppConnectionSchema,
GenericCreateAppConnectionFieldsSchema,
GenericUpdateAppConnectionFieldsSchema
} from "@app/services/app-connection/app-connection-schemas";
import { GitLabAccessTokenType, GitLabConnectionMethod } from "./gitlab-connection-enums";
export const GitLabConnectionAccessTokenCredentialsSchema = z.object({
accessToken: z
.string()
.trim()
.min(1, "Access Token required")
.describe(AppConnections.CREDENTIALS.GITLAB.accessToken),
instanceUrl: z
.string()
.trim()
.url("Invalid Instance URL")
.optional()
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl),
accessTokenType: z.nativeEnum(GitLabAccessTokenType).describe(AppConnections.CREDENTIALS.GITLAB.accessTokenType)
});
export const GitLabConnectionOAuthCredentialsSchema = z.object({
code: z.string().trim().min(1, "OAuth code required").describe(AppConnections.CREDENTIALS.GITLAB.code),
instanceUrl: z
.string()
.trim()
.url("Invalid Instance URL")
.optional()
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
});
export const GitLabConnectionOAuthOutputCredentialsSchema = z.object({
accessToken: z.string().trim(),
refreshToken: z.string().trim(),
expiresAt: z.date(),
tokenType: z.string().optional().default("bearer"),
createdAt: z.string().optional(),
instanceUrl: z
.string()
.trim()
.url("Invalid Instance URL")
.optional()
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
});
export const GitLabConnectionRefreshTokenCredentialsSchema = z.object({
refreshToken: z.string().trim().min(1, "Refresh token required"),
instanceUrl: z
.string()
.trim()
.url("Invalid Instance URL")
.optional()
.describe(AppConnections.CREDENTIALS.GITLAB.instanceUrl)
});
const BaseGitLabConnectionSchema = BaseAppConnectionSchema.extend({
app: z.literal(AppConnection.GitLab)
});
export const GitLabConnectionSchema = z.intersection(
BaseGitLabConnectionSchema,
z.discriminatedUnion("method", [
z.object({
method: z.literal(GitLabConnectionMethod.AccessToken),
credentials: GitLabConnectionAccessTokenCredentialsSchema
}),
z.object({
method: z.literal(GitLabConnectionMethod.OAuth),
credentials: GitLabConnectionOAuthOutputCredentialsSchema
})
])
);
export const SanitizedGitLabConnectionSchema = z.discriminatedUnion("method", [
BaseGitLabConnectionSchema.extend({
method: z.literal(GitLabConnectionMethod.AccessToken),
credentials: GitLabConnectionAccessTokenCredentialsSchema.pick({
instanceUrl: true,
accessTokenType: true
})
}),
BaseGitLabConnectionSchema.extend({
method: z.literal(GitLabConnectionMethod.OAuth),
credentials: GitLabConnectionOAuthOutputCredentialsSchema.pick({
instanceUrl: true
})
})
]);
export const ValidateGitLabConnectionCredentialsSchema = z.discriminatedUnion("method", [
z.object({
method: z.literal(GitLabConnectionMethod.AccessToken).describe(AppConnections.CREATE(AppConnection.GitLab).method),
credentials: GitLabConnectionAccessTokenCredentialsSchema.describe(
AppConnections.CREATE(AppConnection.GitLab).credentials
)
}),
z.object({
method: z.literal(GitLabConnectionMethod.OAuth).describe(AppConnections.CREATE(AppConnection.GitLab).method),
credentials: z
.union([
GitLabConnectionOAuthCredentialsSchema,
GitLabConnectionRefreshTokenCredentialsSchema,
GitLabConnectionOAuthOutputCredentialsSchema
])
.describe(AppConnections.CREATE(AppConnection.GitLab).credentials)
})
]);
export const CreateGitLabConnectionSchema = ValidateGitLabConnectionCredentialsSchema.and(
GenericCreateAppConnectionFieldsSchema(AppConnection.GitLab)
);
export const UpdateGitLabConnectionSchema = z
.object({
credentials: z
.union([
GitLabConnectionAccessTokenCredentialsSchema,
GitLabConnectionOAuthOutputCredentialsSchema,
GitLabConnectionRefreshTokenCredentialsSchema,
GitLabConnectionOAuthCredentialsSchema
])
.optional()
.describe(AppConnections.UPDATE(AppConnection.GitLab).credentials)
})
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.GitLab));
export const GitLabConnectionListItemSchema = z.object({
name: z.literal("GitLab"),
app: z.literal(AppConnection.GitLab),
methods: z.nativeEnum(GitLabConnectionMethod).array(),
oauthClientId: z.string().optional()
});

View File

@@ -1,47 +0,0 @@
import { logger } from "@app/lib/logger";
import { OrgServiceActor } from "@app/lib/types";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TAppConnectionDALFactory } from "../app-connection-dal";
import { AppConnection } from "../app-connection-enums";
import { listGitLabGroups, listGitLabProjects } from "./gitlab-connection-fns";
import { TGitLabConnection } from "./gitlab-connection-types";
type TGetAppConnectionFunc = (
app: AppConnection,
connectionId: string,
actor: OrgServiceActor
) => Promise<TGitLabConnection>;
export const gitlabConnectionService = (
getAppConnection: TGetAppConnectionFunc,
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
) => {
const listProjects = async (connectionId: string, actor: OrgServiceActor) => {
try {
const appConnection = await getAppConnection(AppConnection.GitLab, connectionId, actor);
const projects = await listGitLabProjects({ appConnection, appConnectionDAL, kmsService });
return projects;
} catch (error) {
logger.error(error, `Failed to establish connection with GitLab for app ${connectionId}`);
return [];
}
};
const listGroups = async (connectionId: string, actor: OrgServiceActor) => {
try {
const appConnection = await getAppConnection(AppConnection.GitLab, connectionId, actor);
const groups = await listGitLabGroups({ appConnection, appConnectionDAL, kmsService });
return groups;
} catch (error) {
logger.error(error, `Failed to establish connection with GitLab for app ${connectionId}`);
return [];
}
};
return {
listProjects,
listGroups
};
};

View File

@@ -1,56 +0,0 @@
import z from "zod";
import { DiscriminativePick } from "@app/lib/types";
import { AppConnection } from "../app-connection-enums";
import {
CreateGitLabConnectionSchema,
GitLabConnectionSchema,
ValidateGitLabConnectionCredentialsSchema
} from "./gitlab-connection-schemas";
export type TGitLabConnection = z.infer<typeof GitLabConnectionSchema>;
export type TGitLabConnectionInput = z.infer<typeof CreateGitLabConnectionSchema> & {
app: AppConnection.GitLab;
};
export type TValidateGitLabConnectionCredentialsSchema = typeof ValidateGitLabConnectionCredentialsSchema;
export type TGitLabConnectionConfig = DiscriminativePick<TGitLabConnectionInput, "method" | "app" | "credentials"> & {
orgId: string;
};
export type TGitLabProject = {
name: string;
id: string;
};
export type TGitLabAccessTokenCredentials = {
accessToken: string;
instanceUrl: string;
};
export type TGitLabOAuthCredentials = {
accessToken: string;
refreshToken: string;
expiresAt: Date;
tokenType?: string;
createdAt?: Date;
instanceUrl: string;
};
export type TGitLabOAuthCodeCredentials = {
code: string;
instanceUrl: string;
};
export type TGitLabRefreshTokenCredentials = {
refreshToken: string;
instanceUrl: string;
};
export interface TGitLabGroup {
id: string;
name: string;
}

View File

@@ -1,4 +0,0 @@
export * from "./gitlab-connection-enums";
export * from "./gitlab-connection-fns";
export * from "./gitlab-connection-schemas";
export * from "./gitlab-connection-types";

View File

@@ -1,10 +0,0 @@
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import { TSecretSyncListItem } from "@app/services/secret-sync/secret-sync-types";
export const GITLAB_SYNC_LIST_OPTION: TSecretSyncListItem = {
name: "GitLab",
destination: SecretSync.GitLab,
connection: AppConnection.GitLab,
canImportSecrets: false
};

View File

@@ -1,4 +0,0 @@
export enum GitLabSyncScope {
Project = "project",
Group = "group"
}

View File

@@ -1,452 +0,0 @@
/* eslint-disable no-await-in-loop */
import { GitbeakerRequestError } from "@gitbeaker/rest";
import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
import {
getGitLabClient,
GitLabConnectionMethod,
refreshGitLabToken,
TGitLabConnection
} from "@app/services/app-connection/gitlab";
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
import { TGitLabSyncWithCredentials, TGitLabVariable } from "@app/services/secret-sync/gitlab/gitlab-sync-types";
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
import { GitLabSyncScope } from "./gitlab-sync-enums";
interface TGitLabVariablePayload {
key?: string;
value: string;
variable_type?: "env_var" | "file";
environment_scope?: string;
protected?: boolean;
masked?: boolean;
masked_and_hidden?: boolean;
description?: string;
}
interface TGitLabVariableCreate extends TGitLabVariablePayload {
key: string;
}
interface TGitLabVariableUpdate extends Omit<TGitLabVariablePayload, "key"> {}
type TGitLabSyncFactoryDeps = {
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">;
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
};
const getValidAccessToken = async (
connection: TGitLabConnection,
appConnectionDAL: Pick<TAppConnectionDALFactory, "updateById">,
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">
): Promise<string> => {
if (
connection.method === GitLabConnectionMethod.OAuth &&
connection.credentials.refreshToken &&
new Date(connection.credentials.expiresAt) < new Date()
) {
const accessToken = await refreshGitLabToken(
connection.credentials.refreshToken,
connection.id,
connection.orgId,
appConnectionDAL,
kmsService,
connection.credentials.instanceUrl
);
return accessToken;
}
return connection.credentials.accessToken;
};
const getGitLabVariables = async ({
accessToken,
connection,
scope,
resourceId,
targetEnvironment
}: {
accessToken: string;
connection: TGitLabConnection;
scope: GitLabSyncScope;
resourceId: string;
targetEnvironment?: string;
}): Promise<TGitLabVariable[]> => {
try {
const client = await getGitLabClient(
accessToken,
connection.credentials.instanceUrl,
connection.method === GitLabConnectionMethod.OAuth
);
let variables: TGitLabVariable[] = [];
if (scope === GitLabSyncScope.Project) {
variables = await client.ProjectVariables.all(resourceId);
} else {
variables = await client.GroupVariables.all(resourceId);
}
if (targetEnvironment) {
variables = variables.filter((v) => v.environmentScope === targetEnvironment);
}
return variables;
} catch (error) {
if (error instanceof GitbeakerRequestError) {
throw new SecretSyncError({
error: new Error(
`Failed to fetch variables: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
)
});
}
throw new SecretSyncError({
error
});
}
};
const createGitLabVariable = async ({
accessToken,
connection,
scope,
resourceId,
variable
}: {
accessToken: string;
connection: TGitLabConnection;
scope: GitLabSyncScope;
resourceId: string;
variable: TGitLabVariableCreate;
}): Promise<void> => {
try {
const client = await getGitLabClient(
accessToken,
connection.credentials.instanceUrl,
connection.method === GitLabConnectionMethod.OAuth
);
const payload = {
key: variable.key,
value: variable.value,
variableType: "env_var",
environmentScope: variable.environment_scope || "*",
protected: variable.protected || false,
masked: variable.masked || false,
masked_and_hidden: variable.masked_and_hidden || false,
raw: false
};
if (scope === GitLabSyncScope.Project) {
await client.ProjectVariables.create(resourceId, payload.key, payload.value, {
variableType: "env_var",
environmentScope: payload.environmentScope,
protected: payload.protected,
masked: payload.masked,
masked_and_hidden: payload.masked_and_hidden,
raw: false
});
} else {
await client.GroupVariables.create(resourceId, payload.key, payload.value, {
variableType: "env_var",
environmentScope: payload.environmentScope,
protected: payload.protected,
masked: payload.masked,
...(payload.masked_and_hidden && { masked_and_hidden: payload.masked_and_hidden }),
raw: false
});
}
} catch (error) {
if (error instanceof GitbeakerRequestError) {
throw new SecretSyncError({
error: new Error(
`Failed to create variable: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
),
secretKey: variable.key
});
}
throw new SecretSyncError({
error,
secretKey: variable.key
});
}
};
const updateGitLabVariable = async ({
accessToken,
connection,
scope,
resourceId,
key,
variable,
targetEnvironment
}: {
accessToken: string;
connection: TGitLabConnection;
scope: GitLabSyncScope;
resourceId: string;
key: string;
variable: TGitLabVariableUpdate;
targetEnvironment?: string;
}): Promise<void> => {
try {
const client = await getGitLabClient(
accessToken,
connection.credentials.instanceUrl,
connection.method === GitLabConnectionMethod.OAuth
);
const options = {
...(variable.environment_scope && { environmentScope: variable.environment_scope }),
...(variable.protected !== undefined && { protected: variable.protected }),
...(variable.masked !== undefined && { masked: variable.masked })
};
if (targetEnvironment) {
options.environmentScope = targetEnvironment;
}
if (scope === GitLabSyncScope.Project) {
await client.ProjectVariables.edit(resourceId, key, variable.value, {
...options,
filter: { environment_scope: targetEnvironment || "*" }
});
} else {
await client.GroupVariables.edit(resourceId, key, variable.value, {
...options,
filter: { environment_scope: targetEnvironment || "*" }
});
}
} catch (error) {
if (error instanceof GitbeakerRequestError) {
throw new SecretSyncError({
error: new Error(
`Failed to update variable: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
),
secretKey: key
});
}
throw new SecretSyncError({
error,
secretKey: key
});
}
};
const deleteGitLabVariable = async ({
accessToken,
connection,
scope,
resourceId,
key,
targetEnvironment,
allVariables
}: {
accessToken: string;
connection: TGitLabConnection;
scope: GitLabSyncScope;
resourceId: string;
key: string;
targetEnvironment?: string;
allVariables?: TGitLabVariable[];
}): Promise<void> => {
if (allVariables && !allVariables.find((v) => v.key === key)) {
return;
}
try {
const client = await getGitLabClient(
accessToken,
connection.credentials.instanceUrl,
connection.method === GitLabConnectionMethod.OAuth
);
const options: { filter?: { environment_scope: string } } = {};
if (targetEnvironment) {
options.filter = { environment_scope: targetEnvironment || "*" };
}
if (scope === GitLabSyncScope.Project) {
await client.ProjectVariables.remove(resourceId, key, options);
} else {
await client.GroupVariables.remove(resourceId, key);
}
} catch (error: unknown) {
if (error instanceof GitbeakerRequestError) {
throw new SecretSyncError({
error: new Error(
`Failed to delete variable: ${error.message ?? "Unknown error"}${error.cause?.description && error.message !== "Unauthorized" ? `. Cause: ${error.cause.description}` : ""}`
),
secretKey: key
});
}
throw new SecretSyncError({
error,
secretKey: key
});
}
};
export const GitLabSyncFns = {
syncSecrets: async (
secretSync: TGitLabSyncWithCredentials,
secretMap: TSecretMap,
{ appConnectionDAL, kmsService }: TGitLabSyncFactoryDeps
): Promise<void> => {
const { connection, environment, destinationConfig } = secretSync;
const { scope, targetEnvironment } = destinationConfig;
const resourceId = scope === GitLabSyncScope.Project ? destinationConfig.projectId : destinationConfig.groupId;
const accessToken = await getValidAccessToken(connection, appConnectionDAL, kmsService);
try {
const currentVariables = await getGitLabVariables({
accessToken,
connection,
scope,
resourceId,
targetEnvironment
});
const currentVariableMap = new Map(currentVariables.map((v) => [v.key, v]));
for (const [key, { value }] of Object.entries(secretMap)) {
if (value?.length < 8 && destinationConfig.shouldMaskSecrets) {
throw new SecretSyncError({
message: `Secret ${key} is too short to be masked. GitLab requires a minimum of 8 characters for masked secrets.`,
secretKey: key
});
}
try {
const existingVariable = currentVariableMap.get(key);
if (existingVariable) {
if (
existingVariable.value !== value ||
existingVariable.environmentScope !== targetEnvironment ||
existingVariable.protected !== destinationConfig.shouldProtectSecrets ||
existingVariable.masked !== destinationConfig.shouldMaskSecrets
) {
await updateGitLabVariable({
accessToken,
connection,
scope,
resourceId,
key,
variable: {
value,
environment_scope: targetEnvironment,
protected: destinationConfig.shouldProtectSecrets,
masked: destinationConfig.shouldMaskSecrets || existingVariable.hidden
},
targetEnvironment
});
}
} else {
await createGitLabVariable({
accessToken,
connection,
scope,
resourceId,
variable: {
key,
value,
variable_type: "env_var",
environment_scope: targetEnvironment || "*",
protected: destinationConfig.shouldProtectSecrets || false,
masked: destinationConfig.shouldMaskSecrets || false,
masked_and_hidden: destinationConfig.shouldHideSecrets || false
}
});
}
} catch (error) {
throw new SecretSyncError({
error,
secretKey: key
});
}
}
if (!secretSync.syncOptions.disableSecretDeletion) {
for (const variable of currentVariables) {
try {
const shouldDelete =
matchesSchema(variable.key, environment?.slug || "", secretSync.syncOptions.keySchema) &&
!(variable.key in secretMap);
if (shouldDelete) {
await deleteGitLabVariable({
accessToken,
connection,
scope,
resourceId,
key: variable.key,
targetEnvironment
});
}
} catch (error) {
throw new SecretSyncError({
error,
secretKey: variable.key
});
}
}
}
} catch (error) {
if (error instanceof SecretSyncError) {
throw error;
}
throw new SecretSyncError({
message: "Failed to sync secrets",
error
});
}
},
removeSecrets: async (
secretSync: TGitLabSyncWithCredentials,
secretMap: TSecretMap,
{ appConnectionDAL, kmsService }: TGitLabSyncFactoryDeps
): Promise<void> => {
const { connection, destinationConfig } = secretSync;
const { scope, targetEnvironment } = destinationConfig;
const resourceId = scope === GitLabSyncScope.Project ? destinationConfig.projectId : destinationConfig.groupId;
const accessToken = await getValidAccessToken(connection, appConnectionDAL, kmsService);
const allVariables = await getGitLabVariables({
accessToken,
connection,
scope,
resourceId,
targetEnvironment
});
for (const key of Object.keys(secretMap)) {
try {
await deleteGitLabVariable({
accessToken,
connection,
scope,
resourceId,
key,
targetEnvironment,
allVariables
});
} catch (error) {
throw new SecretSyncError({
error,
secretKey: key
});
}
}
},
getSecrets: async (secretSync: TGitLabSyncWithCredentials): Promise<TSecretMap> => {
throw new Error(`${SECRET_SYNC_NAME_MAP[secretSync.destination]} does not support importing secrets.`);
}
};

View File

@@ -1,97 +0,0 @@
import { z } from "zod";
import { SecretSyncs } from "@app/lib/api-docs";
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import {
BaseSecretSyncSchema,
GenericCreateSecretSyncFieldsSchema,
GenericUpdateSecretSyncFieldsSchema
} from "@app/services/secret-sync/secret-sync-schemas";
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
import { GitLabSyncScope } from "./gitlab-sync-enums";
const GitLabSyncDestinationConfigSchema = z.discriminatedUnion("scope", [
z.object({
scope: z.literal(GitLabSyncScope.Project).describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.scope),
projectId: z.string().min(1, "Project ID is required").describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.projectId),
projectName: z
.string()
.min(1, "Project name is required")
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.projectName),
targetEnvironment: z
.string()
.optional()
.default("*")
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.targetEnvironment),
shouldProtectSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldProtectSecrets),
shouldMaskSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldMaskSecrets),
shouldHideSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldHideSecrets)
}),
z.object({
scope: z.literal(GitLabSyncScope.Group).describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.scope),
groupId: z.string().min(1, "Group ID is required").describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.groupId),
groupName: z.string().min(1, "Group name is required").describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.groupName),
targetEnvironment: z
.string()
.optional()
.default("*")
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.targetEnvironment),
shouldProtectSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldProtectSecrets),
shouldMaskSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldMaskSecrets),
shouldHideSecrets: z
.boolean()
.optional()
.default(false)
.describe(SecretSyncs.DESTINATION_CONFIG.GITLAB.shouldHideSecrets)
})
]);
const GitLabSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: false };
export const GitLabSyncSchema = BaseSecretSyncSchema(SecretSync.GitLab, GitLabSyncOptionsConfig).extend({
destination: z.literal(SecretSync.GitLab),
destinationConfig: GitLabSyncDestinationConfigSchema
});
export const CreateGitLabSyncSchema = GenericCreateSecretSyncFieldsSchema(
SecretSync.GitLab,
GitLabSyncOptionsConfig
).extend({
destinationConfig: GitLabSyncDestinationConfigSchema
});
export const UpdateGitLabSyncSchema = GenericUpdateSecretSyncFieldsSchema(
SecretSync.GitLab,
GitLabSyncOptionsConfig
).extend({
destinationConfig: GitLabSyncDestinationConfigSchema.optional()
});
export const GitLabSyncListItemSchema = z.object({
name: z.literal("GitLab"),
connection: z.literal(AppConnection.GitLab),
destination: z.literal(SecretSync.GitLab),
canImportSecrets: z.literal(false)
});

View File

@@ -1,58 +0,0 @@
import { z } from "zod";
import { TGitLabConnection } from "@app/services/app-connection/gitlab";
import { CreateGitLabSyncSchema, GitLabSyncListItemSchema, GitLabSyncSchema } from "./gitlab-sync-schemas";
export type TGitLabSync = z.infer<typeof GitLabSyncSchema>;
export type TGitLabSyncInput = z.infer<typeof CreateGitLabSyncSchema>;
export type TGitLabSyncListItem = z.infer<typeof GitLabSyncListItemSchema>;
export type TGitLabSyncWithCredentials = TGitLabSync & {
connection: TGitLabConnection;
};
export type TGitLabVariable = {
key: string;
value: string;
protected: boolean;
masked: boolean;
environmentScope?: string;
hidden?: boolean;
};
export type TGitLabVariableCreate = {
key: string;
value: string;
variable_type?: "env_var" | "file";
protected?: boolean;
masked?: boolean;
raw?: boolean;
environment_scope?: string;
description?: string;
};
export type TGitLabVariableUpdate = {
value: string;
variable_type?: "env_var" | "file";
protected?: boolean;
masked?: boolean;
raw?: boolean;
environment_scope?: string;
description?: string | null;
};
export type TGitLabListVariables = {
accessToken: string;
projectId: string;
environmentScope?: string;
};
export type TGitLabCreateVariable = TGitLabListVariables & {
variable: TGitLabVariableCreate;
};
export type TGitLabUpdateVariable = TGitLabListVariables & {
key: string;
variable: TGitLabVariableUpdate;
};

View File

@@ -1,4 +0,0 @@
export * from "./gitlab-sync-constants";
export * from "./gitlab-sync-fns";
export * from "./gitlab-sync-schemas";
export * from "./gitlab-sync-types";

View File

@@ -19,7 +19,6 @@ export enum SecretSync {
Heroku = "heroku", Heroku = "heroku",
Render = "render", Render = "render",
Flyio = "flyio", Flyio = "flyio",
GitLab = "gitlab",
CloudflarePages = "cloudflare-pages" CloudflarePages = "cloudflare-pages"
} }

View File

@@ -34,7 +34,6 @@ import { CloudflarePagesSyncFns } from "./cloudflare-pages/cloudflare-pages-fns"
import { FLYIO_SYNC_LIST_OPTION, FlyioSyncFns } from "./flyio"; import { FLYIO_SYNC_LIST_OPTION, FlyioSyncFns } from "./flyio";
import { GCP_SYNC_LIST_OPTION } from "./gcp"; import { GCP_SYNC_LIST_OPTION } from "./gcp";
import { GcpSyncFns } from "./gcp/gcp-sync-fns"; import { GcpSyncFns } from "./gcp/gcp-sync-fns";
import { GITLAB_SYNC_LIST_OPTION, GitLabSyncFns } from "./gitlab";
import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault"; import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault";
import { HEROKU_SYNC_LIST_OPTION, HerokuSyncFns } from "./heroku"; import { HEROKU_SYNC_LIST_OPTION, HerokuSyncFns } from "./heroku";
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec"; import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
@@ -67,7 +66,6 @@ const SECRET_SYNC_LIST_OPTIONS: Record<SecretSync, TSecretSyncListItem> = {
[SecretSync.Heroku]: HEROKU_SYNC_LIST_OPTION, [SecretSync.Heroku]: HEROKU_SYNC_LIST_OPTION,
[SecretSync.Render]: RENDER_SYNC_LIST_OPTION, [SecretSync.Render]: RENDER_SYNC_LIST_OPTION,
[SecretSync.Flyio]: FLYIO_SYNC_LIST_OPTION, [SecretSync.Flyio]: FLYIO_SYNC_LIST_OPTION,
[SecretSync.GitLab]: GITLAB_SYNC_LIST_OPTION,
[SecretSync.CloudflarePages]: CLOUDFLARE_PAGES_SYNC_LIST_OPTION [SecretSync.CloudflarePages]: CLOUDFLARE_PAGES_SYNC_LIST_OPTION
}; };
@@ -232,8 +230,6 @@ export const SecretSyncFns = {
return RenderSyncFns.syncSecrets(secretSync, schemaSecretMap); return RenderSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Flyio: case SecretSync.Flyio:
return FlyioSyncFns.syncSecrets(secretSync, schemaSecretMap); return FlyioSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.GitLab:
return GitLabSyncFns.syncSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService });
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return CloudflarePagesSyncFns.syncSecrets(secretSync, schemaSecretMap); return CloudflarePagesSyncFns.syncSecrets(secretSync, schemaSecretMap);
default: default:
@@ -322,9 +318,6 @@ export const SecretSyncFns = {
case SecretSync.Flyio: case SecretSync.Flyio:
secretMap = await FlyioSyncFns.getSecrets(secretSync); secretMap = await FlyioSyncFns.getSecrets(secretSync);
break; break;
case SecretSync.GitLab:
secretMap = await GitLabSyncFns.getSecrets(secretSync);
break;
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
secretMap = await CloudflarePagesSyncFns.getSecrets(secretSync); secretMap = await CloudflarePagesSyncFns.getSecrets(secretSync);
break; break;
@@ -401,8 +394,6 @@ export const SecretSyncFns = {
return RenderSyncFns.removeSecrets(secretSync, schemaSecretMap); return RenderSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Flyio: case SecretSync.Flyio:
return FlyioSyncFns.removeSecrets(secretSync, schemaSecretMap); return FlyioSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.GitLab:
return GitLabSyncFns.removeSecrets(secretSync, schemaSecretMap, { appConnectionDAL, kmsService });
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return CloudflarePagesSyncFns.removeSecrets(secretSync, schemaSecretMap); return CloudflarePagesSyncFns.removeSecrets(secretSync, schemaSecretMap);
default: default:

View File

@@ -22,7 +22,6 @@ export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
[SecretSync.Heroku]: "Heroku", [SecretSync.Heroku]: "Heroku",
[SecretSync.Render]: "Render", [SecretSync.Render]: "Render",
[SecretSync.Flyio]: "Fly.io", [SecretSync.Flyio]: "Fly.io",
[SecretSync.GitLab]: "GitLab",
[SecretSync.CloudflarePages]: "Cloudflare Pages" [SecretSync.CloudflarePages]: "Cloudflare Pages"
}; };
@@ -47,7 +46,6 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.Heroku]: AppConnection.Heroku, [SecretSync.Heroku]: AppConnection.Heroku,
[SecretSync.Render]: AppConnection.Render, [SecretSync.Render]: AppConnection.Render,
[SecretSync.Flyio]: AppConnection.Flyio, [SecretSync.Flyio]: AppConnection.Flyio,
[SecretSync.GitLab]: AppConnection.GitLab,
[SecretSync.CloudflarePages]: AppConnection.Cloudflare [SecretSync.CloudflarePages]: AppConnection.Cloudflare
}; };
@@ -72,6 +70,5 @@ export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
[SecretSync.Heroku]: SecretSyncPlanType.Regular, [SecretSync.Heroku]: SecretSyncPlanType.Regular,
[SecretSync.Render]: SecretSyncPlanType.Regular, [SecretSync.Render]: SecretSyncPlanType.Regular,
[SecretSync.Flyio]: SecretSyncPlanType.Regular, [SecretSync.Flyio]: SecretSyncPlanType.Regular,
[SecretSync.GitLab]: SecretSyncPlanType.Regular,
[SecretSync.CloudflarePages]: SecretSyncPlanType.Regular [SecretSync.CloudflarePages]: SecretSyncPlanType.Regular
}; };

View File

@@ -72,15 +72,8 @@ import {
TAzureKeyVaultSyncListItem, TAzureKeyVaultSyncListItem,
TAzureKeyVaultSyncWithCredentials TAzureKeyVaultSyncWithCredentials
} from "./azure-key-vault"; } from "./azure-key-vault";
import {
TCloudflarePagesSync,
TCloudflarePagesSyncInput,
TCloudflarePagesSyncListItem,
TCloudflarePagesSyncWithCredentials
} from "./cloudflare-pages/cloudflare-pages-types";
import { TFlyioSync, TFlyioSyncInput, TFlyioSyncListItem, TFlyioSyncWithCredentials } from "./flyio/flyio-sync-types"; import { TFlyioSync, TFlyioSyncInput, TFlyioSyncListItem, TFlyioSyncWithCredentials } from "./flyio/flyio-sync-types";
import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp"; import { TGcpSync, TGcpSyncInput, TGcpSyncListItem, TGcpSyncWithCredentials } from "./gcp";
import { TGitLabSync, TGitLabSyncInput, TGitLabSyncListItem, TGitLabSyncWithCredentials } from "./gitlab";
import { import {
THCVaultSync, THCVaultSync,
THCVaultSyncInput, THCVaultSyncInput,
@@ -113,6 +106,12 @@ import {
TTerraformCloudSyncWithCredentials TTerraformCloudSyncWithCredentials
} from "./terraform-cloud"; } from "./terraform-cloud";
import { TVercelSync, TVercelSyncInput, TVercelSyncListItem, TVercelSyncWithCredentials } from "./vercel"; import { TVercelSync, TVercelSyncInput, TVercelSyncListItem, TVercelSyncWithCredentials } from "./vercel";
import {
TCloudflarePagesSync,
TCloudflarePagesSyncInput,
TCloudflarePagesSyncListItem,
TCloudflarePagesSyncWithCredentials
} from "./cloudflare-pages/cloudflare-pages-types";
export type TSecretSync = export type TSecretSync =
| TAwsParameterStoreSync | TAwsParameterStoreSync
@@ -135,7 +134,6 @@ export type TSecretSync =
| THerokuSync | THerokuSync
| TRenderSync | TRenderSync
| TFlyioSync | TFlyioSync
| TGitLabSync
| TCloudflarePagesSync; | TCloudflarePagesSync;
export type TSecretSyncWithCredentials = export type TSecretSyncWithCredentials =
@@ -159,7 +157,6 @@ export type TSecretSyncWithCredentials =
| THerokuSyncWithCredentials | THerokuSyncWithCredentials
| TRenderSyncWithCredentials | TRenderSyncWithCredentials
| TFlyioSyncWithCredentials | TFlyioSyncWithCredentials
| TGitLabSyncWithCredentials
| TCloudflarePagesSyncWithCredentials; | TCloudflarePagesSyncWithCredentials;
export type TSecretSyncInput = export type TSecretSyncInput =
@@ -183,7 +180,6 @@ export type TSecretSyncInput =
| THerokuSyncInput | THerokuSyncInput
| TRenderSyncInput | TRenderSyncInput
| TFlyioSyncInput | TFlyioSyncInput
| TGitLabSyncInput
| TCloudflarePagesSyncInput; | TCloudflarePagesSyncInput;
export type TSecretSyncListItem = export type TSecretSyncListItem =
@@ -207,7 +203,6 @@ export type TSecretSyncListItem =
| THerokuSyncListItem | THerokuSyncListItem
| TRenderSyncListItem | TRenderSyncListItem
| TFlyioSyncListItem | TFlyioSyncListItem
| TGitLabSyncListItem
| TCloudflarePagesSyncListItem; | TCloudflarePagesSyncListItem;
export type TSyncOptionsConfig = { export type TSyncOptionsConfig = {

View File

@@ -1,4 +0,0 @@
---
title: "Available"
openapi: "GET /api/v1/app-connections/gitlab/available"
---

View File

@@ -1,10 +0,0 @@
---
title: "Create"
openapi: "POST /api/v1/app-connections/gitlab"
---
<Note>
Gitlab OAuth Connections must be created through the Infisical UI.
Check out the configuration docs for [Gitlab OAuth Connections](/integrations/app-connections/gitlab) for a step-by-step
guide.
</Note>

View File

@@ -1,4 +0,0 @@
---
title: "Delete"
openapi: "DELETE /api/v1/app-connections/gitlab/{connectionId}"
---

View File

@@ -1,4 +0,0 @@
---
title: "Get by ID"
openapi: "GET /api/v1/app-connections/gitlab/{connectionId}"
---

View File

@@ -1,4 +0,0 @@
---
title: "Get by Name"
openapi: "GET /api/v1/app-connections/gitlab/connection-name/{connectionName}"
---

View File

@@ -1,4 +0,0 @@
---
title: "List"
openapi: "GET /api/v1/app-connections/gitlab"
---

View File

@@ -1,10 +0,0 @@
---
title: "Update"
openapi: "PATCH /api/v1/app-connections/gitlab/{connectionId}"
---
<Note>
Gitlab OAuth Connections must be updated through the Infisical UI.
Check out the configuration docs for [Gitlab OAuth Connections](/integrations/app-connections/gitlab) for a step-by-step
guide.
</Note>

View File

@@ -1,4 +0,0 @@
---
title: "Create"
openapi: "POST /api/v1/secret-syncs/gitlab"
---

View File

@@ -1,4 +0,0 @@
---
title: "Delete"
openapi: "DELETE /api/v1/secret-syncs/gitlab/{syncId}"
---

View File

@@ -1,4 +0,0 @@
---
title: "Get by ID"
openapi: "GET /api/v1/secret-syncs/gitlab/{syncId}"
---

View File

@@ -1,4 +0,0 @@
---
title: "Get by Name"
openapi: "GET /api/v1/secret-syncs/gitlab/sync-name/{syncName}"
---

View File

@@ -1,4 +0,0 @@
---
title: "List"
openapi: "GET /api/v1/secret-syncs/gitlab"
---

View File

@@ -1,4 +0,0 @@
---
title: "Remove Secrets"
openapi: "POST /api/v1/secret-syncs/gitlab/{syncId}/remove-secrets"
---

View File

@@ -1,4 +0,0 @@
---
title: "Sync Secrets"
openapi: "POST /api/v1/secret-syncs/gitlab/{syncId}/sync-secrets"
---

View File

@@ -1,4 +0,0 @@
---
title: "Update"
openapi: "PATCH /api/v1/secret-syncs/gitlab/{syncId}"
---

View File

@@ -475,7 +475,6 @@
"integrations/app-connections/gcp", "integrations/app-connections/gcp",
"integrations/app-connections/github", "integrations/app-connections/github",
"integrations/app-connections/github-radar", "integrations/app-connections/github-radar",
"integrations/app-connections/gitlab",
"integrations/app-connections/hashicorp-vault", "integrations/app-connections/hashicorp-vault",
"integrations/app-connections/heroku", "integrations/app-connections/heroku",
"integrations/app-connections/humanitec", "integrations/app-connections/humanitec",
@@ -513,7 +512,6 @@
"integrations/secret-syncs/flyio", "integrations/secret-syncs/flyio",
"integrations/secret-syncs/gcp-secret-manager", "integrations/secret-syncs/gcp-secret-manager",
"integrations/secret-syncs/github", "integrations/secret-syncs/github",
"integrations/secret-syncs/gitlab",
"integrations/secret-syncs/hashicorp-vault", "integrations/secret-syncs/hashicorp-vault",
"integrations/secret-syncs/heroku", "integrations/secret-syncs/heroku",
"integrations/secret-syncs/humanitec", "integrations/secret-syncs/humanitec",
@@ -1319,18 +1317,6 @@
"api-reference/endpoints/app-connections/github/delete" "api-reference/endpoints/app-connections/github/delete"
] ]
}, },
{
"group": "GitLab",
"pages": [
"api-reference/endpoints/app-connections/gitlab/list",
"api-reference/endpoints/app-connections/gitlab/available",
"api-reference/endpoints/app-connections/gitlab/get-by-id",
"api-reference/endpoints/app-connections/gitlab/get-by-name",
"api-reference/endpoints/app-connections/gitlab/create",
"api-reference/endpoints/app-connections/gitlab/update",
"api-reference/endpoints/app-connections/gitlab/delete"
]
},
{ {
"group": "GitHub Radar", "group": "GitHub Radar",
"pages": [ "pages": [
@@ -1681,19 +1667,6 @@
"api-reference/endpoints/secret-syncs/github/remove-secrets" "api-reference/endpoints/secret-syncs/github/remove-secrets"
] ]
}, },
{
"group": "GitLab",
"pages": [
"api-reference/endpoints/secret-syncs/gitlab/list",
"api-reference/endpoints/secret-syncs/gitlab/get-by-id",
"api-reference/endpoints/secret-syncs/gitlab/get-by-name",
"api-reference/endpoints/secret-syncs/gitlab/create",
"api-reference/endpoints/secret-syncs/gitlab/update",
"api-reference/endpoints/secret-syncs/gitlab/delete",
"api-reference/endpoints/secret-syncs/gitlab/sync-secrets",
"api-reference/endpoints/secret-syncs/gitlab/remove-secrets"
]
},
{ {
"group": "Hashicorp Vault", "group": "Hashicorp Vault",
"pages": [ "pages": [

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 759 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

After

Width:  |  Height:  |  Size: 497 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 KiB

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 531 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 480 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 946 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 636 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 618 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 569 KiB

View File

@@ -1,192 +0,0 @@
---
title: "GitLab Connection"
description: "Learn how to configure a GitLab Connection for Infisical using OAuth or Access Token methods."
---
Infisical supports two methods for connecting to GitLab: **OAuth** and **Access Token**. Choose the method that best fits your setup and security requirements.
<Tabs>
<Tab title="OAuth Method">
The OAuth method provides secure authentication through GitLab's OAuth flow.
<Accordion title="Self-Hosted Instance Setup">
Using the GitLab Connection with OAuth on a self-hosted instance of Infisical requires configuring an OAuth application in GitLab and registering your instance with it.
**Prerequisites:**
- A GitLab account with existing projects
- Self-hosted Infisical instance
<Steps>
<Step title="Create an OAuth application in GitLab">
Navigate to your user Settings > Applications to create a new GitLab application.
![GitLab Dashboard](/images/app-connections/gitlab/gitlab-dashboard.png)
![GitLab Applications Settings](/images/app-connections/gitlab/gitlab-applications.png)
Create the application. As part of the form, set the **Redirect URI** to `https://your-domain.com/organization/app-connections/gitlab/oauth/callback`.
![GitLab New Application Form](/images/app-connections/gitlab/gitlab-create-application-top.png)
![GitLab New Application Form](/images/app-connections/gitlab/gitlab-create-application-bottom.png)
<Tip>
The domain you defined in the Redirect URI should be equivalent to the `SITE_URL` configured in your Infisical instance.
</Tip>
<Note>
If you have a GitLab group, you can create an OAuth application under it in your group Settings > Applications.
</Note>
</Step>
<Step title="Add your GitLab OAuth application credentials to Infisical">
Obtain the **Application ID** and **Secret** for your GitLab OAuth application.
![GitLab Application Credentials](/images/app-connections/gitlab/gitlab-config-credentials.png)
Back in your Infisical instance, add two new environment variables for the credentials of your GitLab OAuth application:
- `INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID`: The **Application ID** of your GitLab OAuth application.
- `INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET`: The **Secret** of your GitLab OAuth application.
Once added, restart your Infisical instance and use the GitLab Connection.
</Step>
</Steps>
</Accordion>
## Setup GitLab OAuth Connection in Infisical
<Steps>
<Step title="Navigate to App Connections">
Navigate to the **App Connections** tab on the **Organization Settings** page.
![App Connections Tab](/images/app-connections/general/add-connection.png)
</Step>
<Step title="Add Connection">
Select the **GitLab Connection** option from the connection options modal.
![Select GitLab Connection](/images/app-connections/gitlab/select-gitlab-connection.png)
</Step>
<Step title="Choose OAuth Method">
Select the **OAuth** method and click **Connect to GitLab**.
![Connect via GitLab OAuth](/images/app-connections/gitlab/create-gitlab-oauth-connection.png)
</Step>
<Step title="Grant Access">
You will be redirected to GitLab to grant Infisical access to your GitLab account. Once granted, you will be redirected back to Infisical's App Connections page.
![GitLab Authorization](/images/app-connections/gitlab/gitlab-authorization-page.png)
</Step>
<Step title="Connection Created">
Your **GitLab Connection** is now available for use.
![GitLab OAuth Connection](/images/app-connections/gitlab/gitlab-oauth-connection.png)
</Step>
</Steps>
</Tab>
<Tab title="Access Token Method">
The Access Token method uses a GitLab access token for authentication, providing a straightforward setup process.
## Generate GitLab Access Token
<Tabs>
<Tab title="Personal Access Token">
Personal access tokens provide access to your GitLab account and all projects you have access to.
<Steps>
<Step title="Navigate to Access Tokens">
Log in to your GitLab account and navigate to User Settings > Access tokens. Click **Add new token** to create a new personal access token.
![GitLab Personal Access Tokens](/images/app-connections/gitlab/gitlab-add-access-token.png)
</Step>
<Step title="Configure Token">
<Tabs>
<Tab title="Secret Sync">
For Secret Syncs, your token will require the ability to access the API:
Fill in the token details:
- **Token name**: A descriptive name for the token (e.g., "connection-token")
- **Expiration date**: Set an appropriate expiration date
- **Select scopes**: Choose the **api** scope for full API access
![GitLab Personal Token Form](/images/app-connections/gitlab/gitlab-personal-access-token-form.png)
</Tab>
</Tabs>
<Info>
Personal Access Token connections require manual token rotation when your GitLab access token expires or is regenerated. Monitor your connection status and update the token as needed.
</Info>
</Step>
<Step title="Copy Token">
Copy the generated token immediately as it won't be shown again.
![GitLab Personal Token Created](/images/app-connections/gitlab/gitlab-copy-token.png)
<Warning>
Keep your access token secure and do not share it. Anyone with access to this token can access your GitLab account and projects.
</Warning>
</Step>
</Steps>
</Tab>
<Tab title="Project Access Token">
Project access tokens provide access to a specific GitLab project, offering more granular control.
<Steps>
<Step title="Navigate to Project Settings">
Go to your GitLab project and navigate to Settings > Access Tokens. Click **Add new token** to create a new project access token.
![GitLab Project Access Tokens](/images/app-connections/gitlab/gitlab-project-access-token-list.png)
</Step>
<Step title="Configure Token">
<Tabs>
<Tab title="Secret Sync">
For Secret Syncs, your token will require the ability to access the API and be at least an **Owner**:
Fill in the token details:
- **Token name**: A descriptive name for the token
- **Expiration date**: Set an appropriate expiration date
- **Select role**: Choose **Owner** or higher role
- **Select scopes**: Choose the **api** scope for API access
![GitLab Create Project Token](/images/app-connections/gitlab/gitlab-project-access-token-form.png)
</Tab>
</Tabs>
<Info>
Project Access Token connections require manual token rotation when your GitLab access token expires or is regenerated. Monitor your connection status and update the token as needed.
</Info>
</Step>
<Step title="Copy Token">
Copy the generated token immediately as it won't be shown again.
![GitLab Project Token Form](/images/app-connections/gitlab/gitlab-project-access-token-created.png)
<Warning>
Keep your access token secure and do not share it. Anyone with access to this token can access your GitLab account and projects.
</Warning>
</Step>
</Steps>
</Tab>
</Tabs>
## Setup GitLab Access Token Connection in Infisical
<Steps>
<Step title="Navigate to App Connections">
Navigate to the **App Connections** tab on the **Organization Settings** page.
![App Connections Tab](/images/app-connections/general/add-connection.png)
</Step>
<Step title="Add Connection">
Select the **GitLab Connection** option from the connection options modal.
![Select GitLab Connection](/images/app-connections/gitlab/select-gitlab-connection.png)
</Step>
<Step title="Configure Access Token">
Select the **Access Token** method, paste your GitLab access token in the provided field, and select the appropriate token type.
![Configure Access Token](/images/app-connections/gitlab/create-gitlab-access-token-connection.png)
Click **Connect** to establish the connection.
</Step>
<Step title="Connection Created">
Your **GitLab Connection** is now available for use.
![GitLab Access Token Connection](/images/app-connections/gitlab/gitlab-access-token-connection.png)
</Step>
</Steps>
</Tab>
</Tabs>

View File

@@ -1,6 +1,6 @@
--- ---
title: "Heroku Connection" title: "Heroku App Connection"
description: "Learn how to configure a Heroku Connection for Infisical using OAuth or Auth Token methods." description: "Learn how to configure a Heroku App Connection for Infisical using OAuth or Auth Token methods."
--- ---
Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth Token**. Choose the method that best fits your setup and security requirements. Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth Token**. Choose the method that best fits your setup and security requirements.
@@ -10,7 +10,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
The OAuth method provides secure authentication through Heroku's OAuth flow. The OAuth method provides secure authentication through Heroku's OAuth flow.
<Accordion title="Self-Hosted Instance Setup"> <Accordion title="Self-Hosted Instance Setup">
Using the Heroku Connection with OAuth on a self-hosted instance of Infisical requires configuring an API client in Heroku and registering your instance with it. Using the Heroku App Connection with OAuth on a self-hosted instance of Infisical requires configuring an API client in Heroku and registering your instance with it.
**Prerequisites:** **Prerequisites:**
- A Heroku account with existing applications - A Heroku account with existing applications
@@ -42,7 +42,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
- `CLIENT_ID_HEROKU`: The **Client ID** of your Heroku API client. - `CLIENT_ID_HEROKU`: The **Client ID** of your Heroku API client.
- `CLIENT_SECRET_HEROKU`: The **Client Secret** of your Heroku API client. - `CLIENT_SECRET_HEROKU`: The **Client Secret** of your Heroku API client.
Once added, restart your Infisical instance and use the Heroku Connection. Once added, restart your Infisical instance and use the Heroku App Connection.
</Step> </Step>
</Steps> </Steps>
</Accordion> </Accordion>
@@ -55,7 +55,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
![App Connections Tab](/images/app-connections/general/add-connection.png) ![App Connections Tab](/images/app-connections/general/add-connection.png)
</Step> </Step>
<Step title="Add Connection"> <Step title="Add Connection">
Select the **Heroku Connection** option from the connection options modal. Select the **Heroku App Connection** option from the connection options modal.
![Select Heroku Connection](/images/app-connections/heroku/heroku-select-connection.png) ![Select Heroku Connection](/images/app-connections/heroku/heroku-select-connection.png)
</Step> </Step>
<Step title="Choose OAuth Method"> <Step title="Choose OAuth Method">
@@ -68,7 +68,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
![Heroku Authorization](/images/integrations/heroku/integrations-heroku-auth.png) ![Heroku Authorization](/images/integrations/heroku/integrations-heroku-auth.png)
</Step> </Step>
<Step title="Connection Created"> <Step title="Connection Created">
Your **Heroku Connection** is now available for use. Your **Heroku App Connection** is now available for use.
![Heroku OAuth Connection](/images/app-connections/heroku/heroku-connection.png) ![Heroku OAuth Connection](/images/app-connections/heroku/heroku-connection.png)
</Step> </Step>
</Steps> </Steps>
@@ -97,7 +97,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
![App Connections Tab](/images/app-connections/general/add-connection.png) ![App Connections Tab](/images/app-connections/general/add-connection.png)
</Step> </Step>
<Step title="Add Connection"> <Step title="Add Connection">
Select the **Heroku Connection** option from the connection options modal. Select the **Heroku App Connection** option from the connection options modal.
![Select Heroku Connection](/images/app-connections/heroku/heroku-select-connection.png) ![Select Heroku Connection](/images/app-connections/heroku/heroku-select-connection.png)
</Step> </Step>
<Step title="Configure Auth Token"> <Step title="Configure Auth Token">
@@ -108,7 +108,7 @@ Infisical supports two methods for connecting to Heroku: **OAuth** and **Auth To
Click **Connect** to establish the connection. Click **Connect** to establish the connection.
</Step> </Step>
<Step title="Connection Created"> <Step title="Connection Created">
Your **Heroku Connection** is now available for use. Your **Heroku App Connection** is now available for use.
![Heroku Auth Token Connection](/images/app-connections/heroku/heroku-connection.png) ![Heroku Auth Token Connection](/images/app-connections/heroku/heroku-connection.png)
</Step> </Step>
</Steps> </Steps>

View File

@@ -1,180 +0,0 @@
---
title: "GitLab Sync"
description: "Learn how to configure a GitLab Sync for Infisical."
---
**Prerequisites:**
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
- Create a [GitLab Connection](/integrations/app-connections/gitlab)
<Tabs>
<Tab title="Infisical UI">
1. Navigate to **Project** > **Integrations** and select the **Secret Syncs** tab. Click on the **Add Sync** button.
![Secret Syncs Tab](/images/secret-syncs/general/secret-sync-tab.png)
2. Select the **GitLab** option.
![Select GitLab](/images/secret-syncs/gitlab/gitlab-secret-sync-option.png)
3. Configure the **Source** from where secrets should be retrieved, then click **Next**.
![Configure Source](/images/secret-syncs/gitlab/gitlab-secret-sync-source.png)
- **Environment**: The project environment to retrieve secrets from.
- **Secret Path**: The folder path to retrieve secrets from.
<Tip>
If you need to sync secrets from multiple folder locations, check out [secret imports](/documentation/platform/secret-reference#secret-imports).
</Tip>
4. Configure the **Destination** to where secrets should be deployed, then click **Next**.
![Configure Destination](/images/secret-syncs/gitlab/gitlab-secret-sync-destination.png)
- **GitLab Connection**: The GitLab Connection to authenticate with.
- **Scope**: The GitLab scope to sync secrets to.
- **Project**: Sync secrets to a GitLab project.
- **Group**: Sync secrets to a GitLab group.
<p class="height:1px" />
The remaining fields are determined by the selected **Scope**:
<AccordionGroup>
<Accordion title="Project">
- **GitLab Project**: The project to deploy secrets to.
- **GitLab Environment Scope**: The environment scope to deploy secrets to (optional, defaults to "*" for all environments).
- **Mark secrets as Protected**: If enabled, synced secrets will be marked as protected in GitLab.
- **Mark secrets as Masked**: If enabled, synced secrets will be masked in GitLab CI/CD logs.
- **Mark secrets as Hidden**: If enabled, synced secrets will be hidden from the GitLab UI.
</Accordion>
<Accordion title="Group">
- **GitLab Group**: The group to deploy secrets to.
- **GitLab Environment Scope**: The environment scope to deploy secrets to (optional, defaults to "*" for all environments).
- **Mark secrets as Protected**: If enabled, synced secrets will be marked as protected in GitLab.
- **Mark secrets as Masked**: If enabled, synced secrets will be masked in GitLab CI/CD logs.
- **Mark secrets as Hidden**: If enabled, synced secrets will be hidden from the GitLab UI.
</Accordion>
</AccordionGroup>
<Note>
Be aware that GitLab only allows to mark secrets as hidden for new secrets. If you try to mark an existing secret as hidden, it produces an error.
</Note>
<Warning>
If you enable **Mark secrets as Hidden**, Infisical will not be able to unhide/unmask secrets from the sync destination if you disable the option later. This is because GitLab does not allow to unhide/unmask existing secrets.
</Warning>
5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**.
![Configure Options](/images/secret-syncs/gitlab/gitlab-secret-sync-options.png)
- **Initial Sync Behavior**: Determines how Infisical should resolve the initial sync.
- **Overwrite Destination Secrets**: Removes any secrets at the destination endpoint not present in Infisical.
<Note>
GitLab does not support importing secrets.
</Note>
- **Key Schema**: Template that determines how secret names are transformed when syncing, using `{{secretKey}}` as a placeholder for the original secret name and `{{environment}}` for the environment.
<Note>
We highly recommend using a Key Schema to ensure that Infisical only manages the specific keys you intend, keeping everything else untouched.
</Note>
- **Auto-Sync Enabled**: If enabled, secrets will automatically be synced from the source location when changes occur. Disable to enforce manual syncing only.
- **Disable Secret Deletion**: If enabled, Infisical will not remove secrets from the sync destination. Enable this option if you intend to manage some secrets manually outside of Infisical.
6. Configure the **Details** of your GitLab Sync, then click **Next**.
![Configure Details](/images/secret-syncs/gitlab/gitlab-secret-sync-details.png)
- **Name**: The name of your sync. Must be slug-friendly.
- **Description**: An optional description for your sync.
7. Review your GitLab Sync configuration, then click **Create Sync**.
![Confirm Configuration](/images/secret-syncs/gitlab/gitlab-secret-sync-review.png)
8. If enabled, your GitLab Sync will begin syncing your secrets to the destination endpoint.
![Sync Secrets](/images/secret-syncs/gitlab/gitlab-secret-sync-created.png)
</Tab>
<Tab title="API">
To create a **GitLab Sync**, make an API request to the [Create GitLab Sync](/api-reference/endpoints/secret-syncs/gitlab/create) API endpoint.
### Sample request
```bash Request
curl --request POST \
--url https://app.infisical.com/api/v1/secret-syncs/gitlab \
--header 'Content-Type: application/json' \
--data '{
"name": "my-gitlab-sync",
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"description": "an example sync",
"connectionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"environment": "dev",
"secretPath": "/my-secrets",
"isEnabled": true,
"syncOptions": {
"initialSyncBehavior": "overwrite-destination"
},
"destinationConfig": {
"scope": "project",
"projectId": "70998370",
"projectName": "test",
"targetEnvironment": "*",
"shouldProtectSecrets": true,
"shouldMaskSecrets": true,
"shouldHideSecrets": false
}
}'
```
### Sample response
```bash Response
{
"secretSync": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "my-gitlab-sync",
"description": "an example sync",
"isEnabled": true,
"version": 1,
"folderId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connectionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"createdAt": "2023-11-07T05:31:56Z",
"updatedAt": "2023-11-07T05:31:56Z",
"syncStatus": "succeeded",
"lastSyncJobId": "123",
"lastSyncMessage": null,
"lastSyncedAt": "2023-11-07T05:31:56Z",
"importStatus": null,
"lastImportJobId": null,
"lastImportMessage": null,
"lastImportedAt": null,
"removeStatus": null,
"lastRemoveJobId": null,
"lastRemoveMessage": null,
"lastRemovedAt": null,
"syncOptions": {
"initialSyncBehavior": "overwrite-destination"
},
"projectId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"connection": {
"app": "gitlab",
"name": "my-gitlab-connection",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"environment": {
"slug": "dev",
"name": "Development",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
},
"folder": {
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"path": "/my-secrets"
},
"destination": "gitlab",
"destinationConfig": {
"scope": "project",
"projectId": "70998370",
"projectName": "test",
"targetEnvironment": "*",
"shouldProtectSecrets": true,
"shouldMaskSecrets": true,
"shouldHideSecrets": false
}
}
}
```
</Tab>
</Tabs>

View File

@@ -6,7 +6,7 @@ description: "Learn how to configure a Heroku Sync for Infisical."
**Prerequisites:** **Prerequisites:**
- Set up and add secrets to [Infisical Cloud](https://app.infisical.com) - Set up and add secrets to [Infisical Cloud](https://app.infisical.com)
- Create a [Heroku Connection](/integrations/app-connections/heroku) - Create a [Heroku App Connection](/integrations/app-connections/heroku)
<Tabs> <Tabs>
<Tab title="Infisical UI"> <Tab title="Infisical UI">
@@ -29,7 +29,7 @@ description: "Learn how to configure a Heroku Sync for Infisical."
4. Configure the **Destination** to where secrets should be deployed, then click **Next**. 4. Configure the **Destination** to where secrets should be deployed, then click **Next**.
![Configure Destination](/images/secret-syncs/heroku/heroku-destination.png) ![Configure Destination](/images/secret-syncs/heroku/heroku-destination.png)
- **Heroku Connection**: The Heroku Connection to authenticate with. - **Heroku App Connection**: The Heroku App Connection to authenticate with.
- **Heroku App**: The Heroku application to sync secrets to. - **Heroku App**: The Heroku application to sync secrets to.
5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**. 5. Configure the **Sync Options** to specify how secrets should be synced, then click **Next**.

File diff suppressed because it is too large Load Diff

View File

@@ -590,17 +590,6 @@ You can configure third-party app connections for re-use across Infisical Projec
</Accordion> </Accordion>
<Accordion title="GitLab OAuth Connection">
<ParamField query="INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_ID" type="string" default="none" optional>
The Application ID of your GitLab OAuth application.
</ParamField>
<ParamField query="INF_APP_CONNECTION_GITLAB_OAUTH_CLIENT_SECRET" type="string" default="none" optional>
The Secret of your GitLab OAuth application.
</ParamField>
</Accordion>
## Native Secret Integrations ## Native Secret Integrations
To help you sync secrets from Infisical to services such as Github and Gitlab, Infisical provides native integrations out of the box. To help you sync secrets from Infisical to services such as Github and Gitlab, Infisical provides native integrations out of the box.

View File

@@ -1,282 +0,0 @@
import { Controller, useFormContext, useWatch } from "react-hook-form";
import { SingleValue } from "react-select";
import { faCircleInfo, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
import {
FilterableSelect,
FormControl,
Input,
Select,
SelectItem,
Switch,
Tooltip
} from "@app/components/v2";
import {
TGitLabGroup,
TGitLabProject,
useGitlabConnectionListGroups,
useGitlabConnectionListProjects
} from "@app/hooks/api/appConnections/gitlab";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { GitLabSyncScope } from "@app/hooks/api/secretSyncs/types/gitlab-sync";
import { TSecretSyncForm } from "../schemas";
const SecretProtectionOption = ({
title,
isEnabled,
onChange,
id,
isDisabled = false,
tooltip
}: {
title: string;
isEnabled: boolean;
onChange: (checked: boolean) => void;
id: string;
isDisabled?: boolean;
tooltip?: string;
}) => {
return (
<Switch
className="bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
id={id}
thumbClassName="bg-mineshaft-800"
onCheckedChange={onChange}
isChecked={isEnabled}
isDisabled={isDisabled}
containerClassName="w-full"
>
<p>
{title}{" "}
{tooltip && (
<Tooltip className="max-w-md" content={tooltip}>
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
</Tooltip>
)}
</p>
</Switch>
);
};
export const GitLabSyncFields = () => {
const { control, setValue } = useFormContext<
TSecretSyncForm & { destination: SecretSync.GitLab }
>();
const connectionId = useWatch({ name: "connection.id", control });
const scope = useWatch({ name: "destinationConfig.scope", control });
const shouldMaskSecrets = useWatch({ name: "destinationConfig.shouldMaskSecrets", control });
const { data: groups, isLoading: isGroupsLoading } = useGitlabConnectionListGroups(connectionId, {
enabled: Boolean(connectionId) && scope === GitLabSyncScope.Group
});
const { data: projects, isLoading: isProjectsLoading } = useGitlabConnectionListProjects(
connectionId,
{
enabled: Boolean(connectionId)
}
);
return (
<div className="h-full overflow-auto">
<SecretSyncConnectionField
onChange={() => {
setValue("destinationConfig.projectId", "");
setValue("destinationConfig.projectName", "");
setValue("destinationConfig.groupId", "");
setValue("destinationConfig.groupName", "");
setValue("destinationConfig.scope", GitLabSyncScope.Project);
}}
/>
<Controller
name="destinationConfig.scope"
control={control}
defaultValue={GitLabSyncScope.Project}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl errorText={error?.message} isError={Boolean(error?.message)} label="Scope">
<Select
value={value}
onValueChange={(val) => {
onChange(val);
setValue("destinationConfig.projectId", "");
setValue("destinationConfig.projectName", "");
setValue("destinationConfig.groupId", "");
setValue("destinationConfig.groupName", "");
}}
className="w-full border border-mineshaft-500 capitalize"
position="popper"
placeholder="Select a scope..."
dropdownContainerClassName="max-w-none"
>
{Object.values(GitLabSyncScope).map((projectScope) => (
<SelectItem className="capitalize" value={projectScope} key={projectScope}>
{projectScope.replace("-", " ")}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
{scope === GitLabSyncScope.Group && (
<Controller
name="destinationConfig.groupId"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
isError={Boolean(error)}
errorText={error?.message}
label="Group"
helperText={
<Tooltip
className="max-w-md"
content="Ensure the group exists in the connection's GitLab instance URL."
>
<div>
<span>Don&#39;t see the group you&#39;re looking for?</span>{" "}
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-400" />
</div>
</Tooltip>
}
>
<FilterableSelect
menuPlacement="top"
isLoading={isGroupsLoading && Boolean(connectionId)}
isDisabled={!connectionId}
value={groups?.find((group) => group.id === value) ?? null}
onChange={(option) => {
onChange((option as SingleValue<TGitLabGroup>)?.id ?? "");
setValue(
"destinationConfig.groupName",
(option as SingleValue<TGitLabGroup>)?.name ?? ""
);
}}
options={groups}
placeholder="Select a group..."
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
/>
</FormControl>
)}
/>
)}
{scope === GitLabSyncScope.Project && (
<Controller
name="destinationConfig.projectId"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
isError={Boolean(error)}
errorText={error?.message}
label="GitLab Project"
helperText={
<Tooltip
className="max-w-md"
content="Ensure the project exists in the connection's GitLab instance URL and the connection has access to it."
>
<div>
<span>Don&#39;t see the project you&#39;re looking for?</span>{" "}
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-400" />
</div>
</Tooltip>
}
>
<FilterableSelect
menuPlacement="top"
isLoading={isProjectsLoading && Boolean(connectionId)}
isDisabled={!connectionId}
value={projects?.find((project) => project.id === value) ?? null}
onChange={(option) => {
onChange((option as SingleValue<TGitLabProject>)?.id ?? "");
setValue(
"destinationConfig.projectName",
(option as SingleValue<TGitLabProject>)?.name ?? ""
);
}}
options={projects}
placeholder="Select a project..."
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
/>
</FormControl>
)}
/>
)}
<Controller
control={control}
defaultValue=""
name="destinationConfig.targetEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="GitLab Environment Scope (Optional)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="*" />
</FormControl>
)}
/>
{/* Secret Protection Settings Section */}
<div className="mt-6">
<div className="space-y-4">
<Controller
control={control}
name="destinationConfig.shouldProtectSecrets"
render={({ field: { onChange, value } }) => (
<SecretProtectionOption
id="should-protect-secrets"
title="Mark secrets as Protected"
isEnabled={value || false}
onChange={onChange}
/>
)}
/>
<Controller
control={control}
name="destinationConfig.shouldMaskSecrets"
render={({ field: { onChange, value } }) => (
<SecretProtectionOption
id="should-mask-secrets"
title="Mark secrets as Masked"
tooltip="GitLab has limitations for masked variables: secrets must be at least 8 characters long and not match existing CI/CD variable names. Secrets not meeting these criteria won't be masked."
isEnabled={value || false}
onChange={(checked) => {
onChange(checked);
if (!checked) {
setValue("destinationConfig.shouldHideSecrets", false);
}
}}
/>
)}
/>
<Controller
control={control}
name="destinationConfig.shouldHideSecrets"
render={({ field: { onChange, value } }) => (
<div className="max-h-32 opacity-100 transition-all duration-300">
<SecretProtectionOption
id="should-hide-secrets"
title="Mark secrets as Hidden"
tooltip="Secrets can only be marked as hidden if they are also masked. If this is enabled, Infisical will not be able to unhide/unmask secrets from the sync destination if you disable the option later."
isEnabled={value || false}
onChange={onChange}
isDisabled={!shouldMaskSecrets}
/>
</div>
)}
/>
</div>
</div>
</div>
);
};

View File

@@ -15,7 +15,6 @@ import { DatabricksSyncFields } from "./DatabricksSyncFields";
import { FlyioSyncFields } from "./FlyioSyncFields"; import { FlyioSyncFields } from "./FlyioSyncFields";
import { GcpSyncFields } from "./GcpSyncFields"; import { GcpSyncFields } from "./GcpSyncFields";
import { GitHubSyncFields } from "./GitHubSyncFields"; import { GitHubSyncFields } from "./GitHubSyncFields";
import { GitLabSyncFields } from "./GitLabSyncFields";
import { HCVaultSyncFields } from "./HCVaultSyncFields"; import { HCVaultSyncFields } from "./HCVaultSyncFields";
import { HerokuSyncFields } from "./HerokuSyncFields"; import { HerokuSyncFields } from "./HerokuSyncFields";
import { HumanitecSyncFields } from "./HumanitecSyncFields"; import { HumanitecSyncFields } from "./HumanitecSyncFields";
@@ -72,8 +71,6 @@ export const SecretSyncDestinationFields = () => {
return <RenderSyncFields />; return <RenderSyncFields />;
case SecretSync.Flyio: case SecretSync.Flyio:
return <FlyioSyncFields />; return <FlyioSyncFields />;
case SecretSync.GitLab:
return <GitLabSyncFields />;
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
return <CloudflarePagesSyncFields />; return <CloudflarePagesSyncFields />;
default: default:

View File

@@ -55,7 +55,6 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
case SecretSync.Heroku: case SecretSync.Heroku:
case SecretSync.Render: case SecretSync.Render:
case SecretSync.Flyio: case SecretSync.Flyio:
case SecretSync.GitLab:
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
AdditionalSyncOptionsFieldsComponent = null; AdditionalSyncOptionsFieldsComponent = null;
break; break;

View File

@@ -1,37 +0,0 @@
import { useFormContext } from "react-hook-form";
import { GenericFieldLabel } from "@app/components/secret-syncs";
import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { GitLabSyncScope } from "@app/hooks/api/secretSyncs/types/gitlab-sync";
export const GitLabSyncReviewFields = () => {
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.GitLab }>();
const projectName = watch("destinationConfig.projectName");
const targetEnvironment = watch("destinationConfig.targetEnvironment");
const groupName = watch("destinationConfig.groupName");
const scope = watch("destinationConfig.scope");
const shouldProtectSecrets = watch("destinationConfig.shouldProtectSecrets");
const shouldMaskSecrets = watch("destinationConfig.shouldMaskSecrets");
const shouldHideSecrets = watch("destinationConfig.shouldHideSecrets");
return (
<>
<GenericFieldLabel label="Scope">{scope}</GenericFieldLabel>
{scope === GitLabSyncScope.Project && (
<GenericFieldLabel label="Project Name">{projectName}</GenericFieldLabel>
)}
{scope === GitLabSyncScope.Group && (
<GenericFieldLabel label="Group Name">{groupName}</GenericFieldLabel>
)}
{targetEnvironment && (
<GenericFieldLabel label="Environment">{targetEnvironment}</GenericFieldLabel>
)}
<GenericFieldLabel label="Protect Secrets">
{shouldProtectSecrets ? "Yes" : "No"}
</GenericFieldLabel>
<GenericFieldLabel label="Mask Secrets">{shouldMaskSecrets ? "Yes" : "No"}</GenericFieldLabel>
<GenericFieldLabel label="Hide Secrets">{shouldHideSecrets ? "Yes" : "No"}</GenericFieldLabel>
</>
);
};

View File

@@ -24,7 +24,6 @@ import { DatabricksSyncReviewFields } from "./DatabricksSyncReviewFields";
import { FlyioSyncReviewFields } from "./FlyioSyncReviewFields"; import { FlyioSyncReviewFields } from "./FlyioSyncReviewFields";
import { GcpSyncReviewFields } from "./GcpSyncReviewFields"; import { GcpSyncReviewFields } from "./GcpSyncReviewFields";
import { GitHubSyncReviewFields } from "./GitHubSyncReviewFields"; import { GitHubSyncReviewFields } from "./GitHubSyncReviewFields";
import { GitLabSyncReviewFields } from "./GitLabSyncReviewFields";
import { HCVaultSyncReviewFields } from "./HCVaultSyncReviewFields"; import { HCVaultSyncReviewFields } from "./HCVaultSyncReviewFields";
import { HerokuSyncReviewFields } from "./HerokuSyncReviewFields"; import { HerokuSyncReviewFields } from "./HerokuSyncReviewFields";
import { HumanitecSyncReviewFields } from "./HumanitecSyncReviewFields"; import { HumanitecSyncReviewFields } from "./HumanitecSyncReviewFields";
@@ -118,9 +117,6 @@ export const SecretSyncReviewFields = () => {
case SecretSync.Flyio: case SecretSync.Flyio:
DestinationFieldsComponent = <FlyioSyncReviewFields />; DestinationFieldsComponent = <FlyioSyncReviewFields />;
break; break;
case SecretSync.GitLab:
DestinationFieldsComponent = <GitLabSyncReviewFields />;
break;
case SecretSync.CloudflarePages: case SecretSync.CloudflarePages:
DestinationFieldsComponent = <CloudflarePagesSyncReviewFields />; DestinationFieldsComponent = <CloudflarePagesSyncReviewFields />;
break; break;

View File

@@ -1,31 +0,0 @@
import { z } from "zod";
import { BaseSecretSyncSchema } from "@app/components/secret-syncs/forms/schemas/base-secret-sync-schema";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { GitLabSyncScope } from "@app/hooks/api/secretSyncs/types/gitlab-sync";
export const GitlabSyncDestinationSchema = BaseSecretSyncSchema().merge(
z.object({
destination: z.literal(SecretSync.GitLab),
destinationConfig: z.discriminatedUnion("scope", [
z.object({
scope: z.literal(GitLabSyncScope.Project),
projectId: z.string().trim().min(1, "Project ID required"),
projectName: z.string().trim().min(1, "Project name required"),
targetEnvironment: z.string().optional(),
shouldProtectSecrets: z.boolean().optional().default(false),
shouldMaskSecrets: z.boolean().optional().default(false),
shouldHideSecrets: z.boolean().optional().default(false)
}),
z.object({
scope: z.literal(GitLabSyncScope.Group),
targetEnvironment: z.string().optional(),
groupId: z.string().trim().min(1, "Group ID required"),
groupName: z.string().trim().min(1, "Group name required"),
shouldProtectSecrets: z.boolean().optional().default(false),
shouldMaskSecrets: z.boolean().optional().default(false),
shouldHideSecrets: z.boolean().optional().default(false)
})
])
})
);

View File

@@ -12,7 +12,6 @@ import { DatabricksSyncDestinationSchema } from "./databricks-sync-destination-s
import { FlyioSyncDestinationSchema } from "./flyio-sync-destination-schema"; import { FlyioSyncDestinationSchema } from "./flyio-sync-destination-schema";
import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema"; import { GcpSyncDestinationSchema } from "./gcp-sync-destination-schema";
import { GitHubSyncDestinationSchema } from "./github-sync-destination-schema"; import { GitHubSyncDestinationSchema } from "./github-sync-destination-schema";
import { GitlabSyncDestinationSchema } from "./gitlab-sync-destination-schema";
import { HCVaultSyncDestinationSchema } from "./hc-vault-sync-destination-schema"; import { HCVaultSyncDestinationSchema } from "./hc-vault-sync-destination-schema";
import { HerokuSyncDestinationSchema } from "./heroku-sync-destination-schema"; import { HerokuSyncDestinationSchema } from "./heroku-sync-destination-schema";
import { HumanitecSyncDestinationSchema } from "./humanitec-sync-destination-schema"; import { HumanitecSyncDestinationSchema } from "./humanitec-sync-destination-schema";
@@ -44,7 +43,6 @@ const SecretSyncUnionSchema = z.discriminatedUnion("destination", [
HerokuSyncDestinationSchema, HerokuSyncDestinationSchema,
RenderSyncDestinationSchema, RenderSyncDestinationSchema,
FlyioSyncDestinationSchema, FlyioSyncDestinationSchema,
GitlabSyncDestinationSchema,
CloudflarePagesSyncDestinationSchema CloudflarePagesSyncDestinationSchema
]); ]);

View File

@@ -1,5 +1,6 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { TooltipProps as RootProps } from "@radix-ui/react-tooltip";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
export type TooltipProps = Omit<TooltipPrimitive.TooltipContentProps, "open" | "content"> & { export type TooltipProps = Omit<TooltipPrimitive.TooltipContentProps, "open" | "content"> & {
@@ -14,6 +15,7 @@ export type TooltipProps = Omit<TooltipPrimitive.TooltipContentProps, "open" | "
isDisabled?: boolean; isDisabled?: boolean;
center?: boolean; center?: boolean;
size?: "sm" | "md"; size?: "sm" | "md";
rootProps?: RootProps;
}; };
export const Tooltip = ({ export const Tooltip = ({
@@ -28,12 +30,14 @@ export const Tooltip = ({
isDisabled, isDisabled,
position = "top", position = "top",
size = "md", size = "md",
rootProps,
...props ...props
}: TooltipProps) => }: TooltipProps) =>
// just render children if tooltip content is empty // just render children if tooltip content is empty
content ? ( content ? (
<TooltipPrimitive.Root <TooltipPrimitive.Root
delayDuration={50} delayDuration={50}
{...rootProps}
open={isOpen} open={isOpen}
defaultOpen={defaultOpen} defaultOpen={defaultOpen}
onOpenChange={onOpenChange} onOpenChange={onOpenChange}

View File

@@ -24,7 +24,6 @@ import {
GcpConnectionMethod, GcpConnectionMethod,
GitHubConnectionMethod, GitHubConnectionMethod,
GitHubRadarConnectionMethod, GitHubRadarConnectionMethod,
GitLabConnectionMethod,
HCVaultConnectionMethod, HCVaultConnectionMethod,
HumanitecConnectionMethod, HumanitecConnectionMethod,
LdapConnectionMethod, LdapConnectionMethod,
@@ -87,7 +86,6 @@ export const APP_CONNECTION_MAP: Record<
[AppConnection.Heroku]: { name: "Heroku", image: "Heroku.png" }, [AppConnection.Heroku]: { name: "Heroku", image: "Heroku.png" },
[AppConnection.Render]: { name: "Render", image: "Render.png" }, [AppConnection.Render]: { name: "Render", image: "Render.png" },
[AppConnection.Flyio]: { name: "Fly.io", image: "Flyio.svg" }, [AppConnection.Flyio]: { name: "Fly.io", image: "Flyio.svg" },
[AppConnection.Gitlab]: { name: "GitLab", image: "GitLab.png" },
[AppConnection.Cloudflare]: { name: "Cloudflare", image: "Cloudflare.png" } [AppConnection.Cloudflare]: { name: "Cloudflare", image: "Cloudflare.png" }
}; };
@@ -102,7 +100,6 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
case AzureDevOpsConnectionMethod.OAuth: case AzureDevOpsConnectionMethod.OAuth:
case GitHubConnectionMethod.OAuth: case GitHubConnectionMethod.OAuth:
case HerokuConnectionMethod.OAuth: case HerokuConnectionMethod.OAuth:
case GitLabConnectionMethod.OAuth:
return { name: "OAuth", icon: faPassport }; return { name: "OAuth", icon: faPassport };
case AwsConnectionMethod.AccessKey: case AwsConnectionMethod.AccessKey:
case OCIConnectionMethod.AccessKey: case OCIConnectionMethod.AccessKey:

View File

@@ -74,10 +74,6 @@ export const SECRET_SYNC_MAP: Record<SecretSync, { name: string; image: string }
name: "Fly.io", name: "Fly.io",
image: "Flyio.svg" image: "Flyio.svg"
}, },
[SecretSync.GitLab]: {
name: "GitLab",
image: "GitLab.png"
},
[SecretSync.CloudflarePages]: { [SecretSync.CloudflarePages]: {
name: "Cloudflare Pages", name: "Cloudflare Pages",
image: "Cloudflare.png" image: "Cloudflare.png"
@@ -105,7 +101,6 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
[SecretSync.Heroku]: AppConnection.Heroku, [SecretSync.Heroku]: AppConnection.Heroku,
[SecretSync.Render]: AppConnection.Render, [SecretSync.Render]: AppConnection.Render,
[SecretSync.Flyio]: AppConnection.Flyio, [SecretSync.Flyio]: AppConnection.Flyio,
[SecretSync.GitLab]: AppConnection.Gitlab,
[SecretSync.CloudflarePages]: AppConnection.Cloudflare [SecretSync.CloudflarePages]: AppConnection.Cloudflare
}; };

View File

@@ -26,6 +26,5 @@ export enum AppConnection {
Heroku = "heroku", Heroku = "heroku",
Render = "render", Render = "render",
Flyio = "flyio", Flyio = "flyio",
Gitlab = "gitlab",
Cloudflare = "cloudflare" Cloudflare = "cloudflare"
} }

View File

@@ -1,2 +0,0 @@
export * from "./queries";
export * from "./types";

View File

@@ -1,64 +0,0 @@
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { appConnectionKeys } from "../queries";
import { TGitLabGroup, TGitLabProject } from "./types";
const gitlabConnectionKeys = {
all: [...appConnectionKeys.all, "gitlab"] as const,
listProjects: (connectionId: string) =>
[...gitlabConnectionKeys.all, "projects", connectionId] as const,
listGroups: (connectionId: string) =>
[...gitlabConnectionKeys.all, "groups", connectionId] as const
};
export const useGitlabConnectionListProjects = (
connectionId: string,
options?: Omit<
UseQueryOptions<
TGitLabProject[],
unknown,
TGitLabProject[],
ReturnType<typeof gitlabConnectionKeys.listProjects>
>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: gitlabConnectionKeys.listProjects(connectionId),
queryFn: async () => {
const { data } = await apiRequest.get<TGitLabProject[]>(
`/api/v1/app-connections/gitlab/${connectionId}/projects`
);
return data;
},
...options
});
};
export const useGitlabConnectionListGroups = (
connectionId: string,
options?: Omit<
UseQueryOptions<
TGitLabGroup[],
unknown,
TGitLabGroup[],
ReturnType<typeof gitlabConnectionKeys.listGroups>
>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: gitlabConnectionKeys.listGroups(connectionId),
queryFn: async () => {
const { data } = await apiRequest.get<TGitLabGroup[]>(
`/api/v1/app-connections/gitlab/${connectionId}/groups`
);
return data;
},
...options
});
};

View File

@@ -1,14 +0,0 @@
export type TGitLabProject = {
id: string;
name: string;
};
export type TGitLabGroup = {
id: string;
name: string;
};
export enum GitLabAccessTokenType {
Personal = "personal",
Project = "project"
}

View File

@@ -123,11 +123,6 @@ export type TFlyioConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Flyio; app: AppConnection.Flyio;
}; };
export type TGitlabConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Gitlab;
oauthClientId?: string;
};
export type TCloudflareConnectionOption = TAppConnectionOptionBase & { export type TCloudflareConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Cloudflare; app: AppConnection.Cloudflare;
}; };
@@ -158,7 +153,6 @@ export type TAppConnectionOption =
| THerokuConnectionOption | THerokuConnectionOption
| TRenderConnectionOption | TRenderConnectionOption
| TFlyioConnectionOption | TFlyioConnectionOption
| TGitlabConnectionOption
| TCloudflareConnectionOption; | TCloudflareConnectionOption;
export type TAppConnectionOptionMap = { export type TAppConnectionOptionMap = {
@@ -189,6 +183,5 @@ export type TAppConnectionOptionMap = {
[AppConnection.Heroku]: THerokuConnectionOption; [AppConnection.Heroku]: THerokuConnectionOption;
[AppConnection.Render]: TRenderConnectionOption; [AppConnection.Render]: TRenderConnectionOption;
[AppConnection.Flyio]: TFlyioConnectionOption; [AppConnection.Flyio]: TFlyioConnectionOption;
[AppConnection.Gitlab]: TGitlabConnectionOption;
[AppConnection.Cloudflare]: TCloudflareConnectionOption; [AppConnection.Cloudflare]: TCloudflareConnectionOption;
}; };

View File

@@ -1,27 +0,0 @@
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
import { GitLabAccessTokenType } from "../gitlab";
export enum GitLabConnectionMethod {
AccessToken = "access-token",
OAuth = "oauth"
}
export type TGitLabConnection = TRootAppConnection & { app: AppConnection.Gitlab } & (
| {
method: GitLabConnectionMethod.AccessToken;
credentials: {
instanceUrl?: string;
accessToken: string;
accessTokenType: GitLabAccessTokenType;
};
}
| {
method: GitLabConnectionMethod.OAuth;
credentials: {
code: string;
instanceUrl?: string;
};
}
);

View File

@@ -14,7 +14,6 @@ import { TFlyioConnection } from "./flyio-connection";
import { TGcpConnection } from "./gcp-connection"; import { TGcpConnection } from "./gcp-connection";
import { TGitHubConnection } from "./github-connection"; import { TGitHubConnection } from "./github-connection";
import { TGitHubRadarConnection } from "./github-radar-connection"; import { TGitHubRadarConnection } from "./github-radar-connection";
import { TGitLabConnection } from "./gitlab-connection";
import { THCVaultConnection } from "./hc-vault-connection"; import { THCVaultConnection } from "./hc-vault-connection";
import { THerokuConnection } from "./heroku-connection"; import { THerokuConnection } from "./heroku-connection";
import { THumanitecConnection } from "./humanitec-connection"; import { THumanitecConnection } from "./humanitec-connection";
@@ -38,13 +37,11 @@ export * from "./azure-client-secrets-connection";
export * from "./azure-devops-connection"; export * from "./azure-devops-connection";
export * from "./azure-key-vault-connection"; export * from "./azure-key-vault-connection";
export * from "./camunda-connection"; export * from "./camunda-connection";
export * from "./cloudflare-connection";
export * from "./databricks-connection"; export * from "./databricks-connection";
export * from "./flyio-connection"; export * from "./flyio-connection";
export * from "./gcp-connection"; export * from "./gcp-connection";
export * from "./github-connection"; export * from "./github-connection";
export * from "./github-radar-connection"; export * from "./github-radar-connection";
export * from "./gitlab-connection";
export * from "./hc-vault-connection"; export * from "./hc-vault-connection";
export * from "./heroku-connection"; export * from "./heroku-connection";
export * from "./humanitec-connection"; export * from "./humanitec-connection";
@@ -59,6 +56,7 @@ export * from "./teamcity-connection";
export * from "./terraform-cloud-connection"; export * from "./terraform-cloud-connection";
export * from "./vercel-connection"; export * from "./vercel-connection";
export * from "./windmill-connection"; export * from "./windmill-connection";
export * from "./cloudflare-connection";
export type TAppConnection = export type TAppConnection =
| TAwsConnection | TAwsConnection
@@ -88,7 +86,6 @@ export type TAppConnection =
| THerokuConnection | THerokuConnection
| TRenderConnection | TRenderConnection
| TFlyioConnection | TFlyioConnection
| TGitLabConnection
| TCloudflareConnection; | TCloudflareConnection;
export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id">; export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id">;
@@ -144,6 +141,5 @@ export type TAppConnectionMap = {
[AppConnection.Heroku]: THerokuConnection; [AppConnection.Heroku]: THerokuConnection;
[AppConnection.Render]: TRenderConnection; [AppConnection.Render]: TRenderConnection;
[AppConnection.Flyio]: TFlyioConnection; [AppConnection.Flyio]: TFlyioConnection;
[AppConnection.Gitlab]: TGitLabConnection;
[AppConnection.Cloudflare]: TCloudflareConnection; [AppConnection.Cloudflare]: TCloudflareConnection;
}; };

View File

@@ -19,7 +19,6 @@ export enum SecretSync {
Heroku = "heroku", Heroku = "heroku",
Render = "render", Render = "render",
Flyio = "flyio", Flyio = "flyio",
GitLab = "gitlab",
CloudflarePages = "cloudflare-pages" CloudflarePages = "cloudflare-pages"
} }

View File

@@ -1,36 +0,0 @@
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { SecretSync } from "@app/hooks/api/secretSyncs";
import { TRootSecretSync } from "@app/hooks/api/secretSyncs/types/root-sync";
export enum GitLabSyncScope {
Project = "project",
Group = "group"
}
export type TGitLabSync = TRootSecretSync & {
destination: SecretSync.GitLab;
destinationConfig:
| {
scope: GitLabSyncScope.Project;
projectId: string;
projectName: string;
targetEnvironment?: string;
shouldProtectSecrets?: boolean;
shouldMaskSecrets?: boolean;
shouldHideSecrets?: boolean;
}
| {
scope: GitLabSyncScope.Group;
groupId: string;
groupName: string;
targetEnvironment?: string;
shouldProtectSecrets?: boolean;
shouldMaskSecrets?: boolean;
shouldHideSecrets?: boolean;
};
connection: {
app: AppConnection.Gitlab;
name: string;
id: string;
};
};

View File

@@ -14,7 +14,6 @@ import { TDatabricksSync } from "./databricks-sync";
import { TFlyioSync } from "./flyio-sync"; import { TFlyioSync } from "./flyio-sync";
import { TGcpSync } from "./gcp-sync"; import { TGcpSync } from "./gcp-sync";
import { TGitHubSync } from "./github-sync"; import { TGitHubSync } from "./github-sync";
import { TGitLabSync } from "./gitlab-sync";
import { THCVaultSync } from "./hc-vault-sync"; import { THCVaultSync } from "./hc-vault-sync";
import { THerokuSync } from "./heroku-sync"; import { THerokuSync } from "./heroku-sync";
import { THumanitecSync } from "./humanitec-sync"; import { THumanitecSync } from "./humanitec-sync";
@@ -52,7 +51,6 @@ export type TSecretSync =
| THerokuSync | THerokuSync
| TRenderSync | TRenderSync
| TFlyioSync | TFlyioSync
| TGitLabSync
| TCloudflarePagesSync; | TCloudflarePagesSync;
export type TListSecretSyncs = { secretSyncs: TSecretSync[] }; export type TListSecretSyncs = { secretSyncs: TSecretSync[] };

View File

@@ -23,7 +23,6 @@ import { FlyioConnectionForm } from "./FlyioConnectionForm";
import { GcpConnectionForm } from "./GcpConnectionForm"; import { GcpConnectionForm } from "./GcpConnectionForm";
import { GitHubConnectionForm } from "./GitHubConnectionForm"; import { GitHubConnectionForm } from "./GitHubConnectionForm";
import { GitHubRadarConnectionForm } from "./GitHubRadarConnectionForm"; import { GitHubRadarConnectionForm } from "./GitHubRadarConnectionForm";
import { GitLabConnectionForm } from "./GitLabConnectionForm";
import { HCVaultConnectionForm } from "./HCVaultConnectionForm"; import { HCVaultConnectionForm } from "./HCVaultConnectionForm";
import { HerokuConnectionForm } from "./HerokuAppConnectionForm"; import { HerokuConnectionForm } from "./HerokuAppConnectionForm";
import { HumanitecConnectionForm } from "./HumanitecConnectionForm"; import { HumanitecConnectionForm } from "./HumanitecConnectionForm";
@@ -130,8 +129,6 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => {
return <RenderConnectionForm onSubmit={onSubmit} />; return <RenderConnectionForm onSubmit={onSubmit} />;
case AppConnection.Flyio: case AppConnection.Flyio:
return <FlyioConnectionForm onSubmit={onSubmit} />; return <FlyioConnectionForm onSubmit={onSubmit} />;
case AppConnection.Gitlab:
return <GitLabConnectionForm onSubmit={onSubmit} />;
case AppConnection.Cloudflare: case AppConnection.Cloudflare:
return <CloudflareConnectionForm onSubmit={onSubmit} />; return <CloudflareConnectionForm onSubmit={onSubmit} />;
default: default:
@@ -224,8 +221,6 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
return <RenderConnectionForm onSubmit={onSubmit} appConnection={appConnection} />; return <RenderConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Flyio: case AppConnection.Flyio:
return <FlyioConnectionForm onSubmit={onSubmit} appConnection={appConnection} />; return <FlyioConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Gitlab:
return <GitLabConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Cloudflare: case AppConnection.Cloudflare:
return <CloudflareConnectionForm onSubmit={onSubmit} appConnection={appConnection} />; return <CloudflareConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
default: default:

Some files were not shown because too many files have changed in this diff Show More