mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 13:22:08 +00:00
Merge remote-tracking branch 'origin/main' into feat/acme-and-external-ca
This commit is contained in:
Vendored
+1
@@ -111,6 +111,7 @@ import { TWorkflowIntegrationServiceFactory } from "@app/services/workflow-integ
|
||||
declare module "@fastify/request-context" {
|
||||
interface RequestContextData {
|
||||
reqId: string;
|
||||
orgId?: string;
|
||||
identityAuthInfo?: {
|
||||
identityId: string;
|
||||
oidc?: {
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
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 {
|
||||
CreateOCIConnectionSchema,
|
||||
SanitizedOCIConnectionSchema,
|
||||
UpdateOCIConnectionSchema
|
||||
} from "@app/services/app-connection/oci";
|
||||
} from "@app/ee/services/app-connections/oci";
|
||||
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 { AuthMode } from "@app/services/auth/auth-type";
|
||||
|
||||
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
|
||||
import { registerAppConnectionEndpoints } from "../../../../server/routes/v1/app-connection-routers/app-connection-endpoints";
|
||||
|
||||
export const registerOCIConnectionRouter = async (server: FastifyZodProvider) => {
|
||||
registerAppConnectionEndpoints({
|
||||
+2
-3
@@ -2,11 +2,10 @@ import {
|
||||
CreateOCIVaultSyncSchema,
|
||||
OCIVaultSyncSchema,
|
||||
UpdateOCIVaultSyncSchema
|
||||
} from "@app/services/secret-sync/oci-vault";
|
||||
} from "@app/ee/services/secret-sync/oci-vault";
|
||||
import { registerSyncSecretsEndpoints } from "@app/server/routes/v1/secret-sync-routers/secret-sync-endpoints";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
|
||||
import { registerSyncSecretsEndpoints } from "./secret-sync-endpoints";
|
||||
|
||||
export const registerOCIVaultSyncRouter = async (server: FastifyZodProvider) =>
|
||||
registerSyncSecretsEndpoints({
|
||||
destination: SecretSync.OCIVault,
|
||||
+23
-2
@@ -1,7 +1,9 @@
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { OrgServiceActor } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { AppConnection } from "../../../../services/app-connection/app-connection-enums";
|
||||
import { TLicenseServiceFactory } from "../../license/license-service";
|
||||
import { listOCICompartments, listOCIVaultKeys, listOCIVaults } from "./oci-connection-fns";
|
||||
import { TOCIConnection } from "./oci-connection-types";
|
||||
|
||||
@@ -22,8 +24,23 @@ type TListOCIVaultKeysDTO = {
|
||||
vaultOcid: string;
|
||||
};
|
||||
|
||||
export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||
// Enterprise check
|
||||
export const checkPlan = async (licenseService: Pick<TLicenseServiceFactory, "getPlan">, 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 ociConnectionService = (
|
||||
getAppConnection: TGetAppConnectionFunc,
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">
|
||||
) => {
|
||||
const listCompartments = async (connectionId: string, actor: OrgServiceActor) => {
|
||||
await checkPlan(licenseService, actor.orgId);
|
||||
|
||||
const appConnection = await getAppConnection(AppConnection.OCI, connectionId, actor);
|
||||
|
||||
try {
|
||||
@@ -36,6 +53,8 @@ export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) =>
|
||||
};
|
||||
|
||||
const listVaults = async ({ connectionId, compartmentOcid }: TListOCIVaultsDTO, actor: OrgServiceActor) => {
|
||||
await checkPlan(licenseService, actor.orgId);
|
||||
|
||||
const appConnection = await getAppConnection(AppConnection.OCI, connectionId, actor);
|
||||
|
||||
try {
|
||||
@@ -51,6 +70,8 @@ export const ociConnectionService = (getAppConnection: TGetAppConnectionFunc) =>
|
||||
{ connectionId, compartmentOcid, vaultOcid }: TListOCIVaultKeysDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
await checkPlan(licenseService, actor.orgId);
|
||||
|
||||
const appConnection = await getAppConnection(AppConnection.OCI, connectionId, actor);
|
||||
|
||||
try {
|
||||
+1
-1
@@ -2,7 +2,7 @@ import z from "zod";
|
||||
|
||||
import { DiscriminativePick } from "@app/lib/types";
|
||||
|
||||
import { AppConnection } from "../app-connection-enums";
|
||||
import { AppConnection } from "../../../../services/app-connection/app-connection-enums";
|
||||
import {
|
||||
CreateOCIConnectionSchema,
|
||||
OCIConnectionSchema,
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ProjectType } from "@app/db/schemas";
|
||||
import {
|
||||
TCreateProjectTemplateDTO,
|
||||
TUpdateProjectTemplateDTO
|
||||
@@ -319,7 +320,6 @@ export enum EventType {
|
||||
CREATE_PROJECT_TEMPLATE = "create-project-template",
|
||||
UPDATE_PROJECT_TEMPLATE = "update-project-template",
|
||||
DELETE_PROJECT_TEMPLATE = "delete-project-template",
|
||||
APPLY_PROJECT_TEMPLATE = "apply-project-template",
|
||||
GET_APP_CONNECTIONS = "get-app-connections",
|
||||
GET_AVAILABLE_APP_CONNECTIONS_DETAILS = "get-available-app-connections-details",
|
||||
GET_APP_CONNECTION = "get-app-connection",
|
||||
@@ -379,7 +379,13 @@ export enum EventType {
|
||||
MICROSOFT_TEAMS_WORKFLOW_INTEGRATION_LIST = "microsoft-teams-workflow-integration-list",
|
||||
|
||||
PROJECT_ASSUME_PRIVILEGE_SESSION_START = "project-assume-privileges-session-start",
|
||||
PROJECT_ASSUME_PRIVILEGE_SESSION_END = "project-assume-privileges-session-end"
|
||||
PROJECT_ASSUME_PRIVILEGE_SESSION_END = "project-assume-privileges-session-end",
|
||||
|
||||
UPDATE_ORG = "update-org",
|
||||
|
||||
CREATE_PROJECT = "create-project",
|
||||
UPDATE_PROJECT = "update-project",
|
||||
DELETE_PROJECT = "delete-project"
|
||||
}
|
||||
|
||||
export const filterableSecretEvents: EventType[] = [
|
||||
@@ -2493,14 +2499,6 @@ interface DeleteProjectTemplateEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface ApplyProjectTemplateEvent {
|
||||
type: EventType.APPLY_PROJECT_TEMPLATE;
|
||||
metadata: {
|
||||
template: string;
|
||||
projectId: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface GetAppConnectionsEvent {
|
||||
type: EventType.GET_APP_CONNECTIONS;
|
||||
metadata: {
|
||||
@@ -2955,6 +2953,59 @@ interface MicrosoftTeamsWorkflowIntegrationUpdateEvent {
|
||||
};
|
||||
}
|
||||
|
||||
interface OrgUpdateEvent {
|
||||
type: EventType.UPDATE_ORG;
|
||||
metadata: {
|
||||
name?: string;
|
||||
slug?: string;
|
||||
authEnforced?: boolean;
|
||||
scimEnabled?: boolean;
|
||||
defaultMembershipRoleSlug?: string;
|
||||
enforceMfa?: boolean;
|
||||
selectedMfaMethod?: string;
|
||||
allowSecretSharingOutsideOrganization?: boolean;
|
||||
bypassOrgAuthEnabled?: boolean;
|
||||
userTokenExpiration?: string;
|
||||
secretsProductEnabled?: boolean;
|
||||
pkiProductEnabled?: boolean;
|
||||
kmsProductEnabled?: boolean;
|
||||
sshProductEnabled?: boolean;
|
||||
scannerProductEnabled?: boolean;
|
||||
shareSecretsProductEnabled?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
interface ProjectCreateEvent {
|
||||
type: EventType.CREATE_PROJECT;
|
||||
metadata: {
|
||||
name: string;
|
||||
slug?: string;
|
||||
type: ProjectType;
|
||||
};
|
||||
}
|
||||
|
||||
interface ProjectUpdateEvent {
|
||||
type: EventType.UPDATE_PROJECT;
|
||||
metadata: {
|
||||
name?: string;
|
||||
description?: string;
|
||||
autoCapitalization?: boolean;
|
||||
hasDeleteProtection?: boolean;
|
||||
slug?: string;
|
||||
secretSharing?: boolean;
|
||||
pitVersionLimit?: number;
|
||||
auditLogsRetentionDays?: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface ProjectDeleteEvent {
|
||||
type: EventType.DELETE_PROJECT;
|
||||
metadata: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type Event =
|
||||
| GetSecretsEvent
|
||||
| GetSecretEvent
|
||||
@@ -3163,7 +3214,6 @@ export type Event =
|
||||
| CreateProjectTemplateEvent
|
||||
| UpdateProjectTemplateEvent
|
||||
| DeleteProjectTemplateEvent
|
||||
| ApplyProjectTemplateEvent
|
||||
| GetAppConnectionsEvent
|
||||
| GetAvailableAppConnectionsDetailsEvent
|
||||
| GetAppConnectionEvent
|
||||
@@ -3225,4 +3275,8 @@ export type Event =
|
||||
| MicrosoftTeamsWorkflowIntegrationGetTeamsEvent
|
||||
| MicrosoftTeamsWorkflowIntegrationGetEvent
|
||||
| MicrosoftTeamsWorkflowIntegrationListEvent
|
||||
| MicrosoftTeamsWorkflowIntegrationUpdateEvent;
|
||||
| MicrosoftTeamsWorkflowIntegrationUpdateEvent
|
||||
| OrgUpdateEvent
|
||||
| ProjectCreateEvent
|
||||
| ProjectUpdateEvent
|
||||
| ProjectDeleteEvent;
|
||||
|
||||
@@ -29,7 +29,9 @@ export const getDefaultOnPremFeatures = () => {
|
||||
secretApproval: true,
|
||||
secretRotation: true,
|
||||
caCrl: false,
|
||||
sshHostGroups: false
|
||||
sshHostGroups: false,
|
||||
enterpriseSecretSyncs: false,
|
||||
enterpriseAppConnections: false
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export const licenseDALFactory = (db: TDbClient) => {
|
||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
||||
.where(`${TableName.Users}.isGhost`, false)
|
||||
.count();
|
||||
return Number(doc?.[0].count);
|
||||
return Number(doc?.[0]?.count ?? 0);
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Count of Org Members" });
|
||||
}
|
||||
|
||||
@@ -55,7 +55,9 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
projectTemplates: false,
|
||||
kmip: false,
|
||||
gateway: false,
|
||||
sshHostGroups: false
|
||||
sshHostGroups: false,
|
||||
enterpriseSecretSyncs: false,
|
||||
enterpriseAppConnections: false
|
||||
});
|
||||
|
||||
export const setupLicenseRequestWithStore = (baseURL: string, refreshUrl: string, licenseKey: string) => {
|
||||
|
||||
@@ -92,6 +92,10 @@ export const licenseServiceFactory = ({
|
||||
const {
|
||||
data: { currentPlan }
|
||||
} = await licenseServerOnPremApi.request.get<{ currentPlan: TFeatureSet }>("/api/license/v1/plan");
|
||||
|
||||
const workspacesUsed = await projectDAL.countOfOrgProjects(null);
|
||||
currentPlan.workspacesUsed = workspacesUsed;
|
||||
|
||||
onPremFeatures = currentPlan;
|
||||
logger.info("Successfully synchronized license key features");
|
||||
} catch (error) {
|
||||
@@ -185,6 +189,9 @@ export const licenseServiceFactory = ({
|
||||
} = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>(
|
||||
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`
|
||||
);
|
||||
const workspacesUsed = await projectDAL.countOfOrgProjects(orgId);
|
||||
currentPlan.workspacesUsed = workspacesUsed;
|
||||
|
||||
await keyStore.setItemWithExpiry(
|
||||
FEATURE_CACHE_KEY(org.id),
|
||||
LICENSE_SERVER_CLOUD_PLAN_TTL,
|
||||
|
||||
@@ -27,7 +27,7 @@ export type TFeatureSet = {
|
||||
slug: null;
|
||||
tier: -1;
|
||||
workspaceLimit: null;
|
||||
workspacesUsed: 0;
|
||||
workspacesUsed: number;
|
||||
dynamicSecret: false;
|
||||
memberLimit: null;
|
||||
membersUsed: number;
|
||||
@@ -72,6 +72,8 @@ export type TFeatureSet = {
|
||||
kmip: false;
|
||||
gateway: false;
|
||||
sshHostGroups: false;
|
||||
enterpriseSecretSyncs: false;
|
||||
enterpriseAppConnections: false;
|
||||
};
|
||||
|
||||
export type TOrgPlansTableDTO = {
|
||||
|
||||
+2
-1
@@ -6,5 +6,6 @@ export const OCI_VAULT_SYNC_LIST_OPTION: TSecretSyncListItem = {
|
||||
name: "OCI Vault",
|
||||
destination: SecretSync.OCIVault,
|
||||
connection: AppConnection.OCI,
|
||||
canImportSecrets: true
|
||||
canImportSecrets: true,
|
||||
enterprise: true
|
||||
};
|
||||
+3
-3
@@ -1,7 +1,6 @@
|
||||
import { secrets, vault } from "oci-sdk";
|
||||
|
||||
import { delay } from "@app/lib/delay";
|
||||
import { getOCIProvider } from "@app/services/app-connection/oci";
|
||||
import { getOCIProvider } from "@app/ee/services/app-connections/oci";
|
||||
import {
|
||||
TCreateOCIVaultVariable,
|
||||
TDeleteOCIVaultVariable,
|
||||
@@ -9,7 +8,8 @@ import {
|
||||
TOCIVaultSyncWithCredentials,
|
||||
TUnmarkOCIVaultVariableFromDeletion,
|
||||
TUpdateOCIVaultVariable
|
||||
} from "@app/services/secret-sync/oci-vault/oci-vault-sync-types";
|
||||
} from "@app/ee/services/secret-sync/oci-vault/oci-vault-sync-types";
|
||||
import { delay } from "@app/lib/delay";
|
||||
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";
|
||||
+2
-1
@@ -66,5 +66,6 @@ export const OCIVaultSyncListItemSchema = z.object({
|
||||
name: z.literal("OCI Vault"),
|
||||
connection: z.literal(AppConnection.OCI),
|
||||
destination: z.literal(SecretSync.OCIVault),
|
||||
canImportSecrets: z.literal(true)
|
||||
canImportSecrets: z.literal(true),
|
||||
enterprise: z.boolean()
|
||||
});
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { SimpleAuthenticationDetailsProvider } from "oci-sdk";
|
||||
import { z } from "zod";
|
||||
|
||||
import { TOCIConnection } from "@app/services/app-connection/oci";
|
||||
import { TOCIConnection } from "@app/ee/services/app-connections/oci";
|
||||
|
||||
import { CreateOCIVaultSyncSchema, OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "./oci-vault-sync-schemas";
|
||||
|
||||
@@ -69,6 +69,9 @@ const envSchema = z
|
||||
SMTP_PASSWORD: zpStr(z.string().optional()),
|
||||
SMTP_FROM_ADDRESS: zpStr(z.string().optional()),
|
||||
SMTP_FROM_NAME: zpStr(z.string().optional().default("Infisical")),
|
||||
SMTP_CUSTOM_CA_CERT: zpStr(
|
||||
z.string().optional().describe("Base64 encoded custom CA certificate PEM(s) for the SMTP server")
|
||||
),
|
||||
COOKIE_SECRET_SIGN_KEY: z
|
||||
.string()
|
||||
.min(32)
|
||||
@@ -298,6 +301,17 @@ export const initEnvConfig = (logger?: CustomLogger) => {
|
||||
};
|
||||
|
||||
export const formatSmtpConfig = () => {
|
||||
const tlsOptions: {
|
||||
rejectUnauthorized: boolean;
|
||||
ca?: string | string[];
|
||||
} = {
|
||||
rejectUnauthorized: envCfg.SMTP_TLS_REJECT_UNAUTHORIZED
|
||||
};
|
||||
|
||||
if (envCfg.SMTP_CUSTOM_CA_CERT) {
|
||||
tlsOptions.ca = Buffer.from(envCfg.SMTP_CUSTOM_CA_CERT, "base64").toString("utf-8");
|
||||
}
|
||||
|
||||
return {
|
||||
host: envCfg.SMTP_HOST,
|
||||
port: envCfg.SMTP_PORT,
|
||||
@@ -309,8 +323,6 @@ export const formatSmtpConfig = () => {
|
||||
from: `"${envCfg.SMTP_FROM_NAME}" <${envCfg.SMTP_FROM_ADDRESS}>`,
|
||||
ignoreTLS: envCfg.SMTP_IGNORE_TLS,
|
||||
requireTLS: envCfg.SMTP_REQUIRE_TLS,
|
||||
tls: {
|
||||
rejectUnauthorized: envCfg.SMTP_TLS_REJECT_UNAUTHORIZED
|
||||
}
|
||||
tls: tlsOptions
|
||||
};
|
||||
};
|
||||
|
||||
@@ -95,11 +95,20 @@ const extractReqId = () => {
|
||||
try {
|
||||
return requestContext.get("reqId") || UNKNOWN_REQUEST_ID;
|
||||
} catch (err) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("failed to get request context", err);
|
||||
return UNKNOWN_REQUEST_ID;
|
||||
}
|
||||
};
|
||||
|
||||
const extractOrgId = () => {
|
||||
try {
|
||||
return requestContext.get("orgId");
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export const initLogger = () => {
|
||||
const cfg = loggerConfig.parse(process.env);
|
||||
const targets: pino.TransportMultiOptions["targets"][number][] = [
|
||||
@@ -135,22 +144,22 @@ export const initLogger = () => {
|
||||
const wrapLogger = (originalLogger: Logger): CustomLogger => {
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any
|
||||
originalLogger.info = (obj: unknown, msg?: string, ...args: any[]) => {
|
||||
return originalLogger.child({ reqId: extractReqId() }).info(obj, msg, ...args);
|
||||
return originalLogger.child({ reqId: extractReqId(), orgId: extractOrgId() }).info(obj, msg, ...args);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any
|
||||
originalLogger.error = (obj: unknown, msg?: string, ...args: any[]) => {
|
||||
return originalLogger.child({ reqId: extractReqId() }).error(obj, msg, ...args);
|
||||
return originalLogger.child({ reqId: extractReqId(), orgId: extractOrgId() }).error(obj, msg, ...args);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any
|
||||
originalLogger.warn = (obj: unknown, msg?: string, ...args: any[]) => {
|
||||
return originalLogger.child({ reqId: extractReqId() }).warn(obj, msg, ...args);
|
||||
return originalLogger.child({ reqId: extractReqId(), orgId: extractOrgId() }).warn(obj, msg, ...args);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/no-explicit-any
|
||||
originalLogger.debug = (obj: unknown, msg?: string, ...args: any[]) => {
|
||||
return originalLogger.child({ reqId: extractReqId() }).debug(obj, msg, ...args);
|
||||
return originalLogger.child({ reqId: extractReqId(), orgId: extractOrgId() }).debug(obj, msg, ...args);
|
||||
};
|
||||
|
||||
return originalLogger;
|
||||
|
||||
@@ -123,6 +123,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
switch (authMode) {
|
||||
case AuthMode.JWT: {
|
||||
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
|
||||
requestContext.set("orgId", orgId);
|
||||
req.auth = {
|
||||
authMode: AuthMode.JWT,
|
||||
user,
|
||||
@@ -138,6 +139,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
|
||||
const serverCfg = await getServerCfg();
|
||||
requestContext.set("orgId", identity.orgId);
|
||||
req.auth = {
|
||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||
actor,
|
||||
@@ -157,6 +159,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
}
|
||||
case AuthMode.SERVICE_TOKEN: {
|
||||
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
|
||||
requestContext.set("orgId", serviceToken.orgId);
|
||||
req.auth = {
|
||||
orgId: serviceToken.orgId,
|
||||
authMode: AuthMode.SERVICE_TOKEN as const,
|
||||
@@ -181,6 +184,7 @@ export const injectIdentity = fp(async (server: FastifyZodProvider) => {
|
||||
}
|
||||
case AuthMode.SCIM_TOKEN: {
|
||||
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
|
||||
requestContext.set("orgId", orgId);
|
||||
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null };
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -971,7 +971,8 @@ export const registerRoutes = async (
|
||||
secretVersionV2BridgeDAL,
|
||||
secretVersionTagV2BridgeDAL,
|
||||
resourceMetadataDAL,
|
||||
appConnectionDAL
|
||||
appConnectionDAL,
|
||||
licenseService
|
||||
});
|
||||
|
||||
const secretQueueService = secretQueueFactory({
|
||||
@@ -1588,7 +1589,8 @@ export const registerRoutes = async (
|
||||
const appConnectionService = appConnectionServiceFactory({
|
||||
appConnectionDAL,
|
||||
permissionService,
|
||||
kmsService
|
||||
kmsService,
|
||||
licenseService
|
||||
});
|
||||
|
||||
const secretSyncService = secretSyncServiceFactory({
|
||||
@@ -1599,7 +1601,8 @@ export const registerRoutes = async (
|
||||
folderDAL,
|
||||
secretSyncQueue,
|
||||
projectBotService,
|
||||
keyStore
|
||||
keyStore,
|
||||
licenseService
|
||||
});
|
||||
|
||||
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { OCIConnectionListItemSchema, SanitizedOCIConnectionSchema } from "@app/ee/services/app-connections/oci";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { ApiDocsTags } from "@app/lib/api-docs";
|
||||
import { readLimit } from "@app/server/config/rateLimiter";
|
||||
@@ -38,7 +39,6 @@ import {
|
||||
} from "@app/services/app-connection/humanitec";
|
||||
import { LdapConnectionListItemSchema, SanitizedLdapConnectionSchema } from "@app/services/app-connection/ldap";
|
||||
import { MsSqlConnectionListItemSchema, SanitizedMsSqlConnectionSchema } from "@app/services/app-connection/mssql";
|
||||
import { OCIConnectionListItemSchema, SanitizedOCIConnectionSchema } from "@app/services/app-connection/oci";
|
||||
import {
|
||||
PostgresConnectionListItemSchema,
|
||||
SanitizedPostgresConnectionSchema
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { registerOCIConnectionRouter } from "@app/ee/routes/v1/app-connection-routers/oci-connection-router";
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
|
||||
import { registerAuth0ConnectionRouter } from "./auth0-connection-router";
|
||||
@@ -13,7 +14,6 @@ import { registerHCVaultConnectionRouter } from "./hc-vault-connection-router";
|
||||
import { registerHumanitecConnectionRouter } from "./humanitec-connection-router";
|
||||
import { registerLdapConnectionRouter } from "./ldap-connection-router";
|
||||
import { registerMsSqlConnectionRouter } from "./mssql-connection-router";
|
||||
import { registerOCIConnectionRouter } from "./oci-connection-router";
|
||||
import { registerPostgresConnectionRouter } from "./postgres-connection-router";
|
||||
import { registerTeamCityConnectionRouter } from "./teamcity-connection-router";
|
||||
import { registerTerraformCloudConnectionRouter } from "./terraform-cloud-router";
|
||||
|
||||
@@ -312,8 +312,17 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
||||
data: req.body
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
event: {
|
||||
type: EventType.UPDATE_ORG,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully changed organization name",
|
||||
message: "Successfully updated organization",
|
||||
organization
|
||||
};
|
||||
}
|
||||
|
||||
@@ -263,6 +263,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.DELETE_PROJECT,
|
||||
metadata: workspace
|
||||
}
|
||||
});
|
||||
|
||||
return { workspace };
|
||||
}
|
||||
});
|
||||
@@ -297,6 +308,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
projectId: req.params.workspaceId,
|
||||
name: req.body.name
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully changed workspace name",
|
||||
workspace
|
||||
@@ -375,6 +397,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
actor: req.permission.type,
|
||||
actorOrgId: req.permission.orgId
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
workspace
|
||||
};
|
||||
@@ -411,6 +444,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
projectId: req.params.workspaceId,
|
||||
autoCapitalization: req.body.autoCapitalization
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully changed workspace settings",
|
||||
workspace
|
||||
@@ -448,6 +492,17 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
projectId: req.params.workspaceId,
|
||||
hasDeleteProtection: req.body.hasDeleteProtection
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: req.params.workspaceId,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully changed workspace settings",
|
||||
workspace
|
||||
@@ -486,6 +541,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
workspaceSlug: req.params.workspaceSlug
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: workspace.id,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully changed workspace version limit",
|
||||
workspace
|
||||
@@ -524,6 +589,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
auditLogsRetentionDays: req.body.auditLogsRetentionDays
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: workspace.id,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
message: "Successfully updated project's audit logs retention period",
|
||||
workspace
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
|
||||
import { registerOCIVaultSyncRouter } from "../../../../ee/routes/v1/secret-sync-routers/oci-vault-sync-router";
|
||||
import { registerAwsParameterStoreSyncRouter } from "./aws-parameter-store-sync-router";
|
||||
import { registerAwsSecretsManagerSyncRouter } from "./aws-secrets-manager-sync-router";
|
||||
import { registerAzureAppConfigurationSyncRouter } from "./azure-app-configuration-sync-router";
|
||||
@@ -10,7 +11,6 @@ import { registerGcpSyncRouter } from "./gcp-sync-router";
|
||||
import { registerGitHubSyncRouter } from "./github-sync-router";
|
||||
import { registerHCVaultSyncRouter } from "./hc-vault-sync-router";
|
||||
import { registerHumanitecSyncRouter } from "./humanitec-sync-router";
|
||||
import { registerOCIVaultSyncRouter } from "./oci-vault-sync-router";
|
||||
import { registerTeamCitySyncRouter } from "./teamcity-sync-router";
|
||||
import { registerTerraformCloudSyncRouter } from "./terraform-cloud-sync-router";
|
||||
import { registerVercelSyncRouter } from "./vercel-sync-router";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
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";
|
||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||
@@ -24,7 +25,6 @@ import { GcpSyncListItemSchema, GcpSyncSchema } from "@app/services/secret-sync/
|
||||
import { GitHubSyncListItemSchema, GitHubSyncSchema } from "@app/services/secret-sync/github";
|
||||
import { HCVaultSyncListItemSchema, HCVaultSyncSchema } from "@app/services/secret-sync/hc-vault";
|
||||
import { HumanitecSyncListItemSchema, HumanitecSyncSchema } from "@app/services/secret-sync/humanitec";
|
||||
import { OCIVaultSyncListItemSchema, OCIVaultSyncSchema } from "@app/services/secret-sync/oci-vault";
|
||||
import { TeamCitySyncListItemSchema, TeamCitySyncSchema } from "@app/services/secret-sync/teamcity";
|
||||
import { TerraformCloudSyncListItemSchema, TerraformCloudSyncSchema } from "@app/services/secret-sync/terraform-cloud";
|
||||
import { VercelSyncListItemSchema, VercelSyncSchema } from "@app/services/secret-sync/vercel";
|
||||
|
||||
@@ -205,19 +205,18 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
if (req.body.template) {
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
event: {
|
||||
type: EventType.APPLY_PROJECT_TEMPLATE,
|
||||
metadata: {
|
||||
template: req.body.template,
|
||||
projectId: project.id
|
||||
}
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: project.id,
|
||||
event: {
|
||||
type: EventType.CREATE_PROJECT,
|
||||
metadata: {
|
||||
...req.body,
|
||||
name: req.body.projectName
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { project };
|
||||
}
|
||||
@@ -261,6 +260,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
actor: req.permission.type
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: project.id,
|
||||
event: {
|
||||
type: EventType.DELETE_PROJECT,
|
||||
metadata: project
|
||||
}
|
||||
});
|
||||
|
||||
return project;
|
||||
}
|
||||
});
|
||||
@@ -340,6 +349,16 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
|
||||
actorOrgId: req.permission.orgId
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
orgId: req.permission.orgId,
|
||||
projectId: project.id,
|
||||
event: {
|
||||
type: EventType.UPDATE_PROJECT,
|
||||
metadata: req.body
|
||||
}
|
||||
});
|
||||
|
||||
return project;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -66,3 +66,8 @@ export enum AWSRegion {
|
||||
// South America
|
||||
SA_EAST_1 = "sa-east-1" // Sao Paulo
|
||||
}
|
||||
|
||||
export enum AppConnectionPlanType {
|
||||
Enterprise = "enterprise",
|
||||
Regular = "regular"
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { TAppConnections } from "@app/db/schemas/app-connections";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { generateHash } from "@app/lib/crypto/encryption";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import { APP_CONNECTION_NAME_MAP } from "@app/services/app-connection/app-connection-maps";
|
||||
import { APP_CONNECTION_NAME_MAP, APP_CONNECTION_PLAN_MAP } from "@app/services/app-connection/app-connection-maps";
|
||||
import {
|
||||
transferSqlConnectionCredentialsToPlatform,
|
||||
validateSqlConnectionCredentials
|
||||
} from "@app/services/app-connection/shared/sql";
|
||||
import { KmsDataKey } from "@app/services/kms/kms-types";
|
||||
|
||||
import { AppConnection } from "./app-connection-enums";
|
||||
import {
|
||||
getOCIConnectionListItem,
|
||||
OCIConnectionMethod,
|
||||
validateOCIConnectionCredentials
|
||||
} from "../../ee/services/app-connections/oci";
|
||||
import { AppConnection, AppConnectionPlanType } from "./app-connection-enums";
|
||||
import { TAppConnectionServiceFactoryDep } from "./app-connection-service";
|
||||
import {
|
||||
TAppConnection,
|
||||
@@ -53,7 +59,6 @@ import {
|
||||
} from "./humanitec";
|
||||
import { getLdapConnectionListItem, LdapConnectionMethod, validateLdapConnectionCredentials } from "./ldap";
|
||||
import { getMsSqlConnectionListItem, MsSqlConnectionMethod } from "./mssql";
|
||||
import { getOCIConnectionListItem, OCIConnectionMethod, validateOCIConnectionCredentials } from "./oci";
|
||||
import { getPostgresConnectionListItem, PostgresConnectionMethod } from "./postgres";
|
||||
import {
|
||||
getTeamCityConnectionListItem,
|
||||
@@ -257,3 +262,18 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
||||
[AppConnection.TeamCity]: platformManagedCredentialsNotSupported,
|
||||
[AppConnection.OCI]: platformManagedCredentialsNotSupported
|
||||
};
|
||||
|
||||
export const enterpriseAppCheck = async (
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">,
|
||||
appConnection: AppConnection,
|
||||
orgId: string,
|
||||
errorMessage: string
|
||||
) => {
|
||||
if (APP_CONNECTION_PLAN_MAP[appConnection] === AppConnectionPlanType.Enterprise) {
|
||||
const plan = await licenseService.getPlan(orgId);
|
||||
if (!plan.enterpriseAppConnections)
|
||||
throw new BadRequestError({
|
||||
message: errorMessage
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppConnection } from "./app-connection-enums";
|
||||
import { AppConnection, AppConnectionPlanType } from "./app-connection-enums";
|
||||
|
||||
export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
||||
[AppConnection.AWS]: "AWS",
|
||||
@@ -21,3 +21,25 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
||||
[AppConnection.TeamCity]: "TeamCity",
|
||||
[AppConnection.OCI]: "OCI"
|
||||
};
|
||||
|
||||
export const APP_CONNECTION_PLAN_MAP: Record<AppConnection, AppConnectionPlanType> = {
|
||||
[AppConnection.AWS]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.GitHub]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.GCP]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.AzureKeyVault]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.AzureAppConfiguration]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.AzureClientSecrets]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Databricks]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Humanitec]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.TerraformCloud]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Vercel]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Postgres]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.MsSql]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Camunda]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Windmill]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.Auth0]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.HCVault]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.LDAP]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.TeamCity]: AppConnectionPlanType.Regular,
|
||||
[AppConnection.OCI]: AppConnectionPlanType.Enterprise
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ForbiddenError, subject } from "@casl/ability";
|
||||
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { OrgPermissionAppConnectionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { generateHash } from "@app/lib/crypto/encryption";
|
||||
@@ -9,6 +10,7 @@ import { DiscriminativePick, OrgServiceActor } from "@app/lib/types";
|
||||
import {
|
||||
decryptAppConnection,
|
||||
encryptAppConnectionCredentials,
|
||||
enterpriseAppCheck,
|
||||
getAppConnectionMethodName,
|
||||
listAppConnectionOptions,
|
||||
TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM,
|
||||
@@ -17,6 +19,8 @@ import {
|
||||
import { auth0ConnectionService } from "@app/services/app-connection/auth0/auth0-connection-service";
|
||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { ValidateOCIConnectionCredentialsSchema } from "../../ee/services/app-connections/oci";
|
||||
import { ociConnectionService } from "../../ee/services/app-connections/oci/oci-connection-service";
|
||||
import { TAppConnectionDALFactory } from "./app-connection-dal";
|
||||
import { AppConnection } from "./app-connection-enums";
|
||||
import { APP_CONNECTION_NAME_MAP } from "./app-connection-maps";
|
||||
@@ -49,8 +53,6 @@ import { ValidateHumanitecConnectionCredentialsSchema } from "./humanitec";
|
||||
import { humanitecConnectionService } from "./humanitec/humanitec-connection-service";
|
||||
import { ValidateLdapConnectionCredentialsSchema } from "./ldap";
|
||||
import { ValidateMsSqlConnectionCredentialsSchema } from "./mssql";
|
||||
import { ValidateOCIConnectionCredentialsSchema } from "./oci";
|
||||
import { ociConnectionService } from "./oci/oci-connection-service";
|
||||
import { ValidatePostgresConnectionCredentialsSchema } from "./postgres";
|
||||
import { ValidateTeamCityConnectionCredentialsSchema } from "./teamcity";
|
||||
import { teamcityConnectionService } from "./teamcity/teamcity-connection-service";
|
||||
@@ -65,6 +67,7 @@ export type TAppConnectionServiceFactoryDep = {
|
||||
appConnectionDAL: TAppConnectionDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TAppConnectionServiceFactory = ReturnType<typeof appConnectionServiceFactory>;
|
||||
@@ -94,7 +97,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
||||
export const appConnectionServiceFactory = ({
|
||||
appConnectionDAL,
|
||||
permissionService,
|
||||
kmsService
|
||||
kmsService,
|
||||
licenseService
|
||||
}: TAppConnectionServiceFactoryDep) => {
|
||||
const listAppConnectionsByOrg = async (actor: OrgServiceActor, app?: AppConnection) => {
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
@@ -191,6 +195,13 @@ export const appConnectionServiceFactory = ({
|
||||
OrgPermissionSubjects.AppConnections
|
||||
);
|
||||
|
||||
await enterpriseAppCheck(
|
||||
licenseService,
|
||||
app,
|
||||
actor.orgId,
|
||||
"Failed to create app connection due to plan restriction. Upgrade plan to access enterprise app connections."
|
||||
);
|
||||
|
||||
const validatedCredentials = await validateAppConnectionCredentials({
|
||||
app,
|
||||
credentials,
|
||||
@@ -253,6 +264,13 @@ export const appConnectionServiceFactory = ({
|
||||
|
||||
if (!appConnection) throw new NotFoundError({ message: `Could not find App Connection with ID ${connectionId}` });
|
||||
|
||||
await enterpriseAppCheck(
|
||||
licenseService,
|
||||
appConnection.app as AppConnection,
|
||||
actor.orgId,
|
||||
"Failed to update app connection due to plan restriction. Upgrade plan to access enterprise app connections."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getOrgPermission(
|
||||
actor.type,
|
||||
actor.id,
|
||||
@@ -399,6 +417,13 @@ export const appConnectionServiceFactory = ({
|
||||
|
||||
if (!appConnection) throw new NotFoundError({ message: `Could not find App Connection with ID ${connectionId}` });
|
||||
|
||||
await enterpriseAppCheck(
|
||||
licenseService,
|
||||
app,
|
||||
actor.orgId,
|
||||
"Failed to connect app due to plan restriction. Upgrade plan to access enterprise app connections."
|
||||
);
|
||||
|
||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
||||
actor.type,
|
||||
actor.id,
|
||||
@@ -468,6 +493,6 @@ export const appConnectionServiceFactory = ({
|
||||
hcvault: hcVaultConnectionService(connectAppConnectionById),
|
||||
windmill: windmillConnectionService(connectAppConnectionById),
|
||||
teamcity: teamcityConnectionService(connectAppConnectionById),
|
||||
oci: ociConnectionService(connectAppConnectionById)
|
||||
oci: ociConnectionService(connectAppConnectionById, licenseService)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,6 +2,12 @@ import { TAppConnectionDALFactory } from "@app/services/app-connection/app-conne
|
||||
import { TSqlConnectionConfig } from "@app/services/app-connection/shared/sql/sql-connection-types";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
|
||||
import {
|
||||
TOCIConnection,
|
||||
TOCIConnectionConfig,
|
||||
TOCIConnectionInput,
|
||||
TValidateOCIConnectionCredentialsSchema
|
||||
} from "../../ee/services/app-connections/oci";
|
||||
import { AWSRegion } from "./app-connection-enums";
|
||||
import {
|
||||
TAuth0Connection,
|
||||
@@ -76,12 +82,6 @@ import {
|
||||
TValidateLdapConnectionCredentialsSchema
|
||||
} from "./ldap";
|
||||
import { TMsSqlConnection, TMsSqlConnectionInput, TValidateMsSqlConnectionCredentialsSchema } from "./mssql";
|
||||
import {
|
||||
TOCIConnection,
|
||||
TOCIConnectionConfig,
|
||||
TOCIConnectionInput,
|
||||
TValidateOCIConnectionCredentialsSchema
|
||||
} from "./oci";
|
||||
import {
|
||||
TPostgresConnection,
|
||||
TPostgresConnectionInput,
|
||||
|
||||
@@ -425,6 +425,21 @@ export const projectDALFactory = (db: TDbClient) => {
|
||||
return { docs, totalCount: Number(docs?.[0]?.count ?? 0) };
|
||||
};
|
||||
|
||||
const countOfOrgProjects = async (orgId: string | null, tx?: Knex) => {
|
||||
try {
|
||||
const doc = await (tx || db.replicaNode())(TableName.Project)
|
||||
.andWhere((bd) => {
|
||||
if (orgId) {
|
||||
void bd.where({ orgId });
|
||||
}
|
||||
})
|
||||
.count();
|
||||
return Number(doc?.[0]?.count ?? 0);
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "Count of Org Projects" });
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...projectOrm,
|
||||
findUserProjects,
|
||||
@@ -437,6 +452,7 @@ export const projectDALFactory = (db: TDbClient) => {
|
||||
findProjectWithOrg,
|
||||
checkProjectUpgradeStatus,
|
||||
getProjectFromSplitId,
|
||||
searchProjects
|
||||
searchProjects,
|
||||
countOfOrgProjects
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,3 +26,8 @@ export enum SecretSyncImportBehavior {
|
||||
PrioritizeSource = "prioritize-source",
|
||||
PrioritizeDestination = "prioritize-destination"
|
||||
}
|
||||
|
||||
export enum SecretSyncPlanType {
|
||||
Enterprise = "enterprise",
|
||||
Regular = "regular"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { AxiosError } from "axios";
|
||||
import RE2 from "re2";
|
||||
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { OCI_VAULT_SYNC_LIST_OPTION, OCIVaultSyncFns } from "@app/ee/services/secret-sync/oci-vault";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
import {
|
||||
AWS_PARAMETER_STORE_SYNC_LIST_OPTION,
|
||||
AwsParameterStoreSyncFns
|
||||
@@ -11,7 +14,7 @@ import {
|
||||
} from "@app/services/secret-sync/aws-secrets-manager";
|
||||
import { DATABRICKS_SYNC_LIST_OPTION, databricksSyncFactory } from "@app/services/secret-sync/databricks";
|
||||
import { GITHUB_SYNC_LIST_OPTION, GithubSyncFns } from "@app/services/secret-sync/github";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import {
|
||||
TSecretMap,
|
||||
@@ -29,7 +32,7 @@ import { GcpSyncFns } from "./gcp/gcp-sync-fns";
|
||||
import { HC_VAULT_SYNC_LIST_OPTION, HCVaultSyncFns } from "./hc-vault";
|
||||
import { HUMANITEC_SYNC_LIST_OPTION } from "./humanitec";
|
||||
import { HumanitecSyncFns } from "./humanitec/humanitec-sync-fns";
|
||||
import { OCI_VAULT_SYNC_LIST_OPTION, OCIVaultSyncFns } from "./oci-vault";
|
||||
import { SECRET_SYNC_PLAN_MAP } from "./secret-sync-maps";
|
||||
import { TEAMCITY_SYNC_LIST_OPTION, TeamCitySyncFns } from "./teamcity";
|
||||
import { TERRAFORM_CLOUD_SYNC_LIST_OPTION, TerraformCloudSyncFns } from "./terraform-cloud";
|
||||
import { VERCEL_SYNC_LIST_OPTION, VercelSyncFns } from "./vercel";
|
||||
@@ -327,3 +330,18 @@ export const parseSyncErrorMessage = (err: unknown): string => {
|
||||
? errorMessage
|
||||
: `${errorMessage.substring(0, MAX_MESSAGE_LENGTH - 3)}...`;
|
||||
};
|
||||
|
||||
export const enterpriseSyncCheck = async (
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">,
|
||||
secretSync: SecretSync,
|
||||
orgId: string,
|
||||
errorMessage: string
|
||||
) => {
|
||||
if (SECRET_SYNC_PLAN_MAP[secretSync] === SecretSyncPlanType.Enterprise) {
|
||||
const plan = await licenseService.getPlan(orgId);
|
||||
if (!plan.enterpriseSecretSyncs)
|
||||
throw new BadRequestError({
|
||||
message: errorMessage
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSync, SecretSyncPlanType } from "@app/services/secret-sync/secret-sync-enums";
|
||||
|
||||
export const SECRET_SYNC_NAME_MAP: Record<SecretSync, string> = {
|
||||
[SecretSync.AWSParameterStore]: "AWS Parameter Store",
|
||||
@@ -36,3 +36,21 @@ export const SECRET_SYNC_CONNECTION_MAP: Record<SecretSync, AppConnection> = {
|
||||
[SecretSync.TeamCity]: AppConnection.TeamCity,
|
||||
[SecretSync.OCIVault]: AppConnection.OCI
|
||||
};
|
||||
|
||||
export const SECRET_SYNC_PLAN_MAP: Record<SecretSync, SecretSyncPlanType> = {
|
||||
[SecretSync.AWSParameterStore]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AWSSecretsManager]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.GitHub]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.GCPSecretManager]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AzureKeyVault]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.AzureAppConfiguration]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Databricks]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Humanitec]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.TerraformCloud]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Camunda]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Vercel]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.Windmill]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.HCVault]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.TeamCity]: SecretSyncPlanType.Regular,
|
||||
[SecretSync.OCIVault]: SecretSyncPlanType.Enterprise
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Job } from "bullmq";
|
||||
import { ProjectMembershipRole, SecretType } from "@app/db/schemas";
|
||||
import { TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-service";
|
||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { KeyStorePrefixes, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { logger } from "@app/lib/logger";
|
||||
@@ -32,7 +33,7 @@ import {
|
||||
SecretSyncInitialSyncBehavior
|
||||
} from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
||||
import { parseSyncErrorMessage, SecretSyncFns } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { enterpriseSyncCheck, parseSyncErrorMessage, SecretSyncFns } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { SECRET_SYNC_NAME_MAP } from "@app/services/secret-sync/secret-sync-maps";
|
||||
import {
|
||||
SecretSyncAction,
|
||||
@@ -93,6 +94,7 @@ type TSecretSyncQueueFactoryDep = {
|
||||
secretVersionV2BridgeDAL: Pick<TSecretVersionV2DALFactory, "insertMany" | "findLatestVersionMany">;
|
||||
secretVersionTagV2BridgeDAL: Pick<TSecretVersionV2TagDALFactory, "insertMany">;
|
||||
resourceMetadataDAL: Pick<TResourceMetadataDALFactory, "insertMany" | "delete">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
type SecretSyncActionJob = Job<
|
||||
@@ -133,7 +135,8 @@ export const secretSyncQueueFactory = ({
|
||||
secretVersionTagDAL,
|
||||
secretVersionV2BridgeDAL,
|
||||
secretVersionTagV2BridgeDAL,
|
||||
resourceMetadataDAL
|
||||
resourceMetadataDAL,
|
||||
licenseService
|
||||
}: TSecretSyncQueueFactoryDep) => {
|
||||
const appCfg = getConfig();
|
||||
|
||||
@@ -323,7 +326,20 @@ export const secretSyncQueueFactory = ({
|
||||
secretSync: TSecretSyncWithCredentials,
|
||||
importBehavior: SecretSyncImportBehavior
|
||||
): Promise<TSecretMap> => {
|
||||
const { projectId, environment, folder } = secretSync;
|
||||
const {
|
||||
projectId,
|
||||
environment,
|
||||
folder,
|
||||
destination,
|
||||
connection: { orgId }
|
||||
} = secretSync;
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
destination,
|
||||
orgId,
|
||||
"Failed to import secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
if (!environment || !folder)
|
||||
throw new Error(
|
||||
@@ -400,6 +416,13 @@ export const secretSyncQueueFactory = ({
|
||||
|
||||
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
secretSync.connection.orgId,
|
||||
"Failed to sync secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
await secretSyncDAL.updateById(syncId, {
|
||||
syncStatus: SecretSyncStatus.Running
|
||||
});
|
||||
@@ -659,6 +682,13 @@ export const secretSyncQueueFactory = ({
|
||||
|
||||
if (!secretSync) throw new Error(`Cannot find secret sync with ID ${syncId}`);
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
secretSync.connection.orgId,
|
||||
"Failed to remove secrets due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
await secretSyncDAL.updateById(syncId, {
|
||||
removeStatus: SecretSyncStatus.Running
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
import { ActionProjectType } from "@app/db/schemas";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { throwIfMissingSecretReadValueOrDescribePermission } from "@app/ee/services/permission/permission-fns";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import {
|
||||
@@ -16,7 +17,7 @@ import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-c
|
||||
import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service";
|
||||
import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal";
|
||||
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
|
||||
import { listSecretSyncOptions } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import { enterpriseSyncCheck, listSecretSyncOptions } from "@app/services/secret-sync/secret-sync-fns";
|
||||
import {
|
||||
SecretSyncStatus,
|
||||
TCreateSecretSyncDTO,
|
||||
@@ -49,6 +50,7 @@ type TSecretSyncServiceFactoryDep = {
|
||||
TSecretSyncQueueFactory,
|
||||
"queueSecretSyncSyncSecretsById" | "queueSecretSyncImportSecretsById" | "queueSecretSyncRemoveSecretsById"
|
||||
>;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
};
|
||||
|
||||
export type TSecretSyncServiceFactory = ReturnType<typeof secretSyncServiceFactory>;
|
||||
@@ -61,7 +63,8 @@ export const secretSyncServiceFactory = ({
|
||||
appConnectionService,
|
||||
projectBotService,
|
||||
secretSyncQueue,
|
||||
keyStore
|
||||
keyStore,
|
||||
licenseService
|
||||
}: TSecretSyncServiceFactoryDep) => {
|
||||
const listSecretSyncsByProjectId = async (
|
||||
{ projectId, destination }: TListSecretSyncsByProjectId,
|
||||
@@ -191,6 +194,13 @@ export const secretSyncServiceFactory = ({
|
||||
{ projectId, secretPath, environment, ...params }: TCreateSecretSyncDTO,
|
||||
actor: OrgServiceActor
|
||||
) => {
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
params.destination,
|
||||
actor.orgId,
|
||||
"Failed to create secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission: projectPermission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -260,6 +270,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID ${syncId}`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to update secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -408,6 +425,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -463,6 +487,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
@@ -512,6 +543,13 @@ export const secretSyncServiceFactory = ({
|
||||
message: `Could not find ${SECRET_SYNC_NAME_MAP[destination]} Sync with ID "${syncId}"`
|
||||
});
|
||||
|
||||
await enterpriseSyncCheck(
|
||||
licenseService,
|
||||
secretSync.destination as SecretSync,
|
||||
actor.orgId,
|
||||
"Failed to trigger secret sync due to plan restriction. Upgrade plan to access enterprise secret syncs."
|
||||
);
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission({
|
||||
actor: actor.type,
|
||||
actorId: actor.id,
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { Job } from "bullmq";
|
||||
|
||||
import { AuditLogInfo } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import {
|
||||
TOCIVaultSync,
|
||||
TOCIVaultSyncInput,
|
||||
TOCIVaultSyncListItem,
|
||||
TOCIVaultSyncWithCredentials
|
||||
} from "@app/ee/services/secret-sync/oci-vault";
|
||||
import { QueueJobs } from "@app/queue";
|
||||
import { ResourceMetadataDTO } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||
import {
|
||||
@@ -67,7 +73,6 @@ import {
|
||||
THumanitecSyncListItem,
|
||||
THumanitecSyncWithCredentials
|
||||
} from "./humanitec";
|
||||
import { TOCIVaultSync, TOCIVaultSyncInput, TOCIVaultSyncListItem, TOCIVaultSyncWithCredentials } from "./oci-vault";
|
||||
import {
|
||||
TTeamCitySync,
|
||||
TTeamCitySyncInput,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/pe
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { infisicalSymmetricDecrypt } from "@app/lib/crypto/encryption";
|
||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { TAuthTokenServiceFactory } from "@app/services/auth-token/auth-token-service";
|
||||
import { TokenType } from "@app/services/auth-token/auth-token-types";
|
||||
import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal";
|
||||
@@ -80,6 +81,17 @@ export const userServiceFactory = ({
|
||||
const verifyEmailVerificationCode = async (username: string, code: string) => {
|
||||
// akhilmhdh: case sensitive email resolution
|
||||
const usersByusername = await userDAL.findUserByUsername(username);
|
||||
|
||||
logger.info(
|
||||
usersByusername.map((user) => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
username: user.username,
|
||||
isEmailVerified: user.isEmailVerified
|
||||
})),
|
||||
`Verify email users: [username=${username}]`
|
||||
);
|
||||
|
||||
const user =
|
||||
usersByusername?.length > 1 ? usersByusername.find((el) => el.username === username) : usersByusername?.[0];
|
||||
if (!user) throw new NotFoundError({ name: `User with username '${username}' not found` });
|
||||
|
||||
Reference in New Issue
Block a user