diff --git a/backend/src/ee/services/app-connections/chef/chef-connection-fns.ts b/backend/src/ee/services/app-connections/chef/chef-connection-fns.ts index 31f5d0ee0..6cef8373f 100644 --- a/backend/src/ee/services/app-connections/chef/chef-connection-fns.ts +++ b/backend/src/ee/services/app-connections/chef/chef-connection-fns.ts @@ -5,10 +5,10 @@ import { request } from "@app/lib/config/request"; import { BadRequestError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; +import { AppConnection } from "@app/services/app-connection/app-connection-enums"; import { IntegrationUrls } from "@app/services/integration-auth/integration-list"; import { TChefDataBagItemContent } from "../../secret-sync/chef/chef-sync-types"; -import { AppConnection } from "../../../../services/app-connection/app-connection-enums"; import { ChefConnectionMethod } from "./chef-connection-enums"; import { TChefConnection, diff --git a/backend/src/ee/services/app-connections/chef/chef-connection-service.ts b/backend/src/ee/services/app-connections/chef/chef-connection-service.ts index 05969bf5d..242b1fbf9 100644 --- a/backend/src/ee/services/app-connections/chef/chef-connection-service.ts +++ b/backend/src/ee/services/app-connections/chef/chef-connection-service.ts @@ -1,7 +1,8 @@ -import { ForbiddenRequestError } from "@app/lib/errors"; +import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors"; import { OrgServiceActor } from "@app/lib/types"; import { AppConnection } from "../../../../services/app-connection/app-connection-enums"; +import { TLicenseServiceFactory } from "../../license/license-service"; import { listChefDataBagItems, listChefDataBags } from "./chef-connection-fns"; import { TChefConnection } from "./chef-connection-types"; @@ -11,8 +12,23 @@ type TGetAppConnectionFunc = ( actor: OrgServiceActor ) => Promise; -export const chefConnectionService = (getAppConnection: TGetAppConnectionFunc) => { +// Enterprise check +export const checkPlan = async (licenseService: Pick, orgId: string) => { + const plan = await licenseService.getPlan(orgId); + if (!plan.enterpriseAppConnections) + throw new BadRequestError({ + message: + "Failed to use app connection due to plan restriction. Upgrade plan to access enterprise app connections." + }); +}; + +export const chefConnectionService = ( + getAppConnection: TGetAppConnectionFunc, + licenseService: Pick +) => { const listDataBags = async (appConnectionId: string, actor: OrgServiceActor) => { + await checkPlan(licenseService, actor.orgId); + const appConnection = await getAppConnection(AppConnection.Chef, appConnectionId, actor); if (!appConnection) { @@ -23,6 +39,8 @@ export const chefConnectionService = (getAppConnection: TGetAppConnectionFunc) = }; const listDataBagItems = async (appConnectionId: string, dataBagName: string, actor: OrgServiceActor) => { + await checkPlan(licenseService, actor.orgId); + const appConnection = await getAppConnection(AppConnection.Chef, appConnectionId, actor); if (!appConnection) { diff --git a/backend/src/ee/services/app-connections/chef/chef-connection-types.ts b/backend/src/ee/services/app-connections/chef/chef-connection-types.ts index 096218951..5673614e9 100644 --- a/backend/src/ee/services/app-connections/chef/chef-connection-types.ts +++ b/backend/src/ee/services/app-connections/chef/chef-connection-types.ts @@ -1,7 +1,7 @@ import z from "zod"; -import { DiscriminativePick } from "@app/lib/types"; import { TChefDataBagItemContent } from "@app/ee/services/secret-sync/chef"; +import { DiscriminativePick } from "@app/lib/types"; import { AppConnection } from "../../../../services/app-connection/app-connection-enums"; import { diff --git a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-router.ts b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-router.ts index 0f394f8b2..61e4ab79d 100644 --- a/backend/src/server/routes/v1/secret-sync-routers/secret-sync-router.ts +++ b/backend/src/server/routes/v1/secret-sync-routers/secret-sync-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; +import { ChefSyncListItemSchema, ChefSyncSchema } from "@app/ee/services/secret-sync/chef"; import { OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "@app/ee/services/secret-sync/oci-vault"; import { ApiDocsTags, SecretSyncs } from "@app/lib/api-docs"; import { readLimit } from "@app/server/config/rateLimiter"; @@ -24,7 +25,6 @@ import { AzureKeyVaultSyncListItemSchema, AzureKeyVaultSyncSchema } from "@app/s import { BitbucketSyncListItemSchema, BitbucketSyncSchema } from "@app/services/secret-sync/bitbucket"; import { CamundaSyncListItemSchema, CamundaSyncSchema } from "@app/services/secret-sync/camunda"; import { ChecklySyncListItemSchema, ChecklySyncSchema } from "@app/services/secret-sync/checkly/checkly-sync-schemas"; -import { ChefSyncListItemSchema, ChefSyncSchema } from "@app/ee/services/secret-sync/chef"; import { CloudflarePagesSyncListItemSchema, CloudflarePagesSyncSchema diff --git a/backend/src/services/app-connection/app-connection-service.ts b/backend/src/services/app-connection/app-connection-service.ts index 6d23d3c0a..99ff253d2 100644 --- a/backend/src/services/app-connection/app-connection-service.ts +++ b/backend/src/services/app-connection/app-connection-service.ts @@ -885,6 +885,6 @@ export const appConnectionServiceFactory = ({ northflank: northflankConnectionService(connectAppConnectionById), okta: oktaConnectionService(connectAppConnectionById), laravelForge: laravelForgeConnectionService(connectAppConnectionById), - chef: chefConnectionService(connectAppConnectionById) + chef: chefConnectionService(connectAppConnectionById, licenseService) }; }; diff --git a/backend/src/services/secret-sync/secret-sync-fns.ts b/backend/src/services/secret-sync/secret-sync-fns.ts index ca779bf6a..6ee9b91d3 100644 --- a/backend/src/services/secret-sync/secret-sync-fns.ts +++ b/backend/src/services/secret-sync/secret-sync-fns.ts @@ -290,7 +290,9 @@ export const SecretSyncFns = { case SecretSync.Chef: return ChefSyncFns.syncSecrets(secretSync, schemaSecretMap); default: - throw new Error(`Unhandled sync destination for sync secrets fns: ${secretSync.destination}`); + throw new Error( + `Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}` + ); } }, getSecrets: async ( @@ -413,7 +415,9 @@ export const SecretSyncFns = { secretMap = await ChefSyncFns.getSecrets(secretSync); break; default: - throw new Error(`Unhandled sync destination for get secrets fns: ${secretSync.destination}`); + throw new Error( + `Unhandled sync destination for get secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}` + ); } const filtered = filterForSchema(secretMap, secretSync.environment?.slug || "", secretSync.syncOptions.keySchema); @@ -510,7 +514,9 @@ export const SecretSyncFns = { case SecretSync.Chef: return ChefSyncFns.removeSecrets(secretSync, schemaSecretMap); default: - throw new Error(`Unhandled sync destination for remove secrets fns: ${secretSync.destination}`); + throw new Error( + `Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}` + ); } } }; diff --git a/docs/integrations/app-connections/chef.mdx b/docs/integrations/app-connections/chef.mdx index 60c49fb1f..fdb866557 100644 --- a/docs/integrations/app-connections/chef.mdx +++ b/docs/integrations/app-connections/chef.mdx @@ -3,6 +3,14 @@ title: "Chef Connection" description: "Learn how to configure a Chef Connection for Infisical." --- + + Chef App Connection is a paid feature. + + If you're using Infisical Cloud, then it is available under the **Enterprise Tier**. If you're self-hosting Infisical, + then you should contact team@infisical.com to purchase an enterprise license to use it. + + + Infisical supports the use of User Private Key to connect with Chef Server. Please access your **starter kit** to get all the required information to create a Chef Connection. diff --git a/docs/integrations/secret-syncs/chef.mdx b/docs/integrations/secret-syncs/chef.mdx index 13f3b3474..423d42b4b 100644 --- a/docs/integrations/secret-syncs/chef.mdx +++ b/docs/integrations/secret-syncs/chef.mdx @@ -3,6 +3,14 @@ title: "Chef Sync" description: "Learn how to configure a Chef Sync for Infisical." --- + + Chef Sync is a paid feature. + + If you're using Infisical Cloud, then it is available under the **Enterprise Tier**. If you're self-hosting Infisical, + then you should contact team@infisical.com to purchase an enterprise license to use it. + + + **Prerequisites:** - Create a [Chef Connection](/integrations/app-connections/chef)